diff --git a/enrol/manual/amd/build/quickenrolment.min.js b/enrol/manual/amd/build/quickenrolment.min.js
index ee9d82b6e86..a451f2b7b18 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","core_table/dynamic","core/str","core/toast","core/config","core/fragment","core/modal_events","core/modal_factory","core/notification","jquery","core/prefetch"],function(a,b,c,d,e,f,g,h,i,j,k){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=n(b);c=n(c);d=n(d);e=l(e);f=l(f);g=l(g);h=l(h);i=l(i);j=l(j);k=l(k);function l(a){return a&&a.__esModule?a:{default:a}}function m(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;m=function(){return a};return a}function n(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=m();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}var o={cohortSelector:"#id_cohortlist",triggerButtons:".enrolusersbutton.enrol_manual_plugin [type='submit']",unwantedHiddenFields:"input[value='_qf__force_multiselect_submission']",buttonWrapper:"[data-region=\"wrapper\"]"},p=function(a){return f.default.loadFragment("enrol_manual","enrol_users_form",a,{})},q=function(a){var c=a.closest(o.buttonWrapper);return b.getTableFromId(c.dataset.tableUniqueid)},r=function(a){document.addEventListener("click",function(b){if(b.target.closest(o.triggerButtons)){b.preventDefault();s(q(b.target),a)}})},s=function(a,b){return h.default.create({type:h.default.types.SAVE_CANCEL,large:!0,title:c.get_string("enrolusers","enrol_manual"),body:p(b)}).then(function(b){b.getRoot().on(g.default.save,function(a){a.preventDefault();b.getRoot().find("form").submit()});b.getRoot().on("submit","form",function(c){c.preventDefault();t(a,b)});b.getRoot().on(g.default.hidden,function(){b.destroy()});return b}).then(function(a){a.show();return a}).then(function(a){a.setSaveButtonText(c.get_string("enrolusers","enrol_manual"));a.getBodyPromise().then(function(b){if(b.get(0).querySelector(o.cohortSelector)){a.setSaveButtonText(c.get_string("enroluserscohorts","enrol_manual"))}return b}).catch();return a}).catch(i.default.exception)},t=function(a,f){var g=f.getRoot().find("form");g.get(0).querySelectorAll(o.unwantedHiddenFields).forEach(function(a){return a.remove()});f.hide();f.destroy();j.default.ajax("".concat(e.default.wwwroot,"/enrol/manual/ajax.php?").concat(g.serialize()),{type:"GET",processData:!1,contentType:"application/json"}).then(function(d){if(d.error){throw new Error(d.error)}b.refreshTableContent(a);return c.get_string("totalenrolledusers","enrol",d.count)}).then(function(a){return d.add(a)}).catch(function(a){i.default.addNotification({message:a.message,type:"error"})})},u=function(a){var b=a.contextid;r(b);k.default.prefetchStrings("enrol_manual",["enrolusers","enroluserscohorts"]);k.default.prefetchString("enrol","totalenrolledusers")};a.init=u});
+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","core_table/dynamic","core/str","core/toast","core/config","core/fragment","core/modal_events","core/modal_factory","core/notification","jquery","core/prefetch"],function(a,b,c,d,e,f,g,h,i,j,k){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=n(b);c=n(c);d=n(d);e=l(e);f=l(f);g=l(g);h=l(h);i=l(i);j=l(j);k=l(k);function l(a){return a&&a.__esModule?a:{default:a}}function m(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;m=function(){return a};return a}function n(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=m();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 o(a,b){return t(a)||s(a,b)||q(a,b)||p()}function p(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function q(a,b){if(!a)return;if("string"==typeof a)return r(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return r(a,b)}function r(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);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 * 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
+{"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","count","Promise","all","refreshTableContent","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 return response.count;\n })\n .then(count => {\n return Promise.all([\n Str.get_string('totalenrolledusers', 'enrol', count),\n DynamicTable.refreshTableContent(dynamicTable),\n ]);\n })\n .then(([notificationBody]) => notificationBody)\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 087e4c42811..ee67d3cb11d 100644
--- a/enrol/manual/amd/src/quickenrolment.js
+++ b/enrol/manual/amd/src/quickenrolment.js
@@ -165,9 +165,15 @@ const submitFormAjax = (dynamicTable, modal) => {
throw new Error(response.error);
}
- DynamicTable.refreshTableContent(dynamicTable);
- return Str.get_string('totalenrolledusers', 'enrol', response.count);
+ return response.count;
})
+ .then(count => {
+ return Promise.all([
+ Str.get_string('totalenrolledusers', 'enrol', count),
+ DynamicTable.refreshTableContent(dynamicTable),
+ ]);
+ })
+ .then(([notificationBody]) => notificationBody)
.then(notificationBody => Toast.add(notificationBody))
.catch(error => {
Notification.addNotification({
diff --git a/lib/table/amd/build/dynamic.min.js b/lib/table/amd/build/dynamic.min.js
index 3bf33397a19..29f5cbd5b52 100644
--- a/lib/table/amd/build/dynamic.min.js
+++ b/lib/table/amd/build/dynamic.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 ("core_table/dynamic",["exports","core_table/local/dynamic/selectors","./local/dynamic/events","core/pending","core/loadingicon","core_table/local/dynamic/repository"],function(a,b,c,d,e,f){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Events",{enumerable:!0,get:function get(){return c.default}});a.getTableFromId=a.init=a.showColumn=a.hideColumn=a.getLastInitial=a.setLastInitial=a.getFirstInitial=a.setFirstInitial=a.getPageSize=a.setPageSize=a.getPageNumber=a.setPageNumber=a.setSortOrder=a.getFilters=a.setFilters=a.updateTable=a.refreshTableContent=void 0;b=i(b);c=g(c);d=g(d);function g(a){return a&&a.__esModule?a:{default:a}}function h(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;h=function(){return a};return a}function i(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=h();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 j(a){return n(a)||m(a)||l(a)||k()}function k(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function l(a,b){if(!a)return;if("string"==typeof a)return p(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return p(a,b)}function m(a){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(a))return Array.from(a)}function n(a){if(Array.isArray(a))return p(a)}function p(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);ca.length)b=a.length;for(var c=0,d=Array(b);c.\n\n/**\n * Module to handle dynamic table features.\n *\n * @module core_table/dynamic\n * @package core_table\n * @copyright 2020 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as Selectors from 'core_table/local/dynamic/selectors';\nimport Events from './local/dynamic/events';\nimport Pending from 'core/pending';\nimport {addIconToContainer} from 'core/loadingicon';\nimport {fetch as fetchTableData} from 'core_table/local/dynamic/repository';\n\nlet watching = false;\n\n/**\n * Ensure that a table is a dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Bool}\n */\nconst checkTableIsDynamic = tableRoot => {\n if (!tableRoot) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n if (!tableRoot.matches(Selectors.main.region)) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n return true;\n};\n\n/**\n * Get the filterset data from a known dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Object}\n */\nconst getFiltersetFromTable = tableRoot => {\n return JSON.parse(tableRoot.dataset.tableFilters);\n};\n\n/**\n * Update the specified table based on its current values.\n *\n * @param {HTMLElement} tableRoot\n * @param {Bool} resetContent\n * @returns {Promise}\n */\nexport const refreshTableContent = (tableRoot, resetContent = false) => {\n const filterset = getFiltersetFromTable(tableRoot);\n addIconToContainer(tableRoot);\n\n const pendingPromise = new Pending('core_table/dynamic:refreshTableContent');\n\n return fetchTableData(\n tableRoot.dataset.tableComponent,\n tableRoot.dataset.tableHandler,\n tableRoot.dataset.tableUniqueid,\n {\n sortData: JSON.parse(tableRoot.dataset.tableSortData),\n joinType: filterset.jointype,\n filters: filterset.filters,\n firstinitial: tableRoot.dataset.tableFirstInitial,\n lastinitial: tableRoot.dataset.tableLastInitial,\n pageNumber: tableRoot.dataset.tablePageNumber,\n pageSize: tableRoot.dataset.tablePageSize,\n hiddenColumns: JSON.parse(tableRoot.dataset.tableHiddenColumns),\n },\n resetContent,\n )\n .then(data => {\n const placeholder = document.createElement('div');\n placeholder.innerHTML = data.html;\n tableRoot.replaceWith(...placeholder.childNodes);\n\n // Update the tableRoot.\n return getTableFromId(tableRoot.dataset.tableUniqueid);\n }).then(tableRoot => {\n tableRoot.dispatchEvent(new CustomEvent(Events.tableContentRefreshed, {\n bubbles: true,\n }));\n\n return tableRoot;\n })\n .then(tableRoot => {\n pendingPromise.resolve();\n\n return tableRoot;\n });\n};\n\nexport const updateTable = (tableRoot, {\n sortBy = null,\n sortOrder = null,\n filters = null,\n firstInitial = null,\n lastInitial = null,\n pageNumber = null,\n pageSize = null,\n hiddenColumns = null,\n} = {}, refreshContent = true) => {\n checkTableIsDynamic(tableRoot);\n\n const pendingPromise = new Pending('core_table/dynamic:updateTable');\n\n // Update sort fields.\n if (sortBy && sortOrder) {\n const sortData = JSON.parse(tableRoot.dataset.tableSortData);\n sortData.unshift({\n sortby: sortBy,\n sortorder: parseInt(sortOrder, 10),\n });\n tableRoot.dataset.tableSortData = JSON.stringify(sortData);\n }\n\n // Update initials.\n if (firstInitial !== null) {\n tableRoot.dataset.tableFirstInitial = firstInitial;\n }\n\n if (lastInitial !== null) {\n tableRoot.dataset.tableLastInitial = lastInitial;\n }\n\n if (pageNumber !== null) {\n tableRoot.dataset.tablePageNumber = pageNumber;\n }\n\n if (pageSize !== null) {\n tableRoot.dataset.tablePageSize = pageSize;\n }\n\n // Update filters.\n if (filters) {\n tableRoot.dataset.tableFilters = JSON.stringify(filters);\n }\n\n // Update hidden columns.\n if (hiddenColumns) {\n tableRoot.dataset.tableHiddenColumns = JSON.stringify(hiddenColumns);\n }\n\n // Refresh.\n if (refreshContent) {\n return refreshTableContent(tableRoot)\n .then(tableRoot => {\n pendingPromise.resolve();\n return tableRoot;\n });\n } else {\n pendingPromise.resolve();\n return Promise.resolve(tableRoot);\n }\n};\n\n/**\n * Get the table dataset for the specified tableRoot, ensuring that the provided table is a dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {DOMStringMap}\n */\nconst getTableData = tableRoot => {\n checkTableIsDynamic(tableRoot);\n\n return tableRoot.dataset;\n};\n\n/**\n * Update the specified table using the new filters.\n *\n * @param {HTMLElement} tableRoot\n * @param {Object} filters\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFilters = (tableRoot, filters, refreshContent = true) =>\n updateTable(tableRoot, {filters}, refreshContent);\n\n/**\n * Get the filter data for the specified table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Object}\n */\nexport const getFilters = tableRoot => {\n checkTableIsDynamic(tableRoot);\n\n return getFiltersetFromTable(tableRoot);\n};\n\n/**\n * Update the sort order.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} sortBy\n * @param {Number} sortOrder\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>\n updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);\n\n/**\n * Set the page number.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} pageNumber\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>\n updateTable(tableRoot, {pageNumber}, refreshContent);\n\n/**\n * Get the current page number.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Number}\n */\nexport const getPageNumber = tableRoot => getTableData(tableRoot).tablePageNumber;\n\n/**\n * Set the page size.\n *\n * @param {HTMLElement} tableRoot\n * @param {Number} pageSize\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setPageSize = (tableRoot, pageSize, refreshContent = true) =>\n updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent);\n\n/**\n * Get the current page size.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Number}\n */\nexport const getPageSize = tableRoot => getTableData(tableRoot).tablePageSize;\n\n/**\n * Update the first initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} firstInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>\n updateTable(tableRoot, {firstInitial}, refreshContent);\n\n/**\n * Get the current first initial filter.\n *\n * @param {HTMLElement} tableRoot\n * @returns {String}\n */\nexport const getFirstInitial = tableRoot => getTableData(tableRoot).tableFirstInitial;\n\n/**\n * Update the last initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} lastInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>\n updateTable(tableRoot, {lastInitial}, refreshContent);\n\n/**\n * Get the current last initial filter.\n *\n * @param {HTMLElement} tableRoot\n * @returns {String}\n */\nexport const getLastInitial = tableRoot => getTableData(tableRoot).tableLastInitial;\n\n/**\n * Hide a column in the participants table.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} columnToHide\n * @param {Bool} refreshContent\n */\nexport const hideColumn = (tableRoot, columnToHide, refreshContent = true) => {\n const hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns);\n hiddenColumns.push(columnToHide);\n\n updateTable(tableRoot, {hiddenColumns}, refreshContent);\n};\n\n/**\n * Make a hidden column visible in the participants table.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} columnToShow\n * @param {Bool} refreshContent\n */\nexport const showColumn = (tableRoot, columnToShow, refreshContent = true) => {\n let hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns);\n hiddenColumns = hiddenColumns.filter(columnName => columnName !== columnToShow);\n\n updateTable(tableRoot, {hiddenColumns}, refreshContent);\n};\n\n/**\n * Reset table preferences.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Promise}\n */\nconst resetTablePreferences = tableRoot => refreshTableContent(tableRoot, true);\n\n/**\n * Set up listeners to handle table updates.\n */\nexport const init = () => {\n if (watching) {\n // Already watching.\n return;\n }\n watching = true;\n\n document.addEventListener('click', e => {\n const tableRoot = e.target.closest(Selectors.main.region);\n\n if (!tableRoot) {\n return;\n }\n\n const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);\n if (sortableLink) {\n e.preventDefault();\n\n setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);\n }\n\n const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);\n if (firstInitialLink !== null) {\n e.preventDefault();\n\n setFirstInitial(tableRoot, firstInitialLink.dataset.initial);\n }\n\n const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);\n if (lastInitialLink !== null) {\n e.preventDefault();\n\n setLastInitial(tableRoot, lastInitialLink.dataset.initial);\n }\n\n const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem);\n if (pageItem) {\n e.preventDefault();\n\n setPageNumber(tableRoot, pageItem.dataset.pageNumber);\n }\n\n const hide = e.target.closest(Selectors.table.links.hide);\n if (hide) {\n e.preventDefault();\n\n hideColumn(tableRoot, hide.dataset.column);\n }\n\n const show = e.target.closest(Selectors.table.links.show);\n if (show) {\n e.preventDefault();\n\n showColumn(tableRoot, show.dataset.column);\n }\n\n const resetTablePreferencesLink = e.target.closest('.resettable a');\n if (resetTablePreferencesLink) {\n e.preventDefault();\n\n resetTablePreferences(tableRoot);\n }\n });\n};\n\n/**\n * Fetch the table via its table region id.\n *\n * @param {String} tableRegionId\n * @returns {HTMLElement}\n */\nexport const getTableFromId = tableRegionId => {\n const tableRoot = document.querySelector(Selectors.main.fromRegionId(tableRegionId));\n\n\n if (!tableRoot) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n return tableRoot;\n};\n\nexport {\n Events\n};\n"],"file":"dynamic.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/dynamic.js"],"names":["watching","checkTableIsDynamic","tableRoot","Error","matches","Selectors","main","region","getFiltersetFromTable","JSON","parse","dataset","tableFilters","refreshTableContent","resetContent","filterset","pendingPromise","Pending","tableComponent","tableHandler","tableUniqueid","sortData","tableSortData","joinType","jointype","filters","firstinitial","tableFirstInitial","lastinitial","tableLastInitial","pageNumber","tablePageNumber","pageSize","tablePageSize","hiddenColumns","tableHiddenColumns","then","data","placeholder","document","createElement","innerHTML","html","replaceWith","childNodes","getTableFromId","dispatchEvent","CustomEvent","Events","tableContentRefreshed","bubbles","resolve","updateTable","sortBy","sortOrder","firstInitial","lastInitial","refreshContent","unshift","sortby","sortorder","parseInt","stringify","Promise","getTableData","setFilters","getFilters","setSortOrder","setPageNumber","getPageNumber","setPageSize","getPageSize","setFirstInitial","getFirstInitial","setLastInitial","getLastInitial","hideColumn","columnToHide","push","showColumn","columnToShow","filter","columnName","resetTablePreferences","init","addEventListener","e","target","closest","sortableLink","table","links","sortableColumn","preventDefault","catch","Notification","exception","firstInitialLink","initialsBar","initial","lastInitialLink","pageItem","paginationBar","hide","column","show","resetTablePreferencesLink","tableRegionId","querySelector","fromRegionId"],"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 * Module to handle dynamic table features.\n *\n * @module core_table/dynamic\n * @package core_table\n * @copyright 2020 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as Selectors from 'core_table/local/dynamic/selectors';\nimport Events from './local/dynamic/events';\nimport Pending from 'core/pending';\nimport {addIconToContainer} from 'core/loadingicon';\nimport {fetch as fetchTableData} from 'core_table/local/dynamic/repository';\nimport Notification from 'core/notification';\n\nlet watching = false;\n\n/**\n * Ensure that a table is a dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Bool}\n */\nconst checkTableIsDynamic = tableRoot => {\n if (!tableRoot) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n if (!tableRoot.matches(Selectors.main.region)) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n return true;\n};\n\n/**\n * Get the filterset data from a known dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Object}\n */\nconst getFiltersetFromTable = tableRoot => {\n return JSON.parse(tableRoot.dataset.tableFilters);\n};\n\n/**\n * Update the specified table based on its current values.\n *\n * @param {HTMLElement} tableRoot\n * @param {Bool} resetContent\n * @returns {Promise}\n */\nexport const refreshTableContent = (tableRoot, resetContent = false) => {\n const filterset = getFiltersetFromTable(tableRoot);\n addIconToContainer(tableRoot);\n\n const pendingPromise = new Pending('core_table/dynamic:refreshTableContent');\n\n return fetchTableData(\n tableRoot.dataset.tableComponent,\n tableRoot.dataset.tableHandler,\n tableRoot.dataset.tableUniqueid,\n {\n sortData: JSON.parse(tableRoot.dataset.tableSortData),\n joinType: filterset.jointype,\n filters: filterset.filters,\n firstinitial: tableRoot.dataset.tableFirstInitial,\n lastinitial: tableRoot.dataset.tableLastInitial,\n pageNumber: tableRoot.dataset.tablePageNumber,\n pageSize: tableRoot.dataset.tablePageSize,\n hiddenColumns: JSON.parse(tableRoot.dataset.tableHiddenColumns),\n },\n resetContent,\n )\n .then(data => {\n const placeholder = document.createElement('div');\n placeholder.innerHTML = data.html;\n tableRoot.replaceWith(...placeholder.childNodes);\n\n // Update the tableRoot.\n return getTableFromId(tableRoot.dataset.tableUniqueid);\n }).then(tableRoot => {\n tableRoot.dispatchEvent(new CustomEvent(Events.tableContentRefreshed, {\n bubbles: true,\n }));\n\n return tableRoot;\n })\n .then(tableRoot => {\n pendingPromise.resolve();\n\n return tableRoot;\n });\n};\n\nexport const updateTable = (tableRoot, {\n sortBy = null,\n sortOrder = null,\n filters = null,\n firstInitial = null,\n lastInitial = null,\n pageNumber = null,\n pageSize = null,\n hiddenColumns = null,\n} = {}, refreshContent = true) => {\n checkTableIsDynamic(tableRoot);\n\n const pendingPromise = new Pending('core_table/dynamic:updateTable');\n\n // Update sort fields.\n if (sortBy && sortOrder) {\n const sortData = JSON.parse(tableRoot.dataset.tableSortData);\n sortData.unshift({\n sortby: sortBy,\n sortorder: parseInt(sortOrder, 10),\n });\n tableRoot.dataset.tableSortData = JSON.stringify(sortData);\n }\n\n // Update initials.\n if (firstInitial !== null) {\n tableRoot.dataset.tableFirstInitial = firstInitial;\n }\n\n if (lastInitial !== null) {\n tableRoot.dataset.tableLastInitial = lastInitial;\n }\n\n if (pageNumber !== null) {\n tableRoot.dataset.tablePageNumber = pageNumber;\n }\n\n if (pageSize !== null) {\n tableRoot.dataset.tablePageSize = pageSize;\n }\n\n // Update filters.\n if (filters) {\n tableRoot.dataset.tableFilters = JSON.stringify(filters);\n }\n\n // Update hidden columns.\n if (hiddenColumns) {\n tableRoot.dataset.tableHiddenColumns = JSON.stringify(hiddenColumns);\n }\n\n // Refresh.\n if (refreshContent) {\n return refreshTableContent(tableRoot)\n .then(tableRoot => {\n pendingPromise.resolve();\n return tableRoot;\n });\n } else {\n pendingPromise.resolve();\n return Promise.resolve(tableRoot);\n }\n};\n\n/**\n * Get the table dataset for the specified tableRoot, ensuring that the provided table is a dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {DOMStringMap}\n */\nconst getTableData = tableRoot => {\n checkTableIsDynamic(tableRoot);\n\n return tableRoot.dataset;\n};\n\n/**\n * Update the specified table using the new filters.\n *\n * @param {HTMLElement} tableRoot\n * @param {Object} filters\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFilters = (tableRoot, filters, refreshContent = true) =>\n updateTable(tableRoot, {filters}, refreshContent);\n\n/**\n * Get the filter data for the specified table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Object}\n */\nexport const getFilters = tableRoot => {\n checkTableIsDynamic(tableRoot);\n\n return getFiltersetFromTable(tableRoot);\n};\n\n/**\n * Update the sort order.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} sortBy\n * @param {Number} sortOrder\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>\n updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);\n\n/**\n * Set the page number.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} pageNumber\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>\n updateTable(tableRoot, {pageNumber}, refreshContent);\n\n/**\n * Get the current page number.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Number}\n */\nexport const getPageNumber = tableRoot => getTableData(tableRoot).tablePageNumber;\n\n/**\n * Set the page size.\n *\n * @param {HTMLElement} tableRoot\n * @param {Number} pageSize\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setPageSize = (tableRoot, pageSize, refreshContent = true) =>\n updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent);\n\n/**\n * Get the current page size.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Number}\n */\nexport const getPageSize = tableRoot => getTableData(tableRoot).tablePageSize;\n\n/**\n * Update the first initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} firstInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>\n updateTable(tableRoot, {firstInitial}, refreshContent);\n\n/**\n * Get the current first initial filter.\n *\n * @param {HTMLElement} tableRoot\n * @returns {String}\n */\nexport const getFirstInitial = tableRoot => getTableData(tableRoot).tableFirstInitial;\n\n/**\n * Update the last initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} lastInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>\n updateTable(tableRoot, {lastInitial}, refreshContent);\n\n/**\n * Get the current last initial filter.\n *\n * @param {HTMLElement} tableRoot\n * @returns {String}\n */\nexport const getLastInitial = tableRoot => getTableData(tableRoot).tableLastInitial;\n\n/**\n * Hide a column in the participants table.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} columnToHide\n * @param {Bool} refreshContent\n */\nexport const hideColumn = (tableRoot, columnToHide, refreshContent = true) => {\n const hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns);\n hiddenColumns.push(columnToHide);\n\n updateTable(tableRoot, {hiddenColumns}, refreshContent);\n};\n\n/**\n * Make a hidden column visible in the participants table.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} columnToShow\n * @param {Bool} refreshContent\n */\nexport const showColumn = (tableRoot, columnToShow, refreshContent = true) => {\n let hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns);\n hiddenColumns = hiddenColumns.filter(columnName => columnName !== columnToShow);\n\n updateTable(tableRoot, {hiddenColumns}, refreshContent);\n};\n\n/**\n * Reset table preferences.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Promise}\n */\nconst resetTablePreferences = tableRoot => refreshTableContent(tableRoot, true);\n\n/**\n * Set up listeners to handle table updates.\n */\nexport const init = () => {\n if (watching) {\n // Already watching.\n return;\n }\n watching = true;\n\n document.addEventListener('click', e => {\n const tableRoot = e.target.closest(Selectors.main.region);\n\n if (!tableRoot) {\n return;\n }\n\n const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);\n if (sortableLink) {\n e.preventDefault();\n\n setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder)\n .catch(Notification.exception);\n }\n\n const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);\n if (firstInitialLink !== null) {\n e.preventDefault();\n\n setFirstInitial(tableRoot, firstInitialLink.dataset.initial).catch(Notification.exception);\n }\n\n const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);\n if (lastInitialLink !== null) {\n e.preventDefault();\n\n setLastInitial(tableRoot, lastInitialLink.dataset.initial).catch(Notification.exception);\n }\n\n const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem);\n if (pageItem) {\n e.preventDefault();\n\n setPageNumber(tableRoot, pageItem.dataset.pageNumber).catch(Notification.exception);\n }\n\n const hide = e.target.closest(Selectors.table.links.hide);\n if (hide) {\n e.preventDefault();\n\n hideColumn(tableRoot, hide.dataset.column).catch(Notification.exception);\n }\n\n const show = e.target.closest(Selectors.table.links.show);\n if (show) {\n e.preventDefault();\n\n showColumn(tableRoot, show.dataset.column).catch(Notification.exception);\n }\n\n const resetTablePreferencesLink = e.target.closest('.resettable a');\n if (resetTablePreferencesLink) {\n e.preventDefault();\n\n resetTablePreferences(tableRoot).catch(Notification.exception);\n }\n });\n};\n\n/**\n * Fetch the table via its table region id.\n *\n * @param {String} tableRegionId\n * @returns {HTMLElement}\n */\nexport const getTableFromId = tableRegionId => {\n const tableRoot = document.querySelector(Selectors.main.fromRegionId(tableRegionId));\n\n\n if (!tableRoot) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n return tableRoot;\n};\n\nexport {\n Events\n};\n"],"file":"dynamic.min.js"}
\ No newline at end of file
diff --git a/lib/table/amd/src/dynamic.js b/lib/table/amd/src/dynamic.js
index 1448991adc9..59c4fb58776 100644
--- a/lib/table/amd/src/dynamic.js
+++ b/lib/table/amd/src/dynamic.js
@@ -26,6 +26,7 @@ import Events from './local/dynamic/events';
import Pending from 'core/pending';
import {addIconToContainer} from 'core/loadingicon';
import {fetch as fetchTableData} from 'core_table/local/dynamic/repository';
+import Notification from 'core/notification';
let watching = false;
@@ -353,49 +354,50 @@ export const init = () => {
if (sortableLink) {
e.preventDefault();
- setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);
+ setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder)
+ .catch(Notification.exception);
}
const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);
if (firstInitialLink !== null) {
e.preventDefault();
- setFirstInitial(tableRoot, firstInitialLink.dataset.initial);
+ setFirstInitial(tableRoot, firstInitialLink.dataset.initial).catch(Notification.exception);
}
const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);
if (lastInitialLink !== null) {
e.preventDefault();
- setLastInitial(tableRoot, lastInitialLink.dataset.initial);
+ setLastInitial(tableRoot, lastInitialLink.dataset.initial).catch(Notification.exception);
}
const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem);
if (pageItem) {
e.preventDefault();
- setPageNumber(tableRoot, pageItem.dataset.pageNumber);
+ setPageNumber(tableRoot, pageItem.dataset.pageNumber).catch(Notification.exception);
}
const hide = e.target.closest(Selectors.table.links.hide);
if (hide) {
e.preventDefault();
- hideColumn(tableRoot, hide.dataset.column);
+ hideColumn(tableRoot, hide.dataset.column).catch(Notification.exception);
}
const show = e.target.closest(Selectors.table.links.show);
if (show) {
e.preventDefault();
- showColumn(tableRoot, show.dataset.column);
+ showColumn(tableRoot, show.dataset.column).catch(Notification.exception);
}
const resetTablePreferencesLink = e.target.closest('.resettable a');
if (resetTablePreferencesLink) {
e.preventDefault();
- resetTablePreferences(tableRoot);
+ resetTablePreferences(tableRoot).catch(Notification.exception);
}
});
};
diff --git a/user/amd/build/participantsfilter.min.js b/user/amd/build/participantsfilter.min.js
index 1176f2b8013..60a726d6039 100644
--- a/user/amd/build/participantsfilter.min.js
+++ b/user/amd/build/participantsfilter.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 ("core_user/participantsfilter",["exports","./local/participantsfilter/filtertypes/courseid","core_table/dynamic","./local/participantsfilter/filter","core/str","core/notification","./local/participantsfilter/selectors","core/templates"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=k(b);c=j(c);d=k(d);f=k(f);g=k(g);h=k(h);var x="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function i(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;i=function(){return a};return a}function j(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=i();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 k(a){return a&&a.__esModule?a:{default:a}}function l(a){return o(a)||n(a)||r(a)||m()}function m(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(a){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(a))return Array.from(a)}function o(a){if(Array.isArray(a))return s(a)}function p(a,b){return u(a)||t(a,b)||r(a,b)||q()}function q(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function r(a,b){if(!a)return;if("string"==typeof a)return s(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return s(a,b)}function s(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);ca.length)b=a.length;for(var c=0,d=Array(b);c.\n\n/**\n * Participants filter managemnet.\n *\n * @module core_user/participants_filter\n * @package core_user\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CourseFilter from './local/participantsfilter/filtertypes/courseid';\nimport * as DynamicTable from 'core_table/dynamic';\nimport GenericFilter from './local/participantsfilter/filter';\nimport {get_strings as getStrings} from 'core/str';\nimport Notification from 'core/notification';\nimport Selectors from './local/participantsfilter/selectors';\nimport Templates from 'core/templates';\n\n/**\n * Initialise the participants filter on the element with the given id.\n *\n * @param {String} participantsRegionId\n */\nexport const init = participantsRegionId => {\n // Keep a reference to the filterset.\n const filterSet = document.querySelector(`#${participantsRegionId}`);\n\n // Keep a reference to all of the active filters.\n const activeFilters = {\n courseid: new CourseFilter('courseid', filterSet),\n };\n\n /**\n * Get the filter list region.\n *\n * @return {HTMLElement}\n */\n const getFilterRegion = () => filterSet.querySelector(Selectors.filterset.regions.filterlist);\n\n /**\n * Add an unselected filter row.\n *\n * @return {Promise}\n */\n const addFilterRow = () => {\n const rownum = 1 + getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n return Templates.renderForPromise('core_user/local/participantsfilter/filterrow', {\"rownumber\": rownum})\n .then(({html, js}) => {\n const newContentNodes = Templates.appendNodeContents(getFilterRegion(), html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n updateFiltersOptions();\n\n return filterRow;\n })\n .catch(Notification.exception);\n };\n\n /**\n * Get the filter data source node fro the specified filter type.\n *\n * @param {String} filterType\n * @return {HTMLElement}\n */\n const getFilterDataSource = filterType => {\n const filterDataNode = filterSet.querySelector(Selectors.filterset.regions.datasource);\n\n return filterDataNode.querySelector(Selectors.data.fields.byName(filterType));\n };\n\n /**\n * Add a filter to the list of active filters, performing any necessary setup.\n *\n * @param {HTMLElement} filterRow\n * @param {String} filterType\n * @param {Array} initialFilterValues The initially selected values for the filter\n * @returns {Filter}\n */\n const addFilter = async(filterRow, filterType, initialFilterValues) => {\n // Name the filter on the filter row.\n filterRow.dataset.filterType = filterType;\n\n const filterDataNode = getFilterDataSource(filterType);\n\n // Instantiate the Filter class.\n let Filter = GenericFilter;\n if (filterDataNode.dataset.filterTypeClass) {\n Filter = await import(filterDataNode.dataset.filterTypeClass);\n }\n activeFilters[filterType] = new Filter(filterType, filterSet, initialFilterValues);\n\n // Disable the select.\n const typeField = filterRow.querySelector(Selectors.filter.fields.type);\n typeField.value = filterType;\n typeField.disabled = 'disabled';\n\n // Update the list of available filter types.\n updateFiltersOptions();\n\n return activeFilters[filterType];\n };\n\n /**\n * Get the registered filter class for the named filter.\n *\n * @param {String} name\n * @return {Object} See the Filter class.\n */\n const getFilterObject = name => {\n return activeFilters[name];\n };\n\n /**\n * Remove or replace the specified filter row and associated class, ensuring that if there is only one filter row,\n * that it is replaced instead of being removed.\n *\n * @param {HTMLElement} filterRow\n */\n const removeOrReplaceFilterRow = filterRow => {\n const filterCount = getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n\n if (filterCount === 1) {\n replaceFilterRow(filterRow);\n } else {\n removeFilterRow(filterRow);\n }\n };\n\n /**\n * Remove the specified filter row and associated class.\n *\n * @param {HTMLElement} filterRow\n */\n const removeFilterRow = async filterRow => {\n // Remove the filter object.\n removeFilterObject(filterRow.dataset.filterType);\n\n // Remove the actual filter HTML.\n filterRow.remove();\n\n // Update the list of available filter types.\n updateFiltersOptions();\n\n // Refresh the table.\n updateTableFromFilter();\n\n // Update filter fieldset legends.\n const filterLegends = await getAvailableFilterLegends();\n\n getFilterRegion().querySelectorAll(Selectors.filter.region).forEach((filterRow, index) => {\n filterRow.querySelector('legend').innerText = filterLegends[index];\n });\n\n };\n\n /**\n * Replace the specified filter row with a new one.\n *\n * @param {HTMLElement} filterRow\n * @param {Number} rowNum The number used to label the filter fieldset legend (eg Row 1). Defaults to 1 (the first filter).\n * @return {Promise}\n */\n const replaceFilterRow = (filterRow, rowNum = 1) => {\n // Remove the filter object.\n removeFilterObject(filterRow.dataset.filterType);\n\n return Templates.renderForPromise('core_user/local/participantsfilter/filterrow', {\"rownumber\": rowNum})\n .then(({html, js}) => {\n const newContentNodes = Templates.replaceNode(filterRow, html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n updateFiltersOptions();\n\n return filterRow;\n })\n .then(filterRow => {\n // Refresh the table.\n updateTableFromFilter();\n\n return filterRow;\n })\n .catch(Notification.exception);\n };\n\n /**\n * Remove the Filter Object from the register.\n *\n * @param {string} filterName The name of the filter to be removed\n */\n const removeFilterObject = filterName => {\n if (filterName) {\n const filter = getFilterObject(filterName);\n if (filter) {\n filter.tearDown();\n\n // Remove from the list of active filters.\n delete activeFilters[filterName];\n }\n }\n };\n\n /**\n * Remove all filters.\n *\n * @returns {Promise}\n */\n const removeAllFilters = () => {\n const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => removeOrReplaceFilterRow(filterRow));\n\n // Refresh the table.\n return updateTableFromFilter();\n };\n\n /**\n * Remove any empty filters.\n */\n const removeEmptyFilters = () => {\n const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const filterType = filterRow.querySelector(Selectors.filter.fields.type);\n if (!filterType.value) {\n removeOrReplaceFilterRow(filterRow);\n }\n });\n };\n\n /**\n * Update the list of filter types to filter out those already selected.\n */\n const updateFiltersOptions = () => {\n const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const options = filterRow.querySelectorAll(Selectors.filter.fields.type + ' option');\n options.forEach(option => {\n if (option.value === filterRow.dataset.filterType) {\n option.classList.remove('hidden');\n option.disabled = false;\n } else if (activeFilters[option.value]) {\n option.classList.add('hidden');\n option.disabled = true;\n } else {\n option.classList.remove('hidden');\n option.disabled = false;\n }\n });\n });\n\n // Configure the state of the \"Add row\" button.\n // This button is disabled when there is a filter row available for each condition.\n const addRowButton = filterSet.querySelector(Selectors.filterset.actions.addRow);\n const filterDataNode = filterSet.querySelectorAll(Selectors.data.fields.all);\n if (filterDataNode.length <= filters.length) {\n addRowButton.setAttribute('disabled', 'disabled');\n } else {\n addRowButton.removeAttribute('disabled');\n }\n\n if (filters.length === 1) {\n filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.add('hidden');\n filterSet.querySelector(Selectors.filterset.fields.join).value = 1;\n } else {\n filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.remove('hidden');\n }\n };\n\n /**\n * Set the current filter options based on a provided configuration.\n *\n * @param {Object} config\n * @param {Number} config.jointype\n * @param {Object} config.filters\n */\n const setFilterFromConfig = config => {\n const filterConfig = Object.entries(config.filters);\n\n if (!filterConfig.length) {\n // There are no filters to set from.\n return;\n }\n\n // Set the main join type.\n filterSet.querySelector(Selectors.filterset.fields.join).value = config.jointype;\n\n const filterPromises = filterConfig.map(([filterType, filterData]) => {\n if (filterType === 'courseid') {\n // The courseid is a special case.\n return Promise.resolve();\n }\n\n const filterValues = filterData.values;\n\n if (!filterValues.length) {\n // There are no values for this filter.\n // Skip it.\n return Promise.resolve();\n }\n\n return addFilterRow().then(([filterRow]) => addFilter(filterRow, filterType, filterValues));\n });\n\n Promise.all(filterPromises).then(() => {\n return removeEmptyFilters();\n })\n .then(updateFiltersOptions)\n .then(updateTableFromFilter)\n .catch();\n };\n\n /**\n * Update the Dynamic table based upon the current filter.\n *\n * @return {Promise}\n */\n const updateTableFromFilter = () => {\n return DynamicTable.setFilters(\n DynamicTable.getTableFromId(filterSet.dataset.tableRegion),\n {\n filters: Object.values(activeFilters).map(filter => filter.filterValue),\n jointype: filterSet.querySelector(Selectors.filterset.fields.join).value,\n }\n );\n };\n\n /**\n * Fetch the strings used to populate the fieldset legends for the maximum number of filters possible.\n *\n * @return {array}\n */\n const getAvailableFilterLegends = async() => {\n const maxFilters = document.querySelector(Selectors.data.typeListSelect).length - 1;\n let requests = [];\n\n [...Array(maxFilters)].forEach((_, rowIndex) => {\n requests.push({\n \"key\": \"filterrowlegend\",\n \"component\": \"core_user\",\n // Add 1 since rows begin at 1 (index begins at zero).\n \"param\": rowIndex + 1\n });\n });\n\n const legendStrings = await getStrings(requests)\n .then(fetchedStrings => {\n return fetchedStrings;\n })\n .catch(Notification.exception);\n\n return legendStrings;\n };\n\n // Add listeners for the main actions.\n filterSet.querySelector(Selectors.filterset.region).addEventListener('click', e => {\n if (e.target.closest(Selectors.filterset.actions.addRow)) {\n e.preventDefault();\n\n addFilterRow();\n }\n\n if (e.target.closest(Selectors.filterset.actions.applyFilters)) {\n e.preventDefault();\n\n updateTableFromFilter();\n }\n\n if (e.target.closest(Selectors.filterset.actions.resetFilters)) {\n e.preventDefault();\n\n removeAllFilters();\n }\n });\n\n // Add the listener to remove a single filter.\n filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('click', e => {\n if (e.target.closest(Selectors.filter.actions.remove)) {\n e.preventDefault();\n\n removeOrReplaceFilterRow(e.target.closest(Selectors.filter.region));\n }\n });\n\n // Add listeners for the filter type selection.\n filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('change', e => {\n const typeField = e.target.closest(Selectors.filter.fields.type);\n if (typeField && typeField.value) {\n const filter = e.target.closest(Selectors.filter.region);\n\n addFilter(filter, typeField.value);\n }\n });\n\n filterSet.querySelector(Selectors.filterset.fields.join).addEventListener('change', e => {\n filterSet.dataset.filterverb = e.target.value;\n });\n\n const tableRoot = DynamicTable.getTableFromId(filterSet.dataset.tableRegion);\n const initialFilters = DynamicTable.getFilters(tableRoot);\n if (initialFilters) {\n // Apply the initial filter configuration.\n setFilterFromConfig(initialFilters);\n }\n};\n"],"file":"participantsfilter.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/participantsfilter.js"],"names":["init","participantsRegionId","filterSet","document","querySelector","activeFilters","courseid","CourseFilter","getFilterRegion","Selectors","filterset","regions","filterlist","addFilterRow","rownum","querySelectorAll","filter","region","length","Templates","renderForPromise","then","html","js","newContentNodes","appendNodeContents","filterRow","typeList","data","forEach","contentNode","contentTypeList","fields","type","innerHTML","updateFiltersOptions","catch","Notification","exception","getFilterDataSource","filterType","filterDataNode","datasource","byName","addFilter","initialFilterValues","dataset","Filter","GenericFilter","filterTypeClass","typeField","value","disabled","getFilterObject","name","removeOrReplaceFilterRow","filterCount","replaceFilterRow","removeFilterRow","removeFilterObject","remove","updateTableFromFilter","getAvailableFilterLegends","filterLegends","index","innerText","rowNum","replaceNode","filterName","tearDown","removeAllFilters","filters","removeEmptyFilters","options","option","classList","add","addRowButton","actions","addRow","all","setAttribute","removeAttribute","filtermatch","join","setFilterFromConfig","config","filterConfig","Object","entries","jointype","filterPromises","map","filterData","Promise","resolve","filterValues","values","DynamicTable","setFilters","getTableFromId","tableRegion","filterValue","maxFilters","typeListSelect","requests","Array","_","rowIndex","push","fetchedStrings","legendStrings","addEventListener","e","target","closest","preventDefault","applyFilters","resetFilters","filterverb","tableRoot","initialFilters","getFilters"],"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 * Participants filter managemnet.\n *\n * @module core_user/participants_filter\n * @package core_user\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CourseFilter from './local/participantsfilter/filtertypes/courseid';\nimport * as DynamicTable from 'core_table/dynamic';\nimport GenericFilter from './local/participantsfilter/filter';\nimport {get_strings as getStrings} from 'core/str';\nimport Notification from 'core/notification';\nimport Selectors from './local/participantsfilter/selectors';\nimport Templates from 'core/templates';\n\n/**\n * Initialise the participants filter on the element with the given id.\n *\n * @param {String} participantsRegionId\n */\nexport const init = participantsRegionId => {\n // Keep a reference to the filterset.\n const filterSet = document.querySelector(`#${participantsRegionId}`);\n\n // Keep a reference to all of the active filters.\n const activeFilters = {\n courseid: new CourseFilter('courseid', filterSet),\n };\n\n /**\n * Get the filter list region.\n *\n * @return {HTMLElement}\n */\n const getFilterRegion = () => filterSet.querySelector(Selectors.filterset.regions.filterlist);\n\n /**\n * Add an unselected filter row.\n *\n * @return {Promise}\n */\n const addFilterRow = () => {\n const rownum = 1 + getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n return Templates.renderForPromise('core_user/local/participantsfilter/filterrow', {\"rownumber\": rownum})\n .then(({html, js}) => {\n const newContentNodes = Templates.appendNodeContents(getFilterRegion(), html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n updateFiltersOptions();\n\n return filterRow;\n })\n .catch(Notification.exception);\n };\n\n /**\n * Get the filter data source node fro the specified filter type.\n *\n * @param {String} filterType\n * @return {HTMLElement}\n */\n const getFilterDataSource = filterType => {\n const filterDataNode = filterSet.querySelector(Selectors.filterset.regions.datasource);\n\n return filterDataNode.querySelector(Selectors.data.fields.byName(filterType));\n };\n\n /**\n * Add a filter to the list of active filters, performing any necessary setup.\n *\n * @param {HTMLElement} filterRow\n * @param {String} filterType\n * @param {Array} initialFilterValues The initially selected values for the filter\n * @returns {Filter}\n */\n const addFilter = async(filterRow, filterType, initialFilterValues) => {\n // Name the filter on the filter row.\n filterRow.dataset.filterType = filterType;\n\n const filterDataNode = getFilterDataSource(filterType);\n\n // Instantiate the Filter class.\n let Filter = GenericFilter;\n if (filterDataNode.dataset.filterTypeClass) {\n Filter = await import(filterDataNode.dataset.filterTypeClass);\n }\n activeFilters[filterType] = new Filter(filterType, filterSet, initialFilterValues);\n\n // Disable the select.\n const typeField = filterRow.querySelector(Selectors.filter.fields.type);\n typeField.value = filterType;\n typeField.disabled = 'disabled';\n\n // Update the list of available filter types.\n updateFiltersOptions();\n\n return activeFilters[filterType];\n };\n\n /**\n * Get the registered filter class for the named filter.\n *\n * @param {String} name\n * @return {Object} See the Filter class.\n */\n const getFilterObject = name => {\n return activeFilters[name];\n };\n\n /**\n * Remove or replace the specified filter row and associated class, ensuring that if there is only one filter row,\n * that it is replaced instead of being removed.\n *\n * @param {HTMLElement} filterRow\n */\n const removeOrReplaceFilterRow = filterRow => {\n const filterCount = getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n\n if (filterCount === 1) {\n replaceFilterRow(filterRow);\n } else {\n removeFilterRow(filterRow);\n }\n };\n\n /**\n * Remove the specified filter row and associated class.\n *\n * @param {HTMLElement} filterRow\n */\n const removeFilterRow = async filterRow => {\n // Remove the filter object.\n removeFilterObject(filterRow.dataset.filterType);\n\n // Remove the actual filter HTML.\n filterRow.remove();\n\n // Update the list of available filter types.\n updateFiltersOptions();\n\n // Refresh the table.\n updateTableFromFilter();\n\n // Update filter fieldset legends.\n const filterLegends = await getAvailableFilterLegends();\n\n getFilterRegion().querySelectorAll(Selectors.filter.region).forEach((filterRow, index) => {\n filterRow.querySelector('legend').innerText = filterLegends[index];\n });\n\n };\n\n /**\n * Replace the specified filter row with a new one.\n *\n * @param {HTMLElement} filterRow\n * @param {Number} rowNum The number used to label the filter fieldset legend (eg Row 1). Defaults to 1 (the first filter).\n * @return {Promise}\n */\n const replaceFilterRow = (filterRow, rowNum = 1) => {\n // Remove the filter object.\n removeFilterObject(filterRow.dataset.filterType);\n\n return Templates.renderForPromise('core_user/local/participantsfilter/filterrow', {\"rownumber\": rowNum})\n .then(({html, js}) => {\n const newContentNodes = Templates.replaceNode(filterRow, html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n updateFiltersOptions();\n\n return filterRow;\n })\n .then(filterRow => {\n // Refresh the table.\n updateTableFromFilter();\n\n return filterRow;\n })\n .catch(Notification.exception);\n };\n\n /**\n * Remove the Filter Object from the register.\n *\n * @param {string} filterName The name of the filter to be removed\n */\n const removeFilterObject = filterName => {\n if (filterName) {\n const filter = getFilterObject(filterName);\n if (filter) {\n filter.tearDown();\n\n // Remove from the list of active filters.\n delete activeFilters[filterName];\n }\n }\n };\n\n /**\n * Remove all filters.\n *\n * @returns {Promise}\n */\n const removeAllFilters = () => {\n const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => removeOrReplaceFilterRow(filterRow));\n\n // Refresh the table.\n return updateTableFromFilter();\n };\n\n /**\n * Remove any empty filters.\n */\n const removeEmptyFilters = () => {\n const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const filterType = filterRow.querySelector(Selectors.filter.fields.type);\n if (!filterType.value) {\n removeOrReplaceFilterRow(filterRow);\n }\n });\n };\n\n /**\n * Update the list of filter types to filter out those already selected.\n */\n const updateFiltersOptions = () => {\n const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const options = filterRow.querySelectorAll(Selectors.filter.fields.type + ' option');\n options.forEach(option => {\n if (option.value === filterRow.dataset.filterType) {\n option.classList.remove('hidden');\n option.disabled = false;\n } else if (activeFilters[option.value]) {\n option.classList.add('hidden');\n option.disabled = true;\n } else {\n option.classList.remove('hidden');\n option.disabled = false;\n }\n });\n });\n\n // Configure the state of the \"Add row\" button.\n // This button is disabled when there is a filter row available for each condition.\n const addRowButton = filterSet.querySelector(Selectors.filterset.actions.addRow);\n const filterDataNode = filterSet.querySelectorAll(Selectors.data.fields.all);\n if (filterDataNode.length <= filters.length) {\n addRowButton.setAttribute('disabled', 'disabled');\n } else {\n addRowButton.removeAttribute('disabled');\n }\n\n if (filters.length === 1) {\n filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.add('hidden');\n filterSet.querySelector(Selectors.filterset.fields.join).value = 1;\n } else {\n filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.remove('hidden');\n }\n };\n\n /**\n * Set the current filter options based on a provided configuration.\n *\n * @param {Object} config\n * @param {Number} config.jointype\n * @param {Object} config.filters\n */\n const setFilterFromConfig = config => {\n const filterConfig = Object.entries(config.filters);\n\n if (!filterConfig.length) {\n // There are no filters to set from.\n return;\n }\n\n // Set the main join type.\n filterSet.querySelector(Selectors.filterset.fields.join).value = config.jointype;\n\n const filterPromises = filterConfig.map(([filterType, filterData]) => {\n if (filterType === 'courseid') {\n // The courseid is a special case.\n return Promise.resolve();\n }\n\n const filterValues = filterData.values;\n\n if (!filterValues.length) {\n // There are no values for this filter.\n // Skip it.\n return Promise.resolve();\n }\n\n return addFilterRow().then(([filterRow]) => addFilter(filterRow, filterType, filterValues));\n });\n\n Promise.all(filterPromises).then(() => {\n return removeEmptyFilters();\n })\n .then(updateFiltersOptions)\n .then(updateTableFromFilter)\n .catch();\n };\n\n /**\n * Update the Dynamic table based upon the current filter.\n *\n * @return {Promise}\n */\n const updateTableFromFilter = () => {\n return DynamicTable.setFilters(\n DynamicTable.getTableFromId(filterSet.dataset.tableRegion),\n {\n filters: Object.values(activeFilters).map(filter => filter.filterValue),\n jointype: filterSet.querySelector(Selectors.filterset.fields.join).value,\n }\n )\n .catch(Notification.exception);\n };\n\n /**\n * Fetch the strings used to populate the fieldset legends for the maximum number of filters possible.\n *\n * @return {array}\n */\n const getAvailableFilterLegends = async() => {\n const maxFilters = document.querySelector(Selectors.data.typeListSelect).length - 1;\n let requests = [];\n\n [...Array(maxFilters)].forEach((_, rowIndex) => {\n requests.push({\n \"key\": \"filterrowlegend\",\n \"component\": \"core_user\",\n // Add 1 since rows begin at 1 (index begins at zero).\n \"param\": rowIndex + 1\n });\n });\n\n const legendStrings = await getStrings(requests)\n .then(fetchedStrings => {\n return fetchedStrings;\n })\n .catch(Notification.exception);\n\n return legendStrings;\n };\n\n // Add listeners for the main actions.\n filterSet.querySelector(Selectors.filterset.region).addEventListener('click', e => {\n if (e.target.closest(Selectors.filterset.actions.addRow)) {\n e.preventDefault();\n\n addFilterRow();\n }\n\n if (e.target.closest(Selectors.filterset.actions.applyFilters)) {\n e.preventDefault();\n\n updateTableFromFilter();\n }\n\n if (e.target.closest(Selectors.filterset.actions.resetFilters)) {\n e.preventDefault();\n\n removeAllFilters();\n }\n });\n\n // Add the listener to remove a single filter.\n filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('click', e => {\n if (e.target.closest(Selectors.filter.actions.remove)) {\n e.preventDefault();\n\n removeOrReplaceFilterRow(e.target.closest(Selectors.filter.region));\n }\n });\n\n // Add listeners for the filter type selection.\n filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('change', e => {\n const typeField = e.target.closest(Selectors.filter.fields.type);\n if (typeField && typeField.value) {\n const filter = e.target.closest(Selectors.filter.region);\n\n addFilter(filter, typeField.value);\n }\n });\n\n filterSet.querySelector(Selectors.filterset.fields.join).addEventListener('change', e => {\n filterSet.dataset.filterverb = e.target.value;\n });\n\n const tableRoot = DynamicTable.getTableFromId(filterSet.dataset.tableRegion);\n const initialFilters = DynamicTable.getFilters(tableRoot);\n if (initialFilters) {\n // Apply the initial filter configuration.\n setFilterFromConfig(initialFilters);\n }\n};\n"],"file":"participantsfilter.min.js"}
\ No newline at end of file
diff --git a/user/amd/build/status_field.min.js b/user/amd/build/status_field.min.js
index 5c1b1bb9c3a..f0f6af8f965 100644
--- a/user/amd/build/status_field.min.js
+++ b/user/amd/build/status_field.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 ("core_user/status_field",["exports","core_table/dynamic","./repository","core/str","core_table/local/dynamic/selectors","core/fragment","core/modal_events","core/modal_factory","core/notification","core/templates","core/toast"],function(a,b,c,d,f,g,h,i,j,k,l){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=o(b);c=o(c);d=o(d);f=m(f);g=m(g);h=m(h);i=m(i);j=m(j);k=m(k);function m(a){return a&&a.__esModule?a:{default:a}}function n(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;n=function(){return a};return a}function o(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=n();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 p(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);if(b)d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable});c.push.apply(c,d)}return c}function q(a){for(var b=1,c;ba.length)b=a.length;for(var c=0,d=Array(b);ca.length)b=a.length;for(var c=0,d=Array(b);c.\n\n/**\n * AMD module for the user enrolment status field in the course participants page.\n *\n * @module core_user/status_field\n * @copyright 2017 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as DynamicTable from 'core_table/dynamic';\nimport * as Repository from './repository';\nimport * as Str from 'core/str';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\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 {add as notifyUser} from 'core/toast';\n\nconst Selectors = {\n editEnrolment: '[data-action=\"editenrolment\"]',\n showDetails: '[data-action=\"showdetails\"]',\n unenrol: '[data-action=\"unenrol\"]',\n statusElement: '[data-status]',\n};\n\n/**\n * Get the dynamic table from the specified link.\n *\n * @param {HTMLElement} link\n * @returns {HTMLElement}\n */\nconst getDynamicTableFromLink = link => link.closest(DynamicTableSelectors.main.region);\n\n/**\n * Get the status container from the specified link.\n *\n * @param {HTMLElement} link\n * @returns {HTMLElement}\n */\nconst getStatusContainer = link => link.closest(Selectors.statusElement);\n\n/**\n * Get user enrolment id from the specified link\n *\n * @param {HTMLElement} link\n * @returns {Number}\n */\nconst getUserEnrolmentIdFromLink = link => link.getAttribute('rel');\n\n/**\n * Register all event listeners for the status fields.\n *\n * @param {Number} contextId\n * @param {Number} uniqueId\n */\nconst registerEventListeners = (contextId, uniqueId) => {\n const getBodyFunction = (userEnrolmentId, formData) => getBody(contextId, userEnrolmentId, formData);\n\n document.addEventListener('click', e => {\n const tableRoot = e.target.closest(DynamicTableSelectors.main.fromRegionId(uniqueId));\n if (!tableRoot) {\n return;\n }\n\n const editLink = e.target.closest(Selectors.editEnrolment);\n if (editLink) {\n e.preventDefault();\n\n showEditDialogue(editLink, getBodyFunction);\n }\n\n const unenrolLink = e.target.closest(Selectors.unenrol);\n if (unenrolLink) {\n e.preventDefault();\n\n showUnenrolConfirmation(unenrolLink);\n }\n\n const showDetailsLink = e.target.closest(Selectors.showDetails);\n if (showDetailsLink) {\n e.preventDefault();\n\n showStatusDetails(showDetailsLink);\n }\n });\n};\n\n/**\n * Show the edit dialogue.\n *\n * @param {HTMLElement} link\n * @param {Function} getBody Function to get the body for the specified user enrolment\n */\nconst showEditDialogue = (link, getBody) => {\n const container = getStatusContainer(link);\n const userEnrolmentId = getUserEnrolmentIdFromLink(link);\n\n ModalFactory.create({\n large: true,\n title: Str.get_string('edituserenrolment', 'enrol', container.dataset.fullname),\n type: ModalFactory.types.SAVE_CANCEL,\n body: getBody(userEnrolmentId)\n })\n .then(modal => {\n // Handle save event.\n modal.getRoot().on(ModalEvents.save, e => {\n // Don't close the modal yet.\n e.preventDefault();\n\n // Submit form data.\n submitEditFormAjax(link, getBody, modal, userEnrolmentId, container.dataset);\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Destroy when hidden.\n modal.destroy();\n });\n\n // Show the modal.\n modal.show();\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Show and handle the unenrolment confirmation dialogue.\n *\n * @param {HTMLElement} link\n */\nconst showUnenrolConfirmation = link => {\n const container = getStatusContainer(link);\n const userEnrolmentId = getUserEnrolmentIdFromLink(link);\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n })\n .then(modal => {\n // Handle confirm event.\n modal.getRoot().on(ModalEvents.save, e => {\n // Don't close the modal yet.\n e.preventDefault();\n\n // Submit data.\n submitUnenrolFormAjax(\n link,\n modal,\n {\n ueid: userEnrolmentId,\n },\n container.dataset\n );\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Destroy when hidden.\n modal.destroy();\n });\n\n // Display the delete confirmation modal.\n modal.show();\n\n const stringData = [\n {\n key: 'unenrol',\n component: 'enrol',\n },\n {\n key: 'unenrolconfirm',\n component: 'enrol',\n param: {\n user: container.dataset.fullname,\n course: container.dataset.coursename,\n enrolinstancename: container.dataset.enrolinstancename,\n }\n }\n ];\n\n return Promise.all([Str.get_strings(stringData), modal]);\n })\n .then(([strings, modal]) => {\n modal.setTitle(strings[0]);\n modal.setSaveButtonText(strings[0]);\n modal.setBody(strings[1]);\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Show the user details dialogue.\n *\n * @param {HTMLElement} link\n */\nconst showStatusDetails = link => {\n const container = getStatusContainer(link);\n\n const context = {\n editenrollink: '',\n statusclass: container.querySelector('span.badge').getAttribute('class'),\n ...container.dataset,\n };\n\n // Find the edit enrolment link.\n const editEnrolLink = container.querySelector(Selectors.editEnrolment);\n if (editEnrolLink) {\n // If there's an edit enrolment link for this user, clone it into the context for the modal.\n context.editenrollink = editEnrolLink.outerHTML;\n }\n\n ModalFactory.create({\n large: true,\n type: ModalFactory.types.CANCEL,\n title: Str.get_string('enroldetails', 'enrol'),\n body: Templates.render('core_user/status_details', context),\n })\n .then(modal => {\n if (editEnrolLink) {\n modal.getRoot().on('click', Selectors.editEnrolment, e => {\n e.preventDefault();\n modal.hide();\n\n // Trigger click event for the edit enrolment link to show the edit enrolment modal.\n editEnrolLink.click();\n });\n }\n\n modal.show();\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => modal.destroy());\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Submit the edit dialogue.\n *\n * @param {HTMLElement} clickedLink\n * @param {Function} getBody\n * @param {Object} modal\n * @param {Number} userEnrolmentId\n * @param {Object} userData\n */\nconst submitEditFormAjax = (clickedLink, getBody, modal, userEnrolmentId, userData) => {\n const form = modal.getRoot().find('form');\n\n Repository.submitUserEnrolmentForm(form.serialize())\n .then(data => {\n if (!data.result) {\n throw data.result;\n }\n\n // Dismiss the modal.\n modal.hide();\n modal.destroy();\n\n return data;\n })\n .then(() => {\n DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink));\n\n return Str.get_string('enrolmentupdatedforuser', 'core_enrol', userData);\n })\n .then(notificationString => {\n notifyUser(notificationString);\n\n return;\n })\n .catch(() => {\n modal.setBody(getBody(userEnrolmentId, JSON.stringify(form.serialize())));\n\n return modal;\n });\n};\n\n/**\n * Submit the unenrolment form.\n *\n * @param {HTMLElement} clickedLink\n * @param {Object} modal\n * @param {Object} args\n * @param {Object} userData\n */\nconst submitUnenrolFormAjax = (clickedLink, modal, args, userData) => {\n Repository.unenrolUser(args.ueid)\n .then(data => {\n if (!data.result) {\n // Display an alert containing the error message\n Notification.alert(data.errors[0].key, data.errors[0].message);\n\n return data;\n }\n\n // Dismiss the modal.\n modal.hide();\n modal.destroy();\n\n return data;\n })\n .then(() => {\n DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink));\n\n return Str.get_string('unenrolleduser', 'core_enrol', userData);\n })\n .then(notificationString => {\n notifyUser(notificationString);\n\n return;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Get the body fragment.\n *\n * @param {Number} contextId\n * @param {Number} ueid The user enrolment id\n * @param {Object} formdata\n * @returns {Promise}\n */\nconst getBody = (contextId, ueid, formdata = null) => Fragment.loadFragment(\n 'enrol',\n 'user_enrolment_form',\n contextId,\n {\n ueid,\n formdata,\n }\n);\n\n/**\n * Initialise the statu field handler.\n *\n * @param {Number} contextid\n * @param {Number} uniqueid\n */\nexport const init = ({contextid, uniqueid}) => {\n registerEventListeners(contextid, uniqueid);\n};\n"],"file":"status_field.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/status_field.js"],"names":["Selectors","editEnrolment","showDetails","unenrol","statusElement","getDynamicTableFromLink","link","closest","DynamicTableSelectors","main","region","getStatusContainer","getUserEnrolmentIdFromLink","getAttribute","registerEventListeners","contextId","uniqueId","getBodyFunction","userEnrolmentId","formData","getBody","document","addEventListener","e","tableRoot","target","fromRegionId","editLink","preventDefault","showEditDialogue","unenrolLink","showUnenrolConfirmation","showDetailsLink","showStatusDetails","container","ModalFactory","create","large","title","Str","get_string","dataset","fullname","type","types","SAVE_CANCEL","body","then","modal","getRoot","on","ModalEvents","save","submitEditFormAjax","hidden","destroy","show","catch","Notification","exception","submitUnenrolFormAjax","ueid","stringData","key","component","param","user","course","coursename","enrolinstancename","Promise","all","get_strings","strings","setTitle","setSaveButtonText","setBody","context","editenrollink","statusclass","querySelector","editEnrolLink","outerHTML","CANCEL","Templates","render","hide","click","clickedLink","userData","form","find","Repository","submitUserEnrolmentForm","serialize","data","result","DynamicTable","refreshTableContent","notificationString","JSON","stringify","args","unenrolUser","alert","errors","message","formdata","Fragment","loadFragment","init","contextid","uniqueid"],"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 * AMD module for the user enrolment status field in the course participants page.\n *\n * @module core_user/status_field\n * @copyright 2017 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as DynamicTable from 'core_table/dynamic';\nimport * as Repository from './repository';\nimport * as Str from 'core/str';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\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 {add as notifyUser} from 'core/toast';\n\nconst Selectors = {\n editEnrolment: '[data-action=\"editenrolment\"]',\n showDetails: '[data-action=\"showdetails\"]',\n unenrol: '[data-action=\"unenrol\"]',\n statusElement: '[data-status]',\n};\n\n/**\n * Get the dynamic table from the specified link.\n *\n * @param {HTMLElement} link\n * @returns {HTMLElement}\n */\nconst getDynamicTableFromLink = link => link.closest(DynamicTableSelectors.main.region);\n\n/**\n * Get the status container from the specified link.\n *\n * @param {HTMLElement} link\n * @returns {HTMLElement}\n */\nconst getStatusContainer = link => link.closest(Selectors.statusElement);\n\n/**\n * Get user enrolment id from the specified link\n *\n * @param {HTMLElement} link\n * @returns {Number}\n */\nconst getUserEnrolmentIdFromLink = link => link.getAttribute('rel');\n\n/**\n * Register all event listeners for the status fields.\n *\n * @param {Number} contextId\n * @param {Number} uniqueId\n */\nconst registerEventListeners = (contextId, uniqueId) => {\n const getBodyFunction = (userEnrolmentId, formData) => getBody(contextId, userEnrolmentId, formData);\n\n document.addEventListener('click', e => {\n const tableRoot = e.target.closest(DynamicTableSelectors.main.fromRegionId(uniqueId));\n if (!tableRoot) {\n return;\n }\n\n const editLink = e.target.closest(Selectors.editEnrolment);\n if (editLink) {\n e.preventDefault();\n\n showEditDialogue(editLink, getBodyFunction);\n }\n\n const unenrolLink = e.target.closest(Selectors.unenrol);\n if (unenrolLink) {\n e.preventDefault();\n\n showUnenrolConfirmation(unenrolLink);\n }\n\n const showDetailsLink = e.target.closest(Selectors.showDetails);\n if (showDetailsLink) {\n e.preventDefault();\n\n showStatusDetails(showDetailsLink);\n }\n });\n};\n\n/**\n * Show the edit dialogue.\n *\n * @param {HTMLElement} link\n * @param {Function} getBody Function to get the body for the specified user enrolment\n */\nconst showEditDialogue = (link, getBody) => {\n const container = getStatusContainer(link);\n const userEnrolmentId = getUserEnrolmentIdFromLink(link);\n\n ModalFactory.create({\n large: true,\n title: Str.get_string('edituserenrolment', 'enrol', container.dataset.fullname),\n type: ModalFactory.types.SAVE_CANCEL,\n body: getBody(userEnrolmentId)\n })\n .then(modal => {\n // Handle save event.\n modal.getRoot().on(ModalEvents.save, e => {\n // Don't close the modal yet.\n e.preventDefault();\n\n // Submit form data.\n submitEditFormAjax(link, getBody, modal, userEnrolmentId, container.dataset);\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Destroy when hidden.\n modal.destroy();\n });\n\n // Show the modal.\n modal.show();\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Show and handle the unenrolment confirmation dialogue.\n *\n * @param {HTMLElement} link\n */\nconst showUnenrolConfirmation = link => {\n const container = getStatusContainer(link);\n const userEnrolmentId = getUserEnrolmentIdFromLink(link);\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n })\n .then(modal => {\n // Handle confirm event.\n modal.getRoot().on(ModalEvents.save, e => {\n // Don't close the modal yet.\n e.preventDefault();\n\n // Submit data.\n submitUnenrolFormAjax(\n link,\n modal,\n {\n ueid: userEnrolmentId,\n },\n container.dataset\n );\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Destroy when hidden.\n modal.destroy();\n });\n\n // Display the delete confirmation modal.\n modal.show();\n\n const stringData = [\n {\n key: 'unenrol',\n component: 'enrol',\n },\n {\n key: 'unenrolconfirm',\n component: 'enrol',\n param: {\n user: container.dataset.fullname,\n course: container.dataset.coursename,\n enrolinstancename: container.dataset.enrolinstancename,\n }\n }\n ];\n\n return Promise.all([Str.get_strings(stringData), modal]);\n })\n .then(([strings, modal]) => {\n modal.setTitle(strings[0]);\n modal.setSaveButtonText(strings[0]);\n modal.setBody(strings[1]);\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Show the user details dialogue.\n *\n * @param {HTMLElement} link\n */\nconst showStatusDetails = link => {\n const container = getStatusContainer(link);\n\n const context = {\n editenrollink: '',\n statusclass: container.querySelector('span.badge').getAttribute('class'),\n ...container.dataset,\n };\n\n // Find the edit enrolment link.\n const editEnrolLink = container.querySelector(Selectors.editEnrolment);\n if (editEnrolLink) {\n // If there's an edit enrolment link for this user, clone it into the context for the modal.\n context.editenrollink = editEnrolLink.outerHTML;\n }\n\n ModalFactory.create({\n large: true,\n type: ModalFactory.types.CANCEL,\n title: Str.get_string('enroldetails', 'enrol'),\n body: Templates.render('core_user/status_details', context),\n })\n .then(modal => {\n if (editEnrolLink) {\n modal.getRoot().on('click', Selectors.editEnrolment, e => {\n e.preventDefault();\n modal.hide();\n\n // Trigger click event for the edit enrolment link to show the edit enrolment modal.\n editEnrolLink.click();\n });\n }\n\n modal.show();\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => modal.destroy());\n\n return modal;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Submit the edit dialogue.\n *\n * @param {HTMLElement} clickedLink\n * @param {Function} getBody\n * @param {Object} modal\n * @param {Number} userEnrolmentId\n * @param {Object} userData\n */\nconst submitEditFormAjax = (clickedLink, getBody, modal, userEnrolmentId, userData) => {\n const form = modal.getRoot().find('form');\n\n Repository.submitUserEnrolmentForm(form.serialize())\n .then(data => {\n if (!data.result) {\n throw data.result;\n }\n\n // Dismiss the modal.\n modal.hide();\n modal.destroy();\n\n return data;\n })\n .then(() => {\n DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink))\n .catch(Notification.exception);\n\n return Str.get_string('enrolmentupdatedforuser', 'core_enrol', userData);\n })\n .then(notificationString => {\n notifyUser(notificationString);\n\n return;\n })\n .catch(() => {\n modal.setBody(getBody(userEnrolmentId, JSON.stringify(form.serialize())));\n\n return modal;\n });\n};\n\n/**\n * Submit the unenrolment form.\n *\n * @param {HTMLElement} clickedLink\n * @param {Object} modal\n * @param {Object} args\n * @param {Object} userData\n */\nconst submitUnenrolFormAjax = (clickedLink, modal, args, userData) => {\n Repository.unenrolUser(args.ueid)\n .then(data => {\n if (!data.result) {\n // Display an alert containing the error message\n Notification.alert(data.errors[0].key, data.errors[0].message);\n\n return data;\n }\n\n // Dismiss the modal.\n modal.hide();\n modal.destroy();\n\n return data;\n })\n .then(() => {\n DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink))\n .catch(Notification.exception);\n\n return Str.get_string('unenrolleduser', 'core_enrol', userData);\n })\n .then(notificationString => {\n notifyUser(notificationString);\n\n return;\n })\n .catch(Notification.exception);\n};\n\n/**\n * Get the body fragment.\n *\n * @param {Number} contextId\n * @param {Number} ueid The user enrolment id\n * @param {Object} formdata\n * @returns {Promise}\n */\nconst getBody = (contextId, ueid, formdata = null) => Fragment.loadFragment(\n 'enrol',\n 'user_enrolment_form',\n contextId,\n {\n ueid,\n formdata,\n }\n);\n\n/**\n * Initialise the statu field handler.\n *\n * @param {Number} contextid\n * @param {Number} uniqueid\n */\nexport const init = ({contextid, uniqueid}) => {\n registerEventListeners(contextid, uniqueid);\n};\n"],"file":"status_field.min.js"}
\ No newline at end of file
diff --git a/user/amd/src/participantsfilter.js b/user/amd/src/participantsfilter.js
index 718e5ab79dd..4e31a1590f9 100644
--- a/user/amd/src/participantsfilter.js
+++ b/user/amd/src/participantsfilter.js
@@ -371,7 +371,8 @@ export const init = participantsRegionId => {
filters: Object.values(activeFilters).map(filter => filter.filterValue),
jointype: filterSet.querySelector(Selectors.filterset.fields.join).value,
}
- );
+ )
+ .catch(Notification.exception);
};
/**
diff --git a/user/amd/src/status_field.js b/user/amd/src/status_field.js
index 156312023b1..e5637f60b2d 100644
--- a/user/amd/src/status_field.js
+++ b/user/amd/src/status_field.js
@@ -280,7 +280,8 @@ const submitEditFormAjax = (clickedLink, getBody, modal, userEnrolmentId, userDa
return data;
})
.then(() => {
- DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink));
+ DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink))
+ .catch(Notification.exception);
return Str.get_string('enrolmentupdatedforuser', 'core_enrol', userData);
})
@@ -321,7 +322,8 @@ const submitUnenrolFormAjax = (clickedLink, modal, args, userData) => {
return data;
})
.then(() => {
- DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink));
+ DynamicTable.refreshTableContent(getDynamicTableFromLink(clickedLink))
+ .catch(Notification.exception);
return Str.get_string('unenrolleduser', 'core_enrol', userData);
})