Merge branch 'MDL-69458-39' of git://github.com/mihailges/moodle into MOODLE_39_STABLE
authorAndrew Nicols <andrew@nicols.co.uk>
Thu, 27 Aug 2020 04:43:10 +0000 (12:43 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Thu, 27 Aug 2020 04:43:10 +0000 (12:43 +0800)
21 files changed:
admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
admin/tool/lp/tests/behat/course_competencies.feature
cohort/index.php
competency/classes/api.php
h5p/classes/api.php
h5p/classes/editor_framework.php
h5p/classes/framework.php
h5p/tests/generator_test.php
lang/en/badges.php
lang/en/contentbank.php
lib/classes/task/backup_cleanup_task.php
lib/db/install.xml
lib/db/upgrade.php
lib/tests/scheduled_task_test.php
mod/lesson/lang/en/lesson.php
mod/lti/view.php
theme/boost/scss/preset/default.scss
theme/boost/style/moodle.css
theme/classic/scss/preset/default.scss
theme/classic/style/moodle.css
version.php

index 63d33fe..54d9c5b 100644 (file)
@@ -135,7 +135,7 @@ $string['effectiveretentionperioduser'] = '{$a} (since the last time the user ac
 $string['emailsalutation'] = 'Dear {$a},';
 $string['errorcannotrequestdeleteforself'] = 'You don\'t have permission to create deletion request for yourself.';
 $string['errorcannotrequestdeleteforother'] = 'You don\'t have permission to create deletion request for this user.';
-$string['errorinvalidrequestcomments'] = 'Please ensure your comment contains plain text only.';
+$string['errorinvalidrequestcomments'] = 'The comments field may contain plain text only.';
 $string['errorinvalidrequestcreationmethod'] = 'Invalid request creation method!';
 $string['errorinvalidrequeststatus'] = 'Invalid request status!';
 $string['errorinvalidrequesttype'] = 'Invalid request type!';
index f765213..bb57d22 100644 (file)
@@ -12,8 +12,8 @@ Feature: See the competencies for an activity on the course competencies page.
       | Test-Comp1 | ID-FW1 |
       | Test-Comp2 | ID-FW1 |
     Given the following "courses" exist:
-      | shortname | fullname   |
-      | C1        | Course 1 |
+      | shortname | fullname   | enablecompletion |
+      | C1        | Course 1   | 1                |
     And the following "users" exist:
       | username | firstname | lastname | email |
       | student1 | Student | 1 | student1@example.com |
@@ -21,9 +21,9 @@ Feature: See the competencies for an activity on the course competencies page.
       | user | course | role |
       | student1 | C1 | student |
     And the following "activities" exist:
-      | activity | name       | intro      | course | idnumber |
-      | page     | PageName1  | PageDesc1  | C1     | PAGE1    |
-      | page     | PageName2  | PageDesc2  | C1     | PAGE2    |
+      | activity | name       | intro      | course | idnumber | completion | completionview |
+      | page     | PageName1  | PageDesc1  | C1     | PAGE1    | 1          | 1              |
+      | page     | PageName2  | PageDesc2  | C1     | PAGE2    | 1          | 1              |
     And I log in as "admin"
     And I am on site homepage
     And I follow "Course 1"
@@ -61,3 +61,15 @@ Feature: See the competencies for an activity on the course competencies page.
     And I should not see "Test-Comp1"
     And I should not see "Test-Comp2"
     And I should see "No competencies have been linked to this activity or resource."
+
+  @javascript
+  Scenario: None course competencies page.
+    When I log in as "student1"
+    And I am on site homepage
+    And I follow "Course 1"
+    And I follow "PageName1"
+    Then I should see "Test page content"
+    And I am on site homepage
+    And I follow "Course 1"
+    And I follow "PageName1"
+    Then I should see "Test page content"
index f611f98..0341bf9 100644 (file)
@@ -154,7 +154,7 @@ foreach($cohorts['cohorts'] as $cohort) {
         $cohortmanager = has_capability('moodle/cohort:manage', $cohortcontext);
         $cohortcanassign = has_capability('moodle/cohort:assign', $cohortcontext);
 
-        $urlparams = array('id' => $cohort->id, 'returnurl' => $baseurl->out_as_local_url());
+        $urlparams = array('id' => $cohort->id, 'returnurl' => $baseurl->out_as_local_url(false));
         $showhideurl = new moodle_url('/cohort/edit.php', $urlparams + array('sesskey' => sesskey()));
         if ($cohortmanager) {
             if ($cohort->visible) {
index ba22662..f5df09e 100644 (file)
@@ -4660,6 +4660,9 @@ class api {
                 $recommend = false;
                 $strdesc = 'evidence_coursemodulecompleted';
 
+                if ($outcome == course_module_competency::OUTCOME_NONE) {
+                    continue;
+                }
                 if ($outcome == course_module_competency::OUTCOME_EVIDENCE) {
                     $action = evidence::ACTION_LOG;
 
@@ -4720,6 +4723,9 @@ class api {
             $recommend = false;
             $strdesc = 'evidence_coursecompleted';
 
+            if ($outcome == course_module_competency::OUTCOME_NONE) {
+                continue;
+            }
             if ($outcome == course_competency::OUTCOME_EVIDENCE) {
                 $action = evidence::ACTION_LOG;
 
index 6cd3484..cab3476 100644 (file)
@@ -164,6 +164,7 @@ class api {
             unset($library->major_version);
             $library->minorVersion = (int) $library->minorversion;
             unset($library->minorversion);
+            $library->metadataSettings = json_decode($library->metadatasettings);
 
             // If we already add this library means that it is an old version,as the previous query was sorted by version.
             if (isset($added[$library->name])) {
index c4b575c..8d7f9b4 100644 (file)
@@ -228,7 +228,7 @@ class editor_framework implements H5peditorStorage {
         if ($libraries !== null) {
             // Get details for the specified libraries.
             $librariesin = [];
-            $fields = 'title, runnable';
+            $fields = 'title, runnable, metadatasettings';
 
             foreach ($libraries as $library) {
                 $params = [
@@ -242,11 +242,12 @@ class editor_framework implements H5peditorStorage {
                 if ($details) {
                     $library->title = $details->title;
                     $library->runnable = $details->runnable;
+                    $library->metadataSettings = json_decode($details->metadatasettings);
                     $librariesin[] = $library;
                 }
             }
         } else {
-            $fields = 'id, machinename as name, title, majorversion, minorversion';
+            $fields = 'id, machinename as name, title, majorversion, minorversion, metadatasettings';
             $librariesin = api::get_contenttype_libraries($fields);
         }
 
index 2e4a2ca..4b05422 100644 (file)
@@ -685,6 +685,9 @@ class framework implements \H5PFrameworkInterface {
      *                           - dropLibraryCss(optional): list of associative arrays containing:
      *                             - machineName: machine name for the librarys that are to drop their css
      *                           - semantics(optional): Json describing the content structure for the library
+     *                           - metadataSettings(optional): object containing:
+     *                             - disable: 1 if metadata is disabled completely
+     *                             - disableExtraTitleField: 1 if the title field is hidden in the form
      * @param bool $new Whether it is a new or existing library.
      */
     public function saveLibraryData(&$librarydata, $new = true) {
@@ -722,6 +725,7 @@ class framework implements \H5PFrameworkInterface {
             'addto' => isset($librarydata['addTo']) ? json_encode($librarydata['addTo']) : null,
             'coremajor' => isset($librarydata['coreApi']['majorVersion']) ? $librarydata['coreApi']['majorVersion'] : null,
             'coreminor' => isset($librarydata['coreApi']['majorVersion']) ? $librarydata['coreApi']['minorVersion'] : null,
+            'metadatasettings' => isset($librarydata['metadataSettings']) ? $librarydata['metadataSettings'] : null,
         );
 
         if ($new) {
index 478ab57..dc266f5 100644 (file)
@@ -246,6 +246,7 @@ class generator_testcase extends \advanced_testcase {
             'addto' => '/regex11/',
             'coremajor' => null,
             'coreminor' => null,
+            'metadatasettings' => null,
         ];
 
         $this->assertEquals($expected, $data);
index f0343ee..62e4b4f 100644 (file)
@@ -304,7 +304,7 @@ $string['error:invalidexpiredate'] = 'Expiry date has to be in the future.';
 $string['error:invalidexpireperiod'] = 'Expiry period cannot be negative or equal 0.';
 $string['error:invalidparambadge'] = 'Badge does not exist. ';
 $string['error:noactivities'] = 'There are no activities with completion criteria enabled in this course.';
-$string['error:nobadges'] = 'There are no course or site badges with access enabled to be added as criteria.';
+$string['error:nobadges'] = 'There are currently no badges with access enabled to be added as criteria. A site badge can only have other site badges as criteria. A course badge can have other course badges or site badges as criteria.';
 $string['error:invalidparamcohort'] = 'Cohort does not exist. ';
 $string['error:noactivities'] = 'There are no activities with completion criteria enabled in this course.';
 $string['error:nocohorts'] = 'No cohorts';
index 6411ece..f614161 100644 (file)
@@ -40,7 +40,7 @@ $string['eventcontentupdated'] = 'Content updated';
 $string['eventcontentuploaded'] = 'Content uploaded';
 $string['eventcontentviewed'] = 'Content viewed';
 $string['errordeletingcontentfromcategory'] = 'Error deleting content from category {$a}.';
-$string['errornofile'] = 'A compatible file is needed to create a content';
+$string['errornofile'] = 'A compatible file is needed to create content.';
 $string['deletecontent'] = 'Delete content';
 $string['deletecontentconfirm'] = 'Are you sure you want to delete the content <em>\'{$a->name}\'</em> and all associated files? This action cannot be undone.';
 $string['displaydetails'] = 'Display content bank with file details';
index 1df8fbb..6876b98 100644 (file)
@@ -44,24 +44,27 @@ class backup_cleanup_task extends scheduled_task {
     public function execute() {
         global $DB;
 
-        $timenow = time();
-
-        // Delete old backup_controllers and logs.
         $loglifetime = get_config('backup', 'loglifetime');
-        if (!empty($loglifetime)) {  // Value in days.
-            $loglifetime = $timenow - ($loglifetime * 3600 * 24);
-            // Delete child records from backup_logs.
-            $DB->execute("DELETE FROM {backup_logs}
-                           WHERE EXISTS (
-                               SELECT 'x'
-                                 FROM {backup_controllers} bc
-                                WHERE bc.backupid = {backup_logs}.backupid
-                                  AND bc.timecreated < ?)", array($loglifetime));
-            // Delete records from backup_controllers.
-            $DB->execute("DELETE FROM {backup_controllers}
-                          WHERE timecreated < ?", array($loglifetime));
+
+        if (empty($loglifetime)) {
+            throw new coding_exception('The \'loglifetime\' config is not set. Can\'t proceed and delete old backup records.');
         }
 
+        // First, get the list of all backupids older than loglifetime.
+        $timecreated = time() - ($loglifetime * DAYSECS);
+        $records = $DB->get_records_select('backup_controllers', 'timecreated < ?', array($timecreated), 'id', 'id, backupid');
+
+        foreach ($records as $record) {
+            // Check if there is no incomplete adhoc task relying on the given backupid.
+            $params = array('%' . $record->backupid . '%');
+            $select = $DB->sql_like('customdata', '?', false);
+            $count = $DB->count_records_select('task_adhoc',  $select, $params);
+            if ($count === 0) {
+                // Looks like there is no adhoc task, so we can delete logs and controllers for this backupid.
+                $DB->delete_records('backup_logs', array('backupid' => $record->backupid));
+                $DB->delete_records('backup_controllers', array('backupid' => $record->backupid));
+            }
+        }
     }
 
 }
index 8f91417..a12fa68 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20200504" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20200804" COMMENT="XMLDB file for core Moodle tables"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
 >
         <FIELD NAME="addto" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Plugin configuration data"/>
         <FIELD NAME="coremajor" TYPE="int" LENGTH="4" NOTNULL="false" SEQUENCE="false" COMMENT="H5P core API major version required"/>
         <FIELD NAME="coreminor" TYPE="int" LENGTH="4" NOTNULL="false" SEQUENCE="false" COMMENT="H5P core API minor version required"/>
+        <FIELD NAME="metadatasettings" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Library metadata settings"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </INDEXES>
     </TABLE>
   </TABLES>
-</XMLDB>
\ No newline at end of file
+</XMLDB>
index 94d0c99..7677467 100644 (file)
@@ -2548,5 +2548,46 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2020061501.09);
     }
 
+    if ($oldversion < 2020061501.11) {
+
+        // Define field metadatasettings to be added to h5p_libraries.
+        $table = new xmldb_table('h5p_libraries');
+        $field = new xmldb_field('metadatasettings', XMLDB_TYPE_TEXT, null, null, null, null, null, 'coreminor');
+
+        // Conditionally launch add field metadatasettings.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Get installed library files that have no metadata settings value.
+        $params = [
+            'component' => 'core_h5p',
+            'filearea' => 'libraries',
+            'filename' => 'library.json',
+        ];
+        $sql = "SELECT l.id, f.id as fileid
+                  FROM {files} f
+             LEFT JOIN {h5p_libraries} l ON f.itemid = l.id
+                 WHERE f.component = :component
+                       AND f.filearea = :filearea
+                       AND f.filename = :filename";
+        $libraries = $DB->get_records_sql($sql, $params);
+
+        // Update metadatasettings field when the attribute is present in the library.json file.
+        $fs = get_file_storage();
+        foreach ($libraries as $library) {
+            $jsonfile = $fs->get_file_by_id($library->fileid);
+            $jsoncontent = json_decode($jsonfile->get_content());
+            if (isset($jsoncontent->metadataSettings)) {
+                unset($library->fileid);
+                $library->metadatasettings = json_encode($jsoncontent->metadataSettings);
+                $DB->update_record('h5p_libraries', $library);
+            }
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2020061501.11);
+    }
+
     return true;
 }
index 10ce44b..6b46272 100644 (file)
@@ -148,73 +148,87 @@ class core_scheduled_task_testcase extends advanced_testcase {
         $this->assertContains('2:15 AM', core_text::strtoupper($userdate));
     }
 
-    public function test_reset_scheduled_tasks_for_component() {
-        global $DB;
-
+    public function test_reset_scheduled_tasks_for_component_customised(): void {
         $this->resetAfterTest(true);
-        // Remember the defaults.
-        $defaulttasks = \core\task\manager::load_scheduled_tasks_for_component('moodle');
-        $initcount = count($defaulttasks);
+
+        $tasks = \core\task\manager::load_scheduled_tasks_for_component('moodle');
+
         // Customise a task.
-        $firsttask = reset($defaulttasks);
-        $firsttask->set_minute('1');
-        $firsttask->set_hour('2');
-        $firsttask->set_month('3');
-        $firsttask->set_day_of_week('4');
-        $firsttask->set_day('5');
-        $firsttask->set_customised('1');
-        \core\task\manager::configure_scheduled_task($firsttask);
-        $firsttaskrecord = \core\task\manager::record_from_scheduled_task($firsttask);
-        // We reset this field, because we do not want to compare it.
-        $firsttaskrecord->nextruntime = '0';
+        $task = reset($tasks);
+        $task->set_minute('1');
+        $task->set_hour('2');
+        $task->set_month('3');
+        $task->set_day_of_week('4');
+        $task->set_day('5');
+        $task->set_customised('1');
+        \core\task\manager::configure_scheduled_task($task);
+
+        // Now call reset.
+        \core\task\manager::reset_scheduled_tasks_for_component('moodle');
+
+        // Fetch the task again.
+        $taskafterreset = \core\task\manager::get_scheduled_task(get_class($task));
+
+        // The task should still be the same as the customised.
+        $this->assertTaskEquals($task, $taskafterreset);
+    }
+
+    public function test_reset_scheduled_tasks_for_component_deleted(): void {
+        global $DB;
+        $this->resetAfterTest(true);
 
         // Delete a task to simulate the fact that its new.
-        $secondtask = next($defaulttasks);
-        $DB->delete_records('task_scheduled', array('classname' => '\\' . trim(get_class($secondtask), '\\')));
-        $this->assertFalse(\core\task\manager::get_scheduled_task(get_class($secondtask)));
+        $tasklist = \core\task\manager::load_scheduled_tasks_for_component('moodle');
 
-        // Edit a task to simulate a change in its definition (as if it was not customised).
-        $thirdtask = next($defaulttasks);
-        $thirdtask->set_minute('1');
-        $thirdtask->set_hour('2');
-        $thirdtask->set_month('3');
-        $thirdtask->set_day_of_week('4');
-        $thirdtask->set_day('5');
-        $thirdtaskbefore = \core\task\manager::get_scheduled_task(get_class($thirdtask));
-        $thirdtaskbefore->set_next_run_time(null);      // Ignore this value when comparing.
-        \core\task\manager::configure_scheduled_task($thirdtask);
-        $thirdtask = \core\task\manager::get_scheduled_task(get_class($thirdtask));
-        $thirdtask->set_next_run_time(null);            // Ignore this value when comparing.
-        $this->assertNotEquals($thirdtaskbefore, $thirdtask);
+        // Note: This test must use a task which does not use any random values.
+        $task = \core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class);
+
+        $DB->delete_records('task_scheduled', array('classname' => '\\' . trim(get_class($task), '\\')));
+        $this->assertFalse(\core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class));
 
         // Now call reset on all the tasks.
         \core\task\manager::reset_scheduled_tasks_for_component('moodle');
 
-        // Load the tasks again.
-        $defaulttasks = \core\task\manager::load_scheduled_tasks_for_component('moodle');
-        $finalcount = count($defaulttasks);
-        // Compare the first task.
-        $newfirsttask = reset($defaulttasks);
-        $newfirsttaskrecord = \core\task\manager::record_from_scheduled_task($newfirsttask);
-        // We reset this field, because we do not want to compare it.
-        $newfirsttaskrecord->nextruntime = '0';
+        // Assert that the second task was added back.
+        $taskafterreset = \core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class);
+        $this->assertNotFalse($taskafterreset);
 
-        // Assert a customised task was not altered by reset.
-        $this->assertEquals($firsttaskrecord, $newfirsttaskrecord);
+        $this->assertTaskEquals($task, $taskafterreset);
+        $this->assertCount(count($tasklist), \core\task\manager::load_scheduled_tasks_for_component('moodle'));
+    }
 
-        // Assert that the second task was added back.
-        $secondtaskafter = \core\task\manager::get_scheduled_task(get_class($secondtask));
-        $secondtaskafter->set_next_run_time(null);   // Do not compare the nextruntime.
-        $secondtask->set_next_run_time(null);
-        $this->assertEquals($secondtask, $secondtaskafter);
-
-        // Assert that the third task edits were overridden.
-        $thirdtaskafter = \core\task\manager::get_scheduled_task(get_class($thirdtask));
-        $thirdtaskafter->set_next_run_time(null);
-        $this->assertEquals($thirdtaskbefore, $thirdtaskafter);
-
-        // Assert we have the same number of tasks.
-        $this->assertEquals($initcount, $finalcount);
+    public function test_reset_scheduled_tasks_for_component_changed_in_source(): void {
+        $this->resetAfterTest(true);
+
+        // Delete a task to simulate the fact that its new.
+        // Note: This test must use a task which does not use any random values.
+        $task = \core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class);
+
+        // Get a copy of the task before maing changes for later comparison.
+        $taskbeforechange = \core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class);
+
+        // Edit a task to simulate a change in its definition (as if it was not customised).
+        $task->set_minute('1');
+        $task->set_hour('2');
+        $task->set_month('3');
+        $task->set_day_of_week('4');
+        $task->set_day('5');
+        \core\task\manager::configure_scheduled_task($task);
+
+        // Fetch the task out for comparison.
+        $taskafterchange = \core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class);
+
+        // The task should now be different to the original.
+        $this->assertTaskNotEquals($taskbeforechange, $taskafterchange);
+
+        // Now call reset.
+        \core\task\manager::reset_scheduled_tasks_for_component('moodle');
+
+        // Fetch the task again.
+        $taskafterreset = \core\task\manager::get_scheduled_task(core\task\session_cleanup_task::class);
+
+        // The task should now be the same as the original.
+        $this->assertTaskEquals($taskbeforechange, $taskafterreset);
     }
 
     /**
@@ -502,4 +516,56 @@ class core_scheduled_task_testcase extends advanced_testcase {
         $this->assertEquals(0, $task->get_fail_delay());
         $this->assertLessThan($before + 70, $task->get_next_run_time());
     }
+
+    /**
+     * Assert that the specified tasks are equal.
+     *
+     * @param   \core\task\task_base $task
+     * @param   \core\task\task_base $comparisontask
+     */
+    public function assertTaskEquals(\core\task\task_base $task, \core\task\task_base $comparisontask): void {
+        // Convert both to an object.
+        $task = \core\task\manager::record_from_scheduled_task($task);
+        $comparisontask = \core\task\manager::record_from_scheduled_task($comparisontask);
+
+        // Reset the nextruntime field as it is intentionally dynamic.
+        $task->nextruntime = null;
+        $comparisontask->nextruntime = null;
+
+        $args = array_merge(
+            [
+                $task,
+                $comparisontask,
+            ],
+            array_slice(func_get_args(), 2)
+        );
+
+        call_user_func_array([$this, 'assertEquals'], $args);
+    }
+
+    /**
+     * Assert that the specified tasks are not equal.
+     *
+     * @param   \core\task\task_base $task
+     * @param   \core\task\task_base $comparisontask
+     */
+    public function assertTaskNotEquals(\core\task\task_base $task, \core\task\task_base $comparisontask): void {
+        // Convert both to an object.
+        $task = \core\task\manager::record_from_scheduled_task($task);
+        $comparisontask = \core\task\manager::record_from_scheduled_task($comparisontask);
+
+        // Reset the nextruntime field as it is intentionally dynamic.
+        $task->nextruntime = null;
+        $comparisontask->nextruntime = null;
+
+        $args = array_merge(
+            [
+                $task,
+                $comparisontask,
+            ],
+            array_slice(func_get_args(), 2)
+        );
+
+        call_user_func_array([$this, 'assertNotEquals'], $args);
+    }
 }
index 997176c..36dd037 100644 (file)
@@ -399,7 +399,7 @@ $string['numberofpagesviewed'] = 'Number of questions answered: {$a}';
 $string['numberofpagesviewedheader'] = 'Number of questions answered';
 $string['numberofpagesviewednotice'] = 'Number of questions answered: {$a->nquestions} (You should answer at least {$a->minquestions})';
 $string['numerical'] = 'Numerical';
-$string['numericanswer_help'] = 'You can specify a number, or a range of numbers by using colon. For example 2:5 means any answer between 2 and 5 including them are correct.';
+$string['numericanswer_help'] = 'You can specify a single number, or a range of numbers by using colon. For example 2:5 means any answer between 2 and 5 and including 2 and 5 is correct.';
 $string['numericanswer'] = 'Numeric answer';
 $string['offlinedatamessage'] = 'You have worked on this attempt using a mobile device. Data was last saved to this site {$a} ago. Please check that you do not have any unsaved work.';
 $string['ongoing'] = 'Display ongoing score';
index 5bdceb5..5775363 100644 (file)
@@ -145,9 +145,35 @@ if (($launchcontainer == LTI_LAUNCH_CONTAINER_WINDOW) &&
         $content = lti_initiate_login($cm->course, $id, $lti, $config);
     }
 
+    // Build the allowed URL, since we know what it will be from $lti->toolurl,
+    // If the specified toolurl is invalid the iframe won't load, but we still want to avoid parse related errors here.
+    // So we set an empty default allowed url, and only build a real one if the parse is successful.
+    $ltiallow = '';
+    $urlparts = parse_url($lti->toolurl);
+    if ($urlparts && array_key_exists('scheme', $urlparts) && array_key_exists('host', $urlparts)) {
+        $ltiallow = $urlparts['scheme'] . '://' . $urlparts['host'];
+        // If a port has been specified we append that too.
+        if (array_key_exists('port', $urlparts)) {
+            $ltiallow .= ':' . $urlparts['port'];
+        }
+    }
+
     // Request the launch content with an iframe tag.
-    echo '<iframe id="contentframe" height="600px" width="100%" src="launch.php?id=' . $cm->id .
-         "&triggerview=0\" webkitallowfullscreen mozallowfullscreen allowfullscreen>{$content}</iframe>";
+    $attributes = [];
+    $attributes['id'] = "contentframe";
+    $attributes['height'] = '600px';
+    $attributes['width'] = '100%';
+    $attributes['src'] = 'launch.php?id=' . $cm->id . '&triggerview=0';
+    $attributes['allow'] = "microphone $ltiallow; " .
+        "camera $ltiallow; " .
+        "geolocation $ltiallow; " .
+        "midi $ltiallow; " .
+        "encrypted-media $ltiallow; " .
+        "autoplay $ltiallow";
+    $attributes['allowfullscreen'] = 1;
+    $iframehtml = html_writer::tag('iframe', $content, $attributes);
+    echo $iframehtml;
+
 
     // Output script to make the iframe tag be as large as possible.
     $resize = '
index 280f192..abcdb3c 100644 (file)
@@ -20,7 +20,7 @@ $orange:  #f0ad4e !default;
 $yellow:  #ff7518 !default;
 $green:   #398439 !default;
 $teal:    #20c997 !default;
-$cyan:    #5bc0de !default;
+$cyan:    #008196 !default;
 
 $primary:       $blue !default;
 $success:       $green !default;
@@ -37,7 +37,7 @@ $enable-rounded: false !default;
 $enable-responsive-font-sizes: true !default;
 
 // Body
-$body-color:    $gray-800 !default;
+$body-color:    $gray-900 !default;
 
 // Fonts
 $font-size-base: 0.9375rem !default;
index 64777c9..9a1735e 100644 (file)
   --yellow: #ff7518;
   --green: #398439;
   --teal: #20c997;
-  --cyan: #5bc0de;
+  --cyan: #008196;
   --white: #fff;
   --gray: #6c757d;
   --gray-dark: #343a40;
   --primary: #1177d1;
   --secondary: #ced4da;
   --success: #398439;
-  --info: #5bc0de;
+  --info: #008196;
   --warning: #f0ad4e;
   --danger: #d43f3a;
   --light: #f8f9fa;
@@ -2382,7 +2382,7 @@ body {
   font-size: 0.9375rem;
   font-weight: 400;
   line-height: 1.5;
-  color: #343a40;
+  color: #212529;
   text-align: left;
   background-color: #fff; }
   @media (max-width: 1200px) {
@@ -3513,7 +3513,7 @@ pre {
 .table {
   width: 100%;
   margin-bottom: 1rem;
-  color: #343a40; }
+  color: #212529; }
   .table th,
   .table td {
     padding: 0.75rem;
@@ -3548,7 +3548,7 @@ pre {
   background-color: rgba(0, 0, 0, 0.05); }
 
 .table-hover tbody tr:hover {
-  color: #343a40;
+  color: #212529;
   background-color: rgba(0, 0, 0, 0.075); }
 
 .table-primary,
@@ -3605,19 +3605,19 @@ pre {
 .table-info,
 .table-info > th,
 .table-info > td {
-  background-color: #d1edf6; }
+  background-color: #b8dce2; }
 
 .table-info th,
 .table-info td,
 .table-info thead th,
 .table-info tbody + tbody {
-  border-color: #aadeee; }
+  border-color: #7abdc8; }
 
 .table-hover .table-info:hover {
-  background-color: #bce5f2; }
+  background-color: #a6d3db; }
   .table-hover .table-info:hover > td,
   .table-hover .table-info:hover > th {
-    background-color: #bce5f2; }
+    background-color: #a6d3db; }
 
 .table-warning,
 .table-warning > th,
@@ -3850,7 +3850,7 @@ select.form-control:focus::-ms-value {
   margin-bottom: 0;
   font-size: 0.9375rem;
   line-height: 1.5;
-  color: #343a40;
+  color: #212529;
   background-color: transparent;
   border: solid transparent;
   border-width: 1px 0; }
@@ -4132,7 +4132,7 @@ textarea.form-control {
 .btn {
   display: inline-block;
   font-weight: 400;
-  color: #343a40;
+  color: #212529;
   text-align: center;
   vertical-align: middle;
   user-select: none;
@@ -4150,7 +4150,7 @@ textarea.form-control {
     .btn {
       transition: none; } }
   .btn:hover {
-    color: #343a40;
+    color: #212529;
     text-decoration: none; }
   .btn:focus, .btn.focus {
     outline: 0;
@@ -4243,30 +4243,30 @@ fieldset:disabled a.btn {
       box-shadow: 0 0 0 0.2rem rgba(87, 150, 87, 0.5); }
 
 .btn-info {
-  color: #212529;
-  background-color: #5bc0de;
-  border-color: #5bc0de; }
+  color: #fff;
+  background-color: #008196;
+  border-color: #008196; }
   .btn-info:hover {
     color: #fff;
-    background-color: #3bb4d8;
-    border-color: #31b0d5; }
+    background-color: #006070;
+    border-color: #005563; }
   .btn-info:focus, .btn-info.focus {
     color: #fff;
-    background-color: #3bb4d8;
-    border-color: #31b0d5;
-    box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+    background-color: #006070;
+    border-color: #005563;
+    box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
   .btn-info.disabled, .btn-info:disabled {
-    color: #212529;
-    background-color: #5bc0de;
-    border-color: #5bc0de; }
+    color: #fff;
+    background-color: #008196;
+    border-color: #008196; }
   .btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,
   .show > .btn-info.dropdown-toggle {
     color: #fff;
-    background-color: #31b0d5;
-    border-color: #2aaacf; }
+    background-color: #005563;
+    border-color: #004a56; }
     .btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,
     .show > .btn-info.dropdown-toggle:focus {
-      box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+      box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
 
 .btn-warning {
   color: #212529;
@@ -4436,25 +4436,25 @@ fieldset:disabled a.btn {
       box-shadow: 0 0 0 0.2rem rgba(57, 132, 57, 0.5); }
 
 .btn-outline-info {
-  color: #5bc0de;
-  border-color: #5bc0de; }
+  color: #008196;
+  border-color: #008196; }
   .btn-outline-info:hover {
-    color: #212529;
-    background-color: #5bc0de;
-    border-color: #5bc0de; }
+    color: #fff;
+    background-color: #008196;
+    border-color: #008196; }
   .btn-outline-info:focus, .btn-outline-info.focus {
-    box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+    box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
   .btn-outline-info.disabled, .btn-outline-info:disabled {
-    color: #5bc0de;
+    color: #008196;
     background-color: transparent; }
   .btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,
   .show > .btn-outline-info.dropdown-toggle {
-    color: #212529;
-    background-color: #5bc0de;
-    border-color: #5bc0de; }
+    color: #fff;
+    background-color: #008196;
+    border-color: #008196; }
     .btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,
     .show > .btn-outline-info.dropdown-toggle:focus {
-      box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+      box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
 
 .btn-outline-warning {
   color: #f0ad4e;
@@ -4630,7 +4630,7 @@ input[type="button"].btn-block {
   padding: 0.5rem 0;
   margin: 0.125rem 0 0;
   font-size: 0.9375rem;
-  color: #343a40;
+  color: #212529;
   text-align: left;
   list-style: none;
   background-color: #fff;
@@ -5897,14 +5897,14 @@ input[type="button"].btn-block {
     box-shadow: 0 0 0 0.2rem rgba(57, 132, 57, 0.5); }
 
 .badge-info {
-  color: #212529;
-  background-color: #5bc0de; }
+  color: #fff;
+  background-color: #008196; }
   a.badge-info:hover, a.badge-info:focus {
-    color: #212529;
-    background-color: #31b0d5; }
+    color: #fff;
+    background-color: #005563; }
   a.badge-info:focus, a.badge-info.focus {
     outline: 0;
-    box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+    box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
 
 .badge-warning {
   color: #212529;
@@ -6007,13 +6007,13 @@ input[type="button"].btn-block {
     color: #0f210f; }
 
 .alert-info {
-  color: #2f6473;
-  background-color: #def2f8;
-  border-color: #d1edf6; }
+  color: #00434e;
+  background-color: #cce6ea;
+  border-color: #b8dce2; }
   .alert-info hr {
-    border-top-color: #bce5f2; }
+    border-top-color: #a6d3db; }
   .alert-info .alert-link {
-    color: #20454f; }
+    color: #00171b; }
 
 .alert-warning {
   color: #7d5a29;
@@ -6112,7 +6112,7 @@ input[type="button"].btn-block {
     text-decoration: none;
     background-color: #f8f9fa; }
   .list-group-item-action:active {
-    color: #343a40;
+    color: #212529;
     background-color: #e9ecef; }
 
 .list-group-item {
@@ -6234,15 +6234,15 @@ input[type="button"].btn-block {
     border-color: #1e451e; }
 
 .list-group-item-info {
-  color: #2f6473;
-  background-color: #d1edf6; }
+  color: #00434e;
+  background-color: #b8dce2; }
   .list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
-    color: #2f6473;
-    background-color: #bce5f2; }
+    color: #00434e;
+    background-color: #a6d3db; }
   .list-group-item-info.list-group-item-action.active {
     color: #fff;
-    background-color: #2f6473;
-    border-color: #2f6473; }
+    background-color: #00434e;
+    border-color: #00434e; }
 
 .list-group-item-warning {
   color: #7d5a29;
@@ -6694,7 +6694,7 @@ a.close.disabled {
 
 .popover-body {
   padding: 0.5rem 0.75rem;
-  color: #343a40; }
+  color: #212529; }
 
 .carousel {
   position: relative; }
@@ -6929,12 +6929,12 @@ button.bg-success:focus {
   background-color: #2a602a !important; }
 
 .bg-info {
-  background-color: #5bc0de !important; }
+  background-color: #008196 !important; }
 
 a.bg-info:hover, a.bg-info:focus,
 button.bg-info:hover,
 button.bg-info:focus {
-  background-color: #31b0d5 !important; }
+  background-color: #005563 !important; }
 
 .bg-warning {
   background-color: #f0ad4e !important; }
@@ -7014,7 +7014,7 @@ button.bg-dark:focus {
   border-color: #398439 !important; }
 
 .border-info {
-  border-color: #5bc0de !important; }
+  border-color: #008196 !important; }
 
 .border-warning {
   border-color: #f0ad4e !important; }
@@ -9259,10 +9259,10 @@ a.text-success:hover, a.text-success:focus {
   color: #224f22 !important; }
 
 .text-info {
-  color: #5bc0de !important; }
+  color: #008196 !important; }
 
 a.text-info:hover, a.text-info:focus {
-  color: #28a1c5 !important; }
+  color: #003f4a !important; }
 
 .text-warning {
   color: #f0ad4e !important; }
@@ -9289,7 +9289,7 @@ a.text-dark:hover, a.text-dark:focus {
   color: #121416 !important; }
 
 .text-body {
-  color: #343a40 !important; }
+  color: #212529 !important; }
 
 .text-muted {
   color: #6c757d !important; }
@@ -9417,9 +9417,9 @@ a.text-dark:hover, a.text-dark:focus {
     background-color: #2a602a; }
 
 .tag-info {
-  background-color: #5bc0de; }
+  background-color: #008196; }
   .tag-info[href]:hover, .tag-info[href]:focus {
-    background-color: #31b0d5; }
+    background-color: #005563; }
 
 .tag-warning {
   background-color: #f0ad4e; }
@@ -9857,7 +9857,7 @@ div.dropdown-item:focus-within {
   color: #398439; }
 
 .highlight {
-  color: #5bc0de; }
+  color: #008196; }
 
 .fitem.advanced .text-info {
   font-weight: bold; }
@@ -11502,7 +11502,7 @@ ul {
   #page-footer a .icon {
     color: #fff; }
   #page-footer a:focus .icon {
-    color: #343a40; }
+    color: #212529; }
 
 .bg-inverse a {
   color: #fff;
@@ -11516,7 +11516,7 @@ ul {
 .dropdown-item a {
   display: block;
   width: 100%;
-  color: #343a40; }
+  color: #212529; }
 
 .dropdown-item:active a {
   color: #fff; }
@@ -11665,7 +11665,7 @@ body.h5p-embed .h5pmessages {
 
 .matchtext {
   background-color: #b5d9f9;
-  color: #343a40;
+  color: #212529;
   height: 1.5rem; }
 
 .emoji-picker {
@@ -11734,7 +11734,7 @@ body.h5p-embed .h5pmessages {
   color: #0f210f; }
 
 .alert-info a {
-  color: #20454f; }
+  color: #00171b; }
 
 .alert-warning a {
   color: #573e1c; }
@@ -12246,11 +12246,11 @@ body.h5p-embed .h5pmessages {
   width: 4em; }
 
 #adminthemeselector .selectedtheme td.c0 {
-  border: 1px solid #d1edf6;
+  border: 1px solid #b8dce2;
   border-right-width: 0; }
 
 #adminthemeselector .selectedtheme td.c1 {
-  border: 1px solid #d1edf6;
+  border: 1px solid #b8dce2;
   border-left-width: 0; }
 
 .admin_colourpicker,
@@ -12269,12 +12269,12 @@ body.h5p-embed .h5pmessages {
     box-sizing: content-box; }
   .admin_colourpicker .colourdialogue {
     float: left;
-    border: 1px solid #d1edf6; }
+    border: 1px solid #b8dce2; }
   .admin_colourpicker .previewcolour {
-    border: 1px solid #d1edf6;
+    border: 1px solid #b8dce2;
     margin-left: 301px; }
   .admin_colourpicker .currentcolour {
-    border: 1px solid #d1edf6;
+    border: 1px solid #b8dce2;
     margin-left: 301px;
     border-top-width: 0; } }
 
@@ -12347,7 +12347,7 @@ body.h5p-embed .h5pmessages {
 
 #plugins-check-page .pluginupdateinfo,
 #plugins-control-panel .pluginupdateinfo {
-  background-color: #def2f8;
+  background-color: #cce6ea;
   padding: 5px;
   margin: 10px 0; }
   #plugins-check-page .pluginupdateinfo.maturity50,
@@ -12464,7 +12464,7 @@ body.h5p-embed .h5pmessages {
 
 .block .block-controls .dropdown-toggle {
   /* So that the caret takes the colour of the icon. */
-  color: #343a40; }
+  color: #212529; }
 
 [data-region="blocks-column"] {
   width: 360px;
@@ -13490,11 +13490,11 @@ span.editinstructions {
   margin-left: 30px;
   font-size: 0.8203125rem;
   padding: .1em .4em;
-  background-color: #def2f8;
-  color: #5bc0de;
+  background-color: #cce6ea;
+  color: #008196;
   text-decoration: none;
   z-index: 9999;
-  border: 1px solid #d1edf6; }
+  border: 1px solid #b8dce2; }
 
 /* Course drag and drop upload styles */
 #dndupload-status {
@@ -13503,10 +13503,10 @@ span.editinstructions {
   width: 40%;
   margin: 0 30%;
   padding: 6px;
-  border: 1px solid #d1edf6;
+  border: 1px solid #b8dce2;
   text-align: center;
-  background: #def2f8;
-  color: #5bc0de;
+  background: #cce6ea;
+  color: #008196;
   z-index: 1; }
 
 .dndupload-preview {
@@ -13825,33 +13825,33 @@ span.editinstructions {
   #course-category-listings .listing-pagination {
     text-align: center; }
     #course-category-listings .listing-pagination .yui3-button {
-      color: #212529;
-      background-color: #5bc0de;
-      border-color: #5bc0de;
+      color: #fff;
+      background-color: #008196;
+      border-color: #008196;
       border: 0;
       margin: 0.4rem 0.2rem 0.45rem;
       font-size: 10.4px; }
       #course-category-listings .listing-pagination .yui3-button:hover {
         color: #fff;
-        background-color: #3bb4d8;
-        border-color: #31b0d5; }
+        background-color: #006070;
+        border-color: #005563; }
       #course-category-listings .listing-pagination .yui3-button:focus, #course-category-listings .listing-pagination .yui3-button.focus {
         color: #fff;
-        background-color: #3bb4d8;
-        border-color: #31b0d5;
-        box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+        background-color: #006070;
+        border-color: #005563;
+        box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
       #course-category-listings .listing-pagination .yui3-button.disabled, #course-category-listings .listing-pagination .yui3-button:disabled {
-        color: #212529;
-        background-color: #5bc0de;
-        border-color: #5bc0de; }
+        color: #fff;
+        background-color: #008196;
+        border-color: #008196; }
       #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled):active, #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled).active,
       .show > #course-category-listings .listing-pagination .yui3-button.dropdown-toggle {
         color: #fff;
-        background-color: #31b0d5;
-        border-color: #2aaacf; }
+        background-color: #005563;
+        border-color: #004a56; }
         #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled):active:focus, #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled).active:focus,
         .show > #course-category-listings .listing-pagination .yui3-button.dropdown-toggle:focus {
-          box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+          box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
       #course-category-listings .listing-pagination .yui3-button.active-page {
         color: #fff;
         background-color: #1177d1;
@@ -15603,14 +15603,14 @@ body.path-question-type {
     color: #573e1c; }
 
 .que .formulation {
-  color: #2f6473;
-  background-color: #def2f8;
-  border-color: #d1edf6;
+  color: #00434e;
+  background-color: #cce6ea;
+  border-color: #b8dce2;
   /* stylelint-disable-line max-line-length */ }
   .que .formulation hr {
-    border-top-color: #bce5f2; }
+    border-top-color: #a6d3db; }
   .que .formulation .alert-link {
-    color: #20454f; }
+    color: #00171b; }
 
 .que.multichoice .answer div.r0 .icon.fa-check,
 .que.multichoice .answer div.r1 .icon.fa-check,
@@ -15769,7 +15769,7 @@ body.jsenabled .questionflag input[type=checkbox] {
     margin: 0; }
 
 #page-mod-quiz-edit .questionbankwindow div.header .title {
-  color: #343a40; }
+  color: #212529; }
 
 #page-mod-quiz-edit div.container div.generalbox {
   background-color: transparent;
@@ -16433,7 +16433,7 @@ fieldset.coursesearchbox label {
   padding: 0.2em;
   margin: 0;
   cursor: pointer;
-  color: #343a40; }
+  color: #212529; }
 
 .form-autocomplete-suggestions li:hover {
   background-color: #3f9def;
@@ -16444,7 +16444,7 @@ fieldset.coursesearchbox label {
   color: #495057; }
 
 .form-autocomplete-downarrow {
-  color: #343a40;
+  color: #212529;
   top: 0.2rem;
   right: 0.5rem;
   cursor: pointer; }
@@ -16663,10 +16663,10 @@ select {
   font-weight: inherit; }
 
 .path-mod-forum .subscriptionmode {
-  color: #343a40; }
+  color: #212529; }
 
 .path-mod-forum .activesetting {
-  color: #343a40;
+  color: #212529;
   font-weight: bold; }
 
 .discussion-settings-container .custom-select {
@@ -17569,14 +17569,14 @@ div#dock {
   padding: 0.75rem 1.25rem;
   margin-bottom: 1rem;
   border: 0 solid transparent;
-  color: #2f6473;
-  background-color: #def2f8;
-  border-color: #d1edf6;
+  color: #00434e;
+  background-color: #cce6ea;
+  border-color: #b8dce2;
   /* stylelint-disable-line max-line-length */ }
   .assignfeedback_editpdf_widget .label hr {
-    border-top-color: #bce5f2; }
+    border-top-color: #a6d3db; }
   .assignfeedback_editpdf_widget .label .alert-link {
-    color: #20454f; }
+    color: #00171b; }
 
 .assignfeedback_editpdf_menu {
   padding: 0; }
@@ -17829,7 +17829,7 @@ div#dock {
 .generaltable {
   width: 100%;
   margin-bottom: 1rem;
-  color: #343a40; }
+  color: #212529; }
   .generaltable th,
   .generaltable td {
     padding: 0.75rem;
@@ -17846,7 +17846,7 @@ div#dock {
   .generaltable.table-sm td {
     padding: 0.3rem; }
   .generaltable tbody tr:hover {
-    color: #343a40;
+    color: #212529;
     background-color: rgba(0, 0, 0, 0.075); }
 
 table caption {
@@ -17988,7 +17988,7 @@ p.arrow_button {
   box-shadow: inset 0 0 0 2px #fff; }
 
 .btn-info:focus, .btn-info.focus {
-  outline: 0.2rem solid #124a5b;
+  outline: 0.2rem solid black;
   box-shadow: inset 0 0 0 2px #fff; }
 
 .btn-warning:focus, .btn-warning.focus {
@@ -18020,7 +18020,7 @@ p.arrow_button {
   box-shadow: inset 0 0 0 2px #343a40; }
 
 .btn-outline-info:focus, .btn-outline-info.focus {
-  outline: 0.2rem solid #124a5b;
+  outline: 0.2rem solid black;
   box-shadow: inset 0 0 0 2px #343a40; }
 
 .btn-outline-warning:focus, .btn-outline-warning.focus {
@@ -19092,14 +19092,14 @@ span[data-flexitour="container"][x-placement="right"], span[data-flexitour="cont
     box-shadow: 0 0 0 0.2rem rgba(57, 132, 57, 0.5); }
 
 .label-info {
-  color: #212529;
-  background-color: #5bc0de; }
+  color: #fff;
+  background-color: #008196; }
   a.label-info:hover, a.label-info:focus {
-    color: #212529;
-    background-color: #31b0d5; }
+    color: #fff;
+    background-color: #005563; }
   a.label-info:focus, a.label-info.focus {
     outline: 0;
-    box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+    box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
 
 .label-warning {
   color: #212529;
index c5f2517..9d20756 100644 (file)
@@ -20,7 +20,7 @@ $orange:  #f0ad4e !default;
 $yellow:  #ff7518 !default;
 $green:   #398439 !default;
 $teal:    #20c997 !default;
-$cyan:    #5bc0de !default;
+$cyan:    #008196 !default;
 
 $primary:       $blue !default;
 $success:       $green !default;
@@ -37,7 +37,7 @@ $enable-rounded: true !default;
 $enable-responsive-font-sizes: true !default;
 
 // Body
-$body-color:    $gray-800 !default;
+$body-color:    $gray-900 !default;
 
 // Fonts
 $font-size-base: 0.9375rem !default;
index c346fb7..de04da2 100644 (file)
   --yellow: #ff7518;
   --green: #398439;
   --teal: #20c997;
-  --cyan: #5bc0de;
+  --cyan: #008196;
   --white: #fff;
   --gray: #6c757d;
   --gray-dark: #343a40;
   --primary: #1177d1;
   --secondary: #ced4da;
   --success: #398439;
-  --info: #5bc0de;
+  --info: #008196;
   --warning: #f0ad4e;
   --danger: #d43f3a;
   --light: #f8f9fa;
@@ -2382,7 +2382,7 @@ body {
   font-size: 0.9375rem;
   font-weight: 400;
   line-height: 1.5;
-  color: #343a40;
+  color: #212529;
   text-align: left;
   background-color: #fff; }
   @media (max-width: 1200px) {
@@ -3515,7 +3515,7 @@ pre {
 .table {
   width: 100%;
   margin-bottom: 1rem;
-  color: #343a40; }
+  color: #212529; }
   .table th,
   .table td {
     padding: 0.75rem;
@@ -3550,7 +3550,7 @@ pre {
   background-color: rgba(0, 0, 0, 0.05); }
 
 .table-hover tbody tr:hover {
-  color: #343a40;
+  color: #212529;
   background-color: rgba(0, 0, 0, 0.075); }
 
 .table-primary,
@@ -3607,19 +3607,19 @@ pre {
 .table-info,
 .table-info > th,
 .table-info > td {
-  background-color: #d1edf6; }
+  background-color: #b8dce2; }
 
 .table-info th,
 .table-info td,
 .table-info thead th,
 .table-info tbody + tbody {
-  border-color: #aadeee; }
+  border-color: #7abdc8; }
 
 .table-hover .table-info:hover {
-  background-color: #bce5f2; }
+  background-color: #a6d3db; }
   .table-hover .table-info:hover > td,
   .table-hover .table-info:hover > th {
-    background-color: #bce5f2; }
+    background-color: #a6d3db; }
 
 .table-warning,
 .table-warning > th,
@@ -3852,7 +3852,7 @@ select.form-control:focus::-ms-value {
   margin-bottom: 0;
   font-size: 0.9375rem;
   line-height: 1.5;
-  color: #343a40;
+  color: #212529;
   background-color: transparent;
   border: solid transparent;
   border-width: 1px 0; }
@@ -4138,7 +4138,7 @@ textarea.form-control {
 .btn {
   display: inline-block;
   font-weight: 400;
-  color: #343a40;
+  color: #212529;
   text-align: center;
   vertical-align: middle;
   user-select: none;
@@ -4156,7 +4156,7 @@ textarea.form-control {
     .btn {
       transition: none; } }
   .btn:hover {
-    color: #343a40;
+    color: #212529;
     text-decoration: none; }
   .btn:focus, .btn.focus {
     outline: 0;
@@ -4249,30 +4249,30 @@ fieldset:disabled a.btn {
       box-shadow: 0 0 0 0.2rem rgba(87, 150, 87, 0.5); }
 
 .btn-info {
-  color: #212529;
-  background-color: #5bc0de;
-  border-color: #5bc0de; }
+  color: #fff;
+  background-color: #008196;
+  border-color: #008196; }
   .btn-info:hover {
     color: #fff;
-    background-color: #3bb4d8;
-    border-color: #31b0d5; }
+    background-color: #006070;
+    border-color: #005563; }
   .btn-info:focus, .btn-info.focus {
     color: #fff;
-    background-color: #3bb4d8;
-    border-color: #31b0d5;
-    box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+    background-color: #006070;
+    border-color: #005563;
+    box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
   .btn-info.disabled, .btn-info:disabled {
-    color: #212529;
-    background-color: #5bc0de;
-    border-color: #5bc0de; }
+    color: #fff;
+    background-color: #008196;
+    border-color: #008196; }
   .btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,
   .show > .btn-info.dropdown-toggle {
     color: #fff;
-    background-color: #31b0d5;
-    border-color: #2aaacf; }
+    background-color: #005563;
+    border-color: #004a56; }
     .btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,
     .show > .btn-info.dropdown-toggle:focus {
-      box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+      box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
 
 .btn-warning {
   color: #212529;
@@ -4442,25 +4442,25 @@ fieldset:disabled a.btn {
       box-shadow: 0 0 0 0.2rem rgba(57, 132, 57, 0.5); }
 
 .btn-outline-info {
-  color: #5bc0de;
-  border-color: #5bc0de; }
+  color: #008196;
+  border-color: #008196; }
   .btn-outline-info:hover {
-    color: #212529;
-    background-color: #5bc0de;
-    border-color: #5bc0de; }
+    color: #fff;
+    background-color: #008196;
+    border-color: #008196; }
   .btn-outline-info:focus, .btn-outline-info.focus {
-    box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+    box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
   .btn-outline-info.disabled, .btn-outline-info:disabled {
-    color: #5bc0de;
+    color: #008196;
     background-color: transparent; }
   .btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,
   .show > .btn-outline-info.dropdown-toggle {
-    color: #212529;
-    background-color: #5bc0de;
-    border-color: #5bc0de; }
+    color: #fff;
+    background-color: #008196;
+    border-color: #008196; }
     .btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,
     .show > .btn-outline-info.dropdown-toggle:focus {
-      box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+      box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
 
 .btn-outline-warning {
   color: #f0ad4e;
@@ -4636,7 +4636,7 @@ input[type="button"].btn-block {
   padding: 0.5rem 0;
   margin: 0.125rem 0 0;
   font-size: 0.9375rem;
-  color: #343a40;
+  color: #212529;
   text-align: left;
   list-style: none;
   background-color: #fff;
@@ -6047,14 +6047,14 @@ input[type="button"].btn-block {
     box-shadow: 0 0 0 0.2rem rgba(57, 132, 57, 0.5); }
 
 .badge-info {
-  color: #212529;
-  background-color: #5bc0de; }
+  color: #fff;
+  background-color: #008196; }
   a.badge-info:hover, a.badge-info:focus {
-    color: #212529;
-    background-color: #31b0d5; }
+    color: #fff;
+    background-color: #005563; }
   a.badge-info:focus, a.badge-info.focus {
     outline: 0;
-    box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+    box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
 
 .badge-warning {
   color: #212529;
@@ -6160,13 +6160,13 @@ input[type="button"].btn-block {
     color: #0f210f; }
 
 .alert-info {
-  color: #2f6473;
-  background-color: #def2f8;
-  border-color: #d1edf6; }
+  color: #00434e;
+  background-color: #cce6ea;
+  border-color: #b8dce2; }
   .alert-info hr {
-    border-top-color: #bce5f2; }
+    border-top-color: #a6d3db; }
   .alert-info .alert-link {
-    color: #20454f; }
+    color: #00171b; }
 
 .alert-warning {
   color: #7d5a29;
@@ -6267,7 +6267,7 @@ input[type="button"].btn-block {
     text-decoration: none;
     background-color: #f8f9fa; }
   .list-group-item-action:active {
-    color: #343a40;
+    color: #212529;
     background-color: #e9ecef; }
 
 .list-group-item {
@@ -6427,15 +6427,15 @@ input[type="button"].btn-block {
     border-color: #1e451e; }
 
 .list-group-item-info {
-  color: #2f6473;
-  background-color: #d1edf6; }
+  color: #00434e;
+  background-color: #b8dce2; }
   .list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
-    color: #2f6473;
-    background-color: #bce5f2; }
+    color: #00434e;
+    background-color: #a6d3db; }
   .list-group-item-info.list-group-item-action.active {
     color: #fff;
-    background-color: #2f6473;
-    border-color: #2f6473; }
+    background-color: #00434e;
+    border-color: #00434e; }
 
 .list-group-item-warning {
   color: #7d5a29;
@@ -6897,7 +6897,7 @@ a.close.disabled {
 
 .popover-body {
   padding: 0.5rem 0.75rem;
-  color: #343a40; }
+  color: #212529; }
 
 .carousel {
   position: relative; }
@@ -7132,12 +7132,12 @@ button.bg-success:focus {
   background-color: #2a602a !important; }
 
 .bg-info {
-  background-color: #5bc0de !important; }
+  background-color: #008196 !important; }
 
 a.bg-info:hover, a.bg-info:focus,
 button.bg-info:hover,
 button.bg-info:focus {
-  background-color: #31b0d5 !important; }
+  background-color: #005563 !important; }
 
 .bg-warning {
   background-color: #f0ad4e !important; }
@@ -7217,7 +7217,7 @@ button.bg-dark:focus {
   border-color: #398439 !important; }
 
 .border-info {
-  border-color: #5bc0de !important; }
+  border-color: #008196 !important; }
 
 .border-warning {
   border-color: #f0ad4e !important; }
@@ -9462,10 +9462,10 @@ a.text-success:hover, a.text-success:focus {
   color: #224f22 !important; }
 
 .text-info {
-  color: #5bc0de !important; }
+  color: #008196 !important; }
 
 a.text-info:hover, a.text-info:focus {
-  color: #28a1c5 !important; }
+  color: #003f4a !important; }
 
 .text-warning {
   color: #f0ad4e !important; }
@@ -9492,7 +9492,7 @@ a.text-dark:hover, a.text-dark:focus {
   color: #121416 !important; }
 
 .text-body {
-  color: #343a40 !important; }
+  color: #212529 !important; }
 
 .text-muted {
   color: #6c757d !important; }
@@ -9621,9 +9621,9 @@ a.text-dark:hover, a.text-dark:focus {
     background-color: #2a602a; }
 
 .tag-info {
-  background-color: #5bc0de; }
+  background-color: #008196; }
   .tag-info[href]:hover, .tag-info[href]:focus {
-    background-color: #31b0d5; }
+    background-color: #005563; }
 
 .tag-warning {
   background-color: #f0ad4e; }
@@ -10062,7 +10062,7 @@ div.dropdown-item:focus-within {
   color: #398439; }
 
 .highlight {
-  color: #5bc0de; }
+  color: #008196; }
 
 .fitem.advanced .text-info {
   font-weight: bold; }
@@ -11713,7 +11713,7 @@ ul {
   #page-footer a .icon {
     color: #fff; }
   #page-footer a:focus .icon {
-    color: #343a40; }
+    color: #212529; }
 
 .bg-inverse a {
   color: #fff;
@@ -11727,7 +11727,7 @@ ul {
 .dropdown-item a {
   display: block;
   width: 100%;
-  color: #343a40; }
+  color: #212529; }
 
 .dropdown-item:active a {
   color: #fff; }
@@ -11876,7 +11876,7 @@ body.h5p-embed .h5pmessages {
 
 .matchtext {
   background-color: #b5d9f9;
-  color: #343a40;
+  color: #212529;
   height: 1.5rem; }
 
 .border-radius {
@@ -11948,7 +11948,7 @@ body.h5p-embed .h5pmessages {
   color: #0f210f; }
 
 .alert-info a {
-  color: #20454f; }
+  color: #00171b; }
 
 .alert-warning a {
   color: #573e1c; }
@@ -12460,11 +12460,11 @@ body.h5p-embed .h5pmessages {
   width: 4em; }
 
 #adminthemeselector .selectedtheme td.c0 {
-  border: 1px solid #d1edf6;
+  border: 1px solid #b8dce2;
   border-right-width: 0; }
 
 #adminthemeselector .selectedtheme td.c1 {
-  border: 1px solid #d1edf6;
+  border: 1px solid #b8dce2;
   border-left-width: 0; }
 
 .admin_colourpicker,
@@ -12483,12 +12483,12 @@ body.h5p-embed .h5pmessages {
     box-sizing: content-box; }
   .admin_colourpicker .colourdialogue {
     float: left;
-    border: 1px solid #d1edf6; }
+    border: 1px solid #b8dce2; }
   .admin_colourpicker .previewcolour {
-    border: 1px solid #d1edf6;
+    border: 1px solid #b8dce2;
     margin-left: 301px; }
   .admin_colourpicker .currentcolour {
-    border: 1px solid #d1edf6;
+    border: 1px solid #b8dce2;
     margin-left: 301px;
     border-top-width: 0; } }
 
@@ -12561,7 +12561,7 @@ body.h5p-embed .h5pmessages {
 
 #plugins-check-page .pluginupdateinfo,
 #plugins-control-panel .pluginupdateinfo {
-  background-color: #def2f8;
+  background-color: #cce6ea;
   padding: 5px;
   margin: 10px 0;
   border-radius: 5px; }
@@ -12679,7 +12679,7 @@ body.h5p-embed .h5pmessages {
 
 .block .block-controls .dropdown-toggle {
   /* So that the caret takes the colour of the icon. */
-  color: #343a40; }
+  color: #212529; }
 
 [data-region="blocks-column"] {
   width: 360px;
@@ -13705,11 +13705,11 @@ span.editinstructions {
   margin-left: 30px;
   font-size: 0.8203125rem;
   padding: .1em .4em;
-  background-color: #def2f8;
-  color: #5bc0de;
+  background-color: #cce6ea;
+  color: #008196;
   text-decoration: none;
   z-index: 9999;
-  border: 1px solid #d1edf6; }
+  border: 1px solid #b8dce2; }
 
 /* Course drag and drop upload styles */
 #dndupload-status {
@@ -13718,10 +13718,10 @@ span.editinstructions {
   width: 40%;
   margin: 0 30%;
   padding: 6px;
-  border: 1px solid #d1edf6;
+  border: 1px solid #b8dce2;
   text-align: center;
-  background: #def2f8;
-  color: #5bc0de;
+  background: #cce6ea;
+  color: #008196;
   z-index: 1;
   border-radius: 8px; }
 
@@ -14042,33 +14042,33 @@ span.editinstructions {
   #course-category-listings .listing-pagination {
     text-align: center; }
     #course-category-listings .listing-pagination .yui3-button {
-      color: #212529;
-      background-color: #5bc0de;
-      border-color: #5bc0de;
+      color: #fff;
+      background-color: #008196;
+      border-color: #008196;
       border: 0;
       margin: 0.4rem 0.2rem 0.45rem;
       font-size: 10.4px; }
       #course-category-listings .listing-pagination .yui3-button:hover {
         color: #fff;
-        background-color: #3bb4d8;
-        border-color: #31b0d5; }
+        background-color: #006070;
+        border-color: #005563; }
       #course-category-listings .listing-pagination .yui3-button:focus, #course-category-listings .listing-pagination .yui3-button.focus {
         color: #fff;
-        background-color: #3bb4d8;
-        border-color: #31b0d5;
-        box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+        background-color: #006070;
+        border-color: #005563;
+        box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
       #course-category-listings .listing-pagination .yui3-button.disabled, #course-category-listings .listing-pagination .yui3-button:disabled {
-        color: #212529;
-        background-color: #5bc0de;
-        border-color: #5bc0de; }
+        color: #fff;
+        background-color: #008196;
+        border-color: #008196; }
       #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled):active, #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled).active,
       .show > #course-category-listings .listing-pagination .yui3-button.dropdown-toggle {
         color: #fff;
-        background-color: #31b0d5;
-        border-color: #2aaacf; }
+        background-color: #005563;
+        border-color: #004a56; }
         #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled):active:focus, #course-category-listings .listing-pagination .yui3-button:not(:disabled):not(.disabled).active:focus,
         .show > #course-category-listings .listing-pagination .yui3-button.dropdown-toggle:focus {
-          box-shadow: 0 0 0 0.2rem rgba(82, 169, 195, 0.5); }
+          box-shadow: 0 0 0 0.2rem rgba(38, 148, 166, 0.5); }
       #course-category-listings .listing-pagination .yui3-button.active-page {
         color: #fff;
         background-color: #1177d1;
@@ -15826,14 +15826,14 @@ body.path-question-type {
     color: #573e1c; }
 
 .que .formulation {
-  color: #2f6473;
-  background-color: #def2f8;
-  border-color: #d1edf6;
+  color: #00434e;
+  background-color: #cce6ea;
+  border-color: #b8dce2;
   /* stylelint-disable-line max-line-length */ }
   .que .formulation hr {
-    border-top-color: #bce5f2; }
+    border-top-color: #a6d3db; }
   .que .formulation .alert-link {
-    color: #20454f; }
+    color: #00171b; }
 
 .que.multichoice .answer div.r0 .icon.fa-check,
 .que.multichoice .answer div.r1 .icon.fa-check,
@@ -15994,7 +15994,7 @@ body.jsenabled .questionflag input[type=checkbox] {
     margin: 0; }
 
 #page-mod-quiz-edit .questionbankwindow div.header .title {
-  color: #343a40; }
+  color: #212529; }
 
 #page-mod-quiz-edit div.container div.generalbox {
   background-color: transparent;
@@ -16661,7 +16661,7 @@ fieldset.coursesearchbox label {
   padding: 0.2em;
   margin: 0;
   cursor: pointer;
-  color: #343a40; }
+  color: #212529; }
 
 .form-autocomplete-suggestions li:hover {
   background-color: #3f9def;
@@ -16672,7 +16672,7 @@ fieldset.coursesearchbox label {
   color: #495057; }
 
 .form-autocomplete-downarrow {
-  color: #343a40;
+  color: #212529;
   top: 0.2rem;
   right: 0.5rem;
   cursor: pointer; }
@@ -16892,10 +16892,10 @@ select {
   font-weight: inherit; }
 
 .path-mod-forum .subscriptionmode {
-  color: #343a40; }
+  color: #212529; }
 
 .path-mod-forum .activesetting {
-  color: #343a40;
+  color: #212529;
   font-weight: bold; }
 
 .discussion-settings-container .custom-select {
@@ -17800,14 +17800,14 @@ div#dock {
   margin-bottom: 1rem;
   border: 0 solid transparent;
   border-radius: 0.25rem;
-  color: #2f6473;
-  background-color: #def2f8;
-  border-color: #d1edf6;
+  color: #00434e;
+  background-color: #cce6ea;
+  border-color: #b8dce2;
   /* stylelint-disable-line max-line-length */ }
   .assignfeedback_editpdf_widget .label hr {
-    border-top-color: #bce5f2; }
+    border-top-color: #a6d3db; }
   .assignfeedback_editpdf_widget .label .alert-link {
-    color: #20454f; }
+    color: #00171b; }
 
 .assignfeedback_editpdf_menu {
   padding: 0; }
@@ -18063,7 +18063,7 @@ div#dock {
 .generaltable {
   width: 100%;
   margin-bottom: 1rem;
-  color: #343a40; }
+  color: #212529; }
   .generaltable th,
   .generaltable td {
     padding: 0.75rem;
@@ -18080,7 +18080,7 @@ div#dock {
   .generaltable.table-sm td {
     padding: 0.3rem; }
   .generaltable tbody tr:hover {
-    color: #343a40;
+    color: #212529;
     background-color: rgba(0, 0, 0, 0.075); }
 
 table caption {
@@ -18222,7 +18222,7 @@ p.arrow_button {
   box-shadow: inset 0 0 0 2px #fff; }
 
 .btn-info:focus, .btn-info.focus {
-  outline: 0.2rem solid #124a5b;
+  outline: 0.2rem solid black;
   box-shadow: inset 0 0 0 2px #fff; }
 
 .btn-warning:focus, .btn-warning.focus {
@@ -18254,7 +18254,7 @@ p.arrow_button {
   box-shadow: inset 0 0 0 2px #343a40; }
 
 .btn-outline-info:focus, .btn-outline-info.focus {
-  outline: 0.2rem solid #124a5b;
+  outline: 0.2rem solid black;
   box-shadow: inset 0 0 0 2px #343a40; }
 
 .btn-outline-warning:focus, .btn-outline-warning.focus {
@@ -19277,14 +19277,14 @@ span[data-flexitour="container"][x-placement="right"], span[data-flexitour="cont
     box-shadow: 0 0 0 0.2rem rgba(57, 132, 57, 0.5); }
 
 .label-info {
-  color: #212529;
-  background-color: #5bc0de; }
+  color: #fff;
+  background-color: #008196; }
   a.label-info:hover, a.label-info:focus {
-    color: #212529;
-    background-color: #31b0d5; }
+    color: #fff;
+    background-color: #005563; }
   a.label-info:focus, a.label-info.focus {
     outline: 0;
-    box-shadow: 0 0 0 0.2rem rgba(91, 192, 222, 0.5); }
+    box-shadow: 0 0 0 0.2rem rgba(0, 129, 150, 0.5); }
 
 .label-warning {
   color: #212529;
index 282aac5..01bbad5 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2020061501.10;              // 20200615      = branching date YYYYMMDD - do not modify!
+$version  = 2020061501.11;              // 20200615      = branching date YYYYMMDD - do not modify!
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.
 $release  = '3.9.1+ (Build: 20200822)'; // Human-friendly version name