Merge branch 'MDL-30731-master' of git://github.com/FMCorz/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 20 Nov 2012 07:31:27 +0000 (15:31 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 20 Nov 2012 07:31:27 +0000 (15:31 +0800)
73 files changed:
admin/settings/server.php
admin/user.php
backup/converter/moodle1/lib.php
backup/converter/moodle1/tests/lib_test.php
blocks/dock.js
blocks/glossary_random/block_glossary_random.php
cache/classes/config.php
cache/classes/helper.php
calendar/lib.php
calendar/managesubscriptions_form.php
calendar/renderer.php
course/format/renderer.php
enrol/flatfile/lib.php
enrol/renderer.php
grade/import/csv/index.php
grade/import/grade_import_form.php
grade/report/grader/index.php
grade/report/grader/lib.php
lang/en/admin.php
lang/en/calendar.php
lang/en/message.php
lib/adminlib.php
lib/bennu/iCalendar_components.php
lib/bennu/readme_moodle.txt
lib/db/upgrade.php
lib/eaccelerator.class.php [deleted file]
lib/formslib.php
lib/javascript-static.js
lib/memcached.class.php [deleted file]
lib/messagelib.php
lib/moodlelib.php
lib/setup.php
lib/setuplib.php
lib/tablelib.php
lib/tests/accesslib_test.php
lib/tests/outputcomponents_test.php
lib/tests/setuplib_test.php
message/lib.php
mod/assign/locallib.php
mod/data/preset.php
mod/lesson/format.php
mod/quiz/styles.css
mod/scorm/mod_form.php
mod/workshop/renderer.php
pix/docs.png [new file with mode: 0644]
pix/docs.svg [new file with mode: 0644]
pix/i/down.png [new file with mode: 0644]
pix/i/down.svg [new file with mode: 0644]
pix/i/up.png [new file with mode: 0644]
pix/i/up.svg [new file with mode: 0644]
pix/t/down.png
pix/t/down.svg
pix/t/sort_asc.png [new file with mode: 0644]
pix/t/sort_asc.svg [new file with mode: 0644]
pix/t/sort_desc.png [new file with mode: 0644]
pix/t/sort_desc.svg [new file with mode: 0644]
pix/t/up.png
pix/t/up.svg
question/editlib.php
question/format/xml/format.php
question/type/match/backup/moodle2/restore_qtype_match_plugin.class.php
question/type/multichoice/question.php
question/type/multichoice/tests/question_test.php
repository/filepicker.js
theme/base/style/core.css
theme/formal_white/layout/frontpage.php
theme/formal_white/layout/general.php
theme/formal_white/layout/report.php
theme/formal_white/style/formal_white.css
theme/formal_white/style/frame.css
theme/standard/style/css3.css
theme/upgrade.txt
version.php

index 4e773cd..3ba7201 100644 (file)
@@ -193,29 +193,6 @@ $temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache'
 
 $temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('curltimeoutkbitrate', 'admin'),
                                         new lang_string('curltimeoutkbitrate_help', 'admin'), 56, PARAM_INT));
-/* //TODO: we need to fix code instead of relying on slow rcache, enable this once we have some code that is actually using it
-$temp->add(new admin_setting_special_selectsetup('cachetype', new lang_string('cachetype', 'admin'),
-                                          new lang_string('configcachetype', 'admin'), '',
-                                          array( '' => new lang_string('none'),
-                                                 'internal' => 'internal',
-                                                 'memcached' => 'memcached',
-                                                 'eaccelerator' => 'eaccelerator')));
-// NOTE: $CFG->rcache is forced to bool in lib/setup.php
-$temp->add(new admin_setting_special_selectsetup('rcache', new lang_string('rcache', 'admin'),
-                                          new lang_string('configrcache', 'admin'), 0,
-                                          array( '0' => new lang_string('no'),
-                                                 '1' => new lang_string('yes'))));
-$temp->add(new admin_setting_configtext('rcachettl', new lang_string('rcachettl', 'admin'),
-                                        new lang_string('configrcachettl', 'admin'), 10));
-$temp->add(new admin_setting_configtext('intcachemax', new lang_string('intcachemax', 'admin'),
-                                        new lang_string('configintcachemax', 'admin'), 10));
-$temp->add(new admin_setting_configtext('memcachedhosts', new lang_string('memcachedhosts', 'admin'),
-                                        new lang_string('configmemcachedhosts', 'admin'), ''));
-$temp->add(new admin_setting_configselect('memcachedpconn', new lang_string('memcachedpconn', 'admin'),
-                                          new lang_string('configmemcachedpconn', 'admin'), 0,
-                                          array( '0' => new lang_string('no'),
-                                                 '1' => new lang_string('yes'))));
-*/
 
 $ADMIN->add('server', $temp);
 
index 5abb3b0..97f1abb 100644 (file)
         } else {
             $columndir = $dir == "ASC" ? "DESC":"ASC";
             if ($column == "lastaccess") {
-                $columnicon = $dir == "ASC" ? "up":"down";
+                $columnicon = ($dir == "ASC") ? "sort_desc" : "sort_asc";
             } else {
-                $columnicon = $dir == "ASC" ? "down":"up";
+                $columnicon = ($dir == "ASC") ? "sort_asc" : "sort_desc";
             }
-            $columnicon = " <img src=\"" . $OUTPUT->pix_url('t/' . $columnicon) . "\" alt=\"\" />";
+            $columnicon = "<img class='iconsort' src=\"" . $OUTPUT->pix_url('t/' . $columnicon) . "\" alt=\"\" />";
 
         }
         $$column = "<a href=\"user.php?sort=$column&amp;dir=$columndir\">".$string[$column]."</a>$columnicon";
index 46d7514..c3b47c6 100644 (file)
@@ -641,7 +641,8 @@ class moodle1_converter extends base_converter {
             return $files;
         }
         foreach ($matches[2] as $match) {
-            $files[] = str_replace(array('$@FILEPHP@$', '$@SLASH@$', '$@FORCEDOWNLOAD@$'), array('', '/', ''), $match);
+            $file = str_replace(array('$@FILEPHP@$', '$@SLASH@$', '$@FORCEDOWNLOAD@$'), array('', '/', ''), $match);
+            $files[] = urldecode($file);
         }
 
         return array_unique($files);
index a97720e..20aca62 100644 (file)
@@ -449,6 +449,19 @@ as it is parsed from the backup file. <br /><br /><img border="0" width="110" vs
     <br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />');
     }
 
+    public function test_referenced_files_urlencoded() {
+        // This test covers MDL-36204
+        $text = 'This is a text containing links to file.php
+as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif" /><a href="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif$@FORCEDOWNLOAD@$">no space</a><br />
+    <br /><a href=\'$@FILEPHP@$$@SLASH@$pics$@SLASH@$news%20with%20spaces.gif$@FORCEDOWNLOAD@$\'>with urlencoded spaces</a><br />';
+
+        $files = moodle1_converter::find_referenced_files($text);
+        $this->assertEquals(gettype($files), 'array');
+        $this->assertEquals(2, count($files));
+        $this->assertTrue(in_array('/pics/news.gif', $files));
+        $this->assertTrue(in_array('/pics/news with spaces.gif', $files));
+    }
+
     public function test_question_bank_conversion() {
         global $CFG;
 
index ca685d5..6e56390 100644 (file)
@@ -536,7 +536,7 @@ M.core_dock.fixTitleOrientation = function(item, title, text) {
     });
 
     // Positioning is different when in RTL mode.
-    if (Y.one(document.body).hasClass('dir-rtl')) {
+    if (right_to_left()) {
         title.setStyle('left', width/2 - height);
     } else {
         title.setStyle('right', width/2 - height);
@@ -837,7 +837,11 @@ M.core_dock.genericblock.prototype = {
 
         // Must set the image src seperatly of we get an error with XML strict headers
         var moveto = Y.Node.create('<input type="image" class="moveto customcommand requiresjs" alt="'+M.str.block.addtodock+'" title="'+M.str.block.addtodock+'" />');
-        moveto.setAttribute('src', M.util.image_url('t/block_to_dock', 'moodle'));
+        var icon = 't/block_to_dock';
+        if (right_to_left()) {
+            icon = 't/block_to_dock_rtl';
+        }
+        moveto.setAttribute('src', M.util.image_url(icon, 'moodle'));
         moveto.on('movetodock|click', this.move_to_dock, this, commands);
 
         var blockaction = node.one('.block_action');
@@ -903,7 +907,11 @@ M.core_dock.genericblock.prototype = {
 
         // Must set the image src seperatly of we get an error with XML strict headers
         var movetoimg = Y.Node.create('<img alt="'+M.str.block.undockitem+'" title="'+M.str.block.undockitem+'" />');
-        movetoimg.setAttribute('src', M.util.image_url('t/dock_to_block', 'moodle'));
+        var icon = 't/dock_to_block';
+        if (right_to_left()) {
+            icon = 't/dock_to_block_rtl';
+        }
+        movetoimg.setAttribute('src', M.util.image_url(icon, 'moodle'));
         var moveto = Y.Node.create('<a class="moveto customcommand requiresjs"></a>').append(movetoimg);
         if (location.href.match(/\?/)) {
             moveto.set('href', location.href+'&dock='+this.id);
index 0128f1b..916780d 100644 (file)
@@ -129,11 +129,6 @@ class block_glossary_random extends block_base {
         $course = $this->page->course;
         $modinfo = get_fast_modinfo($course);
         $glossaryid = $this->config->glossary;
-        $cm = $modinfo->instances['glossary'][$glossaryid];
-
-        if (!has_capability('mod/glossary:view', context_module::instance($cm->id))) {
-            return '';
-        }
 
         if (!isset($modinfo->instances['glossary'][$glossaryid])) {
             // we can get here if the glossary has been deleted, so
@@ -147,6 +142,12 @@ class block_glossary_random extends block_base {
             return $this->content;
         }
 
+        $cm = $modinfo->instances['glossary'][$glossaryid];
+
+        if (!has_capability('mod/glossary:view', context_module::instance($cm->id))) {
+            return '';
+        }
+
         if (empty($this->config->cache)) {
             $this->config->cache = '';
         }
index 682ef18..da3b966 100644 (file)
@@ -344,6 +344,61 @@ class cache_config {
         return $this->configdefinitions;
     }
 
+    /**
+     * Returns the definitions mapped into the given store name.
+     *
+     * @param string $storename
+     * @return array Associative array of definitions, id=>definition
+     */
+    public static function get_definitions_by_store($storename) {
+        $definitions = array();
+
+        $config = cache_config::instance();
+        $stores = $config->get_all_stores();
+        if (!array_key_exists($storename, $stores)) {
+            // The store does not exist.
+            return false;
+        }
+
+        $defmappings = $config->get_definition_mappings();
+        // Create an associative array for the definition mappings.
+        $thedefmappings = array();
+        foreach ($defmappings as $defmapping) {
+            $thedefmappings[$defmapping['definition']] = $defmapping;
+        }
+
+        // Search for matches in default mappings.
+        $defs = $config->get_definitions();
+        foreach($config->get_mode_mappings() as $modemapping) {
+            if ($modemapping['store'] !== $storename) {
+                continue;
+            }
+            foreach($defs as $id => $definition) {
+                if ($definition['mode'] !== $modemapping['mode']) {
+                    continue;
+                }
+                // Exclude custom definitions mapping: they will be managed few lines below.
+                if (array_key_exists($id, $thedefmappings)) {
+                    continue;
+                }
+                $definitions[$id] = $definition;
+            }
+        }
+
+        // Search for matches in the custom definitions mapping
+        foreach ($defmappings as $defmapping) {
+            if ($defmapping['store'] !== $storename) {
+                continue;
+            }
+            $definition = $config->get_definition_by_id($defmapping['definition']);
+            if ($definition) {
+                $definitions[$defmapping['definition']] = $definition;
+            }
+        }
+
+        return $definitions;
+    }
+
     /**
      * Returns all of the stores that are suitable for the given mode and requirements.
      *
index 8c56eeb..4439a56 100644 (file)
@@ -270,6 +270,8 @@ class cache_helper {
     /**
      * Purges the cache for a specific definition.
      *
+     * @todo MDL-36660: Change the signature: $aggregate must be added.
+     *
      * @param string $component
      * @param string $area
      * @param array $identifiers
@@ -278,6 +280,14 @@ class cache_helper {
     public static function purge_by_definition($component, $area, array $identifiers = array()) {
         // Create the cache.
         $cache = cache::make($component, $area, $identifiers);
+        // Initialise, in case of a store.
+        if ($cache instanceof cache_store) {
+            $factory = cache_factory::instance();
+            // TODO MDL-36660: Providing $aggregate is required for purging purposes: $definition->get_id()
+            $definition = $factory->create_definition($component, $area, null);
+            $definition->set_identifiers($identifiers);
+            $cache->initialise($definition);
+        }
         // Purge baby, purge.
         $cache->purge();
         return true;
@@ -295,8 +305,13 @@ class cache_helper {
         foreach ($instance->get_definitions() as $name => $definitionarr) {
             $definition = cache_definition::load($name, $definitionarr);
             if ($definition->invalidates_on_event($event)) {
-                // Purge the cache.
+                // Create the cache.
                 $cache = $factory->create_cache($definition);
+                // Initialise, in case of a store.
+                if ($cache instanceof cache_store) {
+                    $cache->initialise($definition);
+                }
+                // Purge the cache.
                 $cache->purge();
 
                 // We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
@@ -389,16 +404,9 @@ class cache_helper {
      */
     public static function purge_all() {
         $config = cache_config::instance();
-        $stores = $config->get_all_stores();
-        $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'core', 'cache_purge');
-        foreach ($stores as $store) {
-            $class = $store['class'];
-            $instance = new $class($store['name'], $store['configuration']);
-            if (!$instance->is_ready()) {
-                continue;
-            }
-            $instance->initialise($definition);
-            $instance->purge();
+
+        foreach ($config->get_all_stores() as $store) {
+            self::purge_store($store['name']);
         }
     }
 
@@ -410,21 +418,32 @@ class cache_helper {
      */
     public static function purge_store($storename) {
         $config = cache_config::instance();
-        foreach ($config->get_all_stores() as $store) {
-            if ($store['name'] !== $storename) {
-                continue;
-            }
-            $class = $store['class'];
+
+        $stores = $config->get_all_stores();
+        if (!array_key_exists($storename, $stores)) {
+            // The store does not exist.
+            return false;
+        }
+
+        $store = $stores[$storename];
+        $class = $store['class'];
+
+        // Found the store: is it ready?
+        $instance = new $class($store['name'], $store['configuration']);
+        if (!$instance->is_ready()) {
+            unset($instance);
+            return false;
+        }
+
+        foreach ($config->get_definitions_by_store($storename) as $id => $definition) {
+            $definition = cache_definition::load($id, $definition);
             $instance = new $class($store['name'], $store['configuration']);
-            if (!$instance->is_ready()) {
-                continue;
-            }
-            $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'core', 'cache_purge');
             $instance->initialise($definition);
             $instance->purge();
-            return true;
+            unset($instance);
         }
-        return false;
+
+        return true;
     }
 
     /**
index d20fe30..14b4999 100644 (file)
@@ -2699,7 +2699,7 @@ function calendar_get_eventtype_choices($courseid) {
         $choices[0] = get_string('userevents', 'calendar');
     }
     if ($allowed->site) {
-        $choices[SITEID] = get_string('globalevents', 'calendar');
+        $choices[SITEID] = get_string('siteevents', 'calendar');
     }
     if (!empty($allowed->courses)) {
         $choices[$courseid] = get_string('courseevents', 'calendar');
index fcd7979..731bbd3 100644 (file)
@@ -61,12 +61,6 @@ class calendar_addsubscription_form extends moodleform {
         // Cannot set as PARAM_URL since we need to allow webcal:// protocol.
         $mform->setType('url', PARAM_RAW);
 
-        // Import file
-        $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar'));
-
-        $mform->disabledIf('url',  'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
-        $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL);
-
         // Poll interval
         $choices = calendar_get_pollinterval_choices();
         $mform->addElement('select', 'pollinterval', get_string('pollinterval', 'calendar'), $choices);
@@ -74,6 +68,14 @@ class calendar_addsubscription_form extends moodleform {
         $mform->addHelpButton('pollinterval', 'pollinterval', 'calendar');
         $mform->setType('pollinterval', PARAM_INT);
 
+        // Import file
+        $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar'));
+
+        // Disable appropriate elements depending on import from value.
+        $mform->disabledIf('pollinterval', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
+        $mform->disabledIf('url',  'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
+        $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL);
+
         // Eventtype: 0 = user, 1 = global, anything else = course ID.
         list($choices, $groups) = calendar_get_eventtype_choices($courseid);
         $mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $choices);
index 842ecc4..5a18073 100644 (file)
@@ -800,6 +800,7 @@ class core_calendar_renderer extends plugin_renderer_base {
                 if ($k == $subscription->pollinterval) {
                     $attributes['selected'] = 'selected';
                 }
+                $attributes['value'] = $k;
                 $html .= html_writer::tag('option', $v, $attributes);
             }
             $html .= html_writer::end_tag('select');
index 1856c62..befde23 100644 (file)
@@ -245,7 +245,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                 $strmoveup = get_string('moveup');
 
                 $controls[] = html_writer::link($url,
-                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/up'),
+                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/up'),
                     'class' => 'icon up', 'alt' => $strmoveup)),
                     array('title' => $strmoveup, 'class' => 'moveup'));
             }
@@ -257,7 +257,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                 $strmovedown =  get_string('movedown');
 
                 $controls[] = html_writer::link($url,
-                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/down'),
+                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/down'),
                     'class' => 'icon down', 'alt' => $strmovedown)),
                     array('title' => $strmovedown, 'class' => 'movedown'));
             }
index 3c839d0..7e01825 100644 (file)
@@ -151,7 +151,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
             if(! @unlink($filename)) {
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
-                $eventdata->component         = 'course';
+                $eventdata->component         = 'enrol_flatfile';
                 $eventdata->name              = 'flatfile_enrolment';
                 $eventdata->userfrom          = get_admin();
                 $eventdata->userto            = get_admin();
@@ -169,7 +169,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
                 // Send mail to admin
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
-                $eventdata->component         = 'course';
+                $eventdata->component         = 'enrol_flatfile';
                 $eventdata->name              = 'flatfile_enrolment';
                 $eventdata->userfrom          = get_admin();
                 $eventdata->userto            = get_admin();
@@ -280,7 +280,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
 
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
-                $eventdata->component         = 'course';
+                $eventdata->component         = 'enrol_flatfile';
                 $eventdata->name              = 'flatfile_enrolment';
                 $eventdata->userfrom          = $teacher;
                 $eventdata->userto            = $user;
@@ -303,7 +303,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
 
                     $eventdata = new stdClass();
                     $eventdata->modulename        = 'moodle';
-                    $eventdata->component         = 'course';
+                    $eventdata->component         = 'enrol_flatfile';
                     $eventdata->name              = 'flatfile_enrolment';
                     $eventdata->userfrom          = $user;
                     $eventdata->userto            = $teacher;
index aa71854..05e43f5 100644 (file)
@@ -512,7 +512,7 @@ class course_enrolment_table extends html_table implements renderable {
                     } else {
                         $link = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n)), $fields[$name][$n]);
                         if ($this->sort == $n) {
-                            $link .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
+                            $link .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
                         }
                         $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n));
 
@@ -525,7 +525,7 @@ class course_enrolment_table extends html_table implements renderable {
                 } else {
                     $newlabel  = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name)), $fields[$name]);
                     if ($this->sort == $name) {
-                        $newlabel .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
+                        $newlabel .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
                     }
                 }
             }
@@ -633,9 +633,11 @@ class course_enrolment_table extends html_table implements renderable {
             $direction = $this->sortdirection;
         }
         if ($direction === 'ASC') {
-            return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/down')));
+            return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
+                'src' => $output->pix_url('t/sort_asc')));
         } else {
-            return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/up')));
+            return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
+                'src' => $output->pix_url('t/sort_desc')));
         }
     }
 
index 7896f39..36784b3 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-require_once '../../../config.php';
-require_once $CFG->libdir.'/gradelib.php';
-require_once $CFG->dirroot.'/grade/lib.php';
-require_once '../grade_import_form.php';
-require_once '../lib.php';
+require_once("../../../config.php");
+require_once($CFG->libdir.'/gradelib.php');
+require_once($CFG->dirroot.'/grade/lib.php');
+require_once($CFG->dirroot. '/grade/import/grade_import_form.php');
+require_once($CFG->dirroot.'/grade/import/lib.php');
+require_once($CFG->libdir . '/csvlib.class.php');
 
 $id            = required_param('id', PARAM_INT); // course id
 $separator     = optional_param('separator', '', PARAM_ALPHA);
 $verbosescales = optional_param('verbosescales', 1, PARAM_BOOL);
+$iid           = optional_param('iid', null, PARAM_INT);
+$importcode    = optional_param('importcode', '', PARAM_FILE);
 
 $url = new moodle_url('/grade/import/csv/index.php', array('id'=>$id));
 if ($separator !== '') {
@@ -34,8 +37,6 @@ if ($verbosescales !== 1) {
 }
 $PAGE->set_url($url);
 
-define('GRADE_CSV_LINE_LENGTH', 4096);
-
 if (!$course = $DB->get_record('course', array('id'=>$id))) {
     print_error('nocourseid');
 }
@@ -48,33 +49,14 @@ require_capability('gradeimport/csv:view', $context);
 $separatemode = (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
 $currentgroup = groups_get_course_group($course);
 
-// sort out delimiter
-if (isset($CFG->CSV_DELIMITER)) {
-    $csv_delimiter = $CFG->CSV_DELIMITER;
-
-    if (isset($CFG->CSV_ENCODE)) {
-        $csv_encode = '/\&\#' . $CFG->CSV_ENCODE . '/';
-    }
-} else if ($separator == 'tab') {
-    $csv_delimiter = "\t";
-    $csv_encode = "";
-} else {
-    $csv_delimiter = ",";
-    $csv_encode = '/\&\#44/';
-}
-
 print_grade_page_head($course->id, 'import', 'csv', get_string('importcsv', 'grades'));
 
-// set up import form
-$mform = new grade_import_form(null, array('includeseparator'=>!isset($CFG->CSV_DELIMITER), 'verbosescales'=>true));
-
-// set up grade import mapping form
-$header = '';
+// Set up the grade import mapping form.
 $gradeitems = array();
 if ($id) {
     if ($grade_items = grade_item::fetch_all(array('courseid'=>$id))) {
         foreach ($grade_items as $grade_item) {
-            // skip course type and category type
+            // Skip course type and category type.
             if ($grade_item->itemtype == 'course' || $grade_item->itemtype == 'category') {
                 continue;
             }
@@ -90,96 +72,84 @@ if ($id) {
     }
 }
 
-if ($importcode = optional_param('importcode', '', PARAM_FILE)) {
-    $filename = $CFG->tempdir.'/gradeimport/cvs/'.$USER->id.'/'.$importcode;
-    $fp = fopen($filename, "r");
-    $headers = fgets($fp, GRADE_CSV_LINE_LENGTH);
-    $header = explode($csv_delimiter, $headers);
-    fclose($fp);
-}
+// Set up the import form.
+$mform = new grade_import_form(null, array('includeseparator'=>true, 'verbosescales'=>true));
 
-$mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
+// If the csv file hasn't been imported yet then look for a form submission or
+// show the initial submission form.
+if (!$iid) {
+    // If the import form has been submitted.
+    if ($formdata = $mform->get_data()) {
 
-// if import form is submitted
-if ($formdata = $mform->get_data()) {
+        // Large files are likely to take their time and memory. Let PHP know
+        // that we'll take longer, and that the process should be recycled soon
+        // to free up memory.
+        @set_time_limit(0);
+        raise_memory_limit(MEMORY_EXTRA);
 
-    // Large files are likely to take their time and memory. Let PHP know
-    // that we'll take longer, and that the process should be recycled soon
-    // to free up memory.
-    @set_time_limit(0);
-    raise_memory_limit(MEMORY_EXTRA);
+        // Use current (non-conflicting) time stamp.
+        $importcode = get_new_importcode();
 
-    // use current (non-conflicting) time stamp
-    $importcode = get_new_importcode();
-    $filename = make_temp_directory('gradeimport/cvs/'.$USER->id);
-    $filename = $filename.'/'.$importcode;
-
-    $text = $mform->get_file_content('userfile');
-    // trim utf-8 bom
-    /// normalize line endings and do the encoding conversion
-    $text = textlib::convert($text, $formdata->encoding);
-    $text = textlib::trim_utf8_bom($text);
-    // Fix mac/dos newlines
-    $text = preg_replace('!\r\n?!',"\n",$text);
-    $fp = fopen($filename, "w");
-    fwrite($fp,$text);
-    fclose($fp);
-
-    if (!$fp = fopen($filename, "r")) {
-        print_error('cannotopenfile');
-    }
+        $text = $mform->get_file_content('userfile');
+        $iid = csv_import_reader::get_new_iid('grade');
+        $csvimport = new csv_import_reader($iid, 'grade');
 
-    // --- get header (field names) ---
-    $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+        $csvimport->load_csv_content($text, $formdata->encoding, $separator);
 
-    // print some preview
-    $numlines = 0; // 0 preview lines displayed
+        // --- get header (field names) ---
+        $header = $csvimport->get_columns();
 
-    echo $OUTPUT->heading(get_string('importpreview', 'grades'));
-    echo '<table>';
-    echo '<tr>';
-    foreach ($header as $h) {
-        $h = clean_param($h, PARAM_RAW);
-        echo '<th>'.$h.'</th>';
-    }
-    echo '</tr>';
-    while (!feof ($fp) && $numlines <= $formdata->previewrows) {
-        $lines = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
-        echo '<tr>';
-        foreach ($lines as $line) {
-            echo '<td>'.$line.'</td>';
-        }
-        $numlines ++;
-        echo '</tr>';
-    }
-    echo '</table>';
+        // Print a preview of the data.
+        $numlines = 0; // 0 lines previewed so far.
 
-    // display the mapping form with header info processed
-    $mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
-    $mform2->set_data(array('importcode'=>$importcode, 'id'=>$id, 'verbosescales'=>$verbosescales, 'separator'=>$separator));
-    $mform2->display();
+        echo $OUTPUT->heading(get_string('importpreview', 'grades'));
 
-//} else if (($formdata = data_submitted()) && !empty($formdata->map)) {
+        foreach ($header as $i => $h) {
+            $h = trim($h); // Remove whitespace.
+            $h = clean_param($h, PARAM_RAW); // Clean the header.
+            $header[$i] = $h;
+        }
 
-// else if grade import mapping form is submitted
-} else if ($formdata = $mform2->get_data()) {
+        $table = new html_table();
+        $table->head = $header;
+        $csvimport->init();
+        $previewdata = array();
+        while ($numlines <= $formdata->previewrows) {
+            $lines = $csvimport->next();
+            if ($lines) {
+                $previewdata[] = $lines;
+            }
+            $numlines ++;
+        }
+        $table->data = $previewdata;
+        echo html_writer::table($table);
+    } else {
+        // Display the standard upload file form.
+        groups_print_course_menu($course, 'index.php?id='.$id);
+        echo html_writer::start_tag('div', array('class' => 'clearer'));
+        echo html_writer::end_tag('div');
+
+        $mform->display();
+        echo $OUTPUT->footer();
+        die();
+    }
+}
 
-    $importcode = clean_param($formdata->importcode, PARAM_FILE);
-    $filename = $CFG->tempdir.'/gradeimport/cvs/'.$USER->id.'/'.$importcode;
+// Data has already been submitted so we can use the $iid to retrieve it.
+$csvimport = new csv_import_reader($iid, 'grade');
+$header = $csvimport->get_columns();
 
-    if (!file_exists($filename)) {
-        print_error('cannotuploadfile');
-    }
+// we create a form to handle mapping data from the file to the database.
+$mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
+$mform2->set_data(array('iid' => $iid, 'id' => $id, 'importcode'=>$importcode, 'verbosescales' => $verbosescales));
 
-    if ($fp = fopen($filename, "r")) {
-        // --- get header (field names) ---
-        $header = explode($csv_delimiter, clean_param(fgets($fp,GRADE_CSV_LINE_LENGTH), PARAM_RAW));
+// Here, if we have data, we process the fields and enter the information into the database.
+if ($formdata = $mform2->get_data()) {
 
-        foreach ($header as $i => $h) {
-            $h = trim($h); $header[$i] = $h; // remove whitespace
-        }
-    } else {
-        print_error('cannotopenfile');
+    foreach ($header as $i => $h) {
+        $h = trim($h); // Remove whitespace.
+        $h = clean_param($h, PARAM_RAW); // Clean the header.
+        $header[$i] = $h;
     }
 
     $map = array();
@@ -204,8 +174,6 @@ if ($formdata = $mform->get_data()) {
                 $maperrors[$j] = true;
             } else {
                 // collision
-                fclose($fp);
-                unlink($filename); // needs to be uploaded again, sorry
                 print_error('cannotmapfield', '', '', $j);
             }
         }
@@ -217,186 +185,160 @@ if ($formdata = $mform->get_data()) {
     @set_time_limit(0);
     raise_memory_limit(MEMORY_EXTRA);
 
-    // we only operate if file is readable
-    if ($fp = fopen($filename, "r")) {
-
-        // read the first line makes sure this doesn't get read again
-        $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+    $csvimport->init();
 
-        $newgradeitems = array(); // temporary array to keep track of what new headers are processed
-        $status = true;
+    $newgradeitems = array(); // temporary array to keep track of what new headers are processed
+    $status = true;
 
-        while (!feof ($fp)) {
-            // add something
-            $line = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+    while ($line = $csvimport->next()) {
+        if(count($line) <= 1){
+            // there is no data on this line, move on
+            continue;
+        }
 
-            if(count($line) <= 1){
-                // there is no data on this line, move on
-                continue;
+        // array to hold all grades to be inserted
+        $newgrades = array();
+        // array to hold all feedback
+        $newfeedbacks = array();
+        // each line is a student record
+        foreach ($line as $key => $value) {
+
+            $value = clean_param($value, PARAM_RAW);
+            $value = trim($value);
+
+            /*
+             * the options are
+             * 1) userid, useridnumber, usermail, username - used to identify user row
+             * 2) new - new grade item
+             * 3) id - id of the old grade item to map onto
+             * 3) feedback_id - feedback for grade item id
+             */
+
+            $t = explode("_", $map[$key]);
+            $t0 = $t[0];
+            if (isset($t[1])) {
+                $t1 = (int)$t[1];
+            } else {
+                $t1 = '';
             }
 
-            // array to hold all grades to be inserted
-            $newgrades = array();
-            // array to hold all feedback
-            $newfeedbacks = array();
-            // each line is a student record
-            foreach ($line as $key => $value) {
-                //decode encoded commas
-                $value = clean_param($value, PARAM_RAW);
-                $value = trim($value);
-                if (!empty($csv_encode)) {
-                    $value = preg_replace($csv_encode, $csv_delimiter, $value);
-                }
+            switch ($t0) {
+                case 'userid': //
+                    if (!$user = $DB->get_record('user', array('id' => $value))) {
+                        // user not found, abort whole import
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with id \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $value;
+                break;
+                case 'useridnumber':
+                    if (!$user = $DB->get_record('user', array('idnumber' => $value))) {
+                         // user not found, abort whole import
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with idnumber \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $user->id;
+                break;
+                case 'useremail':
+                    if (!$user = $DB->get_record('user', array('email' => $value))) {
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with email address \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $user->id;
+                break;
+                case 'username':
+                    if (!$user = $DB->get_record('user', array('username' => $value))) {
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with username \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $user->id;
+                break;
+                case 'new':
+                    // first check if header is already in temp database
 
-                /*
-                 * the options are
-                 * 1) userid, useridnumber, usermail, username - used to identify user row
-                 * 2) new - new grade item
-                 * 3) id - id of the old grade item to map onto
-                 * 3) feedback_id - feedback for grade item id
-                 */
-
-                $t = explode("_", $map[$key]);
-                $t0 = $t[0];
-                if (isset($t[1])) {
-                    $t1 = (int)$t[1];
-                } else {
-                    $t1 = '';
-                }
+                    if (empty($newgradeitems[$key])) {
 
-                switch ($t0) {
-                    case 'userid': //
-                        if (!$user = $DB->get_record('user', array('id' => $value))) {
-                            // user not found, abort whole import
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with id \"$value\"");
+                        $newgradeitem = new stdClass();
+                        $newgradeitem->itemname = $header[$key];
+                        $newgradeitem->importcode = $importcode;
+                        $newgradeitem->importer   = $USER->id;
+
+                        // insert into new grade item buffer
+                        $newgradeitems[$key] = $DB->insert_record('grade_import_newitem', $newgradeitem);
+                    }
+                    $newgrade = new stdClass();
+                    $newgrade->newgradeitem = $newgradeitems[$key];
+
+                    // if the user has a grade for this grade item
+                    if (trim($value) != '-') {
+                        // instead of omitting the grade we could insert one with finalgrade set to 0
+                        // we do not have access to grade item min grade
+                        $newgrade->finalgrade   = $value;
+                        $newgrades[] = $newgrade;
+                    }
+                break;
+                case 'feedback':
+                    if ($t1) {
+                        // case of an id, only maps id of a grade_item
+                        // this was idnumber
+                        if (!$gradeitem = new grade_item(array('id'=>$t1, 'courseid'=>$course->id))) {
+                            // supplied bad mapping, should not be possible since user
+                            // had to pick mapping
                             $status = false;
-                            break 3;
-                        }
-                        $studentid = $value;
-                    break;
-                    case 'useridnumber':
-                        if (!$user = $DB->get_record('user', array('idnumber' => $value))) {
-                             // user not found, abort whole import
                             import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with idnumber \"$value\"");
-                            $status = false;
+                            echo $OUTPUT->notification(get_string('importfailed', 'grades'));
                             break 3;
                         }
-                        $studentid = $user->id;
-                    break;
-                    case 'useremail':
-                        if (!$user = $DB->get_record('user', array('email' => $value))) {
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with email address \"$value\"");
+
+                        // t1 is the id of the grade item
+                        $feedback = new stdClass();
+                        $feedback->itemid   = $t1;
+                        $feedback->feedback = $value;
+                        $newfeedbacks[] = $feedback;
+                    }
+                break;
+                default:
+                    // existing grade items
+                    if (!empty($map[$key])) {
+                        // case of an id, only maps id of a grade_item
+                        // this was idnumber
+                        if (!$gradeitem = new grade_item(array('id'=>$map[$key], 'courseid'=>$course->id))) {
+                            // supplied bad mapping, should not be possible since user
+                            // had to pick mapping
                             $status = false;
+                            import_cleanup($importcode);
+                            echo $OUTPUT->notification(get_string('importfailed', 'grades'));
                             break 3;
                         }
-                        $studentid = $user->id;
-                    break;
-                    case 'username':
-                        if (!$user = $DB->get_record('user', array('username' => $value))) {
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with username \"$value\"");
+
+                        // check if grade item is locked if so, abort
+                        if ($gradeitem->is_locked()) {
                             $status = false;
+                            import_cleanup($importcode);
+                            echo $OUTPUT->notification(get_string('gradeitemlocked', 'grades'));
                             break 3;
                         }
-                        $studentid = $user->id;
-                    break;
-                    case 'new':
-                        // first check if header is already in temp database
-
-                        if (empty($newgradeitems[$key])) {
 
-                            $newgradeitem = new stdClass();
-                            $newgradeitem->itemname = $header[$key];
-                            $newgradeitem->importcode = $importcode;
-                            $newgradeitem->importer   = $USER->id;
-
-                            // insert into new grade item buffer
-                            $newgradeitems[$key] = $DB->insert_record('grade_import_newitem', $newgradeitem);
-                        }
                         $newgrade = new stdClass();
-                        $newgrade->newgradeitem = $newgradeitems[$key];
-
-                        // if the user has a grade for this grade item
-                        if (trim($value) != '-') {
-                            // instead of omitting the grade we could insert one with finalgrade set to 0
-                            // we do not have access to grade item min grade
-                            $newgrade->finalgrade   = $value;
-                            $newgrades[] = $newgrade;
-                        }
-                    break;
-                    case 'feedback':
-                        if ($t1) {
-                            // case of an id, only maps id of a grade_item
-                            // this was idnumber
-                            if (!$gradeitem = new grade_item(array('id'=>$t1, 'courseid'=>$course->id))) {
-                                // supplied bad mapping, should not be possible since user
-                                // had to pick mapping
-                                $status = false;
-                                import_cleanup($importcode);
-                                echo $OUTPUT->notification(get_string('importfailed', 'grades'));
-                                break 3;
-                            }
-
-                            // t1 is the id of the grade item
-                            $feedback = new stdClass();
-                            $feedback->itemid   = $t1;
-                            $feedback->feedback = $value;
-                            $newfeedbacks[] = $feedback;
-                        }
-                    break;
-                    default:
-                        // existing grade items
-                        if (!empty($map[$key])) {
-                            // case of an id, only maps id of a grade_item
-                            // this was idnumber
-                            if (!$gradeitem = new grade_item(array('id'=>$map[$key], 'courseid'=>$course->id))) {
-                                // supplied bad mapping, should not be possible since user
-                                // had to pick mapping
-                                $status = false;
-                                import_cleanup($importcode);
-                                echo $OUTPUT->notification(get_string('importfailed', 'grades'));
-                                break 3;
-                            }
-
-                            // check if grade item is locked if so, abort
-                            if ($gradeitem->is_locked()) {
-                                $status = false;
-                                import_cleanup($importcode);
-                                echo $OUTPUT->notification(get_string('gradeitemlocked', 'grades'));
-                                break 3;
-                            }
-
-                            $newgrade = new stdClass();
-                            $newgrade->itemid     = $gradeitem->id;
-                            if ($gradeitem->gradetype == GRADE_TYPE_SCALE and $verbosescales) {
-                                if ($value === '' or $value == '-') {
-                                    $value = null; // no grade
-                                } else {
-                                    $scale = $gradeitem->load_scale();
-                                    $scales = explode(',', $scale->scale);
-                                    $scales = array_map('trim', $scales); //hack - trim whitespace around scale options
-                                    array_unshift($scales, '-'); // scales start at key 1
-                                    $key = array_search($value, $scales);
-                                    if ($key === false) {
-                                        echo "<br/>t0 is $t0";
-                                        echo "<br/>grade is $value";
-                                        $status = false;
-                                        import_cleanup($importcode);
-                                        echo $OUTPUT->notification(get_string('badgrade', 'grades'));
-                                        break 3;
-                                    }
-                                    $value = $key;
-                                }
-                                $newgrade->finalgrade = $value;
+                        $newgrade->itemid     = $gradeitem->id;
+                        if ($gradeitem->gradetype == GRADE_TYPE_SCALE and $verbosescales) {
+                            if ($value === '' or $value == '-') {
+                                $value = null; // no grade
                             } else {
-                                if ($value === '' or $value == '-') {
-                                    $value = null; // no grade
-
-                                } else if (!is_numeric($value)) {
-                                // non numeric grade value supplied, possibly mapped wrong column
+                                $scale = $gradeitem->load_scale();
+                                $scales = explode(',', $scale->scale);
+                                $scales = array_map('trim', $scales); //hack - trim whitespace around scale options
+                                array_unshift($scales, '-'); // scales start at key 1
+                                $key = array_search($value, $scales);
+                                if ($key === false) {
                                     echo "<br/>t0 is $t0";
                                     echo "<br/>grade is $value";
                                     $status = false;
@@ -404,94 +346,98 @@ if ($formdata = $mform->get_data()) {
                                     echo $OUTPUT->notification(get_string('badgrade', 'grades'));
                                     break 3;
                                 }
-                                $newgrade->finalgrade = $value;
+                                $value = $key;
                             }
-                            $newgrades[] = $newgrade;
-                        } // otherwise, we ignore this column altogether
-                          // because user has chosen to ignore them (e.g. institution, address etc)
-                    break;
-                }
-            }
-
-            // no user mapping supplied at all, or user mapping failed
-            if (empty($studentid) || !is_numeric($studentid)) {
-                // user not found, abort whole import
-                $status = false;
-                import_cleanup($importcode);
-                echo $OUTPUT->notification('user mapping error, could not find user!');
+                            $newgrade->finalgrade = $value;
+                        } else {
+                            if ($value === '' or $value == '-') {
+                                $value = null; // no grade
+
+                            } else if (!is_numeric($value)) {
+                            // non numeric grade value supplied, possibly mapped wrong column
+                                echo "<br/>t0 is $t0";
+                                echo "<br/>grade is $value";
+                                $status = false;
+                                import_cleanup($importcode);
+                                echo $OUTPUT->notification(get_string('badgrade', 'grades'));
+                                break 3;
+                            }
+                            $newgrade->finalgrade = $value;
+                        }
+                        $newgrades[] = $newgrade;
+                    } // otherwise, we ignore this column altogether
+                      // because user has chosen to ignore them (e.g. institution, address etc)
                 break;
             }
+        }
 
-            if ($separatemode and !groups_is_member($currentgroup, $studentid)) {
-                // not allowed to import into this group, abort
-                $status = false;
-                import_cleanup($importcode);
-                echo $OUTPUT->notification('user not member of current group, can not update!');
-                break;
-            }
+        // no user mapping supplied at all, or user mapping failed
+        if (empty($studentid) || !is_numeric($studentid)) {
+            // user not found, abort whole import
+            $status = false;
+            import_cleanup($importcode);
+            echo $OUTPUT->notification('user mapping error, could not find user!');
+            break;
+        }
 
-            // insert results of this students into buffer
-            if ($status and !empty($newgrades)) {
+        if ($separatemode and !groups_is_member($currentgroup, $studentid)) {
+            // not allowed to import into this group, abort
+            $status = false;
+            import_cleanup($importcode);
+            echo $OUTPUT->notification('user not member of current group, can not update!');
+            break;
+        }
 
-                foreach ($newgrades as $newgrade) {
+        // insert results of this students into buffer
+        if ($status and !empty($newgrades)) {
 
-                    // check if grade_grade is locked and if so, abort
-                    if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid'=>$newgrade->itemid, 'userid'=>$studentid))) {
-                        if ($grade_grade->is_locked()) {
-                            // individual grade locked
-                            $status = false;
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification(get_string('gradelocked', 'grades'));
-                            break 2;
-                        }
-                    }
+            foreach ($newgrades as $newgrade) {
 
-                    $newgrade->importcode = $importcode;
-                    $newgrade->userid     = $studentid;
-                    $newgrade->importer   = $USER->id;
-                    $DB->insert_record('grade_import_values', $newgrade);
-                }
-            }
-
-            // updating/inserting all comments here
-            if ($status and !empty($newfeedbacks)) {
-                foreach ($newfeedbacks as $newfeedback) {
-                    $sql = "SELECT *
-                              FROM {grade_import_values}
-                             WHERE importcode=? AND userid=? AND itemid=? AND importer=?";
-                    if ($feedback = $DB->get_record_sql($sql, array($importcode, $studentid, $newfeedback->itemid, $USER->id))) {
-                        $newfeedback->id = $feedback->id;
-                        $DB->update_record('grade_import_values', $newfeedback);
-
-                    } else {
-                        // the grade item for this is not updated
-                        $newfeedback->importcode = $importcode;
-                        $newfeedback->userid     = $studentid;
-                        $newfeedback->importer   = $USER->id;
-                        $DB->insert_record('grade_import_values', $newfeedback);
+                // check if grade_grade is locked and if so, abort
+                if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid'=>$newgrade->itemid, 'userid'=>$studentid))) {
+                    if ($grade_grade->is_locked()) {
+                        // individual grade locked
+                        $status = false;
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification(get_string('gradelocked', 'grades'));
+                        break 2;
                     }
                 }
+
+                $newgrade->importcode = $importcode;
+                $newgrade->userid     = $studentid;
+                $newgrade->importer   = $USER->id;
+                $DB->insert_record('grade_import_values', $newgrade);
             }
         }
 
-        /// at this stage if things are all ok, we commit the changes from temp table
-        if ($status) {
-            grade_import_commit($course->id, $importcode);
+        // updating/inserting all comments here
+        if ($status and !empty($newfeedbacks)) {
+            foreach ($newfeedbacks as $newfeedback) {
+                $sql = "SELECT *
+                          FROM {grade_import_values}
+                         WHERE importcode=? AND userid=? AND itemid=? AND importer=?";
+                if ($feedback = $DB->get_record_sql($sql, array($importcode, $studentid, $newfeedback->itemid, $USER->id))) {
+                    $newfeedback->id = $feedback->id;
+                    $DB->update_record('grade_import_values', $newfeedback);
+
+                } else {
+                    // the grade item for this is not updated
+                    $newfeedback->importcode = $importcode;
+                    $newfeedback->userid     = $studentid;
+                    $newfeedback->importer   = $USER->id;
+                    $DB->insert_record('grade_import_values', $newfeedback);
+                }
+            }
         }
-        // temporary file can go now
-        fclose($fp);
-        unlink($filename);
-    } else {
-        print_error('cannotreadfile');
     }
 
+    /// at this stage if things are all ok, we commit the changes from temp table
+    if ($status) {
+        grade_import_commit($course->id, $importcode);
+    }
 } else {
-    groups_print_course_menu($course, 'index.php?id='.$id);
-    echo '<div class="clearer"></div>';
-
-    // display the standard upload file form
-    $mform->display();
-}
-
-echo $OUTPUT->footer();
-
+    // If data hasn't been submitted then display the data mapping form.
+    $mform2->display();
+    echo $OUTPUT->footer();
+}
\ No newline at end of file
index 76514b3..9723be2 100644 (file)
@@ -118,11 +118,11 @@ class grade_import_mapping_form extends moodleform {
         $mform->setType('map', PARAM_INT);
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
+        $mform->addElement('hidden', 'iid');
+        $mform->setType('iid', PARAM_INT);
         $mform->addElement('hidden', 'importcode');
         $mform->setType('importcode', PARAM_FILE);
         $mform->addElement('hidden', 'verbosescales', 1);
-        $mform->setType('separator', PARAM_ALPHA);
-        $mform->addElement('hidden', 'separator', 'comma');
         $mform->setType('verbosescales', PARAM_INT);
         $mform->addElement('hidden', 'groupid', groups_get_course_group($COURSE));
         $mform->setType('groupid', PARAM_INT);
index a26537b..36e493e 100644 (file)
@@ -107,7 +107,7 @@ grade_regrade_final_grades($courseid);
 
 // Perform actions
 if (!empty($target) && !empty($action) && confirm_sesskey()) {
-    grade_report_grader::process_action($target, $action);
+    grade_report_grader::do_process_action($target, $action);
 }
 
 $reportname = get_string('pluginname', 'gradereport_grader');
index fccb042..2f9d0d4 100644 (file)
@@ -1584,13 +1584,17 @@ class grade_report_grader extends grade_report {
         return $icon;
     }
 
+    public function process_action($target, $action) {
+        return self::do_process_action($target, $action);
+    }
+
     /**
      * Processes a single action against a category, grade_item or grade.
      * @param string $target eid ({type}{id}, e.g. c4 for category4)
      * @param string $action Which action to take (edit, delete etc...)
      * @return
      */
-    public function process_action($target, $action) {
+    public static function do_process_action($target, $action) {
         // TODO: this code should be in some grade_tree static method
         $targettype = substr($target, 0, 1);
         $targetid = substr($target, 1);
index dbf755f..42835f0 100644 (file)
@@ -90,7 +90,6 @@ $string['bookmarkthispage'] = 'bookmark this page';
 $string['cachejs'] = 'Cache Javascript';
 $string['cachejs_help'] = 'Javascript caching and compression greatly improves page loading performance. it is strongly recommended for production sites. Developers will probably want to disable this feature.';
 $string['cachetext'] = 'Text cache lifetime';
-$string['cachetype'] = 'Cache type';
 $string['calendarexportsalt'] = 'Calendar export salt';
 $string['calendarsettings'] = 'Calendar';
 $string['calendar_weekend'] = 'Weekend days';
@@ -143,7 +142,6 @@ $string['configautolang'] = 'Detect default language from browser setting, if di
 $string['configautologinguests'] = 'Should visitors be logged in as guests automatically when entering courses with guest access?';
 $string['configbloglevel'] = 'This setting allows you to restrict the level to which user blogs can be viewed on this site.  Note that they specify the maximum context of the VIEWER not the poster or the types of blog posts.  Blogs can also be disabled completely if you don\'t want them at all.';
 $string['configcachetext'] = 'For larger sites or sites that use text filters, this setting can really speed things up.  Copies of texts will be retained in their processed form for the time specified here.  Setting this too small may actually slow things down slightly,  but setting it too large may mean texts take too long to refresh (with new links, for example).';
-$string['configcachetype'] = 'Select a type of cache for Moodle to use. This will only configure the cache, remember to enable rcache so that the cache is used for something. Use <strong>only</strong> if you need to reduce the load on the database system -- otherwise Moodle will actually run slower. Medium-traffic sites may see benefits using \'internal\'. A single webserver with eAccelerator or Turckmmcache installed <em>with the shared memory options enabled</em> should try \'eaccelerator\'. If you have a multiple-server setup, and you have one or more memcached daemons running and the PHP-memcached extension, select \'memcached\' and configure the memached options below. <br /><strong>Note:</strong> make sure you test performance under load and tune accordingly -- the caches can make your site slower. In high-traffic situations, eAccelerator and memcached can yield the most benefits, but have the higher costs in CPU usage on the webserver.';
 $string['configcalendarexportsalt'] = 'This random text is used for improving of security of authentication tokens used for exporting of calendars. Please note that all current tokens are invalidated if you change this hash salt.';
 $string['configclamactlikevirus'] = 'Treat files like viruses';
 $string['configclamdonothing'] = 'Treat files as OK';
@@ -229,7 +227,6 @@ $string['configgradebookroles'] = 'This setting allows you to control who appear
 $string['configgradeexport'] = 'Choose which gradebook export formats are your primary methods for exporting grades.  Chosen plugins will then set and use a "last exported" field for every grade.  For example, this might result in exported records being identified as being "new" or "updated".  If you are not sure about this then leave everything unchecked.';
 $string['confighiddenuserfields'] = 'Select which user information fields you wish to hide from other users other than course teachers/admins. This will increase student privacy. Hold CTRL key to select multiple fields.';
 $string['configidnumber'] = 'This option specifies whether (a) Users are not be asked for an ID number at all, (b) Users are asked for an ID number but can leave it blank or (c) Users are asked for an ID Number and cannot leave it blank. If given the User\'s ID number is displayed in their Profile.';
-$string['configintcachemax'] = 'For internal cache only. Maximum number of records to keep in the cache. Recommended value: 50. Use lower values to reduce memory usage.';
 $string['configintro'] = 'On this page you can specify a number of configuration variables that help make Moodle work properly on your server.  Don\'t worry too much about it - the defaults will usually work fine and you can always come back to this page later and change these settings.';
 $string['configintroadmin'] = 'On this page you should configure your main administrator account which will have complete control over the site. Make sure you give it a secure username and password as well as a valid email address.  You can create more admin accounts later on.';
 $string['configintrosite'] = 'This page allows you to configure the front page and name of this new site.  You can come back here later to change these settings any time using the Administration menus.';
@@ -248,8 +245,6 @@ $string['configmaxbytes'] = 'This specifies a maximum size that uploaded files c
 $string['configmaxconsecutiveidentchars'] = 'Passwords must not have more than this number of consecutive identical characters. Use 0 to disable this check.';
 $string['configmaxeditingtime'] = 'This specifies the amount of time people have to re-edit forum postings, glossary comments etc.  Usually 30 minutes is a good value.';
 $string['configmaxevents'] = 'Events to Lookahead';
-$string['configmemcachedhosts'] = 'For memcached. Comma-separated list of hosts that are running the memcached daemon. Use IP addresses to avoid DNS latency. memcached does not behave well if you add/remove hosts on a running setup.';
-$string['configmemcachedpconn'] = 'For memcached. Use persistent connections. Use carefully -- it can make Apache/PHP crash after a restart of the memcached daemon.';
 $string['configmessaging'] = 'Should the messaging system between site users be enabled?';
 $string['configmessagingallowemailoverride'] = 'Allow users to have email message notifications sent to an email address other than the email address in their profile';
 $string['configmessaginghidereadnotifications'] = 'Hide read notifications of events like forum posts when viewing messaging history';
@@ -286,8 +281,6 @@ $string['configproxyport'] = 'If this server needs to use a proxy computer, then
 $string['configproxytype'] = 'Type of web proxy (PHP5 and cURL extension required for SOCKS5 support).';
 $string['configproxyuser'] = 'Username needed to access internet through proxy if required, empty if none (PHP cURL extension required).';
 $string['configquarantinedir'] = 'If you want clam AV to move infected files to a quarantine directory, enter it here. It must be writable by the webserver.  If you leave this blank, or if you enter a directory that doesn\'t exist or isn\'t writable, infected files will be deleted.  Do not include a trailing slash.';
-$string['configrcache'] = 'Use the cache to store database records. Remember to set \'cachetype\' as well!';
-$string['configrcachettl'] = 'Time-to-live for cached records, in seconds. Use a short (&lt;15) value here.';
 $string['configrecaptchaprivatekey'] = 'String of characters used to communicate between your Moodle server and the recaptcha server. Obtain one for this site by visiting http://www.google.com/recaptcha';
 $string['configrecaptchapublickey'] = 'String of characters used to display the reCAPTCHA element in the signup form. Generated by http://www.google.com/recaptcha';
 $string['configrequestcategoryselection'] = 'Allow the selection of a category when requesting a course.';
@@ -597,7 +590,6 @@ $string['includemoduleuserdata'] = 'Include module user data';
 $string['incompatibleblocks'] = 'Incompatible blocks';
 $string['installhijacked'] = 'Installation must be finished from the original IP address, sorry.';
 $string['installsessionerror'] = 'Can not initialise PHP session, please verify that your browser accepts cookies.';
-$string['intcachemax'] = 'Int. cache max';
 $string['intlrecommended'] = 'Intl extension is used to improve internationalization support, such as locale aware sorting.';
 $string['invalidsection'] = 'Invalid section.';
 $string['invaliduserchangeme'] = 'Username "changeme" is reserved -- you cannot create an account with it.';
@@ -681,8 +673,6 @@ $string['mediapluginswf'] = 'Enable .swf filter';
 $string['mediapluginswfnote'] = 'As a default security measure, normal users should not be allowed to embed swf flash files.';
 $string['mediapluginwmv'] = 'Enable .wmv filter';
 $string['mediapluginyoutube'] = 'Enable YouTube links filter';
-$string['memcachedhosts'] = 'memcached hosts';
-$string['memcachedpconn'] = 'memcached use persistent connections';
 $string['messaging'] = 'Enable messaging system';
 $string['messagingallowemailoverride'] = 'Notification email override';
 $string['messaginghidereadnotifications'] = 'Hide read notifications';
@@ -866,8 +856,6 @@ $string['questioncwqpfscheck'] = 'One or more \'random\' questions in a quiz are
 $string['questioncwqpfsok'] = 'Good. There are no \'random\' questions in your quizzes that are set up to select questions from a mixture of shared and unshared question categories.';
 $string['questiontype'] = 'Question type';
 $string['questiontypes'] = 'Question types';
-$string['rcache'] = 'Record cache';
-$string['rcachettl'] = 'Record cache TTL';
 $string['recaptchaprivatekey'] = 'ReCAPTCHA private key';
 $string['recaptchapublickey'] = 'ReCAPTCHA public key';
 $string['register'] = 'Register your site';
index 23e8ecf..54ee712 100644 (file)
@@ -161,6 +161,7 @@ $string['showglobalevents'] = 'Show global events';
 $string['showgroupsevents'] = 'Show group events';
 $string['showuserevents'] = 'Show user events';
 $string['shown'] = 'shown';
+$string['siteevents'] = 'Site events';
 $string['spanningevents'] = 'Events underway';
 $string['subscriptions'] = 'Subscriptions';
 $string['subscriptionname'] = 'Calendar name';
index 5594c8c..1a2c751 100644 (file)
@@ -40,7 +40,6 @@ $string['blocknoncontacts'] = 'Prevent non-contacts from messaging me';
 $string['contactlistempty'] = 'Your contact list is empty';
 $string['contacts'] = 'Contacts';
 $string['context'] = 'context';
-$string['couldnotfindpreference'] = 'Could not load preference {$a}. Does the component and name you supplied to message_send() match a row in message_providers? Message providers must appear in the database so users can configure how they will be notified when they receive messages.';
 $string['defaultmessageoutputs'] = 'Default message outputs';
 $string['defaults'] = 'Defaults';
 $string['deletemessagesdays'] = 'Number of days before old messages are automatically deleted';
index e5b4760..2eca489 100644 (file)
@@ -5075,16 +5075,16 @@ class admin_setting_manageenrols extends admin_setting {
                 if ($updowncount > 1) {
                     $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
                     $updown .= "<a href=\"$aurl\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /></a>&nbsp;";
                 } else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
                 }
                 if ($updowncount < $enrolcount) {
                     $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
                     $updown .= "<a href=\"$aurl\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" /></a>";
                 } else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
                 }
                 ++$updowncount;
             }
@@ -5606,17 +5606,17 @@ class admin_setting_manageauths extends admin_setting {
             if ($enabled) {
                 if ($updowncount > 1) {
                     $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
                 }
                 if ($updowncount < $authcount) {
                     $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
                 }
                 ++ $updowncount;
             }
@@ -5773,17 +5773,17 @@ class admin_setting_manageeditors extends admin_setting {
             if ($enabled) {
                 if ($updowncount > 1) {
                     $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
                 }
                 if ($updowncount < $editorcount) {
                     $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
                 }
                 ++ $updowncount;
             }
@@ -6000,7 +6000,7 @@ class admin_setting_manageformats extends admin_setting {
 
         $cnt = 0;
         $defaultformat = get_config('moodlecourse', 'format');
-        $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon'));
+        $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
         foreach ($formats as $format) {
             $url = new moodle_url('/admin/courseformats.php',
                     array('sesskey' => sesskey(), 'format' => $format->name));
@@ -6021,13 +6021,13 @@ class admin_setting_manageformats extends admin_setting {
             $updown = '';
             if ($cnt) {
                 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
-                    $OUTPUT->pix_icon('t/up', $txt->up, 'moodle')). '&nbsp;';
+                    $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
             } else {
                 $updown .= $spacer;
             }
             if ($cnt < count($formats) - 1) {
                 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
-                    $OUTPUT->pix_icon('t/down', $txt->down, 'moodle'));
+                    $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
             } else {
                 $updown .= $spacer;
             }
@@ -6862,18 +6862,19 @@ class admin_setting_managerepository extends admin_setting {
 
                 // Display up/down link
                 $updown = '';
-                $spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
+                // Should be done with CSS instead.
+                $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
 
                 if ($updowncount > 1) {
                     $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
                 }
                 else {
                     $updown .= $spacer;
                 }
                 if ($updowncount < $totalinstances) {
                     $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
                 }
                 else {
                     $updown .= $spacer;
index 3c2936b..1f6bf3d 100644 (file)
@@ -232,7 +232,7 @@ class iCalendar_component {
     
     function unserialize($string) {
         $string = rfc2445_unfold($string); // Unfold any long lines
-        $lines = explode(RFC2445_CRLF, $string); // Create an array of lines
+        $lines = preg_split("<".RFC2445_CRLF."|\n|\r>", $string, 0, PREG_SPLIT_NO_EMPTY); // Create an array of lines.
         
         $components = array(); // Initialise a stack of components
         $this->clear_errors();
index 1c6154b..582b265 100644 (file)
@@ -2,4 +2,5 @@ Description of Bennu library import - customised library by author, this version
 
 modifications:
 1/ removed ereg functions deprecated as of php 5.3 (18 Nov 2009)
-2/ replaced mbstring functions with moodle textlib (28 Nov 2011)
\ No newline at end of file
+2/ replaced mbstring functions with moodle textlib (28 Nov 2011)
+3/ replaced explode in iCalendar_component::unserialize() with preg_split to support various line breaks (20 Nov 2012)
\ No newline at end of file
index 65c3046..d630e21 100644 (file)
@@ -1473,6 +1473,19 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012111200.01);
     }
 
+    if ($oldversion < 2012111601.01) {
+        // Clea up after old shared memory caching support.
+        unset_config('cachetype');
+        unset_config('rcache');
+        unset_config('rcachettl');
+        unset_config('intcachemax');
+        unset_config('memcachedhosts');
+        unset_config('memcachedpconn');
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2012111601.01);
+    }
+
 
     return true;
 }
diff --git a/lib/eaccelerator.class.php b/lib/eaccelerator.class.php
deleted file mode 100644 (file)
index bde70b9..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This class abstracts eaccelerator/turckmmcache
- * API to provide
- *
- * - get()
- * - set()
- * - delete()
- * - getforfill()
- * - releaseforfill()
- *
- * Note: do NOT store booleans here. For compatibility with
- * memcached, a false value is indistinguisable from a
- * "not found in cache" response.
- *
- * @package    core
- * @subpackage lib
- * @copyright  Martin Langhoff <martin@catalyst.net.nz>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- *
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @package moodlecore
- */
-class eaccelerator {
-
-    /**
-     * @todo Document this function
-     *
-     * @global object
-     */
-    function eaccelerator() {
-        global $CFG;
-        if ( function_exists('eaccelerator_get')) {
-            $this->mode = 'eaccelerator';
-        } elseif (function_exists('mmcache_get')) {
-            $this->mode = 'mmcache';
-        } else {
-            debugging("\$CFG->eaccelerator is set to true but the required functions are not available. You need to have either eaccelerator or turckmmcache extensions installed, compiled with the shmem keys option enabled.");
-        }
-
-        $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
-    }
-
-    /**
-     * The status of the eaccelerator, if it has been established
-     * this will return true
-     *
-     * @return bool
-     */
-    function status() {
-        if (isset($this->mode)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @todo Document this function
-     *
-     * @param string $key
-     * @param string $value
-     * @param int $ttl
-     * @return mixed
-     */
-    function set($key, $value, $ttl=0) {
-        $set    = $this->mode . '_put';
-        $unlock = $this->mode . '_unlock';
-
-        // we may have acquired a lock via getforfill
-        // release if it exists
-        @$unlock($this->prefix . $key . '_forfill');
-
-        return $set($this->prefix . $key, serialize($value), $ttl);
-    }
-
-    /**
-     * @todo Document this function
-     *
-     * @param string $key
-     * @return string|bool String if success else false
-     */
-    function get($key) {
-        $fn = $this->mode . '_get';
-        $rec = $fn($this->prefix . $key);
-        if (is_null($rec)) {
-            return false;
-        }
-        return unserialize($rec);
-    }
-
-    /**
-     * @todo Document this function
-     *
-     * @param string $key
-     * @return mixed
-     */
-    function delete($key) {
-        $fn = $this->mode . '_rm';
-        return $fn($this->prefix . $key);
-    }
-
-    /**
-     * In the simple case, this function will
-     * get the cached value if available. If the entry
-     * is not cached, it will try to get an exclusive
-     * lock that announces that this process will
-     * populate the cache.
-     *
-     * If we fail to get the lock -- this means another
-     * process is doing it.
-     * so we wait (block) for a few microseconds while we wait for
-     * the cache to be filled or the lock to timeout.
-     *
-     * If you get a false from this call, you _must_
-     * populate the cache ASAP or indicate that
-     * you won't by calling releaseforfill().
-     *
-     * This technique forces serialisation and so helps deal
-     * with thundering herd scenarios where a lot of clients
-     * ask the for the same idempotent (and costly) operation.
-     * The implementation is based on suggestions in this message
-     * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
-     *
-     * @param $key string
-     * @return mixed on cache hit, false otherwise
-     */
-    function getforfill ($key) {
-        $get    = $this->mode . '_get';
-        $lock   = $this->mode . '_lock';
-
-        $rec = $get($this->prefix . $key);
-        if (!is_null($rec)) {
-            return unserialize($rec);
-        }
-        if ($lock($this->prefix . $key . '_forfill')) {
-            // we obtained the _forfill lock
-            // our caller will compute and set the value
-            return false;
-        }
-        // someone else has the lock
-        // "block" till we can get the value
-        // actually, loop .05s waiting for it
-        for ($n=0;$n<5;$n++) {
-            usleep(10000);
-            $rec = $get($this->prefix . $key);
-            if (!is_null($rec)) {
-                return unserialize($rec);
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Release the exclusive lock obtained by
-     * getforfill(). See getforfill()
-     * for more details.
-     *
-     * @param $key string
-     * @return bool
-     */
-    function releaseforfill ($key) {
-        $unlock = $this->mode . '_unlock';
-        return $unlock($this->prefix . $key . '_forfill');
-    }
-}
-
-?>
\ No newline at end of file
index 5e39e77..e5e1830 100644 (file)
@@ -2227,15 +2227,15 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
         // switch next two lines for ol li containers for form items.
         //        $this->_elementTemplates=array('default'=>"\n\t\t".'<li class="fitem"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class="qfelement<!-- BEGIN error --> error<!-- END error --> {type}"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></li>');
         $this->_elementTemplates = array(
-        'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
+        'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
 
         'actionbuttons'=>"\n\t\t".'<div id="{id}" class="fitem fitem_actionbuttons fitem_{type}"><div class="felement {type}">{element}</div></div>',
 
-        'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
+        'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
 
-        'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}&nbsp;</div></div>',
+        'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}&nbsp;</div></div>',
 
-'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
+        'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
 
         'nodisplay'=>'');
 
index fa0dfc0..6044ea1 100644 (file)
@@ -111,7 +111,7 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
     // Get the height of the div at this point before we shrink it if required
     var height = this.div.get('offsetHeight');
     var collapsedimage = 't/collapsed'; // ltr mode
-    if ( Y.one(document.body).hasClass('dir-rtl') ) {
+    if (right_to_left()) {
         collapsedimage = 't/collapsed_rtl';
     } else {
         collapsedimage = 't/collapsed';
@@ -140,7 +140,7 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
     animation.on('end', function() {
         this.div.toggleClass('collapsed');
         var collapsedimage = 't/collapsed'; // ltr mode
-        if ( Y.one(document.body).hasClass('dir-rtl') ) {
+        if (right_to_left()) {
             collapsedimage = 't/collapsed_rtl';
             } else {
             collapsedimage = 't/collapsed';
@@ -1209,6 +1209,20 @@ function getElementsByClassName(oElm, strTagName, name) {
     return (arrReturnElements)
 }
 
+/**
+ * Return whether we are in right to left mode or not.
+ *
+ * @return boolean
+ */
+function right_to_left() {
+    var body = Y.one('body');
+    var rtl = false;
+    if (body && body.hasClass('dir-rtl')) {
+        rtl = true;
+    }
+    return rtl;
+}
+
 function openpopup(event, args) {
 
     if (event) {
diff --git a/lib/memcached.class.php b/lib/memcached.class.php
deleted file mode 100644 (file)
index 35ac0f4..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * @package    core
- * @subpackage lib
- * @copyright  Martin Langhoff <martin@catalyst.net.nz>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * This class abstracts PHP's PECL memcached
- * API to provide
- *
- * - get()
- * - set()
- * - delete()
- * - getforfill()
- * - releaseforfill()
- *
- * Author: Martin Langhoff <martin@catalyst.net.nz>
- *
- * Note: do NOT store booleans here. With memcached, a false value
- * is indistinguisable from a "not found in cache" response.
- *
- * @package   moodlecore
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-class memcached {
-
-    function memcached() {
-        global $CFG;
-
-        if (!function_exists('memcache_connect')) {
-            debugging("Memcached is set to true but the memcached extension is not installed");
-            return false;
-        }
-        $this->_cache = new Memcache;
-
-        $hosts = explode(',', $CFG->memcachedhosts);
-        if (count($hosts) === 1 && !empty($CFG->memcachedpconn)) {
-            // the faster pconnect is only available
-            // for single-server setups
-            // NOTE: PHP-PECL client is buggy and pconnect()
-            // will segfault if the server is unavailable
-            $this->_cache->pconnect($hosts[0]);
-        } else {
-            // multi-host setup will share key space
-            foreach ($hosts as $host) {
-                $host = trim($host);
-                $this->_cache->addServer($host);
-            }
-        }
-
-        $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
-    }
-
-    function status() {
-        if (is_object($this->_cache)) {
-            return true;
-        }
-        return false;
-    }
-
-    function set($key, $value, $ttl=0) {
-
-        // we may have acquired a lock via getforfill
-        // release if it exists
-        @$this->_cache->delete($this->prefix . $key . '_forfill');
-
-        return $this->_cache->set($this->prefix . $key, $value, false);
-    }
-
-    function get($key) {
-        $rec = $this->_cache->get($this->prefix . $key);
-        return $rec;
-    }
-
-    function delete($key) {
-        return $this->_cache->delete($this->prefix . $key);
-    }
-
-    /**
-     * In the simple case, this function will
-     * get the cached value if available. If the entry
-     * is not cached, it will try to get an exclusive
-     * lock that announces that this process will
-     * populate the cache.
-     *
-     * If we fail to get the lock -- this means another
-     * process is doing it.
-     * so we wait (block) for a few microseconds while we wait for
-     * the cache to be filled or the lock to timeout.
-     *
-     * If you get a false from this call, you _must_
-     * populate the cache ASAP or indicate that
-     * you won't by calling releaseforfill().
-     *
-     * This technique forces serialisation and so helps deal
-     * with thundering herd scenarios where a lot of clients
-     * ask the for the same idempotent (and costly) operation.
-     * The implementation is based on suggestions in this message
-     * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
-     *
-     * @param $key string
-     * @return mixed on cache hit, NULL otherwise
-     */
-    function getforfill ($key) {
-
-        $rec = $this->_cache->get($this->prefix . $key);
-        if ($rec) {
-            return $rec;
-        }
-        if ($this->_cache->add($this->prefix . $key . '_forfill', 'true', false, 1)) {
-            // we obtained the _forfill lock
-            // our caller will compute and set the value
-            return false;
-        }
-        // someone else has the lock
-        // "block" till we can get the value
-        // actually, loop .05s waiting for it
-        for ($n=0;$n<5;$n++) {
-            usleep(10000);
-            $rec = $this->_cache->get($this->prefix . $key);
-            if ($rec) {
-                return $rec;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Release the exclusive lock obtained by
-     * getforfill(). See getforfill()
-     * for more details.
-     *
-     * @param $key string
-     * @return bool
-     */
-    function releaseforfill ($key) {
-        return $this->_cache->delete($this->prefix . $key . '_forfill');
-    }
-}
index 3ab00ea..d464106 100644 (file)
@@ -155,10 +155,11 @@ function message_send($eventdata) {
         if (isset($defaultpreferences->{$defaultpreference})) {
             $permitted = $defaultpreferences->{$defaultpreference};
         } else {
-            //MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
-            //exist in the message_provider table (thus there is no default settings for them)
-            $preferrormsg = get_string('couldnotfindpreference', 'message', $defaultpreference);
-            throw new coding_exception($preferrormsg,'blah');
+            // MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
+            // exist in the message_provider table (thus there is no default settings for them).
+            $preferrormsg = "Could not load preference $defaultpreference. Make sure the component and name you supplied
+                    to message_send() are valid.";
+            throw new coding_exception($preferrormsg);
         }
 
         // Find out if user has configured this output
index 7279079..62648b8 100644 (file)
@@ -1589,7 +1589,7 @@ function set_cache_flag($type, $name, $value, $expiry=NULL) {
 
     if ($f = $DB->get_record('cache_flags', array('name'=>$name, 'flagtype'=>$type), '*', IGNORE_MULTIPLE)) { // this is a potential problem in DEBUG_DEVELOPER
         if ($f->value == $value and $f->expiry == $expiry and $f->timemodified == $timemodified) {
-            return true; //no need to update; helps rcache too
+            return true; //no need to update
         }
         $f->value        = $value;
         $f->expiry       = $expiry;
@@ -10482,15 +10482,6 @@ function get_performance_info() {
         $info['txt'] .= "Session: {$info['sessionsize']} ";
     }
 
-/*    if (isset($rcache->hits) && isset($rcache->misses)) {
-        $info['rcachehits'] = $rcache->hits;
-        $info['rcachemisses'] = $rcache->misses;
-        $info['html'] .= '<span class="rcache">Record cache hit/miss ratio : '.
-            "{$rcache->hits}/{$rcache->misses}</span> ";
-        $info['txt'] .= 'rcache: '.
-            "{$rcache->hits}/{$rcache->misses} ";
-    }*/
-
     if ($stats = cache_helper::get_stats()) {
         $html = '<span class="cachesused">';
         $html .= '<span class="cache-stats-heading">Caches interaction by definition then store</span>';
index 90c5c73..1b53e75 100644 (file)
@@ -344,13 +344,6 @@ global $COURSE;
  */
 global $OUTPUT;
 
-/**
- * Shared memory cache.
- * @global object $MCACHE
- * @name $MCACHE
- */
-global $MCACHE;
-
 /**
  * Cache used within grouplib to cache data within current request only.
  *
@@ -592,42 +585,6 @@ if (!empty($CFG->version) and $CFG->version < 2007101509) {
     die;
 }
 
-// Shared-Memory cache init -- will set $MCACHE
-// $MCACHE is a global object that offers at least add(), set() and delete()
-// with similar semantics to the memcached PHP API http://php.net/memcache
-// Ensure we define rcache - so we can later check for it
-// with a really fast and unambiguous $CFG->rcache === false
-if (!empty($CFG->cachetype)) {
-    if (empty($CFG->rcache)) {
-        $CFG->rcache = false;
-    } else {
-        $CFG->rcache = true;
-    }
-
-    // do not try to initialize if cache disabled
-    if (!$CFG->rcache) {
-        $CFG->cachetype = '';
-    }
-
-    if ($CFG->cachetype === 'memcached' && !empty($CFG->memcachedhosts)) {
-        if (!init_memcached()) {
-            debugging("Error initialising memcached");
-            $CFG->cachetype = '';
-            $CFG->rcache = false;
-        }
-    } else if ($CFG->cachetype === 'eaccelerator') {
-        if (!init_eaccelerator()) {
-            debugging("Error initialising eaccelerator cache");
-            $CFG->cachetype = '';
-            $CFG->rcache = false;
-        }
-    }
-
-} else { // just make sure it is defined
-    $CFG->cachetype = '';
-    $CFG->rcache    = false;
-}
-
 // Calculate and set $CFG->ostype to be used everywhere. Possible values are:
 // - WINDOWS: for any Windows flavour.
 // - UNIX: for the rest
index 33894ad..d100654 100644 (file)
@@ -1292,41 +1292,6 @@ function make_cache_directory($directory, $exceptiononerror = true) {
     return make_writable_directory("$CFG->cachedir/$directory", $exceptiononerror);
 }
 
-
-/**
- * Initialises an Memcached instance
- * @global memcached $MCACHE
- * @return boolean Returns true if an mcached instance could be successfully initialised
- */
-function init_memcached() {
-    global $CFG, $MCACHE;
-
-    include_once($CFG->libdir . '/memcached.class.php');
-    $MCACHE = new memcached;
-    if ($MCACHE->status()) {
-        return true;
-    }
-    unset($MCACHE);
-    return false;
-}
-
-/**
- * Initialises an eAccelerator instance
- * @global eaccelerator $MCACHE
- * @return boolean Returns true if an eAccelerator instance could be successfully initialised
- */
-function init_eaccelerator() {
-    global $CFG, $MCACHE;
-
-    include_once($CFG->libdir . '/eaccelerator.class.php');
-    $MCACHE = new eaccelerator;
-    if ($MCACHE->status()) {
-        return true;
-    }
-    unset($MCACHE);
-    return false;
-}
-
 /**
  * Checks if current user is a web crawler.
  *
@@ -1349,12 +1314,18 @@ function is_web_crawler() {
             return true;
         } else if (strpos($_SERVER['HTTP_USER_AGENT'], '[ZSEBOT]') !== false ) {  // Zoomspider
             return true;
-        } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSNBOT') !== false ) {  // MSN Search
+        } else if (stripos($_SERVER['HTTP_USER_AGENT'], 'msnbot') !== false ) {  // MSN Search
+            return true;
+        } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'bingbot') !== false ) {  // Bing
             return true;
         } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'Yandex') !== false ) {
             return true;
         } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'AltaVista') !== false ) {
             return true;
+        } else if (stripos($_SERVER['HTTP_USER_AGENT'], 'baiduspider') !== false ) {  // Baidu
+            return true;
+        } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'Teoma') !== false ) {  // Ask.com
+            return true;
         }
     }
     return false;
index 4281232..bfb9df9 100644 (file)
@@ -1153,10 +1153,10 @@ class flexible_table {
 
         if ($order == SORT_ASC) {
             return html_writer::empty_tag('img',
-                    array('src' => $OUTPUT->pix_url('t/down'), 'alt' => get_string('asc')));
+                    array('src' => $OUTPUT->pix_url('t/sort_asc'), 'alt' => get_string('asc'), 'class' => 'iconsort'));
         } else {
             return html_writer::empty_tag('img',
-                    array('src' => $OUTPUT->pix_url('t/up'), 'alt' => get_string('desc')));
+                    array('src' => $OUTPUT->pix_url('t/sort_desc'), 'alt' => get_string('desc'), 'class' => 'iconsort'));
         }
     }
 
index 9695adb..becf244 100644 (file)
@@ -1769,7 +1769,8 @@ class accesslib_testcase extends advanced_testcase {
 
         context_helper::reset_caches();
         context_helper::preload_course($SITE->id);
-        $this->assertEquals(7, context_inspection::test_context_cache_size()); // depends on number of default blocks
+        $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id));
+        $this->assertEquals(6 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // depends on number of default blocks
 
         // ====== assign_capability(), unassign_capability() ====================
 
@@ -2074,7 +2075,8 @@ class accesslib_testcase extends advanced_testcase {
         load_all_capabilities();
         $context = context_course::instance($testcourses[2]);
         $page = $DB->get_record('page', array('course'=>$testcourses[2]));
-        $pagecontext = context_module::instance($page->id);
+        $pagecm = get_coursemodule_from_instance('page', $page->id);
+        $pagecontext = context_module::instance($pagecm->id);
 
         $context->mark_dirty();
         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
@@ -2312,7 +2314,8 @@ class accesslib_testcase extends advanced_testcase {
 
         context_helper::reset_caches();
         preload_course_contexts($SITE->id);
-        $this->assertEquals(context_inspection::test_context_cache_size(), 1);
+        $this->assertEquals(1 + $DB->count_records('course_modules', array('course' => $SITE->id)),
+                context_inspection::test_context_cache_size());
 
         context_helper::reset_caches();
         list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx');
@@ -2358,11 +2361,11 @@ class accesslib_testcase extends advanced_testcase {
         $url = get_context_url($coursecontext);
         $this->assertFalse($url instanceof modole_url);
 
-        $page = $DB->get_record('page', array('id'=>$testpages[7]));
-        $context = context_module::instance($page->id);
+        $pagecm = get_coursemodule_from_instance('page', $testpages[7]);
+        $context = context_module::instance($pagecm->id);
         $coursecontext = get_course_context($context);
         $this->assertEquals($coursecontext->contextlevel, CONTEXT_COURSE);
-        $this->assertEquals(get_courseid_from_context($context), $page->course);
+        $this->assertEquals(get_courseid_from_context($context), $pagecm->course);
 
         $caps = fetch_context_capabilities($systemcontext);
         $this->assertTrue(is_array($caps));
index c3b796b..60ba0b9 100644 (file)
@@ -151,7 +151,7 @@ class user_picture_testcase extends advanced_testcase {
         // try legacy picture == 1
         $user1->picture = 1;
         $up1 = new user_picture($user1);
-        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=1', $up1->get_url($page, $renderer)->out(false));
+        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/'.$context1->id.'/user/icon/standard/f2?rev=1', $up1->get_url($page, $renderer)->out(false));
         $user1->picture = 11;
 
         // try valid user with picture when user context is not cached - 1 query expected
@@ -159,7 +159,7 @@ class user_picture_testcase extends advanced_testcase {
         $reads = $DB->perf_get_reads();
         $up1 = new user_picture($user1);
         $this->assertEquals($reads, $DB->perf_get_reads());
-        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
+        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/'.$context1->id.'/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
         $this->assertEquals($reads+1, $DB->perf_get_reads());
 
         // try valid user with contextid hint - no queries expected
@@ -168,7 +168,7 @@ class user_picture_testcase extends advanced_testcase {
         $reads = $DB->perf_get_reads();
         $up1 = new user_picture($user1);
         $this->assertEquals($reads, $DB->perf_get_reads());
-        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
+        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/'.$context1->id.'/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
         $this->assertEquals($reads, $DB->perf_get_reads());
 
         // try valid user without image - no queries expected
@@ -217,13 +217,13 @@ class user_picture_testcase extends advanced_testcase {
         $this->assertEquals('http://www.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=http%3A%2F%2Fwww.example.com%2Fmoodle%2Fpix%2Fu%2Ff2.png', $up2->get_url($page, $renderer)->out(false));
         // uploaded image takes precedence before gravatar
         $up1 = new user_picture($user1);
-        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
+        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/'.$context1->id.'/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
 
         // https version
         $CFG->httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot);
 
         $up1 = new user_picture($user1);
-        $this->assertEquals($CFG->httpswwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
+        $this->assertEquals($CFG->httpswwwroot.'/pluginfile.php/'.$context1->id.'/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
 
         $up3 = new user_picture($user3);
         $this->assertEquals($CFG->httpswwwroot.'/theme/image.php/standard/core/1/u/f2', $up3->get_url($page, $renderer)->out(false));
@@ -261,7 +261,7 @@ class user_picture_testcase extends advanced_testcase {
         $renderer = $page->get_renderer('core');
 
         $up1 = new user_picture($user1);
-        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/formal_white/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
+        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/'.$context1->id.'/user/icon/formal_white/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
 
         $up2 = new user_picture($user2);
         $this->assertEquals($CFG->wwwroot.'/theme/image.php/formal_white/core/1/u/f2', $up2->get_url($page, $renderer)->out(false));
index 7008e58..30a257b 100644 (file)
@@ -71,4 +71,51 @@ class core_setuplib_testcase extends basic_testcase {
         $this->assertEquals($CFG->wwwroot . '/lib/tests/setuplib_test.php',
                 get_docs_url('%%WWWROOT%%/lib/tests/setuplib_test.php'));
     }
+
+    public function test_is_web_crawler() {
+        $browsers = array(
+            'Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))',
+            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:18.0) Gecko/18.0 Firefox/18.0',
+            'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412 (KHTML, like Gecko) Safari/412',
+            'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10',
+            'Opera/9.0 (Windows NT 5.1; U; en)',
+            'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17 –Nexus',
+            'Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5',
+        );
+        $crawlers = array(
+            // Google
+            'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
+            'Googlebot/2.1 (+http://www.googlebot.com/bot.html)',
+            'Googlebot-Image/1.0',
+            // Yahoo
+            'Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)',
+            // Bing
+            'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
+            'Mozilla/5.0 (compatible; bingbot/2.0 +http://www.bing.com/bingbot.htm)',
+            // MSN
+            'msnbot/2.1',
+            // Yandex
+            'Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)',
+            'Mozilla/5.0 (compatible; YandexImages/3.0; +http://yandex.com/bots)',
+            // AltaVista
+            'AltaVista V2.0B crawler@evreka.com',
+            // ZoomSpider
+            'ZoomSpider - wrensoft.com [ZSEBOT]',
+            // Baidu
+            'Baiduspider+(+http://www.baidu.com/search/spider_jp.html)',
+            'Baiduspider+(+http://www.baidu.com/search/spider.htm)',
+            'BaiDuSpider',
+            // Ask.com
+            'User-Agent: Mozilla/2.0 (compatible; Ask Jeeves/Teoma)',
+        );
+
+        foreach ($browsers as $agent) {
+            $_SERVER['HTTP_USER_AGENT'] = $agent;
+            $this->assertFalse(is_web_crawler());
+        }
+        foreach ($crawlers as $agent) {
+            $_SERVER['HTTP_USER_AGENT'] = $agent;
+            $this->assertTrue(is_web_crawler(), "$agent should be considered a search engine");
+        }
+    }
 }
index 964123a..84be3a2 100644 (file)
@@ -1210,7 +1210,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                 echo html_writer::end_tag('td');
 
                 echo html_writer::start_tag('td', array('class' => 'summary'));
-                echo message_get_fragment($message->fullmessage, $keywords);
+                echo message_get_fragment($message->smallmessage, $keywords);
                 echo html_writer::start_tag('div', array('class' => 'link'));
 
                 //If the user clicks the context link display message sender on the left
@@ -1595,10 +1595,10 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
     ///    c.  Messages to and from user
 
     if ($courseid == SITEID) { /// admin is searching all messages
-        $m_read   = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.fullmessage, m.timecreated
+        $m_read   = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
                                             FROM {message_read} m
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
-        $m_unread = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.fullmessage, m.timecreated
+        $m_unread = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
                                             FROM {message} m
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
 
@@ -1623,10 +1623,10 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
             $params['userid'] = $userid;
         }
 
-        $m_read   = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.fullmessage, m.timecreated
+        $m_read   = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
                                             FROM {message_read} m
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
-        $m_unread = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.fullmessage, m.timecreated
+        $m_unread = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
                                             FROM {message} m
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
 
index a6dd9bc..99efb11 100644 (file)
@@ -3966,7 +3966,9 @@ class assign {
         if (!$last) {
             $buttonarray[] = $mform->createElement('submit', 'nosaveandnext', get_string('nosavebutnext', 'assign'));
         }
-        $mform->addGroup($buttonarray, 'navar', '', array(' '), false);
+        if (!empty($buttonarray)) {
+            $mform->addGroup($buttonarray, 'navar', '', array(' '), false);
+        }
     }
 
 
@@ -4095,9 +4097,9 @@ class assign {
         }
 
         if ($this->get_instance()->teamsubmission) {
-            $submission = $this->get_group_submission($USER->id, 0, false);
+            $submission = $this->get_group_submission($userid, 0, false);
         } else {
-            $submission = $this->get_user_submission($USER->id, false);
+            $submission = $this->get_user_submission($userid, false);
         }
 
         if (!$submission) {
index bd31428..e36af7b 100644 (file)
@@ -216,7 +216,7 @@ if (optional_param('sesskey', false, PARAM_BOOL) && confirm_sesskey()) {
         } else if ($action == 'finishimport') {
             $overwritesettings = optional_param('overwritesettings', false, PARAM_BOOL);
             if (!$fullname) {
-                $presetdir = $CFG->tempdir.'/forms/'.required_param('directory', PARAM_ALPHANUMEXT);
+                $presetdir = $CFG->tempdir.'/forms/'.required_param('directory', PARAM_FILE);
                 if (!file_exists($presetdir) || !is_dir($presetdir)) {
                     print_error('cannotimport');
                 }
index f1027ba..9bbf4f5 100644 (file)
@@ -241,6 +241,7 @@ function lesson_save_question_options($question, $lesson) {
             // The first answer should always be the correct answer
             $correctanswer = clone($defaultanswer);
             $correctanswer->answer = get_string('thatsthecorrectanswer', 'lesson');
+            $correctanswer->jumpto = LESSON_NEXTPAGE;
             $DB->insert_record("lesson_answers", $correctanswer);
 
             // The second answer should always be the wrong answer
index 482a8ee..021a2ef 100644 (file)
@@ -190,7 +190,7 @@ table#categoryquestions {width: 100%;overflow: hidden;table-layout: fixed;}
 #categoryquestions .iconcol {width: 15px;text-align: center;padding: 0;}
 #categoryquestions .checkbox {width: 19px;text-align: center;padding: 0;}
 #categoryquestions .qtype {text-align: center;}
-#categoryquestions .qtype {width: 24px;padding: 0;}
+#categoryquestions .qtype {width: 28px;padding: 0;}
 #categoryquestions .questiontext p {margin: 0;}
 
 #page-mod-quiz-edit div.quizcontents {float:left;width:70%;display:block;clear:left;}
index 3d620d0..0798bc4 100644 (file)
@@ -499,7 +499,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         }
 
         // Turn off completion settings if the checkboxes aren't ticked
-        $autocompletion = !empty($data->completion) && $data->completion == COMPLETION_TRACKING_AUTOMATIC;
+        $autocompletion = isset($data->completion) && $data->completion == COMPLETION_TRACKING_AUTOMATIC;
 
         if (isset($data->completionstatusrequired) && is_array($data->completionstatusrequired)) {
             $total = 0;
index f5e22f7..3b67672 100644 (file)
@@ -898,12 +898,14 @@ class mod_workshop_renderer extends plugin_renderer_base {
             if ($sortby !== $sortid or $sorthow !== 'ASC') {
                 $url = new moodle_url($PAGE->url);
                 $url->params(array('sortby' => $sortid, 'sorthow' => 'ASC'));
-                $out .= $this->output->action_icon($url, new pix_icon('t/up', get_string('sortasc', 'workshop')), null, array('class' => 'sort asc'));
+                $out .= $this->output->action_icon($url, new pix_icon('t/sort_asc', get_string('sortasc', 'workshop')),
+                    null, array('class' => 'iconsort sort asc'));
             }
             if ($sortby !== $sortid or $sorthow !== 'DESC') {
                 $url = new moodle_url($PAGE->url);
                 $url->params(array('sortby' => $sortid, 'sorthow' => 'DESC'));
-                $out .= $this->output->action_icon($url, new pix_icon('t/down', get_string('sortdesc', 'workshop')), null, array('class' => 'sort desc'));
+                $out .= $this->output->action_icon($url, new pix_icon('t/sort_desc', get_string('sortdesc', 'workshop')),
+                    null, array('class' => 'iconsort sort desc'));
             }
         }
         return $out;
diff --git a/pix/docs.png b/pix/docs.png
new file mode 100644 (file)
index 0000000..4047841
Binary files /dev/null and b/pix/docs.png differ
diff --git a/pix/docs.svg b/pix/docs.svg
new file mode 100644 (file)
index 0000000..f322a5c
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"\r
+        xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<path style="fill:#999999;" d="M8,0C3.6,0,0,3.6,0,8c0,4.4,3.6,8,8,8c4.4,0,8-3.6,8-8C16,3.6,12.4,0,8,0z M8,14c-3.3,0-6-2.7-6-6\r
+       c0-3.3,2.7-6,6-6c3.3,0,6,2.7,6,6C14,11.3,11.3,14,8,14z M9.2,12c0,0.5-0.5,1-1,1H7.8c-0.5,0-1-0.5-1-1V7.4c0-0.5,0.5-1,1-1h0.5\r
+       c0.5,0,1,0.5,1,1V12z M9.2,4.2c0,0.7-0.6,1.2-1.2,1.2c-0.7,0-1.2-0.6-1.2-1.2C6.8,3.5,7.3,3,8,3C8.7,3,9.2,3.5,9.2,4.2z"/>\r
+</svg>\r
diff --git a/pix/i/down.png b/pix/i/down.png
new file mode 100644 (file)
index 0000000..e1696da
Binary files /dev/null and b/pix/i/down.png differ
diff --git a/pix/i/down.svg b/pix/i/down.svg
new file mode 100644 (file)
index 0000000..b3bbefc
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="16px" height="16px" viewBox="-0.1 0 16 16" style="overflow:visible;enable-background:new -0.1 0 16 16;"\r
+        xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<path style="fill:#999999;" d="M15.6,7.3l-0.7-0.7c-0.4-0.4-1.1-0.4-1.4,0l-4,4V1c0-0.5-0.4-1-1-1h-1c-0.5,0-1,0.5-1,1v9.6l-4-4\r
+       C2,6.2,1.4,6.2,1,6.6L0.3,7.3c-0.4,0.4-0.4,1,0,1.4l7,7c0.4,0.4,1,0.4,1.4,0L9.4,15c0,0,0,0,0,0l6.2-6.2C16,8.4,16,7.7,15.6,7.3z"/>\r
+</svg>\r
diff --git a/pix/i/up.png b/pix/i/up.png
new file mode 100644 (file)
index 0000000..672fc43
Binary files /dev/null and b/pix/i/up.png differ
diff --git a/pix/i/up.svg b/pix/i/up.svg
new file mode 100644 (file)
index 0000000..26b208f
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="16px" height="16px" viewBox="-0.1 0 16 16" style="overflow:visible;enable-background:new -0.1 0 16 16;"\r
+        xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<path style="fill:#999999;" d="M15.6,8.6l-0.7,0.7c-0.4,0.4-1.1,0.4-1.4,0l-4-4v9.6c0,0.5-0.4,1.1-1,1.1h-1c-0.5,0-1-0.5-1-1.1V5.3\r
+       l-4,4C2,9.8,1.4,9.8,1,9.4L0.3,8.7c-0.4-0.4-0.4-1,0-1.4l7-7c0.4-0.4,1-0.4,1.4,0L9.4,1c0,0,0,0,0,0l6.2,6.2C16,7.6,16,8.2,15.6,8.6\r
+       z"/>\r
+</svg>\r
index e1696da..85028dd 100644 (file)
Binary files a/pix/t/down.png and b/pix/t/down.png differ
index b3bbefc..e4ad900 100644 (file)
@@ -5,10 +5,10 @@
 ]>\r
 <svg version="1.1"\r
         xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
-        x="0px" y="0px" width="16px" height="16px" viewBox="-0.1 0 16 16" style="overflow:visible;enable-background:new -0.1 0 16 16;"\r
+        x="0px" y="0px" width="12px" height="12px" viewBox="0 0 12 12" style="overflow:visible;enable-background:new 0 0 12 12;"\r
         xml:space="preserve">\r
 <defs>\r
 </defs>\r
-<path style="fill:#999999;" d="M15.6,7.3l-0.7-0.7c-0.4-0.4-1.1-0.4-1.4,0l-4,4V1c0-0.5-0.4-1-1-1h-1c-0.5,0-1,0.5-1,1v9.6l-4-4\r
-       C2,6.2,1.4,6.2,1,6.6L0.3,7.3c-0.4,0.4-0.4,1,0,1.4l7,7c0.4,0.4,1,0.4,1.4,0L9.4,15c0,0,0,0,0,0l6.2-6.2C16,8.4,16,7.7,15.6,7.3z"/>\r
+<path style="fill:#999999;" d="M7.5,1v5.7l2.1-2.1c0.4-0.4,1-0.4,1.4,0l0.7,0.7c0.4,0.4,0.4,1,0,1.4l-5,5c-0.4,0.4-1,0.4-1.4,0\r
+       L4.6,11c0,0,0,0,0,0L0.3,6.7c-0.4-0.4-0.4-1,0-1.4L1,4.6c0.4-0.4,1-0.4,1.4,0l2.1,2.1V1c0-0.5,0.5-1,1-1h1C7,0,7.5,0.5,7.5,1z"/>\r
 </svg>\r
diff --git a/pix/t/sort_asc.png b/pix/t/sort_asc.png
new file mode 100644 (file)
index 0000000..083b5cc
Binary files /dev/null and b/pix/t/sort_asc.png differ
diff --git a/pix/t/sort_asc.svg b/pix/t/sort_asc.svg
new file mode 100644 (file)
index 0000000..f63ca97
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="12px" height="12px" viewBox="-1 0 12 12" style="overflow:visible;enable-background:new -1 0 12 12;"\r
+        xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<path style="fill:#999999;" d="M9.4,5c0.5,0,0.7-0.3,0.3-0.7l-4-4c-0.4-0.4-1-0.4-1.4,0l-4,4C-0.2,4.7,0,5,0.5,5H9.4z"/>\r
+</svg>\r
diff --git a/pix/t/sort_desc.png b/pix/t/sort_desc.png
new file mode 100644 (file)
index 0000000..ede7352
Binary files /dev/null and b/pix/t/sort_desc.png differ
diff --git a/pix/t/sort_desc.svg b/pix/t/sort_desc.svg
new file mode 100644 (file)
index 0000000..7065b53
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="12px" height="12px" viewBox="-1.1 -7 12 12"\r
+        style="overflow:visible;enable-background:new -1.1 -7 12 12;" xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<path style="fill:#999999;" d="M0.5,0C0,0-0.2,0.3,0.2,0.7l4,4c0.4,0.4,1,0.4,1.4,0l4-4C10,0.3,9.9,0,9.3,0H0.5z"/>\r
+</svg>\r
index 672fc43..860f0f0 100644 (file)
Binary files a/pix/t/up.png and b/pix/t/up.png differ
index 26b208f..81009bb 100644 (file)
@@ -5,11 +5,11 @@
 ]>\r
 <svg version="1.1"\r
         xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
-        x="0px" y="0px" width="16px" height="16px" viewBox="-0.1 0 16 16" style="overflow:visible;enable-background:new -0.1 0 16 16;"\r
+        x="0px" y="0px" width="12px" height="12px" viewBox="0 0 12 12" style="overflow:visible;enable-background:new 0 0 12 12;"\r
         xml:space="preserve">\r
 <defs>\r
 </defs>\r
-<path style="fill:#999999;" d="M15.6,8.6l-0.7,0.7c-0.4,0.4-1.1,0.4-1.4,0l-4-4v9.6c0,0.5-0.4,1.1-1,1.1h-1c-0.5,0-1-0.5-1-1.1V5.3\r
-       l-4,4C2,9.8,1.4,9.8,1,9.4L0.3,8.7c-0.4-0.4-0.4-1,0-1.4l7-7c0.4-0.4,1-0.4,1.4,0L9.4,1c0,0,0,0,0,0l6.2,6.2C16,7.6,16,8.2,15.6,8.6\r
+<path style="fill:#999999;" d="M4.5,11V5.3L2.4,7.4C2,7.8,1.4,7.8,1,7.4L0.3,6.7c-0.4-0.4-0.4-1,0-1.4l5-5c0.4-0.4,1-0.4,1.4,0\r
+       L7.4,1c0,0,0,0,0,0l4.3,4.3c0.4,0.4,0.4,1,0,1.4L11,7.4c-0.4,0.4-1,0.4-1.4,0L7.5,5.3V11c0,0.6-0.5,1-1,1h-1C4.9,12,4.5,11.5,4.5,11\r
        z"/>\r
 </svg>\r
index 4df6412..db535e3 100644 (file)
@@ -251,9 +251,9 @@ abstract class question_bank_column_base {
     protected function get_sort_icon($reverse) {
         global $OUTPUT;
         if ($reverse) {
-            return ' <img src="' . $OUTPUT->pix_url('t/up') . '" alt="' . get_string('desc') . '" />';
+            return $OUTPUT->pix_icon('t/sort_desc', get_string('desc'), '', array('class' => 'iconsort'));
         } else {
-            return ' <img src="' . $OUTPUT->pix_url('t/down') . '" alt="' . get_string('asc') . '" />';
+            return $OUTPUT->pix_icon('t/sort_asc', get_string('asc'), '', array('class' => 'iconsort'));
         }
     }
 
index 9b37215..7186582 100644 (file)
@@ -440,7 +440,21 @@ class qformat_xml extends qformat_default {
         $qo->name = $this->clean_question_name($this->import_text($question['#']['name'][0]['#']['text']));
         $qo->questiontextformat = $questiontext['format'];
         $qo->questiontext = $qo->questiontext['text'];
-        $qo->questiontextfiles = array();
+        $qo->questiontextfiles = $this->import_files($this->getpath($question,
+                array('#', 'questiontext', 0, '#', 'file'), array(), false));
+
+        // Backwards compatibility, deal with the old image tag.
+        $filedata = $this->getpath($question, array('#', 'image_base64', '0', '#'), null, false);
+        $filename = $this->getpath($question, array('#', 'image', '0', '#'), null, false);
+        if ($filedata && $filename) {
+            $data = new stdClass();
+            $data->content = $filedata;
+            $data->encoding = 'base64';
+            // Question file areas don't support subdirs, so convert path to filename if necessary.
+            $data->name = clean_param(str_replace('/', '_', $filename), PARAM_FILE);
+            $qo->questiontextfiles[] = $data;
+            $qo->questiontext .= ' <img src="@@PLUGINFILE@@/' . $data->name . '" />';
+        }
 
         // restore files in generalfeedback
         $qo->generalfeedback = $this->getpath($question,
index 85e248f..b58c47a 100644 (file)
@@ -137,6 +137,25 @@ class restore_qtype_match_plugin extends restore_qtype_plugin {
                     array($newquestionid, $data->questiontext, $data->answertext),
                     'id', IGNORE_MULTIPLE);
 
+            // Not able to find the answer, let's try cleaning the answertext
+            // of all the question answers in DB as slower fallback. MDL-36683 / MDL-30018.
+            if (!$sub) {
+                $params = array('question' => $newquestionid);
+                $potentialsubs = $DB->get_records('question_match_sub', array('question' => $newquestionid), '', 'id, questiontext, answertext');
+                foreach ($potentialsubs as $potentialsub) {
+                    // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+                    $cleanquestion = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is', '', $potentialsub->questiontext); // Clean CTRL chars.
+                    $cleanquestion = preg_replace("/\r\n|\r/", "\n", $cleanquestion); // Normalize line ending.
+
+                    $cleananswer = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is', '', $potentialsub->answertext); // Clean CTRL chars.
+                    $cleananswer = preg_replace("/\r\n|\r/", "\n", $cleananswer); // Normalize line ending.
+
+                    if ($cleanquestion === $data->questiontext && $cleananswer == $data->answertext) {
+                        $sub = $potentialsub;
+                    }
+                }
+            }
+
             // Found, let's create the mapping
             if ($sub) {
                 $this->set_mapping('question_match_sub', $oldid, $sub->id);
index afca6a4..8dd7086 100644 (file)
@@ -126,10 +126,10 @@ abstract class qtype_multichoice_base extends question_graded_automatically {
     }
 
     public function make_html_inline($html) {
-        $html = preg_replace('~\s*<p>\s*~', '', $html);
-        $html = preg_replace('~\s*</p>\s*~', '<br />', $html);
-        $html = preg_replace('~<br />$~', '', $html);
-        return $html;
+        $html = preg_replace('~\s*<p>\s*~u', '', $html);
+        $html = preg_replace('~\s*</p>\s*~u', '<br />', $html);
+        $html = preg_replace('~(<br\s*/?>)+$~u', '', $html);
+        return trim($html);
     }
 }
 
index fe5ba51..cbd3827 100644 (file)
@@ -147,6 +147,8 @@ class qtype_multichoice_single_question_test extends advanced_testcase {
         $this->assertEquals("Frog<br />XXX <img src='http://example.com/pic.png' alt='Graph' />",
                 $mc->make_html_inline(" <p> Frog </p> \n\r
                     <p> XXX <img src='http://example.com/pic.png' alt='Graph' /> </p> "));
+        $this->assertEquals('Frog', $mc->make_html_inline('<p>Frog</p><p></p>'));
+        $this->assertEquals('Frog<br />†', $mc->make_html_inline('<p>Frog</p><p>†</p>'));
     }
 }
 
index 8aacf03..f7b9c98 100644 (file)
@@ -321,7 +321,6 @@ YUI.add('moodle-core_filepicker', function(Y) {
         }
         /** initialize table view */
         var initialize_table_view = function() {
-            var parentid = scope.one('.'+classname).get('id');
             var cols = [
                 {key: "displayname", label: M.str.moodle.name, allowHTML: true, formatter: formatTitle,
                     sortable: true, sortFn: sortFoldersFirst},
@@ -332,8 +331,13 @@ YUI.add('moodle-core_filepicker', function(Y) {
                 {key: "mimetype", label: M.str.repository.type, allowHTML: true,
                     sortable: true, sortFn: sortFoldersFirst}
             ];
-            scope.tableview = new Y.DataTable({columns: cols});
-            scope.tableview.render('#'+parentid);
+            for (var k in fileslist) {
+                // to speed up sorting and formatting
+                fileslist[k].displayname = file_get_displayname(fileslist[k]);
+                fileslist[k].isfolder = file_is_folder(fileslist[k]);
+                fileslist[k].classname = options.classnamecallback(fileslist[k]);
+            }
+            scope.tableview = new Y.DataTable({columns: cols, data: fileslist});
             scope.tableview.delegate('click', function (e, tableview) {
                 var record = tableview.getRecord(e.currentTarget.get('id'));
                 if (record) {
@@ -353,13 +357,8 @@ YUI.add('moodle-core_filepicker', function(Y) {
         }
         /** append items in table view mode */
         var append_files_table = function() {
-            for (var k in fileslist) {
-                // to speed up sorting and formatting
-                fileslist[k].displayname = file_get_displayname(fileslist[k]);
-                fileslist[k].isfolder = file_is_folder(fileslist[k]);
-                fileslist[k].classname = options.classnamecallback(fileslist[k]);
-            }
-            scope.tableview.addRows(fileslist);
+            var parentnode = scope.one('.'+classname);
+            scope.tableview.render(parentnode);
             scope.tableview.sortable = options.sortable ? true : false;
         };
         /** append items in tree view mode */
index a7b16b4..d759d35 100644 (file)
@@ -92,8 +92,10 @@ img.resize {height: 1em;width: 1em;}
 img.icon {height:16px;vertical-align:text-bottom;width:16px;padding: 2px 6px 2px 0;}
 .dir-rtl img.icon {padding: 2px 0 2px 6px;}
 img.iconsmall {height:12px;margin-right:3px;vertical-align:middle;width:12px;}
-img.iconhelp, .helplink img {height:16px; padding-left:3px;vertical-align:middle;width:16px;}
+img.iconhelp, .helplink img {height:16px; padding-left:3px;vertical-align:text-bottom;width:16px;}
 img.iconlarge {height: 24px; width: 24px; vertical-align:middle;}
+img.iconsort { vertical-align: text-bottom; padding-left: .3em; margin-bottom: .15em;}
+.dir-rtl img.iconsort { padding-right: .3em; padding-left: 0;}
 img.icontoggle {height:17px;vertical-align:middle;width:50px;}
 img.iconkbhelp {height:17px;width:49px;}
 .categorybox .category {font-size:1.2em;font-weight:bold;}
@@ -120,6 +122,12 @@ img.emoticon {vertical-align: middle;width: 15px;height: 15px;}
 form.popupform,
 form.popupform div {display: inline;}
 .arrow_button input {overflow:hidden;}
+h1.main img,
+h2.main img,
+h3.main img,
+h4.main img,
+h5.main img,
+h6.main img {vertical-align: middle;}
 
 /** The 1-pixel padding is there to avoid phantom scroll bars on OS X (FF, Safari and Chrome)**/
 .no-overflow {overflow:auto;padding-bottom:1px;}
@@ -180,6 +188,8 @@ a.skip:active {position: static;display: block;}
 #page-footer .logininfo,
 #page-footer .sitelink,
 #page-footer .helplink {margin:0px 10px;}
+#page-footer .helplink img.iconhelp { margin: 0 .45em 0 0 ; padding: 0;}
+.dir-rtl #page-footer .helplink img.iconhelp { margin: 0 0 0 .45em ;}
 #page-footer .performanceinfo {text-align:center;margin:10px 20%;}
 #page-footer .performanceinfo span {display:block;}
 #page-footer .validators {margin-top:40px;padding-top:5px;border-top: 1px dotted gray;}
@@ -237,6 +247,10 @@ a.skip:active {position: static;display: block;}
 .mform fieldset.fdate_selector label {display:inline;float: none;width: auto;}
 .mform .ftags label.accesshide {display: block;position: static;}
 .mform .ftags select {margin-bottom: 0.7em;min-width: 22em;}
+.mform .helplink img { margin: 0 0 0 .45em; padding: 0;}
+.dir-rtl .mform .helplink img { margin: 0 .45em 0 0; padding: 0;}
+.mform legend .helplink img { margin-right: .2em; }
+.dir-rtl .mform legend .helplink img { margin: 0 .45em 0 .2em; }
 
 input#id_externalurl {direction:ltr;}
 
@@ -1051,3 +1065,6 @@ html[dir=rtl] #page-header {float: right;}
 html[dir=rtl] .formrow label.formlabel { float:right; }
 
 html[dir=rtl] .configphp {direction:ltr;text-align:left;}
+
+table.flexible .r0, table.generaltable .r0 {background-color: #F0F0F0;}
+table.flexible .r1, table.generaltable .r1 {background-color: #FAFAFA;}
index 3f577e6..edbb42c 100644 (file)
@@ -70,13 +70,6 @@ echo $OUTPUT->doctype() ?>
 <!-- begin of page-header -->
                             <?php if ($hasheading) { ?>
                             <div id="page-header">
-                            <?php if ($displaylogo) { ?>
-                                <div id="headerlogo">
-                                    <img src="<?php echo $logourl ?>" alt="Custom logo here" />
-                                </div>
-                            <?php } else { ?>
-                                <h1 class="headerheading"><?php echo $PAGE->heading ?></h1>
-                            <?php } ?>
 
                                 <div class="headermenu">
                                     <?php
@@ -87,6 +80,15 @@ echo $OUTPUT->doctype() ?>
                                     echo $PAGE->headingmenu;
                                 ?>
                                 </div>
+
+                                <?php if ($displaylogo) { ?>
+                                    <div id="headerlogo">
+                                        <img src="<?php echo $logourl ?>" alt="Custom logo here" />
+                                    </div>
+                                <?php } else { ?>
+                                    <h1 class="headerheading"><?php echo $PAGE->heading ?></h1>
+                                <?php } ?>
+
                             </div>
                             <?php } ?>
 <!-- end of page-header -->
index 31e373e..1024307 100644 (file)
@@ -68,13 +68,6 @@ echo $OUTPUT->doctype() ?>
 <!-- begin of page-header -->
                             <?php if ($hasheading) { ?>
                             <div id="page-header">
-                            <?php if ($displaylogo) { ?>
-                                <div id="headerlogo">
-                                    <img src="<?php echo $logourl ?>" alt="Custom logo here" />
-                                </div>
-                            <?php } else { ?>
-                                <h1 class="headerheading"><?php echo $PAGE->heading ?></h1>
-                            <?php } ?>
 
                                 <div class="headermenu">
                                     <?php
@@ -85,6 +78,15 @@ echo $OUTPUT->doctype() ?>
                                     echo $PAGE->headingmenu;
                                 ?>
                                 </div>
+
+                                <?php if ($displaylogo) { ?>
+                                    <div id="headerlogo">
+                                        <img src="<?php echo $logourl ?>" alt="Custom logo here" />
+                                    </div>
+                                <?php } else { ?>
+                                    <h1 class="headerheading"><?php echo $PAGE->heading ?></h1>
+                                <?php } ?>
+
                             </div>
                             <?php } ?>
 <!-- end of page-header -->
index 8919acd..05551e9 100644 (file)
@@ -63,13 +63,6 @@ echo $OUTPUT->doctype() ?>
 <!-- begin of page-header -->
                             <?php if ($hasheading) { ?>
                             <div id="page-header">
-                            <?php if ($displaylogo) { ?>
-                                <div id="headerlogo">
-                                    <img src="<?php echo $logourl ?>" alt="Custom logo here" />
-                                </div>
-                            <?php } else { ?>
-                                <h1 class="headerheading"><?php echo $PAGE->heading ?></h1>
-                            <?php } ?>
 
                                 <div class="headermenu">
                                     <?php
@@ -80,6 +73,15 @@ echo $OUTPUT->doctype() ?>
                                     echo $PAGE->headingmenu;
                                     ?>
                                 </div>
+
+                                <?php if ($displaylogo) { ?>
+                                    <div id="headerlogo">
+                                        <img src="<?php echo $logourl ?>" alt="Custom logo here" />
+                                    </div>
+                                <?php } else { ?>
+                                    <h1 class="headerheading"><?php echo $PAGE->heading ?></h1>
+                                <?php } ?>
+
                             </div>
                             <?php } ?>
 <!-- end of page-header -->
index 26d95a3..354a091 100644 (file)
@@ -25,16 +25,43 @@ h1.headerheading {margin:14px 11px 8px 11px;float:left;font-size:200%;}
 h2.main, h3.main, h4.main {margin:1em;padding:0;text-align:center;}
 
 /* page-header */
-#page-header{line-height:0;overflow:hidden;}
+#page-header{
+    margin: 0;
+    overflow: hidden;
+    padding: 0;
+    width: 100%;
+}
 
 /* headerlogo */
-#headerlogo {position:relative;margin:0;}
-  /* if I use: position:absolute; I even need height:105px; in #page-header */
-  /* if I use: position:relative; z-index doesn't work*/
+#headerlogo {
+    float: left;
+    height: auto;
+    margin: 0;
+    padding: 0;
+    width: auto;
+}
+
+.dir-rtl #headerlogo {
+    float: right;
+}
 
 /* headermenu */
-.headermenu {position:absolute;text-align:right;line-height:1.7em;font-size:90%;margin:0.5em;right:[[calculated:headermenuright]];top:15px;}
-.langmenu {margin-right:0.4em}
+.headermenu {
+    float: right;
+    font-size: 90%;
+    line-height: 1.7em;
+    margin: 0.5em;
+    position: relative;
+    right: 0;
+    text-align: right;
+    top: 0;
+}
+.dir-rtl .headermenu {
+    float: left;
+}
+.langmenu {
+    margin-right: 0.4em
+}
 
 #dock {background-color:[[setting:blockcontentbgc]];border-right:1px dashed #000;}
 #dock .dockeditem_container {margin-top: 10px;}
index 34c7f6d..ff8d409 100644 (file)
     background-position:100% 0;
     text-align:left;
     height:17px;
-    margin:0 0 0 17px;
+    margin-left:17px;
 }
 
 #frametopright div,
 #footerframetopright div { /* Frame background top left */
+    background-color:transparent;
     background-image:url([[pix:theme|roundcorner/header_l]]);
+    background-position:0 0;
+    background-repeat:no-repeat;
+    float:left;
     font-size:1px;
-    line-height:1%;
     height:17px;
-    background-repeat:no-repeat;
-    background-position:0 0;
-    background-color:transparent;
+    line-height:1%;
+    margin-left:-17px;
     position:relative;
     width:17px;
-    margin-left:-17px;
 }
 
 #frameleft,
 #framebottomright,
 #footerframebottomright { /* Frame background bottom right */
     background-image:url([[pix:theme|roundcorner/footer_r]]);
-    background-repeat:no-repeat;
     background-position:100% 0;
+    background-repeat:no-repeat;
+    height: 17px;
+    margin-left:17px;
     text-align:left;
-    margin:0 0 0 17px;
 }
 
 #framebottomright div,
 #footerframebottomright div {  /* Frame background bottom left */
+    background-color:transparent;
     background-image:url([[pix:theme|roundcorner/footer_l]]);
+    background-position:0 0;
+    background-repeat:no-repeat;
+    float: left;
     font-size:1px;
-    line-height:1%;
     height:17px;
-    background-repeat:no-repeat;
-    background-position:0 0;
-    background-color:transparent;
+    line-height:1%;
+    margin-left:-17px;
     position:relative;
     width:17px;
-    margin-left:-17px;
 }
 
 #framebottom,
 #footerframebottom { /* Bottom Middle */
-    background-image:url([[pix:theme|roundcorner/footer]]);
-    background-repeat:repeat-x;
-    background-position:0 100%;
     background-attachment:scroll;
     background-color:transparent;
+    background-image:url([[pix:theme|roundcorner/footer]]);
+    background-position:0 100%;
+    background-repeat:repeat-x;
 }
 
 /*******************************************************************/
index 568791c..d559107 100644 (file)
@@ -75,8 +75,6 @@ table.minicalendar {
   border-radius: 10px;
 }
 
-.block_course_summary,
-.block_course_summary .content,
 #page-report-outline-user .section {
   -moz-border-radius:10px;
   -webkit-border-radius: 10px;
index 105f425..908ffb5 100644 (file)
@@ -18,6 +18,8 @@ optional changes:
 * new icon i/switchrole (sized 16x16), was previously using i/roles. Now is a copy of the new i/assignroles icon.
 * new icons i/enrolusers and t/enrolusers, previsouly i/users was used.
 * new icon t/cohorts (sized 12x12), to prevent the use of i/cohorts which is 16x16.
+* new icons t/sort_asc, t/sort_desc to use for ordering in table headers.
+* new class 'iconsort' for icons used for ordering in table headers.
 
 === 2.3 ===
 
index 87c4490..0e2b56e 100644 (file)
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012111601.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012111601.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes