Merge branch 'master_MDL-37696' of git://github.com/danmarsden/moodle
authorSam Hemelryk <sam@moodle.com>
Mon, 28 Jan 2013 21:19:31 +0000 (10:19 +1300)
committerSam Hemelryk <sam@moodle.com>
Mon, 28 Jan 2013 21:19:31 +0000 (10:19 +1300)
83 files changed:
admin/cli/maintenance.php
admin/roles/lib.php
blocks/completionstatus/details.php
blocks/glossary_random/block_glossary_random.php
blocks/glossary_random/db/access.php
blocks/glossary_random/db/upgrade.php [deleted file]
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 [deleted file]
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 [deleted file]
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 [deleted file]
blocks/online_users/lang/en/block_online_users.php
blocks/online_users/version.php
blocks/rss_client/editfeed.php
blocks/rss_client/managefeeds.php
blocks/rss_client/viewfeed.php
cache/classes/factory.php
cache/locallib.php
course/category.php
course/lib.php
course/search.php
course/yui/toolboxes/toolboxes.js
enrol/yui/rolemanager/rolemanager.js
lang/en/admin.php
lang/en/form.php
lang/en/message.php
lang/en/question.php
lang/en/role.php
lib/adminlib.php
lib/csslib.php
lib/db/caches.php
lib/editor/tinymce/editor_styles.css [deleted file]
lib/editor/tinymce/lib.php
lib/editor/tinymce/styles.css [new file with mode: 0644]
lib/editor/tinymce/yui/collapse/collapse.js [new file with mode: 0644]
lib/filestorage/tests/zip_packer_test.php
lib/filestorage/zip_archive.php
lib/form/editor.php
lib/javascript-static.js
lib/moodlelib.php
lib/navigationlib.php
lib/outputrenderers.php
lib/phpunit/bootstrap.php
lib/setup.php
lib/setuplib.php
lib/yui/chooserdialogue/chooserdialogue.js
message/index.php
message/lib.php
message/tests/externallib_test.php
mod/feedback/analysis.php
mod/feedback/analysis_course.php
mod/feedback/lib.php
mod/forum/lib.php
mod/glossary/editcategories.html
mod/glossary/editcategories.php
mod/glossary/formats.php
mod/lesson/format.php
mod/quiz/edit.php
mod/quiz/styles.css
mod/scorm/player.php
mod/wiki/pagelib.php
question/format/blackboard_six/formatqti.php
question/format/blackboard_six/lang/en/qformat_blackboard_six.php
question/format/examview/format.php
question/format/learnwise/format.php
question/format/missingword/format.php
question/format/missingword/lang/en/qformat_missingword.php
question/format/missingword/tests/fixtures/question.missingword1.txt [new file with mode: 0644]
question/format/missingword/tests/fixtures/question.missingword2.txt [new file with mode: 0644]
question/format/missingword/tests/fixtures/question.missingword3.txt [new file with mode: 0644]
question/format/xhtml/format.php
question/type/edit_question_form.php
report/completion/user.php

index 01bfcc6..b267a03 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
@@ -16,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Enable or disable maintenance mode
+ * Enable or disable maintenance mode.
  *
  * @package    core
  * @subpackage cli
 
 define('CLI_SCRIPT', true);
 
-require(dirname(dirname(dirname(__FILE__))).'/config.php');
-require_once($CFG->libdir.'/clilib.php');      // cli only functions
+require(__DIR__.'/../../config.php');
+require_once("$CFG->libdir/clilib.php");
+require_once("$CFG->libdir/adminlib.php");
 
 
-// now get cli options
-list($options, $unrecognized) = cli_get_params(array('enable'=>false, 'disable'=>false, 'help'=>false),
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(array('enable'=>false, 'enablelater'=>0, 'enableold'=>false, 'disable'=>false, 'help'=>false),
                                                array('h'=>'help'));
 
 if ($unrecognized) {
@@ -45,12 +45,14 @@ if ($options['help']) {
 Current status displayed if not option specified.
 
 Options:
---enable              Enable maintenance mode
+--enable              Enable CLI maintenance mode
+--enablelater=MINUTES Number of minutes before entering CLI maintenance mode
+--enableold           Enable legacy half-maintenance mode
 --disable             Disable maintenance mode
 -h, --help            Print out this help
 
 Example:
-\$sudo -u www-data /usr/bin/php admin/cli/maintenance.php
+\$ sudo -u www-data /usr/bin/php admin/cli/maintenance.php
 "; //TODO: localize - to be translated later when everything is finished
 
     echo $help;
@@ -59,18 +61,52 @@ Example:
 
 cli_heading(get_string('sitemaintenancemode', 'admin')." ($CFG->wwwroot)");
 
-if ($options['enable']) {
+if ($options['enablelater']) {
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        // Already enabled, sorry.
+        echo get_string('clistatusenabled', 'admin')."\n";
+        return 1;
+    }
+
+    $time = time() + ($options['enablelater']*60);
+    set_config('maintenance_later', $time);
+
+    echo get_string('clistatusenabledlater', 'admin', userdate($time))."\n";
+    return 0;
+
+} else if ($options['enable']) {
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        // The maintenance is already enabled, nothing to do.
+    } else {
+        enable_cli_maintenance_mode();
+    }
+    set_config('maintenance_enabled', 0);
+    unset_config('maintenance_later');
+    echo get_string('sitemaintenanceoncli', 'admin')."\n";
+    exit(0);
+
+} else if ($options['enableold']) {
     set_config('maintenance_enabled', 1);
+    unset_config('maintenance_later');
     echo get_string('sitemaintenanceon', 'admin')."\n";
     exit(0);
+
 } else if ($options['disable']) {
     set_config('maintenance_enabled', 0);
+    unset_config('maintenance_later');
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        unlink("$CFG->dataroot/climaintenance.html");
+    }
     echo get_string('sitemaintenanceoff', 'admin')."\n";
     exit(0);
 }
 
-if (!empty($CFG->maintenance_enabled)) {
+if (!empty($CFG->maintenance_enabled) or file_exists("$CFG->dataroot/climaintenance.html")) {
     echo get_string('clistatusenabled', 'admin')."\n";
+
+} else if (isset($CFG->maintenance_later)) {
+    echo get_string('clistatusenabledlater', 'admin', userdate($CFG->maintenance_later))."\n";
+
 } else {
     echo get_string('clistatusdisabled', 'admin')."\n";
 }
index 60acdf9..45dccf6 100644 (file)
@@ -661,7 +661,7 @@ class define_role_table_advanced extends capability_table_with_risks {
     public function make_copy() {
         $this->roleid = 0;
         unset($this->role->id);
-        $this->role->name .= ' ' . get_string('copyasnoun');
+        $this->role->name = role_get_name($this->role, null, ROLENAME_ORIGINAL) . ' ' . get_string('copyasnoun');
         $this->role->shortname .= 'copy';
     }
 
@@ -738,6 +738,56 @@ class define_role_table_advanced extends capability_table_with_risks {
         return $output;
     }
 
+    /**
+     * Returns an array of roles of the allowed type.
+     *
+     * @param string $type Must be one of: assign, switch, or override.
+     * @return array
+     */
+    protected function get_allow_roles_list($type) {
+        global $DB;
+
+        if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
+            debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
+            return array();
+        }
+
+        if (empty($this->roleid)) {
+            return array();
+        }
+
+        $sql = "SELECT r.*
+                  FROM {role} r
+                  JOIN {role_allow_{$type}} a ON a.allow{$type} = r.id
+                 WHERE a.roleid = :roleid
+              ORDER BY r.sortorder ASC";
+        return $DB->get_records_sql($sql, array('roleid'=>$this->roleid));
+    }
+
+    /**
+     * Returns an array of roles with the allowed type.
+     *
+     * @param string $type Must be one of: assign, switch, or override.
+     * @return array Am array of role names with the allowed type
+     */
+    protected function get_allow_role_control($type) {
+        if ($roles = $this->get_allow_roles_list($type)) {
+            $roles = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
+            return implode(', ', $roles);
+        } else {
+            return get_string('none');
+        }
+    }
+
+    /**
+     * Returns information about the risks associated with a role.
+     *
+     * @return string
+     */
+    protected function get_role_risks_info() {
+        return '';
+    }
+
     protected function print_field($name, $caption, $field) {
         global $OUTPUT;
         // Attempt to generate HTML like formslib.
@@ -781,6 +831,12 @@ class define_role_table_advanced extends capability_table_with_risks {
         $this->print_field('edit-description', get_string('customroledescription', 'role').'&nbsp;'.$OUTPUT->help_icon('customroledescription', 'role'), $this->get_description_field('description'));
         $this->print_field('menuarchetype', get_string('archetype', 'role').'&nbsp;'.$OUTPUT->help_icon('archetype', 'role'), $this->get_archetype_field('archetype'));
         $this->print_field('', get_string('maybeassignedin', 'role'), $this->get_assignable_levels_control());
+        $this->print_field('', get_string('allowassign', 'role'), $this->get_allow_role_control('assign'));
+        $this->print_field('', get_string('allowoverride', 'role'), $this->get_allow_role_control('override'));
+        $this->print_field('', get_string('allowswitch', 'role'), $this->get_allow_role_control('switch'));
+        if ($risks = $this->get_role_risks_info()) {
+            $this->print_field('', get_string('rolerisks', 'role'), $risks);
+        }
         echo "</div>";
 
         $this->print_show_hide_advanced_button();
@@ -882,6 +938,57 @@ class view_role_definition_table extends define_role_table_advanced {
         // Do nothing.
     }
 
+    /**
+     * Returns HTML risk icons.
+     *
+     * @return string
+     */
+    protected function get_role_risks_info() {
+        global $OUTPUT;
+
+        if (empty($this->roleid)) {
+            return '';
+        }
+
+        $risks = array();
+        $allrisks = get_all_risks();
+        foreach ($this->capabilities as $capability) {
+            $perm = $this->permissions[$capability->name];
+            if ($perm != CAP_ALLOW) {
+                continue;
+            }
+            foreach ($allrisks as $type=>$risk) {
+                if ($risk & (int)$capability->riskbitmask) {
+                    $risks[$type] = $risk;
+                }
+            }
+        }
+
+        $risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'role'))));
+        foreach ($risks as $type=>$risk) {
+            $pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
+            $risks[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl));
+        }
+
+        return implode(' ', $risks);
+    }
+
+    /**
+     * Returns true if the row should be skipped.
+     *
+     * @param string $capability
+     * @return bool
+     */
+    protected function skip_row($capability) {
+        $perm = $this->permissions[$capability->name];
+        if ($perm == CAP_INHERIT) {
+            // Do not print empty rows in role overview, admins need to know quickly what is allowed and prohibited,
+            // if they want to see the list of all capabilities they can go to edit role page.
+            return true;
+        }
+        parent::skip_row($capability);
+    }
+
     protected function add_permission_cells($capability) {
         $perm = $this->permissions[$capability->name];
         $permname = $this->allpermissions[$perm];
index 3878964..2b2525a 100644 (file)
@@ -91,7 +91,7 @@ echo $OUTPUT->header();
 
 
 // Display completion status
-echo '<table class="generalbox boxaligncenter"><tbody>';
+echo '<table class="generaltable boxaligncenter"><tbody>';
 
 // If not display logged in user, show user name
 if ($USER->id != $user->id) {
@@ -148,7 +148,7 @@ if (empty($completions)) {
     echo '</td></tr></tbody></table>';
 
     // Generate markup for criteria statuses
-    echo '<table class="generalbox logtable boxaligncenter" id="criteriastatus" width="100%"><tbody>';
+    echo '<table class="generaltable logtable boxaligncenter" id="criteriastatus" width="100%"><tbody>';
     echo '<tr class="ccheader">';
     echo '<th class="c0 header" scope="col">'.get_string('criteriagroup', 'block_completionstatus').'</th>';
     echo '<th class="c1 header" scope="col">'.get_string('criteria', 'completion').'</th>';
index 8dfa97f..884c909 100644 (file)
@@ -11,10 +11,6 @@ class block_glossary_random extends block_base {
         $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 e7bb687..0c1acd6 100644 (file)
@@ -26,6 +26,16 @@ 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
deleted file mode 100644 (file)
index 81aeabe..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This 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 0147f00..6366bd4 100644 (file)
@@ -28,6 +28,7 @@ $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 061ec44..a5d21fa 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // 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 85f48f3..aa340af 100644 (file)
@@ -7,7 +7,7 @@ class block_mentees extends block_base {
     }
 
     function applicable_formats() {
-        return array('all' => true, 'tag' => false, 'my' => false);
+        return array('all' => true, 'tag' => false);
     }
 
     function specialization() {
index 489ceb3..ba14b07 100644 (file)
@@ -26,6 +26,16 @@ 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
deleted file mode 100644 (file)
index e8aba71..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This 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 1c0cdab..3a22057 100644 (file)
@@ -27,5 +27,6 @@ $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 c3a8db3..7f9e179 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // 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 e803c6e..5ecbec2 100644 (file)
@@ -5,10 +5,6 @@ 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 452158e..86bb1b7 100644 (file)
@@ -26,6 +26,16 @@ 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
deleted file mode 100644 (file)
index e634e57..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This 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 1de6507..7d76b9c 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['news_items:addinstance'] = 'Add a new latest news block';
+$string['news_items:myaddinstance'] = 'Add a new latest news block to the My Moodle page';
 $string['pluginname'] = 'Latest news';
index 11d74ca..ba6e931 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // 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 6d14ebb..50ff41a 100644 (file)
@@ -10,10 +10,6 @@ class block_online_users extends block_base {
         $this->title = get_string('pluginname','block_online_users');
     }
 
-    function applicable_formats() {
-        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
-    }
-
     function has_config() {
         return true;
     }
index 41959c4..f238b73 100644 (file)
@@ -26,6 +26,16 @@ 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
deleted file mode 100644 (file)
index f45a788..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This 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 b7a008e..034fce5 100644 (file)
@@ -25,6 +25,7 @@
 
 $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 4463c45..9a32ef0 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // 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 7067835..110c4d2 100644 (file)
@@ -177,7 +177,7 @@ if ($returnurl) {
 $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
 
 $PAGE->set_url('/blocks/rss_client/editfeed.php', $urlparams);
-$PAGE->set_pagelayout('base');
+$PAGE->set_pagelayout('standard');
 
 if ($rssid) {
     $isadding = false;
@@ -218,10 +218,9 @@ if ($mform->is_cancelled()) {
     $PAGE->set_title($strtitle);
     $PAGE->set_heading($strtitle);
 
-    $settingsurl = new moodle_url('/admin/settings.php?section=blocksettingrss_client');
     $PAGE->navbar->add(get_string('blocks'));
-    $PAGE->navbar->add(get_string('pluginname', 'block_rss_client'), $settingsurl);
-    $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'));
+    $PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+    $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds );
     $PAGE->navbar->add($strtitle);
 
     echo $OUTPUT->header();
index 0340b0f..2252bc9 100644 (file)
@@ -83,10 +83,9 @@ $PAGE->set_pagelayout('standard');
 $PAGE->set_title($strmanage);
 $PAGE->set_heading($strmanage);
 
-$settingsurl = new moodle_url('/admin/settings.php?section=blocksettingrss_client');
 $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
 $PAGE->navbar->add(get_string('blocks'));
-$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'), $settingsurl);
+$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
 $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds);
 echo $OUTPUT->header();
 
index f969a30..1c287d7 100644 (file)
@@ -71,11 +71,10 @@ $strviewfeed = get_string('viewfeed', 'block_rss_client');
 $PAGE->set_title($strviewfeed);
 $PAGE->set_heading($strviewfeed);
 
-$settingsurl = new moodle_url('/admin/settings.php?section=blocksettingrss_client');
 $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
 $PAGE->navbar->add(get_string('blocks'));
-$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'), $settingsurl);
-$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'));
+$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds);
 $PAGE->navbar->add($strviewfeed);
 echo $OUTPUT->header();
 
index 447ef30..c23a147 100644 (file)
@@ -48,6 +48,8 @@ class cache_factory {
     const STATE_SAVING = 2;
     /** The cache is ready to use. */
     const STATE_READY = 3;
+    /** The cache is currently updating itself */
+    const STATE_UPDATING = 4;
     /** The cache encountered an error while initialising. */
     const STATE_ERROR_INITIALISING = 9;
     /** The cache has been disabled. */
@@ -220,7 +222,12 @@ class cache_factory {
      */
     public function create_cache(cache_definition $definition) {
         $class = $definition->get_cache_class();
-        $stores = cache_helper::get_cache_stores($definition);
+        if ($this->is_initialising()) {
+            // Do nothing we just want the dummy store.
+            $stores = array();
+        } else {
+            $stores = cache_helper::get_cache_stores($definition);
+        }
         if (count($stores) === 0) {
             // Hmm no stores, better provide a dummy store to mimick functionality. The dev will be none the wiser.
             $stores[] = $this->create_dummy_store($definition);
@@ -333,21 +340,52 @@ class cache_factory {
             $id .= '::'.$aggregate;
         }
         if (!array_key_exists($id, $this->definitions)) {
-            $instance = $this->create_config_instance();
-            $definition = $instance->get_definition_by_id($id);
-            if (!$definition) {
-                $this->reset();
-                $instance = $this->create_config_instance(true);
-                $instance->update_definitions();
+            // This is the first time this definition has been requested.
+            if ($this->is_initialising()) {
+                // We're initialising the cache right now. Don't try to create another config instance.
+                // We'll just use an ad-hoc cache for the time being.
+                $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, $component, $area);
+            } else {
+                // Load all the known definitions and find the desired one.
+                $instance = $this->create_config_instance();
                 $definition = $instance->get_definition_by_id($id);
                 if (!$definition) {
-                    throw new coding_exception('The requested cache definition does not exist.'. $id, $id);
+                    // Oh-oh the definition doesn't exist.
+                    // There are several things that could be going on here.
+                    // We may be installing/upgrading a site and have hit a definition that hasn't been used before.
+                    // Of the developer may be trying to use a newly created definition.
+                    if ($this->is_updating()) {
+                        // The cache is presently initialising and the requested cache definition has not been found.
+                        // This means that the cache initialisation has requested something from a cache (I had recursive nightmares about this).
+                        // To serve this purpose and avoid errors we are going to make use of an ad-hoc cache rather than
+                        // search for the definition which would possibly cause an infitite loop trying to initialise the cache.
+                        $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, $component, $area);
+                        if ($aggregate !== null) {
+                            // If you get here you deserve a warning. We have to use an ad-hoc cache here, so we can't find the definition and therefor
+                            // can't find any information about the datasource or any of its aggregated.
+                            // Best of luck.
+                            debugging('An unknown cache was requested during development with an aggregate that could not be loaded. Ad-hoc cache used instead.', DEBUG_DEVELOPER);
+                            $aggregate = null;
+                        }
+                    } else {
+                        // Either a typo of the developer has just created the definition and is using it for the first time.
+                        $this->reset();
+                        $instance = $this->create_config_instance(true);
+                        $instance->update_definitions();
+                        $definition = $instance->get_definition_by_id($id);
+                        if (!$definition) {
+                            throw new coding_exception('The requested cache definition does not exist.'. $id, $id);
+                        } else {
+                            debugging('Cache definitions reparsed causing cache reset in order to locate definition.
+                                You should bump the version number to ensure definitions are reprocessed.', DEBUG_DEVELOPER);
+                        }
+                        $definition = cache_definition::load($id, $definition, $aggregate);
+                    }
                 } else {
-                    debugging('Cache definitions reparsed causing cache reset in order to locate definition.
-                        You should bump the version number to ensure definitions are reprocessed.', DEBUG_DEVELOPER);
+                    $definition = cache_definition::load($id, $definition, $aggregate);
                 }
             }
-            $this->definitions[$id] = cache_definition::load($id, $definition, $aggregate);
+            $this->definitions[$id] = $definition;
         }
         return $this->definitions[$id];
     }
@@ -414,6 +452,29 @@ class cache_factory {
         return true;
     }
 
+    /**
+     * Informs the factory that the cache is currently updating itself.
+     *
+     * This forces the state to upgrading and can only be called once the cache is ready to use.
+     * Calling it ensure we don't try to reinstantite things when requesting cache definitions that don't exist yet.
+     */
+    public function updating_started() {
+        if ($this->state !== self::STATE_READY) {
+            return false;
+        }
+        $this->state = self::STATE_UPDATING;
+        return true;
+    }
+
+    /**
+     * Informs the factory that the upgrading has finished.
+     *
+     * This forces the state back to ready.
+     */
+    public function updating_finished() {
+        $this->state = self::STATE_READY;
+    }
+
     /**
      * Returns true if the cache API has been disabled.
      *
@@ -423,6 +484,26 @@ class cache_factory {
         return $this->state === self::STATE_DISABLED;
     }
 
+    /**
+     * Returns true if the cache is currently initialising itself.
+     *
+     * This includes both initialisation and saving the cache config file as part of that initialisation.
+     *
+     * @return bool
+     */
+    public function is_initialising() {
+        return $this->state === self::STATE_INITIALISING || $this->state === self::STATE_SAVING;
+    }
+
+    /**
+     * Returns true if the cache is currently updating itself.
+     *
+     * @return bool
+     */
+    public function is_updating() {
+        return $this->state === self::STATE_UPDATING;
+    }
+
     /**
      * Disables as much of the cache API as possible.
      *
index 76888b7..cd4407c 100644 (file)
@@ -401,8 +401,11 @@ class cache_config_writer extends cache_config {
      * @param bool $coreonly If set to true only core definitions will be updated.
      */
     public static function update_definitions($coreonly = false) {
-        $config = self::instance();
+        $factory = cache_factory::instance();
+        $factory->updating_started();
+        $config = $factory->create_config_instance(true);
         $config->write_definitions_to_cache(self::locate_definitions($coreonly));
+        $factory->updating_finished();
     }
 
     /**
index 71ea312..68c8701 100644 (file)
@@ -322,7 +322,7 @@ if (!$courses) {
 
     echo '<form id="movecourses" action="category.php" method="post"><div>';
     echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
-    echo '<table border="0" cellspacing="2" cellpadding="4" class="generalbox boxaligncenter"><tr>';
+    echo '<table border="0" cellspacing="2" cellpadding="4" class="generaltable boxaligncenter"><tr>';
     echo '<th class="header" scope="col">'.get_string('courses').'</th>';
     if ($editingon) {
         echo '<th class="header" scope="col">'.get_string('edit').'</th>';
index 0673ade..c5e9d86 100644 (file)
@@ -356,7 +356,7 @@ function print_log($course, $user=0, $date=0, $order="l.time ASC", $page=0, $per
     echo $OUTPUT->paging_bar($totalcount, $page, $perpage, "$url&perpage=$perpage");
 
     $table = new html_table();
-    $table->classes = array('logtable','generalbox');
+    $table->classes = array('logtable','generaltable');
     $table->align = array('right', 'left', 'left');
     $table->head = array(
         get_string('time'),
@@ -1144,7 +1144,8 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) {
         // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!!
         $gettypesfunc =  $modname.'_get_types';
         if (function_exists($gettypesfunc)) {
-            if ($types = $gettypesfunc()) {
+            $types = $gettypesfunc();
+            if (is_array($types) && count($types) > 0) {
                 $group = new stdClass();
                 $group->name = $modname;
                 $group->icon = $OUTPUT->pix_icon('icon', '', $modname, array('class' => 'icon'));
@@ -1193,7 +1194,11 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) {
             $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
             $modlist[$course->id][$modname] = $module;
         }
-        $return[$modname] = $modlist[$course->id][$modname];
+        if (isset($modlist[$course->id][$modname])) {
+            $return[$modname] = $modlist[$course->id][$modname];
+        } else {
+            debugging("Invalid module metadata configuration for {$modname}");
+        }
     }
 
     return $return;
index 721d968..aeccc4f 100644 (file)
@@ -282,7 +282,7 @@ if ($courses) {
         } else if (!empty($blocklist) and confirm_sesskey()) {
             echo "<input type=\"hidden\" name=\"blocklist\" value=\"$blocklist\" /></div>\n";
         }
-        echo "<table border=\"0\" cellspacing=\"2\" cellpadding=\"4\" class=\"generalbox boxaligncenter\">\n<tr>\n";
+        echo "<table border=\"0\" cellspacing=\"2\" cellpadding=\"4\" class=\"generaltable boxaligncenter\">\n<tr>\n";
         echo "<th scope=\"col\">$strcourses</th>\n";
         echo "<th scope=\"col\">$strcategory</th>\n";
         echo "<th scope=\"col\">$strselect</th>\n";
index 8c652e0..4e6ad15 100644 (file)
@@ -558,8 +558,9 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             // Cancel the edit if we lose focus or the escape key is pressed
             thisevent = editor.on('blur', cancel_edittitle);
             listenevents.push(thisevent);
-            thisevent = Y.one('document').on('keyup', function(e) {
-                if (e.keyCode == 27) {
+            thisevent = Y.one('document').on('keydown', function(e) {
+                if (e.keyCode === 27) {
+                    e.preventDefault();
                     cancel_edittitle(e);
                 }
             });
index afa52c2..9080888 100644 (file)
@@ -56,7 +56,6 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
     Y.extend(ROLE, Y.Base, {
         users : [],
         roleAssignmentPanel : null,
-        panelsubmitevent : null,
         rolesLoadedEvent : null,
         escCloseEvent  : null,
         initializer : function(config) {
@@ -75,14 +74,16 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
             this.rolesLoadedEvent = this.on('assignablerolesloaded', function(){
                 this.rolesLoadedEvent.detach();
                 var panel = this._getRoleAssignmentPanel();
-                this.panelsubmitevent = panel.on('submit', this.addRoleCallback, this);
-                panel.hide().display(user);
+                panel.hide();
+                panel.submitevent = panel.on('submit', this.addRoleCallback, this);
+                panel.display(user);
             }, this);
             this._loadAssignableRoles();
         },
         addRoleCallback : function(e, roleid, userid) {
-            this.panelsubmitevent.detach();
             var panel = this._getRoleAssignmentPanel();
+            panel.submitevent.detach();
+            panel.submitevent = null;
             Y.io(M.cfg.wwwroot+'/enrol/ajax.php', {
                 method:'POST',
                 data:'id='+this.get(COURSEID)+'&action=assign&sesskey='+M.cfg.sesskey+'&roleid='+roleid+'&user='+userid,
@@ -350,6 +351,7 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
     Y.extend(ROLEPANEL, Y.Base, {
         user : null,
         roles : [],
+        submitevent : null,
         initializer : function() {
             var i, m = this.get(MANIPULATOR);
             var element = Y.Node.create('<div class="enrolpanel roleassign"><div class="container"><div class="header"><h2>'+M.str.role.assignroles+'</h2><div class="close"></div></div><div class="content"></div></div></div>');
@@ -398,6 +400,10 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
             this.roles = [];
             this.user = null;
             this.get('elementNode').removeClass('visible');
+            if (this.submitevent) {
+                this.submitevent.detach();
+                this.submitevent = null;
+            }
             this.displayed = false;
             return this;
         },
index df948f3..12854e1 100644 (file)
@@ -105,6 +105,7 @@ $string['cliincorrectvalueerror'] = 'Error, incorrect value "{$a->value}" for "{
 $string['cliincorrectvalueretry'] = 'Incorrect value, please retry';
 $string['clistatusdisabled'] = 'Status: disabled';
 $string['clistatusenabled'] = 'Status: enabled';
+$string['clistatusenabledlater'] = 'status: CLI maintenance mode will be enabled on {$a}';
 $string['clitypevalue'] = 'type value';
 $string['clitypevaluedefault'] = 'type value, press Enter to use default value ({$a})';
 $string['cliunknowoption'] = 'Unrecognised options:
@@ -664,6 +665,7 @@ $string['loginpasswordautocomplete_help'] = 'Having this off will let users save
 $string['loglifetime'] = 'Keep logs for';
 $string['longtimewarning'] = '<b>Please note that this process can take a long time.</b>';
 $string['maintenancemode'] = 'In maintenance mode';
+$string['maintenancemodeisscheduled'] = 'Site is switching to maintenance mode in {$a} minutes';
 $string['maintfileopenerror'] = 'Error opening maintenance files!';
 $string['maintinprogress'] = 'Maintenance is in progress...';
 $string['manageformats'] = 'Manage course formats';
@@ -955,6 +957,7 @@ $string['sitemaintenance'] = 'The site is undergoing maintenance and is currentl
 $string['sitemaintenancemode'] = 'Maintenance mode';
 $string['sitemaintenanceoff'] = 'Maintenance mode has been disabled and the site is running normally again';
 $string['sitemaintenanceon'] = 'Your site is currently in maintenance mode (only admins can log in or use the site).';
+$string['sitemaintenanceoncli'] = 'Your site is currently in CLI maintenance mode, no web access is allowed.';
 $string['sitemaintenancewarning'] = 'Your site is currently in maintenance mode (only admins can log in).  To return this site to normal operation, <a href="maintenance.php">disable maintenance mode</a>.';
 $string['sitemaintenancewarning2'] = 'Your site is currently in maintenance mode (only admins can log in).  To return this site to normal operation, <a href="{$a}">disable maintenance mode</a>.';
 $string['sitepolicies'] = 'Site policies';
index d926cd2..d5f2c6c 100644 (file)
@@ -41,6 +41,7 @@ $string['err_rangelength'] = 'You must enter between {$a->format[0]} and {$a->fo
 $string['err_required'] = 'You must supply a value here.';
 $string['general'] = 'General';
 $string['hideadvanced'] = 'Hide advanced';
+$string['hideeditortoolbar'] = 'Hide editing tools';
 $string['hour'] = 'Hour';
 $string['minute'] = 'Minute';
 $string['miscellaneoussettings'] = 'Miscellaneous settings';
@@ -57,6 +58,7 @@ $string['security'] = 'Security';
 $string['selectallornone'] = 'Select all/none';
 $string['selected'] = 'Selected';
 $string['showadvanced'] = 'Show advanced';
+$string['showeditortoolbar'] = 'Show editing tools';
 $string['somefieldsrequired'] = 'There are required fields in this form marked {$a}.';
 $string['time'] = 'Time';
 $string['timeunit'] = 'Time unit';
index 6c8ae80..edc77fa 100644 (file)
@@ -37,7 +37,7 @@ $string['blockcontact'] = 'Block contact';
 $string['blockedmessages'] = '{$a} message(s) to/from blocked users';
 $string['blockedusers'] = 'Blocked users ({$a})';
 $string['blocknoncontacts'] = 'Prevent non-contacts from messaging me';
-$string['contactlistempty'] = 'Your contact list is empty';
+$string['contactlistempty'] = 'Contact list empty';
 $string['contacts'] = 'Contacts';
 $string['context'] = 'context';
 $string['defaultmessageoutputs'] = 'Default message outputs';
@@ -83,7 +83,6 @@ $string['messages'] = 'Messages';
 $string['messaging'] = 'Messaging';
 $string['messagingblockednoncontact'] = '{$a} will not be able to reply as you have blocked non-contacts';
 $string['messagingdisabled'] = 'Messaging is disabled on this site, emails will be sent instead';
-$string['mycontacts'] = 'My contacts';
 $string['newonlymsg'] = 'Show only new';
 $string['newsearch'] = 'New search';
 $string['noframesjs'] = 'Use more accessible interface';
index 3dea4dd..d7d58fe 100644 (file)
@@ -421,6 +421,7 @@ $string['technicalinfoquestionsummary'] = 'Question summary: {$a}';
 $string['technicalinforightsummary'] = 'Right answer summary: {$a}';
 $string['technicalinfostate'] = 'Question state: {$a}';
 $string['unknownbehaviour'] = 'Unknown behaviour: {$a}.';
+$string['unknownorunhandledtype'] = 'Unknown or unhandled question type: {$a}';
 $string['unknownquestion'] = 'Unknown question: {$a}.';
 $string['unknownquestioncatregory'] = 'Unknown question category: {$a}.';
 $string['unknownquestiontype'] = 'Unknown question type: {$a}.';
index 67590fe..a1dbf29 100644 (file)
@@ -313,6 +313,7 @@ $string['role:override'] = 'Override permissions for others';
 $string['role:review'] = 'Review permissions for others';
 $string['roleprohibitheader'] = 'Prohibit role';
 $string['roleprohibitinfo'] = 'Select a role to be added to the list of prohibited roles in context {$a->context}, capability {$a->cap}:';
+$string['rolerisks'] = 'Role risks';
 $string['roles'] = 'Roles';
 $string['roles_help'] = 'A role is a collection of permissions defined for the whole system that you can assign to specific users in specific contexts.';
 $string['roles_link'] = 'roles';
index 17f22fc..fe4dc93 100644 (file)
@@ -679,6 +679,34 @@ function is_dataroot_insecure($fetchtest=false) {
     return INSECURE_DATAROOT_WARNING;
 }
 
+/**
+ * Enables CLI maintenance mode by creating new dataroot/climaintenance.html file.
+ */
+function enable_cli_maintenance_mode() {
+    global $CFG;
+
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        unlink("$CFG->dataroot/climaintenance.html");
+    }
+
+    if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) {
+        $data = $CFG->maintenance_message;
+        $data = bootstrap_renderer::early_error_content($data, null, null, null);
+        $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
+
+    } else if (file_exists("$CFG->dataroot/climaintenance.template.html")) {
+        $data = file_get_contents("$CFG->dataroot/climaintenance.template.html");
+
+    } else {
+        $data = get_string('sitemaintenance', 'admin');
+        $data = bootstrap_renderer::early_error_content($data, null, null, null);
+        $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
+    }
+
+    file_put_contents("$CFG->dataroot/climaintenance.html", $data);
+    chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions);
+}
+
 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
 
 
@@ -8043,7 +8071,7 @@ class admin_setting_configcolourpicker extends admin_setting {
         $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
         $content  = html_writer::start_tag('div', array('class'=>'form-colourpicker defaultsnext'));
         $content .= html_writer::tag('div', $OUTPUT->pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', array('class'=>'loadingicon')), array('class'=>'admin_colourpicker clearfix'));
-        $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$this->get_setting(), 'size'=>'12'));
+        $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$data, 'size'=>'12'));
         if (!empty($this->previewconfig)) {
             $content .= html_writer::empty_tag('input', array('type'=>'button','id'=>$this->get_id().'_preview', 'value'=>get_string('preview'), 'class'=>'admin_colourpicker_preview'));
         }
index 548f854..b246000 100644 (file)
@@ -113,7 +113,7 @@ function css_send_ie_css($themename, $rev, $etag, $slasharguments) {
 
     $relroot = preg_replace('|^http.?://[^/]+|', '', $CFG->wwwroot);
 
-    $css  = "/** Unfortunately IE6/7 does not support more than 4096 selectors in one CSS file, which means we have to use some ugly hacks :-( **/";
+    $css  = "/** Unfortunately IE6-9 does not support more than 4096 selectors in one CSS file, which means we have to use some ugly hacks :-( **/";
     if ($slasharguments) {
         $css .= "\n@import url($relroot/styles.php/$themename/$rev/plugins);";
         $css .= "\n@import url($relroot/styles.php/$themename/$rev/parents);";
index 6299390..fa71321 100644 (file)
@@ -102,7 +102,7 @@ $definitions = array(
         'mode' => cache_store::MODE_APPLICATION,
         'simplekeys' => true, // The course id the groupings exist for.
         'simpledata' => true, // Array of stdClass objects containing only strings.
-        'persist' => true, // Likely there will be a couple of calls to this.
+        'persistent' => true, // Likely there will be a couple of calls to this.
         'persistmaxsize' => 2, // The original cache used 1, we've increased that to two.
     ),
      // Used to cache calendar subscriptions.
diff --git a/lib/editor/tinymce/editor_styles.css b/lib/editor/tinymce/editor_styles.css
deleted file mode 100644 (file)
index e69de29..0000000
index ede90a5..277322a 100644 (file)
@@ -106,6 +106,7 @@ class tinymce_texteditor extends texteditor {
         if ($fpoptions) {
             $PAGE->requires->js_init_call('M.editor_tinymce.init_filepicker', array($elementid, $fpoptions), true);
         }
+        $this->initialise_collapse_js();
     }
 
     protected function get_init_params($elementid, array $options=null) {
@@ -274,4 +275,23 @@ class tinymce_texteditor extends texteditor {
         global $CFG;
         return new moodle_url("$CFG->httpswwwroot/lib/editor/tinymce/tiny_mce/$this->version/");
     }
+
+    /**
+     * Initialise javascript form elements
+     * @return void
+     */
+    public function initialise_collapse_js() {
+        global $PAGE;
+        // This method is called for every editor instance. Ensure it's only run once.
+        // Static is a clunky solution but the best we could find to keep everything simple and encapsulated.
+        static $isinitialised;
+        if ($isinitialised) {
+            return;
+        }
+
+        // Initialise language strings.
+        $PAGE->requires->strings_for_js(array('hideeditortoolbar', 'showeditortoolbar'), 'form');
+        $PAGE->requires->yui_module('moodle-editor_tinymce-collapse', 'M.editor_collapse.init');
+        $isinitialised = true;
+    }
 }
diff --git a/lib/editor/tinymce/styles.css b/lib/editor/tinymce/styles.css
new file mode 100644 (file)
index 0000000..f621498
--- /dev/null
@@ -0,0 +1,3 @@
+.mform .felement.feditor .toggle_editor_toolbar {background: #EEEEEE;border-color: #BBBBBB;border-radius: 4px 4px 0 0;border-style: solid solid none;border-width: 1px 1px 0;display: inline-block;font-size: 0.7em;padding: 3px 6px;width: 9em;}
+.mform .felement.feditor .mceStatusbar,
+.mform .felement.feditor iframe {min-width: 35em;}
\ No newline at end of file
diff --git a/lib/editor/tinymce/yui/collapse/collapse.js b/lib/editor/tinymce/yui/collapse/collapse.js
new file mode 100644 (file)
index 0000000..ea68c0d
--- /dev/null
@@ -0,0 +1,166 @@
+YUI.add('moodle-editor_tinymce-collapse', function(Y) {
+
+    var COLLAPSE = function() {
+        COLLAPSE.superclass.constructor.apply(this, arguments);
+    };
+
+    Y.extend(COLLAPSE, Y.Base, {
+
+        toggleNodeTemplate : null,
+        /**
+         * Set up basic values for static access.
+         */
+        init : function() {
+            this.initialise_toggles(10);
+        },
+
+        /**
+         * Has TinyMCE been loaded and the editors been initialised?
+         * Designed mainly for IE
+         * @return bool
+         */
+        editors_initialised : function() {
+            return typeof tinyMCE !== 'undefined';
+        },
+
+        initialise_toggles : function(refreshes) {
+            var editors_initialised = this.editors_initialised(), self = this, editor;
+            if (!editors_initialised && refreshes) {
+                setTimeout(function() {
+                        self.initialise_toggles(refreshes - 1);
+                    }, 100);
+                return;
+            }
+
+            // Create the toggle template for use later
+            this.toggleNodeTemplate = Y.Node.create('<a class="toggle_editor_toolbar" />');
+            this.toggleNodeTemplate.setContent(M.util.get_string('showeditortoolbar', 'form'));
+
+            // Delegate clicks of the toggle_editor_toolbar
+            Y.one('body').delegate('click', this.toggle_collapse_from_event, 'a.toggle_editor_toolbar', this);
+
+            // Set up editors which have already been created
+            for (editor in tinyMCE.editors) {
+                this.setup_collapse(tinyMCE.editors[editor]);
+            }
+
+            // Set up for future editors.
+            // I haven't yet found a way of directly delegating the editor.onInit event. Instead we have to listen for the
+            // tinyMCE.onAddEditor event, and then add a further event listener to the editor's onInit event.
+            // onAddEditor is triggered before the editor has been created.
+            // We use Y.Bind to ensure that context is maintained.
+            tinyMCE.onAddEditor.add(Y.bind(this.add_setup_collapse_listener, this));
+
+        },
+
+        /**
+         * Setup a listener for a new editor which will actually set the editor up
+         * @param {Manager} mgr
+         * @param {Editor} ed
+         */
+        add_setup_collapse_listener : function (mgr, ed) {
+            // Bind the editor.onInit function to set this editor up. This ensures we maintain our context (this)
+            ed.onInit.add(Y.bind(this.setup_collapse, this));
+        },
+
+        /**
+         * Setup the toggle system for the provided editor
+         *
+         * @param {Editor} ed The TinyMCE editor instance
+         */
+        setup_collapse : function(ed) {
+            var textarea = Y.Node(ed.getElement()),
+                editortable = Y.Node(ed.getContainer()).one('> table'),
+                thisToggleNode;
+
+            // Does this text area support collapsing at all?
+            if (!textarea.hasClass('collapsible')) {
+                return;
+            }
+
+            // Did we find an appropriate table to work with
+            if (!editortable) {
+                return;
+            }
+
+            // Add toggle button.
+            thisToggleNode = this.toggleNodeTemplate.cloneNode(true);
+            editortable.get('parentNode').insert(thisToggleNode, editortable);
+
+            // Toggle the toolbars initially.
+            if (Y.Node(ed.getElement()).hasClass('collapsed')) {
+                this.toggle_collapse(thisToggleNode, editortable, 0);
+            } else {
+                this.toggle_collapse(thisToggleNode, editortable, 1);
+            }
+        },
+
+        /**
+         * Toggle the specified editor toolbars.
+         *
+         * @param {Node} button The toggle button which we have to change the text for
+         * @param {Node} editortable The table which the tinyMCE editor is in
+         * @param {Boolean} newstate The intended toggle state
+         */
+        toggle_collapse : function(button, editortable, newstate) {
+            var toolbar = editortable.one('td.mceToolbar').ancestor('tr'),
+                statusbar = editortable.one('.mceStatusbar').ancestor('tr'),
+                editor, iframe, size;
+
+            // Check whether we have a state already.
+            if (typeof newstate === 'undefined') {
+                if (toolbar.getStyle('display') === 'none') {
+                    newstate = 1;
+                } else {
+                    newstate = 0;
+                }
+            }
+
+            // Toggle the various states and update the button text to suit
+            if (newstate === 0) {
+                toolbar.hide();
+                statusbar.hide();
+                button.setContent(M.util.get_string('showeditortoolbar', 'form'));
+            } else {
+                toolbar.show();
+                statusbar.show();
+                button.setContent(M.util.get_string('hideeditortoolbar', 'form'));
+            }
+
+            // TinyMCE renders the toolbar and path bar as part of the textarea. So toggling these items
+            // changes the required size of the rendered textarea. Frustrating but it's the way it's built.
+            // So we get TinyMCE to resize itself for us. Clunky but it works.
+
+            // Get the tinyMCE editor object for this text area.
+            editorid = editortable.ancestor('div').one('textarea').get('id');
+            editor = tinyMCE.getInstanceById(editorid);
+
+            // Somehow, this editor did not exist.
+            if (!editor) {
+                return;
+            }
+
+            // Resize editor to reflect presence of toolbar and path bar..
+            iframe = editor.getBody();
+            if (iframe) {
+                size = tinymce.DOM.getSize(iframe);
+                // If objects exist resize editor.
+                if (size) {
+                    editor.theme.resizeTo(size.w, size.h);
+                }
+            }
+        },
+
+        toggle_collapse_from_event : function(thisevent) {
+            var button = thisevent.target.ancestor('a', true),
+                editortable = thisevent.target.ancestor('span', true).one('table.mceLayout');
+            this.toggle_collapse(button, editortable);
+        }
+    });
+
+    M.editor_collapse = M.editor_collapse || {};
+    M.editor_collapse.init = function(params) {
+        return new COLLAPSE(params);
+    };
+
+}, '@VERSION@', {requires:['base', 'node', 'dom']});
\ No newline at end of file
index d71b798..ff260d1 100644 (file)
@@ -362,6 +362,7 @@ class zip_packer_testcase extends advanced_testcase {
         $zip_archive->close();
         $zip_archive->open($archive, file_archive::OPEN);
         $this->assertEquals(2, $zip_archive->count());
+        $zip_archive->close();
 
         unlink($archive);
     }
@@ -398,6 +399,7 @@ class zip_packer_testcase extends advanced_testcase {
         $zip_archive->close();
         $zip_archive->open($archive, file_archive::OPEN);
         $this->assertEquals(1, $zip_archive->count());
+        $zip_archive->close();
 
         unlink($archive);
         $zip_archive = new zip_archive();
@@ -407,5 +409,8 @@ class zip_packer_testcase extends advanced_testcase {
         $zip_archive->close();
         $zip_archive->open($archive, file_archive::OPEN);
         $this->assertEquals(1, $zip_archive->count());
+        $zip_archive->close();
+
+        unlink($archive);
     }
 }
index f7fe3c3..ba96393 100644 (file)
@@ -610,6 +610,13 @@ class zip_archive extends file_archive {
                             case 'ISO-8859-6': $encoding = 'CP720'; break;
                             case 'ISO-8859-7': $encoding = 'CP737'; break;
                             case 'ISO-8859-8': $encoding = 'CP862'; break;
+                            case 'UTF-8':
+                                if ($winchar = get_string('localewincharset', 'langconfig')) {
+                                    // Most probably works only for zh_cn,
+                                    // if there are more problems we could add zipcharset to langconfig files.
+                                    $encoding = $winchar;
+                                }
+                                break;
                         }
                     }
                     $newname = @textlib::convert($name, $encoding, 'utf-8');
index bd04b22..e3e23aa 100644 (file)
@@ -53,7 +53,7 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
     /** @var array options provided to initalize filepicker */
     protected $_options = array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 0, 'changeformat' => 0,
             'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 'context' => null, 'noclean' => 0, 'trusttext' => 0,
-            'return_types' => 7);
+            'return_types' => 7, 'collapsible' => 0, 'collapsed' => 0);
     // $_options['return_types'] = FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE
 
     /** @var array values for editor */
@@ -383,7 +383,17 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
         if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
             $editorrules = ' onblur="'.htmlspecialchars($this->getAttribute('onblur')).'" onchange="'.htmlspecialchars($this->getAttribute('onchange')).'"';
         }
-        $str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'"'.$editorrules.'>';
+        $str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'"';
+        $classes = array();
+        if (isset($this->_options['collapsed']) && $this->_options['collapsed']) {
+            $this->_options['collapsible'] = 1;
+            $classes[] = 'collapsed';
+        }
+        if (isset($this->_options['collapsible']) && $this->_options['collapsible']) {
+            $classes[] = 'collapsible';
+        }
+        $str .= ' class="' . implode(' ', $classes) . '"';
+        $str .= $editorrules.'>';
         $str .= s($text);
         $str .= '</textarea></div>';
 
index 2a5712e..1c38504 100644 (file)
@@ -1519,7 +1519,7 @@ M.util.help_icon = {
                         });
                         this.overlay.render(Y.one(document.body));
 
-                        footerbtn.on('click', this.overlay.hide, this.overlay);
+                        footerbtn.on('click', this.close, this);
 
                         var boundingBox = this.overlay.get("boundingBox");
 
@@ -1580,8 +1580,14 @@ M.util.help_icon = {
                     },
 
                     display_callback : function(content) {
-                        content = '<div role="alert">' + content + '</div>';
-                        this.overlay.set('bodyContent', content);
+                        var contentnode, heading;
+                        contentnode = Y.Node.create('<div role="alert">' + content + '</div>');
+                        this.overlay.set('bodyContent', contentnode);
+                        heading = contentnode.one('h1');
+                        if (heading) {
+                            heading.set('tabIndex', 0);
+                            heading.focus();
+                        }
                     },
 
                     hideContent : function() {
index f09d6ec..06846c6 100644 (file)
@@ -6477,10 +6477,6 @@ class core_string_manager implements string_manager {
     protected $cache;
     /** @var int get_string() counter */
     protected $countgetstring = 0;
-    /** @var int in-memory cache hits counter */
-    protected $countmemcache = 0;
-    /** @var int on-disk cache hits counter */
-    protected $countdiskcache = 0;
     /** @var bool use disk cache */
     protected $usecache;
     /** @var array limit list of translations */
@@ -6566,7 +6562,6 @@ class core_string_manager implements string_manager {
         if (!$disablecache and !$disablelocal) {
             $string = $this->cache->get($cachekey);
             if ($string) {
-                $this->countdiskcache++;
                 return $string;
             }
         }
@@ -6792,12 +6787,8 @@ class core_string_manager implements string_manager {
     public function get_performance_summary() {
         return array(array(
             'langcountgetstring' => $this->countgetstring,
-            'langcountmemcache' => $this->countmemcache,
-            'langcountdiskcache' => $this->countdiskcache,
         ), array(
             'langcountgetstring' => 'get_string calls',
-            'langcountmemcache' => 'strings mem cache hits',
-            'langcountdiskcache' => 'strings disk cache hits',
         ));
     }
 
index 93a3518..7f4c070 100644 (file)
@@ -2150,8 +2150,8 @@ class global_navigation extends navigation_node {
 
         if (!empty($CFG->messaging)) {
             $messageargs = null;
-            if ($USER->id!=$user->id) {
-                $messageargs = array('id'=>$user->id);
+            if ($USER->id != $user->id) {
+                $messageargs = array('user1' => $user->id);
             }
             $url = new moodle_url('/message/index.php',$messageargs);
             $usernode->add(get_string('messages', 'message'), $url, self::TYPE_SETTING, null, 'messages');
index 76fe99d..c5633ba 100644 (file)
@@ -428,6 +428,27 @@ class core_renderer extends renderer_base {
         if (!empty($CFG->additionalhtmltopofbody)) {
             $output .= "\n".$CFG->additionalhtmltopofbody;
         }
+        $output .= $this->maintenance_warning();
+        return $output;
+    }
+
+    /**
+     * Scheduled maintenance warning message.
+     *
+     * Note: This is a nasty hack to display maintenance notice, this should be moved
+     *       to some general notification area once we have it.
+     *
+     * @return string
+     */
+    public function maintenance_warning() {
+        global $CFG;
+
+        $output = '';
+        if (isset($CFG->maintenance_later) and $CFG->maintenance_later > time()) {
+            $output .= $this->box_start('errorbox maintenancewarning');
+            $output .= get_string('maintenancemodeisscheduled', 'admin', (int)(($CFG->maintenance_later-time())/60));
+            $output .= $this->box_end();
+        }
         return $output;
     }
 
index f63fdb0..94031b9 100644 (file)
@@ -94,12 +94,8 @@ $CFG->filepermissions = ($CFG->directorypermissions & 0666);
 if (!isset($CFG->phpunit_dataroot)) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, 'Missing $CFG->phpunit_dataroot in config.php, can not run tests!');
 }
-// Ensure we access to phpunit_dataroot realpath always.
-$CFG->phpunit_dataroot = realpath($CFG->phpunit_dataroot);
 
-if (isset($CFG->dataroot) and $CFG->phpunit_dataroot === $CFG->dataroot) {
-    phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->dataroot and $CFG->phpunit_dataroot must not be identical, can not run tests!');
-}
+// Create test dir if does not exists yet.
 if (!file_exists($CFG->phpunit_dataroot)) {
     mkdir($CFG->phpunit_dataroot, $CFG->directorypermissions);
 }
@@ -107,6 +103,13 @@ if (!is_dir($CFG->phpunit_dataroot)) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->phpunit_dataroot directory can not be created, can not run tests!');
 }
 
+// Ensure we access to phpunit_dataroot realpath always.
+$CFG->phpunit_dataroot = realpath($CFG->phpunit_dataroot);
+
+if (isset($CFG->dataroot) and $CFG->phpunit_dataroot === $CFG->dataroot) {
+    phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->dataroot and $CFG->phpunit_dataroot must not be identical, can not run tests!');
+}
+
 if (!is_writable($CFG->phpunit_dataroot)) {
     // try to fix permissions if possible
     if (function_exists('posix_getuid')) {
index f25301f..8cf2753 100644 (file)
@@ -888,6 +888,19 @@ if (!empty($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'],
     }
 }
 
+// Switch to CLI maintenance mode if required, we need to do it here after all the settings are initialised.
+if (isset($CFG->maintenance_later) and $CFG->maintenance_later <= time()) {
+    if (!file_exists("$CFG->dataroot/climaintenance.html")) {
+        require_once("$CFG->libdir/adminlib.php");
+        enable_cli_maintenance_mode();
+    }
+    unset_config('maintenance_later');
+    if (AJAX_SCRIPT) {
+        die;
+    } else if (!CLI_SCRIPT) {
+        redirect(new moodle_url('/'));
+    }
+}
 
 // note: we can not block non utf-8 installations here, because empty mysql database
 // might be converted to utf-8 in admin/index.php during installation
index 3ef5396..88fd5fd 100644 (file)
@@ -1596,15 +1596,15 @@ width: 80%; -moz-border-radius: 20px; padding: 15px">
      * @param string $meta meta tag
      * @return string html page
      */
-    protected static function plain_page($title, $content, $meta = '') {
+    public static function plain_page($title, $content, $meta = '') {
         if (function_exists('get_string') && function_exists('get_html_lang')) {
             $htmllang = get_html_lang();
         } else {
             $htmllang = '';
         }
 
-        return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" ' . $htmllang . '>
+        return '<!DOCTYPE html>
+<html ' . $htmllang . '>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 '.$meta.'
index 6f8ceec..cb7d54a 100644 (file)
@@ -144,7 +144,7 @@ YUI.add('moodle-core-chooserdialogue', function(Y) {
             this.listenevents.push(thisevent);
 
             // Grab global keyup events and handle them
-            thisevent = Y.one('document').on('keyup', this.handle_key_press, this);
+            thisevent = Y.one('document').on('keydown', this.handle_key_press, this);
             this.listenevents.push(thisevent);
 
             // Add references to various elements we adjust
index 3ab24b2..f057584 100644 (file)
@@ -64,43 +64,41 @@ $advancedsearch = optional_param('advanced', 0, PARAM_INT);
 //if they have numerous contacts or are viewing course participants we might need to page through them
 $page = optional_param('page', 0, PARAM_INT);
 
-$url = new moodle_url('/message/index.php');
+$url = new moodle_url('/message/index.php', array('user1' => $user1id));
 
 if ($user2id !== 0) {
     $url->param('user2', $user2id);
-}
 
-if ($user2id !== 0) {
     //Switch view back to contacts if:
     //1) theyve searched and selected a user
     //2) they've viewed recent messages or notifications and clicked through to a user
-    if ($viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
+    if ($viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
         $viewing = MESSAGE_VIEW_CONTACTS;
     }
 }
-$url->param('viewing', $viewing);
+
+if ($viewing != MESSAGE_VIEW_UNREAD_MESSAGES) {
+    $url->param('viewing', $viewing);
+}
 
 $PAGE->set_url($url);
 
-$PAGE->set_context(context_user::instance($USER->id));
-$PAGE->navigation->extend_for_user($USER);
-$PAGE->set_pagelayout('course');
+$navigationurl = new moodle_url('/message/index.php', array('user1' => $user1id));
+navigation_node::override_active_url($navigationurl);
 
 // Disable message notification popups while the user is viewing their messages
 $PAGE->set_popup_notification_allowed(false);
 
-$context = context_system::instance();
-
 $user1 = null;
 $currentuser = true;
-$showcontactactionlinks = true;
+$showactionlinks = true;
 if ($user1id != $USER->id) {
     $user1 = $DB->get_record('user', array('id' => $user1id));
     if (!$user1) {
         print_error('invaliduserid');
     }
     $currentuser = false;//if we're looking at someone else's messages we need to lock/remove some UI elements
-    $showcontactactionlinks = false;
+    $showactionlinks = false;
 } else {
     $user1 = $USER;
 }
@@ -115,12 +113,18 @@ if (!empty($user2id)) {
 }
 unset($user2id);
 
+$systemcontext = context_system::instance();
+
 // Is the user involved in the conversation?
 // Do they have the ability to read other user's conversations?
-if (!message_current_user_is_involved($user1, $user2) && !has_capability('moodle/site:readallmessages', $context)) {
+if (!message_current_user_is_involved($user1, $user2) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
     print_error('accessdenied','admin');
 }
 
+$PAGE->set_context(context_user::instance($user1->id));
+$PAGE->set_pagelayout('course');
+$PAGE->navigation->extend_for_user($user1);
+
 /// Process any contact maintenance requests there may be
 if ($addcontact and confirm_sesskey()) {
     add_to_log(SITEID, 'message', 'add contact', 'index.php?user1='.$addcontact.'&amp;user2='.$USER->id, $addcontact);
@@ -142,10 +146,10 @@ if ($unblockcontact and confirm_sesskey()) {
 
 //was a message sent? Do NOT allow someone looking at someone else's messages to send them.
 $messageerror = null;
-if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage', $context)) {
+if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage', $systemcontext)) {
     // Check that the user is not blocking us!!
     if ($contact = $DB->get_record('message_contacts', array('userid' => $user2->id, 'contactid' => $user1->id))) {
-        if ($contact->blocked and !has_capability('moodle/site:readallmessages', $context)) {
+        if ($contact->blocked and !has_capability('moodle/site:readallmessages', $systemcontext)) {
             $messageerror = get_string('userisblockingyou', 'message');
         }
     }
@@ -214,8 +218,10 @@ if (!empty($user2)) {
 }
 $countunreadtotal = message_count_unread_messages($user1);
 
-if ($countunreadtotal == 0 && $viewing == MESSAGE_VIEW_UNREAD_MESSAGES && empty($user2)) {
-    //default to showing the search
+if ($currentuser && $countunreadtotal == 0 && $viewing == MESSAGE_VIEW_UNREAD_MESSAGES && empty($user2)) {
+    // If the user has no unread messages, show the search box.
+    // We don't do this when a user is viewing another user's messages as search doesn't
+    // handle user A searching user B's messages properly.
     $viewing = MESSAGE_VIEW_SEARCH;
 }
 
@@ -224,7 +230,7 @@ $countblocked = count($blockedusers);
 
 list($onlinecontacts, $offlinecontacts, $strangers) = message_get_contacts($user1, $user2);
 
-message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showcontactactionlinks, $page);
+message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showactionlinks, $page);
 
 echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
     if (!empty($user2)) {
@@ -280,11 +286,11 @@ echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
 
             $messagehistorylink .= html_writer::end_tag('div');
 
-            message_print_message_history($user1, $user2, $search, $displaycount, $messagehistorylink, $viewingnewmessages);
+            message_print_message_history($user1, $user2, $search, $displaycount, $messagehistorylink, $viewingnewmessages, $showactionlinks);
         echo html_writer::end_tag('div');
 
         //send message form
-        if ($currentuser && has_capability('moodle/site:sendmessage', $context)) {
+        if ($currentuser && has_capability('moodle/site:sendmessage', $systemcontext)) {
             echo html_writer::start_tag('div', array('class' => 'mdl-align messagesend'));
                 if (!empty($messageerror)) {
                     echo html_writer::tag('span', $messageerror, array('id' => 'messagewarning'));
@@ -313,7 +319,7 @@ echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
     } else if ($viewing == MESSAGE_VIEW_SEARCH) {
         message_print_search($advancedsearch, $user1);
     } else if ($viewing == MESSAGE_VIEW_RECENT_CONVERSATIONS) {
-        message_print_recent_conversations($user1);
+        message_print_recent_conversations($user1, false, $showactionlinks);
     } else if ($viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
         message_print_recent_notifications($user1);
     }
index 804eb04..3b1cbca 100644 (file)
@@ -83,11 +83,11 @@ define('MESSAGE_DEFAULT_PERMITTED', 'permitted');
  * @param array $onlinecontacts an array of $user1's online contacts
  * @param array $offlinecontacts an array of $user1's offline contacts
  * @param array $strangers an array of users who have messaged $user1 who aren't contacts
- * @param bool $showcontactactionlinks show action links (add/remove contact etc) next to the users in the contact selector
+ * @param bool $showactionlinks show action links (add/remove contact etc)
  * @param int $page if there are so many users listed that they have to be split into pages what page are we viewing
  * @return void
  */
-function message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showcontactactionlinks, $page=0) {
+function message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showactionlinks, $page=0) {
     global $PAGE;
 
     echo html_writer::start_tag('div', array('class' => 'contactselector mdl-align'));
@@ -111,14 +111,14 @@ function message_print_contact_selector($countunreadtotal, $viewing, $user1, $us
         $strunreadmessages = get_string('unreadmessages','message', $countunreadtotal);
     }
 
-    message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, count($blockedusers), $strunreadmessages);
+    message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, count($blockedusers), $strunreadmessages, $user1);
 
     if ($viewing == MESSAGE_VIEW_UNREAD_MESSAGES) {
-        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 1, $showcontactactionlinks,$strunreadmessages, $user2);
+        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 1, $showactionlinks,$strunreadmessages, $user2);
     } else if ($viewing == MESSAGE_VIEW_CONTACTS || $viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_RECENT_CONVERSATIONS || $viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
-        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 0, $showcontactactionlinks, $strunreadmessages, $user2);
+        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 0, $showactionlinks, $strunreadmessages, $user2);
     } else if ($viewing == MESSAGE_VIEW_BLOCKED) {
-        message_print_blocked_users($blockedusers, $PAGE->url, $showcontactactionlinks, null, $user2);
+        message_print_blocked_users($blockedusers, $PAGE->url, $showactionlinks, null, $user2);
     } else if (substr($viewing, 0, 7) == MESSAGE_VIEW_COURSE) {
         $courseidtoshow = intval(substr($viewing, 7));
 
@@ -126,24 +126,28 @@ function message_print_contact_selector($countunreadtotal, $viewing, $user1, $us
             && array_key_exists($courseidtoshow, $coursecontexts)
             && has_capability('moodle/course:viewparticipants', $coursecontexts[$courseidtoshow])) {
 
-            message_print_participants($coursecontexts[$courseidtoshow], $courseidtoshow, $PAGE->url, $showcontactactionlinks, null, $page, $user2);
+            message_print_participants($coursecontexts[$courseidtoshow], $courseidtoshow, $PAGE->url, $showactionlinks, null, $page, $user2);
         } else {
             //shouldn't get here. User trying to access a course they're not in perhaps.
             add_to_log(SITEID, 'message', 'view', 'index.php', $viewing);
         }
     }
 
-    echo html_writer::start_tag('form', array('action' => 'index.php','method' => 'GET'));
-    echo html_writer::start_tag('fieldset');
-    $managebuttonclass = 'visible';
-    if ($viewing == MESSAGE_VIEW_SEARCH) {
-        $managebuttonclass = 'hiddenelement';
+    // Only show the search button if we're viewing our own messages.
+    // Search isn't currently able to deal with user A wanting to search user B's messages.
+    if ($showactionlinks) {
+        echo html_writer::start_tag('form', array('action' => 'index.php','method' => 'GET'));
+        echo html_writer::start_tag('fieldset');
+        $managebuttonclass = 'visible';
+        if ($viewing == MESSAGE_VIEW_SEARCH) {
+            $managebuttonclass = 'hiddenelement';
+        }
+        $strmanagecontacts = get_string('search','message');
+        echo html_writer::empty_tag('input', array('type' => 'hidden','name' => 'viewing','value' => MESSAGE_VIEW_SEARCH));
+        echo html_writer::empty_tag('input', array('type' => 'submit','value' => $strmanagecontacts,'class' => $managebuttonclass));
+        echo html_writer::end_tag('fieldset');
+        echo html_writer::end_tag('form');
     }
-    $strmanagecontacts = get_string('search','message');
-    echo html_writer::empty_tag('input', array('type' => 'hidden','name' => 'viewing','value' => MESSAGE_VIEW_SEARCH));
-    echo html_writer::empty_tag('input', array('type' => 'submit','value' => $strmanagecontacts,'class' => $managebuttonclass));
-    echo html_writer::end_tag('fieldset');
-    echo html_writer::end_tag('form');
 
     echo html_writer::end_tag('div');
 }
@@ -410,7 +414,7 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
     }
 
     if($countonlinecontacts) {
-        /// print out list of online contacts
+        // Print out list of online contacts.
 
         if (empty($titletodisplay)) {
             message_print_heading(get_string('onlinecontacts', 'message', $countonlinecontacts));
@@ -426,7 +430,7 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
     }
 
     if ($countofflinecontacts) {
-        /// print out list of offline contacts
+        // Print out list of offline contacts.
 
         if (empty($titletodisplay)) {
             message_print_heading(get_string('offlinecontacts', 'message', $countofflinecontacts));
@@ -442,7 +446,7 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
 
     }
 
-    /// print out list of incoming contacts
+    // Print out list of incoming contacts.
     if ($countstrangers) {
         message_print_heading(get_string('incomingcontacts', 'message', $countstrangers));
 
@@ -471,17 +475,18 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
  * @param array $coursecontexts array of course contexts. Keyed on course id.
  * @param int $countunreadtotal how many unread messages does the user have?
  * @param int $countblocked how many users has the current user blocked?
+ * @param stdClass $user1 The user whose messages we are viewing.
  * @param string $strunreadmessages a preconstructed message about the number of unread messages the user has
  * @return void
  */
-function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, $countblocked, $strunreadmessages) {
+function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, $countblocked, $strunreadmessages, $user1 = null) {
     $options = array();
 
     if ($countunreadtotal>0) { //if there are unread messages
         $options[MESSAGE_VIEW_UNREAD_MESSAGES] = $strunreadmessages;
     }
 
-    $str = get_string('mycontacts', 'message');
+    $str = get_string('contacts', 'message');
     $options[MESSAGE_VIEW_CONTACTS] = $str;
 
     $options[MESSAGE_VIEW_RECENT_CONVERSATIONS] = get_string('mostrecentconversations', 'message');
@@ -514,6 +519,9 @@ function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $
 
     echo html_writer::start_tag('form', array('id' => 'usergroupform','method' => 'get','action' => ''));
     echo html_writer::start_tag('fieldset');
+    if ( !empty($user1) && !empty($user1->id) ) {
+        echo html_writer::empty_tag('input', array('type' => 'hidden','name' => 'user1','value' => $user1->id));
+    }
     echo html_writer::label(get_string('messagenavigation', 'message'), 'viewing');
     echo html_writer::select($options, 'viewing', $viewing, false, array('id' => 'viewing','onchange' => 'this.form.submit()'));
     echo html_writer::end_tag('fieldset');
@@ -793,27 +801,27 @@ function message_get_recent_notifications($user, $limitfrom=0, $limitto=100) {
  * @param stdClass $user the current user
  * @param bool $showicontext flag indicating whether or not to show text next to the action icons
  */
-function message_print_recent_conversations($user=null, $showicontext=false) {
+function message_print_recent_conversations($user1 = null, $showicontext = false, $showactionlinks = true) {
     global $USER;
 
     echo html_writer::start_tag('p', array('class' => 'heading'));
     echo get_string('mostrecentconversations', 'message');
     echo html_writer::end_tag('p');
 
-    if (empty($user)) {
-        $user = $USER;
+    if (empty($user1)) {
+        $user1 = $USER;
     }
 
-    $conversations = message_get_recent_conversations($user);
+    $conversations = message_get_recent_conversations($user1);
 
     // Attach context url information to create the "View this conversation" type links
     foreach($conversations as $conversation) {
-        $conversation->contexturl = new moodle_url("/message/index.php?user2={$conversation->id}");
+        $conversation->contexturl = new moodle_url("/message/index.php?user1={$user1->id}&user2={$conversation->id}");
         $conversation->contexturlname = get_string('thisconversation', 'message');
     }
 
     $showotheruser = true;
-    message_print_recent_messages_table($conversations, $user, $showotheruser, $showicontext);
+    message_print_recent_messages_table($conversations, $user1, $showotheruser, $showicontext, false, $showactionlinks);
 }
 
 /**
@@ -849,7 +857,7 @@ function message_print_recent_notifications($user=null) {
  * @param bool $forcetexttohtml Force text to go through @see text_to_html() via @see format_text()
  * @return void
  */
-function message_print_recent_messages_table($messages, $user=null, $showotheruser=true, $showicontext=false, $forcetexttohtml=false) {
+function message_print_recent_messages_table($messages, $user = null, $showotheruser = true, $showicontext = false, $forcetexttohtml = false, $showactionlinks = true) {
     global $OUTPUT;
     static $dateformat;
 
@@ -862,26 +870,29 @@ function message_print_recent_messages_table($messages, $user=null, $showotherus
         echo html_writer::start_tag('div', array('class' => 'singlemessage'));
 
         if ($showotheruser) {
-            if ( $message->contactlistid )  {
-                if ($message->blocked == 0) { /// not blocked
-                    $strcontact = message_contact_link($message->id, 'remove', true, null, $showicontext);
-                    $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
-                } else { // blocked
+            $strcontact = $strblock = $strhistory = null;
+
+            if ($showactionlinks) {
+                if ( $message->contactlistid )  {
+                    if ($message->blocked == 0) { // The other user isn't blocked.
+                        $strcontact = message_contact_link($message->id, 'remove', true, null, $showicontext);
+                        $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
+                    } else { // The other user is blocked.
+                        $strcontact = message_contact_link($message->id, 'add', true, null, $showicontext);
+                        $strblock   = message_contact_link($message->id, 'unblock', true, null, $showicontext);
+                    }
+                } else {
                     $strcontact = message_contact_link($message->id, 'add', true, null, $showicontext);
-                    $strblock   = message_contact_link($message->id, 'unblock', true, null, $showicontext);
+                    $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
                 }
-            } else {
-                $strcontact = message_contact_link($message->id, 'add', true, null, $showicontext);
-                $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
-            }
 
-            //should we show just the icon or icon and text?
-            $histicontext = 'icon';
-            if ($showicontext) {
-                $histicontext = 'both';
+                //should we show just the icon or icon and text?
+                $histicontext = 'icon';
+                if ($showicontext) {
+                    $histicontext = 'both';
+                }
+                $strhistory = message_history_link($user->id, $message->id, true, '', '', $histicontext);
             }
-            $strhistory = message_history_link($user->id, $message->id, true, '', '', $histicontext);
-
             echo html_writer::start_tag('span', array('class' => 'otheruser'));
 
             echo html_writer::start_tag('span', array('class' => 'pix'));
@@ -890,13 +901,15 @@ function message_print_recent_messages_table($messages, $user=null, $showotherus
 
             echo html_writer::start_tag('span', array('class' => 'contact'));
 
-            $link = new moodle_url("/message/index.php?id=$message->id");
+            $link = new moodle_url("/message/index.php?user1={$user->id}&user2=$message->id");
             $action = null;
             echo $OUTPUT->action_link($link, fullname($message), $action, array('title' => get_string('sendmessageto', 'message', fullname($message))));
 
             echo html_writer::end_tag('span');//end contact
 
-            echo $strcontact.$strblock.$strhistory;
+            if ($showactionlinks) {
+                echo $strcontact.$strblock.$strhistory;
+            }
             echo html_writer::end_tag('span');//end otheruser
         }
         $messagetoprint = null;
@@ -930,19 +943,19 @@ function message_add_contact($contactid, $blocked=0) {
     }
 
     if (($contact = $DB->get_record('message_contacts', array('userid' => $USER->id, 'contactid' => $contactid))) !== false) {
-    /// record already exists - we may be changing blocking status
+    // A record already exists. We may be changing blocking status.
 
         if ($contact->blocked !== $blocked) {
-        /// change to blocking status
+            // Blocking status has been changed.
             $contact->blocked = $blocked;
             return $DB->update_record('message_contacts', $contact);
         } else {
-        /// no changes to blocking status
+            // No change to blocking status.
             return true;
         }
 
     } else {
-    /// new contact record
+        // New contact record.
         $contact = new stdClass();
         $contact->userid = $USER->id;
         $contact->contactid = $contactid;
@@ -1020,7 +1033,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
         $personsearchstring = $frm->combinedsearch;
     }
 
-    /// search for person
+    // Search for person.
     if ($personsearch) {
         if (optional_param('mycourses', 0, PARAM_BOOL)) {
             $users = array();
@@ -1046,7 +1059,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
             foreach ($users as $user) {
 
                 if ( $user->contactlistid )  {
-                    if ($user->blocked == 0) { /// not blocked
+                    if ($user->blocked == 0) { // User is not blocked.
                         $strcontact = message_contact_link($user->id, 'remove', true, null, $showicontext);
                         $strblock   = message_contact_link($user->id, 'block', true, null, $showicontext);
                     } else { // blocked
@@ -1058,7 +1071,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     $strblock   = message_contact_link($user->id, 'block', true, null, $showicontext);
                 }
 
-                //should we show just the icon or icon and text?
+                // Should we show just the icon or icon and text?
                 $histicontext = 'icon';
                 if ($showicontext) {
                     $histicontext = 'both';
@@ -1141,12 +1154,12 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
 
         if (($messages = message_search($keywords, $fromme, $tome, $courseid)) !== false) {
 
-        /// get a list of contacts
+            // Get a list of contacts.
             if (($contacts = $DB->get_records('message_contacts', array('userid' => $USER->id), '', 'contactid, blocked') ) === false) {
                 $contacts = array();
             }
 
-        /// print heading with number of results
+            // Print heading with number of results.
             echo html_writer::start_tag('p', array('class' => 'heading searchresultcount'));
             $countresults = count($messages);
             if ($countresults == MESSAGE_SEARCH_MAX_RESULTS) {
@@ -1156,7 +1169,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
             }
             echo html_writer::end_tag('p');
 
-        /// print table headings
+            // Print table headings.
             echo html_writer::start_tag('table', array('class' => 'messagesearchresults', 'cellspacing' => '0'));
 
             $headertdstart = html_writer::start_tag('td', array('class' => 'messagesearchresultscol'));
@@ -1173,7 +1186,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
             $strcontext = get_string('context', 'message');
             foreach ($messages as $message) {
 
-            /// ignore messages to and from blocked users unless $frm->includeblocked is set
+                // Ignore messages to and from blocked users unless $frm->includeblocked is set.
                 if (!optional_param('includeblocked', 0, PARAM_BOOL) and (
                       ( isset($contacts[$message->useridfrom]) and ($contacts[$message->useridfrom]->blocked == 1)) or
                       ( isset($contacts[$message->useridto]  ) and ($contacts[$message->useridto]->blocked   == 1))
@@ -1183,7 +1196,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     continue;
                 }
 
-            /// load up user to record
+                // Load user-to record.
                 if ($message->useridto !== $USER->id) {
                     $userto = $DB->get_record('user', array('id' => $message->useridto));
                     $tocontact = (array_key_exists($message->useridto, $contacts) and
@@ -1196,7 +1209,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     $toblocked = false;
                 }
 
-            /// load up user from record
+                // Load user-from record.
                 if ($message->useridfrom !== $USER->id) {
                     $userfrom = $DB->get_record('user', array('id' => $message->useridfrom));
                     $fromcontact = (array_key_exists($message->useridfrom, $contacts) and
@@ -1209,11 +1222,11 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     $fromblocked = false;
                 }
 
-            /// find date string for this message
+                // Find date string for this message.
                 $date = usergetdate($message->timecreated);
                 $datestring = $date['year'].$date['mon'].$date['mday'];
 
-            /// print out message row
+                // Print out message row.
                 echo html_writer::start_tag('tr', array('valign' => 'top'));
 
                 echo html_writer::start_tag('td', array('class' => 'contact'));
@@ -1228,8 +1241,8 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                 echo message_get_fragment($message->smallmessage, $keywords);
                 echo html_writer::start_tag('div', array('class' => 'link'));
 
-                //If the user clicks the context link display message sender on the left
-                //EXCEPT if the current user is in the conversation. Current user == always on the left
+                // If the user clicks the context link display message sender on the left.
+                // EXCEPT if the current user is in the conversation. Current user == always on the left.
                 $leftsideuserid = $rightsideuserid = null;
                 if ($currentuser->id == $message->useridto) {
                     $leftsideuserid = $message->useridto;
@@ -1525,7 +1538,10 @@ function message_search_users($courseids, $searchtext, $sort='', $exceptions='')
 }
 
 /**
- * search a user's messages
+ * Search a user's messages
+ *
+ * Returns a list of posts found using an array of search terms
+ * eg   word  +word -word
  *
  * @param array $searchterms an array of search terms (strings)
  * @param bool $fromme include messages from the user?
@@ -1535,20 +1551,17 @@ function message_search_users($courseids, $searchtext, $sort='', $exceptions='')
  * @return mixed An array of messages or false if no matching messages were found
  */
 function message_search($searchterms, $fromme=true, $tome=true, $courseid='none', $userid=0) {
-/// Returns a list of posts found using an array of search terms
-/// eg   word  +word -word
-///
     global $CFG, $USER, $DB;
 
-    // If user is searching all messages check they are allowed to before doing anything else
+    // If user is searching all messages check they are allowed to before doing anything else.
     if ($courseid == SITEID && !has_capability('moodle/site:readallmessages', context_system::instance())) {
         print_error('accessdenied','admin');
     }
 
-    /// If no userid sent then assume current user
+    // If no userid sent then assume current user.
     if ($userid == 0) $userid = $USER->id;
 
-    /// Some differences in SQL syntax
+    // Some differences in SQL syntax.
     if ($DB->sql_regex_supported()) {
         $REGEXP    = $DB->sql_regex(true);
         $NOTREGEXP = $DB->sql_regex(false);
@@ -1558,8 +1571,8 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
     $params = array();
     $i = 0;
 
-    //preprocess search terms to check whether we have at least 1 eligible search term
-    //if we do we can drop words around it like 'a'
+    // Preprocess search terms to check whether we have at least 1 eligible search term.
+    // If we do we can drop words around it like 'a'.
     $dropshortwords = false;
     foreach ($searchterms as $searchterm) {
         if (strlen($searchterm) >= 2) {
@@ -1570,13 +1583,12 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
     foreach ($searchterms as $searchterm) {
         $i++;
 
-        $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
+        $NOT = false; // Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle.
 
         if ($dropshortwords && strlen($searchterm) < 2) {
             continue;
         }
-    /// Under Oracle and MSSQL, trim the + and - operators and perform
-    /// simpler LIKE search
+        // Under Oracle and MSSQL, trim the + and - operators and perform simpler LIKE search.
         if (!$DB->sql_regex_supported()) {
             if (substr($searchterm, 0, 1) == '-') {
                 $NOT = true;
@@ -1609,16 +1621,16 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
         $searchcond = implode(" AND ", $searchcond);
     }
 
-    /// There are several possibilities
-    /// 1. courseid = SITEID : The admin is searching messages by all users
-    /// 2. courseid = ??     : A teacher is searching messages by users in
-    ///                        one of their courses - currently disabled
-    /// 3. courseid = none   : User is searching their own messages;
-    ///    a.  Messages from user
-    ///    b.  Messages to user
-    ///    c.  Messages to and from user
+    // There are several possibilities
+    // 1. courseid = SITEID : The admin is searching messages by all users
+    // 2. courseid = ??     : A teacher is searching messages by users in
+    //                        one of their courses - currently disabled
+    // 3. courseid = none   : User is searching their own messages;
+    //    a.  Messages from user
+    //    b.  Messages to user
+    //    c.  Messages to and from user
 
-    if ($courseid == SITEID) { /// admin is searching all messages
+    if ($courseid == SITEID) { // Admin is searching all messages.
         $m_read   = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
                                             FROM {message_read} m
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
@@ -1627,7 +1639,7 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
 
     } else if ($courseid !== 'none') {
-        /// This has not been implemented due to security concerns
+        // This has not been implemented due to security concerns.
         $m_read   = array();
         $m_unread = array();
 
@@ -1842,7 +1854,7 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
  * @param string $messagehistorylink the html for the message history link or false
  * @param bool $viewingnewmessages are we currently viewing new messages?
  */
-function message_print_message_history($user1,$user2,$search='',$messagelimit=0, $messagehistorylink=false, $viewingnewmessages=false) {
+function message_print_message_history($user1, $user2 ,$search = '', $messagelimit = 0, $messagehistorylink = false, $viewingnewmessages = false, $showactionlinks = true) {
     global $CFG, $OUTPUT;
 
     echo $OUTPUT->box_start('center');
@@ -1862,16 +1874,14 @@ function message_print_message_history($user1,$user2,$search='',$messagelimit=0,
     echo $OUTPUT->user_picture($user2, array('size' => 100, 'courseid' => SITEID));
     echo html_writer::tag('div', fullname($user2), array('class' => 'heading'));
 
-    if (isset($user2->iscontact) && isset($user2->isblocked)) {
-        $incontactlist = $user2->iscontact;
-        $isblocked = $user2->isblocked;
+    if ($showactionlinks && isset($user2->iscontact) && isset($user2->isblocked)) {
 
         $script = null;
         $text = true;
         $icon = false;
 
-        $strcontact = message_get_contact_add_remove_link($incontactlist, $isblocked, $user2, $script, $text, $icon);
-        $strblock   = message_get_contact_block_link($incontactlist, $isblocked, $user2, $script, $text, $icon);
+        $strcontact = message_get_contact_add_remove_link($user2->iscontact, $user2->isblocked, $user2, $script, $text, $icon);
+        $strblock   = message_get_contact_block_link($user2->iscontact, $user2->isblocked, $user2, $script, $text, $icon);
         $useractionlinks = $strcontact.'&nbsp;|'.$strblock;
 
         echo html_writer::tag('div', $useractionlinks, array('class' => 'useractionlinks'));
@@ -2079,7 +2089,7 @@ function message_print_contactlist_user($contact, $incontactlist = true, $isbloc
         $linkclass = 'messageselecteduser';
     }
 
-    /// are there any unread messages for this contact?
+    // Are there any unread messages for this contact?
     if ($contact->messagecount > 0 ){
         $fullnamelink = '<strong>'.$fullnamelink.' ('.$contact->messagecount.')</strong>';
     }
index 37abe4d..9834769 100644 (file)
@@ -62,6 +62,8 @@ class core_message_external_testcase extends externallib_advanced_testcase {
         global $DB, $USER, $CFG;
 
         $this->resetAfterTest(true);
+        // Transactions used in tests, tell phpunit use alternative reset method.
+        $this->preventResetByRollback();
 
         // Turn off all message processors (so nothing is really sent)
         require_once($CFG->dirroot . '/message/lib.php');
index 02a8d39..105a9be 100644 (file)
@@ -140,7 +140,7 @@ if ($check_anonymously) {
         if ($item->hasvalue == 0) {
             continue;
         }
-        echo '<table width="100%" class="generalbox">';
+        echo '<table width="100%" class="generaltable">';
 
         //get the class of item-typ
         $itemobj = feedback_get_item_class($item->typ);
index dcf186f..9cc4463 100644 (file)
@@ -200,7 +200,7 @@ if ($courseitemfilter > 0) {
         if ($item->hasvalue == 0) {
             continue;
         }
-        echo '<table width="100%" class="generalbox">';
+        echo '<table width="100%" class="generaltable">';
         //get the class from item-typ
         $itemobj = feedback_get_item_class($item->typ);
         $itemnr++;
index 96c2f4c..598e9e0 100644 (file)
@@ -453,13 +453,24 @@ function feedback_get_recent_mod_activity(&$activities, &$index,
         $tmpactivity->sectionnum= $cm->sectionnum;
         $tmpactivity->timestamp = $feedbackitem->timemodified;
 
+        $tmpactivity->content = new stdClass();
         $tmpactivity->content->feedbackid = $feedbackitem->id;
         $tmpactivity->content->feedbackuserid = $feedbackitem->userid;
 
-        //TODO: add all necessary user fields, this is not enough for user_picture
-        $tmpactivity->user->userid   = $feedbackitem->userid;
+        $userfields = explode(',', user_picture::fields());
+        $tmpactivity->user = new stdClass();
+        foreach ($userfields as $userfield) {
+            if ($userfield == 'id') {
+                $tmpactivity->user->{$userfield} = $feedbackitem->userid; // aliased in SQL above
+            } else {
+                if (!empty($feedbackitem->{$userfield})) {
+                    $tmpactivity->user->{$userfield} = $feedbackitem->{$userfield};
+                } else {
+                    $tmpactivity->user->{$userfield} = null;
+                }
+            }
+        }
         $tmpactivity->user->fullname = fullname($feedbackitem, $viewfullnames);
-        $tmpactivity->user->picture  = $feedbackitem->picture;
 
         $activities[$index++] = $tmpactivity;
     }
@@ -500,7 +511,7 @@ function feedback_print_recent_mod_activity($activity, $courseid, $detail, $modn
     echo '</div>';
 
     echo '<div class="user">';
-    echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->userid}&amp;course=$courseid\">"
+    echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->id}&amp;course=$courseid\">"
          ."{$activity->user->fullname}</a> - ".userdate($activity->timestamp);
     echo '</div>';
 
index b15c371..5d56afb 100644 (file)
@@ -2951,7 +2951,7 @@ function forum_subscribed_users($course, $forum, $groupid=0, $context = null, $f
  */
 function forum_get_course_forum($courseid, $type) {
 // How to set up special 1-per-course forums
-    global $CFG, $DB, $OUTPUT;
+    global $CFG, $DB, $OUTPUT, $USER;
 
     if ($forums = $DB->get_records_select("forum", "course = ? AND type = ?", array($courseid, $type), "id ASC")) {
         // There should always only be ONE, but with the right combination of
@@ -2965,6 +2965,9 @@ function forum_get_course_forum($courseid, $type) {
     $forum = new stdClass();
     $forum->course = $courseid;
     $forum->type = "$type";
+    if (!empty($USER->htmleditor)) {
+        $forum->introformat = $USER->htmleditor;
+    }
     switch ($forum->type) {
         case "news":
             $forum->name  = get_string("namenews", "forum");
index 3b64818..083a65c 100644 (file)
@@ -5,7 +5,7 @@
 <div class="boxaligncenter">
 <form id="form" method="post" action="editcategories.php">
 <div>
-<table  class="generalbox" cellpadding="5">
+<table  class="generaltable" cellpadding="5">
 <tr valign="top">
     <td align="right"><label for="name"><?php echo get_string("name") ?>:</label></td>
     <td>
index 1c67b47..9e28d61 100644 (file)
@@ -205,7 +205,7 @@ if ( $action ) {
 ?>
 
 <form method="post" action="editcategories.php">
-<table width="40%" class="boxaligncenter generalbox" cellpadding="5">
+<table width="40%" class="boxaligncenter generaltable" cellpadding="5">
         <tr>
           <th style="width:90%" align="center">
           <?php p(get_string("categories","glossary")) ?></th>
index c1cd498..fdea4a3 100644 (file)
@@ -61,7 +61,7 @@ $yes = get_string("yes");
 $no  = get_string("no");
 
 echo '<form method="post" action="formats.php" id="form">';
-echo '<table width="90%" align="center" class="generalbox">';
+echo '<table width="90%" align="center" class="generaltable">';
 ?>
 <tr>
     <td colspan="3" align="center"><strong>
index 5ff51bf..ecdc293 100644 (file)
@@ -503,7 +503,7 @@ class qformat_default {
     }
 
 
-    function readquestion($lines) {
+    protected function readquestion($lines) {
     /// Given an array of lines known to define a question in
     /// this format, this function converts it into a question
     /// object suitable for processing and insertion into Moodle.
index 1fce2b4..46032a0 100644 (file)
@@ -458,12 +458,11 @@ if ($quiz_qbanktool) {
 echo '<div class="questionbankwindow ' . $bankclass . 'block">';
 echo '<div class="header"><div class="title"><h2>';
 echo get_string('questionbankcontents', 'quiz') .
-        ' <a href="' . $thispageurl->out(true, array('qbanktool' => '1')) .
-       '" id="showbankcmd">[' . get_string('show').
-       ']</a>
-       <a href="' . $thispageurl->out(true, array('qbanktool' => '0')) .
-       '" id="hidebankcmd">[' . get_string('hide').
-       ']</a>';
+       '&nbsp;[<a href="' . $thispageurl->out(true, array('qbanktool' => '1')) .
+       '" id="showbankcmd">' . get_string('show').
+       '</a><a href="' . $thispageurl->out(true, array('qbanktool' => '0')) .
+       '" id="hidebankcmd">' . get_string('hide').
+       '</a>]';
 echo '</h2></div></div><div class="content">';
 
 echo '<span id="questionbank"></span>';
index 6d8d193..a390e00 100644 (file)
@@ -319,9 +319,14 @@ but in terms of usability, as testing showed,
 http://docs.moodle.org/dev/Quiz_UI_redesign/usability_testing_of_August_2008/Issues#Question_bank_.2F_question_adding_controls_visibility
 it must be ensured that the question
 bank window's title is prominent enough*/
-#page-mod-quiz-edit .questionbankwindow div.header {background-color:#009;color:#fff;background-image:none;padding-top:0.2em;font-weight:bold;}
-#page-mod-quiz-edit .questionbankwindow div.header a{text-decoration:underline;color:#FFF;}
+#page-mod-quiz-edit .questionbankwindow.block div.header {background-color:#009;background-image:none;padding-top:0.2em;font-weight:bold;border:0 none;}
+#page-mod-quiz-edit .questionbankwindow.block div.header div.title h2 {color:#FFF;text-align: center;}
 #page-mod-quiz-edit .collapsed .container{display: none;}
+
+#page-mod-quiz-edit .questionbankwindow a#showbankcmd,
+#page-mod-quiz-edit .questionbankwindow a#hidebankcmd {color: #FFF;text-decoration:underline;}
+#page-mod-quiz-edit .questionbankwindow a#showbankcmd:hover,
+#page-mod-quiz-edit .questionbankwindow a#hidebankcmd:hover {color:#009;background-color:#fff;text-decoration:none;}
 #page-mod-quiz-edit .questionbankwindow #showbankcmd{display:none;}
 #page-mod-quiz-edit .collapsed #showbankcmd{display:inline;}
 #page-mod-quiz-edit .questionbankwindow #hidebankcmd{display:inline;}
index 2ba9c5b..6b7e0a3 100644 (file)
@@ -135,6 +135,12 @@ $attemptstr = '&amp;attempt=' . $attempt;
 
 $result = scorm_get_toc($USER, $scorm, $cm->id, TOCJSLINK, $currentorg, $scoid, $mode, $attempt, true, true);
 $sco = $result->sco;
+if ($scorm->lastattemptlock == 1 && $result->attemptleft == 0) {
+    echo $OUTPUT->header();
+    echo $OUTPUT->notification(get_string('exceededmaxattempts', 'scorm'));
+    echo $OUTPUT->footer();
+    exit;
+}
 
 if (($mode == 'browse') && ($scorm->hidebrowse == 1)) {
     $mode = 'normal';
index cbae4ee..f95eca4 100644 (file)
@@ -1490,7 +1490,7 @@ class page_wiki_map extends page_wiki {
 
         $table = new html_table();
         $table->head = array(get_string('contributions', 'wiki') . $OUTPUT->help_icon('contributions', 'wiki'));
-        $table->attributes['class'] = 'wiki_editor generalbox';
+        $table->attributes['class'] = 'wiki_editor generaltable';
         $table->data = array();
         $table->rowclasses = array();
 
@@ -1610,7 +1610,7 @@ class page_wiki_map extends page_wiki {
 
         $table = new html_table();
         $table->head = array(get_string('pageindex', 'wiki') . $OUTPUT->help_icon('pageindex', 'wiki'));
-        $table->attributes['class'] = 'wiki_editor generalbox';
+        $table->attributes['class'] = 'wiki_editor generaltable';
         $table->data[] = array($this->render_navigation_node($tree));
 
         echo html_writer::table($table);
@@ -1649,7 +1649,7 @@ class page_wiki_map extends page_wiki {
 
         $table = new html_table();
         $table->head = array(get_string('pagelist', 'wiki') . $OUTPUT->help_icon('pagelist', 'wiki'));
-        $table->attributes['class'] = 'wiki_editor generalbox';
+        $table->attributes['class'] = 'wiki_editor generaltable';
         $table->align = array('center');
         foreach ($stdaux as $key => $elem) {
             $table->data[] = array($key);
@@ -1679,7 +1679,7 @@ class page_wiki_map extends page_wiki {
 
         $table = new html_table();
         $table->head = array(get_string('orphaned', 'wiki') . $OUTPUT->help_icon('orphaned', 'wiki'));
-        $table->attributes['class'] = 'wiki_editor generalbox';
+        $table->attributes['class'] = 'wiki_editor generaltable';
         $table->data = array();
         $table->rowclasses = array();
 
@@ -1715,7 +1715,7 @@ class page_wiki_map extends page_wiki {
 
         $table = new html_table();
         $table->head = array(get_string('updatedpages', 'wiki') . $OUTPUT->help_icon('updatedpages', 'wiki'));
-        $table->attributes['class'] = 'wiki_editor generalbox';
+        $table->attributes['class'] = 'wiki_editor generaltable';
         $table->data = array();
         $table->rowclasses = array();
 
index 6b9edda..744456c 100644 (file)
@@ -87,7 +87,7 @@ class qformat_blackboard_six_qti extends qformat_blackboard_six_base {
                     $this->process_essay($question, $questions);
                     break;
                 default:
-                    $this->error(get_string('unknownorunhandledtype', 'qformat_blackboard_six', $question->qtype));
+                    $this->error(get_string('unknownorunhandledtype', 'question', $question->qtype));
                     break;
             }
         }
index c7c4746..c7c925e 100644 (file)
@@ -31,4 +31,3 @@ $string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' becau
 $string['pluginname'] = 'Blackboard V6+';
 $string['pluginname_help'] = 'Blackboard V6+ format enables questions saved in all Blackboard export formats to be imported via a dat or zip file. For zip files, images import is supported.';
 $string['unhandledpresblock'] = 'Unhandled presentation block';
-$string['unknownorunhandledtype'] = 'Unknown or unhandled question type: {$a}';
index 2155401..95f4e1c 100644 (file)
@@ -184,6 +184,7 @@ class qformat_examview extends qformat_based_on_xml {
     }
 
     public function readquestion($qrec) {
+        global $OUTPUT;
 
         $type = trim($qrec['@']['type']);
         $question = $this->defaultquestion();
@@ -224,7 +225,7 @@ class qformat_examview extends qformat_based_on_xml {
                 break;
                 break;
             default:
-                print("<p>Question type ".$type." import not supported for ".$question->questiontext."<p>");
+                echo $OUTPUT->notification(get_string('unknownorunhandledtype', 'question', $type));
                 $question = null;
         }
 
index 873da65..8c36fc1 100644 (file)
@@ -67,6 +67,8 @@ class qformat_learnwise extends qformat_default {
     }
 
     protected function readquestion($lines) {
+        global $OUTPUT;
+
         $text = implode(' ', $lines);
         $text = str_replace(array('\t','\n','\r'), array('','',''), $text);
 
@@ -131,7 +133,7 @@ class qformat_learnwise extends qformat_default {
             }
 
         } else {
-            echo "<p>I don't understand this question type (type = <strong>$type</strong>).</p>\n";
+            echo $OUTPUT->notification(get_string('unknownorunhandledtype', 'question', $type));
         }
 
         $question = $this->defaultquestion();
index c79998d..e92fc54 100644 (file)
@@ -52,11 +52,11 @@ defined('MOODLE_INTERNAL') || die();
  */
 class qformat_missingword extends qformat_default {
 
-    function provide_import() {
+    public function provide_import() {
       return true;
     }
 
-    function readquestion($lines) {
+    public function readquestion($lines) {
     /// Given an array of lines known to define a question in
     /// this format, this function converts it into a question
     /// object suitable for processing and insertion into Moodle.
@@ -70,28 +70,23 @@ class qformat_missingword extends qformat_default {
 
         $answerstart = strpos($text, "{");
         if ($answerstart === false) {
-            if ($this->displayerrors) {
-                echo "<p>$text<p>Could not find a {";
-            }
+            $this->error(get_string('beginanswernotfound', 'qformat_missingword'), $text);
             return false;
         }
 
         $answerfinish = strpos($text, "}");
         if ($answerfinish === false) {
-            if ($this->displayerrors) {
-                echo "<p>$text<p>Could not find a }";
-            }
+            $this->error(get_string('endanswernotfound', 'qformat_missingword'), $text);
             return false;
         }
 
         $answerlength = $answerfinish - $answerstart;
         $answertext = substr($text, $answerstart + 1, $answerlength - 1);
 
-        /// Save the new question text
+        // Save the new question text.
         $question->questiontext = substr_replace($text, "_____", $answerstart, $answerlength+1);
         $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
 
-
         /// Parse the answers
         $answertext = str_replace("=", "~=", $answertext);
         $answers = explode("~", $answertext);
@@ -105,10 +100,8 @@ class qformat_missingword extends qformat_default {
         $countanswers = count($answers);
 
         switch ($countanswers) {
-            case 0:  // invalid question
-                if ($this->displayerrors) {
-                    echo "<p>No answers found in $answertext";
-                }
+            case 0:  // Invalid question.
+                $this->error(get_string('noanswerfound', 'qformat_missingword'), $answertext);
                 return false;
 
             case 1:
@@ -120,12 +113,14 @@ class qformat_missingword extends qformat_default {
                 }
                 $question->answer[]   = $answer;
                 $question->fraction[] = 1;
-                $question->feedback[] = "";
+                $question->feedback[] = array('text' => '', 'format' => FORMAT_HTML);
 
                 return $question;
 
             default:
                 $question->qtype = 'multichoice';
+                $question = $this->add_blank_combined_feedback($question);
+                $question->single = 1; // Only one answer allowed.
 
                 foreach ($answers as $key => $answer) {
                     $answer = trim($answer);
@@ -166,8 +161,8 @@ class qformat_missingword extends qformat_default {
 #                       $question->fraction[$key] = 0;
                         $question->fraction[$key] = $answeight;
                     }
-                    $question->answer[$key]   = $answer;
-                    $question->feedback[$key] = $comment;
+                    $question->answer[$key]   = array('text' => $answer, 'format' => FORMAT_HTML);
+                    $question->feedback[$key] = array('text' => $comment, 'format' => FORMAT_HTML);
                 }
 
                 return $question;
index 0e190a3..e1fd498 100644 (file)
@@ -26,3 +26,6 @@
 $string['pluginname'] = 'Missing word format';
 $string['pluginname_help'] = 'Missing word format enables questions to be imported via text file.';
 $string['pluginname_link'] = 'Missing word format';
+$string['beginanswernotfound'] = 'Could not find a required "{" character in imported file content.';
+$string['endanswernotfound'] = 'Could not find a required "}" character in imported file content.';
+$string['noanswerfound'] = 'No answers found in question';
diff --git a/question/format/missingword/tests/fixtures/question.missingword1.txt b/question/format/missingword/tests/fixtures/question.missingword1.txt
new file mode 100644 (file)
index 0000000..0580c40
--- /dev/null
@@ -0,0 +1,3 @@
+As soon as we begin to explore our body parts as infants
+we become students of {=anatomy and physiology ~reflexology
+~science ~experiment}, and in a sense we remain students for life.
diff --git a/question/format/missingword/tests/fixtures/question.missingword2.txt b/question/format/missingword/tests/fixtures/question.missingword2.txt
new file mode 100644 (file)
index 0000000..77b58de
--- /dev/null
@@ -0,0 +1,2 @@
+You can use the missing word format to import questions
+into both Moodle's Question bank and {=Lesson} activity.
diff --git a/question/format/missingword/tests/fixtures/question.missingword3.txt b/question/format/missingword/tests/fixtures/question.missingword3.txt
new file mode 100644 (file)
index 0000000..e202f82
--- /dev/null
@@ -0,0 +1,2 @@
+This is {=the best answer#comment on the best answer ~75%a good
+answer#comment on the good answer ~a wrong one#comment on the bad answer}
index a8c9a97..256db70 100644 (file)
@@ -93,7 +93,7 @@ class qformat_xhtml extends qformat_default {
             }
             $expout .= "</ul>\n";
             break;
-        case SHORTANSWER:
+        case 'shortanswer':
             $expout .= html_writer::start_tag('ul', array('class' => 'shortanswer'));
             $expout .= html_writer::start_tag('li');
             $expout .= html_writer::label(get_string('answer'), 'quest_'.$id, false, array('class' => 'accesshide'));
@@ -101,7 +101,7 @@ class qformat_xhtml extends qformat_default {
             $expout .= html_writer::end_tag('li');
             $expout .= html_writer::end_tag('ul');
             break;
-        case NUMERICAL:
+        case 'numerical':
             $expout .= html_writer::start_tag('ul', array('class' => 'numerical'));
             $expout .= html_writer::start_tag('li');
             $expout .= html_writer::label(get_string('answer'), 'quest_'.$id, false, array('class' => 'accesshide'));
@@ -109,7 +109,7 @@ class qformat_xhtml extends qformat_default {
             $expout .= html_writer::end_tag('li');
             $expout .= html_writer::end_tag('ul');
             break;
-        case MATCH:
+        case 'match':
             $expout .= html_writer::start_tag('ul', array('class' => 'match'));
 
             // build answer list
@@ -140,11 +140,9 @@ class qformat_xhtml extends qformat_default {
             break;
         case 'description':
             break;
-        case 'multichoice':
-            $expout .= "<!-- CLOZE type is not supported  -->\n";
-            break;
+        case 'multianswer':
         default:
-            echo $OUTPUT->notification("No handler for qtype $question->qtype for GIFT export" );
+            $expout .= "<!-- export of $question->qtype type is not supported  -->\n";
         }
         // close off div
         $expout .= "</div>\n\n\n";
index da8ad92..f9f8872 100644 (file)
@@ -104,7 +104,7 @@ abstract class question_edit_form extends question_wizard_form {
         $this->context = context::instance_by_id($record->contextid);
 
         $this->editoroptions = array('subdirs' => 1, 'maxfiles' => EDITOR_UNLIMITED_FILES,
-                'context' => $this->context);
+                'context' => $this->context, 'collapsed' => 1);
         $this->fileoptions = array('subdirs' => 1, 'maxfiles' => -1, 'maxbytes' => -1);
 
         $this->category = $category;
@@ -186,7 +186,7 @@ abstract class question_edit_form extends question_wizard_form {
         $mform->addRule('name', null, 'required', null, 'client');
 
         $mform->addElement('editor', 'questiontext', get_string('questiontext', 'question'),
-                array('rows' => 15), $this->editoroptions);
+                array('rows' => 15), $this->get_non_collabsible_editor_options());
         $mform->setType('questiontext', PARAM_RAW);
 
         $mform->addElement('text', 'defaultmark', get_string('defaultmark', 'question'),
@@ -196,7 +196,7 @@ abstract class question_edit_form extends question_wizard_form {
         $mform->addRule('defaultmark', null, 'required', null, 'client');
 
         $mform->addElement('editor', 'generalfeedback', get_string('generalfeedback', 'question'),
-                array('rows' => 10), $this->editoroptions);
+                array('rows' => 10), $this->get_non_collabsible_editor_options());
         $mform->setType('generalfeedback', PARAM_RAW);
         $mform->addHelpButton('generalfeedback', 'generalfeedback', 'question');
 
@@ -673,4 +673,12 @@ abstract class question_edit_form extends question_wizard_form {
      *      in the question type class.
      */
     public abstract function qtype();
+
+    /**
+     * Returns an array of editor options with collapsed options turned off.
+     * @return array
+     */
+    protected function get_non_collabsible_editor_options() {
+        return array_merge($this->editoroptions, array('collapsed' => 0));
+    }
 }
index 9d7767b..7100df8 100644 (file)
@@ -157,7 +157,7 @@ foreach ($courses as $type => $infos) {
     if (!empty($infos)) {
 
         echo '<h1 align="center">'.get_string($type, 'report_completion').'</h1>';
-        echo '<table class="generalbox boxaligncenter">';
+        echo '<table class="generaltable boxaligncenter">';
         echo '<tr class="ccheader">';
         echo '<th class="c0 header" scope="col">'.get_string('course').'</th>';
         echo '<th class="c1 header" scope="col">'.get_string('requiredcriteria', 'completion').'</th>';