Merge branch 'MDL-68464-master-final' of git://github.com/andrewnicols/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 19 May 2020 22:17:53 +0000 (00:17 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 19 May 2020 22:17:53 +0000 (00:17 +0200)
enrol/manual/ajax.php
enrol/manual/amd/build/quickenrolment.min.js
enrol/manual/amd/build/quickenrolment.min.js.map
enrol/manual/amd/src/quickenrolment.js
enrol/manual/tests/behat/quickenrolment.feature
user/index.php

index ba73f21..29cb40e 100644 (file)
@@ -58,6 +58,7 @@ $outcome = new stdClass();
 $outcome->success = true;
 $outcome->response = new stdClass();
 $outcome->error = '';
+$outcome->count = 0;
 
 $searchanywhere = get_user_preferences('userselector_searchanywhere', false);
 
@@ -157,14 +158,10 @@ switch ($action) {
             foreach ($users as $user) {
                 $plugin->enrol_user($instance, $user->id, $roleid, $timestart, $timeend, null, $recovergrades);
             }
-            $counter = count($users);
+            $outcome->count += count($users);
             foreach ($cohorts as $cohort) {
                 $totalenrolledusers = $plugin->enrol_cohort($instance, $cohort->id, $roleid, $timestart, $timeend, null, $recovergrades);
-                $counter += $totalenrolledusers;
-            }
-            // Display a notification message after the bulk user enrollment.
-            if ($counter > 0) {
-                \core\notification::info(get_string('totalenrolledusers', 'enrol', $counter));
+                $outcome->count += $totalenrolledusers;
             }
         } else {
             throw new enrol_ajax_exception('enrolnotpermitted');
index a08ba79..ee9d82b 100644 (file)
Binary files a/enrol/manual/amd/build/quickenrolment.min.js and b/enrol/manual/amd/build/quickenrolment.min.js differ
index d8e65c3..a413c22 100644 (file)
Binary files a/enrol/manual/amd/build/quickenrolment.min.js.map and b/enrol/manual/amd/build/quickenrolment.min.js.map differ
index 74b9e21..087e4c4 100644 (file)
  * @copyright  2016 Damyon Wiese <damyon@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-define(['core/templates',
-         'jquery',
-         'core/str',
-         'core/config',
-         'core/notification',
-         'core/modal_factory',
-         'core/modal_events',
-         'core/fragment',
-         'core/pending',
-       ],
-       function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment, Pending) {
-
-    /** @type {Object} The list of selectors for the quick enrolment modal. */
-    var SELECTORS = {
-        COHORTSELECT: "#id_cohortlist",
-        TRIGGERBUTTONS: ".enrolusersbutton.enrol_manual_plugin [type='submit']",
-        UNWANTEDHIDDENFIELDS: ":input[value='_qf__force_multiselect_submission']"
-    };
-
-    /**
-     * Constructor
-     *
-     * @param {Object} options Object containing options. The only valid option at this time is contextid.
-     * Each call to templates.render gets it's own instance of this class.
-     */
-    var QuickEnrolment = function(options) {
-        this.contextid = options.contextid;
-
-        this.initModal();
-    };
-    // Class variables and functions.
-
-    /** @var {number} courseid - */
-    QuickEnrolment.prototype.courseid = 0;
-
-    /** @var {Modal} modal */
-    QuickEnrolment.prototype.modal = null;
-
-    /**
-     * Private method
-     *
-     * @method initModal
-     * @private
-     */
-    QuickEnrolment.prototype.initModal = function() {
-        var triggerButtons = $(SELECTORS.TRIGGERBUTTONS);
-
-        $.when(
-            Str.get_strings([
-                {key: 'enroluserscohorts', component: 'enrol_manual'},
-                {key: 'enrolusers', component: 'enrol_manual'},
-            ]),
-            ModalFactory.create({
-                type: ModalFactory.types.SAVE_CANCEL,
-                large: true,
-            }, triggerButtons)
-        )
-        .then(function(strings, modal) {
-            this.modal = modal;
-
-            modal.setTitle(strings[1]);
-            modal.setSaveButtonText(strings[1]);
-
-            modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));
-            modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));
-
-            // We want the reset the form every time it is opened.
-            modal.getRoot().on(ModalEvents.hidden, function() {
-                modal.setBody('');
-            });
-
-            modal.getRoot().on(ModalEvents.shown, function() {
-                var pendingPromise = new Pending('enrol_manual/quickenrolment:initModal:shown');
-                var bodyPromise = this.getBody();
-                bodyPromise.then(function(html) {
-                    var stringIndex = $(html).find(SELECTORS.COHORTSELECT).length ? 0 : 1;
-                    modal.setSaveButtonText(strings[stringIndex]);
-
-                    return;
-                })
-                .then(pendingPromise.resolve)
-                .catch(Notification.exception);
-
-                modal.setBody(bodyPromise);
-            }.bind(this));
+import * as DynamicTable from 'core_table/dynamic';
+import * as Str from 'core/str';
+import * as Toast from 'core/toast';
+import Config from 'core/config';
+import Fragment from 'core/fragment';
+import ModalEvents from 'core/modal_events';
+import ModalFactory from 'core/modal_factory';
+import Notification from 'core/notification';
+import jQuery from 'jquery';
+import Prefetch from 'core/prefetch';
+
+const Selectors = {
+    cohortSelector: "#id_cohortlist",
+    triggerButtons: ".enrolusersbutton.enrol_manual_plugin [type='submit']",
+    unwantedHiddenFields: "input[value='_qf__force_multiselect_submission']",
+    buttonWrapper: '[data-region="wrapper"]',
+};
+
+/**
+ * Get the content of the body for the specified context.
+ *
+ * @param {Number} contextId
+ * @returns {Promise}
+ */
+const getBodyForContext = contextId => {
+    return Fragment.loadFragment('enrol_manual', 'enrol_users_form', contextId, {});
+};
+
+/**
+ * Get the dynamic table for the button.
+ *
+ * @param {HTMLElement} element
+ * @returns {HTMLElement}
+ */
+const getDynamicTableForElement = element => {
+    const wrapper = element.closest(Selectors.buttonWrapper);
+
+    return DynamicTable.getTableFromId(wrapper.dataset.tableUniqueid);
+};
+
+/**
+ * Register the event listeners for this contextid.
+ *
+ * @param {Number} contextId
+ */
+const registerEventListeners = contextId => {
+    document.addEventListener('click', e => {
+        if (e.target.closest(Selectors.triggerButtons)) {
+            e.preventDefault();
+
+            showModal(getDynamicTableForElement(e.target), contextId);
 
             return;
-        }.bind(this))
-        .fail(Notification.exception);
-    };
-
-    /**
-     * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.
-     *
-     * @method submitForm
-     * @param {Event} e Form submission event.
-     * @private
-     */
-    QuickEnrolment.prototype.submitForm = function(e) {
-        e.preventDefault();
-        this.modal.getRoot().find('form').submit();
-    };
-
-    /**
-     * Private method
-     *
-     * @method submitForm
-     * @private
-     * @param {Event} e Form submission event.
-     */
-    QuickEnrolment.prototype.submitFormAjax = function(e) {
-        // We don't want to do a real form submission.
-        e.preventDefault();
-
-        var form = this.modal.getRoot().find('form');
-
-        // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.
-        // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.
-        var hidden = form.find(SELECTORS.UNWANTEDHIDDENFIELDS);
-        hidden.each(function() {
-            $(this).remove();
+        }
+    });
+};
+
+/**
+ * Display the modal for this contextId.
+ *
+ * @param {HTMLElement} dynamicTable The table to beb refreshed when changes are made
+ * @param {Number} contextId
+ * @returns {Promise}
+ */
+const showModal = (dynamicTable, contextId) => {
+    return ModalFactory.create({
+        type: ModalFactory.types.SAVE_CANCEL,
+        large: true,
+        title: Str.get_string('enrolusers', 'enrol_manual'),
+        body: getBodyForContext(contextId),
+    })
+    .then(modal => {
+        modal.getRoot().on(ModalEvents.save, e => {
+            // Trigger a form submission, so that any mform elements can do final tricks before the form submission
+            // is processed.
+            // The actual submit even tis captured in the next handler.
+
+            e.preventDefault();
+            modal.getRoot().find('form').submit();
+        });
+
+        modal.getRoot().on('submit', 'form', e => {
+            e.preventDefault();
+
+            submitFormAjax(dynamicTable, modal);
+        });
+
+        modal.getRoot().on(ModalEvents.hidden, () => {
+            modal.destroy();
         });
 
-        var formData = form.serialize();
+        return modal;
+    })
+    .then(modal => {
+        modal.show();
+
+        return modal;
+    })
+    .then(modal => {
+        modal.setSaveButtonText(Str.get_string('enrolusers', 'enrol_manual'));
+
+        modal.getBodyPromise().then(body => {
+            if (body.get(0).querySelector(Selectors.cohortSelector)) {
+                modal.setSaveButtonText(Str.get_string('enroluserscohorts', 'enrol_manual'));
+            }
+
+            return body;
+        })
+        .catch();
+
+        return modal;
+    })
+    .catch(Notification.exception);
+};
+
+/**
+ * Submit the form via ajax.
+ *
+ * @param {HTMLElement} dynamicTable
+ * @param {Object} modal
+ */
+const submitFormAjax = (dynamicTable, modal) => {
+    // Note: We use a jQuery object here so that we can use its serialize functionality.
+    const form = modal.getRoot().find('form');
 
-        this.modal.hide();
+    // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.
+    // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.
+    form.get(0).querySelectorAll(Selectors.unwantedHiddenFields).forEach(hiddenField => hiddenField.remove());
 
-        var settings = {
+    modal.hide();
+    modal.destroy();
+
+    jQuery.ajax(
+        `${Config.wwwroot}/enrol/manual/ajax.php?${form.serialize()}`,
+        {
             type: 'GET',
             processData: false,
-            contentType: "application/json"
-        };
-
-        var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData;
-        $.ajax(script, settings)
-            .then(function(response) {
-
-                if (response.error) {
-                    Notification.addNotification({
-                        message: response.error,
-                        type: "error"
-                    });
-                } else {
-                    // Reload the page, don't show changed data warnings.
-                    if (typeof window.M.core_formchangechecker !== "undefined") {
-                        window.M.core_formchangechecker.reset_form_dirty_state();
-                    }
-                    window.location.reload();
-                }
-                return;
-            })
-            .fail(Notification.exception);
-    };
-
-    /**
-     * Private method
-     *
-     * @method getBody
-     * @private
-     * @return {Promise}
-     */
-    QuickEnrolment.prototype.getBody = function() {
-        return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextid, {}).fail(Notification.exception);
-    };
-
-    /**
-     * Private method
-     *
-     * @method getFooter
-     * @private
-     * @return {Promise}
-     */
-    QuickEnrolment.prototype.getFooter = function() {
-        return Template.render('enrol_manual/enrol_modal_footer', {});
-    };
-
-    return /** @alias module:enrol_manual/quickenrolment */ {
-        // Public variables and functions.
-        /**
-         * Every call to init creates a new instance of the class with it's own event listeners etc.
-         *
-         * @method init
-         * @public
-         * @param {object} config - config variables for the module.
-         */
-        init: function(config) {
-            (new QuickEnrolment(config));
+            contentType: "application/json",
+        }
+    )
+    .then(response => {
+        if (response.error) {
+            throw new Error(response.error);
         }
-    };
-});
+
+        DynamicTable.refreshTableContent(dynamicTable);
+        return Str.get_string('totalenrolledusers', 'enrol', response.count);
+    })
+    .then(notificationBody => Toast.add(notificationBody))
+    .catch(error => {
+        Notification.addNotification({
+            message: error.message,
+            type: 'error',
+        });
+    });
+};
+
+/**
+ * Set up quick enrolment for the manual enrolment plugin.
+ *
+ * @param {Number} contextid The context id to setup for
+ */
+export const init = ({contextid}) => {
+    registerEventListeners(contextid);
+
+    Prefetch.prefetchStrings('enrol_manual', [
+        'enrolusers',
+        'enroluserscohorts',
+    ]);
+
+    Prefetch.prefetchString('enrol', 'totalenrolledusers');
+};
index f2f3f6c..6d4494f 100644 (file)
@@ -124,7 +124,9 @@ Feature: Teacher can search and enrol users one by one into the course
     And I should see "Student 001"
     And I click on "Enrol users" "button" in the "Enrol users" "dialogue"
     Then I should see "Active" in the "Student 001" "table_row"
-    And I should see "1 enrolled users"
+    # The following line is commented out as auto-hidden toasts fire events in the wrong place.
+    # TODO Uncomment this when we upgrade Bootstrap. This issue is fixed in v4.4.0 - see MDL-67386.
+    #And I should see "1 enrolled users"
 
   @javascript
   Scenario: Searching for a non-existing user
index 7c60722..8966980 100644 (file)
@@ -223,6 +223,16 @@ if ($groupid > 0 && ($course->groupmode != SEPARATEGROUPS || $canaccessallgroups
     echo $grouprenderer->group_details($groupdetailpage);
 }
 
+// Should use this variable so that we don't break stuff every time a variable is added or changed.
+$baseurl = new moodle_url('/user/index.php', array(
+        'contextid' => $context->id,
+        'id' => $course->id,
+        'perpage' => $perpage));
+
+$participanttable = new \core_user\table\participants("user-index-participants-{$course->id}");
+$participanttable->set_selectall($selectall);
+$participanttable->define_baseurl($baseurl);
+
 // Manage enrolments.
 $manager = new course_enrolment_manager($PAGE, $course);
 $enrolbuttons = $manager->get_manual_enrol_buttons();
@@ -231,13 +241,10 @@ $enrolbuttonsout = '';
 foreach ($enrolbuttons as $enrolbutton) {
     $enrolbuttonsout .= $enrolrenderer->render($enrolbutton);
 }
-echo html_writer::div($enrolbuttonsout, 'float-right');
-
-// Should use this variable so that we don't break stuff every time a variable is added or changed.
-$baseurl = new moodle_url('/user/index.php', array(
-        'contextid' => $context->id,
-        'id' => $course->id,
-        'perpage' => $perpage));
+echo html_writer::div($enrolbuttonsout, 'float-right', [
+    'data-region' => 'wrapper',
+    'data-table-uniqueid' => $participanttable->uniqueid,
+]);
 
 // Render the unified filter.
 $renderer = $PAGE->get_renderer('core_user');
@@ -274,12 +281,9 @@ if (count($keywordfilter)) {
     $filterset->add_filter($keywordfilter);
 }
 
-$participanttable = new \core_user\table\participants("user-index-participants-{$course->id}");
-$participanttable->set_filterset($filterset);
-$participanttable->define_baseurl($baseurl);
-
 // Do this so we can get the total number of rows.
 ob_start();
+$participanttable->set_filterset($filterset);
 $participanttable->out($perpage, true);
 $participanttablehtml = ob_get_contents();
 ob_end_clean();