Merge branch 'w51_MDL-36807_m25_mysocket' of git://github.com/skodak/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 7 Jan 2013 10:44:16 +0000 (11:44 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 7 Jan 2013 10:44:16 +0000 (11:44 +0100)
115 files changed:
admin/filters.php
admin/tool/uploaduser/index.php
backup/backupfilesedit.php
backup/moodle2/restore_stepslib.php
blocks/completionstatus/block_completionstatus.php
blocks/completionstatus/db/access.php
blocks/completionstatus/db/upgrade.php [new file with mode: 0644]
blocks/completionstatus/lang/en/block_completionstatus.php
blocks/completionstatus/version.php
blocks/course_summary/block_course_summary.php
blocks/course_summary/db/access.php
blocks/course_summary/db/upgrade.php [new file with mode: 0644]
blocks/course_summary/lang/en/block_course_summary.php
blocks/course_summary/version.php
blocks/dock.js
blocks/glossary_random/block_glossary_random.php
blocks/glossary_random/db/access.php
blocks/glossary_random/db/upgrade.php [new file with mode: 0644]
blocks/glossary_random/lang/en/block_glossary_random.php
blocks/glossary_random/version.php
blocks/mentees/block_mentees.php
blocks/mentees/db/access.php
blocks/mentees/db/upgrade.php [new file with mode: 0644]
blocks/mentees/lang/en/block_mentees.php
blocks/mentees/version.php
blocks/news_items/block_news_items.php
blocks/news_items/db/access.php
blocks/news_items/db/upgrade.php [new file with mode: 0644]
blocks/news_items/lang/en/block_news_items.php
blocks/news_items/version.php
blocks/online_users/block_online_users.php
blocks/online_users/db/access.php
blocks/online_users/db/upgrade.php [new file with mode: 0644]
blocks/online_users/lang/en/block_online_users.php
blocks/online_users/version.php
blocks/rss_client/backup/moodle2/restore_rss_client_stepslib.php
blocks/selfcompletion/block_selfcompletion.php
blocks/selfcompletion/db/access.php
blocks/selfcompletion/db/upgrade.php [new file with mode: 0644]
blocks/selfcompletion/lang/en/block_selfcompletion.php
blocks/selfcompletion/version.php
blocks/tags/edit_form.php
blocks/tags/lang/en/block_tags.php
cache/classes/loaders.php
cache/stores/static/lib.php
comment/comment_post.php
course/category.php
course/dnduploadlib.php
course/lib.php
course/switchrole.php
enrol/ldap/lib.php
enrol/locallib.php
enrol/otherusers.php
enrol/renderer.php
filter/activitynames/db/install.php
filter/algebra/algebradebug.php
filter/algebra/pix.php
filter/manage.php
filter/mediaplugin/db/install.php
filter/tex/displaytex.php
filter/tex/pix.php
filter/tex/texdebug.php
filter/upgrade.txt
grade/edit/tree/lib.php
group/externallib.php
lang/en/block.php
lang/en/error.php
lib/adminlib.php
lib/db/install.xml
lib/db/upgrade.php
lib/editor/tinymce/plugins/dragmath/lib.php
lib/editor/tinymce/plugins/moodleemoticon/lib.php
lib/editor/tinymce/plugins/spellchecker/changelog.txt
lib/editor/tinymce/plugins/spellchecker/classes/GoogleSpell.php
lib/editor/tinymce/plugins/spellchecker/readme_moodle.txt
lib/editor/tinymce/upgrade.txt
lib/filelib.php
lib/filterlib.php
lib/navigationlib.php
lib/outputlib.php
lib/outputrenderers.php
lib/outputrequirementslib.php
lib/pluginlib.php
lib/rsslib.php
lib/tests/filter_test.php
lib/tests/textlib_test.php
lib/textlib.class.php
lib/weblib.php
mnet/lib.php
mod/assign/feedback/file/importziplib.php
mod/assign/feedback/file/locallib.php
mod/assign/feedback/offline/locallib.php
mod/assign/locallib.php
mod/assign/submission/comments/lib.php
mod/data/data.js
mod/data/edit.php
mod/data/field/file/field.class.php
mod/data/field/picture/field.class.php
mod/forum/lib.php
mod/forum/rsslib.php
mod/scorm/report/reportlib.php
mod/upgrade.txt
mod/wiki/create.php
mod/wiki/filesedit.php
mod/wiki/pagelib.php
question/format/learnwise/format.php
question/format/learnwise/lang/en/qformat_learnwise.php
question/type/shortanswer/question.php
question/type/shortanswer/tests/question_test.php
report/outline/index.php
report/security/locallib.php
tag/coursetags_add.php
user/files.php
user/profile.php
version.php

index c102666..64589cf 100644 (file)
@@ -35,7 +35,7 @@
     require_once($CFG->libdir . '/adminlib.php');
 
     $action = optional_param('action', '', PARAM_ALPHANUMEXT);
-    $filterpath = optional_param('filterpath', '', PARAM_PATH);
+    $filterpath = optional_param('filterpath', '', PARAM_SAFEDIR);
 
     require_login();
     $systemcontext = context_system::instance();
 
     case 'down':
         if (isset($filters[$filterpath])) {
-            $oldpos = $filters[$filterpath]->sortorder;
-            if ($oldpos <= count($filters)) {
-                filter_set_global_state($filterpath, $filters[$filterpath]->active, $oldpos + 1);
-            }
+            filter_set_global_state($filterpath, $filters[$filterpath]->active, 1);
         }
         break;
 
     case 'up':
         if (isset($filters[$filterpath])) {
             $oldpos = $filters[$filterpath]->sortorder;
-            if ($oldpos >= 1) {
-                filter_set_global_state($filterpath, $filters[$filterpath]->active, $oldpos - 1);
-            }
+            filter_set_global_state($filterpath, $filters[$filterpath]->active, -1);
         }
         break;
 
     case 'delete':
-        if (!empty($filternames[$filterpath])) {
-            $filtername = $filternames[$filterpath];
-        } else {
-            $filtername = $filterpath;
-        }
-
-        if (substr($filterpath, 0, 4) == 'mod/') {
-            $mod = basename($filterpath);
-            $a = new stdClass;
-            $a->filter = $filtername;
-            $a->module = get_string('modulename', $mod);
-            print_error('cannotdeletemodfilter', 'admin', $returnurl, $a);
-        }
-
         // If not yet confirmed, display a confirmation message.
         if (!optional_param('confirm', '', PARAM_BOOL)) {
+            $filtername = filter_get_name($filterpath);
+
             $title = get_string('deletefilterareyousure', 'admin', $filtername);
             echo $OUTPUT->header();
             echo $OUTPUT->heading($title);
         }
 
         // Do the deletion.
-        $title = get_string('deletingfilter', 'admin', $filtername);
+        $title = get_string('deletingfilter', 'admin', $filterpath);
         echo $OUTPUT->header();
         echo $OUTPUT->heading($title);
 
         filter_delete_all_for_filter($filterpath);
 
         $a = new stdClass;
-        $a->filter = $filtername;
-        $a->directory = $filterpath;
+        $a->filter = $filterpath;
+        $a->directory = "$CFG->dirroot/filter/$filterpath";
         echo $OUTPUT->box(get_string('deletefilterfiles', 'admin', $a), 'generalbox', 'notice');
         echo $OUTPUT->continue_button($returnurl);
         echo $OUTPUT->footer();
@@ -241,7 +224,7 @@ function get_table_row($filterinfo, $isfirstrow, $islastactive, $applytostrings)
     }
 
     // Disable/off/on
-    $select = new single_select(filters_action_url($filter, 'setstate'), 'newstate', $activechoices, $filterinfo->active, null, 'active' . basename($filter));
+    $select = new single_select(filters_action_url($filter, 'setstate'), 'newstate', $activechoices, $filterinfo->active, null, 'active' . $filter);
     $select->set_label(get_string('isactive', 'filters'), array('class' => 'accesshide'));
     $row[] = $OUTPUT->render($select);
 
@@ -263,25 +246,20 @@ function get_table_row($filterinfo, $isfirstrow, $islastactive, $applytostrings)
     $row[] = $updown;
 
     // Apply to strings.
-    $select = new single_select(filters_action_url($filter, 'setapplyto'), 'stringstoo', $applytochoices, $applytostrings, null, 'applyto' . basename($filter));
+    $select = new single_select(filters_action_url($filter, 'setapplyto'), 'stringstoo', $applytochoices, $applytostrings, null, 'applyto' . $filter);
     $select->set_label(get_string('applyto', 'filters'), array('class' => 'accesshide'));
     $select->disabled = $filterinfo->active == TEXTFILTER_DISABLED;
     $row[] = $OUTPUT->render($select);
 
     // Settings link, if required
     if (filter_has_global_settings($filter)) {
-        $row[] = '<a href="' . $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=filtersetting' .
-                str_replace('/', '',$filter) . '">' . get_string('settings') . '</a>';
+        $row[] = '<a href="' . $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=filtersetting' . $filter . '">' . get_string('settings') . '</a>';
     } else {
         $row[] = '';
     }
 
     // Delete
-    if (substr($filter, 0, 4) != 'mod/') {
-        $row[] = '<a href="' . filters_action_url($filter, 'delete') . '">' . get_string('delete') . '</a>';
-    } else {
-        $row[] = '';
-    }
+    $row[] = '<a href="' . filters_action_url($filter, 'delete') . '">' . get_string('delete') . '</a>';
 
     return $row;
 }
index 632cfe1..9a6a104 100644 (file)
@@ -285,7 +285,11 @@ if ($formdata = $mform2->is_cancelled()) {
             $userserrors++;
             continue;
         }
-
+        if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
+            $upt->track('status', get_string('invalidusername', 'error', 'username'), 'error');
+            $upt->track('username', $errorstr, 'error');
+            $userserrors++;
+        }
         if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
             $upt->track('id', $existinguser->id, 'normal', false);
         }
index 6b81b7d..ac5584c 100644 (file)
@@ -33,7 +33,7 @@ $currentcontext = required_param('currentcontext', PARAM_INT);
 // file parameters
 $component  = optional_param('component', null, PARAM_COMPONENT);
 $filearea   = optional_param('filearea', null, PARAM_AREA);
-$returnurl  = optional_param('returnurl', null, PARAM_URL);
+$returnurl  = optional_param('returnurl', null, PARAM_LOCALURL);
 
 list($context, $course, $cm) = get_context_info_array($currentcontext);
 $filecontext = context::instance_by_id($contextid, IGNORE_MISSING);
index babbcd0..b7da2d3 100644 (file)
@@ -297,8 +297,13 @@ class restore_gradebook_structure_step extends restore_structure_step {
 
         $data->courseid = $this->get_courseid();
 
-        $newitemid = $DB->insert_record('grade_settings', $data);
-        //$this->set_mapping('grade_setting', $oldid, $newitemid);
+        if (!$DB->record_exists('grade_settings', array('courseid' => $data->courseid, 'name' => $data->name))) {
+            $newitemid = $DB->insert_record('grade_settings', $data);
+        } else {
+            $newitemid = $data->id;
+        }
+
+        $this->set_mapping('grade_setting', $oldid, $newitemid);
     }
 
     /**
@@ -1817,6 +1822,14 @@ class restore_filters_structure_step extends restore_structure_step {
 
         $data = (object)$data;
 
+        if (strpos($data->filter, 'filter/') === 0) {
+            $data->filter = substr($data->filter, 7);
+
+        } else if (strpos($data->filter, '/') !== false) {
+            // Unsupported old filter.
+            return;
+        }
+
         if (!filter_is_enabled($data->filter)) { // Not installed or not enabled, nothing to do
             return;
         }
@@ -1827,6 +1840,14 @@ class restore_filters_structure_step extends restore_structure_step {
 
         $data = (object)$data;
 
+        if (strpos($data->filter, 'filter/') === 0) {
+            $data->filter = substr($data->filter, 7);
+
+        } else if (strpos($data->filter, '/') !== false) {
+            // Unsupported old filter.
+            return;
+        }
+
         if (!filter_is_enabled($data->filter)) { // Not installed or not enabled, nothing to do
             return;
         }
index d098938..12f0ea1 100644 (file)
@@ -38,6 +38,10 @@ class block_completionstatus extends block_base {
         $this->title = get_string('pluginname', 'block_completionstatus');
     }
 
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
+    }
+
     public function get_content() {
         global $USER;
 
index 8220ecc..8d38ec8 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/completionstatus:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/completionstatus:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/completionstatus/db/upgrade.php b/blocks/completionstatus/db/upgrade.php
new file mode 100644 (file)
index 0000000..b5bbe8c
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the completion status block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_completionstatus_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'completionstatus', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'completionstatus');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index 3c90759..e389743 100644 (file)
@@ -25,7 +25,6 @@
 
 $string['completionprogressdetails'] = 'Completion progress details';
 $string['completionstatus:addinstance'] = 'Add a new course completion status block';
-$string['completionstatus:myaddinstance'] = 'Add a new course completion status block to the My Moodle page';
 $string['criteriagroup'] = 'Criteria group';
 $string['firstofsecond'] = '{$a->first} of {$a->second}';
 $string['pluginname'] = 'Course completion status';
index b97ad8e..218f326 100644 (file)
@@ -26,7 +26,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version      = 2012112900; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version      = 2012112901; // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires     = 2012112900; // Requires this Moodle version
 $plugin->component    = 'block_completionstatus';
-$plugin->dependencies = array('report_completion' => 2012112900);
\ No newline at end of file
+$plugin->dependencies = array('report_completion' => 2012112900);
index cac6591..504c626 100644 (file)
@@ -5,6 +5,10 @@ class block_course_summary extends block_base {
         $this->title = get_string('pluginname', 'block_course_summary');
     }
 
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
+    }
+
     function specialization() {
         if($this->page->pagetype == PAGE_COURSE_VIEW && $this->page->course->id != SITEID) {
             $this->title = get_string('coursesummary', 'block_course_summary');
index 5613ae7..a1e4265 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/course_summary:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/course_summary:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/course_summary/db/upgrade.php b/blocks/course_summary/db/upgrade.php
new file mode 100644 (file)
index 0000000..7a16a1f
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the course summary block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_course_summary_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'course_summary', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'course_summary');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index 836cbfc..92adcf9 100644 (file)
@@ -25,5 +25,4 @@
 
 $string['coursesummary'] = 'Course summary';
 $string['course_summary:addinstance'] = 'Add a new course/site description block';
-$string['course_summary:myaddinstance'] = 'Add a new course/site description block to the My Moodle page';
 $string['pluginname'] = 'Course/Site description';
index 38cb1cf..d036ba1 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_course_summary'; // Full name of the plugin (used for diagnostics)
index 73249e9..46c0479 100644 (file)
@@ -936,7 +936,7 @@ M.core_dock.genericblock.prototype = {
             }, this);
             // Add a close icon
             // Must set the image src seperatly of we get an error with XML strict headers
-            var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="" /></span>');
+            var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="'+M.str.block.hidepanel+'" title="'+M.str.block.hidedockpanel+'" /></span>');
             closeicon.one('img').setAttribute('src', M.util.image_url('t/dockclose', 'moodle'));
             closeicon.on('forceclose|click', this.hide, this);
             closeicon.on('dock:actionkey',this.hide, this, {actions:{enter:true,toggle:true}});
index 1eccd11..af9c550 100644 (file)
@@ -5,10 +5,15 @@ define('BGR_LASTMODIFIED', '1');
 define('BGR_NEXTONE',      '2');
 
 class block_glossary_random extends block_base {
+
     function init() {
         $this->title = get_string('pluginname','block_glossary_random');
     }
 
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
+    }
+
     function specialization() {
         global $CFG, $DB;
 
index 0c1acd6..e7bb687 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/glossary_random:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/glossary_random:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/glossary_random/db/upgrade.php b/blocks/glossary_random/db/upgrade.php
new file mode 100644 (file)
index 0000000..81aeabe
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the glossary random block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_glossary_random_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'glossary_random', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'glossary_random');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index ddb483d..3c51dfa 100644 (file)
@@ -28,7 +28,6 @@ $string['askaddentry'] = 'When users can add entries to the glossary, show a lin
 $string['askinvisible'] = 'When users cannot edit or view the glossary, show this text (without link)';
 $string['askviewglossary'] = 'When users can view the glossary but not add entries, show a link with this text';
 $string['glossary_random:addinstance'] = 'Add a new random glossary entry block';
-$string['glossary_random:myaddinstance'] = 'Add a new random glossary entry block to the My Moodle page';
 $string['intro'] = 'Make sure you have at least one glossary with at least one entry added to this course. Then you can adjust the following settings';
 $string['invisible'] = '(to be continued)';
 $string['lastmodified'] = 'Last modified entry';
index bcca83b..061ec44 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_glossary_random'; // Full name of the plugin (used for diagnostics)
index aa340af..85f48f3 100644 (file)
@@ -7,7 +7,7 @@ class block_mentees extends block_base {
     }
 
     function applicable_formats() {
-        return array('all' => true, 'tag' => false);
+        return array('all' => true, 'tag' => false, 'my' => false);
     }
 
     function specialization() {
index ba14b07..489ceb3 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/mentees:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/mentees:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/mentees/db/upgrade.php b/blocks/mentees/db/upgrade.php
new file mode 100644 (file)
index 0000000..e8aba71
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the mentees block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_mentees_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'mentees', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'mentees');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index 3a22057..1c0cdab 100644 (file)
@@ -27,6 +27,5 @@ $string['configtitle'] = 'Block title';
 $string['configtitleblankhides'] = 'Block title (no title if blank)';
 $string['leaveblanktohide'] = 'leave blank to hide the title';
 $string['mentees:addinstance'] = 'Add a new mentees block';
-$string['mentees:myaddinstance'] = 'Add a new mentees block to the My Moodle page';
 $string['newmenteesblock'] = '(new Mentees block)';
 $string['pluginname'] = 'Mentees';
index 8ead4fc..c3a8db3 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_mentees';   // Full name of the plugin (used for diagnostics)
index 5ecbec2..e803c6e 100644 (file)
@@ -5,6 +5,10 @@ class block_news_items extends block_base {
         $this->title = get_string('pluginname', 'block_news_items');
     }
 
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
+    }
+
     function get_content() {
         global $CFG, $USER;
 
index 86bb1b7..452158e 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/news_items:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/news_items:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/news_items/db/upgrade.php b/blocks/news_items/db/upgrade.php
new file mode 100644 (file)
index 0000000..e634e57
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the latest news block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_news_items_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'news_items', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'news_items');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index d1ab3d8..1de6507 100644 (file)
@@ -24,5 +24,4 @@
  */
 
 $string['news_items:addinstance'] = 'Add a new latest news block';
-$string['news_items:myaddinstance'] = 'Add a new navigation block to the My Moodle page';
 $string['pluginname'] = 'Latest news';
index 4cdea31..11d74ca 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_news_items'; // Full name of the plugin (used for diagnostics)
index 77f8a69..6d14ebb 100644 (file)
@@ -10,7 +10,13 @@ class block_online_users extends block_base {
         $this->title = get_string('pluginname','block_online_users');
     }
 
-    function has_config() {return true;}
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
+    }
+
+    function has_config() {
+        return true;
+    }
 
     function get_content() {
         global $USER, $CFG, $DB, $OUTPUT;
index f238b73..41959c4 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/online_users:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/online_users:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/online_users/db/upgrade.php b/blocks/online_users/db/upgrade.php
new file mode 100644 (file)
index 0000000..f45a788
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the online users block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_online_users_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'online_users', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'online_users');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index 034fce5..b7a008e 100644 (file)
@@ -25,7 +25,6 @@
 
 $string['configtimetosee'] = 'Number of minutes determining the period of inactivity after which a user is no longer considered to be online.';
 $string['online_users:addinstance'] = 'Add a new online users block';
-$string['online_users:myaddinstance'] = 'Add a new online users block to the My Moodle page';
 $string['online_users:viewlist'] = 'View list of online users';
 $string['periodnminutes'] = 'last {$a} minutes';
 $string['pluginname'] = 'Online users';
index 18e1354..4463c45 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_online_users'; // Full name of the plugin (used for diagnostics)
index 8e28ac2..c23d7b9 100644 (file)
@@ -78,6 +78,9 @@ class restore_rss_client_block_structure_step extends restore_structure_step {
         $configdata = $DB->get_field('block_instances', 'configdata', array('id' => $this->task->get_blockid()));
         // Extract configdata
         $config = unserialize(base64_decode($configdata));
+        if (empty($config)) {
+            $config = new stdClass();
+        }
         // Set array of used rss feeds
         $config->rssid = $feedsarr;
         // Serialize back the configdata
index 7a44dfe..9ea6db4 100644 (file)
@@ -36,7 +36,11 @@ require_once($CFG->libdir.'/completionlib.php');
 class block_selfcompletion extends block_base {
 
     public function init() {
-        $this->title   = get_string('pluginname', 'block_selfcompletion');
+        $this->title = get_string('pluginname', 'block_selfcompletion');
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
     }
 
     public function get_content() {
index 489eebd..d91d4d4 100644 (file)
@@ -26,16 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
-    'block/selfcompletion:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
     'block/selfcompletion:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/selfcompletion/db/upgrade.php b/blocks/selfcompletion/db/upgrade.php
new file mode 100644 (file)
index 0000000..fd03025
--- /dev/null
@@ -0,0 +1,69 @@
+<?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 file keeps track of upgrades to the self completion block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since 2.0
+ * @package blocks
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
+    global $DB;
+
+    // Moodle v2.4.0 release upgrade line
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2012112901) {
+        // Get the instances of this block.
+        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'selfcompletion', 'pagetypepattern' => 'my-index'))) {
+            // Loop through and remove them from the My Moodle page.
+            foreach ($blocks as $block) {
+                blocks_delete_instance($block);
+            }
+
+        }
+
+        // Savepoint reached.
+        upgrade_block_savepoint(true, 2012112901, 'selfcompletion');
+    }
+
+
+    return true;
+}
\ No newline at end of file
index e7c89d3..457c77c 100644 (file)
@@ -28,4 +28,3 @@ $string['completecourse'] = 'Complete course';
 $string['pluginname'] = 'Self completion';
 $string['selfcompletionnotenabled'] = 'The self completion criteria has not been enabled for this course';
 $string['selfcompletion:addinstance'] = 'Add a new self completion block';
-$string['selfcompletion:myaddinstance'] = 'Add a new self completion block to the My Moodle page';
index 517c84b..2a0d036 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_selfcompletion'; // Full name of the plugin (used for diagnostics)
index bc5c265..e6bde82 100644 (file)
@@ -33,7 +33,7 @@ class block_tags_edit_form extends block_edit_form {
         // Fields for editing HTML block title and contents.
         $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
 
-        $mform->addElement('text', 'config_title', get_string('pluginname', 'block_tags'));
+        $mform->addElement('text', 'config_title', get_string('configtitle', 'block_tags'));
         $mform->setType('config_title', PARAM_TEXT);
         $mform->setDefault('config_title', get_string('pluginname', 'block_tags'));
 
index 7f2d59f..6dcb0b9 100644 (file)
@@ -25,6 +25,7 @@
 $string['add'] = 'Add';
 $string['alltags'] = 'All tags:';
 $string['arrowtitle'] = 'Click here to enter the suggested text (grey letters).';
+$string['configtitle'] = 'Block title';
 $string['coursetags'] = 'Course tags:';
 $string['disabledtags'] = 'Tags are disabled';
 $string['defaultdisplay'] = 'Tag type to display';
index 74014c4..028a31e 100644 (file)
@@ -1093,6 +1093,10 @@ class cache_application extends cache implements cache_loader_with_locking {
             $todelete = array();
             // Iterate the returned data for the events.
             foreach ($events as $event => $keys) {
+                if ($keys === false) {
+                    // There are no keys.
+                    continue;
+                }
                 // Look at each key and check the timestamp.
                 foreach ($keys as $key => $timestamp) {
                     // If the timestamp of the event is more than or equal to the last invalidation (happened between the last
index dcbdbd7..7281fad 100644 (file)
@@ -357,6 +357,7 @@ class cachestore_static extends static_data_store implements cache_is_key_aware
      */
     public function purge() {
         $this->flush_store_by_id($this->storeid);
+        $this->store = &self::register_store_id($this->storeid);
     }
 
     /**
index b7a39a8..a960293 100644 (file)
@@ -38,7 +38,7 @@ $action    = optional_param('action',    '',  PARAM_ALPHA);
 $area      = optional_param('area',      '',  PARAM_AREA);
 $content   = optional_param('content',   '',  PARAM_RAW);
 $itemid    = optional_param('itemid',    '',  PARAM_INT);
-$returnurl = optional_param('returnurl', '/', PARAM_URL);
+$returnurl = optional_param('returnurl', '/', PARAM_LOCALURL);
 $component = optional_param('component', '',  PARAM_COMPONENT);
 
 // Currently this script can only add comments
index 33bc709..37138b5 100644 (file)
@@ -191,6 +191,7 @@ if ($editingon && can_edit_in_category()) {
     // Integrate into the admin tree only if the user can edit categories at the top level,
     // otherwise the admin block does not appear to this user, and you get an error.
     require_once($CFG->libdir . '/adminlib.php');
+    navigation_node::override_active_url(new moodle_url('/course/category.php', array('id' => $id)));
     admin_externalpage_setup('coursemgmt', '', $urlparams, $CFG->wwwroot . '/course/category.php');
     $PAGE->set_context($context);   // Ensure that we are actually showing blocks etc for the cat context
 
index 6fb00b0..21dc7a7 100644 (file)
@@ -555,6 +555,15 @@ class dndupload_ajax_processor {
         $this->cm->groupmode = $this->course->groupmode;
         $this->cm->groupingid = $this->course->defaultgroupingid;
 
+        // Set the correct default for completion tracking.
+        $this->cm->completion = COMPLETION_TRACKING_NONE;
+        $completion = new completion_info($this->course);
+        if ($completion->is_enabled()) {
+            if (plugin_supports('mod', $this->cm->modulename, FEATURE_MODEDIT_DEFAULT_COMPLETION, true)) {
+                $this->cm->completion = COMPLETION_TRACKING_MANUAL;
+            }
+        }
+
         if (!$this->cm->id = add_course_module($this->cm)) {
             throw new coding_exception("Unable to create the course module");
         }
index f2d90db..a58b86a 100644 (file)
@@ -1516,8 +1516,9 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     $textcss = '';
                 }
 
-                // Get on-click attribute value if specified
-                $onclick = $mod->get_on_click();
+                // Get on-click attribute value if specified and decode the onclick - it
+                // has already been encoded for display (puke).
+                $onclick = htmlspecialchars_decode($mod->get_on_click(), ENT_QUOTES);
 
                 $groupinglabel = '';
                 if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', context_course::instance($course->id))) {
index 719762e..2b756b6 100644 (file)
@@ -35,7 +35,7 @@ require_once($CFG->dirroot.'/course/lib.php');
 
 $id         = required_param('id', PARAM_INT);
 $switchrole = optional_param('switchrole',-1, PARAM_INT);
-$returnurl  = optional_param('returnurl', false, PARAM_URL);
+$returnurl  = optional_param('returnurl', false, PARAM_LOCALURL);
 
 $PAGE->set_url('/course/switchrole.php', array('id'=>$id));
 
@@ -84,4 +84,4 @@ if ($returnurl === false) {
     $returnurl = new moodle_url('/course/view.php', array('id' => $course->id));
 }
 
-redirect($returnurl);
\ No newline at end of file
+redirect($returnurl);
index 31224de..f602ffb 100644 (file)
@@ -653,7 +653,7 @@ class enrol_ldap_plugin extends enrol_plugin {
      * @param object role is a record from the mdl_role table.
      * @return array
      */
-    protected function find_ext_enrolments ($ldapconnection, $memberuid, $role) {
+    protected function find_ext_enrolments (&$ldapconnection, $memberuid, $role) {
         global $CFG;
         require_once($CFG->libdir.'/ldaplib.php');
 
@@ -718,13 +718,13 @@ class enrol_ldap_plugin extends enrol_plugin {
         // Get all contexts and look for first matching user
         $ldap_contexts = explode(';', $ldap_contexts);
         $ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
-        $ldap_cookie = '';
         foreach ($ldap_contexts as $context) {
             $context = trim($context);
             if (empty($context)) {
                 continue;
             }
 
+            $ldap_cookie = '';
             $flat_records = array();
             do {
                 if ($ldap_pagedresults) {
index 2ee9a7b..984354a 100644 (file)
@@ -586,16 +586,29 @@ class course_enrolment_manager {
      */
     public function unassign_role_from_user($userid, $roleid) {
         global $DB;
-        require_capability('moodle/role:assign', $this->context);
-        $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
-        try {
-            role_unassign($roleid, $user->id, $this->context->id, '', NULL);
-        } catch (Exception $e) {
+        // Admins may unassign any role, others only those they could assign.
+        if (!is_siteadmin() and !array_key_exists($roleid, $this->get_assignable_roles())) {
             if (defined('AJAX_SCRIPT')) {
-                throw $e;
+                throw new moodle_exception('invalidrole');
             }
             return false;
         }
+        $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+        $ras = $DB->get_records('role_assignments', array('contextid'=>$this->context->id, 'userid'=>$user->id, 'roleid'=>$roleid));
+        foreach ($ras as $ra) {
+            if ($ra->component) {
+                if (strpos($ra->component, 'enrol_') !== 0) {
+                    continue;
+                }
+                if (!$plugin = enrol_get_plugin(substr($ra->component, 6))) {
+                    continue;
+                }
+                if ($plugin->roles_protected()) {
+                    continue;
+                }
+            }
+            role_unassign($ra->roleid, $ra->userid, $ra->contextid, $ra->component, $ra->itemid);
+        }
         return true;
     }
 
@@ -706,6 +719,7 @@ class course_enrolment_manager {
     public function get_user_roles($userid) {
         $roles = array();
         $ras = get_user_roles($this->context, $userid, true, 'c.contextlevel DESC, r.sortorder ASC');
+        $plugins = $this->get_enrolment_plugins(false);
         foreach ($ras as $ra) {
             if ($ra->contextid != $this->context->id) {
                 if (!array_key_exists($ra->roleid, $roles)) {
@@ -717,7 +731,18 @@ class course_enrolment_manager {
             if (array_key_exists($ra->roleid, $roles) && $roles[$ra->roleid] === false) {
                 continue;
             }
-            $roles[$ra->roleid] = ($ra->itemid == 0 and $ra->component === '');
+            $changeable = true;
+            if ($ra->component) {
+                $changeable = false;
+                if (strpos($ra->component, 'enrol_') === 0) {
+                    $plugin = substr($ra->component, 6);
+                    if (isset($plugins[$plugin])) {
+                        $changeable = !$plugins[$plugin]->roles_protected();
+                    }
+                }
+            }
+
+            $roles[$ra->roleid] = $changeable;
         }
         return $roles;
     }
@@ -807,6 +832,7 @@ class course_enrolment_manager {
 
         $userroles = $this->get_other_users($sort, $direction, $page, $perpage);
         $roles = $this->get_all_roles();
+        $plugins = $this->get_enrolment_plugins(false);
 
         $context    = $this->get_context();
         $now = time();
@@ -821,8 +847,17 @@ class course_enrolment_manager {
             }
             $a = new stdClass;
             $a->role = $roles[$userrole->roleid]->localname;
-            $changeable = ($userrole->component == '');
             if ($contextid == $this->context->id) {
+                $changeable = true;
+                if ($userrole->component) {
+                    $changeable = false;
+                    if (strpos($userrole->component, 'enrol_') === 0) {
+                        $plugin = substr($userrole->component, 6);
+                        if (isset($plugins[$plugin])) {
+                            $changeable = !$plugin[$plugin]->roles_protected();
+                        }
+                    }
+                }
                 $roletext = get_string('rolefromthiscourse', 'enrol', $a);
             } else {
                 $changeable = false;
@@ -888,7 +923,11 @@ class course_enrolment_manager {
             // Roles
             $details['roles'] = array();
             foreach ($this->get_user_roles($user->id) as $rid=>$rassignable) {
-                $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>(!$rassignable || !isset($assignable[$rid])));
+                $unchangeable = !$rassignable;
+                if (!is_siteadmin() and !isset($assignable[$rid])) {
+                    $unchangeable = true;
+                }
+                $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>$unchangeable);
             }
 
             // Users
index 3fd7f52..4decf20 100644 (file)
@@ -47,6 +47,7 @@ $PAGE->set_pagelayout('admin');
 $manager = new course_enrolment_manager($PAGE, $course, $filter);
 $table = new course_enrolment_other_users_table($manager, $PAGE);
 $PAGE->set_url('/enrol/otherusers.php', $manager->get_url_params()+$table->get_url_params());
+navigation_node::override_active_url(new moodle_url('/enrol/otherusers.php', array('id' => $id)));
 
 $userdetails = array (
     'picture' => false,
index 05e43f5..de8505c 100644 (file)
@@ -189,7 +189,7 @@ class core_enrol_renderer extends plugin_renderer_base {
         // get list of roles
         $rolesoutput = '';
         foreach ($roles as $roleid=>$role) {
-            if ($canassign && !$role['unchangeable']) {
+            if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) {
                 $strunassign = get_string('unassignarole', 'role', $role['text']);
                 $icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove));
                 $url = new moodle_url($pageurl, array('action'=>'unassign', 'role'=>$roleid, 'user'=>$userid));
index 8caef86..ea065a5 100644 (file)
@@ -26,6 +26,6 @@ function xmldb_filter_activitynames_install() {
     global $CFG;
     require_once("$CFG->libdir/filterlib.php");
 
-    filter_set_global_state('filter/activitynames', TEXTFILTER_ON);
+    filter_set_global_state('activitynames', TEXTFILTER_ON);
 }
 
index d451fbf..3939977 100644 (file)
@@ -7,7 +7,7 @@
 
     require_once("../../config.php");
 
-    if (!filter_is_enabled('filter/algebra')) {
+    if (!filter_is_enabled('algebra')) {
         print_error('filternotenabled');
     }
 
index a4f5843..c4f29d9 100644 (file)
@@ -9,7 +9,7 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
 
     require_once('../../config.php');
 
-    if (!filter_is_enabled('filter/algebra')) {
+    if (!filter_is_enabled('algebra')) {
         print_error('filternotenabled');
     }
 
index 04893f1..19a1e29 100644 (file)
@@ -27,7 +27,7 @@ require_once(dirname(__FILE__) . '/../config.php');
 require_once($CFG->libdir . '/adminlib.php');
 
 $contextid = required_param('contextid',PARAM_INT);
-$forfilter = optional_param('filter', '', PARAM_SAFEPATH);
+$forfilter = optional_param('filter', '', PARAM_SAFEDIR);
 
 list($context, $course, $cm) = get_context_info_array($contextid);
 
@@ -82,8 +82,8 @@ if ($forfilter) {
         print_error('filterdoesnothavelocalconfig', 'error', $forfilter);
     }
     require_once($CFG->dirroot . '/filter/local_settings_form.php');
-    require_once($CFG->dirroot . '/' . $forfilter . '/filterlocalsettings.php');
-    $formname = basename($forfilter) . '_filter_local_settings_form';
+    require_once($CFG->dirroot . '/filter/' . $forfilter . '/filterlocalsettings.php');
+    $formname = $forfilter . '_filter_local_settings_form';
     $settingsform = new $formname($CFG->wwwroot . '/filter/manage.php', $forfilter, $context);
     if ($settingsform->is_cancelled()) {
         redirect($baseurl);
@@ -96,7 +96,7 @@ if ($forfilter) {
 /// Process any form submission.
 if ($forfilter == '' && optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
     foreach ($availablefilters as $filter => $filterinfo) {
-        $newstate = optional_param(str_replace('/', '_', $filter), false, PARAM_INT);
+        $newstate = optional_param($filter, false, PARAM_INT);
         if ($newstate !== false && $newstate != $filterinfo->localstate) {
             filter_set_local_state($filter, $context->id, $newstate);
         }
@@ -181,9 +181,8 @@ if (empty($availablefilters)) {
         } else {
             $activechoices[TEXTFILTER_INHERIT] = $strdefaultoff;
         }
-        $filtername = str_replace('/', '_', $filter);
-        $select = html_writer::label($filterinfo->localstate, 'menu'. $filtername, false, array('class' => 'accesshide'));
-        $select .= html_writer::select($activechoices, $filtername, $filterinfo->localstate, false);
+        $select = html_writer::label($filterinfo->localstate, 'menu'. $filter, false, array('class' => 'accesshide'));
+        $select .= html_writer::select($activechoices, $filter, $filterinfo->localstate, false);
         $row[] = $select;
 
         // Settings link, if required
index 64e3fb9..c128f85 100644 (file)
@@ -27,6 +27,6 @@ function xmldb_filter_mediaplugin_install() {
     global $CFG;
     require_once("$CFG->libdir/filterlib.php");
 
-    filter_set_global_state('filter/mediaplugin', TEXTFILTER_ON);
+    filter_set_global_state('mediaplugin', TEXTFILTER_ON);
 }
 
index ddc6ee6..76eb64a 100644 (file)
@@ -29,7 +29,7 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
 
 require('../../config.php');
 
-if (!filter_is_enabled('filter/tex') and !filter_is_enabled('filter/algebra')) {
+if (!filter_is_enabled('tex') and !filter_is_enabled('algebra')) {
     print_error('filternotenabled');
 }
 
index deb43d5..4ae2cd0 100644 (file)
@@ -9,7 +9,7 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
 
     require_once('../../config.php');
 
-    if (!filter_is_enabled('filter/tex')) {
+    if (!filter_is_enabled('tex')) {
         print_error('filternotenabled');
     }
 
index 3200449..0817d7e 100644 (file)
@@ -28,7 +28,7 @@
 
     require_once("../../config.php");
 
-    if (!filter_is_enabled('filter/tex')) {
+    if (!filter_is_enabled('tex')) {
         print_error('filternotenabled');
     }
 
index cf94ace..99cffdd 100644 (file)
@@ -1,6 +1,13 @@
 This file describes API changes in core filter API and plugins,
 information provided here is intended especially for developers.
 
+=== 2.5 ===
+
+* legacy_filter emulation was removed
+* support for 'mod/*' filters was removed
+* use short filter name instead of old path, ex.: 'filter/tex' ---> 'tex'
+  in all filter API functions and methods
+
 === 2.3 ===
 
 * new setup() method added to moodle_text_filter, invoked before
index 820148f..62c7a4f 100644 (file)
@@ -273,12 +273,6 @@ class grade_edit_tree {
                 $root = true;
             }
 
-            $row_count_offset = 0;
-
-            if (empty($category_total_item) && !$this->moving) {
-                $row_count_offset = -1;
-            }
-
             $levelclass = "level$level";
 
             $courseclass = '';
@@ -297,7 +291,7 @@ class grade_edit_tree {
             $headercell->scope = 'row';
             $headercell->attributes['title'] = $object->stripped_name;
             $headercell->attributes['class'] = 'cell rowspan ' . $levelclass;
-            $headercell->rowspan = $row_count+1+$row_count_offset;
+            $headercell->rowspan = $row_count + 1;
             $row->cells[] = $headercell;
 
             foreach ($this->columns as $column) {
index f7599d7..5963c6e 100644 (file)
@@ -579,7 +579,7 @@ class core_group_external extends external_api {
                             'courseid' => new external_value(PARAM_INT, 'id of course'),
                             'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
                             'description' => new external_value(PARAM_RAW, 'grouping description text'),
-                            'descriptionformat' => new external_format_value('descripiton', VALUE_DEFAULT)
+                            'descriptionformat' => new external_format_value('description', VALUE_DEFAULT)
                         )
                     ), 'List of grouping object. A grouping has a courseid, a name and a description.'
                 )
index a685f0e..d662beb 100644 (file)
@@ -39,6 +39,8 @@ $string['defaultweight'] = 'Default weight';
 $string['defaultweight_help'] = 'The default weight allows you to choose roughly where you want the block to appear in the chosen region, either at the top or the bottom. The final location is calculated from all the blocks in that region (for example, only one block can actually be at the top). This value can be overridden on specific pages if required.';
 $string['deletecheck'] = 'Delete {$a} block?';
 $string['deleteblockcheck'] = 'Are you sure that you want to delete this block titled {$a}?';
+$string['hidedockpanel'] = 'Hide the dock panel';
+$string['hidepanel'] = 'Hide panel';
 $string['moveblockhere'] = 'Move block here';
 $string['movingthisblockcancel'] = 'Moving this block ({$a})';
 $string['onthispage'] = 'On this page';
index b211788..0bf030b 100644 (file)
@@ -331,6 +331,7 @@ $string['invalidurl'] = 'Invalid URL';
 $string['invaliduser'] = 'Invalid user';
 $string['invaliduserid'] = 'Invalid user id';
 $string['invaliduserfield'] = 'Invalid user field: {$a}';
+$string['invalidusername'] = 'The given username contains invalid characters';
 $string['invalidxmlfile'] = '"{$a}" is not a valid XML file';
 $string['iplookupfailed'] = 'Cannot find geo information about this IP address {$a}';
 $string['iplookupprivate'] = 'Cannot display lookup of private IP address';
index ba9a666..674fdb4 100644 (file)
@@ -6092,8 +6092,7 @@ class admin_page_managefilters extends admin_externalpage {
                 $found = true;
                 break;
             }
-            list($type, $filter) = explode('/', $path);
-            if (strpos($filter, $query) !== false) {
+            if (strpos($path, $query) !== false) {
                 $found = true;
                 break;
             }
index f60af6c..bea2404 100644 (file)
     <TABLE NAME="filter_active" COMMENT="Stores information about which filters are active in which contexts. Also the filter sort order. See get_active_filters in lib/filterlib.php for how this data is used." PREVIOUS="course_format_options" NEXT="filter_config">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="filter"/>
-        <FIELD NAME="filter" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The filter internal name, like 'filter/tex' or 'mod/glossary'." PREVIOUS="id" NEXT="contextid"/>
+        <FIELD NAME="filter" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The filter internal name, like 'tex'." PREVIOUS="id" NEXT="contextid"/>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="References context.id." PREVIOUS="filter" NEXT="active"/>
         <FIELD NAME="active" TYPE="int" LENGTH="4" NOTNULL="true" SEQUENCE="false" COMMENT="Whether this filter is active in this context. +1 = On, -1 = Off, no row with this contextid = inherit. As a special case, when contextid points to the system context, -9999 means this filter is completely disabled." PREVIOUS="contextid" NEXT="sortorder"/>
         <FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Only relevant if contextid points to the system context. In other cases this field should contain 0. The order in which the filters should be applied." PREVIOUS="active"/>
     <TABLE NAME="filter_config" COMMENT="Stores per-context configuration settings for filters which have them." PREVIOUS="filter_active" NEXT="event">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="filter"/>
-        <FIELD NAME="filter" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The filter internal name, like 'filter/tex' or 'mod/glossary'." PREVIOUS="id" NEXT="contextid"/>
+        <FIELD NAME="filter" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The filter internal name, like 'tex'." PREVIOUS="id" NEXT="contextid"/>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="References context.id." PREVIOUS="filter" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The config variable name." PREVIOUS="contextid" NEXT="value"/>
         <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="The correspoding config variable value." PREVIOUS="name"/>
index 48a78a8..3dcc1d1 100644 (file)
@@ -1524,5 +1524,46 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012120300.04);
     }
 
+    if ($oldversion < 2012120300.07) {
+        // Purge removed module filters and all their settings.
+
+        $tables = array('filter_active', 'filter_config');
+        foreach ($tables as $table) {
+            $DB->delete_records_select($table, "filter LIKE 'mod/%'");
+            $filters = $DB->get_records_sql("SELECT DISTINCT filter FROM {{$table}} WHERE filter LIKE 'filter/%'");
+            foreach ($filters as $filter) {
+                $DB->set_field($table, 'filter', substr($filter->filter, 7), array('filter'=>$filter->filter));
+            }
+        }
+
+        $configs = array('stringfilters', 'filterall');
+        foreach ($configs as $config) {
+            if ($filters = get_config(null, $config)) {
+                $filters = explode(',', $filters);
+                $newfilters = array();
+                foreach($filters as $filter) {
+                    if (strpos($filter, '/') === false) {
+                        $newfilters[] = $filter;
+                    } else if (strpos($filter, 'filter/') === 0) {
+                        $newfilters[] = substr($filter, 7);
+                    }
+                }
+                $filters = implode(',', $newfilters);
+                set_config($config, $filters);
+            }
+        }
+
+        unset($tables);
+        unset($table);
+        unset($configs);
+        unset($newfilters);
+        unset($filters);
+        unset($filter);
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2012120300.07);
+    }
+
+
     return true;
 }
index 6c2eac2..d4b8ac7 100644 (file)
@@ -33,7 +33,7 @@ class tinymce_dragmath extends editor_tinymce_plugin {
         if ($this->get_config('requiretex', 1)) {
             // If TeX filter is disabled, do not add button.
             $filters = filter_get_active_in_context($context);
-            if (!array_key_exists('filter/tex', $filters)) {
+            if (!array_key_exists('tex', $filters)) {
                 return;
             }
         }
index f61c9ea..c2751a5 100644 (file)
@@ -34,7 +34,7 @@ class tinymce_moodleemoticon extends editor_tinymce_plugin {
         if ($this->get_config('requireemoticon', 1)) {
             // If emoticon filter is disabled, do not add button.
             $filters = filter_get_active_in_context($context);
-            if (!array_key_exists('filter/emoticon', $filters)) {
+            if (!array_key_exists('emoticon', $filters)) {
                 return;
             }
         }
index ed606cf..afe04fb 100644 (file)
@@ -1,3 +1,5 @@
+Version 2.0.6.1 (2012-11-16)\r
+       Fixed security issue with google spellchecker.\r
 Version 2.0.6 (2011-09-29)\r
        Fixed incorrect position of suggestion menu.\r
        Fixed handling of mispelled words with no suggestions in PSpellShell engine.\r
index e3acf2d..5edf76a 100644 (file)
@@ -51,6 +51,8 @@ class GoogleSpell extends SpellChecker {
        }\r
 \r
        function &_getMatches($lang, $str) {\r
+               $lang = preg_replace('/[^a-z\-]/i', '', $lang); // Sanitize, remove everything but a-z or -\r
+               $str = preg_replace('/[\x00-\x1F\x7F]/', '', $str); // Sanitize, remove all control characters\r
                $server = "www.google.com";\r
                $port = 443;\r
                $path = "/tbproxy/spell?lang=" . $lang . "&hl=en";\r
@@ -126,6 +128,7 @@ class GoogleSpell extends SpellChecker {
        }\r
 \r
        function _unhtmlentities($string) {\r
+        return textlib::entities_to_utf8($string); // Moodle hack\r
                $string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);\r
                $string = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $string);\r
 \r
index ffd1bee..deb2af9 100644 (file)
@@ -7,6 +7,4 @@ List of changes:
 * Modified config file to use moodle $CFG.
 * Moved static files to /tinymce/ subfolder.
 * MDL-25736 - French spellchecker fixes.
-
-Commits:
-https://github.com/moodle/custom-tinymce_spellchecker_php/commits/MOODLE_22_2.0.6b
+* Fix htmlentities conversion in GoogleSpell.php
index 2bdb84d..5696839 100644 (file)
@@ -2,6 +2,11 @@ This files describes API changes in /lib/editor/tinymce/* - TinyMCE editor,
 information provided here is intended especially for developers.
 
 
+=== 2.5 ===
+
+* update filter related code to use short filter names instead
+  of original paths, ex.: 'filter/tex' ---> 'tex'
+
 === 2.4 ===
 
 new features:
index ab120b3..3f6cb45 100644 (file)
@@ -2715,7 +2715,7 @@ function file_modify_html_header($text) {
     }*/
 
     $ufo = '';
-    if (filter_is_enabled('filter/mediaplugin')) {
+    if (filter_is_enabled('mediaplugin')) {
         // this script is needed by most media filter plugins.
         $attributes = array('type'=>'text/javascript', 'src'=>$CFG->httpswwwroot . '/lib/ufo.js');
         $ufo = html_writer::tag('script', '', $attributes) . "\n";
index de80835..b8760c0 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -18,8 +17,7 @@
 /**
  * Library functions for managing text filter plugins.
  *
- * @package    core
- * @subpackage filter
+ * @package    core_filter
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -50,8 +48,7 @@ define('TEXTFILTER_EXCL_SEPARATOR', '-%-');
  *
  * This class is a singleton.
  *
- * @package    core
- * @subpackage filter
+ * @package    core_filter
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -115,33 +112,27 @@ class filter_manager {
     }
 
     /**
-     * Factory method for creating a filter
+     * Factory method for creating a filter.
      *
-     * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
-     * @param object $context context object.
+     * @param string $filtername The filter name, for example 'tex'.
+     * @param context $context context object.
      * @param array $localconfig array of local configuration variables for this filter.
-     * @return object moodle_text_filter The filter, or null, if this type of filter is
+     * @return moodle_text_filter The filter, or null, if this type of filter is
      *      not recognised or could not be created.
      */
     protected function make_filter_object($filtername, $context, $localconfig) {
         global $CFG;
-        $path = $CFG->dirroot .'/'. $filtername .'/filter.php';
+        $path = $CFG->dirroot .'/filter/'. $filtername .'/filter.php';
         if (!is_readable($path)) {
             return null;
         }
         include_once($path);
 
-        $filterclassname = 'filter_' . basename($filtername);
+        $filterclassname = 'filter_' . $filtername;
         if (class_exists($filterclassname)) {
             return new $filterclassname($context, $localconfig);
         }
 
-        // TODO: deprecated since 2.2, will be out in 2.3, see MDL-29996
-        $legacyfunctionname = basename($filtername) . '_filter';
-        if (function_exists($legacyfunctionname)) {
-            return new legacy_filter($legacyfunctionname, $context, $localconfig);
-        }
-
         return null;
     }
 
@@ -193,7 +184,7 @@ class filter_manager {
      */
     public function filter_text($text, $context, array $options = array()) {
         $text = $this->apply_filter_chain($text, $this->get_text_filters($context), $options);
-        /// <nolink> tags removed for XHTML compatibility
+        // <nolink> tags removed for XHTML compatibility
         $text = str_replace(array('<nolink>', '</nolink>'), '', $text);
         return $text;
     }
@@ -202,7 +193,7 @@ class filter_manager {
      * Filter a piece of string
      *
      * @param string $string The text to filter
-     * @param object $context
+     * @param context $context
      * @return string resulting string
      */
     public function filter_string($string, $context) {
@@ -211,7 +202,7 @@ class filter_manager {
 
     /**
      * @todo Document this function
-     * @param object $context
+     * @param context $context
      * @return object A string filter
      */
     public function text_filtering_hash($context) {
@@ -253,8 +244,7 @@ class filter_manager {
  *
  * @todo Document this class
  *
- * @package    core
- * @subpackage filter
+ * @package    core_filter
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -286,8 +276,7 @@ class null_filter_manager {
  *
  * @todo Document this class
  *
- * @package    core
- * @subpackage filter
+ * @package    core_filter
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -351,8 +340,7 @@ class performance_measuring_filter_manager extends filter_manager {
  * Base class for text filters. You just need to override this class and
  * implement the filter method.
  *
- * @package    core
- * @subpackage filter
+ * @package    core_filter
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -364,9 +352,9 @@ abstract class moodle_text_filter {
 
     /**
      * Set any context-specific configuration for this filter.
-     * @param object $context The current course id.
-     * @param object $context The current context.
-     * @param array $config Any context-specific configuration for this filter.
+     *
+     * @param context $context The current context.
+     * @param array $localconfig Any context-specific configuration for this filter.
      */
     public function __construct($context, array $localconfig) {
         $this->context = $context;
@@ -408,50 +396,6 @@ abstract class moodle_text_filter {
     public abstract function filter($text, array $options = array());
 }
 
-/**
- * moodle_text_filter implementation that encapsulates an old-style filter that
- * only defines a function, not a class.
- *
- * @deprecated since 2.2, see MDL-29995
- * @todo will be out in 2.3, see MDL-29996
- * @package    core
- * @subpackage filter
- * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class legacy_filter extends moodle_text_filter {
-    /** @var string */
-    protected $filterfunction;
-    protected $courseid;
-
-    /**
-     * Set any context-specific configuration for this filter.
-     *
-     * @param string $filterfunction
-     * @param object $context The current context.
-     * @param array $config Any context-specific configuration for this filter.
-     */
-    public function __construct($filterfunction, $context, array $localconfig) {
-        parent::__construct($context, $localconfig);
-        $this->filterfunction = $filterfunction;
-        $this->courseid = get_courseid_from_context($this->context);
-    }
-
-    /**
-     * @param string $text
-     * @param array $options options - not supported for legacy filters
-     * @return mixed
-     */
-    public function filter($text, array $options = array()) {
-        if ($this->courseid) {
-            // old filters are called only when inside courses
-            return call_user_func($this->filterfunction, $this->courseid, $text);
-        } else {
-            return $text;
-        }
-    }
-}
-
 /**
  * This is just a little object to define a phrase and some instructions
  * for how to process it.  Filters can create an array of these to pass
@@ -509,66 +453,40 @@ class filterobject {
 }
 
 /**
- * Look up the name of this filter in the most appropriate location.
- * If $filterlocation = 'mod' then does get_string('filtername', $filter);
- * else if $filterlocation = 'filter' then does get_string('filtername', 'filter_' . $filter);
- * with a fallback to get_string('filtername', $filter) for backwards compatibility.
- * These are the only two options supported at the moment.
+ * Look up the name of this filter
  *
- * @param string $filter the folder name where the filter lives.
+ * @param string $filter the filter name
  * @return string the human-readable name for this filter.
  */
 function filter_get_name($filter) {
-    // TODO: should we be using pluginname here instead? , see MDL-29998
-    list($type, $filter) = explode('/', $filter);
-    switch ($type) {
-        case 'filter':
-            $strfiltername = get_string('filtername', 'filter_' . $filter);
-            if (substr($strfiltername, 0, 2) != '[[') {
-                // found a valid string.
-                return $strfiltername;
-            }
-            // Fall through to try the legacy location.
-
-        // TODO: deprecated since 2.2, will be out in 2.3, see MDL-29996
-        case 'mod':
-            $strfiltername = get_string('filtername', $filter);
-            if (substr($strfiltername, 0, 2) == '[[') {
-                $strfiltername .= ' (' . $type . '/' . $filter . ')';
-            }
-            return $strfiltername;
+    if (strpos($filter, 'filter/') === 0) {
+        debugging("Old '$filter'' parameter used in filter_get_name()");
+        $filter = substr($filter, 7);
+    } else if (strpos($filter, '/') !== false) {
+        throw new coding_exception('Unknown filter type ' . $filter);
+    }
 
-        default:
-            throw new coding_exception('Unknown filter type ' . $type);
+    if (get_string_manager()->string_exists('filtername', 'filter_' . $filter)) {
+        return get_string('filtername', 'filter_' . $filter);
+    } else {
+        return $filter;
     }
 }
 
 /**
  * Get the names of all the filters installed in this Moodle.
  *
- * @global object
  * @return array path => filter name from the appropriate lang file. e.g.
- * array('mod/glossary' => 'Glossary Auto-linking', 'filter/tex' => 'TeX Notation');
+ * array('tex' => 'TeX Notation');
  * sorted in alphabetical order of name.
  */
 function filter_get_all_installed() {
     global $CFG;
+
     $filternames = array();
-    // TODO: deprecated since 2.2, will be out in 2.3, see MDL-29996
-    $filterlocations = array('mod', 'filter');
-    foreach ($filterlocations as $filterlocation) {
-        // TODO: move get_list_of_plugins() to get_plugin_list()
-        $filters = get_list_of_plugins($filterlocation);
-        foreach ($filters as $filter) {
-            // MDL-29994 - Ignore mod/data and mod/glossary filters forever, this will be out in 2.3
-            if ($filterlocation == 'mod' && ($filter == 'data' || $filter == 'glossary')) {
-                continue;
-            }
-            $path = $filterlocation . '/' . $filter;
-            if (is_readable($CFG->dirroot . '/' . $path . '/filter.php')) {
-                $strfiltername = filter_get_name($path);
-                $filternames[$path] = $strfiltername;
-            }
+    foreach (get_list_of_plugins('filter') as $filter) {
+        if (is_readable("$CFG->dirroot/filter/$filter/filter.php")) {
+            $filternames[$filter] = filter_get_name($filter);
         }
     }
     collatorlib::asort($filternames);
@@ -578,17 +496,11 @@ function filter_get_all_installed() {
 /**
  * Set the global activated state for a text filter.
  *
- * @global object
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
- * @param integer $state One of the values TEXTFILTER_ON, TEXTFILTER_OFF or TEXTFILTER_DISABLED.
- * @param integer $sortorder (optional) a position in the sortorder to place this filter.
- *      If not given defaults to:
- *      No change in order if we are updating an existing record, and not changing to or from TEXTFILTER_DISABLED.
- *      Just after the last currently active filter when adding an unknown filter
- *          in state TEXTFILTER_ON or TEXTFILTER_OFF, or enabling/disabling an existing filter.
- *      Just after the very last filter when adding an unknown filter in state TEXTFILTER_DISABLED
+ * @param string $filtername The filter name, for example 'tex'.
+ * @param int $state One of the values TEXTFILTER_ON, TEXTFILTER_OFF or TEXTFILTER_DISABLED.
+ * @param int $move 1 means up, 0 means the same, -1 means down
  */
-function filter_set_global_state($filter, $state, $sortorder = false) {
+function filter_set_global_state($filtername, $state, $move = 0) {
     global $DB;
 
     // Check requested state is valid.
@@ -597,84 +509,141 @@ function filter_set_global_state($filter, $state, $sortorder = false) {
                 "Must be one of TEXTFILTER_ON, TEXTFILTER_OFF or TEXTFILTER_DISABLED.");
     }
 
-    // Check sortorder is valid.
-    if ($sortorder !== false) {
-        if ($sortorder < 1 || $sortorder > $DB->get_field('filter_active', 'MAX(sortorder)', array()) + 1) {
-            throw new coding_exception("Invalid sort order passed to filter_set_global_state.");
-        }
+    if ($move > 0) {
+        $move = 1;
+    } else if ($move < 0) {
+        $move = -1;
+    }
+
+    if (strpos($filtername, 'filter/') === 0) {
+        //debugging("Old filtername '$filtername' parameter used in filter_set_global_state()", DEBUG_DEVELOPER);
+        $filtername = substr($filtername, 7);
+    } else if (strpos($filtername, '/') !== false) {
+        throw new coding_exception("Invalid filter name '$filtername' used in filter_set_global_state()");
     }
 
-    // See if there is an existing record.
+    $transaction = $DB->start_delegated_transaction();
+
     $syscontext = context_system::instance();
-    $rec = $DB->get_record('filter_active', array('filter' => $filter, 'contextid' => $syscontext->id));
-    if (empty($rec)) {
-        $insert = true;
-        $rec = new stdClass;
-        $rec->filter = $filter;
-        $rec->contextid = $syscontext->id;
-    } else {
-        $insert = false;
-        if ($sortorder === false && !($rec->active == TEXTFILTER_DISABLED xor $state == TEXTFILTER_DISABLED)) {
-            $sortorder = $rec->sortorder;
+    $filters = $DB->get_records('filter_active', array('contextid' => $syscontext->id), 'sortorder ASC');
+
+    $on = array();
+    $off = array();
+
+    foreach($filters as $f) {
+        if ($f->active == TEXTFILTER_DISABLED) {
+            $off[$f->filter] = $f;
+        } else {
+            $on[$f->filter] = $f;
         }
     }
 
-    // Automatic sort order.
-    if ($sortorder === false) {
-        if ($state == TEXTFILTER_DISABLED && $insert) {
-            $prevmaxsortorder = $DB->get_field('filter_active', 'MAX(sortorder)', array());
-        } else {
-            $prevmaxsortorder = $DB->get_field_select('filter_active', 'MAX(sortorder)', 'active <> ?', array(TEXTFILTER_DISABLED));
+    // Update the state or add new record.
+    if (isset($on[$filtername])) {
+        $filter = $on[$filtername];
+        if ($filter->active != $state) {
+            $filter->active = $state;
+            $DB->update_record('filter_active', $filter);
+            if ($filter->active == TEXTFILTER_DISABLED) {
+                unset($on[$filtername]);
+                $off = array($filter->filter => $filter) + $off;
+            }
         }
-        if (empty($prevmaxsortorder)) {
-            $sortorder = 1;
-        } else {
-            $sortorder = $prevmaxsortorder + 1;
-            if (!$insert && $state == TEXTFILTER_DISABLED) {
-                $sortorder = $prevmaxsortorder;
+
+    } else if (isset($off[$filtername])) {
+        $filter = $off[$filtername];
+        if ($filter->active != $state) {
+            $filter->active = $state;
+            $DB->update_record('filter_active', $filter);
+            if ($filter->active != TEXTFILTER_DISABLED) {
+                unset($off[$filtername]);
+                $on[$filter->filter] = $filter;
             }
         }
+
+    } else {
+        $filter = new stdClass();
+        $filter->filter    = $filtername;
+        $filter->contextid = $syscontext->id;
+        $filter->active    = $state;
+        $filter->sortorder = 99999;
+        $filter->id = $DB->insert_record('filter_active', $filter);
+
+        $filters[$filter->id] = $filter;
+        if ($state == TEXTFILTER_DISABLED) {
+            $off[$filter->filter] = $filter;
+        } else {
+            $on[$filter->filter] = $filter;
+        }
     }
 
-    // Move any existing records out of the way of the sortorder.
-    if ($insert) {
-        $DB->execute('UPDATE {filter_active} SET sortorder = sortorder + 1 WHERE sortorder >= ?', array($sortorder));
-    } else if ($sortorder != $rec->sortorder) {
-        $sparesortorder = $DB->get_field('filter_active', 'MIN(sortorder)', array()) - 1;
-        $DB->set_field('filter_active', 'sortorder', $sparesortorder, array('filter' => $filter, 'contextid' => $syscontext->id));
-        if ($sortorder < $rec->sortorder) {
-            $DB->execute('UPDATE {filter_active} SET sortorder = sortorder + 1 WHERE sortorder >= ? AND sortorder < ?',
-                    array($sortorder, $rec->sortorder));
-        } else if ($sortorder > $rec->sortorder) {
-            $DB->execute('UPDATE {filter_active} SET sortorder = sortorder - 1 WHERE sortorder <= ? AND sortorder > ?',
-                    array($sortorder, $rec->sortorder));
+    // Move only active.
+    if ($move != 0 and isset($on[$filter->filter])) {
+        $i = 1;
+        foreach ($on as $f) {
+            $f->newsortorder = $i;
+            $i++;
         }
+
+        $filter->newsortorder = $filter->newsortorder + $move;
+
+        foreach ($on as $f) {
+            if ($f->id == $filter->id) {
+                continue;
+            }
+            if ($f->newsortorder == $filter->newsortorder) {
+                if ($move == 1) {
+                    $f->newsortorder = $f->newsortorder - 1;
+                } else {
+                    $f->newsortorder = $f->newsortorder + 1;
+                }
+            }
+        }
+
+        collatorlib::asort_objects_by_property($on, 'newsortorder', collatorlib::SORT_NUMERIC);
     }
 
-    // Insert/update the new record.
-    $rec->active = $state;
-    $rec->sortorder = $sortorder;
-    if ($insert) {
-        $DB->insert_record('filter_active', $rec);
-    } else {
-        $DB->update_record('filter_active', $rec);
+    // Inactive are sorted by filter name.
+    collatorlib::asort_objects_by_property($off, 'filter', collatorlib::SORT_NATURAL);
+
+    // Update records if necessary.
+    $i = 1;
+    foreach ($on as $f) {
+        if ($f->sortorder != $i) {
+            $DB->set_field('filter_active', 'sortorder', $i, array('id'=>$f->id));
+        }
+        $i++;
+    }
+    foreach ($off as $f) {
+        if ($f->sortorder != $i) {
+            $DB->set_field('filter_active', 'sortorder', $i, array('id'=>$f->id));
+        }
+        $i++;
     }
+
+    $transaction->allow_commit();
 }
 
 /**
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filtername The filter name, for example 'tex'.
  * @return boolean is this filter allowed to be used on this site. That is, the
  *      admin has set the global 'active' setting to On, or Off, but available.
  */
-function filter_is_enabled($filter) {
-    return array_key_exists($filter, filter_get_globally_enabled());
+function filter_is_enabled($filtername) {
+    if (strpos($filtername, 'filter/') === 0) {
+        //debugging("Old filtername '$filtername' parameter used in filter_is_enabled()", DEBUG_DEVELOPER);
+        $filtername = substr($filtername, 7);
+    } else if (strpos($filtername, '/') !== false) {
+        throw new coding_exception("Invalid filter name '$filtername' used in filter_is_enabled()");
+    }
+    return array_key_exists($filtername, filter_get_globally_enabled());
 }
 
 /**
  * Return a list of all the filters that may be in use somewhere.
  *
  * @staticvar array $enabledfilters
- * @return array where the keys and values are both the filter name, like 'filter/tex'.
+ * @return array where the keys and values are both the filter name, like 'tex'.
  */
 function filter_get_globally_enabled() {
     static $enabledfilters = null;
@@ -694,8 +663,7 @@ function filter_get_globally_enabled() {
  * Return the names of the filters that should also be applied to strings
  * (when they are enabled).
  *
- * @global object
- * @return array where the keys and values are both the filter name, like 'filter/tex'.
+ * @return array where the keys and values are both the filter name, like 'tex'.
  */
 function filter_get_string_filters() {
     global $CFG;
@@ -711,7 +679,7 @@ function filter_get_string_filters() {
  * Sets whether a particular active filter should be applied to all strings by
  * format_string, or just used by format_text.
  *
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @param boolean $applytostrings if true, this filter will apply to format_string
  *      and format_text, when it is enabled.
  */
@@ -732,8 +700,7 @@ function filter_set_applies_to_strings($filter, $applytostrings) {
 /**
  * Set the local activated state for a text filter.
  *
- * @global object
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @param integer $contextid The id of the context to get the local config for.
  * @param integer $state One of the values TEXTFILTER_ON, TEXTFILTER_OFF or TEXTFILTER_INHERIT.
  * @return void
@@ -778,8 +745,7 @@ function filter_set_local_state($filter, $contextid, $state) {
 /**
  * Set a particular local config variable for a filter in a context.
  *
- * @global object
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @param integer $contextid The id of the context to get the local config for.
  * @param string $name the setting name.
  * @param string $value the corresponding value.
@@ -808,8 +774,7 @@ function filter_set_local_config($filter, $contextid, $name, $value) {
 /**
  * Remove a particular local config variable for a filter in a context.
  *
- * @global object
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @param integer $contextid The id of the context to get the local config for.
  * @param string $name the setting name.
  */
@@ -824,8 +789,7 @@ function filter_unset_local_config($filter, $contextid, $name) {
  * for you automatically. You only need this, for example, when you are getting
  * the config so you can show the user an editing from.
  *
- * @global object
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @param integer $contextid The ID of the context to get the local config for.
  * @return array of name => value pairs.
  */
@@ -838,7 +802,6 @@ function filter_get_local_config($filter, $contextid) {
  * This function is for use by backup. Gets all the filter information specific
  * to one context.
  *
- * @global object
  * @param int $contextid
  * @return array Array with two elements. The first element is an array of objects with
  *      fields filter and active. These come from the filter_active table. The
@@ -847,7 +810,6 @@ function filter_get_local_config($filter, $contextid) {
  */
 function filter_get_all_local_settings($contextid) {
     global $DB;
-    $context = context_system::instance();
     return array(
         $DB->get_records('filter_active', array('contextid' => $contextid), 'filter', 'filter,active'),
         $DB->get_records('filter_config', array('contextid' => $contextid), 'filter,name', 'filter,name,value'),
@@ -858,14 +820,13 @@ function filter_get_all_local_settings($contextid) {
  * Get the list of active filters, in the order that they should be used
  * for a particular context, along with any local configuration variables.
  *
- * @global object
- * @param object $context a context
+ * @param context $context a context
  * @return array an array where the keys are the filter names, for example
- *      'filter/tex' or 'mod/glossary' and the values are any local
+ *      'tex' and the values are any local
  *      configuration for that filter, as an array of name => value pairs
  *      from the filter_config table. In a lot of cases, this will be an
  *      empty array. So, an example return value for this function might be
- *      array('filter/tex' => array(), 'mod/glossary' => array('glossaryid', 123))
+ *      array(tex' => array())
  */
 function filter_get_active_in_context($context) {
     global $DB, $FILTERLIB_PRIVATE;
@@ -891,15 +852,13 @@ function filter_get_active_in_context($context) {
              JOIN {context} ctx ON f.contextid = ctx.id
              WHERE ctx.id IN ($contextids)
              GROUP BY filter
-             HAVING MAX(f.active * " . $DB->sql_cast_2signed('ctx.depth') .
-                    ") > -MIN(f.active * " . $DB->sql_cast_2signed('ctx.depth') . ")
+             HAVING MAX(f.active * ctx.depth) > -MIN(f.active * ctx.depth)
          ) active
          LEFT JOIN {filter_config} fc ON fc.filter = active.filter AND fc.contextid = $context->id
          ORDER BY active.sortorder";
-    //TODO: remove sql_cast_2signed() once we do not support upgrade from Moodle 2.2
     $rs = $DB->get_recordset_sql($sql);
 
-    // Masssage the data into the specified format to return.
+    // Massage the data into the specified format to return.
     $filters = array();
     foreach ($rs as $row) {
         if (!isset($filters[$row->filter])) {
@@ -918,6 +877,7 @@ function filter_get_active_in_context($context) {
 /**
  * Preloads the list of active filters for all activities (modules) on the course
  * using two database queries.
+ *
  * @param course_modinfo $modinfo Course object from get_fast_modinfo
  */
 function filter_preload_activities(course_modinfo $modinfo) {
@@ -1000,7 +960,7 @@ function filter_preload_activities(course_modinfo $modinfo) {
         }
     }
 
-    // Chuck away the ones that aren't active
+    // Chuck away the ones that aren't active.
     foreach ($courseactive as $filter=>$score) {
         if ($score <= 0) {
             unset($courseactive[$filter]);
@@ -1010,7 +970,7 @@ function filter_preload_activities(course_modinfo $modinfo) {
     }
 
     // Loop through the contexts to reconstruct filter_active lists for each
-    // cm on the course
+    // cm on the course.
     if (!isset($FILTERLIB_PRIVATE->active)) {
         $FILTERLIB_PRIVATE->active = array();
     }
@@ -1023,18 +983,18 @@ function filter_preload_activities(course_modinfo $modinfo) {
             foreach ($remainingactives[$contextid] as $row) {
                 if ($row->active > 0 && empty($banned[$row->filter])) {
                     // If it's marked active for specific context, add entry
-                    // (doesn't matter if one exists already)
+                    // (doesn't matter if one exists already).
                     $FILTERLIB_PRIVATE->active[$contextid][$row->filter] = array();
                 } else {
                     // If it's marked inactive, remove entry (doesn't matter
-                    // if it doesn't exist)
+                    // if it doesn't exist).
                     unset($FILTERLIB_PRIVATE->active[$contextid][$row->filter]);
                 }
             }
         }
     }
 
-    // Process all config rows to add config data to these entries
+    // Process all config rows to add config data to these entries.
     foreach ($filterconfigs as $row) {
         if (isset($FILTERLIB_PRIVATE->active[$row->contextid][$row->filter])) {
             $FILTERLIB_PRIVATE->active[$row->contextid][$row->filter][$row->name] = $row->value;
@@ -1046,10 +1006,9 @@ function filter_preload_activities(course_modinfo $modinfo) {
  * List all of the filters that are available in this context, and what the
  * local and inherited states of that filter are.
  *
- * @global object
- * @param object $context a context that is not the system context.
- * @return array an array with filter names, for example 'filter/tex' or
- *      'mod/glossary' as keys. and and the values are objects with fields:
+ * @param context $context a context that is not the system context.
+ * @return array an array with filter names, for example 'tex'
+ *      as keys. and and the values are objects with fields:
  *      ->filter filter name, same as the key.
  *      ->localstate TEXTFILTER_ON/OFF/INHERIT
  *      ->inheritedstate TEXTFILTER_ON/OFF - the state that will be used if localstate is set to TEXTFILTER_INHERIT.
@@ -1072,8 +1031,7 @@ function filter_get_available_in_context($context) {
                 ELSE fa.active END AS localstate,
              parent_states.inheritedstate
          FROM (SELECT f.filter, MAX(f.sortorder) AS sortorder,
-                    CASE WHEN MAX(f.active * " . $DB->sql_cast_2signed('ctx.depth') .
-                            ") > -MIN(f.active * " . $DB->sql_cast_2signed('ctx.depth') . ") THEN " . TEXTFILTER_ON . "
+                    CASE WHEN MAX(f.active * ctx.depth) > -MIN(f.active * ctx.depth) THEN " . TEXTFILTER_ON . "
                     ELSE " . TEXTFILTER_OFF . " END AS inheritedstate
              FROM {filter_active} f
              JOIN {context} ctx ON f.contextid = ctx.id
@@ -1089,7 +1047,6 @@ function filter_get_available_in_context($context) {
 /**
  * This function is for use by the filter administration page.
  *
- * @global object
  * @return array 'filtername' => object with fields 'filter' (=filtername), 'active' and 'sortorder'
  */
 function filter_get_global_states() {
@@ -1101,14 +1058,12 @@ function filter_get_global_states() {
 /**
  * Delete all the data in the database relating to a filter, prior to deleting it.
  *
- * @global object
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  */
 function filter_delete_all_for_filter($filter) {
     global $DB;
-    if (substr($filter, 0, 7) == 'filter/') {
-        unset_all_config_for_plugin('filter_' . basename($filter));
-    }
+
+    unset_all_config_for_plugin('filter_' . $filter);
     $DB->delete_records('filter_active', array('filter' => $filter));
     $DB->delete_records('filter_config', array('filter' => $filter));
 }
@@ -1126,27 +1081,26 @@ function filter_delete_all_for_context($contextid) {
 
 /**
  * Does this filter have a global settings page in the admin tree?
- * (The settings page for a filter must be called, for example,
- * filtersettingfiltertex or filtersettingmodglossay.)
+ * (The settings page for a filter must be called, for example, filtersettingfiltertex.)
  *
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @return boolean Whether there should be a 'Settings' link on the config page.
  */
 function filter_has_global_settings($filter) {
     global $CFG;
-    $settingspath = $CFG->dirroot . '/' . $filter . '/filtersettings.php';
+    $settingspath = $CFG->dirroot . '/filter/' . $filter . '/filtersettings.php';
     return is_readable($settingspath);
 }
 
 /**
  * Does this filter have local (per-context) settings?
  *
- * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @param string $filter The filter name, for example 'tex'.
  * @return boolean Whether there should be a 'Settings' link on the manage filters in context page.
  */
 function filter_has_local_settings($filter) {
     global $CFG;
-    $settingspath = $CFG->dirroot . '/' . $filter . '/filterlocalsettings.php';
+    $settingspath = $CFG->dirroot . '/filter/' . $filter . '/filterlocalsettings.php';
     return is_readable($settingspath);
 }
 
@@ -1162,7 +1116,7 @@ function filter_context_may_have_filter_settings($context) {
 }
 
 /**
- * Process phrases intelligently found within a HTML text (such as adding links)
+ * Process phrases intelligently found within a HTML text (such as adding links).
  *
  * @staticvar array $usedpharses
  * @param string $text             the text that we are filtering
@@ -1179,8 +1133,8 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
 
     static $usedphrases;
 
-    $ignoretags = array();  //To store all the enclosig tags to be completely ignored
-    $tags = array();        //To store all the simple tags to be ignored
+    $ignoretags = array();  // To store all the enclosig tags to be completely ignored.
+    $tags = array();        // To store all the simple tags to be ignored.
 
     if (!$overridedefaultignore) {
         // A list of open/close tags that we should not replace within
@@ -1192,12 +1146,12 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
         $filterignoretagsclose = array('</head>', '</nolink>', '</span>',
                  '</script>', '</textarea>', '</select>','</a>');
     } else {
-        // Set an empty default list
+        // Set an empty default list.
         $filterignoretagsopen = array();
         $filterignoretagsclose = array();
     }
 
-    // Add the user defined ignore tags to the default list
+    // Add the user defined ignore tags to the default list.
     if ( is_array($ignoretagsopen) ) {
         foreach ($ignoretagsopen as $open) {
             $filterignoretagsopen[] = $open;
@@ -1207,41 +1161,41 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
         }
     }
 
-/// Invalid prefixes and suffixes for the fullmatch searches
-/// Every "word" character, but the underscore, is a invalid suffix or prefix.
-/// (nice to use this because it includes national characters (accents...) as word characters.
+    // Invalid prefixes and suffixes for the fullmatch searches
+    // Every "word" character, but the underscore, is a invalid suffix or prefix.
+    // (nice to use this because it includes national characters (accents...) as word characters.
     $filterinvalidprefixes = '([^\W_])';
     $filterinvalidsuffixes = '([^\W_])';
 
-    //// Double up some magic chars to avoid "accidental matches"
+    // Double up some magic chars to avoid "accidental matches"
     $text = preg_replace('/([#*%])/','\1\1',$text);
 
 
-////Remove everything enclosed by the ignore tags from $text
+    //Remove everything enclosed by the ignore tags from $text
     filter_save_ignore_tags($text,$filterignoretagsopen,$filterignoretagsclose,$ignoretags);
 
-/// Remove tags from $text
+    // Remove tags from $text
     filter_save_tags($text,$tags);
 
-/// Time to cycle through each phrase to be linked
+    // Time to cycle through each phrase to be linked
     $size = sizeof($link_array);
     for ($n=0; $n < $size; $n++) {
         $linkobject =& $link_array[$n];
 
-    /// Set some defaults if certain properties are missing
-    /// Properties may be missing if the filterobject class has not been used to construct the object
+        // Set some defaults if certain properties are missing
+        // Properties may be missing if the filterobject class has not been used to construct the object
         if (empty($linkobject->phrase)) {
             continue;
         }
 
-    /// Avoid integers < 1000 to be linked. See bug 1446.
+        // Avoid integers < 1000 to be linked. See bug 1446.
         $intcurrent = intval($linkobject->phrase);
         if (!empty($intcurrent) && strval($intcurrent) == $linkobject->phrase && $intcurrent < 1000) {
             continue;
         }
 
-    /// All this work has to be done ONLY it it hasn't been done before
-    if (!$linkobject->work_calculated) {
+        // All this work has to be done ONLY it it hasn't been done before
+         if (!$linkobject->work_calculated) {
             if (!isset($linkobject->hreftagbegin) or !isset($linkobject->hreftagend)) {
                 $linkobject->work_hreftagbegin = '<span class="highlight"';
                 $linkobject->work_hreftagend   = '</span>';
@@ -1250,8 +1204,8 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
                 $linkobject->work_hreftagend   = $linkobject->hreftagend;
             }
 
-        /// Double up chars to protect true duplicates
-        /// be cleared up before returning to the user.
+            // Double up chars to protect true duplicates
+            // be cleared up before returning to the user.
             $linkobject->work_hreftagbegin = preg_replace('/([#*%])/','\1\1',$linkobject->work_hreftagbegin);
 
             if (empty($linkobject->casesensitive)) {
@@ -1265,41 +1219,41 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
                 $linkobject->work_fullmatch = true;
             }
 
-        /// Strip tags out of the phrase
+            // Strip tags out of the phrase
             $linkobject->work_phrase = strip_tags($linkobject->phrase);
 
-        /// Double up chars that might cause a false match -- the duplicates will
-        /// be cleared up before returning to the user.
+            // Double up chars that might cause a false match -- the duplicates will
+            // be cleared up before returning to the user.
             $linkobject->work_phrase = preg_replace('/([#*%])/','\1\1',$linkobject->work_phrase);
 
-        /// Set the replacement phrase properly
+            // Set the replacement phrase properly
             if ($linkobject->replacementphrase) {    //We have specified a replacement phrase
-            /// Strip tags
+                // Strip tags
                 $linkobject->work_replacementphrase = strip_tags($linkobject->replacementphrase);
             } else {                                 //The replacement is the original phrase as matched below
                 $linkobject->work_replacementphrase = '$1';
             }
 
-        /// Quote any regular expression characters and the delimiter in the work phrase to be searched
+            // Quote any regular expression characters and the delimiter in the work phrase to be searched
             $linkobject->work_phrase = preg_quote($linkobject->work_phrase, '/');
 
-        /// Work calculated
+            // Work calculated
             $linkobject->work_calculated = true;
 
         }
 
-    /// If $CFG->filtermatchoneperpage, avoid previously (request) linked phrases
+        // If $CFG->filtermatchoneperpage, avoid previously (request) linked phrases
         if (!empty($CFG->filtermatchoneperpage)) {
             if (!empty($usedphrases) && in_array($linkobject->work_phrase,$usedphrases)) {
                 continue;
             }
         }
 
-    /// Regular expression modifiers
+        // Regular expression modifiers
         $modifiers = ($linkobject->work_casesensitive) ? 's' : 'isu'; // works in unicode mode!
 
-    /// Do we need to do a fullmatch?
-    /// If yes then go through and remove any non full matching entries
+        // Do we need to do a fullmatch?
+        // If yes then go through and remove any non full matching entries
         if ($linkobject->work_fullmatch) {
             $notfullmatches = array();
             $regexp = '/'.$filterinvalidprefixes.'('.$linkobject->work_phrase.')|('.$linkobject->work_phrase.')'.$filterinvalidsuffixes.'/'.$modifiers;
@@ -1316,7 +1270,7 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
             }
         }
 
-    /// Finally we do our highlighting
+        // Finally we do our highlighting
         if (!empty($CFG->filtermatchonepertext) || !empty($CFG->filtermatchoneperpage)) {
             $resulttext = preg_replace('/('.$linkobject->work_phrase.')/'.$modifiers,
                                       $linkobject->work_hreftagbegin.
@@ -1330,43 +1284,43 @@ function filter_phrases($text, &$link_array, $ignoretagsopen=NULL, $ignoretagscl
         }
 
 
-    /// If the text has changed we have to look for links again
+        // If the text has changed we have to look for links again
         if ($resulttext != $text) {
-        /// Set $text to $resulttext
+            // Set $text to $resulttext
             $text = $resulttext;
-        /// Remove everything enclosed by the ignore tags from $text
+            // Remove everything enclosed by the ignore tags from $text
             filter_save_ignore_tags($text,$filterignoretagsopen,$filterignoretagsclose,$ignoretags);
-        /// Remove tags from $text
+            // Remove tags from $text
             filter_save_tags($text,$tags);
-        /// If $CFG->filtermatchoneperpage, save linked phrases to request
+            // If $CFG->filtermatchoneperpage, save linked phrases to request
             if (!empty($CFG->filtermatchoneperpage)) {
                 $usedphrases[] = $linkobject->work_phrase;
             }
         }
 
 
-    /// Replace the not full matches before cycling to next link object
+        // Replace the not full matches before cycling to next link object
         if (!empty($notfullmatches)) {
             $text = str_replace(array_keys($notfullmatches),$notfullmatches,$text);
             unset($notfullmatches);
         }
     }
 
-/// Rebuild the text with all the excluded areas
+    // Rebuild the text with all the excluded areas
 
     if (!empty($tags)) {
         $text = str_replace(array_keys($tags), $tags, $text);
     }
 
     if (!empty($ignoretags)) {
-        $ignoretags = array_reverse($ignoretags); /// Reversed so "progressive" str_replace() will solve some nesting problems.
+        $ignoretags = array_reverse($ignoretags);     // Reversed so "progressive" str_replace() will solve some nesting problems.
         $text = str_replace(array_keys($ignoretags),$ignoretags,$text);
     }
 
-    //// Remove the protective doubleups
+    // Remove the protective doubleups
     $text =  preg_replace('/([#*%])(\1)/','\1',$text);
 
-/// Add missing javascript for popus
+    // Add missing javascript for popus
     $text = filter_add_javascript($text);
 
 
@@ -1415,10 +1369,10 @@ function filter_remove_duplicates($linkarray) {
  **/
 function filter_save_ignore_tags(&$text, $filterignoretagsopen, $filterignoretagsclose, &$ignoretags) {
 
-/// Remove everything enclosed by the ignore tags from $text
+    // Remove everything enclosed by the ignore tags from $text
     foreach ($filterignoretagsopen as $ikey=>$opentag) {
         $closetag = $filterignoretagsclose[$ikey];
-    /// form regular expression
+        // form regular expression
         $opentag  = str_replace('/','\/',$opentag); // delimit forward slashes
         $closetag = str_replace('/','\/',$closetag); // delimit forward slashes
         $pregexp = '/'.$opentag.'(.*?)'.$closetag.'/is';
@@ -1464,10 +1418,10 @@ function filter_add_javascript($text) {
     global $CFG;
 
     if (stripos($text, '</html>') === FALSE) {
-        return $text; // this is not a html file
+        return $text; // This is not a html file.
     }
     if (strpos($text, 'onclick="return openpopup') === FALSE) {
-        return $text; // no popup - no need to add javascript
+        return $text; // No popup - no need to add javascript.
     }
     $js ="
     <script type=\"text/javascript\">
@@ -1485,11 +1439,11 @@ function filter_add_javascript($text) {
     // -->
     </script>";
     if (stripos($text, '</head>') !== FALSE) {
-        //try to add it into the head element
+        // Try to add it into the head element.
         $text = str_ireplace('</head>', $js.'</head>', $text);
         return $text;
     }
 
-    //last chance - try adding head element
+    // Last chance - try adding head element.
     return preg_replace("/<html.*?>/is", "\\0<head>".$js.'</head>', $text);
 }
index 450f266..8458475 100644 (file)
@@ -1663,19 +1663,21 @@ class global_navigation extends navigation_node {
                     $categoryids[] = $category->key;
                 }
             }
-            list($categoriessql, $params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED);
-            $params['limit'] = (!empty($CFG->navcourselimit))?$CFG->navcourselimit:20;
-            $sql = "SELECT cc.id, COUNT(c.id) AS coursecount
-                      FROM {course_categories} cc
-                      JOIN {course} c ON c.category = cc.id
-                     WHERE cc.id {$categoriessql}
-                  GROUP BY cc.id
-                    HAVING COUNT(c.id) > :limit";
-            $excessivecategories = $DB->get_records_sql($sql, $params);
-            foreach ($categories as &$category) {
-                if (array_key_exists($category->key, $excessivecategories) && !$this->can_add_more_courses_to_category($category)) {
-                    $url = new moodle_url('/course/category.php', array('id'=>$category->key));
-                    $category->add(get_string('viewallcourses'), $url, self::TYPE_SETTING);
+            if ($categoryids) {
+                list($categoriessql, $params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED);
+                $params['limit'] = (!empty($CFG->navcourselimit))?$CFG->navcourselimit:20;
+                $sql = "SELECT cc.id, COUNT(c.id) AS coursecount
+                          FROM {course_categories} cc
+                          JOIN {course} c ON c.category = cc.id
+                         WHERE cc.id {$categoriessql}
+                      GROUP BY cc.id
+                        HAVING COUNT(c.id) > :limit";
+                $excessivecategories = $DB->get_records_sql($sql, $params);
+                foreach ($categories as &$category) {
+                    if (array_key_exists($category->key, $excessivecategories) && !$this->can_add_more_courses_to_category($category)) {
+                        $url = new moodle_url('/course/category.php', array('id'=>$category->key));
+                        $category->add(get_string('viewallcourses'), $url, self::TYPE_SETTING);
+                    }
                 }
             }
         }
@@ -1922,7 +1924,7 @@ class global_navigation extends navigation_node {
                     $propogrationhandler = 'e.halt();';
                 }
                 // Decode the onclick - it has already been encoded for display (puke)
-                $onclick = htmlspecialchars_decode($activity->onclick);
+                $onclick = htmlspecialchars_decode($activity->onclick, ENT_QUOTES);
                 // Build the JS function the click event will call
                 $jscode = "function {$functionname}(e) { $propogrationhandler $onclick }";
                 $this->page->requires->js_init_code($jscode);
index dcd0875..53e9907 100644 (file)
@@ -846,8 +846,11 @@ class theme_config {
     /**
      * Generate a URL to the file that serves theme JavaScript files.
      *
+     * If we determine that the theme has no relevant files, then we return
+     * early with a null value.
+     *
      * @param bool $inhead true means head url, false means footer
-     * @return moodle_url
+     * @return moodle_url|null
      */
     public function javascript_url($inhead) {
         global $CFG;
@@ -856,6 +859,11 @@ class theme_config {
         $params = array('theme'=>$this->name,'rev'=>$rev);
         $params['type'] = $inhead ? 'head' : 'footer';
 
+        // Return early if there are no files to serve
+        if (count($this->javascript_files($params['type'])) === 0) {
+            return null;
+        }
+
         if (!empty($CFG->slasharguments) and $rev > 0) {
             $url = new moodle_url("$CFG->httpswwwroot/theme/javascript.php");
             $url->set_slashargument('/'.$this->name.'/'.$rev.'/'.$params['type'], 'noparam', true);
index 0e8052d..4e097b9 100644 (file)
@@ -393,10 +393,12 @@ class core_renderer extends renderer_base {
         }
 
         // Get the theme javascript head and footer
-        $jsurl = $this->page->theme->javascript_url(true);
-        $this->page->requires->js($jsurl, true);
-        $jsurl = $this->page->theme->javascript_url(false);
-        $this->page->requires->js($jsurl);
+        if ($jsurl = $this->page->theme->javascript_url(true)) {
+            $this->page->requires->js($jsurl, true);
+        }
+        if ($jsurl = $this->page->theme->javascript_url(false)) {
+            $this->page->requires->js($jsurl);
+        }
 
         // Get any HTML from the page_requirements_manager.
         $output .= $this->page->requires->get_head_code($this->page, $this);
index c57b5d0..d4eff1c 100644 (file)
@@ -407,7 +407,7 @@ class page_requirements_manager {
                     $module = array('name'     => 'core_dock',
                                     'fullpath' => '/blocks/dock.js',
                                     'requires' => array('base', 'node', 'event-custom', 'event-mouseenter', 'event-resize'),
-                                    'strings' => array(array('addtodock', 'block'),array('undockitem', 'block'),array('undockall', 'block'),array('thisdirectionvertical', 'langconfig')));
+                                    'strings' => array(array('addtodock', 'block'),array('undockitem', 'block'),array('undockall', 'block'),array('thisdirectionvertical', 'langconfig'),array('hidedockpanel', 'block'),array('hidepanel', 'block')));
                     break;
                 case 'core_message':
                     $module = array('name'     => 'core_message',
index b740093..3be4ca9 100644 (file)
@@ -2654,12 +2654,12 @@ class plugininfo_filter extends plugininfo_base {
         // get the list of filters from both /filter and /mod location
         $installed = filter_get_all_installed();
 
-        foreach ($installed as $filterlegacyname => $displayname) {
+        foreach ($installed as $name => $displayname) {
             $plugin                 = new $typeclass();
             $plugin->type           = $type;
             $plugin->typerootdir    = $typerootdir;
-            $plugin->name           = self::normalize_legacy_name($filterlegacyname);
-            $plugin->rootdir        = $CFG->dirroot . '/' . $filterlegacyname;
+            $plugin->name           = $name;
+            $plugin->rootdir        = "$CFG->dirroot/filter/$name";
             $plugin->displayname    = $displayname;
 
             $plugin->load_disk_version();
@@ -2676,9 +2676,9 @@ class plugininfo_filter extends plugininfo_base {
             // if we're upgrading from 1.9, the table does not exist yet
             // if it does, make sure that all installed filters are registered
             $needsreload  = false;
-            foreach (array_keys($installed) as $filterlegacyname) {
-                if (!isset($globalstates[self::normalize_legacy_name($filterlegacyname)])) {
-                    filter_set_global_state($filterlegacyname, TEXTFILTER_DISABLED);
+            foreach (array_keys($installed) as $name) {
+                if (!isset($globalstates[$name]) && !isset($globalstates['filter/'.$name])) {
+                    filter_set_global_state($name, TEXTFILTER_DISABLED);
                     $needsreload = true;
                 }
             }
@@ -2695,8 +2695,8 @@ class plugininfo_filter extends plugininfo_base {
                 $plugin->type           = $type;
                 $plugin->typerootdir    = $typerootdir;
                 $plugin->name           = $name;
-                $plugin->rootdir        = $CFG->dirroot . '/' . $info->legacyname;
-                $plugin->displayname    = $info->legacyname;
+                $plugin->rootdir        = "$CFG->dirroot/filter/$name";
+                $plugin->displayname    = $name;
 
                 $plugin->load_db_version();
 
@@ -2721,11 +2721,6 @@ class plugininfo_filter extends plugininfo_base {
      * @see load_version_php()
      */
     protected function load_version_php() {
-        if (strpos($this->name, 'mod_') === 0) {
-            // filters bundled with modules do not have a version.php and so
-            // do not provide their own versioning information.
-            return new stdClass();
-        }
         return parent::load_version_php();
     }
 
@@ -2733,8 +2728,7 @@ class plugininfo_filter extends plugininfo_base {
 
         $globalstates = self::get_global_states();
 
-        foreach ($globalstates as $filterlegacyname => $info) {
-            $name = self::normalize_legacy_name($filterlegacyname);
+        foreach ($globalstates as $name => $info) {
             if ($name === $this->name) {
                 if ($info->active == TEXTFILTER_DISABLED) {
                     return false;
@@ -2753,8 +2747,7 @@ class plugininfo_filter extends plugininfo_base {
         if (!isset($globalstates[$this->name])) {
             return parent::get_settings_section_name();
         }
-        $legacyname = $globalstates[$this->name]->legacyname;
-        return 'filtersetting' . str_replace('/', '', $legacyname);
+        return 'filtersetting' . $this->name;
     }
 
     public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) {
@@ -2776,33 +2769,7 @@ class plugininfo_filter extends plugininfo_base {
     }
 
     public function get_uninstall_url() {
-
-        if (strpos($this->name, 'mod_') === 0) {
-            return null;
-        } else {
-            $globalstates = self::get_global_states();
-            $legacyname = $globalstates[$this->name]->legacyname;
-            return new moodle_url('/admin/filters.php', array('sesskey' => sesskey(), 'filterpath' => $legacyname, 'action' => 'delete'));
-        }
-    }
-
-    /**
-     * Convert legacy filter names like 'filter/foo' or 'mod/bar' into frankenstyle
-     *
-     * @param string $legacyfiltername legacy filter name
-     * @return string frankenstyle-like name
-     */
-    protected static function normalize_legacy_name($legacyfiltername) {
-
-        $name = str_replace('/', '_', $legacyfiltername);
-        if (strpos($name, 'filter_') === 0) {
-            $name = substr($name, 7);
-            if (empty($name)) {
-                throw new coding_exception('Unable to determine filter name: ' . $legacyfiltername);
-            }
-        }
-
-        return $name;
+        return new moodle_url('/admin/filters.php', array('sesskey' => sesskey(), 'filterpath' => $this->name, 'action' => 'delete'));
     }
 
     /**
@@ -2826,10 +2793,8 @@ class plugininfo_filter extends plugininfo_base {
                 $globalstatescache = array();
 
             } else {
-                foreach (filter_get_global_states() as $legacyname => $info) {
-                    $name                       = self::normalize_legacy_name($legacyname);
+                foreach (filter_get_global_states() as $name => $info) {
                     $filterinfo                 = new stdClass();
-                    $filterinfo->legacyname     = $legacyname;
                     $filterinfo->active         = $info->active;
                     $filterinfo->sortorder      = $info->sortorder;
                     $globalstatescache[$name]   = $filterinfo;
index dda8714..6046e66 100644 (file)
@@ -207,10 +207,21 @@ function rss_get_file_full_name($componentname, $filename) {
  *
  * @param stdClass $instance the instance of the source of the RSS feed
  * @param string $sql the SQL used to produce the RSS feed
+ * @param array $params the parameters used in the SQL query
  * @return string the name of the RSS file
  */
-function rss_get_file_name($instance, $sql) {
-    return $instance->id.'_'.md5($sql);
+function rss_get_file_name($instance, $sql, $params = array()) {
+    if ($params) {
+        // If a parameters array is passed, then we want to
+        // serialize it and then concatenate it with the sql.
+        // The reason for this is to generate a unique filename
+        // for queries using the same sql but different parameters.
+        asort($parms);
+        $serializearray = serialize($params);
+        return $instance->id.'_'.md5($sql . $serializearray);
+    } else {
+        return $instance->id.'_'.md5($sql);
+    }
 }
 
 /**
index b220781..2d35b9d 100644 (file)
@@ -44,7 +44,7 @@ class filter_active_global_testcase extends advanced_testcase {
     private function assert_only_one_filter_globally($filter, $state) {
         global $DB;
         $recs = $DB->get_records('filter_active');
-        $this->assertEquals(1, count($recs), 'More than one record returned %s.');
+        $this->assertCount(1, $recs);
         $rec = reset($recs);
         unset($rec->id);
         $expectedrec = new stdClass();
@@ -71,25 +71,25 @@ class filter_active_global_testcase extends advanced_testcase {
     public function test_set_filter_globally_on() {
         // Setup fixture.
         // Exercise SUT.
-        filter_set_global_state('filter/name', TEXTFILTER_ON, 1);
+        filter_set_global_state('name', TEXTFILTER_ON);
         // Validate.
-        $this->assert_only_one_filter_globally('filter/name', TEXTFILTER_ON);
+        $this->assert_only_one_filter_globally('name', TEXTFILTER_ON);
     }
 
     public function test_set_filter_globally_off() {
         // Setup fixture.
         // Exercise SUT.
-        filter_set_global_state('filter/name', TEXTFILTER_OFF, 1);
+        filter_set_global_state('name', TEXTFILTER_OFF);
         // Validate.
-        $this->assert_only_one_filter_globally('filter/name', TEXTFILTER_OFF);
+        $this->assert_only_one_filter_globally('name', TEXTFILTER_OFF);
     }
 
     public function test_set_filter_globally_disabled() {
         // Setup fixture.
         // Exercise SUT.
-        filter_set_global_state('filter/name', TEXTFILTER_DISABLED, 1);
+        filter_set_global_state('name', TEXTFILTER_DISABLED);
         // Validate.
-        $this->assert_only_one_filter_globally('filter/name', TEXTFILTER_DISABLED);
+        $this->assert_only_one_filter_globally('name', TEXTFILTER_DISABLED);
     }
 
     /**
@@ -97,135 +97,93 @@ class filter_active_global_testcase extends advanced_testcase {
      * @return void
      */
     public function test_global_config_exception_on_invalid_state() {
-        filter_set_global_state('filter/name', 0, 1);
+        filter_set_global_state('name', 0);
     }
 
-    public function test_set_no_sortorder_clash() {
+    public function test_auto_sort_order() {
         // Setup fixture.
         // Exercise SUT.
-        filter_set_global_state('filter/one', TEXTFILTER_DISABLED, 1);
-        filter_set_global_state('filter/two', TEXTFILTER_DISABLED, 1);
-        // Validate - should have pushed other filters down.
-        $this->assert_global_sort_order(array('filter/two', 'filter/one'));
-    }
-
-    public function test_auto_sort_order_disabled() {
-        // Setup fixture.
-        // Exercise SUT.
-        filter_set_global_state('filter/one', TEXTFILTER_DISABLED);
-        filter_set_global_state('filter/two', TEXTFILTER_DISABLED);
+        filter_set_global_state('one', TEXTFILTER_DISABLED);
+        filter_set_global_state('two', TEXTFILTER_DISABLED);
         // Validate.
-        $this->assert_global_sort_order(array('filter/one', 'filter/two'));
+        $this->assert_global_sort_order(array('one', 'two'));
     }
 
     public function test_auto_sort_order_enabled() {
         // Setup fixture.
         // Exercise SUT.
-        filter_set_global_state('filter/one', TEXTFILTER_ON);
-        filter_set_global_state('filter/two', TEXTFILTER_OFF);
+        filter_set_global_state('one', TEXTFILTER_ON);
+        filter_set_global_state('two', TEXTFILTER_OFF);
         // Validate.
-        $this->assert_global_sort_order(array('filter/one', 'filter/two'));
-    }
-
-    public function test_auto_sort_order_mixed() {
-        // Setup fixture.
-        // Exercise SUT.
-        filter_set_global_state('filter/0', TEXTFILTER_DISABLED);
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        filter_set_global_state('filter/2', TEXTFILTER_DISABLED);
-        filter_set_global_state('filter/3', TEXTFILTER_OFF);
-        // Validate.
-        $this->assert_global_sort_order(array('filter/1', 'filter/3', 'filter/0', 'filter/2'));
+        $this->assert_global_sort_order(array('one', 'two'));
     }
 
     public function test_update_existing_dont_duplicate() {
         // Setup fixture.
         // Exercise SUT.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_global_state('filter/name', TEXTFILTER_OFF);
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_global_state('name', TEXTFILTER_OFF);
         // Validate.
-        $this->assert_only_one_filter_globally('filter/name', TEXTFILTER_OFF);
-    }
-
-    /**
-     * @expectedException coding_exception
-     * @return void
-     */
-    public function test_sort_order_not_too_low() {
-        // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        // Exercise SUT.
-        filter_set_global_state('filter/2', TEXTFILTER_ON, 0);
-    }
-
-    /**
-     * @expectedException coding_exception
-     * @return void
-     */
-    public function test_sort_order_not_too_high() {
-        // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        // Exercise SUT.
-        filter_set_global_state('filter/2', TEXTFILTER_ON, 3);
+        $this->assert_only_one_filter_globally('name', TEXTFILTER_OFF);
     }
 
     public function test_update_reorder_down() {
         // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        filter_set_global_state('filter/2', TEXTFILTER_ON);
-        filter_set_global_state('filter/3', TEXTFILTER_ON);
+        filter_set_global_state('one', TEXTFILTER_ON);
+        filter_set_global_state('two', TEXTFILTER_ON);
+        filter_set_global_state('three', TEXTFILTER_ON);
         // Exercise SUT.
-        filter_set_global_state('filter/2', TEXTFILTER_ON, 1);
+        filter_set_global_state('two', TEXTFILTER_ON, -1);
         // Validate.
-        $this->assert_global_sort_order(array('filter/2', 'filter/1', 'filter/3'));
+        $this->assert_global_sort_order(array('two', 'one', 'three'));
     }
 
     public function test_update_reorder_up() {
         // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        filter_set_global_state('filter/2', TEXTFILTER_ON);
-        filter_set_global_state('filter/3', TEXTFILTER_ON);
-        filter_set_global_state('filter/4', TEXTFILTER_ON);
+        filter_set_global_state('one', TEXTFILTER_ON);
+        filter_set_global_state('two', TEXTFILTER_ON);
+        filter_set_global_state('three', TEXTFILTER_ON);
+        filter_set_global_state('four', TEXTFILTER_ON);
         // Exercise SUT.
-        filter_set_global_state('filter/2', TEXTFILTER_ON, 3);
+        filter_set_global_state('two', TEXTFILTER_ON, 1);
         // Validate.
-        $this->assert_global_sort_order(array('filter/1', 'filter/3', 'filter/2', 'filter/4'));
+        $this->assert_global_sort_order(array('one', 'three', 'two', 'four'));
     }
 
     public function test_auto_sort_order_change_to_enabled() {
         // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        filter_set_global_state('filter/2', TEXTFILTER_DISABLED);
-        filter_set_global_state('filter/3', TEXTFILTER_DISABLED);
+        filter_set_global_state('one', TEXTFILTER_ON);
+        filter_set_global_state('two', TEXTFILTER_DISABLED);
+        filter_set_global_state('three', TEXTFILTER_DISABLED);
         // Exercise SUT.
-        filter_set_global_state('filter/3', TEXTFILTER_ON);
+        filter_set_global_state('three', TEXTFILTER_ON);
         // Validate.
-        $this->assert_global_sort_order(array('filter/1', 'filter/3', 'filter/2'));
+        $this->assert_global_sort_order(array('one', 'three', 'two'));
     }
 
     public function test_auto_sort_order_change_to_disabled() {
         // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        filter_set_global_state('filter/2', TEXTFILTER_ON);
-        filter_set_global_state('filter/3', TEXTFILTER_DISABLED);
+        filter_set_global_state('one', TEXTFILTER_ON);
+        filter_set_global_state('two', TEXTFILTER_ON);
+        filter_set_global_state('three', TEXTFILTER_DISABLED);
         // Exercise SUT.
-        filter_set_global_state('filter/1', TEXTFILTER_DISABLED);
+        filter_set_global_state('one', TEXTFILTER_DISABLED);
         // Validate.
-        $this->assert_global_sort_order(array('filter/2', 'filter/1', 'filter/3'));
+        $this->assert_global_sort_order(array('two', 'one', 'three'));
     }
 
     public function test_filter_get_global_states() {
         // Setup fixture.
-        filter_set_global_state('filter/1', TEXTFILTER_ON);
-        filter_set_global_state('filter/2', TEXTFILTER_OFF);
-        filter_set_global_state('filter/3', TEXTFILTER_DISABLED);
+        filter_set_global_state('one', TEXTFILTER_ON);
+        filter_set_global_state('two', TEXTFILTER_OFF);
+        filter_set_global_state('three', TEXTFILTER_DISABLED);
         // Exercise SUT.
         $filters = filter_get_global_states();
         // Validate.
         $this->assertEquals(array(
-            'filter/1' => (object) array('filter' => 'filter/1', 'active' => TEXTFILTER_ON, 'sortorder' => 1),
-            'filter/2' => (object) array('filter' => 'filter/2', 'active' => TEXTFILTER_OFF, 'sortorder' => 2),
-            'filter/3' => (object) array('filter' => 'filter/3', 'active' => TEXTFILTER_DISABLED, 'sortorder' => 3)
+            'one' => (object) array('filter' => 'one', 'active' => TEXTFILTER_ON, 'sortorder' => 1),
+            'two' => (object) array('filter' => 'two', 'active' => TEXTFILTER_OFF, 'sortorder' => 2),
+            'three' => (object) array('filter' => 'three', 'active' => TEXTFILTER_DISABLED, 'sortorder' => 3)
         ), $filters);
     }
 }
@@ -264,21 +222,21 @@ class filter_active_local_testcase extends advanced_testcase {
 
     public function test_local_on() {
         // Exercise SUT.
-        filter_set_local_state('filter/name', 123, TEXTFILTER_ON);
+        filter_set_local_state('name', 123, TEXTFILTER_ON);
         // Validate.
-        $this->assert_only_one_local_setting('filter/name', 123, TEXTFILTER_ON);
+        $this->assert_only_one_local_setting('name', 123, TEXTFILTER_ON);
     }
 
     public function test_local_off() {
         // Exercise SUT.
-        filter_set_local_state('filter/name', 123, TEXTFILTER_OFF);
+        filter_set_local_state('name', 123, TEXTFILTER_OFF);
         // Validate.
-        $this->assert_only_one_local_setting('filter/name', 123, TEXTFILTER_OFF);
+        $this->assert_only_one_local_setting('name', 123, TEXTFILTER_OFF);
     }
 
     public function test_local_inherit() {
         // Exercise SUT.
-        filter_set_local_state('filter/name', 123, TEXTFILTER_INHERIT);
+        filter_set_local_state('name', 123, TEXTFILTER_INHERIT);
         // Validate.
         $this->assert_no_local_setting();
     }
@@ -289,7 +247,7 @@ class filter_active_local_testcase extends advanced_testcase {
      */
     public function test_local_invalid_state_throws_exception() {
         // Exercise SUT.
-        filter_set_local_state('filter/name', 123, -9999);
+        filter_set_local_state('name', 123, -9999);
     }
 
     /**
@@ -298,14 +256,14 @@ class filter_active_local_testcase extends advanced_testcase {
      */
     public function test_throws_exception_when_setting_global() {
         // Exercise SUT.
-        filter_set_local_state('filter/name', context_system::instance()->id, TEXTFILTER_INHERIT);
+        filter_set_local_state('name', context_system::instance()->id, TEXTFILTER_INHERIT);
     }
 
     public function test_local_inherit_deletes_existing() {
         // Setup fixture.
-        filter_set_local_state('filter/name', 123, TEXTFILTER_INHERIT);
+        filter_set_local_state('name', 123, TEXTFILTER_INHERIT);
         // Exercise SUT.
-        filter_set_local_state('filter/name', 123, TEXTFILTER_INHERIT);
+        filter_set_local_state('name', 123, TEXTFILTER_INHERIT);
         // Validate.
         $this->assert_no_local_setting();
     }
@@ -340,28 +298,28 @@ class filter_config_testcase extends advanced_testcase {
 
     public function test_set_new_config() {
         // Exercise SUT.
-        filter_set_local_config('filter/name', 123, 'settingname', 'An arbitrary value');
+        filter_set_local_config('name', 123, 'settingname', 'An arbitrary value');
         // Validate.
-        $this->assert_only_one_config('filter/name', 123, 'settingname', 'An arbitrary value');
+        $this->assert_only_one_config('name', 123, 'settingname', 'An arbitrary value');
     }
 
     public function test_update_existing_config() {
         // Setup fixture.
-        filter_set_local_config('filter/name', 123, 'settingname', 'An arbitrary value');
+        filter_set_local_config('name', 123, 'settingname', 'An arbitrary value');
         // Exercise SUT.
-        filter_set_local_config('filter/name', 123, 'settingname', 'A changed value');
+        filter_set_local_config('name', 123, 'settingname', 'A changed value');
         // Validate.
-        $this->assert_only_one_config('filter/name', 123, 'settingname', 'A changed value');
+        $this->assert_only_one_config('name', 123, 'settingname', 'A changed value');
     }
 
     public function test_filter_get_local_config() {
         // Setup fixture.
-        filter_set_local_config('filter/name', 123, 'setting1', 'An arbitrary value');
-        filter_set_local_config('filter/name', 123, 'setting2', 'Another arbitrary value');
-        filter_set_local_config('filter/name', 122, 'settingname', 'Value from another context');
-        filter_set_local_config('filter/other', 123, 'settingname', 'Someone else\'s value');
+        filter_set_local_config('name', 123, 'setting1', 'An arbitrary value');
+        filter_set_local_config('name', 123, 'setting2', 'Another arbitrary value');
+        filter_set_local_config('name', 122, 'settingname', 'Value from another context');
+        filter_set_local_config('other', 123, 'settingname', 'Someone else\'s value');
         // Exercise SUT.
-        $config = filter_get_local_config('filter/name', 123);
+        $config = filter_get_local_config('name', 123);
         // Validate.
         $this->assertEquals(array('setting1' => 'An arbitrary value', 'setting2' => 'Another arbitrary value'), $config);
     }
@@ -398,18 +356,18 @@ class filter_get_active_available_in_context_testcase extends advanced_testcase
 
     public function test_globally_on_is_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
+        filter_set_global_state('name', TEXTFILTER_ON);
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$syscontext);
         // Validate.
-        $this->assert_filter_list(array('filter/name'), $filters);
+        $this->assert_filter_list(array('name'), $filters);
         // Check no config returned correctly.
-        $this->assertEquals(array(), $filters['filter/name']);
+        $this->assertEquals(array(), $filters['name']);
     }
 
     public function test_globally_off_not_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_OFF);
+        filter_set_global_state('name', TEXTFILTER_OFF);
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext2);
         // Validate.
@@ -418,18 +376,18 @@ class filter_get_active_available_in_context_testcase extends advanced_testcase
 
     public function test_globally_off_overridden() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_OFF);
-        filter_set_local_state('filter/name', self::$childcontext->id, TEXTFILTER_ON);
+        filter_set_global_state('name', TEXTFILTER_OFF);
+        filter_set_local_state('name', self::$childcontext->id, TEXTFILTER_ON);
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext2);
         // Validate.
-        $this->assert_filter_list(array('filter/name'), $filters);
+        $this->assert_filter_list(array('name'), $filters);
     }
 
     public function test_globally_on_overridden() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_state('filter/name', self::$childcontext->id, TEXTFILTER_OFF);
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_state('name', self::$childcontext->id, TEXTFILTER_OFF);
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext2);
         // Validate.
@@ -438,8 +396,8 @@ class filter_get_active_available_in_context_testcase extends advanced_testcase
 
     public function test_globally_disabled_not_overridden() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_DISABLED);
-        filter_set_local_state('filter/name', self::$childcontext->id, TEXTFILTER_ON);
+        filter_set_global_state('name', TEXTFILTER_DISABLED);
+        filter_set_local_state('name', self::$childcontext->id, TEXTFILTER_ON);
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$syscontext);
         // Validate.
@@ -448,45 +406,45 @@ class filter_get_active_available_in_context_testcase extends advanced_testcase
 
     public function test_single_config_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_config('filter/name', self::$childcontext->id, 'settingname', 'A value');
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_config('name', self::$childcontext->id, 'settingname', 'A value');
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext);
         // Validate.
-        $this->assertEquals(array('settingname' => 'A value'), $filters['filter/name']);
+        $this->assertEquals(array('settingname' => 'A value'), $filters['name']);
     }
 
     public function test_multi_config_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_config('filter/name', self::$childcontext->id, 'settingname', 'A value');
-        filter_set_local_config('filter/name', self::$childcontext->id, 'anothersettingname', 'Another value');
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_config('name', self::$childcontext->id, 'settingname', 'A value');
+        filter_set_local_config('name', self::$childcontext->id, 'anothersettingname', 'Another value');
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext);
         // Validate.
-        $this->assertEquals(array('settingname' => 'A value', 'anothersettingname' => 'Another value'), $filters['filter/name']);
+        $this->assertEquals(array('settingname' => 'A value', 'anothersettingname' => 'Another value'), $filters['name']);
     }
 
     public function test_config_from_other_context_not_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_config('filter/name', self::$childcontext->id, 'settingname', 'A value');
-        filter_set_local_config('filter/name', self::$childcontext2->id, 'anothersettingname', 'Another value');
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_config('name', self::$childcontext->id, 'settingname', 'A value');
+        filter_set_local_config('name', self::$childcontext2->id, 'anothersettingname', 'Another value');
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext2);
         // Validate.
-        $this->assertEquals(array('anothersettingname' => 'Another value'), $filters['filter/name']);
+        $this->assertEquals(array('anothersettingname' => 'Another value'), $filters['name']);
     }
 
     public function test_config_from_other_filter_not_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_config('filter/name', self::$childcontext->id, 'settingname', 'A value');
-        filter_set_local_config('filter/other', self::$childcontext->id, 'anothersettingname', 'Another value');
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_config('name', self::$childcontext->id, 'settingname', 'A value');
+        filter_set_local_config('other', self::$childcontext->id, 'anothersettingname', 'Another value');
         // Exercise SUT.
         $filters = filter_get_active_in_context(self::$childcontext);
         // Validate.
-        $this->assertEquals(array('settingname' => 'A value'), $filters['filter/name']);
+        $this->assertEquals(array('settingname' => 'A value'), $filters['name']);
     }
 
     protected function assert_one_available_filter($filter, $localstate, $inheritedstate, $filters) {
@@ -502,28 +460,28 @@ class filter_get_active_available_in_context_testcase extends advanced_testcase
 
     public function test_available_in_context_localoverride() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_state('filter/name', self::$childcontext->id, TEXTFILTER_OFF);
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_state('name', self::$childcontext->id, TEXTFILTER_OFF);
         // Exercise SUT.
         $filters = filter_get_available_in_context(self::$childcontext);
         // Validate.
-        $this->assert_one_available_filter('filter/name', TEXTFILTER_OFF, TEXTFILTER_ON, $filters);
+        $this->assert_one_available_filter('name', TEXTFILTER_OFF, TEXTFILTER_ON, $filters);
     }
 
     public function test_available_in_context_nolocaloverride() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_state('filter/name', self::$childcontext->id, TEXTFILTER_OFF);
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_state('name', self::$childcontext->id, TEXTFILTER_OFF);
         // Exercise SUT.
         $filters = filter_get_available_in_context(self::$childcontext2);
         // Validate.
-        $this->assert_one_available_filter('filter/name', TEXTFILTER_INHERIT, TEXTFILTER_OFF, $filters);
+        $this->assert_one_available_filter('name', TEXTFILTER_INHERIT, TEXTFILTER_OFF, $filters);
     }
 
     public function test_available_in_context_disabled_not_returned() {
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_DISABLED);
-        filter_set_local_state('filter/name', self::$childcontext->id, TEXTFILTER_ON);
+        filter_set_global_state('name', TEXTFILTER_DISABLED);
+        filter_set_local_state('name', self::$childcontext->id, TEXTFILTER_ON);
         // Exercise SUT.
         $filters = filter_get_available_in_context(self::$childcontext);
         // Validate.
@@ -610,43 +568,43 @@ class filter_preload_activities_testcase extends advanced_testcase {
         $this->assert_matches($modinfo);
 
         // Enable filter globally, check
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
+        filter_set_global_state('name', TEXTFILTER_ON);
         $this->assert_matches($modinfo);
 
         // Disable for activity 2
-        filter_set_local_state('filter/name', self::$activity2context->id, TEXTFILTER_OFF);
+        filter_set_local_state('name', self::$activity2context->id, TEXTFILTER_OFF);
         $this->assert_matches($modinfo);
 
         // Disable at category
-        filter_set_local_state('filter/name', self::$catcontext->id, TEXTFILTER_OFF);
+        filter_set_local_state('name', self::$catcontext->id, TEXTFILTER_OFF);
         $this->assert_matches($modinfo);
 
         // Enable for activity 1
-        filter_set_local_state('filter/name', self::$activity1context->id, TEXTFILTER_ON);
+        filter_set_local_state('name', self::$activity1context->id, TEXTFILTER_ON);
         $this->assert_matches($modinfo);
 
         // Disable globally
-        filter_set_global_state('filter/name', TEXTFILTER_DISABLED);
+        filter_set_global_state('name', TEXTFILTER_DISABLED);
         $this->assert_matches($modinfo);
 
         // Add another 2 filters
-        filter_set_global_state('filter/frog', TEXTFILTER_ON);
-        filter_set_global_state('filter/zombie', TEXTFILTER_ON);
+        filter_set_global_state('frog', TEXTFILTER_ON);
+        filter_set_global_state('zombie', TEXTFILTER_ON);
         $this->assert_matches($modinfo);
 
         // Disable random one of these in each context
-        filter_set_local_state('filter/zombie', self::$activity1context->id, TEXTFILTER_OFF);
-        filter_set_local_state('filter/frog', self::$activity2context->id, TEXTFILTER_OFF);
+        filter_set_local_state('zombie', self::$activity1context->id, TEXTFILTER_OFF);
+        filter_set_local_state('frog', self::$activity2context->id, TEXTFILTER_OFF);
         $this->assert_matches($modinfo);
 
         // Now do some filter options
-        filter_set_local_config('filter/name', self::$activity1context->id, 'a', 'x');
-        filter_set_local_config('filter/zombie', self::$activity1context->id, 'a', 'y');
-        filter_set_local_config('filter/frog', self::$activity1context->id, 'a', 'z');
+        filter_set_local_config('name', self::$activity1context->id, 'a', 'x');
+        filter_set_local_config('zombie', self::$activity1context->id, 'a', 'y');
+        filter_set_local_config('frog', self::$activity1context->id, 'a', 'z');
         // These last two don't do anything as they are not at final level but I
         // thought it would be good to have that verified in test
-        filter_set_local_config('filter/frog', self::$coursecontext->id, 'q', 'x');
-        filter_set_local_config('filter/frog', self::$catcontext->id, 'q', 'z');
+        filter_set_local_config('frog', self::$coursecontext->id, 'q', 'x');
+        filter_set_local_config('frog', self::$catcontext->id, 'q', 'z');
         $this->assert_matches($modinfo);
     }
 }
@@ -666,19 +624,19 @@ class filter_delete_config_testcase extends advanced_testcase {
         global $DB;
 
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_global_state('filter/other', TEXTFILTER_ON);
-        filter_set_local_config('filter/name', context_system::instance()->id, 'settingname', 'A value');
-        filter_set_local_config('filter/other', context_system::instance()->id, 'settingname', 'Other value');
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_global_state('other', TEXTFILTER_ON);
+        filter_set_local_config('name', context_system::instance()->id, 'settingname', 'A value');
+        filter_set_local_config('other', context_system::instance()->id, 'settingname', 'Other value');
         set_config('configname', 'A config value', 'filter_name');
         set_config('configname', 'Other config value', 'filter_other');
         // Exercise SUT.
-        filter_delete_all_for_filter('filter/name');
+        filter_delete_all_for_filter('name');
         // Validate.
         $this->assertEquals(1, $DB->count_records('filter_active'));
-        $this->assertTrue($DB->record_exists('filter_active', array('filter' => 'filter/other')));
+        $this->assertTrue($DB->record_exists('filter_active', array('filter' => 'other')));
         $this->assertEquals(1, $DB->count_records('filter_config'));
-        $this->assertTrue($DB->record_exists('filter_config', array('filter' => 'filter/other')));
+        $this->assertTrue($DB->record_exists('filter_config', array('filter' => 'other')));
         $expectedconfig = new stdClass;
         $expectedconfig->configname = 'Other config value';
         $this->assertEquals($expectedconfig, get_config('filter_other'));
@@ -689,18 +647,18 @@ class filter_delete_config_testcase extends advanced_testcase {
         global $DB;
 
         // Setup fixture.
-        filter_set_global_state('filter/name', TEXTFILTER_ON);
-        filter_set_local_state('filter/name', 123, TEXTFILTER_OFF);
-        filter_set_local_config('filter/name', 123, 'settingname', 'A value');
-        filter_set_local_config('filter/other', 123, 'settingname', 'Other value');
-        filter_set_local_config('filter/other', 122, 'settingname', 'Other value');
+        filter_set_global_state('name', TEXTFILTER_ON);
+        filter_set_local_state('name', 123, TEXTFILTER_OFF);
+        filter_set_local_config('name', 123, 'settingname', 'A value');
+        filter_set_local_config('other', 123, 'settingname', 'Other value');
+        filter_set_local_config('other', 122, 'settingname', 'Other value');
         // Exercise SUT.
         filter_delete_all_for_context(123);
         // Validate.
         $this->assertEquals(1, $DB->count_records('filter_active'));
         $this->assertTrue($DB->record_exists('filter_active', array('contextid' => context_system::instance()->id)));
         $this->assertEquals(1, $DB->count_records('filter_config'));
-        $this->assertTrue($DB->record_exists('filter_config', array('filter' => 'filter/other')));
+        $this->assertTrue($DB->record_exists('filter_config', array('filter' => 'other')));
     }
 }
 
@@ -735,9 +693,9 @@ class filter_filter_set_applies_to_strings extends advanced_testcase {
         $CFG->filterall = 0;
         $CFG->stringfilters = '';
         // Exercise SUT.
-        filter_set_applies_to_strings('filter/name', true);
+        filter_set_applies_to_strings('name', true);
         // Validate.
-        $this->assertEquals('filter/name', $CFG->stringfilters);
+        $this->assertEquals('name', $CFG->stringfilters);
         $this->assertEquals(1, $CFG->filterall);
     }
 
@@ -745,9 +703,9 @@ class filter_filter_set_applies_to_strings extends advanced_testcase {
         global $CFG;
         // Setup fixture.
         $CFG->filterall = 1;
-        $CFG->stringfilters = 'filter/name';
+        $CFG->stringfilters = 'name';
         // Exercise SUT.
-        filter_set_applies_to_strings('filter/name', false);
+        filter_set_applies_to_strings('name', false);
         // Validate.
         $this->assertEquals('', $CFG->stringfilters);
         $this->assertEquals('', $CFG->filterall);
@@ -757,11 +715,11 @@ class filter_filter_set_applies_to_strings extends advanced_testcase {
         global $CFG;
         // Setup fixture.
         $CFG->filterall = 1;
-        $CFG->stringfilters = 'filter/name,filter/other';
+        $CFG->stringfilters = 'name,other';
         // Exercise SUT.
-        filter_set_applies_to_strings('filter/name', false);
+        filter_set_applies_to_strings('name', false);
         // Validate.
-        $this->assertEquals('filter/other', $CFG->stringfilters);
+        $this->assertEquals('other', $CFG->stringfilters);
         $this->assertEquals(1, $CFG->filterall);
     }
 }
index e45f17f..35f500d 100644 (file)
@@ -293,8 +293,8 @@ class core_textlib_testcase extends advanced_testcase {
      * @return void
      */
     public function test_entities_to_utf8() {
-        $str = "&#x17d;lu&#x165;ou&#x10d;k&#xfd; kon&#237;&#269;ek";
-        $this->assertSame(textlib::entities_to_utf8($str), "Žluťoučký koníček");
+        $str = "&#x17d;lu&#x165;ou&#x10d;k&#xfd; kon&iacute;&#269;ek&copy;&quot;&amp;&lt;&gt;&sect;&laquo;";
+        $this->assertSame("Žluťoučký koníček©\"&<>§«", textlib::entities_to_utf8($str));
     }
 
     /**
@@ -302,10 +302,13 @@ class core_textlib_testcase extends advanced_testcase {
      * @return void
      */
     public function test_utf8_to_entities() {
-        $str = "Žluťoučký koníček";
-        $this->assertSame(textlib::utf8_to_entities($str), "&#x17d;lu&#x165;ou&#x10d;k&#xfd; kon&#xed;&#x10d;ek");
-        $this->assertSame(textlib::utf8_to_entities($str, true), "&#381;lu&#357;ou&#269;k&#253; kon&#237;&#269;ek");
+        $str = "&#x17d;luťoučký kon&iacute;ček&copy;&quot;&amp;&lt;&gt;&sect;&laquo;";
+        $this->assertSame("&#x17d;lu&#x165;ou&#x10d;k&#xfd; kon&iacute;&#x10d;ek&copy;&quot;&amp;&lt;&gt;&sect;&laquo;", textlib::utf8_to_entities($str));
+        $this->assertSame("&#381;lu&#357;ou&#269;k&#253; kon&iacute;&#269;ek&copy;&quot;&amp;&lt;&gt;&sect;&laquo;", textlib::utf8_to_entities($str, true));
 
+        $str = "&#381;luťoučký kon&iacute;ček&copy;&quot;&amp;&lt;&gt;&sect;&laquo;";
+        $this->assertSame("&#x17d;lu&#x165;ou&#x10d;k&#xfd; kon&#xed;&#x10d;ek&#xa9;\"&<>&#xa7;&#xab;", textlib::utf8_to_entities($str, false, true));
+        $this->assertSame("&#381;lu&#357;ou&#269;k&#253; kon&#237;&#269;ek&#169;\"&<>&#167;&#171;", textlib::utf8_to_entities($str, true, true));
     }
 
     /**
index ab0db3c..bddcaa7 100644 (file)
@@ -441,6 +441,34 @@ class textlib {
         return $encoded;
     }
 
+    /**
+     * Returns HTML entity transliteration table.
+     * @return array with (html entity => utf-8) elements
+     */
+    protected static function get_entities_table() {
+        static $trans_tbl = null;
+
+        // Generate/create $trans_tbl
+        if (!isset($trans_tbl)) {
+            if (version_compare(phpversion(), '5.3.4') < 0) {
+                $trans_tbl = array();
+                foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) {
+                    $trans_tbl[$key] = textlib::convert($val, 'ISO-8859-1', 'utf-8');
+                }
+
+            } else if (version_compare(phpversion(), '5.4.0') < 0) {
+                $trans_tbl = get_html_translation_table(HTML_ENTITIES, ENT_COMPAT, 'UTF-8');
+                $trans_tbl = array_flip($trans_tbl);
+
+            } else {
+                $trans_tbl = get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML401, 'UTF-8');
+                $trans_tbl = array_flip($trans_tbl);
+            }
+        }
+
+        return $trans_tbl;
+    }
+
     /**
      * Converts all the numeric entities &#nnnn; or &#xnnn; to UTF-8
      * Original from laurynas dot butkus at gmail at:
@@ -450,28 +478,24 @@ class textlib {
      * @param string $str input string
      * @param boolean $htmlent convert also html entities (defaults to true)
      * @return string encoded UTF-8 string
-     *
-     * NOTE: we could have used typo3 entities_to_utf8() here
-     *       but the direct alternative used runs 400% quicker
-     *       and uses 0.5Mb less memory, so, let's use it
-     *       (tested against 10^6 conversions)
      */
     public static function entities_to_utf8($str, $htmlent=true) {
-        static $trans_tbl; // Going to use static transliteration table
+        static $callback1 = null ;
+        static $callback2 = null ;
+
+        if (!$callback1 or !$callback2) {
+            $callback1 = create_function('$matches', 'return textlib::code2utf8(hexdec($matches[1]));');
+            $callback2 = create_function('$matches', 'return textlib::code2utf8($matches[1]);');
+        }
 
-        // Replace numeric entities
-        $result = preg_replace('~&#x([0-9a-f]+);~ei', 'textlib::code2utf8(hexdec("\\1"))', $str);
-        $result = preg_replace('~&#([0-9]+);~e', 'textlib::code2utf8(\\1)', $result);
+        $result = (string)$str;
+        $result = preg_replace_callback('/&#x([0-9a-f]+);/i', $callback1, $result);
+        $result = preg_replace_callback('/&#([0-9]+);/', $callback2, $result);
 
         // Replace literal entities (if desired)
         if ($htmlent) {
-            // Generate/create $trans_tbl
-            if (!isset($trans_tbl)) {
-                $trans_tbl = array();
-                foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) {
-                    $trans_tbl[$key] = utf8_encode($val);
-                }
-            }
+            $trans_tbl = self::get_entities_table();
+            // It should be safe to search for ascii strings and replace them with utf-8 here.
             $result = strtr($result, $trans_tbl);
         }
         // Return utf8-ised string
@@ -487,17 +511,24 @@ class textlib {
      * @return string converted string
      */
     public static function utf8_to_entities($str, $dec=false, $nonnum=false) {
-        // Avoid some notices from Typo3 code
-        $oldlevel = error_reporting(E_PARSE);
+        static $callback = null ;
+
         if ($nonnum) {
-            $str = self::typo3()->entities_to_utf8((string)$str, true);
+            $str = self::entities_to_utf8($str, true);
         }
+
+        // Avoid some notices from Typo3 code
+        $oldlevel = error_reporting(E_PARSE);
         $result = self::typo3()->utf8_to_entities((string)$str);
+        error_reporting($oldlevel);
+
         if ($dec) {
-            $result = preg_replace('/&#x([0-9a-f]+);/ie', "'&#'.hexdec('$1').';'", $result);
+            if (!$callback) {
+                $callback = create_function('$matches', 'return \'&#\'.(hexdec($matches[1])).\';\';');
+            }
+            $result = preg_replace_callback('/&#x([0-9a-f]+);/i', $callback, $result);
         }
-        // Restore original debug level
-        error_reporting($oldlevel);
+
         return $result;
     }
 
index 25b7bb9..c943f9e 100644 (file)
@@ -1384,7 +1384,7 @@ function format_text_email($text, $format) {
         case FORMAT_WIKI:
             // there should not be any of these any more!
             $text = wikify_links($text);
-            return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
+            return textlib::entities_to_utf8(strip_tags($text), true);
             break;
 
         case FORMAT_HTML:
@@ -1395,7 +1395,7 @@ function format_text_email($text, $format) {
         case FORMAT_MARKDOWN:
         default:
             $text = wikify_links($text);
-            return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
+            return textlib::entities_to_utf8(strip_tags($text), true);
             break;
     }
 }
index 074b86a..1705221 100644 (file)
@@ -447,6 +447,7 @@ function mnet_update_sso_access_control($username, $mnet_host_id, $accessctrl) {
                 "SSO ACL: $accessctrl user '$username' from {$mnethost->name}");
     } else {
         // insert
+        $aclrecord = new stdClass();
         $aclrecord->username = $username;
         $aclrecord->accessctrl = $accessctrl;
         $aclrecord->mnet_host_id = $mnet_host_id;
index b355b33..c3a0441 100644 (file)
@@ -266,7 +266,7 @@ class assignfeedback_file_zip_importer {
                     $fileplugin->update_file_count($grade);
 
                     // Update the last modified time on the grade which will trigger student notifications.
-                    $assignment->update_grade($grade);
+                    $assignment->notify_grade_modified($grade);
                 }
             }
         }
index 6ed295e..7c6a12a 100644 (file)
@@ -403,6 +403,7 @@ class assign_feedback_file extends assign_feedback_plugin {
             // Now copy each of these files to the users feedback file area.
             foreach ($users as $userid) {
                 $grade = $this->assignment->get_user_grade($userid, true);
+                $this->assignment->notify_grade_modified($grade);
 
                 $this->copy_area_files($fs,
                                        $this->assignment->get_context()->id,
index d64927f..e01d7b8 100644 (file)
@@ -157,6 +157,7 @@ class assign_feedback_offline extends assign_feedback_plugin {
                 $grade->grade = $record->grade;
                 $grade->grader = $USER->id;
                 if ($this->assignment->update_grade($grade)) {
+                    $this->assignment->notify_grade_modified($grade);
                     $this->assignment->add_to_log('grade submission', $this->assignment->format_grade_for_log($grade));
                     $updatecount += 1;
                 }
@@ -178,6 +179,7 @@ class assign_feedback_offline extends assign_feedback_plugin {
                     if ($newvalue != $oldvalue) {
                         $updatecount += 1;
                         $grade = $this->assignment->get_user_grade($record->user->id, true);
+                        $this->assignment->notify_grade_modified($grade);
                         if ($plugin->set_editor_text($field, $newvalue, $grade->id)) {
                             $logdesc = get_string('feedbackupdate', 'assignfeedback_offline',
                                                   array('field'=>$description,
index 6163841..6b4b8ed 100644 (file)
@@ -1476,6 +1476,23 @@ class assign {
         return true;
     }
 
+    /**
+     * Mark in the database that this grade record should have an update notification sent by cron.
+     *
+     * @param stdClass $grade a grade record keyed on id
+     * @return bool true for success
+     */
+    public function notify_grade_modified($grade) {
+        global $DB;
+
+        $grade->timemodified = time();
+        if ($grade->mailed != 1) {
+            $grade->mailed = 0;
+        }
+
+        return $DB->update_record('assign_grades', $grade);
+    }
+
     /**
      * Update a grade in the grade table for the assignment and in the gradebook
      *
@@ -2040,11 +2057,26 @@ class assign {
                 }
             }
         }
-        if ($zipfile = $this->pack_files($filesforzipping)) {
+        $result = '';
+        if (count($filesforzipping) == 0) {
+            $header = new assign_header($this->get_instance(),
+                                        $this->get_context(),
+                                        '',
+                                        $this->get_course_module()->id,
+                                        get_string('downloadall', 'assign'));
+            $result .= $this->get_renderer()->render($header);
+            $result .= $this->get_renderer()->notification(get_string('nosubmission', 'assign'));
+            $url = new moodle_url('/mod/assign/view.php', array('id'=>$this->get_course_module()->id,
+                                                                    'action'=>'grading'));
+            $result .= $this->get_renderer()->continue_button($url);
+            $result .= $this->view_footer();
+        } else if ($zipfile = $this->pack_files($filesforzipping)) {
             $this->add_to_log('download all submissions', get_string('downloadall', 'assign'));
             // Send file and delete after sending.
             send_temp_file($zipfile, $filename);
+            // We will not get here - send_temp_file calls exit.
         }
+        return $result;
     }
 
     /**
@@ -2160,6 +2192,10 @@ class assign {
             $grade->grade = -1;
             $grade->grader = $USER->id;
             $grade->extensionduedate = 0;
+
+            // The mailed flag can be one of 3 values: 0 is unsent, 1 is sent and 2 is do not send yet.
+            // This is because students only want to be notified about certain types of update (grades and feedback).
+            $grade->mailed = 2;
             $gid = $DB->insert_record('assign_grades', $grade);
             $grade->id = $gid;
             return $grade;
@@ -2874,7 +2910,7 @@ class assign {
                 }
 
                 $gradeddate = $gradebookgrade->dategraded;
-                $grader = $DB->get_record('user', array('id'=>$gradebookgrade->usermodified));
+                $grader = $DB->get_record('user', array('id'=>$grade->grader));
 
                 $feedbackstatus = new assign_feedback_status($gradefordisplay,
                                                       $gradeddate,
@@ -3697,6 +3733,7 @@ class assign {
             }
 
             $this->update_grade($grade);
+            $this->notify_grade_modified($grade);
 
             // save outcomes
             if ($CFG->enableoutcomes) {
@@ -4391,6 +4428,7 @@ class assign {
             }
         }
         $this->update_grade($grade);
+        $this->notify_grade_modified($grade);
         $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
 
         $this->add_to_log('grade submission', $this->format_grade_for_log($grade));
index e4745f2..5844463 100644 (file)
@@ -31,6 +31,39 @@ defined('MOODLE_INTERNAL') || die();
  * @return bool
  */
 function assignsubmission_comments_comment_validate(stdClass $options) {
+    global $USER, $CFG, $DB;
+
+    if ($options->commentarea != 'submission_comments' &&
+            $options->commentarea != 'submission_comments_upgrade') {
+        throw new comment_exception('invalidcommentarea');
+    }
+    if (!$submission = $DB->get_record('assign_submission', array('id'=>$options->itemid))) {
+        throw new comment_exception('invalidcommentitemid');
+    }
+    $context = $options->context;
+
+    require_once($CFG->dirroot . '/mod/assign/locallib.php');
+    $assignment = new assign($context, null, null);
+
+    if ($assignment->get_instance()->id != $submission->assignment) {
+        throw new comment_exception('invalidcontext');
+    }
+    if (!has_capability('mod/assign:grade', $context)) {
+        if (!has_capability('mod/assign:submit', $context)) {
+            throw new comment_exception('nopermissiontocomment');
+        } else if ($assignment->get_instance()->teamsubmission) {
+            $group = $assignment->get_submission_group($USER->id);
+            $groupid = 0;
+            if ($group) {
+                $groupid = $group->id;
+            }
+            if ($groupid != $submission->groupid) {
+                throw new comment_exception('nopermissiontocomment');
+            }
+        } else if ($submission->userid != $USER->id) {
+            throw new comment_exception('nopermissiontocomment');
+        }
+    }
 
     return true;
 }
@@ -42,6 +75,39 @@ function assignsubmission_comments_comment_validate(stdClass $options) {
  * @return array
  */
 function assignsubmission_comments_comment_permissions(stdClass $options) {
+    global $USER, $CFG, $DB;
+
+    if ($options->commentarea != 'submission_comments' &&
+            $options->commentarea != 'submission_comments_upgrade') {
+        throw new comment_exception('invalidcommentarea');
+    }
+    if (!$submission = $DB->get_record('assign_submission', array('id'=>$options->itemid))) {
+        throw new comment_exception('invalidcommentitemid');
+    }
+    $context = $options->context;
+
+    require_once($CFG->dirroot . '/mod/assign/locallib.php');
+    $assignment = new assign($context, null, null);
+
+    if ($assignment->get_instance()->id != $submission->assignment) {
+        throw new comment_exception('invalidcontext');
+    }
+    if (!has_capability('mod/assign:grade', $context)) {
+        if (!has_capability('mod/assign:submit', $context)) {
+            return array('post' => false, 'view' => false);
+        } else if ($assignment->get_instance()->teamsubmission) {
+            $group = $assignment->get_submission_group($USER->id);
+            $groupid = 0;
+            if ($group) {
+                $groupid = $group->id;
+            }
+            if ($groupid != $submission->groupid) {
+                return array('post' => false, 'view' => false);
+            }
+        } else if ($submission->userid != $USER->id) {
+            return array('post' => false, 'view' => false);
+        }
+    }
 
     return array('post' => true, 'view' => true);
 }
index 18861e7..79f1b37 100644 (file)
@@ -48,9 +48,15 @@ M.data_filepicker.callback = function(params) {
 };
 
 /**
+ * Deprecated since 2.5, will be removed in 2.7.
+ * Please don't use this function.
+ * Use the filemanager instead. (/lib/form/filemanager.js)
  * This fucntion is called for each file picker on page.
  */
 M.data_filepicker.init = function(Y, options) {
+    if (M.cfg.developerdebug) {
+        Y.log("You are using a deprecated function call (M.data_filepicker). Please look at rewriting your call to use M.form_filemanager");
+    }
     options.formcallback = M.data_filepicker.callback;
     if (!M.core_filepicker.instances[options.client_id]) {
         M.core_filepicker.init(Y, options);
@@ -96,9 +102,15 @@ M.data_imagepicker.callback = function(params) {
 };
 
 /**
+ * Deprecated since 2.5, will be removed in 2.7.
+ * Please don't use this function.
+ * Use the filemanager instead. (/lib/form/filemanager.js)
  * This fucntion is called for each file picker on page.
  */
 M.data_imagepicker.init = function(Y, options) {
+    if (M.cfg.developerdebug) {
+        Y.log("You are using a deprecated function call (M.data_imagepicker). Please look at rewriting your call to use M.form_filemanager");
+    }
     options.formcallback = M.data_imagepicker.callback;
     if (!M.core_filepicker.instances[options.client_id]) {
         M.core_filepicker.init(Y, options);
index 4178036..c92aa5f 100644 (file)
@@ -26,6 +26,7 @@
 require_once('../../config.php');
 require_once('lib.php');
 require_once("$CFG->libdir/rsslib.php");
+require_once("$CFG->libdir/form/filemanager.php");
 
 $id    = optional_param('id', 0, PARAM_INT);    // course module id
 $d     = optional_param('d', 0, PARAM_INT);    // database id
index 605eab3..6e81ff5 100644 (file)
@@ -71,21 +71,39 @@ class data_field_file extends data_field_base {
         $html .= '<input type="hidden" name="field_'.$this->field->id.'_file" value="'.$itemid.'" />';
 
         $options = new stdClass();
-        $options->maxbytes  = $this->field->param3;
+        $options->areamaxbytes  = $this->field->param3;
+        $options->maxbytes = $this->field->param3;
+        $options->maxfiles  = 1; // Limit to one file for the moment, this may be changed if requested as a feature in the future.
         $options->itemid    = $itemid;
         $options->accepted_types = '*';
         $options->return_types = FILE_INTERNAL;
         $options->context = $PAGE->context;
 
-        $fp = new file_picker($options);
-        // print out file picker
-        $html .= $OUTPUT->render($fp);
+        $fm = new form_filemanager($options);
+        // Print out file manager.
+
+        $output = $PAGE->get_renderer('core', 'files');
+        $html .= $output->render($fm);
 
         $html .= '</fieldset>';
         $html .= '</div>';
 
-        $module = array('name'=>'data_filepicker', 'fullpath'=>'/mod/data/data.js', 'requires'=>array('core_filepicker'));
-        $PAGE->requires->js_init_call('M.data_filepicker.init', array($fp->options), true, $module);
+        $module = array(
+            'name'=>'form_filemanager',
+            'fullpath'=>'/lib/form/filemanager.js',
+            'requires' => array('core_filepicker', 'base', 'io-base', 'node',
+                    'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+            'strings' => array(
+                array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
+                array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
+                array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
+                array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
+                array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
+                array('confirmrenamefile', 'repository')
+            )
+        );
+
+        $PAGE->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
 
         return $html;
     }
index 37b320d..3e2ee7e 100644 (file)
@@ -67,13 +67,17 @@ class data_field_picture extends data_field_base {
 
         $str = '<div title="'.s($this->field->description).'">';
         $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
+        $str .= '<noscript>';
         if ($file) {
             $src = file_encode_url($CFG->wwwroot.'/pluginfile.php/', $this->context->id.'/mod_data/content/'.$content->id.'/'.$file->get_filename());
             $str .= '<img width="'.s($this->previewwidth).'" height="'.s($this->previewheight).'" src="'.$src.'" alt="" />';
         }
+        $str .= '</noscript>';
 
         $options = new stdClass();
+        $options->areamaxbytes = $this->field->param3;
         $options->maxbytes  = $this->field->param3;
+        $options->maxfiles  = 1; // Only one picture permitted.
         $options->itemid    = $itemid;
         $options->accepted_types = array('web_image');
         $options->return_types = FILE_INTERNAL;
@@ -82,9 +86,12 @@ class data_field_picture extends data_field_base {
             $options->filename = $file->get_filename();
             $options->filepath = '/';
         }
-        $fp = new file_picker($options);
-        $str .= $OUTPUT->render($fp);
 
+        $fm = new form_filemanager($options);
+        // Print out file manager.
+
+        $output = $PAGE->get_renderer('core', 'files');
+        $str .= $output->render($fm);
 
         $str .= '<div class="mdl-left">';
         $str .= '<input type="hidden" name="field_'.$this->field->id.'_file" value="'.$itemid.'" />';
@@ -95,8 +102,23 @@ class data_field_picture extends data_field_base {
         $str .= '</fieldset>';
         $str .= '</div>';
 
-        $module = array('name'=>'data_imagepicker', 'fullpath'=>'/mod/data/data.js', 'requires'=>array('core_filepicker'));
-        $PAGE->requires->js_init_call('M.data_imagepicker.init', array($fp->options), true, $module);
+        $module = array(
+            'name'=>'form_filemanager',
+            'fullpath'=>'/lib/form/filemanager.js',
+            'requires' => array('core_filepicker', 'base', 'io-base', 'node',
+                    'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+            'strings' => array(
+                array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
+                array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
+                array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
+                array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
+                array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
+                array('confirmrenamefile', 'repository')
+            )
+        );
+
+        $PAGE->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
+
         return $str;
     }
 
index 63fed3d..fdb9521 100644 (file)
@@ -5679,7 +5679,7 @@ function forum_print_latest_discussions($course, $forum, $maxdiscussions=-1, $di
                     $link = true;
                 } else {
                     $modcontext = context_module::instance($cm->id);
-                    $link = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
+                    $link = forum_user_can_see_discussion($forum, $discussion, $modcontext, $USER);
                 }
 
                 $discussion->forum = $forum->id;
index 86bf31b..bb46362 100644 (file)
@@ -56,16 +56,10 @@ function forum_rss_get_feed($context, $args) {
     }
 
     //the sql that will retreive the data for the feed and be hashed to get the cache filename
-    $sql = forum_rss_get_sql($forum, $cm);
+    list($sql, $params) = forum_rss_get_sql($forum, $cm);
 
     // Hash the sql to get the cache file name.
-    // If the forum is Q and A then we need to cache the files per user. This can
-    // have a large impact on performance, so we want to only do it on this type of forum.
-    if ($forum->type == 'qanda') {
-        $filename = rss_get_file_name($forum, $sql . $USER->id);
-    } else {
-        $filename = rss_get_file_name($forum, $sql);
-    }
+    $filename = rss_get_file_name($forum, $sql, $params);
     $cachedfilepath = rss_get_file_full_name('mod_forum', $filename);
 
     //Is the cache out of date?
@@ -75,9 +69,9 @@ function forum_rss_get_feed($context, $args) {
     }
     //if the cache is more than 60 seconds old and there's new stuff
     $dontrecheckcutoff = time()-60;
-    if ( $dontrecheckcutoff > $cachedfilelastmodified && forum_rss_newstuff($forum, $cm, $cachedfilelastmodified)) {
+    if ($dontrecheckcutoff > $cachedfilelastmodified && forum_rss_newstuff($forum, $cm, $cachedfilelastmodified)) {
         //need to regenerate the cached version
-        $result = forum_rss_feed_contents($forum, $sql, $modcontext);
+        $result = forum_rss_feed_contents($forum, $sql, $params, $modcontext);
         if (!empty($result)) {
             $status = rss_save_file('mod_forum',$filename,$result);
         }
@@ -111,10 +105,12 @@ function forum_rss_delete_file($forum) {
 function forum_rss_newstuff($forum, $cm, $time) {
     global $DB;
 
-    $sql = forum_rss_get_sql($forum, $cm, $time);
+    list($sql, $params) = forum_rss_get_sql($forum, $cm, $time);
+    if ($DB->count_records_sql($sql, $params) > 0) {
+        return true;
+    }
 
-    $recs = $DB->get_records_sql($sql, null, 0, 1);//limit of 1. If we get even 1 back we have new stuff
-    return ($recs && !empty($recs));
+    return false;
 }
 
 /**
@@ -126,17 +122,11 @@ function forum_rss_newstuff($forum, $cm, $time) {
  * @return string the SQL query to be used to get the Discussion/Post details from the forum table of the database
  */
 function forum_rss_get_sql($forum, $cm, $time=0) {
-    $sql = null;
-
-    if (!empty($forum->rsstype)) {
-        if ($forum->rsstype == 1) {    //Discussion RSS
-            $sql = forum_rss_feed_discussions_sql($forum, $cm, $time);
-        } else {                //Post RSS
-            $sql = forum_rss_feed_posts_sql($forum, $cm, $time);
-        }
+    if ($forum->rsstype == 1) { // Discussion RSS
+        return forum_rss_feed_discussions_sql($forum, $cm, $time);
+    } else { // Post RSS
+        return forum_rss_feed_posts_sql($forum, $cm, $time);
     }
-
-    return $sql;
 }
 
 /**
@@ -155,7 +145,7 @@ function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
     $modcontext = null;
 
     $now = round(time(), -2);
-    $params = array($cm->instance);
+    $params = array();
 
     $modcontext = context_module::instance($cm->id);
 
@@ -172,21 +162,21 @@ function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
         }
     }
 
-    //do we only want new posts?
+    // Do we only want new posts?
     if ($newsince) {
-        $newsince = " AND p.modified > '$newsince'";
+        $params['newsince'] = $newsince;
+        $newsince = " AND p.modified > :newsince";
     } else {
         $newsince = '';
     }
 
-    //get group enforcing SQL
-    $groupmode    = groups_get_activity_groupmode($cm);
+    // Get group enforcing SQL.
+    $groupmode = groups_get_activity_groupmode($cm);
     $currentgroup = groups_get_activity_group($cm);
-    $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
+    list($groupselect, $groupparams) = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
 
-    if ($groupmode && $currentgroup) {
-        $params['groupid'] = $currentgroup;
-    }
+    // Add the groupparams to the params array.
+    $params = array_merge($params, $groupparams);
 
     $forumsort = "d.timemodified DESC";
     $postdata = "p.id AS postid, p.subject, p.created as postcreated, p.modified, p.discussion, p.userid, p.message as postmessage, p.messageformat AS postformat, p.messagetrust AS posttrust";
@@ -199,7 +189,7 @@ function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
              WHERE d.forum = {$forum->id} AND p.parent = 0
                    $timelimit $groupselect $newsince
           ORDER BY $forumsort";
-    return $sql;
+    return array($sql, $params);
 }
 
 /**
@@ -213,19 +203,20 @@ function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
 function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
     $modcontext = context_module::instance($cm->id);
 
-    //get group enforcement SQL
-    $groupmode    = groups_get_activity_groupmode($cm);
+    // Get group enforcement SQL.
+    $groupmode = groups_get_activity_groupmode($cm);
     $currentgroup = groups_get_activity_group($cm);
+    $params = array();
 
-    $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
+    list($groupselect, $groupparams) = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
 
-    if ($groupmode && $currentgroup) {
-        $params['groupid'] = $currentgroup;
-    }
+    // Add the groupparams to the params array.
+    $params = array_merge($params, $groupparams);
 
-    //do we only want new posts?
+    // Do we only want new posts?
     if ($newsince) {
-        $newsince = " AND p.modified > '$newsince'";
+        $params['newsince'] = $newsince;
+        $newsince = " AND p.modified > :newsince";
     } else {
         $newsince = '';
     }
@@ -250,7 +241,7 @@ function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
                 $groupselect
             ORDER BY p.created desc";
 
-    return $sql;
+    return array($sql, $params);
 }
 
 /**
@@ -264,6 +255,7 @@ function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
  */
 function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=null) {
     $groupselect = '';
+    $params = array();
 
     if ($groupmode) {
         if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
@@ -272,7 +264,7 @@ function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=nul
                 $params['groupid'] = $currentgroup;
             }
         } else {
-            //seprate groups without access all
+            // Separate groups without access all.
             if ($currentgroup) {
                 $groupselect = "AND (d.groupid = :groupid OR d.groupid = -1)";
                 $params['groupid'] = $currentgroup;
@@ -282,7 +274,7 @@ function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=nul
         }
     }
 
-    return $groupselect;
+    return array($groupselect, $params);
 }
 
 /**
@@ -290,21 +282,19 @@ function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=nul
  * It returns false if something is wrong
  *
  * @param stdClass $forum the forum object
- * @param string   $sql   The SQL used to retrieve the contents from the database
+ * @param string $sql the SQL used to retrieve the contents from the database
+ * @param array $params the SQL parameters used
  * @param object $context the context this forum relates to
  * @return bool|string false if the contents is empty, otherwise the contents of the feed is returned
  *
  * @Todo MDL-31129 implement post attachment handling
  */
 
-function forum_rss_feed_contents($forum, $sql) {
+function forum_rss_feed_contents($forum, $sql, $params, $context) {
     global $CFG, $DB, $USER;
 
-
     $status = true;
 
-    $params = array();
-    //$params['forumid'] = $forum->id;
     $recs = $DB->get_recordset_sql($sql, $params, 0, $forum->rssarticles);
 
     //set a flag. Are we displaying discussions or posts?
@@ -316,7 +306,6 @@ function forum_rss_feed_contents($forum, $sql) {
     if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
         print_error('invalidcoursemodule');
     }
-    $context = context_module::instance($cm->id);
 
     $formatoptions = new stdClass();
     $items = array();
index 8ea5525..21aa851 100644 (file)
@@ -68,14 +68,16 @@ function get_scorm_question_count($scormid) {
     $params[] = "cmi.interactions_%.id";
     $rs = $DB->get_recordset_select("scorm_scoes_track", $select, $params, 'element');
     $keywords = array("cmi.interactions_", ".id");
-    foreach ($rs as $record) {
-        $num = trim(str_ireplace($keywords, '', $record->element));
-        if (is_numeric($num) && $num > $count) {
-            $count = $num;
+    if ($rs->valid()) {
+        // Done as interactions start at 0 (do only if we have something to report).
+        $count++;
+        foreach ($rs as $record) {
+            $num = trim(str_ireplace($keywords, '', $record->element));
+            if (is_numeric($num) && $num > $count) {
+                $count = $num;
+            }
         }
     }
-    //done as interactions start at 0
-    $count++;
     $rs->close(); // closing recordset
     return $count;
 }
index f83380d..c830266 100644 (file)
@@ -2,6 +2,10 @@ This files describes API changes in /mod/* - activity modules,
 information provided here is intended especially for developers.
 
 
+=== 2.5 ===
+
+* support for 'mod/*' filters was removed
+
 === 2.4 ===
 
 new features:
index ba8e386..971c26a 100644 (file)
@@ -111,14 +111,14 @@ case 'create':
     redirect($CFG->wwwroot . '/mod/wiki/edit.php?pageid='.$newpageid);
     break;
 case 'new':
-    if ((int)$wiki->forceformat == 1 && !empty($title)) {
+    // Go straight to editing if we know the page title and we're in force format mode.
+    if ((int)$wiki->forceformat == 1 && $title != get_string('newpage', 'wiki')) {
         $newpageid = $wikipage->create_page($title);
         add_to_log($course->id, 'wiki', 'add page', "view.php?pageid=".$newpageid, $newpageid, $cm->id);
         redirect($CFG->wwwroot . '/mod/wiki/edit.php?pageid='.$newpageid);
     } else {
-        // create link from moodle navigation block without pagetitle
         $wikipage->print_header();
-        // new page without page title
+        // Create a new page.
         $wikipage->print_content($title);
     }
     $wikipage->print_footer();
index 7809d12..c306eb1 100644 (file)
@@ -31,7 +31,7 @@ require_once("$CFG->dirroot/repository/lib.php");
 $subwikiid = required_param('subwiki', PARAM_INT);
 // not being used for file management, we use it to generate navbar link
 $pageid    = optional_param('pageid', 0, PARAM_INT);
-$returnurl = optional_param('returnurl', '', PARAM_URL);
+$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
 
 if (!$subwiki = wiki_get_subwiki($subwikiid)) {
     print_error('incorrectsubwikiid', 'wiki');
index 507c4c7..cbae4ee 100644 (file)
@@ -937,6 +937,8 @@ class page_wiki_create extends page_wiki {
         $data = $this->mform->get_data();
         if (isset($data->groupinfo)) {
             $groupid = $data->groupinfo;
+        } else if (!empty($this->gid)) {
+            $groupid = $this->gid;
         } else {
             $groupid = '0';
         }
index 0fbc450..873da65 100644 (file)
@@ -42,10 +42,14 @@ defined('MOODLE_INTERNAL') || die();
  */
 class qformat_learnwise extends qformat_default {
 
-    function provide_import() {
+    public function provide_import() {
         return true;
     }
 
+    public function export_file_extension() {
+        return '.xml';
+    }
+
     protected function readquestions($lines) {
         $questions = array();
         $currentquestion = array();
@@ -62,9 +66,9 @@ class qformat_learnwise extends qformat_default {
         return $questions;
     }
 
-    function readquestion($lines) {
+    protected function readquestion($lines) {
         $text = implode(' ', $lines);
-        $text = str_replace(array('\t','\n','\r','\''), array('','','','\\\''), $text);
+        $text = str_replace(array('\t','\n','\r'), array('','',''), $text);
 
         $startpos = strpos($text, '<question type');
         $endpos = strpos($text, '</question>');
@@ -75,8 +79,8 @@ class qformat_learnwise extends qformat_default {
         preg_match("/<question type=[\"\']([^\"\']+)[\"\']>/i", $text, $matches);
         $type = strtolower($matches[1]); // multichoice or multianswerchoice
 
-        $questiontext = $this->unhtmlentities($this->stringbetween($text, '<text>', '</text>'));
-        $questionhint = $this->unhtmlentities($this->stringbetween($text, '<hint>', '</hint>'));
+        $questiontext = textlib::entities_to_utf8($this->stringbetween($text, '<text>', '</text>'));
+        $questionhint = textlib::entities_to_utf8($this->stringbetween($text, '<hint>', '</hint>'));
         $questionaward = $this->stringbetween($text, '<award>', '</award>');
         $optionlist = $this->stringbetween($text, '<answer>', '</answer>');
 
@@ -89,10 +93,13 @@ class qformat_learnwise extends qformat_default {
 
         if ($type == 'multichoice') {
             foreach ($optionlist as $option) {
+                if (trim($option) === '') {
+                    continue;
+                }
                 $correct = $this->stringbetween($option, ' correct="', '">');
                 $answer = $this->stringbetween($option, '">', '</option>');
                 $optionscorrect[$n] = $correct;
-                $optionstext[$n] = $this->unhtmlentities($answer);
+                $optionstext[$n] = textlib::entities_to_utf8($answer);
                 ++$n;
             }
         } else if ($type == 'multianswerchoice') {
@@ -102,6 +109,9 @@ class qformat_learnwise extends qformat_default {
             $optionsaward = array();
 
             foreach ($optionlist as $option) {
+                if (trim($option) === '') {
+                    continue;
+                }
                 preg_match("/correct=\"([^\"]*)\"/i", $option, $correctmatch);
                 preg_match("/award=\"([^\"]*)\"/i", $option, $awardmatch);
 
@@ -115,7 +125,7 @@ class qformat_learnwise extends qformat_default {
                 $answer = $this->stringbetween($option, '">', '</option>');
 
                 $optionscorrect[$n] = $correct;
-                $optionstext[$n] = $this->unhtmlentities($answer);
+                $optionstext[$n] = textlib::entities_to_utf8($answer);
                 $optionsaward[$n] = $award;
                 ++$n;
             }
@@ -127,22 +137,25 @@ class qformat_learnwise extends qformat_default {
         $question = $this->defaultquestion();
         $question->qtype = 'multichoice';
         $question->name = $this->create_default_question_name($questiontext, get_string('questionname', 'question'));
+        $this->add_blank_combined_feedback($question);
 
         $question->questiontext = $questiontext;
+        $question->questiontextformat = FORMAT_HTML;
         $question->single = ($type == 'multichoice') ? 1 : 0;
-        $question->feedback[] = '';
 
         $question->fraction = array();
         $question->answer = array();
         for ($n = 0; $n < count($optionstext); ++$n) {
             if ($optionstext[$n]) {
-                if (!isset($numcorrect)) { // single answer
+                if (!isset($numcorrect)) {
+                    // Single answer.
                     if ($optionscorrect[$n] == 'yes') {
                         $fraction = (int) $questionaward;
                     } else {
                         $fraction = 0;
                     }
-                } else { // mulitple answers
+                } else {
+                    // Multiple answers.
                     if ($optionscorrect[$n] == 'yes') {
                         $fraction = $optionsaward[$n] / $totalaward;
                     } else {
@@ -150,15 +163,22 @@ class qformat_learnwise extends qformat_default {
                     }
                 }
                 $question->fraction[] = $fraction;
-                $question->answer[] = $optionstext[$n];
-                $question->feedback[] = ''; // no feedback in this type
+                $question->answer[] = array('text' => $optionstext[$n], 'format' => FORMAT_HTML);
+                $question->feedback[] = array('text' => '', 'format' => FORMAT_HTML); // No feedback in this type.
             }
         }
 
         return $question;
     }
 
-    function stringbetween($text, $start, $end) {
+    /**
+     * Extract the substring of $text between $start and $end.
+     * @param string $text text to analyse.
+     * @param string $start opening delimiter.
+     * @param string $end closing delimiter.
+     * @return string the requested substring.
+     */
+    protected function stringbetween($text, $start, $end) {
         $startpos = strpos($text, $start) + strlen($start);
         $endpos = strpos($text, $end);
 
@@ -166,13 +186,4 @@ class qformat_learnwise extends qformat_default {
             return substr($text, $startpos, $endpos - $startpos);
         }
     }
-
-    function unhtmlentities($string) {
-        $transtable = get_html_translation_table(HTML_ENTITIES);
-        $transtable = array_flip($transtable);
-        return strtr($string, $transtable);
-    }
-
 }
-
-
index f94cf1d..9c2229e 100644 (file)
@@ -24,4 +24,4 @@
  */
 
 $string['pluginname'] = 'Learnwise format';
-$string['plugidnname_help'] = 'This format enables the import of multiple choice questions saved in Learnwise\'s XML format.';
+$string['pluginname_help'] = 'This format enables the import of multiple choice questions saved in Learnwise\'s XML format.';
index 5e7626b..d46f4e0 100644 (file)
@@ -102,6 +102,11 @@ class qtype_shortanswer_question extends question_graded_by_strategy
             $regexp .= 'i';
         }
 
+        if (function_exists('normalizer_normalize')) {
+            $regexp = normalizer_normalize($regexp, Normalizer::FORM_C);
+            $string = normalizer_normalize($string, Normalizer::FORM_C);
+        }
+
         return preg_match($regexp, trim($string));
     }
 
index 839712c..d287ff4 100644 (file)
@@ -106,6 +106,18 @@ class qtype_shortanswer_question_test extends advanced_testcase {
         // See http://moodle.org/mod/forum/discuss.php?d=120557
         $this->assertTrue((bool)qtype_shortanswer_question::compare_string_with_wildcard(
                 'ITÁLIE', 'Itálie', true));
+
+        if (function_exists('normalizer_normalize')) {
+            // Test ambiguous unicode representations
+            $this->assertTrue((bool)qtype_shortanswer_question::compare_string_with_wildcard(
+                    'départ', 'DÉPART', true));
+            $this->assertFalse((bool)qtype_shortanswer_question::compare_string_with_wildcard(
+                    'départ', 'DÉPART', false));
+            $this->assertTrue((bool)qtype_shortanswer_question::compare_string_with_wildcard(
+                    'd'."\xC3\xA9".'part', 'd'."\x65\xCC\x81".'part', false));
+            $this->assertTrue((bool)qtype_shortanswer_question::compare_string_with_wildcard(
+                    'd'."\xC3\xA9".'part', 'D'."\x45\xCC\x81".'PART', true));
+        }
     }
 
     public function test_is_complete_response() {
index 15c7296..a4144b1 100644 (file)
@@ -42,7 +42,7 @@ add_to_log($course->id, 'course', 'report outline', "report/outline/index.php?id
 $showlastaccess = true;
 $hiddenfields = explode(',', $CFG->hiddenuserfields);
 
-if (array_search('lastaccess', $hiddenfields) and !has_capability('moodle/user:viewhiddendetails', $context)) {
+if (array_search('lastaccess', $hiddenfields) !== false and !has_capability('moodle/user:viewhiddendetails', $context)) {
     $showlastaccess = false;
 }
 
index e30944f..8191a67 100644 (file)
@@ -218,7 +218,7 @@ function report_security_check_mediafilterswf($detailed=false) {
 
     $activefilters = filter_get_globally_enabled();
 
-    if (array_search('filter/mediaplugin', $activefilters) !== false and !empty($CFG->filter_mediaplugin_enable_swf)) {
+    if (array_search('mediaplugin', $activefilters) !== false and !empty($CFG->filter_mediaplugin_enable_swf)) {
         $result->status = REPORT_SECURITY_CRITICAL;
         $result->info   = get_string('check_mediafilterswf_error', 'report_security');
     } else {
index 2ad1777..36573d8 100644 (file)
@@ -35,7 +35,7 @@ if (empty($CFG->usetags)) {
     print_error('tagsaredisabled', 'tag');
 }
 
-$returnurl = optional_param('returnurl', null, PARAM_TEXT);
+$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
 $keyword = optional_param('coursetag_new_tag', '', PARAM_TEXT);
 $courseid = optional_param('entryid', 0, PARAM_INT);
 $userid = optional_param('userid', 0, PARAM_INT);
index d4ec489..d7043c5 100644 (file)
@@ -32,7 +32,7 @@ if (isguestuser()) {
     die();
 }
 
-$returnurl = optional_param('returnurl', '', PARAM_URL);
+$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
 
 if (empty($returnurl)) {
     $returnurl = new moodle_url('/user/files.php');
index 082eaab..54d65f2 100644 (file)
@@ -297,9 +297,13 @@ if ($user->icq && !isset($hiddenfields['icqnumber'])) {
 }
 
 if ($user->skype && !isset($hiddenfields['skypeid'])) {
-    print_row(get_string('skypeid').':','<a href="skype:'.urlencode($user->skype).'?call">'.s($user->skype).
-        ' <img src="http://mystatus.skype.com/smallicon/'.urlencode($user->skype).'" alt="'.get_string('status').'" '.
-        ' /></a>');
+    if (strpos($CFG->httpswwwroot, 'https:') === 0) {
+        // Bad luck, skype devs are lazy to set up SSL on their servers - see MDL-37233.
+        $statusicon = '';
+    } else {
+        $statusicon = ' '.html_writer::empty_tag('img', array('src'=>'http://mystatus.skype.com/smallicon/'.urlencode($user->skype), 'alt'=>get_string('status')));
+    }
+    print_row(get_string('skypeid').':','<a href="skype:'.urlencode($user->skype).'?call">'.s($user->skype).$statusicon.'</a>');
 }
 if ($user->yahoo && !isset($hiddenfields['yahooid'])) {
     print_row(get_string('yahooid').':', '<a href="http://edit.yahoo.com/config/send_webmesg?.target='.urlencode($user->yahoo).'&amp;.src=pg">'.s($user->yahoo)." <img src=\"http://opi.yahoo.com/online?u=".urlencode($user->yahoo)."&m=g&t=0\" alt=\"\"></a>");
index c819d17..7c179c3 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012120300.05;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012120300.07;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.5dev (Build: 20121220)'; // Human-friendly version name
+$release  = '2.5dev (Build: 20121230)'; // Human-friendly version name
 
 $branch   = '25';                       // this version's branch
 $maturity = MATURITY_ALPHA;             // this version's maturity level