Merge branch 'MDL-57338-master' of git://github.com/danpoltawski/moodle
authorDavid Monllao <david.monllao@gmail.com>
Thu, 29 Dec 2016 09:44:01 +0000 (10:44 +0100)
committerDavid Monllao <david.monllao@gmail.com>
Thu, 29 Dec 2016 09:44:01 +0000 (10:44 +0100)
35 files changed:
admin/environment.xml
admin/tool/lpimportcsv/classes/framework_importer.php
admin/tool/lpimportcsv/continue.php [deleted file]
admin/tool/lpimportcsv/index.php
admin/tool/lpimportcsv/lang/en/tool_lpimportcsv.php
auth/classes/output/login.php
auth/tests/behat/rememberusername.feature [new file with mode: 0644]
lang/en/admin.php
lib/adminlib.php
lib/classes/output/mustache_template_finder.php
lib/db/access.php
lib/db/upgrade.php
lib/formslib.php
lib/javascript-static.js
lib/navigationlib.php
lib/outputrenderers.php
lib/phpmailer/moodle_phpmailer.php
lib/upgrade.txt
lib/upgradelib.php
message/amd/build/message_area_messages.min.js
message/amd/src/message_area_messages.js
mod/lesson/locallib.php
mod/quiz/lib.php
report/log/classes/renderable.php
report/log/classes/table_log.php
report/log/lang/en/report_log.php
theme/boost/scss/moodle/core.scss
theme/boost/settings.php
theme/boost/templates/core_form/element-advcheckbox-inline.mustache
theme/boost/templates/core_form/element-advcheckbox.mustache
theme/boost/templates/core_form/element-checkbox-inline.mustache
theme/boost/templates/core_form/element-checkbox.mustache
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/style/moodle.css
version.php

index 8c35fb6..55502ee 100644 (file)
           <ON_CHECK message="unoconvwarning" />
         </FEEDBACK>
       </CUSTOM_CHECK>
-      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_tls_libraries" level="optional">
-        <FEEDBACK>
-          <ON_CHECK message="tlswarning" />
-        </FEEDBACK>
-      </CUSTOM_CHECK>
       <CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
         <FEEDBACK>
           <ON_CHECK message="libcurlwarning" />
index e784814..82b3516 100644 (file)
@@ -53,6 +53,10 @@ class framework_importer {
     protected $importer = null;
     protected $foundheaders = array();
     protected $scalecache = array();
+    /** @var bool $useprogressbar Control whether importing should use progress bars or not. */
+    protected $useprogressbar = false;
+    /** @var \core\progress\display_if_slow|null $progress The progress bar instance. */
+    protected $progress = null;
 
     /**
      * Store an error message for display later
@@ -164,8 +168,11 @@ class framework_importer {
      * @param string delimiter The specified delimiter for the file.
      * @param string importid The id of the csv import.
      * @param array mappingdata The mapping data from the import form.
+     * @param bool $useprogressbar Whether progress bar should be displayed, to avoid html output on CLI.
      */
-    public function __construct($text = null, $encoding = null, $delimiter = null, $importid = 0, $mappingdata = null) {
+    public function __construct($text = null, $encoding = null, $delimiter = null, $importid = 0, $mappingdata = null,
+            $useprogressbar = false) {
+
         global $CFG;
 
         // The format of our records is:
@@ -204,7 +211,7 @@ class framework_importer {
         }
 
         $this->foundheaders = $this->importer->get_columns();
-
+        $this->useprogressbar = $useprogressbar;
         $domainid = 1;
 
         $flat = array();
@@ -264,8 +271,19 @@ class framework_importer {
             $this->fail(get_string('invalidimportfile', 'tool_lpimportcsv'));
             return;
         } else {
+            // We are calling from browser, display progress bar.
+            if ($this->useprogressbar === true) {
+                $this->progress = new \core\progress\display_if_slow(get_string('processingfile', 'tool_lpimportcsv'));
+                $this->progress->start_html();
+            } else {
+                // Avoid html output on CLI scripts.
+                $this->progress = new \core\progress\none();
+            }
+            $this->progress->start_progress('', count($this->flat));
             // Build a tree from this flat list.
+            raise_memory_limit(MEMORY_EXTRA);
             $this->add_children($this->framework, '');
+            $this->progress->end_progress();
         }
     }
 
@@ -278,6 +296,7 @@ class framework_importer {
     public function add_children(& $node, $parentidnumber) {
         foreach ($this->flat as $competency) {
             if ($competency->parentidnumber == $parentidnumber) {
+                $this->progress->increment_progress();
                 $node->children[] = $competency;
                 $this->add_children($competency, $competency->idnumber);
             }
@@ -443,17 +462,28 @@ class framework_importer {
         $record->contextid = context_system::instance()->id;
 
         $framework = api::create_framework($record);
+        if ($this->useprogressbar === true) {
+            $this->progress = new \core\progress\display_if_slow(get_string('importingfile', 'tool_lpimportcsv'));
+            $this->progress->start_html();
+        } else {
+            $this->progress = new \core\progress\none();
+        }
 
+        $this->progress->start_progress('', (count($this->framework->children) * 2));
+        raise_memory_limit(MEMORY_EXTRA);
         // Now all the children.
         foreach ($this->framework->children as $comp) {
+            $this->progress->increment_progress();
             $this->create_competency($comp, null, $framework);
         }
 
         // Now create the rules.
         foreach ($this->framework->children as $record) {
+            $this->progress->increment_progress();
             $this->set_rules($record);
             $this->set_related($record);
         }
+        $this->progress->end_progress();
 
         $this->importer->cleanup();
         return $framework;
diff --git a/admin/tool/lpimportcsv/continue.php b/admin/tool/lpimportcsv/continue.php
deleted file mode 100644 (file)
index ef98a48..0000000
+++ /dev/null
@@ -1,47 +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/>.
-
-/**
- * Page to continue after an action.
- *
- * @package    tool_lpimportcsv
- * @copyright  2015 Damyon Wiese
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-require_once(__DIR__ . '/../../../config.php');
-require_once($CFG->libdir.'/adminlib.php');
-
-$pagetitle = get_string('pluginname', 'tool_lpimportcsv');
-
-$context = context_system::instance();
-
-$id = required_param('id', PARAM_INT);
-$url = new moodle_url("/admin/tool/lpimportcsv/index.php");
-$PAGE->set_context($context);
-$PAGE->set_url($url);
-$PAGE->set_title($pagetitle);
-$PAGE->set_pagelayout('admin');
-$PAGE->set_heading($pagetitle);
-
-echo $OUTPUT->header();
-echo $OUTPUT->heading($pagetitle);
-$urlparams = ['competencyframeworkid' => $id, 'pagecontextid' => $context->id];
-$frameworksurl = new moodle_url('/admin/tool/lp/competencies.php', $urlparams);
-echo $OUTPUT->notification(get_string('competencyframeworkcreated', 'tool_lp'), 'notifysuccess');
-echo $OUTPUT->continue_button($frameworksurl);
-
-echo $OUTPUT->footer();
index a2fc6cb..63d5a2c 100644 (file)
@@ -37,6 +37,7 @@ $PAGE->set_pagelayout('admin');
 $PAGE->set_heading($pagetitle);
 
 $form = null;
+echo $OUTPUT->header();
 if (optional_param('needsconfirm', 0, PARAM_BOOL)) {
     $form = new \tool_lpimportcsv\form\import($url->out(false));
 } else if (optional_param('confirm', 0, PARAM_BOOL)) {
@@ -53,7 +54,7 @@ if ($form->is_cancelled()) {
 
     if ($data->confirm) {
         $importid = $data->importid;
-        $importer = new \tool_lpimportcsv\framework_importer(null, null, null, $importid, $data);
+        $importer = new \tool_lpimportcsv\framework_importer(null, null, null, $importid, $data, true);
 
         $error = $importer->get_error();
         if ($error) {
@@ -61,21 +62,23 @@ if ($form->is_cancelled()) {
             $form->set_import_error($error);
         } else {
             $framework = $importer->import();
-            redirect(new moodle_url('continue.php', array('id' => $framework->get_id())));
+            $urlparams = ['competencyframeworkid' => $framework->get_id(), 'pagecontextid' => $context->id];
+            $frameworksurl = new moodle_url('/admin/tool/lp/competencies.php', $urlparams);
+            echo $OUTPUT->notification(get_string('competencyframeworkcreated', 'tool_lp'), 'notifysuccess');
+            echo $OUTPUT->continue_button($frameworksurl);
             die();
         }
     } else {
         $text = $form->get_file_content('importfile');
         $encoding = $data->encoding;
         $delimiter = $data->delimiter_name;
-        $importer = new \tool_lpimportcsv\framework_importer($text, $encoding, $delimiter);
+        $importer = new \tool_lpimportcsv\framework_importer($text, $encoding, $delimiter, 0, null, true);
         $confirmform = new \tool_lpimportcsv\form\import_confirm(null, $importer);
         $form = $confirmform;
         $pagetitle = get_string('confirmcolumnmappings', 'tool_lpimportcsv');
     }
 }
 
-echo $OUTPUT->header();
 echo $OUTPUT->heading($pagetitle);
 
 $form->display();
index 8c10b04..fd8d9cf 100644 (file)
@@ -38,11 +38,13 @@ $string['importfile'] = 'CSV framework description file';
 $string['importfile_help'] = 'A competency framework may be imported via text file. The format of the file can be determined by creating a new competency framework on the site and then exporting it.';
 $string['importfile_link'] = 'admin/tool/lpimportcsv';
 $string['import'] = 'Import';
+$string['importingfile'] = 'Importing file data';
 $string['invalidimportfile'] = 'File format is invalid.';
 $string['isframework'] = 'Is framework';
 $string['noframeworks'] = 'No competency frameworks have been created yet';
 $string['parentidnumber'] = 'Parent ID number';
 $string['pluginname'] = 'Import competency framework';
+$string['processingfile'] = 'Processing file';
 $string['relatedidnumbers'] = 'Cross-referenced competency ID numbers';
 $string['ruleconfig'] = 'Rule config (optional)';
 $string['ruleoutcome'] = 'Rule outcome (optional)';
index e5e4e7d..5b924bb 100644 (file)
@@ -151,6 +151,7 @@ class login implements renderable, templatable {
         $data->rememberusername = $this->rememberusername;
         $data->passwordautocomplete = $this->passwordautocomplete;
         $data->signupurl = $this->signupurl->out(false);
+        $data->username = $this->username;
 
         return $data;
     }
diff --git a/auth/tests/behat/rememberusername.feature b/auth/tests/behat/rememberusername.feature
new file mode 100644 (file)
index 0000000..754ce8f
--- /dev/null
@@ -0,0 +1,50 @@
+@core @core_auth
+Feature: Test the 'remember username' feature works.
+  In order to see my saved username on the login form
+  As a user
+  I need to have logged in once before and clicked 'Remember username'
+
+  Background:
+    Given the following "users" exist:
+      | username |
+      | teacher1 |
+
+  # Given the user has logged in and selected 'Remember username', when they log in again, then their username should be remembered.
+  Scenario: Check that 'remember username' works without javascript for teachers.
+    # Log in the first time and check the 'remember username' box.
+    Given I am on homepage
+    And I click on "Log in" "link" in the ".logininfo" "css_element"
+    And I set the field "Username" to "teacher1"
+    And I set the field "Password" to "teacher1"
+    And I set the field "Remember username" to "1"
+    And I press "Log in"
+    And I log out
+    # Log out and check that the username was remembered.
+    When I am on homepage
+    And I click on "Log in" "link" in the ".logininfo" "css_element"
+    Then the field "username" matches value "teacher1"
+    And the field "Remember username" matches value "1"
+
+  # Given the user has logged in before and selected 'Remember username', when they log in again and unset 'Remember username', then
+  # their username should be forgotten for future log in attempts.
+  Scenario: Check that 'remember username' unsetting works without javascript for teachers.
+    # Log in the first time and check the 'remember username' box.
+    Given I am on homepage
+    And I click on "Log in" "link" in the ".logininfo" "css_element"
+    And I set the field "Username" to "teacher1"
+    And I set the field "Password" to "teacher1"
+    And I set the field "Remember username" to "1"
+    And I press "Log in"
+    And I log out
+    # Log in again, unsetting the 'remember username' field.
+    When I am on homepage
+    And I click on "Log in" "link" in the ".logininfo" "css_element"
+    And I set the field "Password" to "teacher1"
+    And I set the field "Remember username" to "0"
+    And I press "Log in"
+    And I log out
+    # Check username has been forgotten.
+    Then I am on homepage
+    And I click on "Log in" "link" in the ".logininfo" "css_element"
+    Then the field "username" matches value ""
+    And the field "Remember username" matches value "0"
index ca87cd7..256abff 100644 (file)
@@ -969,6 +969,7 @@ $string['roleswithexceptions'] = '{$a->roles}, with {$a->exceptions}';
 $string['rssglobaldisabled'] = 'Disabled at server level';
 $string['save'] = 'Save';
 $string['savechanges'] = 'Save changes';
+$string['scssinvalid'] = 'SCSS code is not valid, fails with: {$a}';
 $string['search'] = 'Search';
 $string['searchalldeleted'] = 'All indexed contents have been deleted';
 $string['searchareaenabled'] = 'Search area enabled';
index faa3b64..aca0b82 100644 (file)
@@ -10180,3 +10180,41 @@ class admin_setting_searchsetupinfo extends admin_setting {
     }
 
 }
+
+/**
+ * Used to validate the contents of SCSS code and ensuring they are parsable.
+ *
+ * It does not attempt to detect undefined SCSS variables because it is designed
+ * to be used without knowledge of other config/scss included.
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @copyright 2016 Dan Poltawski <dan@moodle.com>
+ */
+class admin_setting_scsscode extends admin_setting_configtextarea {
+
+    /**
+     * Validate the contents of the SCSS to ensure its parsable. Does not
+     * attempt to detect undefined scss variables.
+     *
+     * @param string $data The scss code from text field.
+     * @return mixed bool true for success or string:error on failure.
+     */
+    public function validate($data) {
+        if (empty($data)) {
+            return true;
+        }
+
+        $scss = new core_scss();
+        try {
+            $scss->compile($data);
+        } catch (Leafo\ScssPhp\Exception\ParserException $e) {
+            return get_string('scssinvalid', 'admin', $e->getMessage());
+        } catch (Leafo\ScssPhp\Exception\CompilerException $e) {
+            // Silently ignore this - it could be a scss variable defined from somewhere
+            // else which we are not examining here.
+            return true;
+        }
+
+        return true;
+    }
+}
index baaa605..397fa76 100644 (file)
@@ -76,10 +76,16 @@ class mustache_template_finder {
 
         // First check the theme.
         $dirs[] = $CFG->dirroot . '/theme/' . $themename . '/templates/' . $component . '/';
+        if (isset($CFG->themedir)) {
+            $dirs[] = $CFG->themedir . '/' . $themename . '/templates/' . $component . '/';
+        }
         // Now check the parent themes.
         // Search each of the parent themes second.
         foreach ($parents as $parent) {
             $dirs[] = $CFG->dirroot . '/theme/' . $parent . '/templates/' . $component . '/';
+            if (isset($CFG->themedir)) {
+                $dirs[] = $CFG->themedir . '/' . $parent . '/templates/' . $component . '/';
+            }
         }
 
         $dirs[] = $compdirectory . '/templates/';
index 10242db..8154cf2 100644 (file)
@@ -69,6 +69,7 @@ $capabilities = array(
         'contextlevel' => CONTEXT_SYSTEM,
         'archetypes' => array(
             'manager' => CAP_ALLOW,
+            'coursecreator' => CAP_ALLOW,
         )
     ),
 
index da20823..20e304f 100644 (file)
@@ -2436,5 +2436,34 @@ function xmldb_main_upgrade($oldversion) {
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2016122800.00) {
+        // Find all roles with the coursecreator archetype.
+        $coursecreatorroleids = $DB->get_records('role', array('archetype' => 'coursecreator'), '', 'id');
+
+        $context = context_system::instance();
+        $capability = 'moodle/site:configview';
+
+        foreach ($coursecreatorroleids as $roleid => $notused) {
+
+            // Check that the capability has not already been assigned. If it has then it's either already set
+            // to allow or specifically set to prohibit or prevent.
+            if (!$DB->record_exists('role_capabilities', array('roleid' => $roleid, 'capability' => $capability))) {
+                // Assign the capability.
+                $cap = new stdClass();
+                $cap->contextid    = $context->id;
+                $cap->roleid       = $roleid;
+                $cap->capability   = $capability;
+                $cap->permission   = CAP_ALLOW;
+                $cap->timemodified = time();
+                $cap->modifierid   = 0;
+
+                $DB->insert_record('role_capabilities', $cap);
+            }
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2016122800.00);
+    }
+
     return true;
 }
index de7dfca..2c8a3ea 100644 (file)
@@ -1240,31 +1240,15 @@ abstract class moodleform {
      *                      $enhancement = 'smartselect';
      *                      $options = array('selectablecategories' => true|false)
      *
-     * @since Moodle 2.0
      * @param string|element $element form element for which Javascript needs to be initalized
      * @param string $enhancement which init function should be called
      * @param array $options options passed to javascript
      * @param array $strings strings for javascript
+     * @deprecated since Moodle 3.3 MDL-57471
      */
     function init_javascript_enhancement($element, $enhancement, array $options=array(), array $strings=null) {
-        global $PAGE;
-        if (is_string($element)) {
-            $element = $this->_form->getElement($element);
-        }
-        if (is_object($element)) {
-            $element->_generateId();
-            $elementid = $element->getAttribute('id');
-            $PAGE->requires->js_init_call('M.form.init_'.$enhancement, array($elementid, $options));
-            if (is_array($strings)) {
-                foreach ($strings as $string) {
-                    if (is_array($string)) {
-                        call_user_func_array(array($PAGE->requires, 'string_for_js'), $string);
-                    } else {
-                        $PAGE->requires->string_for_js($string, 'moodle');
-                    }
-                }
-            }
-        }
+        debugging('$mform->init_javascript_enhancement() is deprecated and no longer does anything. '.
+            'smartselect uses should be converted to the searchableselector form element.', DEBUG_DEVELOPER);
     }
 
     /**
index 4320ae2..9c7de46 100644 (file)
@@ -1063,43 +1063,18 @@ function filterByParent(elCollection, parentFinder) {
     return filteredCollection;
 }
 
-/*
-    All this is here just so that IE gets to handle oversized blocks
-    in a visually pleasing manner. It does a browser detect. So sue me.
-*/
-
+/**
+ * @deprecated since Moodle 3.3, but shouldn't be used in earlier versions either.
+ */
 function fix_column_widths() {
-    var agt = navigator.userAgent.toLowerCase();
-    if ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)) {
-        fix_column_width('left-column');
-        fix_column_width('right-column');
-    }
+    Y.log('fix_column_widths() no longer does anything. Please remove it from your code.', 'warn', 'javascript-static.js');
 }
 
+/**
+ * @deprecated since Moodle 3.3, but shouldn't be used in earlier versions either.
+ */
 function fix_column_width(colName) {
-    if(column = document.getElementById(colName)) {
-        if(!column.offsetWidth) {
-            setTimeout("fix_column_width('" + colName + "')", 20);
-            return;
-        }
-
-        var width = 0;
-        var nodes = column.childNodes;
-
-        for(i = 0; i < nodes.length; ++i) {
-            if(nodes[i].className.indexOf("block") != -1 ) {
-                if(width < nodes[i].offsetWidth) {
-                    width = nodes[i].offsetWidth;
-                }
-            }
-        }
-
-        for(i = 0; i < nodes.length; ++i) {
-            if(nodes[i].className.indexOf("block") != -1 ) {
-                nodes[i].style.width = width + 'px';
-            }
-        }
-    }
+    Y.log('fix_column_width() no longer does anything. Please remove it from your code.', 'warn', 'javascript-static.js');
 }
 
 
@@ -1462,209 +1437,11 @@ M.form = M.form || {};
 
 /**
  * Converts a nbsp indented select box into a multi drop down custom control much
- * like the custom menu. It also selectable categories on or off.
- *
- * $form->init_javascript_enhancement('elementname','smartselect', array('selectablecategories'=>true|false, 'mode'=>'compact'|'spanning'));
- *
- * @param {YUI} Y
- * @param {string} id
- * @param {Array} options
+ * like the custom menu. Can no longer be used.
+ * @deprecated since Moodle 3.3
  */
-M.form.init_smartselect = function(Y, id, options) {
-    if (!id.match(/^id_/)) {
-        id = 'id_'+id;
-    }
-    var select = Y.one('select#'+id);
-    if (!select) {
-        return false;
-    }
-    Y.use('event-delegate',function(){
-        var smartselect = {
-            id : id,
-            structure : [],
-            options : [],
-            submenucount : 0,
-            currentvalue : null,
-            currenttext : null,
-            shownevent : null,
-            cfg : {
-                selectablecategories : true,
-                mode : null
-            },
-            nodes : {
-                select : null,
-                loading : null,
-                menu : null
-            },
-            init : function(Y, id, args, nodes) {
-                if (typeof(args)=='object') {
-                    for (var i in this.cfg) {
-                        if (args[i] || args[i]===false) {
-                            this.cfg[i] = args[i];
-                        }
-                    }
-                }
-
-                // Display a loading message first up
-                this.nodes.select = nodes.select;
-
-                this.currentvalue = this.nodes.select.get('selectedIndex');
-                this.currenttext = this.nodes.select.all('option').item(this.currentvalue).get('innerHTML');
-
-                var options = Array();
-                options[''] = {text:this.currenttext,value:'',depth:0,children:[]};
-                this.nodes.select.all('option').each(function(option, index) {
-                    var rawtext = option.get('innerHTML');
-                    var text = rawtext.replace(/^(&nbsp;)*/, '');
-                    if (rawtext === text) {
-                        text = rawtext.replace(/^(\s)*/, '');
-                        var depth = (rawtext.length - text.length ) + 1;
-                    } else {
-                        var depth = ((rawtext.length - text.length )/12)+1;
-                    }
-                    option.set('innerHTML', text);
-                    options['i'+index] = {text:text,depth:depth,index:index,children:[]};
-                }, this);
-
-                this.structure = [];
-                var structcount = 0;
-                for (var i in options) {
-                    var o = options[i];
-                    if (o.depth == 0) {
-                        this.structure.push(o);
-                        structcount++;
-                    } else {
-                        var d = o.depth;
-                        var current = this.structure[structcount-1];
-                        for (var j = 0; j < o.depth-1;j++) {
-                            if (current && current.children) {
-                                current = current.children[current.children.length-1];
-                            }
-                        }
-                        if (current && current.children) {
-                            current.children.push(o);
-                        }
-                    }
-                }
-
-                this.nodes.menu = Y.Node.create(this.generate_menu_content());
-                this.nodes.menu.one('.smartselect_mask').setStyle('opacity', 0.01);
-                this.nodes.menu.one('.smartselect_mask').setStyle('width', (this.nodes.select.get('offsetWidth')+5)+'px');
-                this.nodes.menu.one('.smartselect_mask').setStyle('height', (this.nodes.select.get('offsetHeight'))+'px');
-
-                if (this.cfg.mode == null) {
-                    var formwidth = this.nodes.select.ancestor('form').get('offsetWidth');
-                    if (formwidth < 400 || this.nodes.menu.get('offsetWidth') < formwidth*2) {
-                        this.cfg.mode = 'compact';
-                    } else {
-                        this.cfg.mode = 'spanning';
-                    }
-                }
-
-                if (this.cfg.mode == 'compact') {
-                    this.nodes.menu.addClass('compactmenu');
-                } else {
-                    this.nodes.menu.addClass('spanningmenu');
-                    this.nodes.menu.delegate('mouseover', this.show_sub_menu, '.smartselect_submenuitem', this);
-                }
-
-                Y.one(document.body).append(this.nodes.menu);
-                var pos = this.nodes.select.getXY();
-                pos[0] += 1;
-                this.nodes.menu.setXY(pos);
-                this.nodes.menu.on('click', this.handle_click, this);
-
-                Y.one(window).on('resize', function(){
-                     var pos = this.nodes.select.getXY();
-                    pos[0] += 1;
-                    this.nodes.menu.setXY(pos);
-                 }, this);
-            },
-            generate_menu_content : function() {
-                var content = '<div id="'+this.id+'_smart_select" class="smartselect">';
-                content += this.generate_submenu_content(this.structure[0], true);
-                content += '</ul></div>';
-                return content;
-            },
-            generate_submenu_content : function(item, rootelement) {
-                this.submenucount++;
-                var content = '';
-                if (item.children.length > 0) {
-                    if (rootelement) {
-                        content += '<div class="smartselect_mask" href="#ss_submenu'+this.submenucount+'">&nbsp;</div>';
-                        content += '<div id="ss_submenu'+this.submenucount+'" class="smartselect_menu">';
-                        content += '<div class="smartselect_menu_content">';
-                    } else {
-                        content += '<li class="smartselect_submenuitem">';
-                        var categoryclass = (this.cfg.selectablecategories)?'selectable':'notselectable';
-                        content += '<a class="smartselect_menuitem_label '+categoryclass+'" href="#ss_submenu'+this.submenucount+'" value="'+item.index+'">'+item.text+'</a>';
-                        content += '<div id="ss_submenu'+this.submenucount+'" class="smartselect_submenu">';
-                        content += '<div class="smartselect_submenu_content">';
-                    }
-                    content += '<ul>';
-                    for (var i in item.children) {
-                        content += this.generate_submenu_content(item.children[i],false);
-                    }
-                    content += '</ul>';
-                    content += '</div>';
-                    content += '</div>';
-                    if (rootelement) {
-                    } else {
-                        content += '</li>';
-                    }
-                } else {
-                    content += '<li class="smartselect_menuitem">';
-                    content += '<a class="smartselect_menuitem_content selectable" href="#" value="'+item.index+'">'+item.text+'</a>';
-                    content += '</li>';
-                }
-                return content;
-            },
-            select : function(e) {
-                var t = e.target;
-                e.halt();
-                this.currenttext = t.get('innerHTML');
-                this.currentvalue = t.getAttribute('value');
-                this.nodes.select.set('selectedIndex', this.currentvalue);
-                this.hide_menu();
-            },
-            handle_click : function(e) {
-                var target = e.target;
-                if (target.hasClass('smartselect_mask')) {
-                    this.show_menu(e);
-                } else if (target.hasClass('selectable') || target.hasClass('smartselect_menuitem')) {
-                    this.select(e);
-                } else if (target.hasClass('smartselect_menuitem_label') || target.hasClass('smartselect_submenuitem')) {
-                    this.show_sub_menu(e);
-                }
-            },
-            show_menu : function(e) {
-                e.halt();
-                var menu = e.target.ancestor().one('.smartselect_menu');
-                menu.addClass('visible');
-                this.shownevent = Y.one(document.body).on('click', this.hide_menu, this);
-            },
-            show_sub_menu : function(e) {
-                e.halt();
-                var target = e.target;
-                if (!target.hasClass('smartselect_submenuitem')) {
-                    target = target.ancestor('.smartselect_submenuitem');
-                }
-                if (this.cfg.mode == 'compact' && target.one('.smartselect_submenu').hasClass('visible')) {
-                    target.ancestor('ul').all('.smartselect_submenu.visible').removeClass('visible');
-                    return;
-                }
-                target.ancestor('ul').all('.smartselect_submenu.visible').removeClass('visible');
-                target.one('.smartselect_submenu').addClass('visible');
-            },
-            hide_menu : function() {
-                this.nodes.menu.all('.visible').removeClass('visible');
-                if (this.shownevent) {
-                    this.shownevent.detach();
-                }
-            }
-        };
-        smartselect.init(Y, id, options, {select:select});
-    });
+M.form.init_smartselect = function() {
+    throw new Error('M.form.init_smartselect can not be used any more.');
 };
 
 /**
index 1af75d2..8d1859c 100644 (file)
@@ -2104,7 +2104,7 @@ class global_navigation extends navigation_node {
                 $onclick = htmlspecialchars_decode($activity->onclick, ENT_QUOTES);
                 // Build the JS function the click event will call
                 $jscode = "function {$functionname}(e) { $propogrationhandler $onclick }";
-                $this->page->requires->js_init_code($jscode);
+                $this->page->requires->js_amd_inline($jscode);
                 // Override the default url with the new action link
                 $action = new action_link($action, $activityname, new component_action('click', $functionname));
             }
@@ -3913,34 +3913,38 @@ class settings_navigation extends navigation_node {
         if (isloggedin() && !isguestuser() && (!isset($SESSION->load_navigation_admin) || $SESSION->load_navigation_admin)) {
             $isadminpage = $this->is_admin_tree_needed();
 
-            if (has_capability('moodle/site:config', context_system::instance())) {
-                // Make sure this works even if config capability changes on the fly
-                // and also make it fast for admin right after login.
-                $SESSION->load_navigation_admin = 1;
-                if ($isadminpage) {
-                    $adminsettings = $this->load_administration_settings();
-                }
-
-            } else if (!isset($SESSION->load_navigation_admin)) {
-                $adminsettings = $this->load_administration_settings();
-                $SESSION->load_navigation_admin = (int)($adminsettings->children->count() > 0);
+            if (has_capability('moodle/site:configview', context_system::instance())) {
+                if (has_capability('moodle/site:config', context_system::instance())) {
+                    // Make sure this works even if config capability changes on the fly
+                    // and also make it fast for admin right after login.
+                    $SESSION->load_navigation_admin = 1;
+                    if ($isadminpage) {
+                        $adminsettings = $this->load_administration_settings();
+                    }
 
-            } else if ($SESSION->load_navigation_admin) {
-                if ($isadminpage) {
+                } else if (!isset($SESSION->load_navigation_admin)) {
                     $adminsettings = $this->load_administration_settings();
+                    $SESSION->load_navigation_admin = (int)($adminsettings->children->count() > 0);
+
+                } else if ($SESSION->load_navigation_admin) {
+                    if ($isadminpage) {
+                        $adminsettings = $this->load_administration_settings();
+                    }
                 }
-            }
 
-            // Print empty navigation node, if needed.
-            if ($SESSION->load_navigation_admin && !$isadminpage) {
-                if ($adminsettings) {
-                    // Do not print settings tree on pages that do not need it, this helps with performance.
-                    $adminsettings->remove();
-                    $adminsettings = false;
+                // Print empty navigation node, if needed.
+                if ($SESSION->load_navigation_admin && !$isadminpage) {
+                    if ($adminsettings) {
+                        // Do not print settings tree on pages that do not need it, this helps with performance.
+                        $adminsettings->remove();
+                        $adminsettings = false;
+                    }
+                    $siteadminnode = $this->add(get_string('administrationsite'), new moodle_url('/admin/search.php'),
+                            self::TYPE_SITE_ADMIN, null, 'siteadministration');
+                    $siteadminnode->id = 'expandable_branch_' . $siteadminnode->type . '_' .
+                            clean_param($siteadminnode->key, PARAM_ALPHANUMEXT);
+                    $siteadminnode->requiresajaxloading = 'true';
                 }
-                $siteadminnode = $this->add(get_string('administrationsite'), new moodle_url('/admin/search.php'), self::TYPE_SITE_ADMIN, null, 'siteadministration');
-                $siteadminnode->id = 'expandable_branch_'.$siteadminnode->type.'_'.clean_param($siteadminnode->key, PARAM_ALPHANUMEXT);
-                $siteadminnode->requiresajaxloading = 'true';
             }
         }
 
index 6c81aa7..21f40ff 100644 (file)
@@ -576,8 +576,6 @@ class core_renderer extends renderer_base {
             'loadinghelp',
         ), 'moodle');
 
-        $this->page->requires->js_function_call('setTimeout', array('fix_column_widths()', 20));
-
         $focus = $this->page->focuscontrol;
         if (!empty($focus)) {
             if (preg_match("#forms\['([a-zA-Z0-9]+)'\].elements\['([a-zA-Z0-9]+)'\]#", $focus, $matches)) {
index a25b992..63abdeb 100644 (file)
@@ -74,10 +74,10 @@ class moodle_phpmailer extends PHPMailer {
      */
     public function addCustomHeader($custom_header, $value = null) {
         if ($value === null and preg_match('/message-id:(.*)/i', $custom_header, $matches)) {
-            $this->MessageID = $matches[1];
+            $this->MessageID = trim($matches[1]);
             return true;
         } else if ($value !== null and strcasecmp($custom_header, 'message-id') === 0) {
-            $this->MessageID = $value;
+            $this->MessageID = trim($value);
             return true;
         } else {
             return parent::addCustomHeader($custom_header, $value);
index 2ab1711..ba7e311 100644 (file)
@@ -4,6 +4,8 @@ information provided here is intended especially for developers.
 === 3.3 ===
 * YUI module moodle-core-formautosubmit has been removed, use jquery .change() instead (see lib/templates/url_select.mustache for
   an example)
+* $mform->init_javascript_enhancement() is deprecated and no longer does anything. Existing uses of smartselect enhancement
+  should be switched to the searchableselector form element or other solutions.
 
 === 3.2 ===
 
index de6e6b4..0a61cfa 100644 (file)
@@ -2325,7 +2325,7 @@ function check_unoconv_version(environment_results $result) {
 }
 
 /**
- * Checks for up-to-date TLS libraries.
+ * Checks for up-to-date TLS libraries. NOTE: this is not currently used, see MDL-57262.
  *
  * @param environment_results $result object to update, if relevant.
  * @return environment_results|null updated results or null if unoconv path is not executable.
index c62ff2c..c47cd2e 100644 (file)
Binary files a/message/amd/build/message_area_messages.min.js and b/message/amd/build/message_area_messages.min.js differ
index 3188100..9682d82 100644 (file)
@@ -75,6 +75,9 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust
         /** @type {int} the number of messagess displayed */
         Messages.prototype._numMessagesDisplayed = 0;
 
+        /** @type {array} the messages displayed or about to be displayed on the page */
+        Messages.prototype._messageQueue = [];
+
         /** @type {int} the number of messages to retrieve */
         Messages.prototype._numMessagesToRetrieve = 20;
 
@@ -294,36 +297,8 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust
             }
 
             // Keep track of the number of messages received.
-            var numberreceived = 0;
             return this._getMessages(this._getUserId(), true).then(function(data) {
-                // Filter out any messages already rendered.
-                var messagesArea = this.messageArea.find(SELECTORS.MESSAGES);
-                data.messages = data.messages.filter(function(message) {
-                    var id = "" + message.id + message.isread;
-                    var result = messagesArea.find(SELECTORS.MESSAGE + '[data-id="' + id + '"]');
-                    return !result.length;
-                });
-                numberreceived = data.messages.length;
-                // We have the data - lets render the template with it.
-                return Templates.render('core_message/message_area_messages', data);
-            }.bind(this)).then(function(html, js) {
-                // Check if we got something to do.
-                if (numberreceived > 0) {
-                    var newHtml = $('<div>' + html + '</div>');
-                    if (this._hasMatchingBlockTime(this.messageArea.node, newHtml, false)) {
-                        newHtml.find(SELECTORS.BLOCKTIME + ':first').remove();
-                    }
-                    // Show the new content.
-                    Templates.appendNodeContents(this.messageArea.find(SELECTORS.MESSAGES), newHtml, js);
-                    // Scroll the new message into view.
-                    if (shouldScrollBottom) {
-                        this._scrollBottom();
-                    }
-                    // Increment the number of messages displayed.
-                    this._numMessagesDisplayed += numberreceived;
-                    // Reset the poll timer because the user may be active.
-                    this._backoffTimer.restart();
-                }
+                return this._addMessagesToDom(data.messages, shouldScrollBottom);
             }.bind(this)).always(function() {
                 // Mark that we are no longer busy loading data.
                 this._isLoadingMessages = false;
@@ -435,7 +410,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust
                 // Fire an event to say the message was sent.
                 this.messageArea.trigger(Events.MESSAGESENT, [this._getUserId(), text]);
                 // Update the messaging area.
-                return this._addMessageToDom();
+                return this._addLastMessageToDom();
             }.bind(this)).then(function() {
                 // Ok, we are no longer sending a message.
                 this._isSendingMessage = false;
@@ -624,10 +599,58 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust
         /**
          * Handles adding messages to the DOM.
          *
+         * @param {array} messages An array of messages to be added to the DOM.
+         * @param {boolean} shouldScrollBottom True will scroll to the bottom of the message window and show the new messages.
+         * @return {Promise} The promise resolved when the messages have been added to the DOM.
+         * @private
+         */
+        Messages.prototype._addMessagesToDom = function(messages, shouldScrollBottom) {
+            var numberreceived = 0;
+            var messagesArea = this.messageArea.find(SELECTORS.MESSAGES);
+            messages = messages.filter(function(message) {
+                var id = "" + message.id + message.isread;
+                // If the message is already queued to be rendered, remove from the list of messages.
+                if (this._messageQueue[id]) {
+                    return false;
+                }
+                // Filter out any messages already rendered.
+                var result = messagesArea.find(SELECTORS.MESSAGE + '[data-id="' + id + '"]');
+                // Any message we are rendering should go in the messageQueue.
+                if (!result.length) {
+                    this._messageQueue[id] = true;
+                }
+                return !result.length;
+            }.bind(this));
+            numberreceived = messages.length;
+            // We have the data - lets render the template with it.
+            return Templates.render('core_message/message_area_messages', {messages: messages}).then(function(html, js) {
+                // Check if we got something to do.
+                if (numberreceived > 0) {
+                    var newHtml = $('<div>' + html + '</div>');
+                    if (this._hasMatchingBlockTime(this.messageArea.node, newHtml, false)) {
+                        newHtml.find(SELECTORS.BLOCKTIME + ':first').remove();
+                    }
+                    // Show the new content.
+                    Templates.appendNodeContents(this.messageArea.find(SELECTORS.MESSAGES), newHtml, js);
+                    // Scroll the new message into view.
+                    if (shouldScrollBottom) {
+                        this._scrollBottom();
+                    }
+                    // Increment the number of messages displayed.
+                    this._numMessagesDisplayed += numberreceived;
+                    // Reset the poll timer because the user may be active.
+                    this._backoffTimer.restart();
+                }
+            }.bind(this));
+        };
+
+        /**
+         * Handles adding the last message to the DOM.
+         *
          * @return {Promise} The promise resolved when the message has been added to the DOM.
          * @private
          */
-        Messages.prototype._addMessageToDom = function() {
+        Messages.prototype._addLastMessageToDom = function() {
             // Call the web service to return how the message should look.
             var promises = Ajax.call([{
                 methodname: 'core_message_data_for_messagearea_get_most_recent_message',
@@ -639,13 +662,10 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust
 
             // Add the message.
             return promises[0].then(function(data) {
-                return Templates.render('core_message/message_area_message', data);
-            }).then(function(html, js) {
-                Templates.appendNodeContents(this.messageArea.find(SELECTORS.MESSAGES), html, js);
-                // Empty the response text area.
+                return this._addMessagesToDom([data], true);
+            }.bind(this)).always(function() {
+                // Empty the response text area.text
                 this.messageArea.find(SELECTORS.SENDMESSAGETEXT).val('').trigger('input');
-                // Scroll down.
-                this._scrollBottom();
             }.bind(this)).fail(Notification.exception);
         };
 
index 160d80f..4e02e44 100644 (file)
@@ -2955,7 +2955,7 @@ abstract class lesson_page extends lesson_base {
         for ($i = 0; $i < $this->lesson->maxanswers; $i++) {
             $answer = clone($newanswer);
 
-            if (!empty($properties->answer_editor[$i])) {
+            if (isset($properties->answer_editor[$i])) {
                 if (is_array($properties->answer_editor[$i])) {
                     // Multichoice and true/false pages have an HTML editor.
                     $answer->answer = $properties->answer_editor[$i]['text'];
index fd2b579..21b158f 100644 (file)
@@ -1194,8 +1194,11 @@ function quiz_update_events($quiz, $override = null) {
                    'instance'=>$quiz->id);
     if (!empty($override)) {
         // Only load events for this override.
-        $conds['groupid'] = isset($override->groupid)?  $override->groupid : 0;
-        $conds['userid'] = isset($override->userid)?  $override->userid : 0;
+        if (isset($override->userid)) {
+            $conds['userid'] = $override->userid;
+        } else {
+            $conds['groupid'] = $override->groupid;
+        }
     }
     $oldevents = $DB->get_records('event', $conds);
 
index f5f12fa..56ae1a6 100644 (file)
@@ -442,15 +442,13 @@ class report_log_renderable implements renderable {
      * @return array list of origins.
      */
     public function get_origin_options() {
-        global $DB;
-        $origins = $DB->get_records_sql('select distinct origin from {logstore_standard_log} order by origin ASC');
         $ret = array();
         $ret[''] = get_string('allsources', 'report_log');
-        foreach ($origins as $origin) {
-            if (!empty($origin->origin)) {
-                $ret[$origin->origin] = get_string($origin->origin, 'report_log');
-            }
-        }
+        $ret['cli'] = get_string('cli', 'report_log');
+        $ret['restore'] = get_string('restore', 'report_log');
+        $ret['web'] = get_string('web', 'report_log');
+        $ret['ws'] = get_string('ws', 'report_log');
+        $ret['---'] = get_string('other', 'report_log');
         return $ret;
     }
 
index c1f3ff9..ad9e44a 100644 (file)
@@ -486,10 +486,20 @@ class report_log_table_log extends table_sql {
             $joins[] = "edulevel ".$edulevelsql;
             $params = array_merge($params, $edulevelparams);
         }
+
         // Origin.
         if (isset($this->filterparams->origin) && ($this->filterparams->origin != '')) {
-            $joins[] = "origin = :origin";
-            $params['origin'] = $this->filterparams->origin;
+            if ($this->filterparams->origin !== '---') {
+                // Filter by a single origin.
+                $joins[] = "origin = :origin";
+                $params['origin'] = $this->filterparams->origin;
+            } else {
+                // Filter by everything else.
+                list($originsql, $originparams) = $DB->get_in_or_equal(array('cli', 'restore', 'ws', 'web'),
+                    SQL_PARAMS_NAMED, 'origin', false);
+                $joins[] = "origin " . $originsql;
+                $params = array_merge($params, $originparams);
+            }
         }
 
         if (!($this->filterparams->logreader instanceof logstore_legacy\log\store)) {
index d764bdd..f37d48f 100644 (file)
@@ -39,6 +39,7 @@ $string['page'] = 'Page {$a}';
 $string['logsformat'] = 'Logs format';
 $string['nologreaderenabled'] = 'No log reader enabled';
 $string['origin'] = 'Source';
+$string['other'] = 'Other';
 $string['page-report-log-x'] = 'Any log report';
 $string['page-report-log-index'] = 'Course log report';
 $string['page-report-log-user'] = 'User course log report';
index d97e73d..c669075 100644 (file)
@@ -886,106 +886,6 @@ tr.flagged-tag a {
     text-align: left;
     border: 0 solid black;
 }
-/**
-* Smart Select Element
-*/
-.smartselect {
-    position: absolute;
-}
-
-.smartselect .smartselect_mask {
-    background-color: #fff;
-}
-
-.smartselect ul {
-    padding: 0;
-    margin: 0;
-}
-
-.smartselect ul li {
-    list-style: none;
-}
-
-.smartselect .smartselect_menu {
-    margin-right: 5px;
-}
-
-.safari .smartselect .smartselect_menu {
-    margin-left: 2px;
-}
-
-.smartselect .smartselect_menu,
-.smartselect .smartselect_submenu {
-    border: 1px solid #000;
-    background-color: #fff;
-    display: none;
-}
-
-.smartselect .smartselect_menu.visible,
-.smartselect .smartselect_submenu.visible {
-    display: block;
-}
-
-.smartselect .smartselect_menu_content ul li {
-    position: relative;
-    padding: 2px 5px;
-}
-
-.smartselect .smartselect_menu_content ul li a {
-    color: #333;
-    text-decoration: none;
-}
-
-.smartselect .smartselect_menu_content ul li a.selectable {
-    color: inherit;
-}
-
-.smartselect .smartselect_submenuitem {
-    background-image: url([[pix:moodle|t/collapsed]]);
-    background-repeat: no-repeat;
-    background-position: 100%;
-}
-/** Spanning mode */
-.smartselect.spanningmenu .smartselect_submenu {
-    position: absolute;
-    top: -1px;
-    left: 100%;
-}
-
-.smartselect.spanningmenu .smartselect_submenu a {
-    white-space: nowrap;
-    padding-right: 16px;
-}
-
-.smartselect.spanningmenu .smartselect_menu_content ul li a.selectable:hover {
-    text-decoration: underline;
-}
-/** Compact mode */
-.smartselect.compactmenu .smartselect_submenu {
-    position: relative;
-    margin: 2px -3px;
-    margin-left: 10px;
-    display: none;
-    border-width: 0;
-    z-index: 1010;
-}
-
-.smartselect.compactmenu .smartselect_submenu.visible {
-    display: block;
-}
-
-.smartselect.compactmenu .smartselect_menu {
-    z-index: 1000;
-    overflow: hidden;
-}
-
-.smartselect.compactmenu .smartselect_submenu .smartselect_submenu {
-    z-index: 1020;
-}
-
-.smartselect.compactmenu .smartselect_submenuitem:hover > .smartselect_menuitem_label {
-    font-weight: bold;
-}
 
 /**
 * Enrol
index 326c205..15b2c39 100644 (file)
@@ -73,13 +73,13 @@ if ($ADMIN->fulltree) {
     $page = new admin_settingpage('theme_boost_advanced', get_string('advancedsettings', 'theme_boost'));
 
     // Raw SCSS to include before the content.
-    $setting = new admin_setting_configtextarea('theme_boost/scsspre',
+    $setting = new admin_setting_scsscode('theme_boost/scsspre',
         get_string('rawscsspre', 'theme_boost'), get_string('rawscsspre_desc', 'theme_boost'), '', PARAM_RAW);
     $setting->set_updatedcallback('theme_reset_all_caches');
     $page->add($setting);
 
     // Raw SCSS to include after the content.
-    $setting = new admin_setting_configtextarea('theme_boost/scss', get_string('rawscss', 'theme_boost'),
+    $setting = new admin_setting_scsscode('theme_boost/scss', get_string('rawscss', 'theme_boost'),
         get_string('rawscss_desc', 'theme_boost'), '', PARAM_RAW);
     $setting->set_updatedcallback('theme_reset_all_caches');
     $page->add($setting);
index 918f272..d22db82 100644 (file)
@@ -7,7 +7,7 @@
         <input type="hidden" name="{{element.name}}" value="{{element.frozenvalue}}">
     {{/element.frozen}}
 {{/element.hardfrozen}}
-<input type="checkbox" name="{{element.name}}"
+<input type="checkbox" name="{{element.name}}" class="{{element.extraclasses}}"
     id="{{element.id}}"
     {{#element.selectedvalue}}
         value="{{element.selectedvalue}}"
index a6cb35c..8ec8fe9 100644 (file)
@@ -18,6 +18,7 @@
         {{/element.hardfrozen}}
         <input type="checkbox"
             name="{{element.name}}"
+            class="{{element.extraclasses}}"
             {{#element.selectedvalue}}
                 value="{{element.selectedvalue}}"
             {{/element.selectedvalue}}
index 8e098f0..150d2a0 100644 (file)
@@ -4,7 +4,7 @@
         <input type="hidden" name="{{element.name}}" value="{{element.frozenvalue}}">
     {{/element.frozen}}
 {{/element.hardfrozen}}
-<input type="checkbox" name="{{element.name}}"
+<input type="checkbox" name="{{element.name}}" class="{{element.extraclasses}}"
     id="{{element.id}}"
     {{#element.value}}
         value="{{element.value}}"
index 3a63cc4..ad55331 100644 (file)
@@ -15,6 +15,7 @@
         {{/element.hardfrozen}}
         <input type="checkbox"
             name="{{element.name}}"
+            class="{{element.extraclasses}}"
             {{#element.value}}
                 value="{{element.value}}"
             {{/element.value}}
index ea2ac8e..bc20577 100644 (file)
@@ -934,89 +934,7 @@ tr.flagged-tag a {
     text-align: left;
     border: 0 solid black;
 }
-/**
-* Smart Select Element
-*/
-.smartselect {
-    position: absolute;
-}
-.smartselect .smartselect_mask {
-    background-color: #fff;
-}
-.smartselect ul {
-    padding: 0;
-    margin: 0;
-}
-.smartselect ul li {
-    list-style: none;
-}
-.smartselect .smartselect_menu {
-    margin-right: 5px;
-}
-.safari .smartselect .smartselect_menu {
-    margin-left: 2px;
-}
-.smartselect .smartselect_menu,
-.smartselect .smartselect_submenu {
-    border: 1px solid #000;
-    background-color: #fff;
-    display: none;
-}
-.smartselect .smartselect_menu.visible,
-.smartselect .smartselect_submenu.visible {
-    display: block;
-}
-.smartselect .smartselect_menu_content ul li {
-    position: relative;
-    padding: 2px 5px;
-}
-.smartselect .smartselect_menu_content ul li a {
-    color: #333;
-    text-decoration: none;
-}
-.smartselect .smartselect_menu_content ul li a.selectable {
-    color: inherit;
-}
-.smartselect .smartselect_submenuitem {
-    background-image: url([[pix:moodle|t/collapsed]]);
-    background-repeat: no-repeat;
-    background-position: 100%;
-}
-/** Spanning mode */
-.smartselect.spanningmenu .smartselect_submenu {
-    position: absolute;
-    top: -1px;
-    left: 100%;
-}
-.smartselect.spanningmenu .smartselect_submenu a {
-    white-space: nowrap;
-    padding-right: 16px;
-}
-.smartselect.spanningmenu .smartselect_menu_content ul li a.selectable:hover {
-    text-decoration: underline;
-}
-/** Compact mode */
-.smartselect.compactmenu .smartselect_submenu {
-    position: relative;
-    margin: 2px -3px;
-    margin-left: 10px;
-    display: none;
-    border-width: 0;
-    z-index: 1010;
-}
-.smartselect.compactmenu .smartselect_submenu.visible {
-    display: block;
-}
-.smartselect.compactmenu .smartselect_menu {
-    z-index: 1000;
-    overflow: hidden;
-}
-.smartselect.compactmenu .smartselect_submenu .smartselect_submenu {
-    z-index: 1020;
-}
-.smartselect.compactmenu .smartselect_submenuitem:hover > .smartselect_menuitem_label {
-    font-weight: bold;
-}
+
 /**
 * Registration
 */
index 677e340..d09a3c3 100644 (file)
@@ -895,89 +895,6 @@ tr.flagged-tag a {
   border: 0 solid black;
 }
 /**
-* Smart Select Element
-*/
-.smartselect {
-  position: absolute;
-}
-.smartselect .smartselect_mask {
-  background-color: #fff;
-}
-.smartselect ul {
-  padding: 0;
-  margin: 0;
-}
-.smartselect ul li {
-  list-style: none;
-}
-.smartselect .smartselect_menu {
-  margin-right: 5px;
-}
-.safari .smartselect .smartselect_menu {
-  margin-left: 2px;
-}
-.smartselect .smartselect_menu,
-.smartselect .smartselect_submenu {
-  border: 1px solid #000;
-  background-color: #fff;
-  display: none;
-}
-.smartselect .smartselect_menu.visible,
-.smartselect .smartselect_submenu.visible {
-  display: block;
-}
-.smartselect .smartselect_menu_content ul li {
-  position: relative;
-  padding: 2px 5px;
-}
-.smartselect .smartselect_menu_content ul li a {
-  color: #333;
-  text-decoration: none;
-}
-.smartselect .smartselect_menu_content ul li a.selectable {
-  color: inherit;
-}
-.smartselect .smartselect_submenuitem {
-  background-image: url([[pix:moodle|t/collapsed]]);
-  background-repeat: no-repeat;
-  background-position: 100%;
-}
-/** Spanning mode */
-.smartselect.spanningmenu .smartselect_submenu {
-  position: absolute;
-  top: -1px;
-  left: 100%;
-}
-.smartselect.spanningmenu .smartselect_submenu a {
-  white-space: nowrap;
-  padding-right: 16px;
-}
-.smartselect.spanningmenu .smartselect_menu_content ul li a.selectable:hover {
-  text-decoration: underline;
-}
-/** Compact mode */
-.smartselect.compactmenu .smartselect_submenu {
-  position: relative;
-  margin: 2px -3px;
-  margin-left: 10px;
-  display: none;
-  border-width: 0;
-  z-index: 1010;
-}
-.smartselect.compactmenu .smartselect_submenu.visible {
-  display: block;
-}
-.smartselect.compactmenu .smartselect_menu {
-  z-index: 1000;
-  overflow: hidden;
-}
-.smartselect.compactmenu .smartselect_submenu .smartselect_submenu {
-  z-index: 1020;
-}
-.smartselect.compactmenu .smartselect_submenuitem:hover > .smartselect_menuitem_label {
-  font-weight: bold;
-}
-/**
 * Registration
 */
 #page-admin-registration-register .registration_textfield {
index bb1ea9a..e3914df 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2016122200.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2016122800.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.