Merge branch 'MDL-54741-master' of git://github.com/mihailges/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Tue, 7 Aug 2018 04:19:44 +0000 (12:19 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Tue, 7 Aug 2018 04:19:44 +0000 (12:19 +0800)
24 files changed:
Gruntfile.js
admin/registration/index.php
admin/tool/dataprivacy/db/upgrade.php [new file with mode: 0644]
admin/tool/dataprivacy/version.php
lang/en/hub.php
lib/classes/event/message_sent.php
lib/classes/hub/api.php
lib/classes/hub/registration.php
lib/classes/hub/site_unregistration_form.php
lib/classes/message/manager.php
lib/messagelib.php
lib/upgrade.txt
message/tests/events_test.php
mod/lti/service/memberships/classes/local/resources/linkmemberships.php
question/type/ddwtos/tests/edit_form_test.php [new file with mode: 0644]
question/type/gapselect/edit_form_base.php
question/type/gapselect/edit_gapselect_form.php
question/type/gapselect/tests/edit_form_test.php
repository/coursefiles/pix/icon.svg [new file with mode: 0644]
repository/local/pix/icon.svg [new file with mode: 0644]
repository/recent/pix/icon.svg [new file with mode: 0644]
repository/user/pix/icon.svg [new file with mode: 0644]
theme/boost/scss/moodle/undo.scss
theme/boost/style/moodle.css

index 4501fc6..78583d0 100644 (file)
@@ -37,7 +37,7 @@ module.exports = function(grunt) {
     var expected = semver.validRange(grunt.file.readJSON('package.json').engines.node);
     var actual = semver.valid(process.version);
     if (!semver.satisfies(actual, expected)) {
-        grunt.fail.fatal('Node version too old. Require ' + expected + ', version installed: ' + actual);
+        grunt.fail.fatal('Node version not satisfied. Require ' + expected + ', version installed: ' + actual);
     }
 
     // Windows users can't run grunt in a subdirectory, so allow them to set
index 57d65a3..62f251a 100644 (file)
@@ -40,8 +40,9 @@ if ($unregistration && \core\hub\registration::is_registered()) {
     if ($siteunregistrationform->is_cancelled()) {
         redirect(new moodle_url('/admin/registration/index.php'));
     } else if ($data = $siteunregistrationform->get_data()) {
-        if (\core\hub\registration::unregister($data->unpublishalladvertisedcourses,
-            $data->unpublishalluploadedcourses)) {
+        \core\hub\registration::unregister($data->unpublishalladvertisedcourses,
+            $data->unpublishalluploadedcourses);
+        if (!\core\hub\registration::is_registered()) {
             redirect(new moodle_url('/admin/registration/index.php'));
         }
     }
diff --git a/admin/tool/dataprivacy/db/upgrade.php b/admin/tool/dataprivacy/db/upgrade.php
new file mode 100644 (file)
index 0000000..8c0b4fc
--- /dev/null
@@ -0,0 +1,149 @@
+<?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/>.
+
+/**
+ * tool_dataprivacy plugin upgrade code
+ *
+ * @package    tool_dataprivacy
+ * @copyright  2018 Jun Pataleta
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Function to upgrade tool_dataprivacy.
+ *
+ * @param int $oldversion the version we are upgrading from
+ * @return bool result
+ */
+function xmldb_tool_dataprivacy_upgrade($oldversion) {
+    global $CFG, $DB;
+
+    $dbman = $DB->get_manager();
+
+    if ($oldversion < 2018051405) {
+        // Define table tool_dataprivacy_ctxexpired to be created.
+        $table = new xmldb_table('tool_dataprivacy_ctxexpired');
+
+        // Adding fields to table tool_dataprivacy_ctxexpired.
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('status', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+
+        // Adding keys to table tool_dataprivacy_ctxexpired.
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_key('contextid', XMLDB_KEY_FOREIGN_UNIQUE, array('contextid'), 'context', array('id'));
+
+        // Conditionally launch create table for tool_dataprivacy_ctxexpired.
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define table tool_dataprivacy_contextlist to be created.
+        $table = new xmldb_table('tool_dataprivacy_contextlist');
+
+        // Adding fields to table tool_dataprivacy_contextlist.
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('component', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+
+        // Adding keys to table tool_dataprivacy_contextlist.
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+        // Conditionally launch create table for tool_dataprivacy_contextlist.
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define table tool_dataprivacy_ctxlst_ctx to be created.
+        $table = new xmldb_table('tool_dataprivacy_ctxlst_ctx');
+
+        // Adding fields to table tool_dataprivacy_ctxlst_ctx.
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('contextlistid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('status', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+
+        // Adding keys to table tool_dataprivacy_ctxlst_ctx.
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_key('contextlistid', XMLDB_KEY_FOREIGN, array('contextlistid'), 'tool_dataprivacy_contextlist', array('id'));
+
+        // Conditionally launch create table for tool_dataprivacy_ctxlst_ctx.
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define table tool_dataprivacy_rqst_ctxlst to be created.
+        $table = new xmldb_table('tool_dataprivacy_rqst_ctxlst');
+
+        // Adding fields to table tool_dataprivacy_rqst_ctxlst.
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('requestid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('contextlistid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+
+        // Adding keys to table tool_dataprivacy_rqst_ctxlst.
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_key('requestid', XMLDB_KEY_FOREIGN, array('requestid'), 'tool_dataprivacy_request', array('id'));
+        $table->add_key('contextlistid', XMLDB_KEY_FOREIGN, array('contextlistid'), 'tool_dataprivacy_contextlist', array('id'));
+        $table->add_key('request_contextlist', XMLDB_KEY_UNIQUE, array('requestid', 'contextlistid'));
+
+        // Conditionally launch create table for tool_dataprivacy_rqst_ctxlst.
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define field lawfulbases to be added to tool_dataprivacy_purpose.
+        $table = new xmldb_table('tool_dataprivacy_purpose');
+
+        // It is a required field. We initially define and add it as null and later update it to XMLDB_NOTNULL.
+        $field = new xmldb_field('lawfulbases', XMLDB_TYPE_TEXT, null, null, null, null, null, 'descriptionformat');
+
+        // Conditionally launch add field lawfulbases.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+
+            // Set a kind-of-random value to lawfulbasis field.
+            $DB->set_field('tool_dataprivacy_purpose', 'lawfulbases', 'gdpr_art_6_1_a');
+
+            // We redefine it now as not null.
+            $field = new xmldb_field('lawfulbases', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'descriptionformat');
+
+            // Launch change of nullability for field lawfulbases.
+            $dbman->change_field_notnull($table, $field);
+        }
+
+        // Define field sensitivedatareasons to be added to tool_dataprivacy_purpose.
+        $table = new xmldb_table('tool_dataprivacy_purpose');
+        $field = new xmldb_field('sensitivedatareasons', XMLDB_TYPE_TEXT, null, null, null, null, null, 'lawfulbases');
+
+        // Conditionally launch add field sensitivedatareasons.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Dataprivacy savepoint reached.
+        upgrade_plugin_savepoint(true, 2018051405, 'tool', 'dataprivacy');
+    }
+
+    return true;
+}
index f2cf6d1..f5c7977 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2018051403;
+$plugin->version   = 2018051405;
 $plugin->requires  = 2018050800;        // Moodle 3.5dev (Build 2018031600) and upwards.
 $plugin->component = 'tool_dataprivacy';
index 4a9937d..2e2bcf7 100644 (file)
@@ -80,6 +80,7 @@ $string['errorotherhubsnotsupported'] = 'This page can no longer be used for reg
 $string['errorregistration'] = 'An error occurred during registration, please try again later. ({$a})';
 $string['errorunpublishcourses'] = 'Due to an unexpected error, the courses could not be deleted from Moodle.net. Try again later (recommended) or contact Moodle.net administrator.';
 $string['errorws'] = '{$a}';
+$string['errorwstokenreset'] = '{$a}. Registration token on this site has been reset. You can now register your site again.';
 $string['existingscreenshotnumber'] = '{$a} existing screenshots. You will be able to see these screenshots on this page, only once the Moodle.net administrator enables your course.';
 $string['errorregistrationupdate'] = 'An error occurred during registration update ({$a})';
 $string['existingscreenshots'] = 'Existing screenshots';
@@ -210,6 +211,7 @@ $string['update'] = 'Update';
 $string['updatesite'] = 'Update registration on {$a}';
 $string['updatestatus'] = 'Check it now.';
 $string['usedifferentemail'] = 'Use different email';
+$string['unregisterexplained'] = 'If the site with URL {$a} is registered on Moodle.net its registration will be removed.';
 $string['urlalreadyregistered'] = 'Your site seems to be already registered on Moodle.net, which means something has gone wrong. Please contact the Moodle.net administrator to reset your registration so you can try again.';
 $string['usersnumber'] = 'Number of users ({$a})';
 $string['wrongtoken'] = 'The registration failed for some unknown reason (network?). Please try again.';
index 9b3a8c5..0bfe22c 100644 (file)
@@ -43,14 +43,13 @@ defined('MOODLE_INTERNAL') || die();
 class message_sent extends base {
     /**
      * Create event using ids.
-     * @todo MDL-55449 Make $courseid mandatory in Moodle 3.6
      * @param int $userfromid
      * @param int $usertoid
      * @param int $messageid
-     * @param int|null $courseid course id the event is related with. Use SITEID if no relation exists.
+     * @param int $courseid course id the event is related with.
      * @return message_sent
      */
-    public static function create_from_ids($userfromid, $usertoid, $messageid, $courseid = null) {
+    public static function create_from_ids(int $userfromid, int $usertoid, int $messageid, int $courseid) {
         // We may be sending a message from the 'noreply' address, which means we are not actually sending a
         // message from a valid user. In this case, we will set the userid to 0.
         // Check if the userid is valid.
@@ -58,15 +57,6 @@ class message_sent extends base {
             $userfromid = 0;
         }
 
-        // TODO: MDL-55449 Make $courseid mandatory in Moodle 3.6.
-        if (is_null($courseid)) {
-            // Arrived here with not defined $courseid to associate the event with.
-            // Let's default to SITEID and perform debugging so devs are aware. MDL-47162.
-            $courseid = SITEID;
-            debugging('message_sent::create_from_ids() needs a $courseid to be passed, nothing was detected. Please, change ' .
-                    'the call to include it, using SITEID if the message is unrelated to any real course.', DEBUG_DEVELOPER);
-        }
-
         $event = self::create(array(
             'objectid' => $messageid,
             'userid' => $userfromid,
index 2c66b58..75a0508 100644 (file)
@@ -91,10 +91,11 @@ class api {
         $curloutput = @json_decode($curl->get($serverurl, $params), true);
         $info = $curl->get_info();
         if ($curl->get_errno()) {
+            // Connection error.
             throw new moodle_exception('errorconnect', 'hub', '', $curl->error);
         } else if (isset($curloutput['exception'])) {
-            // Error message returned by web service.
-            throw new moodle_exception('errorws', 'hub', '', $curloutput['message']);
+            // Exception occurred on moodle.net .
+            self::process_curl_exception($token, $curloutput);
         } else if ($info['http_code'] != 200) {
             throw new moodle_exception('errorconnect', 'hub', '', $info['http_code']);
         } else {
@@ -102,6 +103,29 @@ class api {
         }
     }
 
+    /**
+     * Analyses exception received from moodle.net
+     *
+     * @param string $token token used for CURL request
+     * @param array $curloutput output from CURL request
+     * @throws moodle_exception
+     */
+    protected static function process_curl_exception($token, $curloutput) {
+        if (!isset($curloutput['exception'])) {
+            return;
+        }
+        if ($token === registration::get_token()) {
+            // Check if registration token was rejected or there are other problems with registration.
+            if (($curloutput['exception'] === 'moodle_exception' && $curloutput['errorcode'] === 'invalidtoken')
+                    || $curloutput['exception'] === 'registration_exception') {
+                // Force admin to repeat site registration process.
+                registration::reset_token();
+                throw new moodle_exception('errorwstokenreset', 'hub', '', $curloutput['message']);
+            }
+        }
+        throw new moodle_exception('errorws', 'hub', '', $curloutput['message']);
+    }
+
     /**
      * Update site registration on moodle.net
      *
@@ -109,7 +133,7 @@ class api {
      * @throws moodle_exception
      */
     public static function update_registration(array $siteinfo) {
-        $params = array('siteinfo' => $siteinfo);
+        $params = array('siteinfo' => $siteinfo, 'validateurl' => 1);
         self::call('hub_update_site_info', $params);
     }
 
@@ -276,7 +300,8 @@ class api {
      * @throws moodle_exception
      */
     public static function unregister_site() {
-        self::call('hub_unregister_site');
+        global $CFG;
+        self::call('hub_unregister_site', ['url' => [$CFG->wwwroot]]);
     }
 
     /**
index dc09ffb..823e47f 100644 (file)
@@ -275,6 +275,11 @@ class registration {
         try {
             api::update_registration($siteinfo);
         } catch (moodle_exception $e) {
+            if (!self::is_registered()) {
+                // Token was rejected during registration update and site and locally stored token was reset,
+                // proceed to site registration. This method will redirect away.
+                self::register('');
+            }
             \core\notification::add(get_string('errorregistrationupdate', 'hub', $e->getMessage()),
                 \core\output\notification::NOTIFY_ERROR);
             return false;
@@ -428,6 +433,20 @@ class registration {
         return true;
     }
 
+    /**
+     * Resets the registration token without changing site identifier so site can be re-registered
+     *
+     * @return bool
+     */
+    public static function reset_token() {
+        global $DB;
+        if (!$hub = self::get_registration()) {
+            return true;
+        }
+        $DB->delete_records('registration_hubs', array('id' => $hub->id));
+        self::$registration = null;
+    }
+
     /**
      * Generate a new token for the site that is not registered
      *
index ed4116a..70fc070 100644 (file)
@@ -42,6 +42,7 @@ class site_unregistration_form extends \moodleform {
      * Form definition
      */
     public function definition() {
+        global $CFG;
         $mform = & $this->_form;
         $mform->addElement('header', 'site', get_string('unregister', 'hub'));
 
@@ -56,6 +57,8 @@ class site_unregistration_form extends \moodleform {
         $mform->addElement('hidden', 'unregistration', 1);
         $mform->setType('unregistration', PARAM_INT);
 
+        $mform->addElement('static', 'explanation', '', get_string('unregisterexplained', 'hub', $CFG->wwwroot));
+
         $this->add_action_buttons(true, $unregisterlabel);
     }
 }
index c05e14d..17192f3 100644 (file)
@@ -50,30 +50,14 @@ class manager {
      *
      * NOTE: to be used from message_send() only.
      *
-     * @todo MDL-55449 Drop support for stdClass in Moodle 3.6
      * @param \core\message\message $eventdata fully prepared event data for processors
      * @param \stdClass $savemessage the message saved in 'message' table
      * @param array $processorlist list of processors for target user
      * @return int $messageid the id from 'messages' (false is not returned)
      */
-    public static function send_message($eventdata, \stdClass $savemessage, array $processorlist) {
+    public static function send_message(message $eventdata, \stdClass $savemessage, array $processorlist) {
         global $CFG;
 
-        // TODO MDL-55449 Drop support for stdClass in Moodle 3.6.
-        if (!($eventdata instanceof \stdClass) && !($eventdata instanceof message)) {
-            // Not a valid object.
-            throw new \coding_exception('Message should be of type stdClass or \core\message\message');
-        }
-
-        // TODO MDL-55449 Drop support for stdClass in Moodle 3.6.
-        if ($eventdata instanceof \stdClass) {
-            if (!isset($eventdata->courseid)) {
-                $eventdata->courseid = null;
-            }
-
-            debugging('eventdata as \stdClass is deprecated. Please use \core\message\message instead.', DEBUG_DEVELOPER);
-        }
-
         require_once($CFG->dirroot.'/message/lib.php'); // This is most probably already included from messagelib.php file.
 
         if (empty($processorlist)) {
index 0b5d300..060e508 100644 (file)
@@ -50,23 +50,13 @@ require_once(__DIR__ . '/../message/lib.php');
  * Note: processor failure is is not reported as false return value,
  *       earlier versions did not do it consistently either.
  *
- * @todo MDL-55449 Drop support for stdClass in Moodle 3.6
  * @category message
  * @param \core\message\message $eventdata information about the message (component, userfrom, userto, ...)
  * @return mixed the integer ID of the new message or false if there was a problem with submitted data
  */
-function message_send($eventdata) {
+function message_send(\core\message\message $eventdata) {
     global $CFG, $DB;
 
-    // TODO MDL-55449 Drop support for stdClass in Moodle 3.6.
-    if ($eventdata instanceof \stdClass) {
-        if (!isset($eventdata->courseid)) {
-            $eventdata->courseid = null;
-        }
-
-        debugging('eventdata as \stdClass is deprecated. Please use core\message\message instead.', DEBUG_DEVELOPER);
-    }
-
     //new message ID to return
     $messageid = false;
 
index b79b0cc..83198af 100644 (file)
@@ -67,6 +67,10 @@ information provided here is intended especially for developers.
   policy and respect the privacy setting made by site administrators. The list of user identifiers should never be
   hard-coded. Instead, the setting $CFG->showuseridentity should be always respected, which has always been the default
   behaviour (MDL-59847).
+* The function message_send() in messagelib.php will now only take the object \core\message\message as a parameter.
+* The method message_sent::create_from_ids() parameter courseid is now required. A debugging
+  message was previously displayed, and the SITEID was used, when not provided.
+* The method \core\message\manager::send_message() now only takes the object \core\message\message as the first parameter.
 
 === 3.5 ===
 
index 9c9c415..3f63ed0 100644 (file)
@@ -272,22 +272,6 @@ class core_message_events_testcase extends core_message_messagelib_testcase {
         $this->assertEquals(4, $event->other['courseid']);
     }
 
-    public function test_mesage_sent_via_create_from_ids_without_other_courseid() {
-
-        // Creating a message_sent event without courseid leads to debugging + SITEID.
-        // TODO: MDL-55449 Ensure this leads to exception instead of debugging in Moodle 3.6.
-        $event = \core\event\message_sent::create_from_ids(1, 2, 3);
-
-        // Trigger and capturing the event.
-        $sink = $this->redirectEvents();
-        $event->trigger();
-        $events = $sink->get_events();
-        $event = reset($events);
-
-        $this->assertDebuggingCalled();
-        $this->assertEquals(SITEID, $event->other['courseid']);
-    }
-
     /**
      * Test the message viewed event.
      */
index 621a3dd..bcbb01a 100644 (file)
@@ -146,7 +146,7 @@ class linkmemberships extends resource_base {
      */
     public function parse_value($value) {
 
-        if (strpos($value, '$ToolProxyBinding.memberships.url') !== false) {
+        if (strpos($value, '$LtiLink.memberships.url') !== false) {
             $id = optional_param('id', 0, PARAM_INT); // Course Module ID.
             if (!empty($id)) {
                 $cm = get_coursemodule_from_id('lti', $id, 0, false, MUST_EXIST);
diff --git a/question/type/ddwtos/tests/edit_form_test.php b/question/type/ddwtos/tests/edit_form_test.php
new file mode 100644 (file)
index 0000000..0e462aa
--- /dev/null
@@ -0,0 +1,81 @@
+<?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/>.
+
+/**
+ * Unit tests for the drag-and-drop words into sentences edit form.
+ *
+ * @package   qtype_ddwtos
+ * @copyright 2018 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+global $CFG;
+
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+require_once($CFG->dirroot . '/question/type/edit_question_form.php');
+require_once($CFG->dirroot . '/question/type/ddwtos/edit_ddwtos_form.php');
+
+/**
+ * Unit tests for the drag-and-drop words into sentences edit form.
+ *
+ * @copyright  2012 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qtype_ddwtos_edit_form_test extends advanced_testcase {
+    /**
+     * Helper method.
+     *
+     * @param string $classname the question form class to instantiate.
+     *
+     * @return question_edit_form great a question form instance that can be tested.
+     */
+    protected function get_form($classname) {
+        $this->setAdminUser();
+        $this->resetAfterTest();
+
+        $syscontext = context_system::instance();
+        $category = question_make_default_categories(array($syscontext));
+        $fakequestion = new stdClass();
+        $fakequestion->qtype = 'stack';
+        $fakequestion->contextid = $syscontext->id;
+        $fakequestion->createdby = 2;
+        $fakequestion->category = $category->id;
+        $fakequestion->questiontext = 'Test [[1]] question [[2]]';
+        $fakequestion->options = new stdClass();
+        $fakequestion->options->answers = array();
+        $fakequestion->formoptions = new stdClass();
+        $fakequestion->formoptions->movecontext = null;
+        $fakequestion->formoptions->repeatelements = true;
+        $fakequestion->inputs = null;
+        return new $classname(new moodle_url('/'), $fakequestion, $category,
+                new question_edit_contexts($syscontext));
+    }
+
+    /**
+     * Test the form shows the right number of groups of choices.
+     */
+    public function test_number_of_choice_groups() {
+        $form = $this->get_form('qtype_ddwtos_edit_form');
+        // Use reflection to get the protected property we need.
+        $property = new ReflectionProperty('qtype_ddwtos_edit_form', '_form');
+        $property->setAccessible(true);
+        $mform = $property->getValue($form);
+        $choices = $mform->getElement('choices[0]');
+        $groupoptions = $choices->_elements[1];
+        $this->assertCount(8, $groupoptions->_options);
+    }
+}
index ed5e516..bd26c77 100644 (file)
@@ -32,10 +32,6 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class qtype_gapselect_edit_form_base extends question_edit_form {
-    /**
-     * Maximum number of different groups of drag items there can be in a question.
-     */
-    const MAX_GROUPS = 8;
 
     /** @var array of HTML tags allowed in choices / drag boxes. */
     protected $allowedhtmltags = array(
@@ -166,15 +162,25 @@ class qtype_gapselect_edit_form_base extends question_edit_form {
                 get_string('addmorechoiceblanks', 'qtype_gapselect'), true);
     }
 
+    /**
+     * Return how many different groups of choices there should be.
+     *
+     * @return int the maximum group number.
+     */
+    function get_maximum_choice_group_number() {
+        return 8;
+    }
+
     /**
      * Creates an array with elements for a choice group.
      *
      * @param object $mform The Moodle form we are working with
+     * @param int $maxgroup The number of max group generate element select.
      * @return array Array for form elements
      */
     protected function choice_group($mform) {
         $options = array();
-        for ($i = 1; $i <= self::MAX_GROUPS; $i += 1) {
+        for ($i = 1; $i <= $this->get_maximum_choice_group_number(); $i += 1) {
             $options[$i] = $i;
         }
         $grouparray = array();
index c159a3f..c39c8cc 100644 (file)
@@ -41,4 +41,8 @@ class qtype_gapselect_edit_form extends qtype_gapselect_edit_form_base {
     public function qtype() {
         return 'gapselect';
     }
+
+    function get_maximum_choice_group_number() {
+        return 20;
+    }
 }
index 7c6dc38..6c42735 100644 (file)
@@ -15,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Unit tests for the select missing words question definition class.
+ * Unit tests for the select missing words question edit form.
  *
  * @package   qtype_gapselect
  * @copyright 2012 The Open University
@@ -28,7 +28,7 @@ global $CFG;
 
 require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
 require_once($CFG->dirroot . '/question/type/edit_question_form.php');
-require_once($CFG->dirroot . '/question/type/gapselect/edit_form_base.php');
+require_once($CFG->dirroot . '/question/type/gapselect/edit_gapselect_form.php');
 
 
 /**
@@ -38,25 +38,6 @@ require_once($CFG->dirroot . '/question/type/gapselect/edit_form_base.php');
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class qtype_gapselect_edit_form_base_testable extends qtype_gapselect_edit_form_base {
-    public function __construct() {
-        $syscontext = context_system::instance();
-        $category = question_make_default_categories(array($syscontext));
-        $fakequestion = new stdClass();
-        $fakequestion->qtype = 'stack';
-        $fakequestion->contextid = $syscontext->id;
-        $fakequestion->createdby = 2;
-        $fakequestion->category = $category->id;
-        $fakequestion->questiontext = 'Test [[1]] question [[2]]';
-        $fakequestion->options = new stdClass();
-        $fakequestion->options->answers = array();
-        $fakequestion->formoptions = new stdClass();
-        $fakequestion->formoptions->movecontext = null;
-        $fakequestion->formoptions->repeatelements = true;
-        $fakequestion->inputs = null;
-        parent::__construct(new moodle_url('/'), $fakequestion, $category,
-                new question_edit_contexts($syscontext));
-    }
-
     public function get_illegal_tag_error($text) {
         return parent::get_illegal_tag_error($text);
     }
@@ -72,7 +53,7 @@ class qtype_gapselect_edit_form_base_testable extends qtype_gapselect_edit_form_
 
 
 /**
- * Unit tests for Stack question editing form.
+ * Unit tests for select missing words question edit form.
  *
  * @copyright  2012 The Open University
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -81,17 +62,35 @@ class qtype_gapselect_edit_form_test extends advanced_testcase {
 
     /**
      * Helper method.
-     * @return qtype_gapselect_edit_form_base_testable a new form instance that can be tested.
+     *
+     * @param string $classname the question form class to instantiate.
+     *
+     * @return question_edit_form great a question form instance that can be tested.
      */
-    protected function get_form() {
+    protected function get_form($classname) {
         $this->setAdminUser();
         $this->resetAfterTest();
 
-        return new qtype_gapselect_edit_form_base_testable();
+        $syscontext = context_system::instance();
+        $category = question_make_default_categories(array($syscontext));
+        $fakequestion = new stdClass();
+        $fakequestion->qtype = 'stack';
+        $fakequestion->contextid = $syscontext->id;
+        $fakequestion->createdby = 2;
+        $fakequestion->category = $category->id;
+        $fakequestion->questiontext = 'Test [[1]] question [[2]]';
+        $fakequestion->options = new stdClass();
+        $fakequestion->options->answers = array();
+        $fakequestion->formoptions = new stdClass();
+        $fakequestion->formoptions->movecontext = null;
+        $fakequestion->formoptions->repeatelements = true;
+        $fakequestion->inputs = null;
+        return new $classname(new moodle_url('/'), $fakequestion, $category,
+                new question_edit_contexts($syscontext));
     }
 
     public function test_get_illegal_tag_error() {
-        $form = $this->get_form();
+        $form = $this->get_form('qtype_gapselect_edit_form_base_testable');
 
         $this->assertEquals('', $form->get_illegal_tag_error('frog'));
         $this->assertEquals('', $form->get_illegal_tag_error('<i>toad</i>'));
@@ -127,4 +126,18 @@ class qtype_gapselect_edit_form_test extends advanced_testcase {
         $this->assertEquals(get_string('tagsnotallowedatall', 'qtype_gapselect', $a),
                 $form->get_illegal_tag_error('<i><br /></i>'));
     }
+
+    /**
+     * Test the form shows the right number of groups of choices.
+     */
+    public function test_number_of_choice_groups() {
+        $form = $this->get_form('qtype_gapselect_edit_form');
+        // Use reflection to get the protected property we need.
+        $property = new ReflectionProperty('qtype_gapselect_edit_form', '_form');
+        $property->setAccessible(true);
+        $mform = $property->getValue($form);
+        $choices = $mform->getElement('choices[0]');
+        $groupoptions = $choices->_elements[1];
+        $this->assertCount(20, $groupoptions->_options);
+    }
 }
diff --git a/repository/coursefiles/pix/icon.svg b/repository/coursefiles/pix/icon.svg
new file mode 100644 (file)
index 0000000..3011b9f
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="74px" height="51px" viewBox="-0.535 -0.774 74 51"\r
+        style="overflow:visible;enable-background:new -0.535 -0.774 74 51;" xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<radialGradient id="SVGID_1_" cx="137.084" cy="32.2324" r="123.3346" gradientUnits="userSpaceOnUse">\r
+       <stop  offset="0" style="stop-color:#FAAF40"/>\r
+       <stop  offset="0.0432" style="stop-color:#F9A538"/>\r
+       <stop  offset="0.1116" style="stop-color:#F89D31"/>\r
+       <stop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <stop  offset="0.5276" style="stop-color:#F7922D"/>\r
+       <stop  offset="1" style="stop-color:#F37B28"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.1982" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="0.6064" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#F37B28"/>\r
+</radialGradient>\r
+<path style="fill:url(#SVGID_1_);" d="M61.192,49.375V26.558c0-4.771-1.972-7.156-5.911-7.156c-3.942,0-5.912,2.386-5.912,7.156\r
+       v22.817H37.754V26.558c0-4.771-1.938-7.156-5.811-7.156c-3.94,0-5.91,2.386-5.91,7.156v22.817H14.417V25.211\r
+       c0-4.979,1.728-8.747,5.185-11.304c3.043-2.282,7.158-3.425,12.343-3.425c5.255,0,9.127,1.349,11.617,4.045\r
+       c2.142-2.696,6.049-4.045,11.72-4.045c5.186,0,9.298,1.143,12.341,3.425c3.457,2.557,5.186,6.325,5.186,11.304v24.164H61.192z"/>\r
+<path style="fill:#58595B;" d="M15.499,16.321c-0.394,1.999-0.788,3.999-1.181,5.997c10.983,3.72,21.4,0.111,26.883-9.489\r
+       C33.184,7.282,25.601,12.914,15.499,16.321"/>\r
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="14.4287" y1="16.0166" x2="40.6895" y2="16.0166">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_2_);" d="M15.499,14.889c-0.356,2.259-0.714,4.518-1.07,6.776c10.527,3.567,20.84,0.503,26.261-8.944\r
+       C33.708,4.677,25.925,11.373,15.499,14.889"/>\r
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="19.457" y1="7.248" x2="30.3611" y2="22.8207">\r
+       <stop  offset="0" style="stop-color:#231F20"/>\r
+       <stop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0.5" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_3_);" d="M27.993,17.575c-4.764-0.997-10.036,1.485-13.564,4.09\r
+       C12.103,4.879,22.536,5.222,36.098,9.415c-0.857,4.143-2.387,9.598-5.017,12.903C31.081,20.182,30.052,18.6,27.993,17.575"/>\r
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="0.0078" y1="7.7275" x2="48.0068" y2="7.7275">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_4_);" d="M0.008,14.889C17.625,4.318,27.468,2.282,48.007,0.202\r
+       C24.279,18.919,23.64,14.889,0.008,14.889"/>\r
+<line style="fill:#383738;stroke:#4A4A4C;stroke-width:0.5;" x1="48.007" y1="0.202" x2="29.186" y2="13.948"/>\r
+<path style="opacity:0.23;fill:#231F20;" d="M25.506,7.567C25.733,9.723,25.286,5.423,25.506,7.567"/>\r
+<line style="fill:#FFFFFF;stroke:#A8ABAD;stroke-width:0.5;" x1="0.008" y1="14.889" x2="29.186" y2="13.948"/>\r
+<path style="fill:none;stroke:#F16922;stroke-width:0.5;" d="M23.79,7.733c-4.996,1.381-21.387,5.041-21.64,7.086\r
+       c-0.483,3.917-0.123,10.143-0.123,10.143"/>\r
+<path style="fill:#F16922;" d="M3.532,39.84C1.697,35.389-0.443,30.363,2.1,24.184C3.794,29.957,3.544,34.362,3.532,39.84"/>\r
+<ellipse transform="matrix(0.942 -0.3356 0.3356 0.942 -1.1544 8.1596)" style="fill:#6D6E70;" cx="23.032" cy="7.42" rx="0.792" ry="0.411"/>\r
+</svg>\r
diff --git a/repository/local/pix/icon.svg b/repository/local/pix/icon.svg
new file mode 100644 (file)
index 0000000..3011b9f
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="74px" height="51px" viewBox="-0.535 -0.774 74 51"\r
+        style="overflow:visible;enable-background:new -0.535 -0.774 74 51;" xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<radialGradient id="SVGID_1_" cx="137.084" cy="32.2324" r="123.3346" gradientUnits="userSpaceOnUse">\r
+       <stop  offset="0" style="stop-color:#FAAF40"/>\r
+       <stop  offset="0.0432" style="stop-color:#F9A538"/>\r
+       <stop  offset="0.1116" style="stop-color:#F89D31"/>\r
+       <stop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <stop  offset="0.5276" style="stop-color:#F7922D"/>\r
+       <stop  offset="1" style="stop-color:#F37B28"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.1982" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="0.6064" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#F37B28"/>\r
+</radialGradient>\r
+<path style="fill:url(#SVGID_1_);" d="M61.192,49.375V26.558c0-4.771-1.972-7.156-5.911-7.156c-3.942,0-5.912,2.386-5.912,7.156\r
+       v22.817H37.754V26.558c0-4.771-1.938-7.156-5.811-7.156c-3.94,0-5.91,2.386-5.91,7.156v22.817H14.417V25.211\r
+       c0-4.979,1.728-8.747,5.185-11.304c3.043-2.282,7.158-3.425,12.343-3.425c5.255,0,9.127,1.349,11.617,4.045\r
+       c2.142-2.696,6.049-4.045,11.72-4.045c5.186,0,9.298,1.143,12.341,3.425c3.457,2.557,5.186,6.325,5.186,11.304v24.164H61.192z"/>\r
+<path style="fill:#58595B;" d="M15.499,16.321c-0.394,1.999-0.788,3.999-1.181,5.997c10.983,3.72,21.4,0.111,26.883-9.489\r
+       C33.184,7.282,25.601,12.914,15.499,16.321"/>\r
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="14.4287" y1="16.0166" x2="40.6895" y2="16.0166">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_2_);" d="M15.499,14.889c-0.356,2.259-0.714,4.518-1.07,6.776c10.527,3.567,20.84,0.503,26.261-8.944\r
+       C33.708,4.677,25.925,11.373,15.499,14.889"/>\r
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="19.457" y1="7.248" x2="30.3611" y2="22.8207">\r
+       <stop  offset="0" style="stop-color:#231F20"/>\r
+       <stop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0.5" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_3_);" d="M27.993,17.575c-4.764-0.997-10.036,1.485-13.564,4.09\r
+       C12.103,4.879,22.536,5.222,36.098,9.415c-0.857,4.143-2.387,9.598-5.017,12.903C31.081,20.182,30.052,18.6,27.993,17.575"/>\r
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="0.0078" y1="7.7275" x2="48.0068" y2="7.7275">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_4_);" d="M0.008,14.889C17.625,4.318,27.468,2.282,48.007,0.202\r
+       C24.279,18.919,23.64,14.889,0.008,14.889"/>\r
+<line style="fill:#383738;stroke:#4A4A4C;stroke-width:0.5;" x1="48.007" y1="0.202" x2="29.186" y2="13.948"/>\r
+<path style="opacity:0.23;fill:#231F20;" d="M25.506,7.567C25.733,9.723,25.286,5.423,25.506,7.567"/>\r
+<line style="fill:#FFFFFF;stroke:#A8ABAD;stroke-width:0.5;" x1="0.008" y1="14.889" x2="29.186" y2="13.948"/>\r
+<path style="fill:none;stroke:#F16922;stroke-width:0.5;" d="M23.79,7.733c-4.996,1.381-21.387,5.041-21.64,7.086\r
+       c-0.483,3.917-0.123,10.143-0.123,10.143"/>\r
+<path style="fill:#F16922;" d="M3.532,39.84C1.697,35.389-0.443,30.363,2.1,24.184C3.794,29.957,3.544,34.362,3.532,39.84"/>\r
+<ellipse transform="matrix(0.942 -0.3356 0.3356 0.942 -1.1544 8.1596)" style="fill:#6D6E70;" cx="23.032" cy="7.42" rx="0.792" ry="0.411"/>\r
+</svg>\r
diff --git a/repository/recent/pix/icon.svg b/repository/recent/pix/icon.svg
new file mode 100644 (file)
index 0000000..3011b9f
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="74px" height="51px" viewBox="-0.535 -0.774 74 51"\r
+        style="overflow:visible;enable-background:new -0.535 -0.774 74 51;" xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<radialGradient id="SVGID_1_" cx="137.084" cy="32.2324" r="123.3346" gradientUnits="userSpaceOnUse">\r
+       <stop  offset="0" style="stop-color:#FAAF40"/>\r
+       <stop  offset="0.0432" style="stop-color:#F9A538"/>\r
+       <stop  offset="0.1116" style="stop-color:#F89D31"/>\r
+       <stop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <stop  offset="0.5276" style="stop-color:#F7922D"/>\r
+       <stop  offset="1" style="stop-color:#F37B28"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.1982" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="0.6064" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#F37B28"/>\r
+</radialGradient>\r
+<path style="fill:url(#SVGID_1_);" d="M61.192,49.375V26.558c0-4.771-1.972-7.156-5.911-7.156c-3.942,0-5.912,2.386-5.912,7.156\r
+       v22.817H37.754V26.558c0-4.771-1.938-7.156-5.811-7.156c-3.94,0-5.91,2.386-5.91,7.156v22.817H14.417V25.211\r
+       c0-4.979,1.728-8.747,5.185-11.304c3.043-2.282,7.158-3.425,12.343-3.425c5.255,0,9.127,1.349,11.617,4.045\r
+       c2.142-2.696,6.049-4.045,11.72-4.045c5.186,0,9.298,1.143,12.341,3.425c3.457,2.557,5.186,6.325,5.186,11.304v24.164H61.192z"/>\r
+<path style="fill:#58595B;" d="M15.499,16.321c-0.394,1.999-0.788,3.999-1.181,5.997c10.983,3.72,21.4,0.111,26.883-9.489\r
+       C33.184,7.282,25.601,12.914,15.499,16.321"/>\r
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="14.4287" y1="16.0166" x2="40.6895" y2="16.0166">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_2_);" d="M15.499,14.889c-0.356,2.259-0.714,4.518-1.07,6.776c10.527,3.567,20.84,0.503,26.261-8.944\r
+       C33.708,4.677,25.925,11.373,15.499,14.889"/>\r
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="19.457" y1="7.248" x2="30.3611" y2="22.8207">\r
+       <stop  offset="0" style="stop-color:#231F20"/>\r
+       <stop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0.5" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_3_);" d="M27.993,17.575c-4.764-0.997-10.036,1.485-13.564,4.09\r
+       C12.103,4.879,22.536,5.222,36.098,9.415c-0.857,4.143-2.387,9.598-5.017,12.903C31.081,20.182,30.052,18.6,27.993,17.575"/>\r
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="0.0078" y1="7.7275" x2="48.0068" y2="7.7275">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_4_);" d="M0.008,14.889C17.625,4.318,27.468,2.282,48.007,0.202\r
+       C24.279,18.919,23.64,14.889,0.008,14.889"/>\r
+<line style="fill:#383738;stroke:#4A4A4C;stroke-width:0.5;" x1="48.007" y1="0.202" x2="29.186" y2="13.948"/>\r
+<path style="opacity:0.23;fill:#231F20;" d="M25.506,7.567C25.733,9.723,25.286,5.423,25.506,7.567"/>\r
+<line style="fill:#FFFFFF;stroke:#A8ABAD;stroke-width:0.5;" x1="0.008" y1="14.889" x2="29.186" y2="13.948"/>\r
+<path style="fill:none;stroke:#F16922;stroke-width:0.5;" d="M23.79,7.733c-4.996,1.381-21.387,5.041-21.64,7.086\r
+       c-0.483,3.917-0.123,10.143-0.123,10.143"/>\r
+<path style="fill:#F16922;" d="M3.532,39.84C1.697,35.389-0.443,30.363,2.1,24.184C3.794,29.957,3.544,34.362,3.532,39.84"/>\r
+<ellipse transform="matrix(0.942 -0.3356 0.3356 0.942 -1.1544 8.1596)" style="fill:#6D6E70;" cx="23.032" cy="7.42" rx="0.792" ry="0.411"/>\r
+</svg>\r
diff --git a/repository/user/pix/icon.svg b/repository/user/pix/icon.svg
new file mode 100644 (file)
index 0000000..3011b9f
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]>\r
+<svg version="1.1"\r
+        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"\r
+        x="0px" y="0px" width="74px" height="51px" viewBox="-0.535 -0.774 74 51"\r
+        style="overflow:visible;enable-background:new -0.535 -0.774 74 51;" xml:space="preserve">\r
+<defs>\r
+</defs>\r
+<radialGradient id="SVGID_1_" cx="137.084" cy="32.2324" r="123.3346" gradientUnits="userSpaceOnUse">\r
+       <stop  offset="0" style="stop-color:#FAAF40"/>\r
+       <stop  offset="0.0432" style="stop-color:#F9A538"/>\r
+       <stop  offset="0.1116" style="stop-color:#F89D31"/>\r
+       <stop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <stop  offset="0.5276" style="stop-color:#F7922D"/>\r
+       <stop  offset="1" style="stop-color:#F37B28"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.1982" style="stop-color:#FAAF40"/>\r
+       <a:midPointStop  offset="0.2269" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="0.6064" style="stop-color:#F89A2F"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#F37B28"/>\r
+</radialGradient>\r
+<path style="fill:url(#SVGID_1_);" d="M61.192,49.375V26.558c0-4.771-1.972-7.156-5.911-7.156c-3.942,0-5.912,2.386-5.912,7.156\r
+       v22.817H37.754V26.558c0-4.771-1.938-7.156-5.811-7.156c-3.94,0-5.91,2.386-5.91,7.156v22.817H14.417V25.211\r
+       c0-4.979,1.728-8.747,5.185-11.304c3.043-2.282,7.158-3.425,12.343-3.425c5.255,0,9.127,1.349,11.617,4.045\r
+       c2.142-2.696,6.049-4.045,11.72-4.045c5.186,0,9.298,1.143,12.341,3.425c3.457,2.557,5.186,6.325,5.186,11.304v24.164H61.192z"/>\r
+<path style="fill:#58595B;" d="M15.499,16.321c-0.394,1.999-0.788,3.999-1.181,5.997c10.983,3.72,21.4,0.111,26.883-9.489\r
+       C33.184,7.282,25.601,12.914,15.499,16.321"/>\r
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="14.4287" y1="16.0166" x2="40.6895" y2="16.0166">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_2_);" d="M15.499,14.889c-0.356,2.259-0.714,4.518-1.07,6.776c10.527,3.567,20.84,0.503,26.261-8.944\r
+       C33.708,4.677,25.925,11.373,15.499,14.889"/>\r
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="19.457" y1="7.248" x2="30.3611" y2="22.8207">\r
+       <stop  offset="0" style="stop-color:#231F20"/>\r
+       <stop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0.5" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20;stop-opacity:0"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_3_);" d="M27.993,17.575c-4.764-0.997-10.036,1.485-13.564,4.09\r
+       C12.103,4.879,22.536,5.222,36.098,9.415c-0.857,4.143-2.387,9.598-5.017,12.903C31.081,20.182,30.052,18.6,27.993,17.575"/>\r
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="0.0078" y1="7.7275" x2="48.0068" y2="7.7275">\r
+       <stop  offset="0" style="stop-color:#929497"/>\r
+       <stop  offset="0.1245" style="stop-color:#757578"/>\r
+       <stop  offset="0.2792" style="stop-color:#575658"/>\r
+       <stop  offset="0.4403" style="stop-color:#403E3F"/>\r
+       <stop  offset="0.6085" style="stop-color:#302D2E"/>\r
+       <stop  offset="0.7884" style="stop-color:#262223"/>\r
+       <stop  offset="1" style="stop-color:#231F20"/>\r
+       <a:midPointStop  offset="0" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="0.2606" style="stop-color:#929497"/>\r
+       <a:midPointStop  offset="1" style="stop-color:#231F20"/>\r
+</linearGradient>\r
+<path style="fill:url(#SVGID_4_);" d="M0.008,14.889C17.625,4.318,27.468,2.282,48.007,0.202\r
+       C24.279,18.919,23.64,14.889,0.008,14.889"/>\r
+<line style="fill:#383738;stroke:#4A4A4C;stroke-width:0.5;" x1="48.007" y1="0.202" x2="29.186" y2="13.948"/>\r
+<path style="opacity:0.23;fill:#231F20;" d="M25.506,7.567C25.733,9.723,25.286,5.423,25.506,7.567"/>\r
+<line style="fill:#FFFFFF;stroke:#A8ABAD;stroke-width:0.5;" x1="0.008" y1="14.889" x2="29.186" y2="13.948"/>\r
+<path style="fill:none;stroke:#F16922;stroke-width:0.5;" d="M23.79,7.733c-4.996,1.381-21.387,5.041-21.64,7.086\r
+       c-0.483,3.917-0.123,10.143-0.123,10.143"/>\r
+<path style="fill:#F16922;" d="M3.532,39.84C1.697,35.389-0.443,30.363,2.1,24.184C3.794,29.957,3.544,34.362,3.532,39.84"/>\r
+<ellipse transform="matrix(0.942 -0.3356 0.3356 0.942 -1.1544 8.1596)" style="fill:#6D6E70;" cx="23.032" cy="7.42" rx="0.792" ry="0.411"/>\r
+</svg>\r
index 26557f8..8fdb4e4 100644 (file)
@@ -168,3 +168,20 @@ body:not(.jsenabled) .langmenu:hover > .dropdown-menu,
 .custom-select {
     word-wrap: normal;
 }
+
+/* Add commented out carousel transistions back in.
+ *
+ * The Css prefixer used in Moodle breaks on @supports syntax, See MDL-61515.
+ */
+.carousel-item-next.carousel-item-left,
+.carousel-item-prev.carousel-item-right {
+    transform: translateX(0);
+}
+.carousel-item-next,
+.active.carousel-item-right {
+    transform: translateX(100%);
+}
+.carousel-item-prev,
+.active.carousel-item-left {
+    transform: translateX(-100%);
+}
index ae74bbc..be02405 100644 (file)
@@ -16411,6 +16411,22 @@ body:not(.jsenabled) .langmenu:hover > .dropdown-menu,
 .custom-select {
   word-wrap: normal; }
 
+/* Add commented out carousel transistions back in.
+ *
+ * The Css prefixer used in Moodle breaks on @supports syntax, See MDL-61515.
+ */
+.carousel-item-next.carousel-item-left,
+.carousel-item-prev.carousel-item-right {
+  transform: translateX(0); }
+
+.carousel-item-next,
+.active.carousel-item-right {
+  transform: translateX(100%); }
+
+.carousel-item-prev,
+.active.carousel-item-left {
+  transform: translateX(-100%); }
+
 body.behat-site .fixed-top {
   position: absolute; }