From c50f5af248fc88893b3c6382de4b99da8c718cae Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Mon, 20 Apr 2020 09:24:12 +0800 Subject: [PATCH 1/3] MDL-68464 enrol_manual: Rewrite quickenrolment to use ES6 --- enrol/manual/amd/build/quickenrolment.min.js | 2 +- .../amd/build/quickenrolment.min.js.map | 2 +- enrol/manual/amd/src/quickenrolment.js | 106 +++++++----------- 3 files changed, 43 insertions(+), 67 deletions(-) diff --git a/enrol/manual/amd/build/quickenrolment.min.js b/enrol/manual/amd/build/quickenrolment.min.js index a08ba79e625..d5d24a5cf20 100644 --- a/enrol/manual/amd/build/quickenrolment.min.js +++ b/enrol/manual/amd/build/quickenrolment.min.js @@ -1,2 +1,2 @@ -define ("enrol_manual/quickenrolment",["core/templates","jquery","core/str","core/config","core/notification","core/modal_factory","core/modal_events","core/fragment","core/pending"],function(a,b,c,d,f,g,h,i,j){var k={COHORTSELECT:"#id_cohortlist",TRIGGERBUTTONS:".enrolusersbutton.enrol_manual_plugin [type='submit']",UNWANTEDHIDDENFIELDS:":input[value='_qf__force_multiselect_submission']"},l=function(a){this.contextid=a.contextid;this.initModal()};l.prototype.courseid=0;l.prototype.modal=null;l.prototype.initModal=function(){var a=b(k.TRIGGERBUTTONS);b.when(c.get_strings([{key:"enroluserscohorts",component:"enrol_manual"},{key:"enrolusers",component:"enrol_manual"}]),g.create({type:g.types.SAVE_CANCEL,large:!0},a)).then(function(a,c){this.modal=c;c.setTitle(a[1]);c.setSaveButtonText(a[1]);c.getRoot().on(h.save,this.submitForm.bind(this));c.getRoot().on("submit","form",this.submitFormAjax.bind(this));c.getRoot().on(h.hidden,function(){c.setBody("")});c.getRoot().on(h.shown,function(){var d=new j("enrol_manual/quickenrolment:initModal:shown"),e=this.getBody();e.then(function(d){var e=b(d).find(k.COHORTSELECT).length?0:1;c.setSaveButtonText(a[e])}).then(d.resolve).catch(f.exception);c.setBody(e)}.bind(this))}.bind(this)).fail(f.exception)};l.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};l.prototype.submitFormAjax=function(a){a.preventDefault();var c=this.modal.getRoot().find("form"),e=c.find(k.UNWANTEDHIDDENFIELDS);e.each(function(){b(this).remove()});var g=c.serialize();this.modal.hide();var h=d.wwwroot+"/enrol/manual/ajax.php?"+g;b.ajax(h,{type:"GET",processData:!1,contentType:"application/json"}).then(function(a){if(a.error){f.addNotification({message:a.error,type:"error"})}else{if("undefined"!=typeof window.M.core_formchangechecker){window.M.core_formchangechecker.reset_form_dirty_state()}window.location.reload()}}).fail(f.exception)};l.prototype.getBody=function(){return i.loadFragment("enrol_manual","enrol_users_form",this.contextid,{}).fail(f.exception)};l.prototype.getFooter=function(){return a.render("enrol_manual/enrol_modal_footer",{})};return{init:function init(a){new l(a)}}}); +function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("enrol_manual/quickenrolment",["exports","jquery","core/str","core/fragment","core/modal_events","core/modal_factory","core/notification","core/templates","core/config","core/pending"],function(a,b,c,d,e,f,g,h,i,j){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=m(b);c=l(c);d=m(d);e=m(e);f=m(f);g=m(g);h=m(h);i=m(i);j=m(j);function k(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;k=function(){return a};return a}function l(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=k();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function m(a){return a&&a.__esModule?a:{default:a}}function n(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function o(a,b){for(var c=0,d;c.\n\n/**\n * Quick enrolment AMD module.\n *\n * @module enrol_manual/quickenrolment\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['core/templates',\n 'jquery',\n 'core/str',\n 'core/config',\n 'core/notification',\n 'core/modal_factory',\n 'core/modal_events',\n 'core/fragment',\n 'core/pending',\n ],\n function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment, Pending) {\n\n /** @type {Object} The list of selectors for the quick enrolment modal. */\n var SELECTORS = {\n COHORTSELECT: \"#id_cohortlist\",\n TRIGGERBUTTONS: \".enrolusersbutton.enrol_manual_plugin [type='submit']\",\n UNWANTEDHIDDENFIELDS: \":input[value='_qf__force_multiselect_submission']\"\n };\n\n /**\n * Constructor\n *\n * @param {Object} options Object containing options. The only valid option at this time is contextid.\n * Each call to templates.render gets it's own instance of this class.\n */\n var QuickEnrolment = function(options) {\n this.contextid = options.contextid;\n\n this.initModal();\n };\n // Class variables and functions.\n\n /** @var {number} courseid - */\n QuickEnrolment.prototype.courseid = 0;\n\n /** @var {Modal} modal */\n QuickEnrolment.prototype.modal = null;\n\n /**\n * Private method\n *\n * @method initModal\n * @private\n */\n QuickEnrolment.prototype.initModal = function() {\n var triggerButtons = $(SELECTORS.TRIGGERBUTTONS);\n\n $.when(\n Str.get_strings([\n {key: 'enroluserscohorts', component: 'enrol_manual'},\n {key: 'enrolusers', component: 'enrol_manual'},\n ]),\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n large: true,\n }, triggerButtons)\n )\n .then(function(strings, modal) {\n this.modal = modal;\n\n modal.setTitle(strings[1]);\n modal.setSaveButtonText(strings[1]);\n\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n // We want the reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.setBody('');\n });\n\n modal.getRoot().on(ModalEvents.shown, function() {\n var pendingPromise = new Pending('enrol_manual/quickenrolment:initModal:shown');\n var bodyPromise = this.getBody();\n bodyPromise.then(function(html) {\n var stringIndex = $(html).find(SELECTORS.COHORTSELECT).length ? 0 : 1;\n modal.setSaveButtonText(strings[stringIndex]);\n\n return;\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n\n modal.setBody(bodyPromise);\n }.bind(this));\n\n return;\n }.bind(this))\n .fail(Notification.exception);\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n QuickEnrolment.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n /**\n * Private method\n *\n * @method submitForm\n * @private\n * @param {Event} e Form submission event.\n */\n QuickEnrolment.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n var form = this.modal.getRoot().find('form');\n\n // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.\n // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.\n var hidden = form.find(SELECTORS.UNWANTEDHIDDENFIELDS);\n hidden.each(function() {\n $(this).remove();\n });\n\n var formData = form.serialize();\n\n this.modal.hide();\n\n var settings = {\n type: 'GET',\n processData: false,\n contentType: \"application/json\"\n };\n\n var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData;\n $.ajax(script, settings)\n .then(function(response) {\n\n if (response.error) {\n Notification.addNotification({\n message: response.error,\n type: \"error\"\n });\n } else {\n // Reload the page, don't show changed data warnings.\n if (typeof window.M.core_formchangechecker !== \"undefined\") {\n window.M.core_formchangechecker.reset_form_dirty_state();\n }\n window.location.reload();\n }\n return;\n })\n .fail(Notification.exception);\n };\n\n /**\n * Private method\n *\n * @method getBody\n * @private\n * @return {Promise}\n */\n QuickEnrolment.prototype.getBody = function() {\n return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextid, {}).fail(Notification.exception);\n };\n\n /**\n * Private method\n *\n * @method getFooter\n * @private\n * @return {Promise}\n */\n QuickEnrolment.prototype.getFooter = function() {\n return Template.render('enrol_manual/enrol_modal_footer', {});\n };\n\n return /** @alias module:enrol_manual/quickenrolment */ {\n // Public variables and functions.\n /**\n * Every call to init creates a new instance of the class with it's own event listeners etc.\n *\n * @method init\n * @public\n * @param {object} config - config variables for the module.\n */\n init: function(config) {\n (new QuickEnrolment(config));\n }\n };\n});\n"],"file":"quickenrolment.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/quickenrolment.js"],"names":["Selectors","cohortSelector","triggerButtons","unwantedHiddenFields","QuickEnrolment","contextId","initModal","jQuery","when","Str","get_strings","key","component","ModalFactory","create","type","types","SAVE_CANCEL","large","then","strings","modal","setTitle","setSaveButtonText","getRoot","on","ModalEvents","save","submitForm","bind","submitFormAjax","hidden","setBody","shown","pendingPromise","Pending","bodyPromise","getBody","html","stringIndex","find","length","resolve","catch","Notification","exception","fail","e","preventDefault","submit","form","each","remove","formData","serialize","hide","script","Config","wwwroot","ajax","processData","contentType","response","error","addNotification","message","window","M","core_formchangechecker","reset_form_dirty_state","location","reload","Fragment","loadFragment","Templates","render","init","contextid"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Quick enrolment AMD module.\n *\n * @module enrol_manual/quickenrolment\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport jQuery from 'jquery';\nimport * as Str from 'core/str';\nimport Fragment from 'core/fragment';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport Config from 'core/config';\nimport Pending from 'core/pending';\n\nconst Selectors = {\n cohortSelector: \"#id_cohortlist\",\n triggerButtons: \".enrolusersbutton.enrol_manual_plugin [type='submit']\",\n unwantedHiddenFields: \":input[value='_qf__force_multiselect_submission']\"\n};\n\nconst QuickEnrolment = class {\n constructor(contextId) {\n this.contextId = contextId;\n\n this.initModal();\n }\n\n /**\n * Private method\n *\n * @method initModal\n * @private\n */\n initModal() {\n var triggerButtons = jQuery(Selectors.triggerButtons);\n\n jQuery.when(\n Str.get_strings([\n {key: 'enroluserscohorts', component: 'enrol_manual'},\n {key: 'enrolusers', component: 'enrol_manual'},\n ]),\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n large: true,\n }, triggerButtons)\n )\n .then(function(strings, modal) {\n this.modal = modal;\n\n modal.setTitle(strings[1]);\n modal.setSaveButtonText(strings[1]);\n\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n // We want the reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.setBody('');\n });\n\n modal.getRoot().on(ModalEvents.shown, function() {\n var pendingPromise = new Pending('enrol_manual/quickenrolment:initModal:shown');\n var bodyPromise = this.getBody();\n bodyPromise.then(function(html) {\n var stringIndex = jQuery(html).find(Selectors.cohortSelector).length ? 0 : 1;\n modal.setSaveButtonText(strings[stringIndex]);\n\n return;\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n\n modal.setBody(bodyPromise);\n }.bind(this));\n\n return;\n }.bind(this))\n .fail(Notification.exception);\n\n }\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n submitForm(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n }\n\n /**\n * Private method\n *\n * @method submitForm\n * @private\n * @param {Event} e Form submission event.\n */\n submitFormAjax(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n var form = this.modal.getRoot().find('form');\n\n // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.\n // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.\n var hidden = form.find(Selectors.unwantedHiddenFields);\n hidden.each(function() {\n jQuery(this).remove();\n });\n\n var formData = form.serialize();\n\n this.modal.hide();\n\n var settings = {\n type: 'GET',\n processData: false,\n contentType: \"application/json\"\n };\n\n var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData;\n jQuery.ajax(script, settings)\n .then(function(response) {\n\n if (response.error) {\n Notification.addNotification({\n message: response.error,\n type: \"error\"\n });\n } else {\n // Reload the page, don't show changed data warnings.\n if (typeof window.M.core_formchangechecker !== \"undefined\") {\n window.M.core_formchangechecker.reset_form_dirty_state();\n }\n window.location.reload();\n }\n return;\n })\n .fail(Notification.exception);\n }\n\n /**\n * Private method\n *\n * @method getBody\n * @private\n * @return {Promise}\n */\n getBody() {\n return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextId, {}).fail(Notification.exception);\n }\n\n /**\n * Private method\n *\n * @method getFooter\n * @private\n * @return {Promise}\n */\n getFooter() {\n return Templates.render('enrol_manual/enrol_modal_footer', {});\n }\n};\n\nexport const init = ({contextid}) => {\n new QuickEnrolment(contextid);\n};\n"],"file":"quickenrolment.min.js"} \ No newline at end of file diff --git a/enrol/manual/amd/src/quickenrolment.js b/enrol/manual/amd/src/quickenrolment.js index 74b9e21a6a7..afcfc3f15ef 100644 --- a/enrol/manual/amd/src/quickenrolment.js +++ b/enrol/manual/amd/src/quickenrolment.js @@ -20,43 +20,28 @@ * @copyright 2016 Damyon Wiese * @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) { +import jQuery from 'jquery'; +import * as Str from 'core/str'; +import Fragment from 'core/fragment'; +import ModalEvents from 'core/modal_events'; +import ModalFactory from 'core/modal_factory'; +import Notification from 'core/notification'; +import Templates from 'core/templates'; +import Config from 'core/config'; +import Pending from 'core/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']" - }; +const Selectors = { + cohortSelector: "#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; +const QuickEnrolment = class { + constructor(contextId) { + this.contextId = contextId; this.initModal(); - }; - // Class variables and functions. - - /** @var {number} courseid - */ - QuickEnrolment.prototype.courseid = 0; - - /** @var {Modal} modal */ - QuickEnrolment.prototype.modal = null; + } /** * Private method @@ -64,10 +49,10 @@ define(['core/templates', * @method initModal * @private */ - QuickEnrolment.prototype.initModal = function() { - var triggerButtons = $(SELECTORS.TRIGGERBUTTONS); + initModal() { + var triggerButtons = jQuery(Selectors.triggerButtons); - $.when( + jQuery.when( Str.get_strings([ {key: 'enroluserscohorts', component: 'enrol_manual'}, {key: 'enrolusers', component: 'enrol_manual'}, @@ -95,7 +80,7 @@ define(['core/templates', 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; + var stringIndex = jQuery(html).find(Selectors.cohortSelector).length ? 0 : 1; modal.setSaveButtonText(strings[stringIndex]); return; @@ -109,7 +94,8 @@ define(['core/templates', 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. @@ -118,10 +104,10 @@ define(['core/templates', * @param {Event} e Form submission event. * @private */ - QuickEnrolment.prototype.submitForm = function(e) { + submitForm(e) { e.preventDefault(); this.modal.getRoot().find('form').submit(); - }; + } /** * Private method @@ -130,7 +116,7 @@ define(['core/templates', * @private * @param {Event} e Form submission event. */ - QuickEnrolment.prototype.submitFormAjax = function(e) { + submitFormAjax(e) { // We don't want to do a real form submission. e.preventDefault(); @@ -138,9 +124,9 @@ define(['core/templates', // 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); + var hidden = form.find(Selectors.unwantedHiddenFields); hidden.each(function() { - $(this).remove(); + jQuery(this).remove(); }); var formData = form.serialize(); @@ -154,7 +140,7 @@ define(['core/templates', }; var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData; - $.ajax(script, settings) + jQuery.ajax(script, settings) .then(function(response) { if (response.error) { @@ -172,7 +158,7 @@ define(['core/templates', return; }) .fail(Notification.exception); - }; + } /** * Private method @@ -181,9 +167,9 @@ define(['core/templates', * @private * @return {Promise} */ - QuickEnrolment.prototype.getBody = function() { - return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextid, {}).fail(Notification.exception); - }; + getBody() { + return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextId, {}).fail(Notification.exception); + } /** * Private method @@ -192,21 +178,11 @@ define(['core/templates', * @private * @return {Promise} */ - QuickEnrolment.prototype.getFooter = function() { - return Template.render('enrol_manual/enrol_modal_footer', {}); - }; + getFooter() { + return Templates.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)); - } - }; -}); +export const init = ({contextid}) => { + new QuickEnrolment(contextid); +}; From e0e7b19f9ce70d125f4f3956f23a295f57342d24 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Mon, 20 Apr 2020 11:24:26 +0800 Subject: [PATCH 2/3] MDL-68464 enrol_manual: Reload participants table after enroling --- enrol/manual/ajax.php | 9 +- enrol/manual/amd/build/quickenrolment.min.js | 2 +- .../amd/build/quickenrolment.min.js.map | 2 +- enrol/manual/amd/src/quickenrolment.js | 278 +++++++++--------- user/index.php | 27 +- 5 files changed, 162 insertions(+), 156 deletions(-) diff --git a/enrol/manual/ajax.php b/enrol/manual/ajax.php index ba73f21d97a..29cb40e1053 100644 --- a/enrol/manual/ajax.php +++ b/enrol/manual/ajax.php @@ -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'); diff --git a/enrol/manual/amd/build/quickenrolment.min.js b/enrol/manual/amd/build/quickenrolment.min.js index d5d24a5cf20..ee9d82b6e86 100644 --- a/enrol/manual/amd/build/quickenrolment.min.js +++ b/enrol/manual/amd/build/quickenrolment.min.js @@ -1,2 +1,2 @@ -function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("enrol_manual/quickenrolment",["exports","jquery","core/str","core/fragment","core/modal_events","core/modal_factory","core/notification","core/templates","core/config","core/pending"],function(a,b,c,d,e,f,g,h,i,j){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=m(b);c=l(c);d=m(d);e=m(e);f=m(f);g=m(g);h=m(h);i=m(i);j=m(j);function k(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;k=function(){return a};return a}function l(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=k();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function m(a){return a&&a.__esModule?a:{default:a}}function n(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function o(a,b){for(var c=0,d;c.\n\n/**\n * Quick enrolment AMD module.\n *\n * @module enrol_manual/quickenrolment\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport jQuery from 'jquery';\nimport * as Str from 'core/str';\nimport Fragment from 'core/fragment';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport Config from 'core/config';\nimport Pending from 'core/pending';\n\nconst Selectors = {\n cohortSelector: \"#id_cohortlist\",\n triggerButtons: \".enrolusersbutton.enrol_manual_plugin [type='submit']\",\n unwantedHiddenFields: \":input[value='_qf__force_multiselect_submission']\"\n};\n\nconst QuickEnrolment = class {\n constructor(contextId) {\n this.contextId = contextId;\n\n this.initModal();\n }\n\n /**\n * Private method\n *\n * @method initModal\n * @private\n */\n initModal() {\n var triggerButtons = jQuery(Selectors.triggerButtons);\n\n jQuery.when(\n Str.get_strings([\n {key: 'enroluserscohorts', component: 'enrol_manual'},\n {key: 'enrolusers', component: 'enrol_manual'},\n ]),\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n large: true,\n }, triggerButtons)\n )\n .then(function(strings, modal) {\n this.modal = modal;\n\n modal.setTitle(strings[1]);\n modal.setSaveButtonText(strings[1]);\n\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n // We want the reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.setBody('');\n });\n\n modal.getRoot().on(ModalEvents.shown, function() {\n var pendingPromise = new Pending('enrol_manual/quickenrolment:initModal:shown');\n var bodyPromise = this.getBody();\n bodyPromise.then(function(html) {\n var stringIndex = jQuery(html).find(Selectors.cohortSelector).length ? 0 : 1;\n modal.setSaveButtonText(strings[stringIndex]);\n\n return;\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n\n modal.setBody(bodyPromise);\n }.bind(this));\n\n return;\n }.bind(this))\n .fail(Notification.exception);\n\n }\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n submitForm(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n }\n\n /**\n * Private method\n *\n * @method submitForm\n * @private\n * @param {Event} e Form submission event.\n */\n submitFormAjax(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n var form = this.modal.getRoot().find('form');\n\n // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.\n // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.\n var hidden = form.find(Selectors.unwantedHiddenFields);\n hidden.each(function() {\n jQuery(this).remove();\n });\n\n var formData = form.serialize();\n\n this.modal.hide();\n\n var settings = {\n type: 'GET',\n processData: false,\n contentType: \"application/json\"\n };\n\n var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData;\n jQuery.ajax(script, settings)\n .then(function(response) {\n\n if (response.error) {\n Notification.addNotification({\n message: response.error,\n type: \"error\"\n });\n } else {\n // Reload the page, don't show changed data warnings.\n if (typeof window.M.core_formchangechecker !== \"undefined\") {\n window.M.core_formchangechecker.reset_form_dirty_state();\n }\n window.location.reload();\n }\n return;\n })\n .fail(Notification.exception);\n }\n\n /**\n * Private method\n *\n * @method getBody\n * @private\n * @return {Promise}\n */\n getBody() {\n return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextId, {}).fail(Notification.exception);\n }\n\n /**\n * Private method\n *\n * @method getFooter\n * @private\n * @return {Promise}\n */\n getFooter() {\n return Templates.render('enrol_manual/enrol_modal_footer', {});\n }\n};\n\nexport const init = ({contextid}) => {\n new QuickEnrolment(contextid);\n};\n"],"file":"quickenrolment.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/quickenrolment.js"],"names":["Selectors","cohortSelector","triggerButtons","unwantedHiddenFields","buttonWrapper","getBodyForContext","contextId","Fragment","loadFragment","getDynamicTableForElement","element","wrapper","closest","DynamicTable","getTableFromId","dataset","tableUniqueid","registerEventListeners","document","addEventListener","e","target","preventDefault","showModal","dynamicTable","ModalFactory","create","type","types","SAVE_CANCEL","large","title","Str","get_string","body","then","modal","getRoot","on","ModalEvents","save","find","submit","submitFormAjax","hidden","destroy","show","setSaveButtonText","getBodyPromise","get","querySelector","catch","Notification","exception","form","querySelectorAll","forEach","hiddenField","remove","hide","jQuery","ajax","Config","wwwroot","serialize","processData","contentType","response","error","Error","refreshTableContent","count","notificationBody","Toast","add","addNotification","message","init","contextid","Prefetch","prefetchStrings","prefetchString"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Quick enrolment AMD module.\n *\n * @module enrol_manual/quickenrolment\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as DynamicTable from 'core_table/dynamic';\nimport * as Str from 'core/str';\nimport * as Toast from 'core/toast';\nimport Config from 'core/config';\nimport Fragment from 'core/fragment';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Notification from 'core/notification';\nimport jQuery from 'jquery';\nimport Prefetch from 'core/prefetch';\n\nconst Selectors = {\n cohortSelector: \"#id_cohortlist\",\n triggerButtons: \".enrolusersbutton.enrol_manual_plugin [type='submit']\",\n unwantedHiddenFields: \"input[value='_qf__force_multiselect_submission']\",\n buttonWrapper: '[data-region=\"wrapper\"]',\n};\n\n/**\n * Get the content of the body for the specified context.\n *\n * @param {Number} contextId\n * @returns {Promise}\n */\nconst getBodyForContext = contextId => {\n return Fragment.loadFragment('enrol_manual', 'enrol_users_form', contextId, {});\n};\n\n/**\n * Get the dynamic table for the button.\n *\n * @param {HTMLElement} element\n * @returns {HTMLElement}\n */\nconst getDynamicTableForElement = element => {\n const wrapper = element.closest(Selectors.buttonWrapper);\n\n return DynamicTable.getTableFromId(wrapper.dataset.tableUniqueid);\n};\n\n/**\n * Register the event listeners for this contextid.\n *\n * @param {Number} contextId\n */\nconst registerEventListeners = contextId => {\n document.addEventListener('click', e => {\n if (e.target.closest(Selectors.triggerButtons)) {\n e.preventDefault();\n\n showModal(getDynamicTableForElement(e.target), contextId);\n\n return;\n }\n });\n};\n\n/**\n * Display the modal for this contextId.\n *\n * @param {HTMLElement} dynamicTable The table to beb refreshed when changes are made\n * @param {Number} contextId\n * @returns {Promise}\n */\nconst showModal = (dynamicTable, contextId) => {\n return ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n large: true,\n title: Str.get_string('enrolusers', 'enrol_manual'),\n body: getBodyForContext(contextId),\n })\n .then(modal => {\n modal.getRoot().on(ModalEvents.save, e => {\n // Trigger a form submission, so that any mform elements can do final tricks before the form submission\n // is processed.\n // The actual submit even tis captured in the next handler.\n\n e.preventDefault();\n modal.getRoot().find('form').submit();\n });\n\n modal.getRoot().on('submit', 'form', e => {\n e.preventDefault();\n\n submitFormAjax(dynamicTable, modal);\n });\n\n modal.getRoot().on(ModalEvents.hidden, () => {\n modal.destroy();\n });\n\n return modal;\n })\n .then(modal => {\n modal.show();\n\n return modal;\n })\n .then(modal => {\n modal.setSaveButtonText(Str.get_string('enrolusers', 'enrol_manual'));\n\n modal.getBodyPromise().then(body => {\n if (body.get(0).querySelector(Selectors.cohortSelector)) {\n modal.setSaveButtonText(Str.get_string('enroluserscohorts', 'enrol_manual'));\n }\n\n return body;\n })\n .catch();\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Submit the form via ajax.\n *\n * @param {HTMLElement} dynamicTable\n * @param {Object} modal\n */\nconst submitFormAjax = (dynamicTable, modal) => {\n // Note: We use a jQuery object here so that we can use its serialize functionality.\n const form = modal.getRoot().find('form');\n\n // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.\n // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.\n form.get(0).querySelectorAll(Selectors.unwantedHiddenFields).forEach(hiddenField => hiddenField.remove());\n\n modal.hide();\n modal.destroy();\n\n jQuery.ajax(\n `${Config.wwwroot}/enrol/manual/ajax.php?${form.serialize()}`,\n {\n type: 'GET',\n processData: false,\n contentType: \"application/json\",\n }\n )\n .then(response => {\n if (response.error) {\n throw new Error(response.error);\n }\n\n DynamicTable.refreshTableContent(dynamicTable);\n return Str.get_string('totalenrolledusers', 'enrol', response.count);\n })\n .then(notificationBody => Toast.add(notificationBody))\n .catch(error => {\n Notification.addNotification({\n message: error.message,\n type: 'error',\n });\n });\n};\n\n/**\n * Set up quick enrolment for the manual enrolment plugin.\n *\n * @param {Number} contextid The context id to setup for\n */\nexport const init = ({contextid}) => {\n registerEventListeners(contextid);\n\n Prefetch.prefetchStrings('enrol_manual', [\n 'enrolusers',\n 'enroluserscohorts',\n ]);\n\n Prefetch.prefetchString('enrol', 'totalenrolledusers');\n};\n"],"file":"quickenrolment.min.js"} \ No newline at end of file diff --git a/enrol/manual/amd/src/quickenrolment.js b/enrol/manual/amd/src/quickenrolment.js index afcfc3f15ef..087e4c42811 100644 --- a/enrol/manual/amd/src/quickenrolment.js +++ b/enrol/manual/amd/src/quickenrolment.js @@ -20,169 +20,175 @@ * @copyright 2016 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -import jQuery from 'jquery'; +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 Templates from 'core/templates'; -import Config from 'core/config'; -import Pending from 'core/pending'; +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']" + unwantedHiddenFields: "input[value='_qf__force_multiselect_submission']", + buttonWrapper: '[data-region="wrapper"]', }; -const QuickEnrolment = class { - constructor(contextId) { - this.contextId = contextId; +/** + * 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, {}); +}; - this.initModal(); - } +/** + * Get the dynamic table for the button. + * + * @param {HTMLElement} element + * @returns {HTMLElement} + */ +const getDynamicTableForElement = element => { + const wrapper = element.closest(Selectors.buttonWrapper); - /** - * Private method - * - * @method initModal - * @private - */ - initModal() { - var triggerButtons = jQuery(Selectors.triggerButtons); + return DynamicTable.getTableFromId(wrapper.dataset.tableUniqueid); +}; - jQuery.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; +/** + * 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(); - 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 = jQuery(html).find(Selectors.cohortSelector).length ? 0 : 1; - modal.setSaveButtonText(strings[stringIndex]); - - return; - }) - .then(pendingPromise.resolve) - .catch(Notification.exception); - - modal.setBody(bodyPromise); - }.bind(this)); + showModal(getDynamicTableForElement(e.target), contextId); return; - }.bind(this)) - .fail(Notification.exception); + } + }); +}; - } +/** + * 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. - /** - * 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 - */ - submitForm(e) { - e.preventDefault(); - this.modal.getRoot().find('form').submit(); - } - - /** - * Private method - * - * @method submitForm - * @private - * @param {Event} e Form submission event. - */ - submitFormAjax(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() { - jQuery(this).remove(); + e.preventDefault(); + modal.getRoot().find('form').submit(); }); - var formData = form.serialize(); + modal.getRoot().on('submit', 'form', e => { + e.preventDefault(); - this.modal.hide(); + submitFormAjax(dynamicTable, modal); + }); - var settings = { + modal.getRoot().on(ModalEvents.hidden, () => { + modal.destroy(); + }); + + 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'); + + // 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()); + + modal.hide(); + modal.destroy(); + + jQuery.ajax( + `${Config.wwwroot}/enrol/manual/ajax.php?${form.serialize()}`, + { type: 'GET', processData: false, - contentType: "application/json" - }; + contentType: "application/json", + } + ) + .then(response => { + if (response.error) { + throw new Error(response.error); + } - var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData; - jQuery.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} - */ - getBody() { - return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextId, {}).fail(Notification.exception); - } - - /** - * Private method - * - * @method getFooter - * @private - * @return {Promise} - */ - getFooter() { - return Templates.render('enrol_manual/enrol_modal_footer', {}); - } + 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}) => { - new QuickEnrolment(contextid); + registerEventListeners(contextid); + + Prefetch.prefetchStrings('enrol_manual', [ + 'enrolusers', + 'enroluserscohorts', + ]); + + Prefetch.prefetchString('enrol', 'totalenrolledusers'); }; diff --git a/user/index.php b/user/index.php index 92f81e2bfdb..26e5f209e4a 100644 --- a/user/index.php +++ b/user/index.php @@ -224,6 +224,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(); @@ -232,13 +242,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'); @@ -275,13 +282,9 @@ if (count($keywordfilter)) { $filterset->add_filter($keywordfilter); } -$participanttable = new \core_user\table\participants("user-index-participants-{$course->id}"); -$participanttable->set_selectall($selectall); -$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(); From abc83c40b5fc2ffd32967b2b84bc0f66d03bd250 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 14 May 2020 11:10:57 +0800 Subject: [PATCH 3/3] MDL-68464 enrol_manual: Comment out buggy behat line This is commented out because auto-hidden toasts currently call `hide()` and trigger the `bs.toast.hide` event immediately, and _then_ apply the autohide delay. Since we automatically add M.util.pending_js calls when we _start_ to hide, and resolve them when the hide _finishes_, this means that we do: - addToast called - trigger `bs.toast.show` event - add to pending_js - [pending_js queue not empty - behat waits] - message is shown in UI - `hide()` called - trigger `bs.toast.hide` event - add to pending_js - [pending_js queue not empty - behat waits] - start autohide delay - [pending_js queue not empty - behat waits] - [pending_js queue not empty - behat waits] - [pending_js queue not empty - behat waits] - [pending_js queue not empty - behat waits] - end autohide delay - remove message (no longer present in DOM) - trigger `bs.toast.hidden` event - resolve pending_js - [pending_js queue empty - behat stops waiting] - Behat runs next step: And I should see "1 enrolled users" -- Step fails beacuse the message has been shown, and has then been removed The conversation should have been: - addToast called - trigger `bs.toast.show` event - add to pending_js - [pending_js queue not empty - behat waits] - message is shown in UI - start autohide delay - trigger `bs.toast.shown` event - resolve pending_js - [pending_js queue empty - behat stops waiting] - Behat runs next step: And I should see "1 enrolled users" -- Step passes - autohide delay ends and calls `hide()` - trigger bs.toast.hide event - add to pending_js - [behat waits] - end autohide delay - remove message (no longer present in DOM) - trigger `bs.toast.hidden` event - resolve pending_js - [pending_js queue empty - behat stops waiting] - Behat run continues See MDL-67386 for futher information. --- enrol/manual/tests/behat/quickenrolment.feature | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/enrol/manual/tests/behat/quickenrolment.feature b/enrol/manual/tests/behat/quickenrolment.feature index f2f3f6cc139..6d4494fe960 100644 --- a/enrol/manual/tests/behat/quickenrolment.feature +++ b/enrol/manual/tests/behat/quickenrolment.feature @@ -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