Merge branch 'MDL-61218-master' of git://github.com/lameze/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Sun, 28 Jan 2018 23:10:25 +0000 (00:10 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Sun, 28 Jan 2018 23:10:25 +0000 (00:10 +0100)
52 files changed:
admin/roles/classes/define_role_table_advanced.php
admin/tool/usertours/amd/build/usertours.min.js
admin/tool/usertours/amd/src/usertours.js
admin/tool/usertours/tests/behat/behat_tool_usertours.php
admin/tool/usertours/tests/behat/tour_accessibility.feature [new file with mode: 0644]
admin/tool/usertours/tests/behat/tour_filter.feature
auth/ldap/lang/en/auth_ldap.php
auth/ldap/settings.php
badges/criteria/award_criteria_profile.php
badges/tests/behat/criteria_profile.feature [new file with mode: 0644]
enrol/manual/classes/enrol_users_form.php
install/lang/tg/moodle.php
lang/en/role.php
lib/behat/classes/partial_named_selector.php
lib/deprecatedlib.php
lib/dml/sqlsrv_native_moodle_database.php
lib/moodlelib.php
lib/tests/behat/behat_general.php
lib/upgrade.txt
message/amd/build/message_preferences.min.js
message/amd/src/message_preferences.js
message/tests/behat/update_messaging_preferences.feature [new file with mode: 0644]
mod/assign/backup/moodle2/restore_assign_stepslib.php
mod/assign/locallib.php
mod/assign/tests/behat/assign_course_reset.feature
mod/glossary/formats/entrylist/entrylist_format.php
mod/glossary/lib.php
mod/quiz/report/statistics/report.php
mod/quiz/tests/behat/manually_mark_question.feature
question/classes/statistics/questions/all_calculated_for_qubaid_condition.php
question/classes/statistics/questions/calculator.php
question/classes/statistics/responses/analysis_for_question.php
question/classes/statistics/responses/analysis_for_subpart.php
question/type/calculated/pix/icon.svg [new file with mode: 0644]
question/type/calculatedmulti/pix/icon.svg [new file with mode: 0644]
question/type/calculatedsimple/pix/icon.svg [new file with mode: 0644]
question/type/ddimageortext/pix/icon.svg [new file with mode: 0644]
question/type/ddmarker/pix/icon.svg [new file with mode: 0644]
question/type/ddwtos/pix/icon.svg [new file with mode: 0644]
question/type/description/pix/icon.svg [new file with mode: 0644]
question/type/essay/pix/icon.svg [new file with mode: 0644]
question/type/gapselect/pix/icon.svg [new file with mode: 0644]
question/type/match/pix/icon.svg [new file with mode: 0644]
question/type/missingtype/pix/icon.svg [new file with mode: 0644]
question/type/multianswer/pix/icon.svg [new file with mode: 0644]
question/type/multichoice/pix/icon.svg [new file with mode: 0644]
question/type/numerical/pix/icon.svg [new file with mode: 0644]
question/type/random/pix/icon.svg [new file with mode: 0644]
question/type/randomsamatch/pix/icon.svg [new file with mode: 0644]
question/type/shortanswer/pix/icon.svg [new file with mode: 0644]
question/type/truefalse/pix/icon.svg [new file with mode: 0644]
version.php

index 957fe85..16e188b 100644 (file)
@@ -103,6 +103,8 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
             $this->role->shortname = core_text::strtolower(clean_param($this->role->shortname, PARAM_ALPHANUMEXT));
             if (empty($this->role->shortname)) {
                 $this->errors['shortname'] = get_string('errorbadroleshortname', 'core_role');
+            } else if (core_text::strlen($this->role->shortname) > 100) { // Check if it exceeds the max of 100 characters.
+                $this->errors['shortname'] = get_string('errorroleshortnametoolong', 'core_role');
             }
         }
         if ($DB->record_exists_select('role', 'shortname = ? and id <> ?', array($this->role->shortname, $this->roleid))) {
@@ -496,7 +498,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
     }
 
     protected function get_shortname_field($id) {
-        return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->shortname) . '"' .
+        return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="100" value="' . s($this->role->shortname) . '"' .
                 ' class="form-control"/>';
     }
 
index efc5448..3caa790 100644 (file)
Binary files a/admin/tool/usertours/amd/build/usertours.min.js and b/admin/tool/usertours/amd/build/usertours.min.js differ
index 044180b..70bd057 100644 (file)
@@ -54,6 +54,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
          * @param   {Number}    tourId      The ID of the tour to start.
          */
         fetchTour: function(tourId) {
+            M.util.js_pending('admin_usertour_fetchTour' + tourId);
             $.when(
                 ajax.call([
                     {
@@ -66,10 +67,16 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
                     }
                 ])[0],
                 templates.render('tool_usertours/tourstep', {})
-            ).then(function(response, template) {
-                usertours.startBootstrapTour(tourId, template[0], response.tourconfig);
+            )
+            .then(function(response, template) {
+                return usertours.startBootstrapTour(tourId, template[0], response.tourconfig);
+            })
+            .always(function() {
+                M.util.js_complete('admin_usertour_fetchTour' + tourId);
+
                 return;
-            }).fail(notification.exception);
+            })
+            .fail(notification.exception);
         },
 
         /**
@@ -79,6 +86,8 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
          */
         addResetLink: function() {
             var ele;
+            M.util.js_pending('admin_usertour_addResetLink');
+
             // Append the link to the most suitable place on the page
             // with fallback to legacy selectors and finally the body
             // if there is no better place.
@@ -92,9 +101,17 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
                 ele = $('body');
             }
             templates.render('tool_usertours/resettour', {})
-                .done(function(html, js) {
-                    templates.appendNodeContents(ele, html, js);
-                });
+            .then(function(html, js) {
+                templates.appendNodeContents(ele, html, js);
+
+                return;
+            })
+            .always(function() {
+                M.util.js_complete('admin_usertour_addResetLink');
+
+                return;
+            })
+            .fail();
         },
 
         /**
@@ -104,6 +121,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
          * @param   {Number}    tourId      The ID of the tour to start.
          * @param   {String}    template    The template to use.
          * @param   {Object}    tourConfig  The tour configuration.
+         * @return  {Object}
          */
         startBootstrapTour: function(tourId, template, tourConfig) {
             if (usertours.currentTour) {
@@ -147,7 +165,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
             });
 
             usertours.currentTour = new BootstrapTour(tourConfig);
-            usertours.currentTour.startTour();
+            return usertours.currentTour.startTour();
         },
 
         /**
index 63afcbe..b08bc14 100644 (file)
@@ -62,7 +62,16 @@ class behat_tool_usertours extends behat_base {
     public function i_add_steps_to_the_named_tour($tourname, TableNode $table) {
         $this->execute('behat_tool_usertours::i_open_the_user_tour_settings_page');
         $this->execute('behat_general::click_link', $this->escape($tourname));
+        $this->execute('behat_tool_usertours::i_add_steps_to_the_tour', $table);
+    }
 
+    /**
+     * Add new steps to the current user tour.
+     *
+     * @Given /^I add steps to the tour:$/
+     * @param   TableNode   $table
+     */
+    public function i_add_steps_to_the_tour(TableNode $table) {
         foreach ($table->getHash() as $step) {
             $this->execute('behat_general::click_link', get_string('newstep', 'tool_usertours'));
 
diff --git a/admin/tool/usertours/tests/behat/tour_accessibility.feature b/admin/tool/usertours/tests/behat/tour_accessibility.feature
new file mode 100644 (file)
index 0000000..4cfd3b5
--- /dev/null
@@ -0,0 +1,85 @@
+@tool @tool_usertours
+Feature: Apply accessibility to a tour
+  Background:
+    Given I log in as "admin"
+    And I add a new user tour with:
+      | Name                | First tour |
+      | Description         | My first tour |
+      | Apply to URL match  | FRONTPAGE |
+      | Tour is enabled     | 1 |
+      | Show with backdrop  | 1 |
+    And I add steps to the "First tour" tour:
+      | targettype                  | Title             | Content |
+      | Display in middle of page   | Welcome           | Welcome tour. |
+    And I add steps to the tour:
+      | targettype | targetvalue_selector | Title       | Content   |
+      | Selector   | .usermenu            | User menu   | Next page |
+      | Selector   | input,button         | Page 2      | Next page |
+    And I add steps to the tour:
+      | targettype                  | Title   | Content     |
+      | Display in middle of page   | Page 3  | Final page. |
+
+  @javascript
+  Scenario: Check tabbing working correctly.
+    Given I am on site homepage
+    And I wait "1" seconds
+    And I should see "Welcome"
+    # First dialogue of the tour, "Welcome". It has Close, Next and End buttons.
+    # Nothing highlighted on the page. Initially whole dialogue focused.
+    When I press tab
+    Then the focused element is ".close" "css_element" in the "Welcome" "dialogue"
+    When I press tab
+    Then the focused element is "Next" "button" in the "Welcome" "dialogue"
+    When I press tab
+    Then the focused element is "End tour" "button" in the "Welcome" "dialogue"
+    When I press tab
+    # Here the focus loops round to the whole dialogue again.
+    And I press tab
+    Then the focused element is ".close" "css_element" in the "Welcome" "dialogue"
+    # Check looping works properly going backwards too.
+    When I press shift tab
+    And I press shift tab
+    Then the focused element is "End tour" "button" in the "Welcome" "dialogue"
+
+    When I press "Next"
+    # Now we are on the "User menu" step, so Previous is also enabled.
+    # Also, the user menu section in the page is highlighted, and this
+    # section contain a hyperlink so the focus have to go though and back to the dialogue.
+    And I wait "1" seconds
+    And I press tab
+    Then the focused element is ".close" "css_element" in the "User menu" "dialogue"
+    When I press tab
+    Then the focused element is "Previous" "button" in the "User menu" "dialogue"
+    When I press tab
+    Then the focused element is "Next" "button" in the "User menu" "dialogue"
+    When I press tab
+    Then the focused element is "End tour" "button" in the "User menu" "dialogue"
+    # We tab 3 times from "End Tour" button to header container, drop down then go to "Dashboard" link.
+    When I press tab
+    Then the focused element is ".usermenu" "css_element"
+    When I press tab
+    Then the focused element is "Admin User" "link" in the ".usermenu" "css_element"
+    When I press tab
+    And I press tab
+    Then the focused element is ".close" "css_element" in the "User menu" "dialogue"
+    # Press shift-tab twice should lead us back to "Admin user" link.
+    When I press shift tab
+    And I press shift tab
+    Then the focused element is "Admin User" "link" in the ".usermenu" "css_element"
+
+  @javascript
+  Scenario: Aria tags should not exist
+    And I am on site homepage
+    When I click on "Next" "button"
+    And I click on "Next" "button"
+    Then "input[aria-describedby^='tour-step-tool_usertours'],button[aria-describedby^='tour-step-tool_usertours']" "css_element" should exist
+    And "input[tabindex],button[tabindex]" "css_element" should exist
+    When I click on "Next" "button"
+    Then "input[aria-describedby^='tour-step-tool_usertours'],button[aria-describedby^='tour-step-tool_usertours']" "css_element" should not exist
+    And "input[tabindex],button[tabindex]" "css_element" should not exist
+    When I click on "Previous" "button"
+    Then "input[aria-describedby^='tour-step-tool_usertours'],button[aria-describedby^='tour-step-tool_usertours']" "css_element" should exist
+    And "input[tabindex],button[tabindex]" "css_element" should exist
+    When I click on "End tour" "button"
+    Then "input[aria-describedby^='tour-step-tool_usertours'],button[aria-describedby^='tour-step-tool_usertours']" "css_element" should not exist
+    And "input[tabindex],button[tabindex]" "css_element" should not exist
index 0bafb34..fdcd28d 100644 (file)
@@ -157,23 +157,3 @@ Feature: Apply tour filters to a tour
     When I am on "Course 2" course homepage
     And I wait until the page is ready
     Then I should not see "Welcome to your course tour."
-
-  @javascript
-  Scenario: Aria tags should not exist
-    Given I log in as "admin"
-    And I open the User tour settings page
-    # Turn on default tour for boost theme.
-    And I click on "Enable" "link" in the "Boost - administrator" "table_row"
-    And I am on site homepage
-    When I click on "Next" "button"
-    Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should exist
-    And "button[tabindex]" "css_element" should exist
-    When I click on "Next" "button"
-    Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should not exist
-    And "button[tabindex]" "css_element" should not exist
-    When I click on "Previous" "button"
-    Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should exist
-    And "button[tabindex]" "css_element" should exist
-    When I click on "End tour" "button"
-    Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should not exist
-    And "button[tabindex]" "css_element" should not exist
index fb61dd1..5629542 100644 (file)
@@ -113,6 +113,7 @@ $string['auth_ntlmsso_subnet'] = 'If set, it will only attempt SSO with clients
 $string['auth_ntlmsso_subnet_key'] = 'Subnet';
 $string['auth_ntlmsso_type_key'] = 'Authentication type';
 $string['auth_ntlmsso_type'] = 'The authentication method configured in the web server to authenticate the users (if in doubt, choose NTLM)';
+$string['cannotmaprole'] = 'The role "{$a->rolename}" can\'t be mapped because its short name "{$a->shortname}" is too long or contains hyphens. To allow it to be mapped, you need to reduce the short name to {$a->charlimit} characters or remove the hyphens. <a href="{$a->link}">Edit the role here</a>';
 $string['connectingldap'] = "Connecting to LDAP server...\n";
 $string['connectingldapsuccess'] = "Connecting to your LDAP server was successful";
 $string['creatingtemptable'] = "Creating temporary table {\$a}\n";
index 43fb8eb..f9bc8d9 100644 (file)
@@ -245,9 +245,27 @@ if ($ADMIN->fulltree) {
         // Create system role mapping field for each assignable system role.
         $roles = get_ldap_assignable_role_names();
         foreach ($roles as $role) {
-            $settings->add(new admin_setting_configtext('auth_ldap/' . $role['settingname'],
+            // Before we can add this setting we need to check a few things.
+            // A) It does not exceed 100 characters otherwise it will break the DB as the 'name' field
+            //    in the 'config_plugins' table is a varchar(100).
+            // B) The setting name does not contain hyphens. If it does then it will fail the check
+            //    in parse_setting_name() and everything will explode. Role short names are validated
+            //    against PARAM_ALPHANUMEXT which is similar to the regex used in parse_setting_name()
+            //    except it also allows hyphens.
+            // Instead of shortening the name and removing/replacing the hyphens we are showing a warning.
+            // If we were to manipulate the setting name by removing the hyphens we may get conflicts, eg
+            // 'thisisashortname' and 'this-is-a-short-name'. The same applies for shortening the setting name.
+            if (core_text::strlen($role['settingname']) > 100 || !preg_match('/^[a-zA-Z0-9_]+$/', $role['settingname'])) {
+                $url = new moodle_url('/admin/roles/define.php', array('action' => 'edit', 'roleid' => $role['id']));
+                $a = (object)['rolename' => $role['localname'], 'shortname' => $role['shortname'], 'charlimit' => 93,
+                    'link' => $url->out()];
+                $settings->add(new admin_setting_heading('auth_ldap/role_not_mapped_' . sha1($role['settingname']), '',
+                    get_string('cannotmaprole', 'auth_ldap', $a)));
+            } else {
+                $settings->add(new admin_setting_configtext('auth_ldap/' . $role['settingname'],
                     get_string('auth_ldap_rolecontext', 'auth_ldap', $role),
                     get_string('auth_ldap_rolecontext_help', 'auth_ldap', $role), '', PARAM_RAW_TRIMMED));
+            }
         }
 
         // User Account Sync.
index 51b4988..da76bc8 100644 (file)
@@ -52,7 +52,7 @@ class award_criteria_profile extends award_criteria {
 
         // Note: cannot use user_get_default_fields() here because it is not possible to decide which fields user can modify.
         $dfields = array('firstname', 'lastname', 'email', 'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo',
-                         'aim', 'msn', 'department', 'institution', 'description', 'city', 'url', 'country');
+                         'aim', 'msn', 'department', 'institution', 'description', 'picture', 'city', 'url', 'country');
 
         $sql = "SELECT uf.id as fieldid, uf.name as name, ic.id as categoryid, ic.name as categoryname, uf.datatype
                 FROM {user_info_field} uf
@@ -185,7 +185,12 @@ class award_criteria_profile extends award_criteria {
                 $whereparts[] = "uid{$idx}.id IS NOT NULL";
             } else {
                 // This is a field from {user} table.
-                $whereparts[] = $DB->sql_isnotempty('u', "u.{$param['field']}", false, true);
+                if ($param['field'] == 'picture') {
+                    // The picture field is numeric and requires special handling.
+                    $whereparts[] = "u.{$param['field']} != 0";
+                } else {
+                    $whereparts[] = $DB->sql_isnotempty('u', "u.{$param['field']}", false, true);
+                }
             }
         }
 
@@ -224,7 +229,13 @@ class award_criteria_profile extends award_criteria {
                 $params["fieldid{$idx}"] = $param['field'];
                 $whereparts[] = "uid{$idx}.id IS NOT NULL";
             } else {
-                $whereparts[] = $DB->sql_isnotempty('u', "u.{$param['field']}", false, true);
+                // This is a field from {user} table.
+                if ($param['field'] == 'picture') {
+                    // The picture field is numeric and requires special handling.
+                    $whereparts[] = "u.{$param['field']} != 0";
+                } else {
+                    $whereparts[] = $DB->sql_isnotempty('u', "u.{$param['field']}", false, true);
+                }
             }
         }
 
diff --git a/badges/tests/behat/criteria_profile.feature b/badges/tests/behat/criteria_profile.feature
new file mode 100644 (file)
index 0000000..abdb166
--- /dev/null
@@ -0,0 +1,31 @@
+@core @core_badges @_file_upload
+Feature: Award badges based on user profile field
+  In order to award badges to users based on completion of their user profile
+  As an admin
+  I need to add profile completion criteria to badges in the system
+
+  @javascript
+  Scenario: Award badge for a uploading a profile picture.
+    Given the following "users" exist:
+      | username | firstname | lastname | email           |
+      | user1    | First     | User     | first@example.com  |
+    And I log in as "admin"
+    And I navigate to "Add a new badge" node in "Site administration > Badges"
+    And I set the following fields to these values:
+      | Name | Site Badge |
+      | Description | Site badge description |
+      | issuername | Tester of site badge |
+    And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    And I set the field "type" to "Profile completion"
+    And I set the field "id_field_picture" to "1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    And I log out
+    When I log in as "user1"
+    And I follow "Profile" in the user menu
+    And I click on "Edit profile" "link" in the "region-main" "region"
+    And I upload "badges/tests/behat/badge.png" file to "New picture" filemanager
+    And I press "Update profile"
+    Then I should see "Site Badge"
index c34d9b2..dcb5f29 100644 (file)
@@ -123,9 +123,7 @@ class enrol_manual_enrol_users_form extends moodleform {
 
         $roles = get_assignable_roles($context);
         $mform->addElement('select', 'roletoassign', get_string('assignrole', 'enrol_manual'), $roles);
-        $keys = array_keys($roles);
-        $defaultrole = end($keys);
-        $mform->setDefault('roletoassign', $defaultrole);
+        $mform->setDefault('roletoassign', $instance->roleid);
 
         $mform->addAdvancedStatusElement('main');
 
index decac63..3123912 100644 (file)
@@ -31,6 +31,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['language'] = 'Забон';
+$string['moodlelogo'] = 'Логотипи Moodle';
 $string['next'] = 'Давомаш';
 $string['previous'] = 'Ба ақиб';
 $string['reload'] = 'Навсозӣ карда шавад';
index 8c8072e..f35cf01 100644 (file)
@@ -218,6 +218,7 @@ $string['errorbadrolename'] = 'Incorrect role name';
 $string['errorbadroleshortname'] = 'Incorrect role short name';
 $string['errorexistsrolename'] = 'Role name already exists';
 $string['errorexistsroleshortname'] = 'Role name already exists';
+$string['errorroleshortnametoolong'] = 'The short name must not exceed 100 characters';
 $string['eventroleallowassignupdated'] = 'Allow role assignment';
 $string['eventroleallowoverrideupdated'] = 'Allow role override';
 $string['eventroleallowswitchupdated'] = 'Allow role switch';
index 1faa0db..5ce4724 100644 (file)
@@ -138,6 +138,18 @@ XPATH
     normalize-space(descendant::div[@class='hd']) = %locator%]
         |
 .//div[@data-region='modal' and descendant::*[@data-region='title'] = %locator%]
+        |
+.//div[
+        contains(concat(' ', normalize-space(@class), ' '), ' modal-content ')
+            and
+        normalize-space(descendant::h4[contains(concat(' ', normalize-space(@class), ' '), ' modal-title ')]) = %locator%
+    ]
+        |
+.//div[
+        contains(concat(' ', normalize-space(@class), ' '), ' modal ')
+            and
+        normalize-space(descendant::*[contains(concat(' ', normalize-space(@class), ' '), ' modal-header ')] = %locator%)
+    ]
 XPATH
         , 'icon' => <<<XPATH
 .//*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') and ( contains(normalize-space(@title), %locator%))]
index a206596..0f34ef2 100644 (file)
@@ -839,32 +839,10 @@ function print_container_end($return=false) {
 }
 
 /**
- * Print a bold message in an optional color.
- *
  * @deprecated since Moodle 2.0 MDL-19077 - use $OUTPUT->notification instead.
- * @todo MDL-50469 This will be deleted in Moodle 3.3.
- * @param string $message The message to print out
- * @param string $classes Optional style to display message text in
- * @param string $align Alignment option
- * @param bool $return whether to return an output string or echo now
- * @return string|bool Depending on $result
- */
-function notify($message, $classes = 'error', $align = 'center', $return = false) {
-    global $OUTPUT;
-
-    debugging('notify() is deprecated, please use $OUTPUT->notification() instead', DEBUG_DEVELOPER);
-
-    if ($classes == 'green') {
-        debugging('Use of deprecated class name "green" in notify. Please change to "success".', DEBUG_DEVELOPER);
-        $classes = 'success'; // Backward compatible with old color system.
-    }
-
-    $output = $OUTPUT->notification($message, $classes);
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
+ */
+function notify() {
+    throw new coding_exception('notify() is removed, please use $OUTPUT->notification() instead');
 }
 
 /**
index 08f2735..d1d27f1 100644 (file)
@@ -443,7 +443,7 @@ class sqlsrv_native_moodle_database extends moodle_database {
      * @return array of table names in lowercase and without prefix
      */
     public function get_tables($usecache = true) {
-        if ($usecache and count($this->tables) > 0) {
+        if ($usecache and $this->tables !== null) {
             return $this->tables;
         }
         $this->tables = array ();
index 9ba9f39..a488445 100644 (file)
@@ -3667,6 +3667,9 @@ function get_user_field_name($field) {
         case 'msn' : {
             return get_string('msnid');
         }
+        case 'picture' : {
+            return get_string('pictureofuser');
+        }
     }
     // Otherwise just use the same lang string.
     return get_string($field);
index 749540d..4128402 100644 (file)
@@ -1643,4 +1643,83 @@ class behat_general extends behat_base {
 
         throw new \Moodle\BehatExtension\Exception\SkippedException();
     }
+
+    /**
+     * Checks focus is with the given element.
+     *
+     * @Then /^the focused element is( not)? "(?P<node_string>(?:[^"]|\\")*)" "(?P<node_selector_string>[^"]*)"$/
+     * @param string $not optional step verifier
+     * @param string $nodeelement Element identifier
+     * @param string $nodeselectortype Element type
+     * @throws DriverException If not using JavaScript
+     * @throws ExpectationException
+     */
+    public function the_focused_element_is($not, $nodeelement, $nodeselectortype) {
+        if (!$this->running_javascript()) {
+            throw new DriverException('Checking focus on an element requires JavaScript');
+        }
+        list($a, $b) = $this->transform_selector($nodeselectortype, $nodeelement);
+        $element = $this->find($a, $b);
+        $xpath = addslashes_js($element->getXpath());
+        $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '",
+                document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';
+        $targetisfocused = $this->getSession()->evaluateScript($script);
+        if ($not == ' not') {
+            if ($targetisfocused) {
+                throw new ExpectationException("$nodeelement $nodeselectortype is focused", $this->getSession());
+            }
+        } else {
+            if (!$targetisfocused) {
+                throw new ExpectationException("$nodeelement $nodeselectortype is not focused", $this->getSession());
+            }
+        }
+    }
+
+    /**
+     * Checks focus is with the given element.
+     *
+     * @Then /^the focused element is( not)? "(?P<n>(?:[^"]|\\")*)" "(?P<ns>[^"]*)" in the "(?P<c>(?:[^"]|\\")*)" "(?P<cs>[^"]*)"$/
+     * @param string $not string optional step verifier
+     * @param string $element Element identifier
+     * @param string $selectortype Element type
+     * @param string $nodeelement Element we look in
+     * @param string $nodeselectortype The type of selector where we look in
+     * @throws DriverException If not using JavaScript
+     * @throws ExpectationException
+     */
+    public function the_focused_element_is_in_the($not, $element, $selectortype, $nodeelement, $nodeselectortype) {
+        if (!$this->running_javascript()) {
+            throw new DriverException('Checking focus on an element requires JavaScript');
+        }
+        $element = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
+        $xpath = addslashes_js($element->getXpath());
+        $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '",
+                document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';
+        $targetisfocused = $this->getSession()->evaluateScript($script);
+        if ($not == ' not') {
+            if ($targetisfocused) {
+                throw new ExpectationException("$nodeelement $nodeselectortype is focused", $this->getSession());
+            }
+        } else {
+            if (!$targetisfocused) {
+                throw new ExpectationException("$nodeelement $nodeselectortype is not focused", $this->getSession());
+            }
+        }
+    }
+
+    /**
+     * Manually press tab key.
+     *
+     * @When /^I press( shift)? tab$/
+     * @param string $shift string optional step verifier
+     * @throws DriverException
+     */
+    public function i_manually_press_tab($shift = '') {
+        if (!$this->running_javascript()) {
+            throw new DriverException($shift . ' Tab press step is not available with Javascript disabled');
+        }
+
+        $value = ($shift == ' shift') ? [\WebDriver\Key::SHIFT . \WebDriver\Key::TAB] : [\WebDriver\Key::TAB];
+        $this->getSession()->getDriver()->getWebDriverSession()->activeElement()->postValue(['value' => $value]);
+    }
 }
index 4fbd4bd..f616a89 100644 (file)
@@ -11,6 +11,8 @@ information provided here is intended especially for developers.
 * Event triggering and event handlers:
     - The following events, deprecated since moodle 2.6, have been finally removed: groups_members_removed,
       groups_groupings_groups_removed, groups_groups_deleted, groups_groupings_deleted.
+* The following functions have been finally deprecated and can not be used any more:
+  - notify()
 
 === 3.4 ===
 
index cee25aa..436b3bb 100644 (file)
Binary files a/message/amd/build/message_preferences.min.js and b/message/amd/build/message_preferences.min.js differ
index e167890..c8a4372 100644 (file)
@@ -40,6 +40,7 @@ define(['jquery', 'core/ajax', 'core/notification',
      */
     var MessagePreferences = function(element) {
         this.root = $(element);
+        this.userId = this.root.find(SELECTORS.PREFERENCES_CONTAINER).attr('data-user-id');
 
         this.registerEventListeners();
     };
@@ -75,6 +76,7 @@ define(['jquery', 'core/ajax', 'core/notification',
         var request = {
             methodname: 'core_user_update_user_preferences',
             args: {
+                userid: this.userId,
                 preferences: [
                     {
                         type: checkbox.attr('data-preference-key'),
@@ -109,7 +111,7 @@ define(['jquery', 'core/ajax', 'core/notification',
             if (!this.preferencesDisabled()) {
                 var preferencesContainer = $(e.target).closest(SELECTORS.PREFERENCES_CONTAINER);
                 var preferenceElement = $(e.target).closest(SELECTORS.PREFERENCE);
-                var messagePreference = new MessageNotificationPreference(preferencesContainer);
+                var messagePreference = new MessageNotificationPreference(preferencesContainer, this.userId);
 
                 preferenceElement.addClass('loading');
                 messagePreference.save().always(function() {
diff --git a/message/tests/behat/update_messaging_preferences.feature b/message/tests/behat/update_messaging_preferences.feature
new file mode 100644 (file)
index 0000000..5a23c1e
--- /dev/null
@@ -0,0 +1,33 @@
+@core @message @javascript
+Feature: Messaging preferences
+  In order to be notified of messages
+  As a user
+  I need to be able to alter my message preferences
+
+  Background:
+    Given I log in as "admin"
+    And I navigate to "Manage message outputs" node in "Site administration > Plugins > Message outputs"
+    And I click on "//table[contains(@class, 'admintable')]/tbody/tr/td[contains(text(), 'Email')]/following-sibling::td[1]/a" "xpath_element"
+
+  Scenario: Alter my message preferences
+    Given I follow "Preferences" in the user menu
+    And I click on "Message preferences" "link" in the "region-main" "region"
+    And I should see "On" in the "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+    And I should not see "Off" in the "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+    And I click on "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+    And I reload the page
+    Then I should see "Off" in the "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+
+  Scenario: Alter another users preferences
+    Given the following "users" exist:
+      | username | firstname | lastname | email            |
+      | user1    | User      | 1        | user1@example.com    |
+    And I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
+    And I click on "User 1" "link"
+    And I click on "Preferences" "link" in the ".profile_tree" "css_element"
+    And I click on "Message preferences" "link" in the "region-main" "region"
+    And I should see "On" in the "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+    And I should not see "Off" in the "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+    And I click on "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
+    And I reload the page
+    Then I should see "Off" in the "[data-preference-key=message_provider_moodle_instantmessage] [data-state=loggedoff] .preference-state-status-container" "css_element"
index 0146519..0987c53 100644 (file)
@@ -117,6 +117,8 @@ class restore_assign_activity_structure_step extends restore_activity_structure_
         }
         if (!isset($data->gradingduedate)) {
             $data->gradingduedate = 0;
+        } else {
+            $data->gradingduedate = $this->apply_date_offset($data->gradingduedate);
         }
         if (!isset($data->markingworkflow)) {
             $data->markingworkflow = 0;
index 54adce0..4d84daf 100644 (file)
@@ -1130,11 +1130,11 @@ class assign {
                 // Remove all grades from gradebook.
                 require_once($CFG->dirroot.'/mod/assign/lib.php');
                 assign_reset_gradebook($data->courseid);
+            }
 
-                // Reset revealidentities if both submissions and grades have been reset.
-                if ($this->get_instance()->blindmarking && $this->get_instance()->revealidentities) {
-                    $DB->set_field('assign', 'revealidentities', 0, array('id' => $this->get_instance()->id));
-                }
+            // Reset revealidentities for assign if blindmarking is enabled.
+            if ($this->get_instance()->blindmarking) {
+                $DB->set_field('assign', 'revealidentities', 0, array('id' => $this->get_instance()->id));
             }
         }
 
index 5fc52cc..0ba1b6a 100644 (file)
@@ -108,3 +108,25 @@ Feature: Assign reset
     And I follow "Test assignment name"
     And I navigate to "Group overrides" in current page administration
     Then I should not see "Group 1"
+
+  Scenario: Use course reset to reset blind marking assignment.
+    Given I follow "Test assignment name"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+        | blindmarking | 1 |
+    And I press "Save"
+    When I follow "Test assignment name"
+    And I navigate to "View all submissions" in current page administration
+    And I select "Reveal student identities" from the "Grading action" singleselect
+    And I press "Continue"
+    And I should see "Sam1 Student1"
+    And I am on "Course 1" course homepage
+    When I navigate to "Reset" node in "Course administration"
+    And I set the following fields to these values:
+        | Delete all submissions | 1 |
+    And I press "Reset course"
+    And I press "Continue"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment name"
+    And I navigate to "View all submissions" in current page administration
+    Then I should not see "Sam1 Student1"
index 6a35248..b1482f6 100644 (file)
@@ -25,7 +25,7 @@ function glossary_show_entry_entrylist($course, $cm, $glossary, $entry, $mode=''
         }
         if (!empty($entry->rating)) {
             echo '<br />';
-            echo '<span class="ratings">';
+            echo '<span class="ratings d-block p-t-1">';
             $return = glossary_print_entry_ratings($course, $entry);
             echo '</span>';
         }
@@ -37,7 +37,8 @@ function glossary_show_entry_entrylist($course, $cm, $glossary, $entry, $mode=''
     }
     echo '</td></tr>';
 
-    echo "</table>\n";
+    echo "</table>";
+    echo "<hr>\n";
     return $return;
 }
 
index b3c9f92..83ec65d 100644 (file)
@@ -1329,7 +1329,6 @@ function glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode='',$h
         $return .= '<div>'.$comment->output(true).'</div>';
         $output = true;
     }
-    $return .= '<hr>';
 
     //If we haven't calculated any REAL thing, delete result ($return)
     if (!$output) {
@@ -1373,11 +1372,12 @@ function  glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $m
             echo '<tr valign="top"><td class="icons">'.$icons.'</td></tr>';
         }
         if (!empty($entry->rating)) {
-            echo '<tr valign="top"><td class="ratings">';
+            echo '<tr valign="top"><td class="ratings p-t-1">';
             glossary_print_entry_ratings($course, $entry);
             echo '</td></tr>';
         }
         echo '</table>';
+        echo "<hr>\n";
     }
 }
 
index 790be61..84cfe27 100644 (file)
@@ -201,7 +201,7 @@ class quiz_statistics_report extends quiz_default_report {
 
         } else if ($qid) {
             // Report on an individual sub-question indexed questionid.
-            if (is_null($questionstats->for_subq($qid, $variantno))) {
+            if (!$questionstats->has_subq($qid, $variantno)) {
                 print_error('questiondoesnotexist', 'question');
             }
 
index f465f19..5ae87fe 100644 (file)
@@ -85,7 +85,7 @@ Feature: Teachers can override the grade for any question
     And I set the field "Comment" to "<img src=\"@@PLUGINFILE@@/moodle_logo.jpg\" alt=\"It's the logo\" width=\"48\" height=\"48\" class=\"img-responsive atto_image_button_text-bottom\"><!-- File hash: a8e3ffba4ab315b3fb9187ebbf122fe9 -->"
     And I press "Save" and switch to main window
     And I switch to the main window
-    And I should see "It's the logo" in the "3" "table_row"
-    And "//*[contains(@class, 'comment')]//img[contains(@src, 'moodle_logo.jpg')]" "xpath_element" should exist
+    And I should see "Commented: [It's the logo]" in the ".history table" "css_element"
+    And "img[contains(@src, 'moodle_logo.jpg')]" "xpath_element" should exist in the ".comment" "css_element"
     # This time is same as time the window is open. So wait for it to close before proceeding.
     And I wait "2" seconds
index bafebfe..592c126 100644 (file)
@@ -95,23 +95,41 @@ class all_calculated_for_qubaid_condition {
         }
     }
 
+    /**
+     * Do we have stats for a particular quesitonid (and optionally variant)?
+     *
+     * @param int  $questionid The id of the sub question.
+     * @param int|null $variant if not null then we want the object to store a variant of a sub-question's stats.
+     * @return bool whether those stats exist (yet).
+     */
+    public function has_subq($questionid, $variant = null) {
+        if ($variant === null) {
+            return isset($this->subquestionstats[$questionid]);
+        } else {
+            return isset($this->subquestionstats[$questionid]->variantstats[$variant]);
+        }
+    }
+
     /**
      * Reference for a item stats instance for a questionid and optional variant no.
      *
      * @param int  $questionid The id of the sub question.
      * @param int|null $variant if not null then we want the object to store a variant of a sub-question's stats.
-     * @return calculated_for_subquestion|null null if the stats object does not yet exist.
+     * @return calculated|calculated_for_subquestion stats instance for a questionid and optional variant no.
+     *     Will be a calculated_for_subquestion if no variant specified.
+     * @throws \coding_exception if there is an attempt to respond to a non-existant set of stats.
      */
     public function for_subq($questionid, $variant = null) {
         if ($variant === null) {
             if (!isset($this->subquestionstats[$questionid])) {
-                return null;
+                throw new \coding_exception('Reference to unknown question id ' . $questionid);
             } else {
                 return $this->subquestionstats[$questionid];
             }
         } else {
             if (!isset($this->subquestionstats[$questionid]->variantstats[$variant])) {
-                return null;
+                throw new \coding_exception('Reference to unknown question id ' . $questionid .
+                        ' variant ' . $variant);
             } else {
                 return $this->subquestionstats[$questionid]->variantstats[$variant];
             }
@@ -136,23 +154,39 @@ class all_calculated_for_qubaid_condition {
         return array_keys($this->questionstats);
     }
 
+    /**
+     * Do we have stats for a particular slot (and optionally variant)?
+     *
+     * @param int  $slot The slot no.
+     * @param int|null $variant if provided then we want the object which stores a variant of a position's stats.
+     * @return bool whether those stats exist (yet).
+     */
+    public function has_slot($slot, $variant = null) {
+        if ($variant === null) {
+            return isset($this->questionstats[$slot]);
+        } else {
+            return isset($this->questionstats[$slot]->variantstats[$variant]);
+        }
+    }
+
     /**
      * Get position stats instance for a slot and optional variant no.
      *
      * @param int  $slot The slot no.
-     * @param null $variant if provided then we want the object which stores a variant of a position's stats.
-     * @return calculated|null An instance of the class storing the calculated position stats.
+     * @param int|null $variant if provided then we want the object which stores a variant of a position's stats.
+     * @return calculated|calculated_for_subquestion An instance of the class storing the calculated position stats.
+     * @throws \coding_exception if there is an attempt to respond to a non-existant set of stats.
      */
     public function for_slot($slot, $variant = null) {
         if ($variant === null) {
             if (!isset($this->questionstats[$slot])) {
-                return null;
+                throw new \coding_exception('Reference to unknown slot ' . $slot);
             } else {
                 return $this->questionstats[$slot];
             }
         } else {
             if (!isset($this->questionstats[$slot]->variantstats[$variant])) {
-                return null;
+                throw new \coding_exception('Reference to unknown slot ' . $slot . ' variant ' . $variant);
             } else {
                 return $this->questionstats[$slot]->variantstats[$variant];
             }
index 4f0f285..6624912 100644 (file)
@@ -106,7 +106,7 @@ class calculator {
                 $israndomquestion = ($step->questionid != $this->stats->for_slot($step->slot)->questionid);
                 $breakdownvariants = !$israndomquestion && $this->stats->for_slot($step->slot)->break_down_by_variant();
                 // If this is a variant we have not seen before create a place to store stats calculations for this variant.
-                if ($breakdownvariants && is_null($this->stats->for_slot($step->slot , $step->variant))) {
+                if ($breakdownvariants && !$this->stats->has_slot($step->slot, $step->variant)) {
                     $question = $this->stats->for_slot($step->slot)->question;
                     $this->stats->initialise_for_slot($step->slot, $question, $step->variant);
                     $this->stats->for_slot($step->slot, $step->variant)->randomguessscore =
@@ -118,14 +118,14 @@ class calculator {
 
                 // If this is a random question do the calculations for sub question stats.
                 if ($israndomquestion) {
-                    if (is_null($this->stats->for_subq($step->questionid))) {
+                    if (!$this->stats->has_subq($step->questionid)) {
                         $this->stats->initialise_for_subq($step);
                     } else if ($this->stats->for_subq($step->questionid)->maxmark != $step->maxmark) {
                         $this->stats->for_subq($step->questionid)->differentweights = true;
                     }
 
                     // If this is a variant of this subq we have not seen before create a place to store stats calculations for it.
-                    if (is_null($this->stats->for_subq($step->questionid, $step->variant))) {
+                    if (!$this->stats->has_subq($step->questionid, $step->variant)) {
                         $this->stats->initialise_for_subq($step, $step->variant);
                     }
 
index 5be3e42..3e06f3c 100644 (file)
@@ -128,6 +128,11 @@ class analysis_for_question {
         if (!isset($this->subparts[$variantno])) {
             $this->initialise_stats_for_variant($variantno);
         }
+        if (!isset($this->subparts[$variantno][$subpartid])) {
+            debugging('Unexpected sub-part id ' . $subpartid .
+                    ' encountered.');
+            $this->subparts[$variantno][$subpartid] = new analysis_for_subpart();
+        }
         return $this->subparts[$variantno][$subpartid];
     }
 
index a9e8a86..cbb7352 100644 (file)
@@ -47,6 +47,11 @@ namespace core_question\statistics\responses;
  */
 class analysis_for_subpart {
 
+    /**
+     * @var analysis_for_class[]
+     */
+    protected $responseclasses;
+
     /**
      * Takes an array of possible_responses as returned from {@link \question_type::get_possible_responses()}.
      *
@@ -57,14 +62,11 @@ class analysis_for_subpart {
             foreach ($responseclasses as $responseclassid => $responseclass) {
                 $this->responseclasses[$responseclassid] = new analysis_for_class($responseclass, $responseclassid);
             }
+        } else {
+            $this->responseclasses = [];
         }
     }
 
-    /**
-     * @var analysis_for_class[]
-     */
-    protected $responseclasses;
-
     /**
      * Unique ids for response classes.
      *
@@ -81,7 +83,12 @@ class analysis_for_subpart {
      * @return analysis_for_class
      */
     public function get_response_class($classid) {
+        if (!isset($this->responseclasses[$classid])) {
+            debugging('Unexpected class id ' . $classid . ' encountered.');
+            $this->responseclasses[$classid] = new analysis_for_class('[Unknown]', $classid);
+        }
         return $this->responseclasses[$classid];
+
     }
 
     /**
diff --git a/question/type/calculated/pix/icon.svg b/question/type/calculated/pix/icon.svg
new file mode 100644 (file)
index 0000000..aac701f
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M11.197 15v-1.232h1.231V15h-1.231zm1.119-1.657h-1.119v-.291a1.935 1.935 0 0 1 .179-.896 2.72 2.72 0 0 1 .716-.784c.228-.173.441-.364.639-.571a.772.772 0 0 0 .156-.47.793.793 0 0 0-.235-.616 1.114 1.114 0 0 0-.772-.257 1.121 1.121 0 0 0-.784.268 1.42 1.42 0 0 0-.437.818l-1.119-.135c.029-.518.272-1 .671-1.332a2.366 2.366 0 0 1 1.624-.549 2.454 2.454 0 0 1 1.679.549c.391.314.621.786.627 1.288a1.405 1.405 0 0 1-.235.772 5.05 5.05 0 0 1-.985.985c-.192.14-.356.315-.482.516a1.749 1.749 0 0 0-.123.705zm-10.637.022v-1.119h4.479v1.119H1.679zm0-1.937v-1.119h4.479v1.119H1.679zm13.582-5.676v1.119h-4.299c.049-.437.194-.857.425-1.231a8.204 8.204 0 0 1 1.377-1.512 8.714 8.714 0 0 0 1.008-1.052c.159-.219.249-.48.257-.751a.851.851 0 0 0-.257-.627.943.943 0 0 0-1.221 0c-.173.22-.264.493-.257.773l-1.187-.112A2.007 2.007 0 0 1 11.79.903a2.306 2.306 0 0 1 1.444-.436c.545-.03 1.08.155 1.49.515.354.328.55.793.537 1.276a2.22 2.22 0 0 1-.157.829c-.123.295-.289.57-.492.817a7.781 7.781 0 0 1-.807.817q-.582.538-.739.706a2.264 2.264 0 0 0-.246.336h2.441v-.011zm-7.703.224V4.262h-1.68V3.143h1.68V1.486h1.119v1.657h1.736v1.119H8.677v1.714H7.558zM5.05 5.752v1.119H.75c.049-.437.194-.858.426-1.231a8.192 8.192 0 0 1 1.399-1.512c.369-.321.71-.674 1.019-1.052.159-.219.249-.48.258-.751a.858.858 0 0 0-.224-.627.822.822 0 0 0-.605-.224.818.818 0 0 0-.616.236 1.186 1.186 0 0 0-.257.772L.896 2.359A2.004 2.004 0 0 1 1.579.903 2.302 2.302 0 0 1 3.023.456a2.082 2.082 0 0 1 1.489.515c.355.328.55.793.538 1.276 0 .284-.053.565-.157.829-.125.294-.29.569-.493.817a7.772 7.772 0 0 1-.806.817l-.728.672a2.195 2.195 0 0 0-.246.336h2.43v.034z"/></g></svg>
\ No newline at end of file
diff --git a/question/type/calculatedmulti/pix/icon.svg b/question/type/calculatedmulti/pix/icon.svg
new file mode 100644 (file)
index 0000000..e236c64
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M11.012 15.594v-1.181h1.18v1.181h-1.18zm1.073-1.588h-1.073v-.279a1.856 1.856 0 0 1 .172-.859c.18-.281.414-.526.687-.719a5.2 5.2 0 0 0 .611-.547.737.737 0 0 0 .15-.526.758.758 0 0 0-.225-.547 1.067 1.067 0 0 0-.74-.247 1.077 1.077 0 0 0-.752.257c-.223.207-.37.483-.418.784l-1.073-.129a1.79 1.79 0 0 1 .644-1.277c.434-.364.99-.551 1.556-.526a2.348 2.348 0 0 1 1.609.526c.375.301.595.754.601 1.234a1.348 1.348 0 0 1-.225.741c-.27.356-.588.674-.944.944a1.78 1.78 0 0 0-.462.493 1.666 1.666 0 0 0-.118.677zm-10.194 0v-1.074h4.292v1.074H1.891zm0-1.857v-1.073h4.292v1.073H1.891zm13.016-6.664v1.073h-4.12a2.81 2.81 0 0 1 .408-1.18 7.79 7.79 0 0 1 1.319-1.449c.35-.309.673-.646.966-1.009a1.3 1.3 0 0 0 .247-.719.83.83 0 0 0-.247-.601.901.901 0 0 0-1.169 0c-.167.21-.255.473-.247.741l-1.17-.118a1.918 1.918 0 0 1 .655-1.395 2.212 2.212 0 0 1 1.384-.419 2 2 0 0 1 1.427.494c.34.315.528.76.515 1.223.001.272-.05.542-.15.794a3.208 3.208 0 0 1-.472.784 7.619 7.619 0 0 1-.773.783q-.558.515-.708.676a2.018 2.018 0 0 0-.236.322h2.371zm-7.383.225V4.101H5.915V3.028h1.609v-1.61h1.074v1.577h1.663v1.074H8.598V5.71H7.524zm-2.403-.225v1.073H1c.046-.419.186-.822.408-1.18a7.813 7.813 0 0 1 1.341-1.449c.342-.309.658-.647.944-1.009.153-.209.239-.46.247-.719a.817.817 0 0 0-.214-.601.784.784 0 0 0-.58-.182.786.786 0 0 0-.59.225c-.167.21-.254.473-.247.741l-1.18-.161A1.921 1.921 0 0 1 1.783.828 2.213 2.213 0 0 1 3.178.409a2.002 2.002 0 0 1 1.428.494c.339.315.527.76.515 1.223 0 .272-.051.542-.151.794a3.208 3.208 0 0 1-.472.784 7.609 7.609 0 0 1-.772.783q-.558.515-.709.676a2.13 2.13 0 0 0-.236.322h2.34z"/><path vector-effect="non-scaling-stroke" stroke-width="1.073" stroke="#000" stroke-miterlimit="10" d="M1.676 8.071h12.877"/></g></svg>
\ No newline at end of file
diff --git a/question/type/calculatedsimple/pix/icon.svg b/question/type/calculatedsimple/pix/icon.svg
new file mode 100644 (file)
index 0000000..2b818fd
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M3.676 8.93l2.249-.229c.072.631.362 1.218.819 1.658a2.495 2.495 0 0 0 1.679.53 2.566 2.566 0 0 0 1.681-.471c.353-.261.562-.671.569-1.108a.996.996 0 0 0-.239-.689 1.899 1.899 0 0 0-.84-.48c-.268-.093-.881-.26-1.84-.5a6.303 6.303 0 0 1-2.608-1.129 3.002 3.002 0 0 1-1.06-2.31 2.938 2.938 0 0 1 .511-1.63c.346-.521.84-.925 1.42-1.16a5.708 5.708 0 0 1 2.249-.399 4.835 4.835 0 0 1 3.249.95 3.338 3.338 0 0 1 1.14 2.519l-2.31.101a2.014 2.014 0 0 0-.641-1.27 2.326 2.326 0 0 0-1.46-.391 2.644 2.644 0 0 0-1.579.41.827.827 0 0 0-.37.71c0 .253.109.493.301.66a6.073 6.073 0 0 0 2.13.77c.861.174 1.701.449 2.499.819a3.23 3.23 0 0 1 1.3 1.21c.32.552.479 1.183.46 1.819a3.385 3.385 0 0 1-.55 1.84 3.28 3.28 0 0 1-1.55 1.279 6.524 6.524 0 0 1-2.489.42 5.002 5.002 0 0 1-3.34-1 4.347 4.347 0 0 1-1.38-2.929z" fill="#999"/><path d="M11.197 15v-1.232h1.231V15h-1.231zm1.119-1.657h-1.119v-.291a1.935 1.935 0 0 1 .179-.896 2.72 2.72 0 0 1 .716-.784c.228-.173.441-.364.639-.571a.772.772 0 0 0 .156-.47.791.791 0 0 0-.235-.616 1.112 1.112 0 0 0-.772-.257 1.123 1.123 0 0 0-.784.268 1.42 1.42 0 0 0-.437.818l-1.119-.135c.029-.518.272-1 .671-1.332a2.366 2.366 0 0 1 1.624-.549 2.454 2.454 0 0 1 1.679.549c.391.314.621.786.627 1.288a1.405 1.405 0 0 1-.235.772 5.05 5.05 0 0 1-.985.985c-.192.14-.356.315-.482.516a1.752 1.752 0 0 0-.123.705zm-10.637.022v-1.119h4.479v1.119H1.679zm0-1.937v-1.119h4.479v1.119H1.679zm13.582-5.676v1.119h-4.299c.049-.437.194-.857.425-1.231a8.236 8.236 0 0 1 1.377-1.512 8.714 8.714 0 0 0 1.008-1.052c.159-.219.249-.48.257-.751a.848.848 0 0 0-.257-.627.943.943 0 0 0-1.221 0c-.173.22-.264.493-.257.773l-1.187-.112A2.007 2.007 0 0 1 11.79.903a2.304 2.304 0 0 1 1.444-.436c.545-.03 1.08.155 1.49.515.354.328.55.793.537 1.276a2.22 2.22 0 0 1-.157.829c-.123.295-.289.57-.492.817a7.781 7.781 0 0 1-.807.817q-.582.538-.739.706a2.317 2.317 0 0 0-.246.336h2.441v-.011zm-7.703.224V4.262h-1.68V3.143h1.68V1.486h1.119v1.657h1.736v1.119H8.677v1.714H7.558zM5.05 5.752v1.119H.75c.049-.437.194-.858.426-1.231a8.192 8.192 0 0 1 1.399-1.512c.369-.321.71-.674 1.019-1.052.159-.219.249-.48.258-.751a.856.856 0 0 0-.224-.627.822.822 0 0 0-.605-.224.818.818 0 0 0-.616.236 1.186 1.186 0 0 0-.257.772L.896 2.359A2.004 2.004 0 0 1 1.579.903 2.302 2.302 0 0 1 3.023.456a2.082 2.082 0 0 1 1.489.515c.355.328.55.793.538 1.276 0 .284-.053.565-.157.829-.125.294-.29.569-.493.817a7.772 7.772 0 0 1-.806.817l-.728.672a2.195 2.195 0 0 0-.246.336h2.43v.034z"/></g></svg>
\ No newline at end of file
diff --git a/question/type/ddimageortext/pix/icon.svg b/question/type/ddimageortext/pix/icon.svg
new file mode 100644 (file)
index 0000000..1f9be66
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M6.85 9.15v3.3h-1.6l2.8 2.8 2.6-2.8h-1.5v-3.3h3.3v1.5l2.8-2.6-2.8-2.8v1.6h-3.3v-3.3h1.5L7.95.75l-2.7 2.8h1.6v3.3h-3.3v-1.6l-2.8 2.8 2.8 2.6v-1.5h3.3zm.9-.9h.5v-.5h-.5v.5z"/></g></svg>
\ No newline at end of file
diff --git a/question/type/ddmarker/pix/icon.svg b/question/type/ddmarker/pix/icon.svg
new file mode 100644 (file)
index 0000000..514544e
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><clipPath id="b"><path d="M.35.3h15.3v15.4H.35V.3z" fill="#FFF"/></clipPath><g clip-path="url(#b)"><path d="M9.139 11.539v.85h1.5l-2.6 2.9-2.8-2.9h1.6v-.85h2.3zm-4.695-2.35h-.85v1.5l-2.9-2.6 2.9-2.8v1.6h.85v2.3zm2.406-4.65v-.85h-1.5l2.6-2.9 2.8 2.9h-1.6v.85h-2.3zm4.639 2.25h.85v-1.5l2.9 2.6-2.9 2.8v-1.6h-.85v-2.3zm-.939 4.129h-.145L8.239 9.089l.505-.512 1.879 2.194a.153.153 0 0 1-.073.147zM9.394 7.406L9.25 7.26l-.289-.146-.289.146-1.661-1.39a.37.37 0 0 0 0-.512l-.216-.146a.214.214 0 0 0-.289 0L4.917 6.821a.221.221 0 0 0 0 .293l.144.146.289.146h.217l1.372 1.61a.368.368 0 0 0 0 .512l.144.146a.214.214 0 0 0 .289 0l2.022-2.048a.221.221 0 0 0 0-.22z"/></g></g></svg>
\ No newline at end of file
diff --git a/question/type/ddwtos/pix/icon.svg b/question/type/ddwtos/pix/icon.svg
new file mode 100644 (file)
index 0000000..6dd097b
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M9.173 11.5v.85h1.5l-2.6 2.9-2.8-2.9h1.6v-.85h2.3zM4.478 9.15h-.85v1.5l-2.9-2.6 2.9-2.8v1.6h.85v2.3zM6.884 4.5v-.85h-1.5L7.983.75l2.801 2.9h-1.6v.85h-2.3zM11.522 6.75h.851v-1.5l2.899 2.6-2.899 2.8v-1.6h-.851v-2.3zM5.361 5h5.279v1.76h-.24a1.601 1.601 0 0 0-.719-1.28l-.96-.16v4.64a.876.876 0 0 0 .16.64c.215.133.468.189.72.16V11h-3.12v-.24a1.04 1.04 0 0 0 .64-.16.885.885 0 0 0 .16-.64V5.32l-.96.16A1.523 1.523 0 0 0 5.6 6.76h-.239V5z"/></g></svg>
\ No newline at end of file
diff --git a/question/type/description/pix/icon.svg b/question/type/description/pix/icon.svg
new file mode 100644 (file)
index 0000000..3afc0e5
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M1.5 12.5h12.7M1.5 2.5h13m0 10.5V2m-13 11V2" fill="none" vector-effect="non-scaling-stroke" stroke="#000" stroke-miterlimit="10"/><path d="M2 3h12v9H2V3z" fill="#FFF"/><path d="M3 4.5h2m-2 6h2m-2-2h5m-2 2h2m3-4h2m-10 0h3m0-2h6m-5 2h3" fill="#A5B0B0" vector-effect="non-scaling-stroke" stroke="#A5B0B0" stroke-miterlimit="10"/><path d="M9 8.5h4m-3 1h1" fill="#0092FF" vector-effect="non-scaling-stroke" stroke="#0092FF" stroke-miterlimit="10"/><path vector-effect="non-scaling-stroke" stroke="#824E5D" stroke-miterlimit="10" d="M11 9.5h1"/><path vector-effect="non-scaling-stroke" stroke="#009F00" stroke-miterlimit="10" d="M9 9.5h1"/><path d="M9 10.5h4m-1-1h1" fill="#239771" vector-effect="non-scaling-stroke" stroke="#239771" stroke-miterlimit="10"/></g></svg>
\ No newline at end of file
diff --git a/question/type/essay/pix/icon.svg b/question/type/essay/pix/icon.svg
new file mode 100644 (file)
index 0000000..89a90da
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M2 15.5h12M2 .6h12m-.5 14.9V.6m-11 14.9V.6" fill="none" vector-effect="non-scaling-stroke" stroke="#000" stroke-miterlimit="10"/><path d="M3 1h10v14H3V1z" fill="#FFF"/><path d="M4 7.5h1m6 4h1m-3-2h3m-5 2h3m-4-4h3m-1-2h4m-8 8.1h3m3-6.1h2m-4 6.1h2M4 9.5h4m-4 2h2m-2-6h3" fill="#A5B0B0" vector-effect="non-scaling-stroke" stroke="#A5B0B0" stroke-miterlimit="10"/><path d="M9 2.5h2m-6 0h3" fill="#7C7C7C" vector-effect="non-scaling-stroke" stroke="#7C7C7C" stroke-miterlimit="10"/></g></svg>
\ No newline at end of file
diff --git a/question/type/gapselect/pix/icon.svg b/question/type/gapselect/pix/icon.svg
new file mode 100644 (file)
index 0000000..9d3d4c0
--- /dev/null
@@ -0,0 +1 @@
+<svg id="Ebene_3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet"><style>.st0{fill:#fff}.st0,.st1{stroke:#000;stroke-miterlimit:10}</style><path class="st0" d="M2 6zM0 0zM14 7zM8 11z"/><path class="st1" d="M8 12L3 7h10z"/></svg>
\ No newline at end of file
diff --git a/question/type/match/pix/icon.svg b/question/type/match/pix/icon.svg
new file mode 100644 (file)
index 0000000..7a3f602
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)" stroke="#000" stroke-miterlimit="10"><path d="M6 13.5h4m-4-5h4m-4-5h4" fill="none" vector-effect="non-scaling-stroke"/><path d="M12.5 13.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm0-5a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm0-5a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm-11.2 0a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm0 5a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm0 5a1 1 0 1 1 2 0 1 1 0 0 1-2 0z" vector-effect="non-scaling-stroke"/></g></svg>
\ No newline at end of file
diff --git a/question/type/missingtype/pix/icon.svg b/question/type/missingtype/pix/icon.svg
new file mode 100644 (file)
index 0000000..193df63
--- /dev/null
@@ -0,0 +1 @@
+<svg id="Ebene_3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet"><style>.st0,.st1{fill:#fff;stroke:#000;stroke-miterlimit:10}.st1{fill:none}.st2{font-family:&apos;ArialMT&apos;}.st3{font-size:18px}</style><path class="st0" d="M2 6zM0 0zM14 7zM8 11z"/><text transform="translate(2.656 14.533)" class="st2 st3">?</text></svg>
\ No newline at end of file
diff --git a/question/type/multianswer/pix/icon.svg b/question/type/multianswer/pix/icon.svg
new file mode 100644 (file)
index 0000000..b8339f1
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M9 1h6v3H9V1zM8 12h3v3H8v-3zM1 6h7v3H1V6z"/><path d="M1 1h2v3H1V1zm4 0h2v3H5V1zM1 12h5v3H1v-3zm12 0h2v3h-2v-3zm-3-6h5v3h-5V6z" fill="#8E8E8E"/></g></svg>
\ No newline at end of file
diff --git a/question/type/multichoice/pix/icon.svg b/question/type/multichoice/pix/icon.svg
new file mode 100644 (file)
index 0000000..da42e99
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M7 3h7v1H7V3zm0 10h7v1H7v-1zm0-5h7v1H7V8z"/><path d="M2 13.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm0-10a1 1 0 1 1 2 0 1 1 0 0 1-2 0zm0 5a1 1 0 1 1 2 0 1 1 0 0 1-2 0z" vector-effect="non-scaling-stroke" stroke="#000" stroke-miterlimit="10"/></g></svg>
\ No newline at end of file
diff --git a/question/type/numerical/pix/icon.svg b/question/type/numerical/pix/icon.svg
new file mode 100644 (file)
index 0000000..80cb04e
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><clipPath id="b"><path d="M0 2.5h16v11H0v-11z" fill="#FFF"/></clipPath><g clip-path="url(#b)"><path d="M10.915 6.004v.779H8.092c0-.292.097-.584.292-.779.267-.346.56-.671.876-.973.195-.292.487-.584.681-.779a.739.739 0 0 0 .195-.487c0-.194-.097-.292-.195-.389-.194-.195-.584-.195-.778 0-.098.097-.195.195-.195.389h-.779c0-.389.195-.681.487-.973.194-.195.584-.292.876-.292.389 0 .681.097.973.292.292.292.39.584.39.876 0 .195 0 .39-.098.584-.097.195-.194.39-.292.487-.194.195-.292.389-.486.487-.39.292-.487.389-.584.486-.098.098-.098.195-.195.195l1.655.097zm-3.894.682h-.876V3.668c-.292.292-.584.487-.974.584v-.681c.195-.098.487-.195.682-.39.194-.194.389-.389.486-.681h.682v4.186zm7.788 1.947H1.18v3.894h14.602v.973H.207V7.659h15.575v4.868h-.973V8.633z"/><path d="M1.18 8.633h13.629v3.894H1.18V8.633z" fill="#FFF"/></g></g></svg>
\ No newline at end of file
diff --git a/question/type/random/pix/icon.svg b/question/type/random/pix/icon.svg
new file mode 100644 (file)
index 0000000..d8ce4bd
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M14.7 5.5l-.096 5.97-5.008 3.23L9.5 8.143 14.7 5.5zM7.8 1.1l5.7 2.3-4.9 3-5.8-2.8 5-2.5zm-.1 7l.1 6.7-5.9-3.2-.1-6.7 5.9 3.2z" vector-effect="non-scaling-stroke" stroke="#000" stroke-miterlimit="10"/><path d="M7.9.1s-.1 0-.1.1L1.6 3.6c-.1 0 0 0 0 .1l6.9 3.5c.1.1.2.1.3 0l6.1-3.7c.1-.1.1-.1 0-.2L8.2.3C8.1.1 8 .1 7.9.1zm-.6.8h.4c.6 0 1.1.3 1.1.6 0 .2-.5.5-1.1.5-.6 0-1.1-.3-1.1-.6 0-.2.3-.4.7-.5zM3.8 2.8h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6 0-1.1-.3-1.1-.6s.3-.5.7-.6zm5.7-.9h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6-.1-1-.3-1-.7 0-.2.3-.4.6-.5zM1.2 4c0 .1 0 .1 0 0l.1 7.9c0 .1 0 .1.1.1l6.7 3.7c.2.1.2.1.2-.1v-8c0-.1 0-.2-.1-.2L1.2 4c.1.1 0 0 0 0zM6 3.9h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.5c-.6 0-1.1-.2-1-.5 0-.3.2-.5.6-.6zm5.8-1h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6 0-1.1-.3-1.1-.6.1-.3.3-.5.7-.6zM1.9 5.4c0-.1 0-.1 0 0 .3-.1.7.1 1 .5.3.5.3 1.1.1 1.4-.3.2-.8.1-1.2-.4-.3-.5-.4-1.2-.1-1.4.1-.1.1-.1.2-.1zM8.3 5h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6 0-1.1-.3-1.1-.6.1-.3.3-.5.7-.6zm7-1.3s0 .1 0 0L9 7.6c-.1.1-.1.1-.1.2v7.9c0 .1 0 .2.1.1l6.2-3.9c.1-.1.1-.1.1-.2v-8c.1 0 .1 0 0 0zm-.8 1.5c.2 0 .4 0 .5.2.2.3.1 1-.3 1.4-.4.4-.9.5-1.1.2-.2-.3-.1-1 .3-1.4.2-.2.4-.4.6-.4zM6.4 7.6c.3 0 .6.2.9.5.3.5.4 1.1.1 1.4-.3.3-.8.1-1.1-.4-.4-.5-.4-1.1-.1-1.4 0 0 .1 0 .2-.1zM4.1 9c.3 0 .7.2.9.5.3.5.4 1.1.1 1.4-.2.3-.7.1-1.1-.4-.3-.5-.4-1.1-.1-1.4.1 0 .1-.1.2-.1zm-2.2 1.4c.1 0 .1 0 0 0 .3-.1.7.1 1 .5.3.5.4 1.1.1 1.4-.3.3-.8.1-1.1-.4-.3-.5-.4-1.1-.1-1.4 0-.1.1-.1.1-.1zm10.7-1.5c.2 0 .4 0 .5.2.2.3.1 1-.3 1.4-.4.4-.9.5-1.1.2-.2-.3-.1-1 .3-1.4.2-.2.4-.3.6-.4zm-6.3 3.9c.1-.1.1-.1 0 0 .3-.1.7.1 1 .5.3.5.4 1.1.1 1.4-.3.3-.8.1-1.1-.4-.3-.5-.4-1.1-.1-1.4 0-.1.1-.1.1-.1zm4.2-.1c.2 0 .4 0 .5.2.2.3.1 1-.3 1.4-.4.4-.9.5-1.1.2-.2-.3-.1-1 .3-1.4.2-.2.4-.4.6-.4z" fill="#C4CCCB"/></g></svg>
\ No newline at end of file
diff --git a/question/type/randomsamatch/pix/icon.svg b/question/type/randomsamatch/pix/icon.svg
new file mode 100644 (file)
index 0000000..366a868
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><clipPath id="b"><path d="M0 .571h16v14.858H0V.571z" fill="#FFF"/></clipPath><g clip-path="url(#b)"><path d="M13.183 13.632a1.127 1.127 0 1 1 2.253-.071 1.127 1.127 0 0 1-2.253.071zm0-5.633a1.129 1.129 0 1 1 1.127 1.093 1.129 1.129 0 0 1-1.127-1.093zm0-5.634a1.128 1.128 0 1 1 2.254-.073 1.128 1.128 0 0 1-2.254.073zm-12.62 0a1.13 1.13 0 0 1 1.703-1.006A1.127 1.127 0 1 1 .563 2.365zm0 5.634a1.129 1.129 0 1 1 1.128 1.093A1.129 1.129 0 0 1 .563 8v-.001zm0 5.633a1.13 1.13 0 0 1 1.703-1.006 1.127 1.127 0 0 1-.576 2.099 1.129 1.129 0 0 1-1.127-1.093z" vector-effect="non-scaling-stroke" stroke-width="1.127" stroke="#000" stroke-miterlimit="10"/><path d="M7.211 10.68v-.36a3.366 3.366 0 0 1 .191-1.194 2.79 2.79 0 0 1 .475-.779 8.98 8.98 0 0 1 .856-.833c.307-.249.577-.54.8-.867.122-.217.184-.462.18-.711-.004-.46-.2-.896-.542-1.205a1.837 1.837 0 0 0-1.329-.53 1.777 1.777 0 0 0-1.261.473c-.402.4-.657.925-.722 1.488l-1.126-.147a3.157 3.157 0 0 1 .934-2.073c.603-.5 1.37-.757 2.152-.721.823-.038 1.63.24 2.254.778.543.468.852 1.153.846 1.87a2.372 2.372 0 0 1-.294 1.126 5.517 5.517 0 0 1-1.127 1.296 5.918 5.918 0 0 0-.754.756c-.121.17-.209.361-.259.563a4.71 4.71 0 0 0-.102 1.025H7.256l-.045.045zm-.067 2.389v-1.352h1.352v1.352H7.144z"/></g></g></svg>
\ No newline at end of file
diff --git a/question/type/shortanswer/pix/icon.svg b/question/type/shortanswer/pix/icon.svg
new file mode 100644 (file)
index 0000000..a02a4f2
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M16 6V5H0v6h16v-1H1V6h14v4h1V6z"/><path d="M1 6h14v4H1V6z" fill="#FFF"/></g></svg>
\ No newline at end of file
diff --git a/question/type/truefalse/pix/icon.svg b/question/type/truefalse/pix/icon.svg
new file mode 100644 (file)
index 0000000..06a70e3
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M10 8a2 2 0 1 1 4.001.001A2 2 0 0 1 10 8zM2 8a2 2 0 1 1 4.001.001A2 2 0 0 1 2 8z"/></g></svg>
\ No newline at end of file
index f98573f..9aa56d8 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2018011800.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2018012500.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.
 
-$release  = '3.5dev (Build: 20180118)'; // Human-friendly version name
+$release  = '3.5dev (Build: 20180125)'; // Human-friendly version name
 
 $branch   = '35';                       // This version's branch.
 $maturity = MATURITY_ALPHA;             // This version's maturity level.