Merge branch 'install_master' of https://git.in.moodle.com/amosbot/moodle-install
authorDan Poltawski <dan@moodle.com>
Tue, 14 Oct 2014 17:00:44 +0000 (18:00 +0100)
committerDan Poltawski <dan@moodle.com>
Tue, 14 Oct 2014 17:00:44 +0000 (18:00 +0100)
30 files changed:
admin/cli/mysql_compressed_rows.php
blocks/badges/db/upgrade.php
blocks/calendar_month/db/upgrade.php
blocks/calendar_upcoming/db/upgrade.php
cache/stores/memcache/lib.php
cache/stores/memcache/tests/memcache_test.php
cache/tests/fixtures/stores.php
grade/import/csv/classes/load_data.php
grade/import/csv/tests/load_data_test.php
grade/import/direct/index.php
grade/tests/behat/grade_natural_normalisation.feature
lib/blocklib.php
lib/csvlib.class.php
lib/db/upgrade.php
lib/editor/atto/autosave-ajax.php
lib/editor/atto/lang/en/editor_atto.php
lib/editor/atto/lib.php
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/autosave.js
lib/grade/grade_category.php
mod/quiz/classes/output/edit_renderer.php
mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank-debug.js
mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank-min.js
mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank.js
mod/quiz/yui/src/quizquestionbank/js/quizquestionbank.js
my/tests/behat/add_blocks.feature
user/tests/behat/table_sorting.feature
version.php

index 92aa9db..95af47d 100644 (file)
@@ -52,7 +52,7 @@ $help =
 
 By default InnoDB storage table is using legacy Antelope file format
 which has major restriction on database row size.
-Use this script to detect and fix database tables with potentail data
+Use this script to detect and fix database tables with potential data
 overflow problems.
 
 Options:
index 3be12fd..3b3ec4d 100644 (file)
@@ -49,20 +49,25 @@ function xmldb_block_badges_upgrade($oldversion, $block) {
         // Add this block the default blocks on /my.
         $blockname = 'badges';
 
-        $page = new moodle_page();
-        $page->set_context(context_system::instance());
+        // Do not try to add the block if we cannot find the default my_pages entry.
+        // Private => 1 refers to MY_PAGE_PRIVATE.
+        if ($systempage = $DB->get_record('my_pages', array('userid' => null, 'private' => 1))) {
+            $page = new moodle_page();
+            $page->set_context(context_system::instance());
 
-        // Check to see if this block is already on the default /my page.
-        $criteria = array(
-            'blockname' => $blockname,
-            'parentcontextid' => $page->context->id,
-            'pagetypepattern' => 'my-index'
-        );
+            // Check to see if this block is already on the default /my page.
+            $criteria = array(
+                'blockname' => $blockname,
+                'parentcontextid' => $page->context->id,
+                'pagetypepattern' => 'my-index',
+                'subpagepattern' => $systempage->id,
+            );
 
-        if (!$DB->record_exists('block_instances', $criteria)) {
-            // Add the block to the default /my.
-            $page->blocks->add_region(BLOCK_POS_RIGHT);
-            $page->blocks->add_block($blockname, BLOCK_POS_RIGHT, 0, false, 'my-index');
+            if (!$DB->record_exists('block_instances', $criteria)) {
+                // Add the block to the default /my.
+                $page->blocks->add_region(BLOCK_POS_RIGHT);
+                $page->blocks->add_block($blockname, BLOCK_POS_RIGHT, 0, false, 'my-index', $systempage->id);
+            }
         }
 
         upgrade_block_savepoint(true, 2014062600, $blockname);
index d4ae9b1..a03a0e1 100644 (file)
@@ -49,20 +49,25 @@ function xmldb_block_calendar_month_upgrade($oldversion, $block) {
         // Add this block the default blocks on /my.
         $blockname = 'calendar_month';
 
-        $page = new moodle_page();
-        $page->set_context(context_system::instance());
+        // Do not try to add the block if we cannot find the default my_pages entry.
+        // Private => 1 refers to MY_PAGE_PRIVATE.
+        if ($systempage = $DB->get_record('my_pages', array('userid' => null, 'private' => 1))) {
+            $page = new moodle_page();
+            $page->set_context(context_system::instance());
 
-        // Check to see if this block is already on the default /my page.
-        $criteria = array(
-            'blockname' => $blockname,
-            'parentcontextid' => $page->context->id,
-            'pagetypepattern' => 'my-index'
-        );
+            // Check to see if this block is already on the default /my page.
+            $criteria = array(
+                'blockname' => $blockname,
+                'parentcontextid' => $page->context->id,
+                'pagetypepattern' => 'my-index',
+                'subpagepattern' => $systempage->id,
+            );
 
-        if (!$DB->record_exists('block_instances', $criteria)) {
-            // Add the block to the default /my.
-            $page->blocks->add_region(BLOCK_POS_RIGHT);
-            $page->blocks->add_block($blockname, BLOCK_POS_RIGHT, 0, false, 'my-index');
+            if (!$DB->record_exists('block_instances', $criteria)) {
+                // Add the block to the default /my.
+                $page->blocks->add_region(BLOCK_POS_RIGHT);
+                $page->blocks->add_block($blockname, BLOCK_POS_RIGHT, 0, false, 'my-index', $systempage->id);
+            }
         }
 
         upgrade_block_savepoint(true, 2014062600, $blockname);
index 947d37c..ecce6e4 100644 (file)
@@ -49,20 +49,25 @@ function xmldb_block_calendar_upcoming_upgrade($oldversion, $block) {
         // Add this block the default blocks on /my.
         $blockname = 'calendar_upcoming';
 
-        $page = new moodle_page();
-        $page->set_context(context_system::instance());
+        // Do not try to add the block if we cannot find the default my_pages entry.
+        // Private => 1 refers to MY_PAGE_PRIVATE.
+        if ($systempage = $DB->get_record('my_pages', array('userid' => null, 'private' => 1))) {
+            $page = new moodle_page();
+            $page->set_context(context_system::instance());
 
-        // Check to see if this block is already on the default /my page.
-        $criteria = array(
-            'blockname' => $blockname,
-            'parentcontextid' => $page->context->id,
-            'pagetypepattern' => 'my-index'
-        );
+            // Check to see if this block is already on the default /my page.
+            $criteria = array(
+                'blockname' => $blockname,
+                'parentcontextid' => $page->context->id,
+                'pagetypepattern' => 'my-index',
+                'subpagepattern' => $systempage->id,
+            );
 
-        if (!$DB->record_exists('block_instances', $criteria)) {
-            // Add the block to the default /my.
-            $page->blocks->add_region(BLOCK_POS_RIGHT);
-            $page->blocks->add_block($blockname, BLOCK_POS_RIGHT, 0, false, 'my-index');
+            if (!$DB->record_exists('block_instances', $criteria)) {
+                // Add the block to the default /my.
+                $page->blocks->add_region(BLOCK_POS_RIGHT);
+                $page->blocks->add_block($blockname, BLOCK_POS_RIGHT, 0, false, 'my-index', $systempage->id);
+            }
         }
 
         upgrade_block_savepoint(true, 2014062600, $blockname);
index 4cedf01..9179ee5 100644 (file)
@@ -105,6 +105,12 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      */
     protected $setconnections = array();
 
+    /**
+     * If true data going in and out will be encoded.
+     * @var bool
+     */
+    protected $encode = true;
+
     /**
      * Default prefix for key names.
      * @var string
@@ -202,6 +208,24 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
         }
         $this->definition = $definition;
         $this->isinitialised = true;
+        $this->encode = self::require_encoding();
+    }
+
+    /**
+     * Tests if encoding is going to be required.
+     *
+     * Prior to memcache 3.0.3 scalar data types were not preserved.
+     * For earlier versions of the memcache extension we need to encode and decode scalar types
+     * to ensure that it is preserved.
+     *
+     * @param string $version The version to check, if null it is fetched from PHP.
+     * @return bool
+     */
+    public static function require_encoding($version = null) {
+        if (!$version) {
+            $version = phpversion('memcache');
+        }
+        return (version_compare($version, '3.0.3', '<'));
     }
 
     /**
@@ -292,7 +316,11 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      * @return mixed The data that was associated with the key, or false if the key did not exist.
      */
     public function get($key) {
-        return $this->connection->get($this->parse_key($key));
+        $result = $this->connection->get($this->parse_key($key));
+        if ($this->encode && $result !== false) {
+            return @unserialize($result);
+        }
+        return $result;
     }
 
     /**
@@ -319,6 +347,9 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
                 $return[$key] = false;
             } else {
                 $return[$key] = $result[$mkey];
+                if ($this->encode && $return[$key] !== false) {
+                    $return[$key] = @unserialize($return[$key]);
+                }
             }
         }
         return $return;
@@ -332,6 +363,11 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      * @return bool True if the operation was a success false otherwise.
      */
     public function set($key, $data) {
+        if ($this->encode) {
+            // We must serialise this data.
+            $data = serialize($data);
+        }
+
         if ($this->clustered) {
             $status = true;
             foreach ($this->setconnections as $connection) {
index 63d366c..0cba975 100644 (file)
@@ -264,4 +264,30 @@ class cachestore_memcache_test extends cachestore_tests {
             }
         }
     }
+
+    /**
+     * Test our checks for encoding.
+     */
+    public function test_require_encoding() {
+        $this->assertTrue(cachestore_memcache::require_encoding('dev'));
+        $this->assertTrue(cachestore_memcache::require_encoding('1.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('1.0.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('2.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('2.0.8'));
+        $this->assertTrue(cachestore_memcache::require_encoding('2.2.8'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0-dev'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.1'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.2-dev'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.2'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.3-dev'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.3'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.4'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.4-dev'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.8'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.1.0'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.1.2'));
+
+    }
 }
index ee5f373..8d4f11c 100644 (file)
@@ -86,19 +86,39 @@ abstract class cachestore_tests extends advanced_testcase {
      */
     public function run_tests(cache_store $instance) {
 
-        // Test set.
+        // Test set with a string.
         $this->assertTrue($instance->set('test1', 'test1'));
         $this->assertTrue($instance->set('test2', 'test2'));
+        $this->assertTrue($instance->set('test3', '3'));
 
-        // Test get.
-        $this->assertEquals('test1', $instance->get('test1'));
-        $this->assertEquals('test2', $instance->get('test2'));
+        // Test get with a string.
+        $this->assertSame('test1', $instance->get('test1'));
+        $this->assertSame('test2', $instance->get('test2'));
+        $this->assertSame('3', $instance->get('test3'));
+
+        // Test set with an int.
+        $this->assertTrue($instance->set('test1', 1));
+        $this->assertTrue($instance->set('test2', 2));
+
+        // Test get with an int.
+        $this->assertSame(1, $instance->get('test1'));
+        $this->assertInternalType('int', $instance->get('test1'));
+        $this->assertSame(2, $instance->get('test2'));
+        $this->assertInternalType('int', $instance->get('test2'));
+
+        // Test set with a bool.
+        $this->assertTrue($instance->set('test1', true));
+
+        // Test get with an bool.
+        $this->assertSame(true, $instance->get('test1'));
+        $this->assertInternalType('boolean', $instance->get('test1'));
 
         // Test delete.
         $this->assertTrue($instance->delete('test1'));
+        $this->assertTrue($instance->delete('test3'));
         $this->assertFalse($instance->delete('test3'));
         $this->assertFalse($instance->get('test1'));
-        $this->assertEquals('test2', $instance->get('test2'));
+        $this->assertSame(2, $instance->get('test2'));
         $this->assertTrue($instance->set('test1', 'test1'));
 
         // Test purge.
@@ -114,16 +134,16 @@ abstract class cachestore_tests extends advanced_testcase {
             array('key' => 'many4', 'value' => 'many4'),
             array('key' => 'many5', 'value' => 'many5')
         ));
-        $this->assertEquals(5, $outcome);
-        $this->assertEquals('many1', $instance->get('many1'));
-        $this->assertEquals('many5', $instance->get('many5'));
+        $this->assertSame(5, $outcome);
+        $this->assertSame('many1', $instance->get('many1'));
+        $this->assertSame('many5', $instance->get('many5'));
         $this->assertFalse($instance->get('many6'));
 
         // Test get_many.
         $result = $instance->get_many(array('many1', 'many3', 'many5', 'many6'));
         $this->assertInternalType('array', $result);
         $this->assertCount(4, $result);
-        $this->assertEquals(array(
+        $this->assertSame(array(
             'many1' => 'many1',
             'many3' => 'many3',
             'many5' => 'many5',
@@ -131,7 +151,7 @@ abstract class cachestore_tests extends advanced_testcase {
         ), $result);
 
         // Test delete_many.
-        $this->assertEquals(3, $instance->delete_many(array('many2', 'many3', 'many4')));
-        $this->assertEquals(2, $instance->delete_many(array('many1', 'many5', 'many6')));
+        $this->assertSame(3, $instance->delete_many(array('many2', 'many3', 'many4')));
+        $this->assertSame(2, $instance->delete_many(array('many1', 'many5', 'many6')));
     }
 }
\ No newline at end of file
index 3cbb069..21477b9 100644 (file)
@@ -77,17 +77,21 @@ class gradeimport_csv_load_data {
         $csvimport->load_csv_content($text, $encoding, $separator);
         $this->error = $csvimport->get_error();
 
-        // Get header (field names).
-        $this->headers = $csvimport->get_columns();
-        $this->trim_headers();
+        // If there are no import errors then proceed.
+        if (empty($this->error)) {
 
-        $csvimport->init();
-        $this->previewdata = array();
+            // Get header (field names).
+            $this->headers = $csvimport->get_columns();
+            $this->trim_headers();
 
-        for ($numlines = 0; $numlines <= $previewrows; $numlines++) {
-            $lines = $csvimport->next();
-            if ($lines) {
-                $this->previewdata[] = $lines;
+            $csvimport->init();
+            $this->previewdata = array();
+
+            for ($numlines = 0; $numlines <= $previewrows; $numlines++) {
+                $lines = $csvimport->next();
+                if ($lines) {
+                    $this->previewdata[] = $lines;
+                }
             }
         }
     }
index 790f889..1d57c7d 100644 (file)
@@ -59,6 +59,10 @@ Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,75.00';
     /** @var array $columns The first row of the csv file. These are the columns of the import file.*/
     protected $columns;
 
+    public function tearDown() {
+        $this->csvimport = null;
+    }
+
     /**
      * Load up the above text through the csv import.
      *
index 1a9fc67..d1b6a4b 100644 (file)
@@ -69,7 +69,7 @@ if (!$iid) {
         $csvimport->load_csv_content($text, $formdata->encoding, 'tab', $formdata->previewrows);
         $csvimporterror = $csvimport->get_error();
         if (!empty($csvimporterror)) {
-            echo $renderer->errors($csvimport->get_error());
+            echo $renderer->errors(array($csvimport->get_error()));
             echo $OUTPUT->footer();
             die();
         }
index 5512a3f..a2d50cb 100644 (file)
@@ -250,3 +250,18 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
   Then the field "Weight of Test assignment five" matches value "80.0"
   And the field "Weight of Test assignment six" matches value "40.0"
   And the field "Weight of Test assignment seven" matches value "60.0"
+
+  @javascript
+  Scenario: Overriding a grade item with a negative value results in the value being changed to zero.
+
+  When I set the field "Override weight of Test assignment five" to "1"
+  And I set the field "Weight of Test assignment five" to "-15"
+  And I press "Save changes"
+  Then the field "Weight of Test assignment five" matches value "0.0"
+  And the field "Weight of Test assignment six" matches value "40.0"
+  And the field "Weight of Test assignment seven" matches value "60.0"
+  And I set the field "Override weight of Test assignment six" to "1"
+  And I set the field "Weight of Test assignment six" to "-25"
+  And I press "Save changes"
+  Then the field "Weight of Test assignment six" matches value "0.0"
+  And the field "Weight of Test assignment seven" matches value "100.0"
index 9c9dc65..f8d12bf 100644 (file)
@@ -2178,7 +2178,13 @@ function blocks_add_default_system_blocks() {
     $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('navigation', 'settings')), '*', null, true);
     $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2);
 
+    if ($defaultmypage = $DB->get_record('my_pages', array('userid' => null, 'name' => '__default', 'private' => 1))) {
+        $subpagepattern = $defaultmypage->id;
+    } else {
+        $subpagepattern = null;
+    }
+
     $newblocks = array('private_files', 'online_users', 'badges', 'calendar_month', 'calendar_upcoming');
     $newcontent = array('course_overview');
-    $page->blocks->add_blocks(array(BLOCK_POS_RIGHT => $newblocks, 'content' => $newcontent), 'my-index');
+    $page->blocks->add_blocks(array(BLOCK_POS_RIGHT => $newblocks, 'content' => $newcontent), 'my-index', $subpagepattern);
 }
index 229d568..f159d5a 100644 (file)
@@ -35,26 +35,31 @@ defined('MOODLE_INTERNAL') || die();
  * @package   moodlecore
  */
 class csv_import_reader {
+
     /**
      * @var int import identifier
      */
-    var $_iid;
+    private $_iid;
+
     /**
      * @var string which script imports?
      */
-    var $_type;
+    private $_type;
+
     /**
      * @var string|null Null if ok, error msg otherwise
      */
-    var $_error;
+    private $_error;
+
     /**
      * @var array cached columns
      */
-    var $_columns;
+    private $_columns;
+
     /**
      * @var object file handle used during import
      */
-    var $_fp;
+    private $_fp;
 
     /**
      * Contructor
@@ -62,24 +67,29 @@ class csv_import_reader {
      * @param int $iid import identifier
      * @param string $type which script imports?
      */
-    function csv_import_reader($iid, $type) {
+    public function __construct($iid, $type) {
         $this->_iid  = $iid;
         $this->_type = $type;
     }
 
+    /**
+     * Make sure the file is closed when this object is discarded.
+     */
+    public function __destruct() {
+        $this->close();
+    }
+
     /**
      * Parse this content
      *
-     * @global object
-     * @global object
-     * @param string $content passed by ref for memory reasons, unset after return
+     * @param string $content the content to parse.
      * @param string $encoding content encoding
      * @param string $delimiter_name separator (comma, semicolon, colon, cfg)
      * @param string $column_validation name of function for columns validation, must have one param $columns
      * @param string $enclosure field wrapper. One character only.
      * @return bool false if error, count of data lines if ok; use get_error() to get error string
      */
-    function load_csv_content(&$content, $encoding, $delimiter_name, $column_validation=null, $enclosure='"') {
+    public function load_csv_content($content, $encoding, $delimiter_name, $column_validation=null, $enclosure='"') {
         global $USER, $CFG;
 
         $this->close();
@@ -182,7 +192,7 @@ class csv_import_reader {
      *
      * @return array
      */
-    function get_columns() {
+    public function get_columns() {
         if (isset($this->_columns)) {
             return $this->_columns;
         }
@@ -210,7 +220,7 @@ class csv_import_reader {
      * @global object
      * @return bool Success
      */
-    function init() {
+    public function init() {
         global $CFG, $USER;
 
         if (!empty($this->_fp)) {
@@ -232,7 +242,7 @@ class csv_import_reader {
      *
      * @return mixed false, or an array of values
      */
-    function next() {
+    public function next() {
         if (empty($this->_fp) or feof($this->_fp)) {
             return false;
         }
@@ -248,7 +258,7 @@ class csv_import_reader {
      *
      * @return void
      */
-    function close() {
+    public function close() {
         if (!empty($this->_fp)) {
             fclose($this->_fp);
             $this->_fp = null;
@@ -260,7 +270,7 @@ class csv_import_reader {
      *
      * @return string error text of null if none
      */
-    function get_error() {
+    public function get_error() {
         return $this->_error;
     }
 
@@ -271,7 +281,7 @@ class csv_import_reader {
      * @global object
      * @param boolean $full true means do a full cleanup - all sessions for current user, false only the active iid
      */
-    function cleanup($full=false) {
+    public function cleanup($full=false) {
         global $USER, $CFG;
 
         if ($full) {
@@ -286,7 +296,7 @@ class csv_import_reader {
      *
      * @return array suitable for selection box
      */
-    static function get_delimiter_list() {
+    public static function get_delimiter_list() {
         global $CFG;
         $delimiters = array('comma'=>',', 'semicolon'=>';', 'colon'=>':', 'tab'=>'\\t');
         if (isset($CFG->CSV_DELIMITER) and strlen($CFG->CSV_DELIMITER) === 1 and !in_array($CFG->CSV_DELIMITER, $delimiters)) {
@@ -301,7 +311,7 @@ class csv_import_reader {
      * @param string separator name
      * @return string delimiter char
      */
-    static function get_delimiter($delimiter_name) {
+    public static function get_delimiter($delimiter_name) {
         global $CFG;
         switch ($delimiter_name) {
             case 'colon':     return ':';
@@ -320,7 +330,7 @@ class csv_import_reader {
      * @param string separator name
      * @return string encoded delimiter char
      */
-    static function get_encoded_delimiter($delimiter_name) {
+    public static function get_encoded_delimiter($delimiter_name) {
         global $CFG;
         if ($delimiter_name == 'cfg' and isset($CFG->CSV_ENCODE)) {
             return $CFG->CSV_ENCODE;
@@ -336,7 +346,7 @@ class csv_import_reader {
      * @param string who imports?
      * @return int iid
      */
-    static function get_new_iid($type) {
+    public static function get_new_iid($type) {
         global $USER;
 
         $filename = make_temp_directory('csvimport/'.$type.'/'.$USER->id);
@@ -351,6 +361,7 @@ class csv_import_reader {
     }
 }
 
+
 /**
  * Utitily class for exporting of CSV files.
  * @copyright 2012 Adrian Greeve
index 7f8cbc7..ec35ffa 100644 (file)
@@ -3980,5 +3980,43 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2014100800.00);
     }
 
+    if ($oldversion < 2014101001.00) {
+        // Some blocks added themselves to the my/ home page, but they did not declare the
+        // subpage of the default my home page. While the upgrade script has been fixed, this
+        // upgrade script will fix the data that was wrongly added.
+
+        // We only proceed if we can find the right entry from my_pages. Private => 1 refers to
+        // the constant value MY_PAGE_PRIVATE.
+        if ($systempage = $DB->get_record('my_pages', array('userid' => null, 'private' => 1))) {
+
+            // Select the blocks there could have been automatically added. showinsubcontexts is hardcoded to 0
+            // because it is possible for administrators to have forced it on the my/ page by adding it to the
+            // system directly rather than updating the default my/ page.
+            $blocks = array('course_overview', 'private_files', 'online_users', 'badges', 'calendar_month', 'calendar_upcoming');
+            list($blocksql, $blockparams) = $DB->get_in_or_equal($blocks, SQL_PARAMS_NAMED);
+            $select = "parentcontextid = :contextid
+                    AND pagetypepattern = :page
+                    AND showinsubcontexts = 0
+                    AND subpagepattern IS NULL
+                    AND blockname $blocksql";
+            $params = array(
+                'contextid' => context_system::instance()->id,
+                'page' => 'my-index'
+            );
+            $params = array_merge($params, $blockparams);
+
+            $DB->set_field_select(
+                'block_instances',
+                'subpagepattern',
+                $systempage->id,
+                $select,
+                $params
+            );
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2014101001.00);
+    }
+
     return true;
 }
index 36dcc06..fa45fd4 100644 (file)
@@ -45,6 +45,8 @@ require_sesskey();
 
 $action = required_param('action', PARAM_ALPHA);
 
+$response = array();
+
 if ($action === 'save') {
     $drafttext = required_param('drafttext', PARAM_RAW);
     $params = array('elementid' => $elementid,
@@ -138,7 +140,8 @@ if ($action === 'save') {
 
         // A response means the draft has been restored and here is the auto-saved text.
         if (!$stale) {
-            echo $record->drafttext;
+            $response['result'] = $record->drafttext;
+            echo json_encode($response);
         }
         die();
     }
index d1c2b68..ebbca5f 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 $string['autosavefailed'] = 'Could not connect to the server. If you submit this page now, your changes may be lost.';
-$string['autosavefrequency'] = 'Autosave frequency (seconds).';
+$string['autosavefrequency'] = 'Autosave frequency';
 $string['autosavefrequency_desc'] = 'This is the number of seconds between auto save attempts. Atto will automatically save the text in the editor according to this setting, so that text can be automatically restored when the same user returns to the same form.';
 $string['autosavesucceeded'] = 'Draft saved.';
 $string['errorcannotparseline'] = 'The line \'{$a}\' is not in the correct format.';
@@ -31,6 +31,7 @@ $string['errorgroupisusedtwice'] = 'The group \'{$a}\' is defined twice; group n
 $string['errornopluginsorgroupsfound'] = 'No plugins or groups found; please add some groups and plugins.';
 $string['errorpluginnotfound'] = 'The plugin \'{$a}\' cannot be used; it does not appear to be installed.';
 $string['errorpluginisusedtwice'] = 'The plugin \'{$a}\' is used twice; plugins can only be defined once.';
+$string['errortextrecovery'] = 'Unfortunately the draft version could not be restored.';
 $string['pluginname'] = 'Atto HTML editor';
 $string['subplugintype_atto'] = 'Atto plugin';
 $string['subplugintype_atto_plural'] = 'Atto plugins';
index 00cd928..65caee5 100644 (file)
@@ -127,7 +127,8 @@ class atto_texteditor extends texteditor {
                 'plugin_title_shortcut',
                 'textrecovered',
                 'autosavefailed',
-                'autosavesucceeded'
+                'autosavesucceeded',
+                'errortextrecovery'
             ), 'editor_atto');
         $PAGE->requires->strings_for_js(array(
                 'warning',
index 6969164..2254cc0 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 5ce80c8..0a8ea93 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index d743822..8f3a664 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index 07598bc..ee2ec44 100644 (file)
@@ -145,10 +145,19 @@ EditorAutosave.prototype = {
                     if (typeof o.responseText !== "undefined" &&
                             o.responseText !== "" &&
                             o.responseText !== this.textarea.get('value')) {
-                        Y.log('Autosave text found - recover it.', 'debug', LOGNAME_AUTOSAVE);
-                        this.recoverText(o.responseText);
+                        response_json = JSON.parse(o.responseText);
+                        if (!response_json.error && response_json.result) {
+                            Y.log('Autosave text found - recover it.', 'debug', LOGNAME_AUTOSAVE);
+                            this.recoverText(response_json.result);
+                        } else {
+                            Y.log('Error occurred recovering draft text: ' + response_json.error, 'debug', LOGNAME_AUTOSAVE);
+                            this.showMessage(M.util.get_string('errortextrecovery', 'editor_atto'), NOTIFY_WARNING, RECOVER_MESSAGE_TIMEOUT);
+                        }
                         this._fireSelectionChanged();
                     }
+                },
+                failure: function() {
+                    this.showMessage(M.util.get_string('errortextrecovery', 'editor_atto'), NOTIFY_WARNING, RECOVER_MESSAGE_TIMEOUT);
                 }
             }
         });
index b70030c..32fd6f5 100644 (file)
@@ -1373,10 +1373,13 @@ class grade_category extends grade_object {
                             (1 - $totaloverriddenweight);
                 }
                 $gradeitem->update();
-            } else if ((!$automaticgradeitemspresent && $normalisetotal != 1) || ($requiresnormalising)) {
+            } else if ((!$automaticgradeitemspresent && $normalisetotal != 1) || ($requiresnormalising)
+                    || $overridearray[$gradeitem->id]['weight'] < 0) {
                 // Just divide the overriden weight for this item against the total weight override of all
                 // items in this category.
-                if ($normalisetotal == 0) {
+                if ($normalisetotal == 0 || $overridearray[$gradeitem->id]['weight'] < 0) {
+                    // If the normalised total equals zero, or the weight value is less than zero,
+                    // set the weight for the grade item to zero.
                     $gradeitem->aggregationcoef2 = 0;
                 } else {
                     $gradeitem->aggregationcoef2 = $overridearray[$gradeitem->id]['weight'] / $normalisetotal;
index a1c2606..33de44b 100644 (file)
@@ -877,22 +877,22 @@ class edit_renderer extends \plugin_renderer_base {
 
         // Require various strings for the command toolbox.
         $this->page->requires->strings_for_js(array(
-                'moveleft',
+                'clicktohideshow',
                 'deletechecktype',
                 'deletechecktypename',
                 'edittitle',
                 'edittitleinstructions',
-                'show',
+                'emptydragdropregion',
                 'hide',
-                'clicktochangeinbrackets',
-                'markthistopic',
                 'markedthistopic',
+                'markthistopic',
                 'move',
-                'movesection',
                 'movecontent',
+                'moveleft',
+                'movesection',
                 'selectall',
+                'show',
                 'tocontent',
-                'emptydragdropregion'
         ), 'moodle');
 
         $this->page->requires->strings_for_js(array(
index cf9daa2..132d92c 100644 (file)
Binary files a/mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank-debug.js and b/mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank-debug.js differ
index ad574e5..af57316 100644 (file)
Binary files a/mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank-min.js and b/mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank-min.js differ
index a176a6d..4d4e4eb 100644 (file)
Binary files a/mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank.js and b/mod/quiz/yui/build/moodle-mod_quiz-quizquestionbank/moodle-mod_quiz-quizquestionbank.js differ
index d21ee3c..4d3becc 100644 (file)
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-
 var CSS = {
-        QBANKLOADING: 'div.questionbankloading',
-        ADDQUESTIONLINKS: 'ul.menu a.questionbank',
-        ADDTOQUIZCONTAINER: 'td.addtoquizaction'
+        QBANKLOADING:       'div.questionbankloading',
+        ADDQUESTIONLINKS:   'ul.menu a.questionbank',
+        ADDTOQUIZCONTAINER: 'td.addtoquizaction',
+        PREVIEWCONTAINER:   'td.previewaction',
+        SEARCHOPTIONS:      '#advancedsearch'
 };
 
 var PARAMS = {
@@ -42,6 +43,7 @@ Y.extend(POPUP, Y.Base, {
     loadingDiv: '',
     dialogue: null,
     addonpage: 0,
+    searchRegionInitialised: false,
 
     create_dialogue: function() {
         // Create a dialogue on the page and hide it.
@@ -58,8 +60,7 @@ Y.extend(POPUP, Y.Base, {
             extraClasses: ['mod_quiz_qbank_dialogue']
         };
         this.dialogue = new M.core.dialogue(config);
-        this.dialogue.bodyNode.delegate('click', this.link_clicked,
-                '.paging a[href], thead tr a[href]', this);
+        this.dialogue.bodyNode.delegate('click', this.link_clicked, 'a[href]', this);
         this.dialogue.hide();
 
         this.loadingDiv = this.dialogue.bodyNode.getHTML();
@@ -89,6 +90,7 @@ Y.extend(POPUP, Y.Base, {
             hidden.set('value', this.addonpage);
         }
 
+        this.initialiseSearchRegion();
         this.dialogue.show();
     },
 
@@ -133,9 +135,9 @@ Y.extend(POPUP, Y.Base, {
         }
         M.question.qbankmanager.init();
 
-        if (Y.one('#advancedsearch')) {
-            M.util.init_collapsible_region(Y, "advancedsearch", "question_bank_advanced_search",
-                    M.util.get_string('clicktohideshow'));
+        this.searchRegionInitialised = false;
+        if (this.dialogue.get('visible')) {
+            this.initialiseSearchRegion();
         }
 
         this.dialogue.fire('widget:contentUpdate');
@@ -155,11 +157,29 @@ Y.extend(POPUP, Y.Base, {
     },
 
     link_clicked: function(e) {
+        // Add question to quiz. mofify the URL, then let it work as normal.
         if (e.currentTarget.ancestor(CSS.ADDTOQUIZCONTAINER)) {
-            // These links need to work like normal, after we modify the URL.
             e.currentTarget.set('href', e.currentTarget.get('href') + '&addonpage=' + this.addonpage);
             return;
         }
+
+        // Question preview. Needs to open in a pop-up.
+        if (e.currentTarget.ancestor(CSS.PREVIEWCONTAINER)) {
+            openpopup(e, {
+                url: e.currentTarget.get('href'),
+                name: 'questionpreview',
+                options: 'height=600,width=800,top=0,left=0,menubar=0,location=0,scrollbars,resizable,toolbar,status,directories=0,fullscreen=0,dependent'
+            });
+            return;
+        }
+
+        // Click on expand/collaspse search-options. Has its own handler.
+        // We should not interfere.
+        if (e.currentTarget.ancestor(CSS.SEARCHOPTIONS)) {
+            return;
+        }
+
+        // Anything else means reload the pop-up contents.
         e.preventDefault();
         this.load_content(e.currentTarget.get('search'));
     },
@@ -167,6 +187,19 @@ Y.extend(POPUP, Y.Base, {
     options_changed: function(e) {
         e.preventDefault();
         this.load_content('?' + Y.IO.stringify(e.currentTarget.get('form')));
+    },
+
+    initialiseSearchRegion: function() {
+        if (this.searchRegionInitialised === true) {
+            return;
+        }
+        if (!Y.one(CSS.SEARCHOPTIONS)) {
+            return;
+        }
+
+        M.util.init_collapsible_region(Y, "advancedsearch", "question_bank_advanced_search",
+                M.util.get_string('clicktohideshow', 'moodle'));
+        this.searchRegionInitialised = true;
     }
 });
 
index f011fbf..e0a3749 100644 (file)
@@ -22,6 +22,7 @@ Feature: Add blocks to my home page
   Scenario: Add blocks to page
     When I press "Customise this page"
     And I add the "Latest news" block
-    And I add the "My latest badges" block
-    Then I should see "Latest news"
-    And I should see "My latest badges"
\ No newline at end of file
+    Then I should see "Latest news" in the "Latest news" "block"
+    And I should see "My latest badges" in the "My latest badges" "block"
+    And I should see "Calendar" in the "Calendar" "block"
+    And I should see "Upcoming events" in the "Upcoming events" "block"
\ No newline at end of file
index bf80e1b..f3923e5 100644 (file)
@@ -8,7 +8,7 @@ Feature: Tables can be sorted by additional names
     Given the following "users" exist:
     | username | firstname | lastname | middlename | alternatename | email | idnumber |
     | student1 | Annie | Edison | Faith | Anne | student1@mail.com | s1 |
-    | student2 | George | Bradley | David | gman | student2@mail.com | s2 |
+    | student2 | George | Bradley | David | Gman | student2@mail.com | s2 |
     | student3 | Travis | Sutcliff | Peter | Mr T | student3@mail.com | s3 |
     And I log in as "admin"
     And I navigate to "User policies" node in "Site administration > Users > Permissions"
@@ -19,37 +19,29 @@ Feature: Tables can be sorted by additional names
   @javascript
   Scenario: All user names are show and sortable in the administration user list.
     Given I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
-    # And I should see "First name / Middle name / Alternate name / Surname"
     Then the following should exist in the "users" table:
     | First name / Middle name / Alternate name / Surname | Email address |
     | Admin User | moodle@moodlemoodle.com |
     | Annie Faith Anne Edison | student1@mail.com |
-    | George David gman Bradley | student2@mail.com |
+    | George David Gman Bradley | student2@mail.com |
     | Travis Peter Mr T Sutcliff | student3@mail.com |
-    And "Admin User" "table_row" should appear before "Annie Faith Anne Edison" "table_row"
-    And "Annie Faith Anne Edison" "table_row" should appear before "George David gman Bradley" "table_row"
-    And "George David gman Bradley" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
+    And "Annie Faith Anne Edison" "table_row" should appear before "George David Gman Bradley" "table_row"
+    And "George David Gman Bradley" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
     And I follow "Middle name"
-    And "George David gman Bradley" "table_row" should appear before "Annie Faith Anne Edison" "table_row"
+    And "George David Gman Bradley" "table_row" should appear before "Annie Faith Anne Edison" "table_row"
     And "Annie Faith Anne Edison" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
-    And "Travis Peter Mr T Sutcliff" "table_row" should appear before "Admin User" "table_row"
     And I follow "Middle name"
-    And "George David gman Bradley" "table_row" should appear after "Annie Faith Anne Edison" "table_row"
+    And "George David Gman Bradley" "table_row" should appear after "Annie Faith Anne Edison" "table_row"
     And "Annie Faith Anne Edison" "table_row" should appear after "Travis Peter Mr T Sutcliff" "table_row"
-    And "Travis Peter Mr T Sutcliff" "table_row" should appear after "Admin User" "table_row"
     And I follow "Alternate name"
-    And "Annie Faith Anne Edison" "table_row" should appear before "George David gman Bradley" "table_row"
-    And "George David gman Bradley" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
-    And "Travis Peter Mr T Sutcliff" "table_row" should appear before "Admin User" "table_row"
+    And "Annie Faith Anne Edison" "table_row" should appear before "George David Gman Bradley" "table_row"
+    And "George David Gman Bradley" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
     And I follow "Alternate name"
-    And "Annie Faith Anne Edison" "table_row" should appear after "George David gman Bradley" "table_row"
-    And "George David gman Bradley" "table_row" should appear after "Travis Peter Mr T Sutcliff" "table_row"
-    And "Travis Peter Mr T Sutcliff" "table_row" should appear after "Admin User" "table_row"
+    And "Annie Faith Anne Edison" "table_row" should appear after "George David Gman Bradley" "table_row"
+    And "George David Gman Bradley" "table_row" should appear after "Travis Peter Mr T Sutcliff" "table_row"
     And I follow "Surname"
-    And "George David gman Bradley" "table_row" should appear before "Annie Faith Anne Edison" "table_row"
+    And "George David Gman Bradley" "table_row" should appear before "Annie Faith Anne Edison" "table_row"
     And "Annie Faith Anne Edison" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
-    And "Travis Peter Mr T Sutcliff" "table_row" should appear before "Admin User" "table_row"
     And I follow "Surname"
-    And "George David gman Bradley" "table_row" should appear after "Annie Faith Anne Edison" "table_row"
+    And "George David Gman Bradley" "table_row" should appear after "Annie Faith Anne Edison" "table_row"
     And "Annie Faith Anne Edison" "table_row" should appear after "Travis Peter Mr T Sutcliff" "table_row"
-    And "Travis Peter Mr T Sutcliff" "table_row" should appear after "Admin User" "table_row"
index e5f6d12..5f7f299 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2014101000.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2014101001.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.