Merge branch 'MDL-69526-master' of git://github.com/lucaboesch/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Tue, 17 Nov 2020 06:52:58 +0000 (14:52 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Tue, 17 Nov 2020 06:52:58 +0000 (14:52 +0800)
15 files changed:
lib/amd/build/fullscreen.min.js [new file with mode: 0644]
lib/amd/build/fullscreen.min.js.map [new file with mode: 0644]
lib/amd/build/modal.min.js
lib/amd/build/modal.min.js.map
lib/amd/build/modal_backdrop.min.js
lib/amd/build/modal_backdrop.min.js.map
lib/amd/src/fullscreen.js [new file with mode: 0644]
lib/amd/src/modal.js
lib/amd/src/modal_backdrop.js
lib/db/upgrade.php
mod/forum/tests/behat/grade_view_discussion.feature [new file with mode: 0644]
user/amd/build/participants.min.js
user/amd/build/participants.min.js.map
user/amd/src/participants.js
user/tests/behat/view_participants.feature

diff --git a/lib/amd/build/fullscreen.min.js b/lib/amd/build/fullscreen.min.js
new file mode 100644 (file)
index 0000000..b227c0a
Binary files /dev/null and b/lib/amd/build/fullscreen.min.js differ
diff --git a/lib/amd/build/fullscreen.min.js.map b/lib/amd/build/fullscreen.min.js.map
new file mode 100644 (file)
index 0000000..82ff7a4
Binary files /dev/null and b/lib/amd/build/fullscreen.min.js.map differ
index 1374a94..91677e8 100644 (file)
Binary files a/lib/amd/build/modal.min.js and b/lib/amd/build/modal.min.js differ
index 3b050c2..e330a08 100644 (file)
Binary files a/lib/amd/build/modal.min.js.map and b/lib/amd/build/modal.min.js.map differ
index dfedcae..1778e05 100644 (file)
Binary files a/lib/amd/build/modal_backdrop.min.js and b/lib/amd/build/modal_backdrop.min.js differ
index 9b2bf43..df2f559 100644 (file)
Binary files a/lib/amd/build/modal_backdrop.min.js.map and b/lib/amd/build/modal_backdrop.min.js.map differ
diff --git a/lib/amd/src/fullscreen.js b/lib/amd/src/fullscreen.js
new file mode 100644 (file)
index 0000000..4ac2acc
--- /dev/null
@@ -0,0 +1,48 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Detects if an element is fullscreen.
+ *
+ * @module     core/fullscreen
+ * @class      fullscreen
+ * @package    core
+ * @copyright  2020 University of Nottingham
+ * @author     Neill Magill <neill.magill@nottingham.ac.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Gets the element that is fullscreen or null if no element is fullscreen.
+ *
+ * @returns {HTMLElement}
+ */
+export const getElement = () => {
+    let element = null;
+    if (document.fullscreenElement) {
+        element = document.fullscreenElement;
+    } else if (document.mozFullscreenElement) {
+        // Fallback for older Firefox.
+        element = document.mozFullscreenElement;
+    } else if (document.msFullscreenElement) {
+        // Fallback for Edge and IE.
+        element = document.msFullscreenElement;
+    } else if (document.webkitFullscreenElement) {
+        // Fallback for Chrome, Edge and Safari.
+        element = document.webkitFullscreenElement;
+    }
+
+    return element;
+};
index 37ce574..118d679 100644 (file)
@@ -34,7 +34,21 @@ define([
     'core/local/aria/focuslock',
     'core/pending',
     'core/aria',
-], function($, Templates, Notification, KeyCodes, CustomEvents, ModalBackdrop, Event, ModalEvents, FocusLock, Pending, Aria) {
+    'core/fullscreen'
+], function(
+    $,
+    Templates,
+    Notification,
+    KeyCodes,
+    CustomEvents,
+    ModalBackdrop,
+    Event,
+    ModalEvents,
+    FocusLock,
+    Pending,
+    Aria,
+    Fullscreen
+) {
 
     var SELECTORS = {
         CONTAINER: '[data-region="modal-container"]',
@@ -117,17 +131,20 @@ define([
     };
 
     /**
-     * Add the modal to the page, if it hasn't already been added. This includes running any
+     * Attach the modal to the correct part of the page.
+     *
+     * If it hasn't already been added it runs any
      * javascript that has been cached until now.
      *
      * @method attachToDOM
      */
     Modal.prototype.attachToDOM = function() {
+        this.getAttachmentPoint().append(this.root);
+
         if (this.isAttached) {
             return;
         }
 
-        $('body').append(this.root);
         FocusLock.trapFocus(this.root[0]);
 
         // If we'd cached any JS then we can run it how that the modal is
@@ -625,6 +642,15 @@ define([
         return this.getRoot().hasClass('fade');
     };
 
+    /**
+     * Gets the jQuery wrapped node that the Modal should be attached to.
+     *
+     * @returns {jQuery}
+     */
+    Modal.prototype.getAttachmentPoint = function() {
+        return $(Fullscreen.getElement() || document.body);
+    };
+
     /**
      * Display this modal. The modal will be attached to the DOM if it hasn't
      * already been.
@@ -645,9 +671,7 @@ define([
             this.hideFooter();
         }
 
-        if (!this.isAttached) {
-            this.attachToDOM();
-        }
+        this.attachToDOM();
 
         return this.getBackdrop()
         .then(function(backdrop) {
@@ -689,6 +713,7 @@ define([
     Modal.prototype.hide = function() {
         this.getBackdrop().done(function(backdrop) {
             FocusLock.untrapFocus();
+
             if (!this.countOtherVisibleModals()) {
                 // Hide the backdrop if we're the last open modal.
                 backdrop.hide();
@@ -710,6 +735,11 @@ define([
                 this.getRoot().removeClass('show').addClass('hide');
             }
 
+            // Ensure the modal is moved onto the body node if it is still attached to the DOM.
+            if ($(document.body).find(this.getRoot()).length) {
+                $(document.body).append(this.getRoot());
+            }
+
             this.root.trigger(ModalEvents.hidden, this);
         }.bind(this));
     };
index 75a7b26..1cbc1fd 100644 (file)
@@ -22,8 +22,8 @@
  * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-define(['jquery', 'core/templates', 'core/notification'],
-     function($, Templates, Notification) {
+define(['jquery', 'core/templates', 'core/notification', 'core/fullscreen'],
+     function($, Templates, Notification, Fullscreen) {
 
     var SELECTORS = {
         ROOT: '[data-region="modal-backdrop"]',
@@ -53,17 +53,27 @@ define(['jquery', 'core/templates', 'core/notification'],
         return this.root;
     };
 
+     /**
+      * Gets the jQuery wrapped node that the Modal should be attached to.
+      *
+      * @returns {jQuery}
+      */
+     ModalBackdrop.prototype.getAttachmentPoint = function() {
+         return $(Fullscreen.getElement() || document.body);
+     };
+
     /**
      * Add the modal backdrop to the page, if it hasn't already been added.
      *
      * @method attachToDOM
      */
     ModalBackdrop.prototype.attachToDOM = function() {
+        this.getAttachmentPoint().append(this.root);
+
         if (this.isAttached) {
             return;
         }
 
-        $('body').append(this.root);
         this.isAttached = true;
     };
 
@@ -108,9 +118,7 @@ define(['jquery', 'core/templates', 'core/notification'],
             return;
         }
 
-        if (!this.isAttached) {
-            this.attachToDOM();
-        }
+        this.attachToDOM();
 
         this.root.removeClass('hide').addClass('show');
     };
@@ -133,6 +141,11 @@ define(['jquery', 'core/templates', 'core/notification'],
         } else {
             this.getRoot().removeClass('show').addClass('hide');
         }
+
+        // Ensure the modal is moved onto the body node if it is still attached to the DOM.
+        if ($(document.body).find(this.getRoot()).length) {
+            $(document.body).append(this.getRoot());
+        }
     };
 
     /**
index e3e2548..d24a5c2 100644 (file)
@@ -2994,5 +2994,23 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2021052500.36);
     }
 
+    if ($oldversion < 2021052500.42) {
+        // Get all lessons that are set with a completion criteria of 'requires grade' but with no grade type set.
+        $sql = "SELECT cm.id
+                  FROM {course_modules} cm
+                  JOIN {lesson} l ON l.id = cm.instance
+                  JOIN {modules} m ON m.id = cm.module
+                 WHERE m.name = :name AND cm.completiongradeitemnumber IS NOT NULL AND l.grade = :grade";
+
+        do {
+            if ($invalidconfigrations = $DB->get_records_sql($sql, ['name' => 'lesson', 'grade' => 0], 0, 1000)) {
+                list($insql, $inparams) = $DB->get_in_or_equal(array_keys($invalidconfigrations), SQL_PARAMS_NAMED);
+                $DB->set_field_select('course_modules', 'completiongradeitemnumber', null, "id $insql", $inparams);
+            }
+        } while ($invalidconfigrations);
+
+        upgrade_main_savepoint(true, 2021052500.42);
+    }
+
     return true;
 }
diff --git a/mod/forum/tests/behat/grade_view_discussion.feature b/mod/forum/tests/behat/grade_view_discussion.feature
new file mode 100644 (file)
index 0000000..4cafd08
--- /dev/null
@@ -0,0 +1,60 @@
+@mod @mod_forum @javascript
+Feature: View discussion while grading in a forum
+  In order to grade efficiently
+  As a teacher
+  I want to be able to see the full discussion the student was taking part in.
+
+  Background:
+    # Student 1 needs to be created first or they will not be the first user on the grading screen.
+    Given the following "users" exist:
+      | username | firstname | lastname | email                 |
+      | student1 | Student   | 1        | student.1@example.com |
+      | student2 | Student   | 2        | student.2@example.com |
+      | teacher  | Teacher   | Tom      | teacher@example.com   |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | student1 | C1     | student        |
+      | student2 | C1     | student        |
+      | teacher  | C1     | editingteacher |
+    And the following "activity" exists:
+      | activity    | forum                      |
+      | name        | Gradable forum             |
+      | intro       | Standard forum description |
+      | course      | C1                         |
+      | idnumber    | forum1                     |
+      | grade_forum | 100                        |
+      | scale       | 100                        |
+    # If there is more than one pots for Student 1 the test will not be able to select the
+    # correct View discussion link, as there is no selector for thier container.
+    And the following forum discussions exist in course "Course 1":
+      | forum          | user     | name     | message                          |
+      | Gradable forum | student1 | My topic | This is the thing I posted about |
+    And the following forum replies exist in course "Course 1":
+      | forum          | user     | discussion | message    |
+      | Gradable forum | student2 | My topic   | I disagree |
+
+  Scenario: Viewing a discussion
+    Given I log in as "teacher"
+    And I am on "Course 1" course homepage
+    And I follow "Gradable forum"
+    And I press "Grade users"
+    When I press "View discussion"
+    Then I should see "I disagree" in the "My topic" "dialogue"
+    And I click on "Cancel" "button" in the "My topic" "dialogue"
+    And I should not see "I disagree"
+
+  Scenario: Viewing a discussion while grading is fullscreen
+    Given I log in as "teacher"
+    And I am on "Course 1" course homepage
+    And I follow "Gradable forum"
+    And I press "Grade users"
+    # Uses the aria-label for the menu in in the grading interface.
+    And I press "Actions for the grader interface"
+    And I press "Toggle full screen"
+    When I press "View discussion"
+    Then I should see "I disagree" in the "My topic" "dialogue"
+    And I click on "Cancel" "button" in the "My topic" "dialogue"
+    And I should not see "I disagree"
index 4e49ea2..071682e 100644 (file)
Binary files a/user/amd/build/participants.min.js and b/user/amd/build/participants.min.js differ
index 5938593..aeaff37 100644 (file)
Binary files a/user/amd/build/participants.min.js.map and b/user/amd/build/participants.min.js.map differ
index ebe72f6..63c8e0a 100644 (file)
@@ -125,7 +125,7 @@ export const init = ({
                 .then(tableRoot => {
                     // Always update the toggle state.
                     // This ensures that the bulk actions are disabled after changing the page size.
-                    CheckboxToggleAll.setGroupState(tableRoot, 'participants-table', checkCountButtonClicked);
+                    CheckboxToggleAll.setGroupState(root, 'participants-table', checkCountButtonClicked);
 
                     return tableRoot;
                 })
@@ -144,7 +144,7 @@ export const init = ({
             const currentPageSize = parseInt(tableRoot.dataset.tablePageSize, 10);
             const totalRowCount = parseInt(tableRoot.dataset.tableTotalRows, 10);
 
-            CheckboxToggleAll.updateSlavesFromMasterState(tableRoot, 'participants-table');
+            CheckboxToggleAll.updateSlavesFromMasterState(root, 'participants-table');
 
             const pageCountStrings = [
                 {
index 67d9209..f023b5d 100644 (file)
@@ -180,6 +180,7 @@ Feature: View course participants
     And the field "Select 'Student 18x'" matches value "0"
     And the field "Select 'Student 19x'" matches value "0"
 
+    # Pressing the "Select all X users" button should select all including the 21st user (Student 9x).
     And I press "Select all 21 users"
     And I should see "Student 9x"
     And the field "Select 'Teacher 1x'" matches value "1"
@@ -204,6 +205,7 @@ Feature: View course participants
     And the field "Select 'Student 17x'" matches value "1"
     And the field "Select 'Student 18x'" matches value "1"
     And the field "Select 'Student 19x'" matches value "1"
+    And the "With selected users..." "select" should be enabled
 
     And I click on "Deselect all" "checkbox"
     And the field "Select 'Teacher 1x'" matches value "0"