diff --git a/admin/category.php b/admin/category.php
index 9cd3aba1016..b203497bfeb 100644
--- a/admin/category.php
+++ b/admin/category.php
@@ -158,9 +158,7 @@ echo $outputhtml;
echo html_writer::end_tag('fieldset');
echo html_writer::end_tag('form');
-$PAGE->requires->yui_module('moodle-core-formchangechecker', 'M.core_formchangechecker.init', [[
- 'formid' => 'adminsettings'
-]]);
-$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+// Add the form change checker.
+$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['adminsettings']);
echo $OUTPUT->footer();
diff --git a/admin/settings.php b/admin/settings.php
index 0872e0375cc..24b90244dc9 100644
--- a/admin/settings.php
+++ b/admin/settings.php
@@ -148,13 +148,8 @@ if (empty($SITE->fullname)) {
echo $OUTPUT->render_from_template('core_admin/settings', $context);
}
-$PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => 'adminsettings'
- ))
-);
-$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+// Add the form change checker.
+$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['adminsettings']);
if ($settingspage->has_dependencies()) {
$opts = [
diff --git a/admin/tool/dataprivacy/amd/build/add_category.min.js b/admin/tool/dataprivacy/amd/build/add_category.min.js
index 52f6aeb8fb0..987f86b93c9 100644
--- a/admin/tool/dataprivacy/amd/build/add_category.min.js
+++ b/admin/tool/dataprivacy/amd/build/add_category.min.js
@@ -1,2 +1,2 @@
-define ("tool_dataprivacy/add_category",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g){var h={CATEGORY_LINK:"[data-add-element=\"category\"]"},i=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addcategory",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};i.prototype.contextId=0;i.prototype.strings=0;i.prototype.registerEventListeners=function(){var b=a(h.CATEGORY_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};i.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addcategory_form",this.contextId,b)};i.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};i.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_category_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};i.prototype.close=function(){this.destroy();document.location.reload()};i.prototype.destroy=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});this.modal.destroy()};i.prototype.removeListeners=function(){a(h.CATEGORY_LINK).off("click")};return{getInstance:function getInstance(a){return new i(a)}}});
+define ("tool_dataprivacy/add_category",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment","core_form/changechecker"],function(a,b,c,d,e,f,g,h){var i={CATEGORY_LINK:"[data-add-element=\"category\"]"},j=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addcategory",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};j.prototype.contextId=0;j.prototype.strings=0;j.prototype.registerEventListeners=function(){var b=a(i.CATEGORY_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};j.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addcategory_form",this.contextId,b)};j.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};j.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};j.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_category_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};j.prototype.close=function(){this.destroy();document.location.reload()};j.prototype.destroy=function(){h.resetAllFormDirtyStates();this.modal.destroy()};j.prototype.removeListeners=function(){a(i.CATEGORY_LINK).off("click")};return{getInstance:function getInstance(a){return new j(a)}}});
//# sourceMappingURL=add_category.min.js.map
diff --git a/admin/tool/dataprivacy/amd/build/add_category.min.js.map b/admin/tool/dataprivacy/amd/build/add_category.min.js.map
index ba77ccb2094..f97e7286498 100644
--- a/admin/tool/dataprivacy/amd/build/add_category.min.js.map
+++ b/admin/tool/dataprivacy/amd/build/add_category.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/add_category.js"],"names":["define","$","Str","Ajax","Notification","ModalFactory","ModalEvents","Fragment","SELECTORS","CATEGORY_LINK","AddCategory","contextId","strings","get_strings","key","component","registerEventListeners","prototype","trigger","on","then","create","type","types","SAVE_CANCEL","title","body","done","modal","setupFormModal","bind","fail","exception","getBody","formdata","params","jsonformdata","JSON","stringify","loadFragment","saveText","setLarge","setSaveButtonText","getRoot","hidden","destroy","setBody","save","submitForm","submitFormAjax","show","e","preventDefault","find","submit","formData","serialize","call","methodname","args","data","validationerrors","close","document","location","reload","Y","use","M","core_formchangechecker","reset_form_dirty_state","removeListeners","off","getInstance"],"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 add categories.\n *\n * @module tool_dataprivacy/add_category\n * @copyright 2018 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],\n function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {\n\n var SELECTORS = {\n CATEGORY_LINK: '[data-add-element=\"category\"]',\n };\n\n var AddCategory = function(contextId) {\n this.contextId = contextId;\n\n var stringKeys = [\n {\n key: 'addcategory',\n component: 'tool_dataprivacy'\n },\n {\n key: 'save',\n component: 'admin'\n }\n ];\n this.strings = Str.get_strings(stringKeys);\n\n this.registerEventListeners();\n };\n\n /**\n * @var {int} contextId\n * @private\n */\n AddCategory.prototype.contextId = 0;\n\n /**\n * @var {Promise}\n * @private\n */\n AddCategory.prototype.strings = 0;\n\n AddCategory.prototype.registerEventListeners = function() {\n\n var trigger = $(SELECTORS.CATEGORY_LINK);\n trigger.on('click', function() {\n return this.strings.then(function(strings) {\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: strings[0],\n body: '',\n }, trigger).done(function(modal) {\n this.setupFormModal(modal, strings[1]);\n }.bind(this));\n }.bind(this))\n .fail(Notification.exception);\n }.bind(this));\n\n };\n\n /**\n * @method getBody\n * @param {Object} formdata\n * @private\n * @return {Promise}\n */\n AddCategory.prototype.getBody = function(formdata) {\n\n var params = null;\n if (typeof formdata !== \"undefined\") {\n params = {jsonformdata: JSON.stringify(formdata)};\n }\n // Get the content of the modal.\n return Fragment.loadFragment('tool_dataprivacy', 'addcategory_form', this.contextId, params);\n };\n\n AddCategory.prototype.setupFormModal = function(modal, saveText) {\n modal.setLarge();\n\n modal.setSaveButtonText(saveText);\n\n // We want to reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));\n\n modal.setBody(this.getBody());\n\n // We catch the modal save event, and use it to submit the form inside the modal.\n // Triggering a form submission will give JS validation scripts a chance to check for errors.\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n // We also catch the form submit event and use it to submit the form with ajax.\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n this.modal = modal;\n\n modal.show();\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n AddCategory.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n AddCategory.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = this.modal.getRoot().find('form').serialize();\n\n Ajax.call([{\n methodname: 'tool_dataprivacy_create_category_form',\n args: {jsonformdata: JSON.stringify(formData)},\n done: function(data) {\n if (data.validationerrors) {\n this.modal.setBody(this.getBody(formData));\n } else {\n this.close();\n }\n }.bind(this),\n fail: Notification.exception\n }]);\n };\n\n AddCategory.prototype.close = function() {\n this.destroy();\n document.location.reload();\n };\n\n AddCategory.prototype.destroy = function() {\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n this.modal.destroy();\n };\n\n AddCategory.prototype.removeListeners = function() {\n $(SELECTORS.CATEGORY_LINK).off('click');\n };\n\n return /** @alias module:tool_dataprivacy/add_category */ {\n getInstance: function(contextId) {\n return new AddCategory(contextId);\n }\n };\n }\n);\n\n"],"file":"add_category.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/add_category.js"],"names":["define","$","Str","Ajax","Notification","ModalFactory","ModalEvents","Fragment","FormChangeChecker","SELECTORS","CATEGORY_LINK","AddCategory","contextId","strings","get_strings","key","component","registerEventListeners","prototype","trigger","on","then","create","type","types","SAVE_CANCEL","title","body","done","modal","setupFormModal","bind","fail","exception","getBody","formdata","params","jsonformdata","JSON","stringify","loadFragment","saveText","setLarge","setSaveButtonText","getRoot","hidden","destroy","setBody","save","submitForm","submitFormAjax","show","e","preventDefault","find","submit","formData","serialize","call","methodname","args","data","validationerrors","close","document","location","reload","resetAllFormDirtyStates","removeListeners","off","getInstance"],"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 add categories.\n *\n * @module tool_dataprivacy/add_category\n * @copyright 2018 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/str',\n 'core/ajax',\n 'core/notification',\n 'core/modal_factory',\n 'core/modal_events',\n 'core/fragment',\n 'core_form/changechecker',\n], function(\n $,\n Str,\n Ajax,\n Notification,\n ModalFactory,\n ModalEvents,\n Fragment,\n FormChangeChecker\n) {\n\n var SELECTORS = {\n CATEGORY_LINK: '[data-add-element=\"category\"]',\n };\n\n var AddCategory = function(contextId) {\n this.contextId = contextId;\n\n var stringKeys = [\n {\n key: 'addcategory',\n component: 'tool_dataprivacy'\n },\n {\n key: 'save',\n component: 'admin'\n }\n ];\n this.strings = Str.get_strings(stringKeys);\n\n this.registerEventListeners();\n };\n\n /**\n * @var {int} contextId\n * @private\n */\n AddCategory.prototype.contextId = 0;\n\n /**\n * @var {Promise}\n * @private\n */\n AddCategory.prototype.strings = 0;\n\n AddCategory.prototype.registerEventListeners = function() {\n\n var trigger = $(SELECTORS.CATEGORY_LINK);\n trigger.on('click', function() {\n return this.strings.then(function(strings) {\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: strings[0],\n body: '',\n }, trigger).done(function(modal) {\n this.setupFormModal(modal, strings[1]);\n }.bind(this));\n }.bind(this))\n .fail(Notification.exception);\n }.bind(this));\n\n };\n\n /**\n * @method getBody\n * @param {Object} formdata\n * @private\n * @return {Promise}\n */\n AddCategory.prototype.getBody = function(formdata) {\n\n var params = null;\n if (typeof formdata !== \"undefined\") {\n params = {jsonformdata: JSON.stringify(formdata)};\n }\n // Get the content of the modal.\n return Fragment.loadFragment('tool_dataprivacy', 'addcategory_form', this.contextId, params);\n };\n\n AddCategory.prototype.setupFormModal = function(modal, saveText) {\n modal.setLarge();\n\n modal.setSaveButtonText(saveText);\n\n // We want to reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));\n\n modal.setBody(this.getBody());\n\n // We catch the modal save event, and use it to submit the form inside the modal.\n // Triggering a form submission will give JS validation scripts a chance to check for errors.\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n // We also catch the form submit event and use it to submit the form with ajax.\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n this.modal = modal;\n\n modal.show();\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n AddCategory.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n AddCategory.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = this.modal.getRoot().find('form').serialize();\n\n Ajax.call([{\n methodname: 'tool_dataprivacy_create_category_form',\n args: {jsonformdata: JSON.stringify(formData)},\n done: function(data) {\n if (data.validationerrors) {\n this.modal.setBody(this.getBody(formData));\n } else {\n this.close();\n }\n }.bind(this),\n fail: Notification.exception\n }]);\n };\n\n AddCategory.prototype.close = function() {\n this.destroy();\n document.location.reload();\n };\n\n AddCategory.prototype.destroy = function() {\n FormChangeChecker.resetAllFormDirtyStates();\n this.modal.destroy();\n };\n\n AddCategory.prototype.removeListeners = function() {\n $(SELECTORS.CATEGORY_LINK).off('click');\n };\n\n return /** @alias module:tool_dataprivacy/add_category */ {\n getInstance: function(contextId) {\n return new AddCategory(contextId);\n }\n };\n }\n);\n\n"],"file":"add_category.min.js"}
\ No newline at end of file
diff --git a/admin/tool/dataprivacy/amd/build/add_purpose.min.js b/admin/tool/dataprivacy/amd/build/add_purpose.min.js
index d3bcb8b901b..9e71843cdb6 100644
--- a/admin/tool/dataprivacy/amd/build/add_purpose.min.js
+++ b/admin/tool/dataprivacy/amd/build/add_purpose.min.js
@@ -1,2 +1,2 @@
-define ("tool_dataprivacy/add_purpose",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g){var h={PURPOSE_LINK:"[data-add-element=\"purpose\"]"},i=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addpurpose",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};i.prototype.contextId=0;i.prototype.strings=0;i.prototype.registerEventListeners=function(){var b=a(h.PURPOSE_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};i.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addpurpose_form",this.contextId,b)};i.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};i.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_purpose_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};i.prototype.close=function(){this.destroy();document.location.reload()};i.prototype.destroy=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});this.modal.destroy()};i.prototype.removeListeners=function(){a(h.PURPOSE_LINK).off("click")};return{getInstance:function getInstance(a){return new i(a)}}});
+define ("tool_dataprivacy/add_purpose",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment","core_form/changechecker"],function(a,b,c,d,e,f,g,h){var i={PURPOSE_LINK:"[data-add-element=\"purpose\"]"},j=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addpurpose",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};j.prototype.contextId=0;j.prototype.strings=0;j.prototype.registerEventListeners=function(){var b=a(i.PURPOSE_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};j.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addpurpose_form",this.contextId,b)};j.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};j.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};j.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_purpose_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};j.prototype.close=function(){this.destroy();document.location.reload()};j.prototype.destroy=function(){h.resetAllFormDirtyStates();this.modal.destroy()};j.prototype.removeListeners=function(){a(i.PURPOSE_LINK).off("click")};return{getInstance:function getInstance(a){return new j(a)}}});
//# sourceMappingURL=add_purpose.min.js.map
diff --git a/admin/tool/dataprivacy/amd/build/add_purpose.min.js.map b/admin/tool/dataprivacy/amd/build/add_purpose.min.js.map
index 525a7405613..81d703e1eca 100644
--- a/admin/tool/dataprivacy/amd/build/add_purpose.min.js.map
+++ b/admin/tool/dataprivacy/amd/build/add_purpose.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/add_purpose.js"],"names":["define","$","Str","Ajax","Notification","ModalFactory","ModalEvents","Fragment","SELECTORS","PURPOSE_LINK","AddPurpose","contextId","strings","get_strings","key","component","registerEventListeners","prototype","trigger","on","then","create","type","types","SAVE_CANCEL","title","body","done","modal","setupFormModal","bind","fail","exception","getBody","formdata","params","jsonformdata","JSON","stringify","loadFragment","saveText","setLarge","setSaveButtonText","getRoot","hidden","destroy","setBody","save","submitForm","submitFormAjax","show","e","preventDefault","find","submit","formData","serialize","call","methodname","args","data","validationerrors","close","document","location","reload","Y","use","M","core_formchangechecker","reset_form_dirty_state","removeListeners","off","getInstance"],"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 add purposes.\n *\n * @module tool_dataprivacy/add_purpose\n * @copyright 2018 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],\n function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {\n\n var SELECTORS = {\n PURPOSE_LINK: '[data-add-element=\"purpose\"]',\n };\n\n var AddPurpose = function(contextId) {\n this.contextId = contextId;\n\n var stringKeys = [\n {\n key: 'addpurpose',\n component: 'tool_dataprivacy'\n },\n {\n key: 'save',\n component: 'admin'\n }\n ];\n this.strings = Str.get_strings(stringKeys);\n\n this.registerEventListeners();\n };\n\n /**\n * @var {int} contextId\n * @private\n */\n AddPurpose.prototype.contextId = 0;\n\n /**\n * @var {Promise}\n * @private\n */\n AddPurpose.prototype.strings = 0;\n\n AddPurpose.prototype.registerEventListeners = function() {\n\n var trigger = $(SELECTORS.PURPOSE_LINK);\n trigger.on('click', function() {\n return this.strings.then(function(strings) {\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: strings[0],\n body: '',\n }, trigger).done(function(modal) {\n this.setupFormModal(modal, strings[1]);\n }.bind(this));\n }.bind(this))\n .fail(Notification.exception);\n }.bind(this));\n\n };\n\n /**\n * @method getBody\n * @param {Object} formdata\n * @private\n * @return {Promise}\n */\n AddPurpose.prototype.getBody = function(formdata) {\n\n var params = null;\n if (typeof formdata !== \"undefined\") {\n params = {jsonformdata: JSON.stringify(formdata)};\n }\n // Get the content of the modal.\n return Fragment.loadFragment('tool_dataprivacy', 'addpurpose_form', this.contextId, params);\n };\n\n AddPurpose.prototype.setupFormModal = function(modal, saveText) {\n modal.setLarge();\n\n modal.setSaveButtonText(saveText);\n\n // We want to reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));\n\n modal.setBody(this.getBody());\n\n // We catch the modal save event, and use it to submit the form inside the modal.\n // Triggering a form submission will give JS validation scripts a chance to check for errors.\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n // We also catch the form submit event and use it to submit the form with ajax.\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n this.modal = modal;\n\n modal.show();\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n AddPurpose.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n AddPurpose.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = this.modal.getRoot().find('form').serialize();\n\n Ajax.call([{\n methodname: 'tool_dataprivacy_create_purpose_form',\n args: {jsonformdata: JSON.stringify(formData)},\n done: function(data) {\n if (data.validationerrors) {\n this.modal.setBody(this.getBody(formData));\n } else {\n this.close();\n }\n }.bind(this),\n\n fail: Notification.exception\n }]);\n };\n\n AddPurpose.prototype.close = function() {\n this.destroy();\n document.location.reload();\n };\n\n AddPurpose.prototype.destroy = function() {\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n this.modal.destroy();\n };\n\n AddPurpose.prototype.removeListeners = function() {\n $(SELECTORS.PURPOSE_LINK).off('click');\n };\n\n return /** @alias module:tool_dataprivacy/add_purpose */ {\n getInstance: function(contextId) {\n return new AddPurpose(contextId);\n }\n };\n }\n);\n\n"],"file":"add_purpose.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/add_purpose.js"],"names":["define","$","Str","Ajax","Notification","ModalFactory","ModalEvents","Fragment","FormChangeChecker","SELECTORS","PURPOSE_LINK","AddPurpose","contextId","strings","get_strings","key","component","registerEventListeners","prototype","trigger","on","then","create","type","types","SAVE_CANCEL","title","body","done","modal","setupFormModal","bind","fail","exception","getBody","formdata","params","jsonformdata","JSON","stringify","loadFragment","saveText","setLarge","setSaveButtonText","getRoot","hidden","destroy","setBody","save","submitForm","submitFormAjax","show","e","preventDefault","find","submit","formData","serialize","call","methodname","args","data","validationerrors","close","document","location","reload","resetAllFormDirtyStates","removeListeners","off","getInstance"],"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 add purposes.\n *\n * @module tool_dataprivacy/add_purpose\n * @copyright 2018 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/str',\n 'core/ajax',\n 'core/notification',\n 'core/modal_factory',\n 'core/modal_events',\n 'core/fragment',\n 'core_form/changechecker',\n], function(\n $,\n Str,\n Ajax,\n Notification,\n ModalFactory,\n ModalEvents,\n Fragment,\n FormChangeChecker\n) {\n\n var SELECTORS = {\n PURPOSE_LINK: '[data-add-element=\"purpose\"]',\n };\n\n var AddPurpose = function(contextId) {\n this.contextId = contextId;\n\n var stringKeys = [\n {\n key: 'addpurpose',\n component: 'tool_dataprivacy'\n },\n {\n key: 'save',\n component: 'admin'\n }\n ];\n this.strings = Str.get_strings(stringKeys);\n\n this.registerEventListeners();\n };\n\n /**\n * @var {int} contextId\n * @private\n */\n AddPurpose.prototype.contextId = 0;\n\n /**\n * @var {Promise}\n * @private\n */\n AddPurpose.prototype.strings = 0;\n\n AddPurpose.prototype.registerEventListeners = function() {\n\n var trigger = $(SELECTORS.PURPOSE_LINK);\n trigger.on('click', function() {\n return this.strings.then(function(strings) {\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: strings[0],\n body: '',\n }, trigger).done(function(modal) {\n this.setupFormModal(modal, strings[1]);\n }.bind(this));\n }.bind(this))\n .fail(Notification.exception);\n }.bind(this));\n\n };\n\n /**\n * @method getBody\n * @param {Object} formdata\n * @private\n * @return {Promise}\n */\n AddPurpose.prototype.getBody = function(formdata) {\n\n var params = null;\n if (typeof formdata !== \"undefined\") {\n params = {jsonformdata: JSON.stringify(formdata)};\n }\n // Get the content of the modal.\n return Fragment.loadFragment('tool_dataprivacy', 'addpurpose_form', this.contextId, params);\n };\n\n AddPurpose.prototype.setupFormModal = function(modal, saveText) {\n modal.setLarge();\n\n modal.setSaveButtonText(saveText);\n\n // We want to reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));\n\n modal.setBody(this.getBody());\n\n // We catch the modal save event, and use it to submit the form inside the modal.\n // Triggering a form submission will give JS validation scripts a chance to check for errors.\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n // We also catch the form submit event and use it to submit the form with ajax.\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n this.modal = modal;\n\n modal.show();\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n AddPurpose.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n AddPurpose.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = this.modal.getRoot().find('form').serialize();\n\n Ajax.call([{\n methodname: 'tool_dataprivacy_create_purpose_form',\n args: {jsonformdata: JSON.stringify(formData)},\n done: function(data) {\n if (data.validationerrors) {\n this.modal.setBody(this.getBody(formData));\n } else {\n this.close();\n }\n }.bind(this),\n\n fail: Notification.exception\n }]);\n };\n\n AddPurpose.prototype.close = function() {\n this.destroy();\n document.location.reload();\n };\n\n AddPurpose.prototype.destroy = function() {\n FormChangeChecker.resetAllFormDirtyStates();\n this.modal.destroy();\n };\n\n AddPurpose.prototype.removeListeners = function() {\n $(SELECTORS.PURPOSE_LINK).off('click');\n };\n\n return /** @alias module:tool_dataprivacy/add_purpose */ {\n getInstance: function(contextId) {\n return new AddPurpose(contextId);\n }\n };\n }\n);\n\n"],"file":"add_purpose.min.js"}
\ No newline at end of file
diff --git a/admin/tool/dataprivacy/amd/build/data_registry.min.js b/admin/tool/dataprivacy/amd/build/data_registry.min.js
index 85868edb04a..44c2310075f 100644
--- a/admin/tool/dataprivacy/amd/build/data_registry.min.js
+++ b/admin/tool/dataprivacy/amd/build/data_registry.min.js
@@ -1,2 +1,2 @@
-define ("tool_dataprivacy/data_registry",["jquery","core/str","core/ajax","core/notification","core/templates","core/modal_factory","core/modal_events","core/fragment","tool_dataprivacy/add_purpose","tool_dataprivacy/add_category"],function(a,b,c,d,e,f,g,h,i,j){var k={TREE_NODES:"[data-context-tree-node=1]",FORM_CONTAINER:"#context-form-container"},l=function(a,b,c){this.systemContextId=a;this.currentContextLevel=b;this.currentContextId=c;this.init()};l.prototype.systemContextId=0;l.prototype.currentContextLevel=0;l.prototype.currentContextId=0;l.prototype.addpurpose=null;l.prototype.addcategory=null;l.prototype.init=function(){this.addpurpose=i.getInstance(this.systemContextId);this.addcategory=j.getInstance(this.systemContextId);this.strings=b.get_strings([{key:"changessaved",component:"moodle"},{key:"contextpurposecategorysaved",component:"tool_dataprivacy"},{key:"noblockstoload",component:"tool_dataprivacy"},{key:"noactivitiestoload",component:"tool_dataprivacy"},{key:"nocoursestoload",component:"tool_dataprivacy"}]);this.registerEventListeners();if(this.currentContextId){this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}};l.prototype.registerEventListeners=function(){a(k.TREE_NODES).on("click",function(b){b.preventDefault();var c=a(b.currentTarget);a(k.TREE_NODES).removeClass("active");c.addClass("active");var d=c.data("contextlevel"),e=c.data("contextid");if(d){window.history.pushState({},null,"?contextlevel="+d);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextLevel=d;this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}else if(e){window.history.pushState({},null,"?contextid="+e);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextId=e;this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{var f=c.data("expandcontextid"),g=c.data("expandelement"),h=c.data("expanded");if(g){if(!h){if(c.data("loaded")||!f||!g){this.expand(c)}else{c.find("> i").removeClass("fa-plus");c.find("> i").addClass("fa-circle-o-notch fa-spin");this.loadExtra(c,f,g)}}else{this.collapse(c)}}}}.bind(this))};l.prototype.removeListeners=function(){a(k.TREE_NODES).off("click")};l.prototype.loadForm=function(b,c,f){this.clearForm();var g=h.loadFragment("tool_dataprivacy",b,this.systemContextId,c);g.done(function(b,c){a(k.FORM_CONTAINER).html(b);e.runTemplateJS(c);this.addpurpose.registerEventListeners();this.addcategory.registerEventListeners();a(k.FORM_CONTAINER).on("submit","form",f)}.bind(this)).fail(d.exception)};l.prototype.clearForm=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});a(k.FORM_CONTAINER).off("submit","form")};l.prototype.submitForm=function(b){b.preventDefault();a(k.FORM_CONTAINER).find("form").submit()};l.prototype.submitContextLevelFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_contextlevel_form")};l.prototype.submitContextFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_context_form")};l.prototype.submitFormAjax=function(b,e){b.preventDefault();var f=a(k.FORM_CONTAINER).find("form").serialize();return this.strings.then(function(a){c.call([{methodname:e,args:{jsonformdata:JSON.stringify(f)},done:function done(){d.alert(a[0],a[1])},fail:d.exception}])}).catch(d.exception)};l.prototype.loadExtra=function(a,b,f){c.call([{methodname:"tool_dataprivacy_tree_extra_branches",args:{contextid:b,element:f},done:function(b){if(0==b.branches.length){this.noElements(a,f);return}e.render("tool_dataprivacy/context_tree_branches",b).then(function(b){a.after(b);this.removeListeners();this.registerEventListeners();this.expand(a);a.data("loaded",1)}.bind(this)).fail(d.exception)}.bind(this),fail:d.exception}])};l.prototype.noElements=function(a,b){a.data("expandcontextid","");a.data("expandelement","");this.strings.then(function(c){var d=2;if("module"==b){d=3}else if("course"==b){d=4}a.text(c[d])}).fail(d.exception)};l.prototype.collapse=function(a){a.data("expanded",0);a.siblings("nav").addClass("hidden");a.find("> i").removeClass("fa-minus");a.find("> i").addClass("fa-plus")};l.prototype.expand=function(a){a.data("expanded",1);a.siblings("nav").removeClass("hidden");a.find("> i").removeClass("fa-plus");a.find("> i").removeClass("fa-circle-o-notch fa-spin");a.find("> i").addClass("fa-minus")};return{init:function init(a,b,c){return new l(a,b,c)}}});
+define ("tool_dataprivacy/data_registry",["jquery","core/str","core/ajax","core/notification","core/templates","core/modal_factory","core/modal_events","core/fragment","tool_dataprivacy/add_purpose","tool_dataprivacy/add_category"],function(a,b,c,d,e,f,g,h,i,j){var k={TREE_NODES:"[data-context-tree-node=1]",FORM_CONTAINER:"#context-form-container"},l=function(a,b,c){this.systemContextId=a;this.currentContextLevel=b;this.currentContextId=c;this.init()};l.prototype.systemContextId=0;l.prototype.currentContextLevel=0;l.prototype.currentContextId=0;l.prototype.addpurpose=null;l.prototype.addcategory=null;l.prototype.init=function(){this.addpurpose=i.getInstance(this.systemContextId);this.addcategory=j.getInstance(this.systemContextId);this.strings=b.get_strings([{key:"changessaved",component:"moodle"},{key:"contextpurposecategorysaved",component:"tool_dataprivacy"},{key:"noblockstoload",component:"tool_dataprivacy"},{key:"noactivitiestoload",component:"tool_dataprivacy"},{key:"nocoursestoload",component:"tool_dataprivacy"}]);this.registerEventListeners();if(this.currentContextId){this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}};l.prototype.registerEventListeners=function(){a(k.TREE_NODES).on("click",function(b){b.preventDefault();var c=a(b.currentTarget);a(k.TREE_NODES).removeClass("active");c.addClass("active");var d=c.data("contextlevel"),e=c.data("contextid");if(d){window.history.pushState({},null,"?contextlevel="+d);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextLevel=d;this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}else if(e){window.history.pushState({},null,"?contextid="+e);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextId=e;this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{var f=c.data("expandcontextid"),g=c.data("expandelement"),h=c.data("expanded");if(g){if(!h){if(c.data("loaded")||!f||!g){this.expand(c)}else{c.find("> i").removeClass("fa-plus");c.find("> i").addClass("fa-circle-o-notch fa-spin");this.loadExtra(c,f,g)}}else{this.collapse(c)}}}}.bind(this))};l.prototype.removeListeners=function(){a(k.TREE_NODES).off("click")};l.prototype.loadForm=function(b,c,f){this.clearForm();var g=h.loadFragment("tool_dataprivacy",b,this.systemContextId,c);g.done(function(b,c){a(k.FORM_CONTAINER).html(b);e.runTemplateJS(c);this.addpurpose.registerEventListeners();this.addcategory.registerEventListeners();a(k.FORM_CONTAINER).on("submit","form",f)}.bind(this)).fail(d.exception)};l.prototype.clearForm=function(){a(k.FORM_CONTAINER).off("submit","form")};l.prototype.submitForm=function(b){b.preventDefault();a(k.FORM_CONTAINER).find("form").submit()};l.prototype.submitContextLevelFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_contextlevel_form")};l.prototype.submitContextFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_context_form")};l.prototype.submitFormAjax=function(b,e){b.preventDefault();var f=a(k.FORM_CONTAINER).find("form").serialize();return this.strings.then(function(a){c.call([{methodname:e,args:{jsonformdata:JSON.stringify(f)},done:function done(){d.alert(a[0],a[1])},fail:d.exception}])}).catch(d.exception)};l.prototype.loadExtra=function(a,b,f){c.call([{methodname:"tool_dataprivacy_tree_extra_branches",args:{contextid:b,element:f},done:function(b){if(0==b.branches.length){this.noElements(a,f);return}e.render("tool_dataprivacy/context_tree_branches",b).then(function(b){a.after(b);this.removeListeners();this.registerEventListeners();this.expand(a);a.data("loaded",1)}.bind(this)).fail(d.exception)}.bind(this),fail:d.exception}])};l.prototype.noElements=function(a,b){a.data("expandcontextid","");a.data("expandelement","");this.strings.then(function(c){var d=2;if("module"==b){d=3}else if("course"==b){d=4}a.text(c[d])}).fail(d.exception)};l.prototype.collapse=function(a){a.data("expanded",0);a.siblings("nav").addClass("hidden");a.find("> i").removeClass("fa-minus");a.find("> i").addClass("fa-plus")};l.prototype.expand=function(a){a.data("expanded",1);a.siblings("nav").removeClass("hidden");a.find("> i").removeClass("fa-plus");a.find("> i").removeClass("fa-circle-o-notch fa-spin");a.find("> i").addClass("fa-minus")};return{init:function init(a,b,c){return new l(a,b,c)}}});
//# sourceMappingURL=data_registry.min.js.map
diff --git a/admin/tool/dataprivacy/amd/build/data_registry.min.js.map b/admin/tool/dataprivacy/amd/build/data_registry.min.js.map
index b7c8d8f895c..02e3bb008c7 100644
--- a/admin/tool/dataprivacy/amd/build/data_registry.min.js.map
+++ b/admin/tool/dataprivacy/amd/build/data_registry.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/data_registry.js"],"names":["define","$","Str","Ajax","Notification","Templates","ModalFactory","ModalEvents","Fragment","AddPurpose","AddCategory","SELECTORS","TREE_NODES","FORM_CONTAINER","DataRegistry","systemContextId","initContextLevel","initContextId","currentContextLevel","currentContextId","init","prototype","addpurpose","addcategory","getInstance","strings","get_strings","key","component","registerEventListeners","loadForm","submitContextFormAjax","bind","submitContextLevelFormAjax","on","ev","preventDefault","trigger","currentTarget","removeClass","addClass","contextLevel","data","contextId","window","history","pushState","removeListeners","expandContextId","expandElement","expanded","expand","find","loadExtra","collapse","off","fragmentName","fragmentArgs","formSubmitCallback","clearForm","fragment","loadFragment","done","html","js","runTemplateJS","fail","exception","Y","use","M","core_formchangechecker","reset_form_dirty_state","submitForm","e","submit","submitFormAjax","saveMethodName","formData","serialize","then","call","methodname","args","jsonformdata","JSON","stringify","alert","catch","parentNode","contextid","element","branches","length","noElements","render","after","node","text","siblings"],"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 * Request actions.\n *\n * @module tool_dataprivacy/data_registry\n * @copyright 2018 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/templates', 'core/modal_factory',\n 'core/modal_events', 'core/fragment', 'tool_dataprivacy/add_purpose', 'tool_dataprivacy/add_category'],\n function($, Str, Ajax, Notification, Templates, ModalFactory, ModalEvents, Fragment, AddPurpose, AddCategory) {\n\n var SELECTORS = {\n TREE_NODES: '[data-context-tree-node=1]',\n FORM_CONTAINER: '#context-form-container',\n };\n\n var DataRegistry = function(systemContextId, initContextLevel, initContextId) {\n this.systemContextId = systemContextId;\n this.currentContextLevel = initContextLevel;\n this.currentContextId = initContextId;\n this.init();\n };\n\n /**\n * @var {int} systemContextId\n * @private\n */\n DataRegistry.prototype.systemContextId = 0;\n\n /**\n * @var {int} currentContextLevel\n * @private\n */\n DataRegistry.prototype.currentContextLevel = 0;\n\n /**\n * @var {int} currentContextId\n * @private\n */\n DataRegistry.prototype.currentContextId = 0;\n\n /**\n * @var {AddPurpose} addpurpose\n * @private\n */\n DataRegistry.prototype.addpurpose = null;\n\n /**\n * @var {AddCategory} addcategory\n * @private\n */\n DataRegistry.prototype.addcategory = null;\n\n DataRegistry.prototype.init = function() {\n // Add purpose and category modals always at system context.\n this.addpurpose = AddPurpose.getInstance(this.systemContextId);\n this.addcategory = AddCategory.getInstance(this.systemContextId);\n\n var stringKeys = [\n {\n key: 'changessaved',\n component: 'moodle'\n }, {\n key: 'contextpurposecategorysaved',\n component: 'tool_dataprivacy'\n }, {\n key: 'noblockstoload',\n component: 'tool_dataprivacy'\n }, {\n key: 'noactivitiestoload',\n component: 'tool_dataprivacy'\n }, {\n key: 'nocoursestoload',\n component: 'tool_dataprivacy'\n }\n ];\n this.strings = Str.get_strings(stringKeys);\n\n this.registerEventListeners();\n\n // Load the default context level form.\n if (this.currentContextId) {\n this.loadForm('context_form', [this.currentContextId], this.submitContextFormAjax.bind(this));\n } else {\n this.loadForm('contextlevel_form', [this.currentContextLevel], this.submitContextLevelFormAjax.bind(this));\n }\n };\n\n DataRegistry.prototype.registerEventListeners = function() {\n $(SELECTORS.TREE_NODES).on('click', function(ev) {\n ev.preventDefault();\n\n var trigger = $(ev.currentTarget);\n\n // Active node.\n $(SELECTORS.TREE_NODES).removeClass('active');\n trigger.addClass('active');\n\n var contextLevel = trigger.data('contextlevel');\n var contextId = trigger.data('contextid');\n if (contextLevel) {\n // Context level level.\n\n window.history.pushState({}, null, '?contextlevel=' + contextLevel);\n\n // Remove previous add purpose and category listeners to avoid memory leaks.\n this.addpurpose.removeListeners();\n this.addcategory.removeListeners();\n\n // Load the context level form.\n this.currentContextLevel = contextLevel;\n this.loadForm('contextlevel_form', [this.currentContextLevel], this.submitContextLevelFormAjax.bind(this));\n } else if (contextId) {\n // Context instance level.\n\n window.history.pushState({}, null, '?contextid=' + contextId);\n\n // Remove previous add purpose and category listeners to avoid memory leaks.\n this.addpurpose.removeListeners();\n this.addcategory.removeListeners();\n\n // Load the context level form.\n this.currentContextId = contextId;\n this.loadForm('context_form', [this.currentContextId], this.submitContextFormAjax.bind(this));\n } else {\n // Expandable nodes.\n\n var expandContextId = trigger.data('expandcontextid');\n var expandElement = trigger.data('expandelement');\n var expanded = trigger.data('expanded');\n\n // Extra checking that there is an expandElement because we remove it after loading 0 branches.\n if (expandElement) {\n\n if (!expanded) {\n if (trigger.data('loaded') || !expandContextId || !expandElement) {\n this.expand(trigger);\n } else {\n\n trigger.find('> i').removeClass('fa-plus');\n trigger.find('> i').addClass('fa-circle-o-notch fa-spin');\n this.loadExtra(trigger, expandContextId, expandElement);\n }\n } else {\n this.collapse(trigger);\n }\n }\n }\n\n }.bind(this));\n };\n\n DataRegistry.prototype.removeListeners = function() {\n $(SELECTORS.TREE_NODES).off('click');\n };\n\n DataRegistry.prototype.loadForm = function(fragmentName, fragmentArgs, formSubmitCallback) {\n\n this.clearForm();\n\n var fragment = Fragment.loadFragment('tool_dataprivacy', fragmentName, this.systemContextId, fragmentArgs);\n fragment.done(function(html, js) {\n\n $(SELECTORS.FORM_CONTAINER).html(html);\n Templates.runTemplateJS(js);\n\n this.addpurpose.registerEventListeners();\n this.addcategory.registerEventListeners();\n\n // We also catch the form submit event and use it to submit the form with ajax.\n $(SELECTORS.FORM_CONTAINER).on('submit', 'form', formSubmitCallback);\n\n }.bind(this)).fail(Notification.exception);\n };\n\n DataRegistry.prototype.clearForm = function() {\n // For the previously loaded form.\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n\n // Remove previous listeners.\n $(SELECTORS.FORM_CONTAINER).off('submit', 'form');\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n DataRegistry.prototype.submitForm = function(e) {\n e.preventDefault();\n $(SELECTORS.FORM_CONTAINER).find('form').submit();\n };\n\n DataRegistry.prototype.submitContextLevelFormAjax = function(e) {\n this.submitFormAjax(e, 'tool_dataprivacy_set_contextlevel_form');\n };\n\n DataRegistry.prototype.submitContextFormAjax = function(e) {\n this.submitFormAjax(e, 'tool_dataprivacy_set_context_form');\n };\n\n DataRegistry.prototype.submitFormAjax = function(e, saveMethodName) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = $(SELECTORS.FORM_CONTAINER).find('form').serialize();\n return this.strings.then(function(strings) {\n Ajax.call([{\n methodname: saveMethodName,\n args: {jsonformdata: JSON.stringify(formData)},\n done: function() {\n Notification.alert(strings[0], strings[1]);\n },\n fail: Notification.exception\n }]);\n return;\n }).catch(Notification.exception);\n\n };\n\n DataRegistry.prototype.loadExtra = function(parentNode, expandContextId, expandElement) {\n\n Ajax.call([{\n methodname: 'tool_dataprivacy_tree_extra_branches',\n args: {\n contextid: expandContextId,\n element: expandElement,\n },\n done: function(data) {\n if (data.branches.length == 0) {\n this.noElements(parentNode, expandElement);\n return;\n }\n Templates.render('tool_dataprivacy/context_tree_branches', data)\n .then(function(html) {\n parentNode.after(html);\n this.removeListeners();\n this.registerEventListeners();\n this.expand(parentNode);\n parentNode.data('loaded', 1);\n return;\n }.bind(this))\n .fail(Notification.exception);\n }.bind(this),\n fail: Notification.exception\n }]);\n };\n\n DataRegistry.prototype.noElements = function(node, expandElement) {\n node.data('expandcontextid', '');\n node.data('expandelement', '');\n this.strings.then(function(strings) {\n\n // 2 = blocks, 3 = activities, 4 = courses (although courses is not likely really).\n var key = 2;\n if (expandElement == 'module') {\n key = 3;\n } else if (expandElement == 'course') {\n key = 4;\n }\n node.text(strings[key]);\n return;\n }).fail(Notification.exception);\n };\n\n DataRegistry.prototype.collapse = function(node) {\n node.data('expanded', 0);\n node.siblings('nav').addClass('hidden');\n node.find('> i').removeClass('fa-minus');\n node.find('> i').addClass('fa-plus');\n };\n\n DataRegistry.prototype.expand = function(node) {\n node.data('expanded', 1);\n node.siblings('nav').removeClass('hidden');\n node.find('> i').removeClass('fa-plus');\n // Also remove the spinning one if data was just loaded.\n node.find('> i').removeClass('fa-circle-o-notch fa-spin');\n node.find('> i').addClass('fa-minus');\n };\n return /** @alias module:tool_dataprivacy/data_registry */ {\n\n /**\n * Initialise the page.\n *\n * @param {Number} systemContextId\n * @param {Number} initContextLevel\n * @param {Number} initContextId\n * @return {DataRegistry}\n */\n init: function(systemContextId, initContextLevel, initContextId) {\n return new DataRegistry(systemContextId, initContextLevel, initContextId);\n }\n };\n }\n);\n\n"],"file":"data_registry.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/data_registry.js"],"names":["define","$","Str","Ajax","Notification","Templates","ModalFactory","ModalEvents","Fragment","AddPurpose","AddCategory","SELECTORS","TREE_NODES","FORM_CONTAINER","DataRegistry","systemContextId","initContextLevel","initContextId","currentContextLevel","currentContextId","init","prototype","addpurpose","addcategory","getInstance","strings","get_strings","key","component","registerEventListeners","loadForm","submitContextFormAjax","bind","submitContextLevelFormAjax","on","ev","preventDefault","trigger","currentTarget","removeClass","addClass","contextLevel","data","contextId","window","history","pushState","removeListeners","expandContextId","expandElement","expanded","expand","find","loadExtra","collapse","off","fragmentName","fragmentArgs","formSubmitCallback","clearForm","fragment","loadFragment","done","html","js","runTemplateJS","fail","exception","submitForm","e","submit","submitFormAjax","saveMethodName","formData","serialize","then","call","methodname","args","jsonformdata","JSON","stringify","alert","catch","parentNode","contextid","element","branches","length","noElements","render","after","node","text","siblings"],"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 * Request actions.\n *\n * @module tool_dataprivacy/data_registry\n * @copyright 2018 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/templates', 'core/modal_factory',\n 'core/modal_events', 'core/fragment', 'tool_dataprivacy/add_purpose', 'tool_dataprivacy/add_category'],\n function($, Str, Ajax, Notification, Templates, ModalFactory, ModalEvents, Fragment, AddPurpose, AddCategory) {\n\n var SELECTORS = {\n TREE_NODES: '[data-context-tree-node=1]',\n FORM_CONTAINER: '#context-form-container',\n };\n\n var DataRegistry = function(systemContextId, initContextLevel, initContextId) {\n this.systemContextId = systemContextId;\n this.currentContextLevel = initContextLevel;\n this.currentContextId = initContextId;\n this.init();\n };\n\n /**\n * @var {int} systemContextId\n * @private\n */\n DataRegistry.prototype.systemContextId = 0;\n\n /**\n * @var {int} currentContextLevel\n * @private\n */\n DataRegistry.prototype.currentContextLevel = 0;\n\n /**\n * @var {int} currentContextId\n * @private\n */\n DataRegistry.prototype.currentContextId = 0;\n\n /**\n * @var {AddPurpose} addpurpose\n * @private\n */\n DataRegistry.prototype.addpurpose = null;\n\n /**\n * @var {AddCategory} addcategory\n * @private\n */\n DataRegistry.prototype.addcategory = null;\n\n DataRegistry.prototype.init = function() {\n // Add purpose and category modals always at system context.\n this.addpurpose = AddPurpose.getInstance(this.systemContextId);\n this.addcategory = AddCategory.getInstance(this.systemContextId);\n\n var stringKeys = [\n {\n key: 'changessaved',\n component: 'moodle'\n }, {\n key: 'contextpurposecategorysaved',\n component: 'tool_dataprivacy'\n }, {\n key: 'noblockstoload',\n component: 'tool_dataprivacy'\n }, {\n key: 'noactivitiestoload',\n component: 'tool_dataprivacy'\n }, {\n key: 'nocoursestoload',\n component: 'tool_dataprivacy'\n }\n ];\n this.strings = Str.get_strings(stringKeys);\n\n this.registerEventListeners();\n\n // Load the default context level form.\n if (this.currentContextId) {\n this.loadForm('context_form', [this.currentContextId], this.submitContextFormAjax.bind(this));\n } else {\n this.loadForm('contextlevel_form', [this.currentContextLevel], this.submitContextLevelFormAjax.bind(this));\n }\n };\n\n DataRegistry.prototype.registerEventListeners = function() {\n $(SELECTORS.TREE_NODES).on('click', function(ev) {\n ev.preventDefault();\n\n var trigger = $(ev.currentTarget);\n\n // Active node.\n $(SELECTORS.TREE_NODES).removeClass('active');\n trigger.addClass('active');\n\n var contextLevel = trigger.data('contextlevel');\n var contextId = trigger.data('contextid');\n if (contextLevel) {\n // Context level level.\n\n window.history.pushState({}, null, '?contextlevel=' + contextLevel);\n\n // Remove previous add purpose and category listeners to avoid memory leaks.\n this.addpurpose.removeListeners();\n this.addcategory.removeListeners();\n\n // Load the context level form.\n this.currentContextLevel = contextLevel;\n this.loadForm('contextlevel_form', [this.currentContextLevel], this.submitContextLevelFormAjax.bind(this));\n } else if (contextId) {\n // Context instance level.\n\n window.history.pushState({}, null, '?contextid=' + contextId);\n\n // Remove previous add purpose and category listeners to avoid memory leaks.\n this.addpurpose.removeListeners();\n this.addcategory.removeListeners();\n\n // Load the context level form.\n this.currentContextId = contextId;\n this.loadForm('context_form', [this.currentContextId], this.submitContextFormAjax.bind(this));\n } else {\n // Expandable nodes.\n\n var expandContextId = trigger.data('expandcontextid');\n var expandElement = trigger.data('expandelement');\n var expanded = trigger.data('expanded');\n\n // Extra checking that there is an expandElement because we remove it after loading 0 branches.\n if (expandElement) {\n\n if (!expanded) {\n if (trigger.data('loaded') || !expandContextId || !expandElement) {\n this.expand(trigger);\n } else {\n\n trigger.find('> i').removeClass('fa-plus');\n trigger.find('> i').addClass('fa-circle-o-notch fa-spin');\n this.loadExtra(trigger, expandContextId, expandElement);\n }\n } else {\n this.collapse(trigger);\n }\n }\n }\n\n }.bind(this));\n };\n\n DataRegistry.prototype.removeListeners = function() {\n $(SELECTORS.TREE_NODES).off('click');\n };\n\n DataRegistry.prototype.loadForm = function(fragmentName, fragmentArgs, formSubmitCallback) {\n\n this.clearForm();\n\n var fragment = Fragment.loadFragment('tool_dataprivacy', fragmentName, this.systemContextId, fragmentArgs);\n fragment.done(function(html, js) {\n\n $(SELECTORS.FORM_CONTAINER).html(html);\n Templates.runTemplateJS(js);\n\n this.addpurpose.registerEventListeners();\n this.addcategory.registerEventListeners();\n\n // We also catch the form submit event and use it to submit the form with ajax.\n $(SELECTORS.FORM_CONTAINER).on('submit', 'form', formSubmitCallback);\n\n }.bind(this)).fail(Notification.exception);\n };\n\n DataRegistry.prototype.clearForm = function() {\n // Remove previous listeners.\n $(SELECTORS.FORM_CONTAINER).off('submit', 'form');\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n DataRegistry.prototype.submitForm = function(e) {\n e.preventDefault();\n $(SELECTORS.FORM_CONTAINER).find('form').submit();\n };\n\n DataRegistry.prototype.submitContextLevelFormAjax = function(e) {\n this.submitFormAjax(e, 'tool_dataprivacy_set_contextlevel_form');\n };\n\n DataRegistry.prototype.submitContextFormAjax = function(e) {\n this.submitFormAjax(e, 'tool_dataprivacy_set_context_form');\n };\n\n DataRegistry.prototype.submitFormAjax = function(e, saveMethodName) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = $(SELECTORS.FORM_CONTAINER).find('form').serialize();\n return this.strings.then(function(strings) {\n Ajax.call([{\n methodname: saveMethodName,\n args: {jsonformdata: JSON.stringify(formData)},\n done: function() {\n Notification.alert(strings[0], strings[1]);\n },\n fail: Notification.exception\n }]);\n return;\n }).catch(Notification.exception);\n\n };\n\n DataRegistry.prototype.loadExtra = function(parentNode, expandContextId, expandElement) {\n\n Ajax.call([{\n methodname: 'tool_dataprivacy_tree_extra_branches',\n args: {\n contextid: expandContextId,\n element: expandElement,\n },\n done: function(data) {\n if (data.branches.length == 0) {\n this.noElements(parentNode, expandElement);\n return;\n }\n Templates.render('tool_dataprivacy/context_tree_branches', data)\n .then(function(html) {\n parentNode.after(html);\n this.removeListeners();\n this.registerEventListeners();\n this.expand(parentNode);\n parentNode.data('loaded', 1);\n return;\n }.bind(this))\n .fail(Notification.exception);\n }.bind(this),\n fail: Notification.exception\n }]);\n };\n\n DataRegistry.prototype.noElements = function(node, expandElement) {\n node.data('expandcontextid', '');\n node.data('expandelement', '');\n this.strings.then(function(strings) {\n\n // 2 = blocks, 3 = activities, 4 = courses (although courses is not likely really).\n var key = 2;\n if (expandElement == 'module') {\n key = 3;\n } else if (expandElement == 'course') {\n key = 4;\n }\n node.text(strings[key]);\n return;\n }).fail(Notification.exception);\n };\n\n DataRegistry.prototype.collapse = function(node) {\n node.data('expanded', 0);\n node.siblings('nav').addClass('hidden');\n node.find('> i').removeClass('fa-minus');\n node.find('> i').addClass('fa-plus');\n };\n\n DataRegistry.prototype.expand = function(node) {\n node.data('expanded', 1);\n node.siblings('nav').removeClass('hidden');\n node.find('> i').removeClass('fa-plus');\n // Also remove the spinning one if data was just loaded.\n node.find('> i').removeClass('fa-circle-o-notch fa-spin');\n node.find('> i').addClass('fa-minus');\n };\n return /** @alias module:tool_dataprivacy/data_registry */ {\n\n /**\n * Initialise the page.\n *\n * @param {Number} systemContextId\n * @param {Number} initContextLevel\n * @param {Number} initContextId\n * @return {DataRegistry}\n */\n init: function(systemContextId, initContextLevel, initContextId) {\n return new DataRegistry(systemContextId, initContextLevel, initContextId);\n }\n };\n }\n);\n\n"],"file":"data_registry.min.js"}
\ No newline at end of file
diff --git a/admin/tool/dataprivacy/amd/src/add_category.js b/admin/tool/dataprivacy/amd/src/add_category.js
index 75bf7701f77..469b52e8a61 100644
--- a/admin/tool/dataprivacy/amd/src/add_category.js
+++ b/admin/tool/dataprivacy/amd/src/add_category.js
@@ -20,8 +20,25 @@
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],
- function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {
+define([
+ 'jquery',
+ 'core/str',
+ 'core/ajax',
+ 'core/notification',
+ 'core/modal_factory',
+ 'core/modal_events',
+ 'core/fragment',
+ 'core_form/changechecker',
+], function(
+ $,
+ Str,
+ Ajax,
+ Notification,
+ ModalFactory,
+ ModalEvents,
+ Fragment,
+ FormChangeChecker
+) {
var SELECTORS = {
CATEGORY_LINK: '[data-add-element="category"]',
@@ -151,9 +168,7 @@ define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_fact
};
AddCategory.prototype.destroy = function() {
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ FormChangeChecker.resetAllFormDirtyStates();
this.modal.destroy();
};
diff --git a/admin/tool/dataprivacy/amd/src/add_purpose.js b/admin/tool/dataprivacy/amd/src/add_purpose.js
index 9567cc5d6cf..bf10868c8a2 100644
--- a/admin/tool/dataprivacy/amd/src/add_purpose.js
+++ b/admin/tool/dataprivacy/amd/src/add_purpose.js
@@ -20,8 +20,25 @@
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],
- function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {
+define([
+ 'jquery',
+ 'core/str',
+ 'core/ajax',
+ 'core/notification',
+ 'core/modal_factory',
+ 'core/modal_events',
+ 'core/fragment',
+ 'core_form/changechecker',
+], function(
+ $,
+ Str,
+ Ajax,
+ Notification,
+ ModalFactory,
+ ModalEvents,
+ Fragment,
+ FormChangeChecker
+) {
var SELECTORS = {
PURPOSE_LINK: '[data-add-element="purpose"]',
@@ -152,9 +169,7 @@ define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_fact
};
AddPurpose.prototype.destroy = function() {
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ FormChangeChecker.resetAllFormDirtyStates();
this.modal.destroy();
};
diff --git a/admin/tool/dataprivacy/amd/src/data_registry.js b/admin/tool/dataprivacy/amd/src/data_registry.js
index c149f128c44..5f21baddb0a 100644
--- a/admin/tool/dataprivacy/amd/src/data_registry.js
+++ b/admin/tool/dataprivacy/amd/src/data_registry.js
@@ -189,11 +189,6 @@ define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/templates'
};
DataRegistry.prototype.clearForm = function() {
- // For the previously loaded form.
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
-
// Remove previous listeners.
$(SELECTORS.FORM_CONTAINER).off('submit', 'form');
};
diff --git a/admin/tool/policy/amd/build/acceptmodal.min.js b/admin/tool/policy/amd/build/acceptmodal.min.js
index 0caa34f0e90..b1c6edfaeb7 100644
--- a/admin/tool/policy/amd/build/acceptmodal.min.js
+++ b/admin/tool/policy/amd/build/acceptmodal.min.js
@@ -1,2 +1,2 @@
-define ("tool_policy/acceptmodal",["jquery","core/str","core/modal_factory","core/modal_events","core/notification","core/fragment","core/ajax","core/yui"],function(a,b,c,d,f,g,h,i){"use strict";var e=function(a){this.contextid=a;this.init()};e.prototype.modal=null;e.prototype.contextid=-1;e.prototype.currentTrigger=null;e.prototype.triggers={SINGLE:"a[data-action=acceptmodal]",BULK:"input[data-action=acceptmodal]"};e.prototype.init=function(){a(this.triggers.SINGLE).on("click",function(b){b.preventDefault();this.currentTrigger=a(b.currentTarget);var c=a(b.currentTarget).attr("href"),d=c.slice(c.indexOf("?")+1);this.showFormModal(d)}.bind(this));a(this.triggers.BULK).on("click",function(c){c.preventDefault();this.currentTrigger=a(c.currentTarget);var d=a(c.currentTarget).closest("form");if(d.find("input[type=checkbox][name=\"userids[]\"]:checked").length){var e=d.serialize();this.showFormModal(e)}else{b.get_strings([{key:"notice"},{key:"selectusersforconsent",component:"tool_policy"},{key:"ok"}]).then(function(a){f.alert(a[0],a[1],a[2])}).fail(f.exception)}}.bind(this))};e.prototype.showFormModal=function(a){for(var d,e=a.split("&"),g=0,h;g .\n\n/**\n * Add policy consent modal to the page\n *\n * @module tool_policy/acceptmodal\n * @copyright 2018 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/notification', 'core/fragment',\n 'core/ajax', 'core/yui'],\n function($, Str, ModalFactory, ModalEvents, Notification, Fragment, Ajax, Y) {\n\n \"use strict\";\n\n /**\n * Constructor\n *\n * @param {int} contextid\n *\n * Each call to init gets it's own instance of this class.\n */\n var AcceptOnBehalf = function(contextid) {\n this.contextid = contextid;\n this.init();\n };\n\n /**\n * @var {Modal} modal\n * @private\n */\n AcceptOnBehalf.prototype.modal = null;\n\n /**\n * @var {int} contextid\n * @private\n */\n AcceptOnBehalf.prototype.contextid = -1;\n\n /**\n * @var {object} currentTrigger The triggered HTML jQuery object\n * @private\n */\n AcceptOnBehalf.prototype.currentTrigger = null;\n\n /**\n * @var {object} triggers The trigger selectors\n * @private\n */\n AcceptOnBehalf.prototype.triggers = {\n SINGLE: 'a[data-action=acceptmodal]',\n BULK: 'input[data-action=acceptmodal]'\n };\n\n /**\n * Initialise the class.\n *\n * @private\n */\n AcceptOnBehalf.prototype.init = function() {\n // Initialise for links accepting policies for individual users.\n $(this.triggers.SINGLE).on('click', function(e) {\n e.preventDefault();\n this.currentTrigger = $(e.currentTarget);\n var href = $(e.currentTarget).attr('href'),\n formData = href.slice(href.indexOf('?') + 1);\n this.showFormModal(formData);\n }.bind(this));\n\n // Initialise for multiple users acceptance form.\n $(this.triggers.BULK).on('click', function(e) {\n e.preventDefault();\n this.currentTrigger = $(e.currentTarget);\n var form = $(e.currentTarget).closest('form');\n if (form.find('input[type=checkbox][name=\"userids[]\"]:checked').length) {\n var formData = form.serialize();\n this.showFormModal(formData);\n } else {\n Str.get_strings([\n {key: 'notice'},\n {key: 'selectusersforconsent', component: 'tool_policy'},\n {key: 'ok'}\n ]).then(function(strings) {\n Notification.alert(strings[0], strings[1], strings[2]);\n return;\n }).fail(Notification.exception);\n }\n }.bind(this));\n };\n\n /**\n * Show modal with a form\n *\n * @param {String} formData\n */\n AcceptOnBehalf.prototype.showFormModal = function(formData) {\n var action;\n var params = formData.split('&');\n for (var i = 0; i < params.length; i++) {\n var pair = params[i].split('=');\n if (pair[0] == 'action') {\n action = pair[1];\n }\n }\n // Fetch the title string.\n Str.get_strings([\n {key: 'statusformtitleaccept', component: 'tool_policy'},\n {key: 'iagreetothepolicy', component: 'tool_policy'},\n {key: 'statusformtitlerevoke', component: 'tool_policy'},\n {key: 'irevokethepolicy', component: 'tool_policy'},\n {key: 'statusformtitledecline', component: 'tool_policy'},\n {key: 'declinethepolicy', component: 'tool_policy'}\n ]).then(function(strings) {\n var title;\n var saveText;\n if (action == 'accept') {\n title = strings[0];\n saveText = strings[1];\n } else if (action == 'revoke') {\n title = strings[2];\n saveText = strings[3];\n } else if (action == 'decline') {\n title = strings[4];\n saveText = strings[5];\n }\n // Create the modal.\n return ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: title,\n body: ''\n }).done(function(modal) {\n this.modal = modal;\n this.setupFormModal(formData, saveText);\n }.bind(this));\n }.bind(this))\n .catch(Notification.exception);\n };\n\n /**\n * Setup form inside a modal\n *\n * @param {String} formData\n * @param {String} saveText\n */\n AcceptOnBehalf.prototype.setupFormModal = function(formData, saveText) {\n var modal = this.modal;\n\n modal.setLarge();\n\n modal.setSaveButtonText(saveText);\n\n // We want to reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));\n\n modal.setBody(this.getBody(formData));\n\n // We catch the modal save event, and use it to submit the form inside the modal.\n // Triggering a form submission will give JS validation scripts a chance to check for errors.\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n // We also catch the form submit event and use it to submit the form with ajax.\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n modal.show();\n };\n\n /**\n * Load the body of the modal (contains the form)\n *\n * @method getBody\n * @private\n * @param {String} formData\n * @return {Promise}\n */\n AcceptOnBehalf.prototype.getBody = function(formData) {\n if (typeof formData === \"undefined\") {\n formData = {};\n }\n // Get the content of the modal.\n var params = {jsonformdata: JSON.stringify(formData)};\n return Fragment.loadFragment('tool_policy', 'accept_on_behalf', this.contextid, params);\n };\n\n /**\n * Submit the form inside the modal via AJAX request\n *\n * @method submitFormAjax\n * @private\n * @param {Event} e Form submission event.\n */\n AcceptOnBehalf.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = this.modal.getRoot().find('form').serialize();\n\n var requests = Ajax.call([{\n methodname: 'tool_policy_submit_accept_on_behalf',\n args: {jsonformdata: JSON.stringify(formData)}\n }]);\n requests[0].done(function(data) {\n if (data.validationerrors) {\n this.modal.setBody(this.getBody(formData));\n } else {\n this.close();\n }\n }.bind(this)).fail(Notification.exception);\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n AcceptOnBehalf.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n /**\n * Close the modal\n */\n AcceptOnBehalf.prototype.close = function() {\n this.destroy();\n document.location.reload();\n };\n\n /**\n * Destroy the modal\n */\n AcceptOnBehalf.prototype.destroy = function() {\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n this.modal.destroy();\n this.currentTrigger.focus();\n };\n\n return /** @alias module:tool_policy/acceptmodal */ {\n // Public variables and functions.\n /**\n * Attach event listeners to initialise this module.\n *\n * @method init\n * @param {int} contextid The contextid for the course.\n * @return {AcceptOnBehalf}\n */\n getInstance: function(contextid) {\n return new AcceptOnBehalf(contextid);\n }\n };\n });\n"],"file":"acceptmodal.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/acceptmodal.js"],"names":["define","$","Str","ModalFactory","ModalEvents","Notification","Fragment","Ajax","FormChangeChecker","AcceptOnBehalf","contextid","init","prototype","modal","currentTrigger","triggers","SINGLE","BULK","on","e","preventDefault","currentTarget","href","attr","formData","slice","indexOf","showFormModal","bind","form","closest","find","length","serialize","get_strings","key","component","then","strings","alert","fail","exception","action","params","split","i","pair","title","saveText","create","type","types","SAVE_CANCEL","body","done","setupFormModal","catch","setLarge","setSaveButtonText","getRoot","hidden","destroy","setBody","getBody","save","submitForm","submitFormAjax","show","jsonformdata","JSON","stringify","loadFragment","requests","call","methodname","args","data","validationerrors","close","submit","document","location","reload","resetAllFormDirtyStates","focus","getInstance"],"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 * Add policy consent modal to the page\n *\n * @module tool_policy/acceptmodal\n * @copyright 2018 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/str',\n 'core/modal_factory',\n 'core/modal_events',\n 'core/notification',\n 'core/fragment',\n 'core/ajax',\n 'core_form/changechecker',\n], function(\n $,\n Str,\n ModalFactory,\n ModalEvents,\n Notification,\n Fragment,\n Ajax,\n FormChangeChecker\n) {\n\n \"use strict\";\n\n /**\n * Constructor\n *\n * @param {int} contextid\n *\n * Each call to init gets it's own instance of this class.\n */\n var AcceptOnBehalf = function(contextid) {\n this.contextid = contextid;\n this.init();\n };\n\n /**\n * @var {Modal} modal\n * @private\n */\n AcceptOnBehalf.prototype.modal = null;\n\n /**\n * @var {int} contextid\n * @private\n */\n AcceptOnBehalf.prototype.contextid = -1;\n\n /**\n * @var {object} currentTrigger The triggered HTML jQuery object\n * @private\n */\n AcceptOnBehalf.prototype.currentTrigger = null;\n\n /**\n * @var {object} triggers The trigger selectors\n * @private\n */\n AcceptOnBehalf.prototype.triggers = {\n SINGLE: 'a[data-action=acceptmodal]',\n BULK: 'input[data-action=acceptmodal]'\n };\n\n /**\n * Initialise the class.\n *\n * @private\n */\n AcceptOnBehalf.prototype.init = function() {\n // Initialise for links accepting policies for individual users.\n $(this.triggers.SINGLE).on('click', function(e) {\n e.preventDefault();\n this.currentTrigger = $(e.currentTarget);\n var href = $(e.currentTarget).attr('href'),\n formData = href.slice(href.indexOf('?') + 1);\n this.showFormModal(formData);\n }.bind(this));\n\n // Initialise for multiple users acceptance form.\n $(this.triggers.BULK).on('click', function(e) {\n e.preventDefault();\n this.currentTrigger = $(e.currentTarget);\n var form = $(e.currentTarget).closest('form');\n if (form.find('input[type=checkbox][name=\"userids[]\"]:checked').length) {\n var formData = form.serialize();\n this.showFormModal(formData);\n } else {\n Str.get_strings([\n {key: 'notice'},\n {key: 'selectusersforconsent', component: 'tool_policy'},\n {key: 'ok'}\n ]).then(function(strings) {\n Notification.alert(strings[0], strings[1], strings[2]);\n return;\n }).fail(Notification.exception);\n }\n }.bind(this));\n };\n\n /**\n * Show modal with a form\n *\n * @param {String} formData\n */\n AcceptOnBehalf.prototype.showFormModal = function(formData) {\n var action;\n var params = formData.split('&');\n for (var i = 0; i < params.length; i++) {\n var pair = params[i].split('=');\n if (pair[0] == 'action') {\n action = pair[1];\n }\n }\n // Fetch the title string.\n Str.get_strings([\n {key: 'statusformtitleaccept', component: 'tool_policy'},\n {key: 'iagreetothepolicy', component: 'tool_policy'},\n {key: 'statusformtitlerevoke', component: 'tool_policy'},\n {key: 'irevokethepolicy', component: 'tool_policy'},\n {key: 'statusformtitledecline', component: 'tool_policy'},\n {key: 'declinethepolicy', component: 'tool_policy'}\n ]).then(function(strings) {\n var title;\n var saveText;\n if (action == 'accept') {\n title = strings[0];\n saveText = strings[1];\n } else if (action == 'revoke') {\n title = strings[2];\n saveText = strings[3];\n } else if (action == 'decline') {\n title = strings[4];\n saveText = strings[5];\n }\n // Create the modal.\n return ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: title,\n body: ''\n }).done(function(modal) {\n this.modal = modal;\n this.setupFormModal(formData, saveText);\n }.bind(this));\n }.bind(this))\n .catch(Notification.exception);\n };\n\n /**\n * Setup form inside a modal\n *\n * @param {String} formData\n * @param {String} saveText\n */\n AcceptOnBehalf.prototype.setupFormModal = function(formData, saveText) {\n var modal = this.modal;\n\n modal.setLarge();\n\n modal.setSaveButtonText(saveText);\n\n // We want to reset the form every time it is opened.\n modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));\n\n modal.setBody(this.getBody(formData));\n\n // We catch the modal save event, and use it to submit the form inside the modal.\n // Triggering a form submission will give JS validation scripts a chance to check for errors.\n modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));\n // We also catch the form submit event and use it to submit the form with ajax.\n modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));\n\n modal.show();\n };\n\n /**\n * Load the body of the modal (contains the form)\n *\n * @method getBody\n * @private\n * @param {String} formData\n * @return {Promise}\n */\n AcceptOnBehalf.prototype.getBody = function(formData) {\n if (typeof formData === \"undefined\") {\n formData = {};\n }\n // Get the content of the modal.\n var params = {jsonformdata: JSON.stringify(formData)};\n return Fragment.loadFragment('tool_policy', 'accept_on_behalf', this.contextid, params);\n };\n\n /**\n * Submit the form inside the modal via AJAX request\n *\n * @method submitFormAjax\n * @private\n * @param {Event} e Form submission event.\n */\n AcceptOnBehalf.prototype.submitFormAjax = function(e) {\n // We don't want to do a real form submission.\n e.preventDefault();\n\n // Convert all the form elements values to a serialised string.\n var formData = this.modal.getRoot().find('form').serialize();\n\n var requests = Ajax.call([{\n methodname: 'tool_policy_submit_accept_on_behalf',\n args: {jsonformdata: JSON.stringify(formData)}\n }]);\n requests[0].done(function(data) {\n if (data.validationerrors) {\n this.modal.setBody(this.getBody(formData));\n } else {\n this.close();\n }\n }.bind(this)).fail(Notification.exception);\n };\n\n /**\n * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.\n *\n * @method submitForm\n * @param {Event} e Form submission event.\n * @private\n */\n AcceptOnBehalf.prototype.submitForm = function(e) {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n };\n\n /**\n * Close the modal\n */\n AcceptOnBehalf.prototype.close = function() {\n this.destroy();\n document.location.reload();\n };\n\n /**\n * Destroy the modal\n */\n AcceptOnBehalf.prototype.destroy = function() {\n FormChangeChecker.resetAllFormDirtyStates();\n this.modal.destroy();\n this.currentTrigger.focus();\n };\n\n return /** @alias module:tool_policy/acceptmodal */ {\n // Public variables and functions.\n /**\n * Attach event listeners to initialise this module.\n *\n * @method init\n * @param {int} contextid The contextid for the course.\n * @return {AcceptOnBehalf}\n */\n getInstance: function(contextid) {\n return new AcceptOnBehalf(contextid);\n }\n };\n });\n"],"file":"acceptmodal.min.js"}
\ No newline at end of file
diff --git a/admin/tool/policy/amd/src/acceptmodal.js b/admin/tool/policy/amd/src/acceptmodal.js
index 57808ae979f..31f7241255a 100644
--- a/admin/tool/policy/amd/src/acceptmodal.js
+++ b/admin/tool/policy/amd/src/acceptmodal.js
@@ -20,9 +20,25 @@
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/notification', 'core/fragment',
- 'core/ajax', 'core/yui'],
- function($, Str, ModalFactory, ModalEvents, Notification, Fragment, Ajax, Y) {
+define([
+ 'jquery',
+ 'core/str',
+ 'core/modal_factory',
+ 'core/modal_events',
+ 'core/notification',
+ 'core/fragment',
+ 'core/ajax',
+ 'core_form/changechecker',
+], function(
+ $,
+ Str,
+ ModalFactory,
+ ModalEvents,
+ Notification,
+ Fragment,
+ Ajax,
+ FormChangeChecker
+) {
"use strict";
@@ -244,9 +260,7 @@ define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/n
* Destroy the modal
*/
AcceptOnBehalf.prototype.destroy = function() {
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ FormChangeChecker.resetAllFormDirtyStates();
this.modal.destroy();
this.currentTrigger.focus();
};
diff --git a/course/bulkcompletion.php b/course/bulkcompletion.php
index 1343983b136..0f012b1cedc 100644
--- a/course/bulkcompletion.php
+++ b/course/bulkcompletion.php
@@ -73,14 +73,7 @@ echo $OUTPUT->heading(get_string('bulkactivitycompletion', 'completion'));
echo $renderer->navigation($course, 'bulkcompletion');
-$PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => 'theform'
- ))
-);
-$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
-
+$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['theform']);
echo $renderer->bulkcompletion($bulkcompletiondata);
diff --git a/course/defaultcompletion.php b/course/defaultcompletion.php
index 4b5f98f73ac..3d209a86e2e 100644
--- a/course/defaultcompletion.php
+++ b/course/defaultcompletion.php
@@ -68,13 +68,7 @@ echo $OUTPUT->heading(get_string('defaultcompletion', 'completion'));
echo $renderer->navigation($course, 'defaultcompletion');
-$PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => 'theform'
- ))
-);
-$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['theform']);
echo $renderer->defaultcompletion($activityresourcedata);
diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index 152cd65a83e..c3ee7249020 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -299,13 +299,7 @@ if ($moving) {
echo $OUTPUT->container_end();
-$PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => 'gradetreeform'
- ))
-);
-$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['gradetreeform']);
echo $OUTPUT->footer();
die;
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index fa5b2d80a4b..bba2d312bed 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -1254,13 +1254,7 @@ class grade_report_grader extends grade_report {
$PAGE->requires->strings_for_js(array('addfeedback', 'feedback', 'grade'), 'grades');
$PAGE->requires->strings_for_js(array('ajaxchoosescale', 'ajaxclicktoclose', 'ajaxerror', 'ajaxfailedupdate', 'ajaxfieldchanged'), 'gradereport_grader');
if (!$enableajax && $USER->gradeediting[$this->courseid]) {
- $PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => 'gradereport_grader'
- ))
- );
- $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+ $PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['gradereport_grader']);
}
$rows = $this->get_right_range_row($rows);
diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js
index 71d7b14e7da..2b0bd36c3b9 100644
--- a/lib/amd/build/form-autocomplete.min.js
+++ b/lib/amd/build/form-autocomplete.min.js
@@ -1,2 +1,2 @@
-define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);d.attr("data-active-value",f.attr("data-value"));return a.Deferred().resolve()},l=function(b){var c=a(document.getElementById(b.selectionId)),d=c.attr("aria-activedescendant");if(d){var e=a(document.getElementById(d));if(e.length){return e}}var f=c.attr("data-active-value");return c.find("[data-value=\""+f+"\"]")},m=function(b){var c=l(b),d=c.attr("data-value"),e=a(document.getElementById(b.selectionId));if(d){var f=e.find("[aria-selected=true]").index(c);if(-1!==f){k(f,b);return}}k(0,b)},n=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId));e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});if(!o(c,h)){M.util.js_complete(g);return Promise.resolve()}c.items=h;var j=a.extend(b,c);return d.render(b.templates.items,j).then(function(a,b){d.replaceNodeContents(i,a,b);m(c)}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},o=function(a,b){if(a.items.length!==b.length){return!0}return 0b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return r(e+1,b)},t=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},u=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},v=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return r(e-1,b)},w=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},x=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var o=e.caseSensitive?g:g.toLocaleLowerCase(),p=a.extend({options:n},b,e),q=d.render("core/form_autocomplete_suggestions",p).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return n(b,c,d).then(function(){p(d)}).then(function(){e.val("")}).then(function(){return w(c)})},z=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return n(b,c,d).then(function(){p(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return w(c)}else{e.focus();return x(b,c,e.val(),d)}})},A=function(b,c,d,e,f){var h=C("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a(" ");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(x(c,d,"",e))},function(a){h.reject(a)});return h},B=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=C("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(s(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(A(f,b,c,d,a))})}else{e.resolve(x(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(v(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var y="",z=d.render(r.templates.layout,{}).then(function(b){return a(b)}),A=d.render(r.templates.input,x).then(function(b,c){y+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){y+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){y+=c;return a(b)});return a.when(z,A,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();c.find("input").attr("data-fieldtype","autocomplete");g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(y);v.attr("for",u.inputId);B(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return n(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
+define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria","core_form/changechecker"],function(a,b,c,d,f,g,h,i){var j={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},k=Date.now(),l=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);d.attr("data-active-value",f.attr("data-value"));return a.Deferred().resolve()},m=function(b){var c=a(document.getElementById(b.selectionId)),d=c.attr("aria-activedescendant");if(d){var e=a(document.getElementById(d));if(e.length){return e}}var f=c.attr("data-active-value");return c.find("[data-value=\""+f+"\"]")},n=function(b){var c=m(b),d=c.attr("data-value"),e=a(document.getElementById(b.selectionId));if(d){var f=e.find("[aria-selected=true]").index(c);if(-1!==f){l(f,b);return}}l(0,b)},o=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId));e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});if(!p(c,h)){M.util.js_complete(g);return Promise.resolve()}c.items=h;var j=a.extend(b,c);return d.render(b.templates.items,j).then(function(a,b){d.replaceNodeContents(i,a,b);n(c)}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},p=function(a,b){if(a.items.length!==b.length){return!0}return 0b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},t=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return s(e+1,b)},u=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return l(0,b)}var e=c.children("[aria-selected=true]").index(d);return l(e-1,b)},v=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return l(e,b)},w=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return s(e-1,b)},x=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},y=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var o=e.caseSensitive?g:g.toLocaleLowerCase(),p=a.extend({options:n},b,e),q=d.render("core/form_autocomplete_suggestions",p).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return o(b,c,d).then(function(){q(d)}).then(function(){e.val("")}).then(function(){return x(c)})},A=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return o(b,c,d).then(function(){q(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return x(c)}else{e.focus();return y(b,c,e.val(),d)}})},B=function(b,c,d,e,f){var h=D("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a(" ");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(y(c,d,"",e))},function(a){h.reject(a)});return h},C=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=D("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case j.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(t(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(B(f,b,c,d,a))})}else{e.resolve(y(b,c,g.val(),d))}}f.preventDefault();return!1;case j.UP:e.resolve(w(c));f.preventDefault();return!1;case j.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var y="",z=d.render(r.templates.layout,{}).then(function(b){return a(b)}),A=d.render(r.templates.input,x).then(function(b,c){y+=c;return a(b)}),B=d.render(r.templates.suggestions,x).then(function(b,c){y+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){y+=c;return a(b)});return a.when(z,A,B,D).then(function(b,c,e,f){t.hide();var g=t.parent();c.find("input").attr("data-fieldtype","autocomplete");g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(y);v.attr("for",u.inputId);C(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return o(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
//# sourceMappingURL=form-autocomplete.min.js.map
diff --git a/lib/amd/build/form-autocomplete.min.js.map b/lib/amd/build/form-autocomplete.min.js.map
index 60630f6b80b..3494d8f0214 100644
--- a/lib/amd/build/form-autocomplete.min.js.map
+++ b/lib/amd/build/form-autocomplete.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","getActiveElementFromState","selectionRegion","activeId","activeElement","activeValue","find","updateActiveSelectionFromState","activeIndex","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","each","ele","prop","label","data","html","push","value","hasItemListChanged","js_complete","Promise","context","extend","render","then","js","replaceNodeContents","catch","exception","filter","item","indexOf","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","replaceWith","runTemplateJS"],"mappings":"AAuBAA,OAAM,0BACF,CAAC,QAAD,CAAW,UAAX,CAAuB,UAAvB,CAAmC,gBAAnC,CAAqD,mBAArD,CAA0E,kBAA1E,CAA8F,WAA9F,CADE,CAEN,SAASC,CAAT,CAAYC,CAAZ,CAAiBC,CAAjB,CAAsBC,CAAtB,CAAiCC,CAAjC,CAA+CC,CAA/C,CAA4DC,CAA5D,CAAkE,IAI1DC,CAAAA,CAAI,CAAG,CACPC,IAAI,CAAE,EADC,CAEPC,KAAK,CAAE,EAFA,CAGPC,KAAK,CAAE,EAHA,CAIPC,MAAM,CAAE,EAJD,CAKPC,KAAK,CAAE,EALA,CAMPC,EAAE,CAAE,EANG,CAOPC,IAAI,CAAE,EAPC,CAQPC,KAAK,CAAE,EARA,CAJmD,CAe1DC,CAAQ,CAAGC,IAAI,CAACC,GAAL,EAf+C,CA0B1DC,CAAiB,CAAG,SAASC,CAAT,CAAgBC,CAAhB,CAAuB,IAEvCC,CAAAA,CAAgB,CAAGtB,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFmB,CAKvCC,CAAM,CAAGJ,CAAgB,CAACK,QAAjB,CAA0B,sBAA1B,EAAkDD,MALpB,CAO3CN,CAAK,CAAGA,CAAK,CAAGM,CAAhB,CACA,MAAe,CAAR,CAAAN,CAAP,CAAkB,CACdA,CAAK,EAAIM,CACZ,CAV0C,GAYvCE,CAAAA,CAAO,CAAG5B,CAAC,CAACsB,CAAgB,CAACK,QAAjB,CAA0B,sBAA1B,EAAkDE,GAAlD,CAAsDT,CAAtD,CAAD,CAZ4B,CAcvCU,CAAM,CAAGT,CAAK,CAACI,WAAN,CAAoB,GAApB,CAA0BL,CAdI,CAiB3CE,CAAgB,CAACK,QAAjB,GAA4BI,IAA5B,CAAiC,uBAAjC,CAA0D,IAA1D,EAAgEA,IAAhE,CAAqE,IAArE,CAA2E,EAA3E,EAGAH,CAAO,CAACG,IAAR,CAAa,uBAAb,KAA4CA,IAA5C,CAAiD,IAAjD,CAAuDD,CAAvD,EAGAR,CAAgB,CAACS,IAAjB,CAAsB,uBAAtB,CAA+CD,CAA/C,EACAR,CAAgB,CAACS,IAAjB,CAAsB,mBAAtB,CAA2CH,CAAO,CAACG,IAAR,CAAa,YAAb,CAA3C,EAEA,MAAO/B,CAAAA,CAAC,CAACgC,QAAF,GAAaC,OAAb,EACV,CArD6D,CA6D1DC,CAAyB,CAAG,SAASb,CAAT,CAAgB,IACxCc,CAAAA,CAAe,CAAGnC,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CADqB,CAExCW,CAAQ,CAAGD,CAAe,CAACJ,IAAhB,CAAqB,uBAArB,CAF6B,CAI5C,GAAIK,CAAJ,CAAc,CACV,GAAIC,CAAAA,CAAa,CAAGrC,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBY,CAAxB,CAAD,CAArB,CACA,GAAIC,CAAa,CAACX,MAAlB,CAA0B,CAEtB,MAAOW,CAAAA,CACV,CACJ,CAED,GAAIC,CAAAA,CAAW,CAAGH,CAAe,CAACJ,IAAhB,CAAqB,mBAArB,CAAlB,CACA,MAAOI,CAAAA,CAAe,CAACI,IAAhB,CAAqB,iBAAkBD,CAAlB,CAAgC,KAArD,CACV,CA3E6D,CAkF1DE,CAA8B,CAAG,SAASnB,CAAT,CAAgB,IAC7CgB,CAAAA,CAAa,CAAGH,CAAyB,CAACb,CAAD,CADI,CAE7CiB,CAAW,CAAGD,CAAa,CAACN,IAAd,CAAmB,YAAnB,CAF+B,CAI7CI,CAAe,CAAGnC,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAJ0B,CAKjD,GAAIa,CAAJ,CAAiB,CAEb,GAAIG,CAAAA,CAAW,CAAGN,CAAe,CAACI,IAAhB,CAAqB,sBAArB,EAA6CnB,KAA7C,CAAmDiB,CAAnD,CAAlB,CAEA,GAAoB,CAAC,CAAjB,GAAAI,CAAJ,CAAwB,CACpBtB,CAAiB,CAACsB,CAAD,CAAcpB,CAAd,CAAjB,CACA,MACH,CACJ,CAIDF,CAAiB,CAAC,CAAD,CAAIE,CAAJ,CACpB,CApG6D,CAgH1DqB,CAAmB,CAAG,SAASC,CAAT,CAAkBtB,CAAlB,CAAyBuB,CAAzB,CAAyC,CAC/D,GAAIC,CAAAA,CAAU,CAAG,yCAA2CxB,CAAK,CAACyB,OAAlE,CACAC,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EAF+D,GAK3DK,CAAAA,CAAK,CAAG,EALmD,CAM3DC,CAAY,CAAGnD,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAN2C,CAO/DmB,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAAShC,CAAT,CAAgBiC,CAAhB,CAAqB,CACxD,GAAIrD,CAAC,CAACqD,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,CAAJ,CAA6B,CACzB,GAAIC,CAAAA,CAAJ,CACA,GAAIvD,CAAC,CAACqD,CAAD,CAAD,CAAOG,IAAP,CAAY,MAAZ,CAAJ,CAAyB,CACrBD,CAAK,CAAGvD,CAAC,CAACqD,CAAD,CAAD,CAAOG,IAAP,CAAY,MAAZ,CACX,CAFD,IAEO,CACHD,CAAK,CAAGvD,CAAC,CAACqD,CAAD,CAAD,CAAOI,IAAP,EACX,CACD,GAAc,EAAV,GAAAF,CAAJ,CAAkB,CACdL,CAAK,CAACQ,IAAN,CAAW,CAACH,KAAK,CAAEA,CAAR,CAAeI,KAAK,CAAE3D,CAAC,CAACqD,CAAD,CAAD,CAAOtB,IAAP,CAAY,OAAZ,CAAtB,CAAX,CACH,CACJ,CACJ,CAZD,EAcA,GAAI,CAAC6B,CAAkB,CAACvC,CAAD,CAAQ6B,CAAR,CAAvB,CAAuC,CACnCH,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,EACA,MAAOiB,CAAAA,OAAO,CAAC7B,OAAR,EACV,CAEDZ,CAAK,CAAC6B,KAAN,CAAcA,CAAd,CAEA,GAAIa,CAAAA,CAAO,CAAG/D,CAAC,CAACgE,MAAF,CAASrB,CAAT,CAAkBtB,CAAlB,CAAd,CAEA,MAAOlB,CAAAA,CAAS,CAAC8D,MAAV,CAAiBtB,CAAO,CAACxC,SAAR,CAAkB+C,KAAnC,CAA0Ca,CAA1C,EACNG,IADM,CACD,SAAST,CAAT,CAAeU,CAAf,CAAmB,CAErBhE,CAAS,CAACiE,mBAAV,CAA8BjB,CAA9B,CAA4CM,CAA5C,CAAkDU,CAAlD,EAEA3B,CAA8B,CAACnB,CAAD,CAGjC,CARM,EASN6C,IATM,CASD,UAAW,CACb,MAAOnB,CAAAA,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,CACV,CAXM,EAYNwB,KAZM,CAYAjE,CAAY,CAACkE,SAZb,CAaV,CA3J6D,CAoK1DV,CAAkB,CAAG,SAASvC,CAAT,CAAgB6B,CAAhB,CAAuB,CAC5C,GAAI7B,CAAK,CAAC6B,KAAN,CAAYxB,MAAZ,GAAuBwB,CAAK,CAACxB,MAAjC,CAAyC,CACrC,QACH,CAGD,MAAuE,EAAhE,CAAAL,CAAK,CAAC6B,KAAN,CAAYqB,MAAZ,CAAmB,SAAAC,CAAI,QAA4B,CAAC,CAAzB,GAAAtB,CAAK,CAACuB,OAAN,CAAcD,CAAd,CAAJ,CAAvB,EAAuD9C,MACjE,CA3K6D,CAkL1DgD,CAAY,CAAG,SAAS9B,CAAT,CAAyB,CACxC,GAAwC,WAApC,QAAOG,CAAAA,CAAC,CAAC4B,sBAAb,CAAqD,CACjD5B,CAAC,CAAC4B,sBAAF,CAAyBC,gBAAzB,EACH,CAIDhC,CAAc,CAAC,CAAD,CAAd,CAAkBiC,aAAlB,CAAgC,GAAIC,CAAAA,KAAJ,CAAU,QAAV,CAAhC,CACH,CA1L6D,CAuM1DC,CAAY,CAAG,SAASpC,CAAT,CAAkBtB,CAAlB,CAAyBmD,CAAzB,CAA+B5B,CAA/B,CAA+C,CAC9D,GAAIoC,CAAAA,CAAiB,CAAGhF,CAAC,CAACwE,CAAD,CAAD,CAAQzC,IAAR,CAAa,YAAb,CAAxB,CAGAa,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAAShC,CAAT,CAAgBiC,CAAhB,CAAqB,CACxD,GAAIrD,CAAC,CAACqD,CAAD,CAAD,CAAOtB,IAAP,CAAY,OAAZ,GAAwBiD,CAA5B,CAA+C,CAC3ChF,CAAC,CAACqD,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,KAEA,GAAItD,CAAC,CAACqD,CAAD,CAAD,CAAOtB,IAAP,CAAY,eAAZ,CAAJ,CAAkC,CAC9B/B,CAAC,CAACqD,CAAD,CAAD,CAAO4B,MAAP,EACH,CACJ,CACJ,CARD,EAUA,MAAOvC,CAAAA,CAAmB,CAACC,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAAnB,CACNsB,IADM,CACD,UAAW,CAEbQ,CAAY,CAAC9B,CAAD,CAGf,CANM,CAOV,CA5N6D,CAuO1DsC,CAAY,CAAG,SAAS9D,CAAT,CAAgBC,CAAhB,CAAuB,IAElC8D,CAAAA,CAAY,CAAGnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CAFkB,CAGlCsC,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAHY,CAMlC3D,CAAM,CAAG0D,CAAkB,CAACzD,QAAnB,CAA4B,qBAA5B,EAAmDD,MAN1B,CAQtCN,CAAK,CAAGA,CAAK,CAAGM,CAAhB,CACA,MAAe,CAAR,CAAAN,CAAP,CAAkB,CACdA,CAAK,EAAIM,CACZ,CAXqC,GAalCE,CAAAA,CAAO,CAAG5B,CAAC,CAACoF,CAAkB,CAACzD,QAAnB,CAA4B,qBAA5B,EAAmDE,GAAnD,CAAuDT,CAAvD,CAAD,CAbuB,CAelCkE,CAAW,CAAGtF,CAAC,CAACoF,CAAkB,CAACzD,QAAnB,CAA4B,eAA5B,CAAD,CAAD,CAAgDP,KAAhD,CAAsDQ,CAAtD,CAfoB,CAiBlCE,CAAM,CAAGT,CAAK,CAACgE,aAAN,CAAsB,GAAtB,CAA4BC,CAjBH,CAoBtCF,CAAkB,CAACzD,QAAnB,GAA8BI,IAA9B,CAAmC,eAAnC,KAA2DA,IAA3D,CAAgE,IAAhE,CAAsE,EAAtE,EAEAH,CAAO,CAACG,IAAR,CAAa,eAAb,KAAoCA,IAApC,CAAyC,IAAzC,CAA+CD,CAA/C,EAEAqD,CAAY,CAACpD,IAAb,CAAkB,uBAAlB,CAA2CD,CAA3C,EAGA,GAAIyD,CAAAA,CAAS,CAAG3D,CAAO,CAAC4D,MAAR,GAAiBC,GAAjB,CACCL,CAAkB,CAACI,MAAnB,GAA4BC,GAD7B,CAECL,CAAkB,CAACM,SAAnB,EAFD,CAGEN,CAAkB,CAACO,MAAnB,GAA8B,CAHhD,CAIA,MAAOP,CAAAA,CAAkB,CAACQ,OAAnB,CAA2B,CAC9BF,SAAS,CAAEH,CADmB,CAA3B,CAEJ,GAFI,EAECM,OAFD,EAGV,CAzQ6D,CAmR1DC,CAAgB,CAAG,SAASzE,CAAT,CAAgB,IAE/B+D,CAAAA,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAFS,CAI/BzD,CAAO,CAAGwD,CAAkB,CAACzD,QAAnB,CAA4B,sBAA5B,CAJqB,CAM/BoE,CAAO,CAAGX,CAAkB,CAACzD,QAAnB,CAA4B,qBAA5B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CANqB,CAQnC,MAAOsD,CAAAA,CAAY,CAACa,CAAO,CAAG,CAAX,CAAc1E,CAAd,CACtB,CA5R6D,CAsS1D2E,CAAyB,CAAG,SAAS3E,CAAT,CAAgB,IAExC4E,CAAAA,CAAiB,CAAGjG,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFmB,CAIxCG,CAAO,CAAGqE,CAAiB,CAACtE,QAAlB,CAA2B,yBAA3B,CAJ8B,CAK5C,GAAI,CAACC,CAAL,CAAc,CACV,MAAOT,CAAAA,CAAiB,CAAC,CAAD,CAAIE,CAAJ,CAC3B,CAED,GAAI0E,CAAAA,CAAO,CAAGE,CAAiB,CAACtE,QAAlB,CAA2B,sBAA3B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CAAd,CAEA,MAAOT,CAAAA,CAAiB,CAAC4E,CAAO,CAAG,CAAX,CAAc1E,CAAd,CAC3B,CAlT6D,CA4T1D6E,CAAqB,CAAG,SAAS7E,CAAT,CAAgB,IAEpC4E,CAAAA,CAAiB,CAAGjG,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFe,CAKpCG,CAAO,CAAGqE,CAAiB,CAACtE,QAAlB,CAA2B,yBAA3B,CAL0B,CAMpCoE,CAAO,CAAG,CAN0B,CAQxC,GAAInE,CAAJ,CAAa,CAETmE,CAAO,CAAGE,CAAiB,CAACtE,QAAlB,CAA2B,sBAA3B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CAAV,CACAmE,CAAO,CAAGA,CAAO,CAAG,CACvB,CAJD,IAIO,CAEHA,CAAO,CAAG,CACb,CAED,MAAO5E,CAAAA,CAAiB,CAAC4E,CAAD,CAAU1E,CAAV,CAC3B,CA9U6D,CAwV1D8E,CAAoB,CAAG,SAAS9E,CAAT,CAAgB,IAEnC+D,CAAAA,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAFa,CAKnCzD,CAAO,CAAGwD,CAAkB,CAACzD,QAAnB,CAA4B,sBAA5B,CALyB,CAQnCoE,CAAO,CAAGX,CAAkB,CAACzD,QAAnB,CAA4B,qBAA5B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CARyB,CAWvC,MAAOsD,CAAAA,CAAY,CAACa,CAAO,CAAG,CAAX,CAAc1E,CAAd,CACtB,CApW6D,CA8W1D+E,CAAgB,CAAG,SAAS/E,CAAT,CAAgB,IAE/B8D,CAAAA,CAAY,CAAGnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CAFe,CAG/BsC,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAHS,CAKnC,GAA2C,MAAvC,GAAAF,CAAY,CAACpD,IAAb,CAAkB,eAAlB,CAAJ,CAAmD,CAE/CoD,CAAY,CAACpD,IAAb,CAAkB,eAAlB,IACH,CAEDoD,CAAY,CAACpD,IAAb,CAAkB,uBAAlB,CAA2CV,CAAK,CAACI,WAAjD,EAGAnB,CAAI,CAAC+F,IAAL,CAAUjB,CAAkB,CAACvD,GAAnB,EAAV,EACAuD,CAAkB,CAACiB,IAAnB,GAEA,MAAOrG,CAAAA,CAAC,CAACgC,QAAF,GAAaC,OAAb,EACV,CA/X6D,CA4Y1DqE,CAAiB,CAAG,SAAS3D,CAAT,CAAkBtB,CAAlB,CAAyBkF,CAAzB,CAAgC3D,CAAhC,CAAgD,CACpE,GAAIC,CAAAA,CAAU,CAAG,uCAAyCxB,CAAK,CAACyB,OAAhE,CACAC,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EAFoE,GAKhEsC,CAAAA,CAAY,CAAGnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CALgD,CAMhEsC,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAN0C,CAShEmB,CAAgB,GATgD,CAWhEC,CAAW,CAAG,EAXkD,CAYpE7D,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAAShC,CAAT,CAAgBsF,CAAhB,CAAwB,CAC3D,GAAI,KAAA1G,CAAC,CAAC0G,CAAD,CAAD,CAAUpD,IAAV,CAAe,UAAf,CAAJ,CAAyC,CACrCmD,CAAW,CAACA,CAAW,CAAC/E,MAAb,CAAX,CAAkC,CAAC6B,KAAK,CAAEmD,CAAM,CAACC,SAAf,CAA0BhD,KAAK,CAAE3D,CAAC,CAAC0G,CAAD,CAAD,CAAU3E,IAAV,CAAe,OAAf,CAAjC,CACrC,CACJ,CAJD,EAZoE,GAmBhE6E,CAAAA,CAAW,CAAGvF,CAAK,CAACwF,aAAN,CAAsBN,CAAtB,CAA8BA,CAAK,CAACO,iBAAN,EAnBoB,CAoBhE/C,CAAO,CAAG/D,CAAC,CAACgE,MAAF,CAAS,CAACrB,OAAO,CAAE8D,CAAV,CAAT,CAAiC9D,CAAjC,CAA0CtB,CAA1C,CApBsD,CAqBhE0F,CAAS,CAAG5G,CAAS,CAAC8D,MAAV,CACZ,oCADY,CAEZF,CAFY,EAIfG,IAJe,CAIV,SAAST,CAAT,CAAeU,CAAf,CAAmB,CAErBhE,CAAS,CAAC6G,WAAV,CAAsB5B,CAAtB,CAA0C3B,CAA1C,CAAgDU,CAAhD,EAGAiB,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAAtB,CAGA/E,CAAI,CAAC2G,MAAL,CAAY7B,CAAkB,CAACvD,GAAnB,EAAZ,EACAuD,CAAkB,CAAC8B,IAAnB,GAGA9B,CAAkB,CAACzD,QAAnB,GAA8ByB,IAA9B,CAAmC,SAAShC,CAAT,CAAgB+F,CAAhB,CAAsB,CACrDA,CAAI,CAAGnH,CAAC,CAACmH,CAAD,CAAR,CACA,GAAKxE,CAAO,CAACkE,aAAR,EAA4D,CAAC,CAApC,CAAAM,CAAI,CAACC,IAAL,GAAY3C,OAAZ,CAAoBmC,CAApB,CAA1B,EACK,CAACjE,CAAO,CAACkE,aAAT,EAAiF,CAAC,CAAxD,CAAAM,CAAI,CAACC,IAAL,GAAYN,iBAAZ,GAAgCrC,OAAhC,CAAwCmC,CAAxC,CADnC,CAC+F,CAC3FtG,CAAI,CAAC2G,MAAL,CAAYE,CAAI,CAACtF,GAAL,EAAZ,EACAsF,CAAI,CAACD,IAAL,GACAV,CAAgB,GACnB,CALD,IAKO,CACHW,CAAI,CAACd,IAAL,GACA/F,CAAI,CAAC+F,IAAL,CAAUc,CAAI,CAACtF,GAAL,EAAV,CACH,CACJ,CAXD,EAaAsD,CAAY,CAACpD,IAAb,CAAkB,eAAlB,KACA,GAAIa,CAAc,CAACb,IAAf,CAAoB,aAApB,CAAJ,CAAwC,CAEpCqD,CAAkB,CAAC3B,IAAnB,CAAwBb,CAAc,CAACb,IAAf,CAAoB,aAApB,CAAxB,CACH,CAHD,IAGO,IAAIyE,CAAJ,CAAsB,CAIzB,GAAI,CAAC7D,CAAO,CAAC0E,IAAb,CAAmB,CACfnC,CAAY,CAAC,CAAD,CAAI7D,CAAJ,CACf,CACJ,CAPM,IAOA,CAEHnB,CAAG,CAACoH,UAAJ,CAAe,eAAf,CAAgC,MAAhC,EAAwCC,IAAxC,CAA6C,SAASC,CAAT,CAA2B,CACpEpC,CAAkB,CAAC3B,IAAnB,CAAwB+D,CAAxB,CACH,CAFD,CAGH,CAED,MAAOpC,CAAAA,CACV,CAhDe,EAiDflB,IAjDe,CAiDV,UAAW,CACb,MAAOnB,CAAAA,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,CACV,CAnDe,EAoDfwB,KApDe,CAoDTjE,CAAY,CAACkE,SApDJ,CArBoD,CA2EpE,MAAOyC,CAAAA,CACV,CAxd6D,CAoe1DU,CAAU,CAAG,SAAS9E,CAAT,CAAkBtB,CAAlB,CAAyBuB,CAAzB,CAAyC,IAElDuC,CAAAA,CAAY,CAAGnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CAFkC,CAIlDyD,CAAK,CAAGpB,CAAY,CAACuC,GAAb,EAJ0C,CAKlDL,CAAI,CAAGd,CAAK,CAACoB,KAAN,CAAY,GAAZ,CAL2C,CAMlDC,CAAK,GAN6C,CAQtD5H,CAAC,CAACoD,IAAF,CAAOiE,CAAP,CAAa,SAASQ,CAAT,CAAmBC,CAAnB,CAAwB,CAEjCA,CAAG,CAAGA,CAAG,CAACC,IAAJ,EAAN,CACA,GAAY,EAAR,GAAAD,CAAJ,CAAgB,CACZ,GAAI,CAACnF,CAAO,CAACqF,QAAb,CAAuB,CACnBpF,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkC2B,IAAlC,CAAuC,UAAvC,IACH,CAEDV,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAAShC,CAAT,CAAgBiC,CAAhB,CAAqB,CACxD,GAAIrD,CAAC,CAACqD,CAAD,CAAD,CAAOtB,IAAP,CAAY,OAAZ,GAAwB+F,CAA5B,CAAiC,CAC7BF,CAAK,GAAL,CACA5H,CAAC,CAACqD,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,IACH,CACJ,CALD,EAOA,GAAI,CAACsE,CAAL,CAAY,CACR,GAAIlB,CAAAA,CAAM,CAAG1G,CAAC,CAAC,UAAD,CAAd,CACA0G,CAAM,CAACuB,MAAP,CAAc1G,QAAQ,CAAC2G,cAAT,CAAwBJ,CAAxB,CAAd,EACApB,CAAM,CAAC3E,IAAP,CAAY,OAAZ,CAAqB+F,CAArB,EACAlF,CAAc,CAACqF,MAAf,CAAsBvB,CAAtB,EACAA,CAAM,CAACpD,IAAP,CAAY,UAAZ,KAEAoD,CAAM,CAAC3E,IAAP,CAAY,eAAZ,IACH,CACJ,CACJ,CAzBD,EA2BA,MAAOW,CAAAA,CAAmB,CAACC,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAAnB,CACNsB,IADM,CACD,UAAW,CAEbQ,CAAY,CAAC9B,CAAD,CAGf,CANM,EAONsB,IAPM,CAOD,UAAW,CAEbiB,CAAY,CAACuC,GAAb,CAAiB,EAAjB,CAGH,CAZM,EAaNxD,IAbM,CAaD,UAAW,CAEb,MAAOkC,CAAAA,CAAgB,CAAC/E,CAAD,CAC1B,CAhBM,CAiBV,CAxhB6D,CAoiB1D8G,CAAiB,CAAG,SAASxF,CAAT,CAAkBtB,CAAlB,CAAyBuB,CAAzB,CAAyC,IAEzDuC,CAAAA,CAAY,CAAGnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CAFyC,CAGzDsC,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAHmC,CAMzDL,CAAiB,CAAGI,CAAkB,CAACzD,QAAnB,CAA4B,sBAA5B,EAAoDI,IAApD,CAAyD,YAAzD,CANqC,CAW7D,GAAI,CAACY,CAAO,CAACqF,QAAb,CAAuB,CACnBpF,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkC2B,IAAlC,CAAuC,UAAvC,IACH,CAEDV,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAAShC,CAAT,CAAgBiC,CAAhB,CAAqB,CACxD,GAAIrD,CAAC,CAACqD,CAAD,CAAD,CAAOtB,IAAP,CAAY,OAAZ,GAAwBiD,CAA5B,CAA+C,CAC3ChF,CAAC,CAACqD,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,IACH,CACJ,CAJD,EAMA,MAAOZ,CAAAA,CAAmB,CAACC,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAAnB,CACNsB,IADM,CACD,UAAW,CAEbQ,CAAY,CAAC9B,CAAD,CAGf,CANM,EAONsB,IAPM,CAOD,UAAW,CACb,GAAIvB,CAAO,CAACyF,wBAAZ,CAAsC,CAElCjD,CAAY,CAACuC,GAAb,CAAiB,EAAjB,EAEA,MAAOtB,CAAAA,CAAgB,CAAC/E,CAAD,CAC1B,CALD,IAKO,CAEH8D,CAAY,CAACkD,KAAb,GAEA,MAAO/B,CAAAA,CAAiB,CAAC3D,CAAD,CAAUtB,CAAV,CAAiB8D,CAAY,CAACuC,GAAb,EAAjB,CAAqC9E,CAArC,CAC3B,CACJ,CAnBM,CAoBV,CA7kB6D,CA2lB1D0F,CAAU,CAAG,SAASC,CAAT,CAAY5F,CAAZ,CAAqBtB,CAArB,CAA4BuB,CAA5B,CAA4C4F,CAA5C,CAAyD,IAClEC,CAAAA,CAAc,CAAGC,CAAmB,CAAC,YAAD,CAD8B,CAIlEC,CAAa,CAAG3I,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACuH,QAA9B,CAAD,CAAD,CAA2CC,MAA3C,EAJkD,CAKtExI,CAAW,CAACyI,oCAAZ,CAAiDH,CAAjD,CAAgEF,CAAhE,EAGA,GAAIlC,CAAAA,CAAK,CAAGvG,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EAAZ,CAEAc,CAAW,CAACQ,SAAZ,CAAsBrG,CAAO,CAACsG,QAA9B,CAAwC1C,CAAxC,CAA+C,SAAS2C,CAAT,CAAkB,IAEzDC,CAAAA,CAAgB,CAAGX,CAAW,CAACY,cAAZ,CAA2BzG,CAAO,CAACsG,QAAnC,CAA6CC,CAA7C,CAFsC,CAGzDG,CAAc,CAAG,EAHwC,CAM7D,GAAI,CAAC1G,CAAO,CAACqF,QAAb,CAAuB,CACnBpF,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCsD,MAAlC,EACH,CACDrC,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAASkG,CAAT,CAAsB5C,CAAtB,CAA8B,CACjEA,CAAM,CAAG1G,CAAC,CAAC0G,CAAD,CAAV,CACA,GAAI,CAACA,CAAM,CAACpD,IAAP,CAAY,UAAZ,CAAL,CAA8B,CAC1BoD,CAAM,CAACzB,MAAP,EACH,CAFD,IAEO,CACHoE,CAAc,CAAC3F,IAAf,CAA2BgD,CAAM,CAAC3E,IAAP,CAAY,OAAZ,CAA3B,IACH,CACJ,CAPD,EASA,GAAI,CAACY,CAAO,CAACqF,QAAT,EAAkE,CAA7C,GAAApF,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCD,MAA3D,CAAyE,CAIrE,GAAIgF,CAAAA,CAAM,CAAG1G,CAAC,CAAC,UAAD,CAAd,CACA4C,CAAc,CAACqF,MAAf,CAAsBvB,CAAtB,CACH,CACD,GAAI1G,CAAC,CAACuJ,OAAF,CAAUJ,CAAV,CAAJ,CAAiC,CAE7BnJ,CAAC,CAACoD,IAAF,CAAO+F,CAAP,CAAyB,SAASK,CAAT,CAAsBC,CAAtB,CAA8B,CACnD,GAAqD,CAAC,CAAlD,GAAAJ,CAAc,CAAC5E,OAAf,CAA8BgF,CAAM,CAAC9F,KAArC,IAAJ,CAAyD,CACrD,GAAI+C,CAAAA,CAAM,CAAG1G,CAAC,CAAC,UAAD,CAAd,CACA0G,CAAM,CAACuB,MAAP,CAAcwB,CAAM,CAAClG,KAArB,EACAmD,CAAM,CAAC3E,IAAP,CAAY,OAAZ,CAAqB0H,CAAM,CAAC9F,KAA5B,EACAf,CAAc,CAACqF,MAAf,CAAsBvB,CAAtB,CACH,CACJ,CAPD,EAQA9D,CAAc,CAACb,IAAf,CAAoB,aAApB,CAAmC,EAAnC,CACH,CAXD,IAWO,CAEHa,CAAc,CAACb,IAAf,CAAoB,aAApB,CAAmCoH,CAAnC,CACH,CAEDV,CAAc,CAACxG,OAAf,CAAuBqE,CAAiB,CAAC3D,CAAD,CAAUtB,CAAV,CAAiB,EAAjB,CAAqBuB,CAArB,CAAxC,CACH,CA1CD,CA0CG,SAAS8G,CAAT,CAAgB,CACfjB,CAAc,CAACkB,MAAf,CAAsBD,CAAtB,CACH,CA5CD,EA8CA,MAAOjB,CAAAA,CACV,CAppB6D,CA+pB1DmB,CAAa,CAAG,SAASjH,CAAT,CAAkBtB,CAAlB,CAAyBuB,CAAzB,CAAyC,CAEzD,GAAIuC,CAAAA,CAAY,CAAGnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CAApB,CAEAqC,CAAY,CAAC0E,EAAb,CAAgB,SAAhB,CAA2B,SAAStB,CAAT,CAAY,CACnC,GAAIuB,CAAAA,CAAgB,CAAGpB,CAAmB,CAAC,iBAAmBrH,CAAK,CAACyB,OAAzB,CAAmC,GAAnC,CAAyCyF,CAAC,CAACwB,OAA5C,CAA1C,CAEA,OAAQxB,CAAC,CAACwB,OAAV,EACI,IAAKxJ,CAAAA,CAAI,CAACC,IAAV,CAEI,GAAI,CAACmC,CAAO,CAACqH,eAAb,CAA8B,CAE1BF,CAAgB,CAAC7H,OAAjB,GACA,QACH,CAJD,IAIO,IAA2C,MAAvC,GAAAkD,CAAY,CAACpD,IAAb,CAAkB,eAAlB,CAAJ,CAAmD,CACtD+H,CAAgB,CAAC7H,OAAjB,CAAyB6D,CAAgB,CAACzE,CAAD,CAAzC,CACH,CAFM,IAEA,CAEH,GAAI,CAAC8D,CAAY,CAACuC,GAAb,EAAD,EAAuB/E,CAAO,CAACsH,IAAnC,CAAyC,CACrCC,OAAO,CAAC,CAACvH,CAAO,CAACsH,IAAT,CAAD,CAAiB,SAASzB,CAAT,CAAsB,CAC1CsB,CAAgB,CAAC7H,OAAjB,CAAyBqG,CAAU,CAACC,CAAD,CAAI5F,CAAJ,CAAatB,CAAb,CAAoBuB,CAApB,CAAoC4F,CAApC,CAAnC,CACH,CAFM,CAGV,CAJD,IAIO,CAEHsB,CAAgB,CAAC7H,OAAjB,CAAyBqE,CAAiB,CAAC3D,CAAD,CAAUtB,CAAV,CAAiB8D,CAAY,CAACuC,GAAb,EAAjB,CAAqC9E,CAArC,CAA1C,CACH,CACJ,CAED2F,CAAC,CAAC4B,cAAF,GACA,SACJ,IAAK5J,CAAAA,CAAI,CAACM,EAAV,CAEIiJ,CAAgB,CAAC7H,OAAjB,CAAyBkE,CAAoB,CAAC9E,CAAD,CAA7C,EAGAkH,CAAC,CAAC4B,cAAF,GACA,SACJ,IAAK5J,CAAAA,CAAI,CAACE,KAAV,CACI,GAAI2E,CAAAA,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAA1B,CACA,GAA4C,MAAvC,GAAAF,CAAY,CAACpD,IAAb,CAAkB,eAAlB,CAAD,EACkE,CAA7D,CAAAqD,CAAkB,CAACzD,QAAnB,CAA4B,sBAA5B,EAAoDD,MAD7D,CAC0E,CAEtEoI,CAAgB,CAAC7H,OAAjB,CAAyBkG,CAAiB,CAACxF,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAA1C,CACH,CAJD,IAIO,IAAID,CAAO,CAAC0E,IAAZ,CAAkB,CAErByC,CAAgB,CAAC7H,OAAjB,CAAyBwF,CAAU,CAAC9E,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAAnC,CACH,CAHM,IAGA,CACHkH,CAAgB,CAAC7H,OAAjB,EACH,CAGDsG,CAAC,CAAC4B,cAAF,GACA,SACJ,IAAK5J,CAAAA,CAAI,CAACI,MAAV,CACI,GAA2C,MAAvC,GAAAwE,CAAY,CAACpD,IAAb,CAAkB,eAAlB,CAAJ,CAAmD,CAE/C+H,CAAgB,CAAC7H,OAAjB,CAAyBmE,CAAgB,CAAC/E,CAAD,CAAzC,CACH,CAHD,IAGO,CACHyI,CAAgB,CAAC7H,OAAjB,EACH,CAEDsG,CAAC,CAAC4B,cAAF,GACA,SAvDR,CAyDAL,CAAgB,CAAC7H,OAAjB,GACA,QACH,CA9DD,EAgEAkD,CAAY,CAAC0E,EAAb,CAAgB,UAAhB,CAA4B,SAAStB,CAAT,CAAY,CAEpC,GAAIA,CAAC,CAACwB,OAAF,GAAcxJ,CAAI,CAACK,KAAvB,CAA8B,CAC1B,GAAI+B,CAAO,CAAC0E,IAAZ,CAAkB,CAEdqB,CAAmB,CAAC,YAAcH,CAAC,CAACwB,OAAjB,CAAnB,CACC9H,OADD,CACSwF,CAAU,CAAC9E,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CADnB,CAEH,CAED2F,CAAC,CAAC4B,cAAF,GACA,QACH,CACD,QACH,CAbD,EAgBAhF,CAAY,CAACiF,OAAb,CAAqB,MAArB,EAA6BP,EAA7B,CAAgC,QAAhC,CAA0C,UAAW,CACjD,GAAIlH,CAAO,CAAC0E,IAAZ,CAAkB,CAEdqB,CAAmB,CAAC,0BAAD,CAAnB,CACCzG,OADD,CACSwF,CAAU,CAAC9E,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CADnB,CAEH,CAED,QACH,CARD,EASAuC,CAAY,CAAC0E,EAAb,CAAgB,MAAhB,CAAwB,UAAW,CAC/B,GAAIpB,CAAAA,CAAc,CAAGC,CAAmB,CAAC,wBAAD,CAAxC,CACA2B,MAAM,CAACC,UAAP,CAAkB,UAAW,IAErBC,CAAAA,CAAY,CAAGvK,CAAC,CAACuB,QAAQ,CAACc,aAAV,CAFK,CAGrBmI,CAAc,CAAGxK,CAAC,CAACgC,QAAF,EAHI,CASzB,GAAIuI,CAAY,CAACE,EAAb,CAAgBlJ,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAhB,CAAJ,CAAmE,CAC/DF,CAAY,CAACkD,KAAb,EACH,CAFD,IAEO,IAAI,CAACkC,CAAY,CAACE,EAAb,CAAgBtF,CAAhB,CAAD,EAAkCnF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACyB,OAA9B,CAAD,CAAD,CAA0CpB,MAAhF,CAAwF,CAC3F,GAAIiB,CAAO,CAAC0E,IAAZ,CAAkB,CACdmD,CAAc,CAACtG,IAAf,CAAoB,UAAW,CAC3B,MAAOuD,CAAAA,CAAU,CAAC9E,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CACpB,CAFD,EAGCyB,KAHD,EAIH,CACDmG,CAAc,CAACtG,IAAf,CAAoB,UAAW,CAC3B,MAAOkC,CAAAA,CAAgB,CAAC/E,CAAD,CAC1B,CAFD,EAGCgD,KAHD,EAIH,CAEDmG,CAAc,CAACtG,IAAf,CAAoB,UAAW,CAC3B,MAAOuE,CAAAA,CAAc,CAACxG,OAAf,EACV,CAFD,EAGCoC,KAHD,GAIAmG,CAAc,CAACvI,OAAf,EACH,CA7BD,CA6BG,GA7BH,CA8BH,CAhCD,EAiCA,GAAIU,CAAO,CAACqH,eAAZ,CAA6B,CACzB,GAAIU,CAAAA,CAAY,CAAG1K,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsJ,WAA9B,CAAD,CAApB,CACAD,CAAY,CAACb,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,CACjC,GAAIE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,oCAAD,CAAxC,CAGAvD,CAAY,CAACkD,KAAb,GAGA,GAAI,CAAClD,CAAY,CAACuC,GAAb,EAAD,EAAuB/E,CAAO,CAACsH,IAAnC,CAAyC,CACrCC,OAAO,CAAC,CAACvH,CAAO,CAACsH,IAAT,CAAD,CAAiB,SAASzB,CAAT,CAAsB,CAC1CC,CAAc,CAACxG,OAAf,CAAuBqG,CAAU,CAACC,CAAD,CAAI5F,CAAJ,CAAatB,CAAb,CAAoBuB,CAApB,CAAoC4F,CAApC,CAAjC,CACH,CAFM,CAGV,CAJD,IAIO,CAEHC,CAAc,CAACxG,OAAf,CAAuBqE,CAAiB,CAAC3D,CAAD,CAAUtB,CAAV,CAAiB8D,CAAY,CAACuC,GAAb,EAAjB,CAAqC9E,CAArC,CAAxC,CACH,CACJ,CAfD,CAgBH,CAED,GAAIwC,CAAAA,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAA1B,CAEAD,CAAkB,CAACyD,MAAnB,GAA4BvF,IAA5B,CAAiC,SAAjC,CAA4C,IAA5C,EAAkDsH,GAAlD,CAAsD,OAAtD,EACAxF,CAAkB,CAACyD,MAAnB,GAA4BgB,EAA5B,CAA+B,OAA/B,YAA4CxI,CAAK,CAACgE,aAAlD,mBAAiF,SAASkD,CAAT,CAAY,IACrFE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,0BAAD,CADiD,CAGrF9G,CAAO,CAAG5B,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBqB,OAAnB,CAA2B,eAA3B,CAH2E,CAIrFhF,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAJ+D,CAMrFU,CAAO,CAAGX,CAAkB,CAACzD,QAAnB,CAA4B,qBAA5B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CAN2E,CASzFsD,CAAY,CAACa,CAAD,CAAU1E,CAAV,CAAZ,CACC6C,IADD,CACM,UAAW,CAEb,MAAOiE,CAAAA,CAAiB,CAACxF,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAC3B,CAJD,EAKCsB,IALD,CAKM,UAAW,CACb,MAAOuE,CAAAA,CAAc,CAACxG,OAAf,EACV,CAPD,EAQCoC,KARD,EASH,CAlBD,EAmBA,GAAI/C,CAAAA,CAAgB,CAAGtB,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAAxB,CAGAH,CAAgB,CAACuI,EAAjB,CAAoB,OAApB,CAA6B,eAA7B,CAA8C,SAAStB,CAAT,CAAY,CACtD,GAAIE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,0BAAD,CAAxC,CAGAD,CAAc,CAACxG,OAAf,CAAuB8C,CAAY,CAACpC,CAAD,CAAUtB,CAAV,CAAiBrB,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAlB,CAAqCnG,CAArC,CAAnC,CACH,CALD,EAQAtB,CAAgB,CAACuI,EAAjB,CAAoB,OAApB,CAA6B,UAAW,CACpCrH,CAA8B,CAACnB,CAAD,CACjC,CAFD,EAKAC,CAAgB,CAACuI,EAAjB,CAAoB,SAApB,CAA+B,SAAStB,CAAT,CAAY,CACvC,GAAIE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,6BAA+BH,CAAC,CAACwB,OAAlC,CAAxC,CACA,OAAQxB,CAAC,CAACwB,OAAV,EACI,IAAKxJ,CAAAA,CAAI,CAACQ,KAAV,CACA,IAAKR,CAAAA,CAAI,CAACC,IAAV,CAEI+H,CAAC,CAAC4B,cAAF,GAGA1B,CAAc,CAACxG,OAAf,CAAuBiE,CAAqB,CAAC7E,CAAD,CAA5C,EACA,OACJ,IAAKd,CAAAA,CAAI,CAACO,IAAV,CACA,IAAKP,CAAAA,CAAI,CAACM,EAAV,CAEI0H,CAAC,CAAC4B,cAAF,GAGA1B,CAAc,CAACxG,OAAf,CAAuB+D,CAAyB,CAAC3E,CAAD,CAAhD,EACA,OACJ,IAAKd,CAAAA,CAAI,CAACG,KAAV,CACA,IAAKH,CAAAA,CAAI,CAACE,KAAV,CAEI,GAAIoK,CAAAA,CAAY,CAAG7K,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAAD,CAA8CE,QAA9C,CAAuD,yBAAvD,CAAnB,CACA,GAAIkJ,CAAJ,CAAkB,CACdtC,CAAC,CAAC4B,cAAF,GAGA1B,CAAc,CAACxG,OAAf,CAAuB8C,CAAY,CAACpC,CAAD,CAAUtB,CAAV,CAAiBwJ,CAAjB,CAA+BjI,CAA/B,CAAnC,CACH,CACD,OA3BR,CA+BA6F,CAAc,CAACxG,OAAf,EACH,CAlCD,EAoCA,GAAIU,CAAO,CAACqH,eAAZ,CAA6B,CAEzB7E,CAAY,CAAC0E,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,CACjC,GAAIhC,CAAAA,CAAK,CAAGvG,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EAAZ,CACA1H,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBvF,IAAnB,CAAwB,YAAxB,CAAsC+C,CAAtC,CACH,CAHD,EAMA,GAAI5D,CAAO,CAACsH,IAAZ,CAAkB,CACdC,OAAO,CAAC,CAACvH,CAAO,CAACsH,IAAT,CAAD,CAAiB,SAASzB,CAAT,CAAsB,IAKtCsC,CAAAA,CAAe,CAAG,IALoB,CAMtCC,CAAU,GAN4B,CAOtClI,CAAU,CAAG,+BAPyB,CAQtCmI,CAAO,CAAG,SAASzC,CAAT,CAAY,CAEtBuC,CAAe,CAAG,IAAlB,CAGAC,CAAU,GAAV,CAGAzC,CAAU,CAACC,CAAD,CAAI5F,CAAJ,CAAatB,CAAb,CAAoBuB,CAApB,CAAoC4F,CAApC,CAAV,CACCtE,IADD,CACM,UAAW,CAMb,GAAI,OAAS4G,CAAb,CAA8B,CAE1B/H,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,CACH,CACDkI,CAAU,GAAV,CAEA,MAAOE,CAAAA,SAAS,CAAC,CAAD,CACnB,CAdD,EAeC5G,KAfD,CAeOjE,CAAY,CAACkE,SAfpB,CAgBH,CAhCyC,CAmCtC4G,CAAgB,CAAG,SAAS3C,CAAT,CAAY,CAC/B8B,MAAM,CAACc,YAAP,CAAoBL,CAApB,EACA,GAAIC,CAAJ,CAAgB,CAGZD,CAAe,CAAGT,MAAM,CAACC,UAAP,CAAkBY,CAAgB,CAACE,IAAjB,CAAsB,IAAtB,CAA4B7C,CAA5B,CAAlB,CAAkD,GAAlD,CAAlB,CACA,MACH,CAED,GAAwB,IAApB,GAAAuC,CAAJ,CAA8B,CAG1B/H,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,CACH,CAKDiI,CAAe,CAAGT,MAAM,CAACC,UAAP,CAAkBU,CAAO,CAACI,IAAR,CAAa,IAAb,CAAmB7C,CAAnB,CAAlB,CAAyC,GAAzC,CACrB,CAtDyC,CAyD1CpD,CAAY,CAAC0E,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,IAC7BhC,CAAAA,CAAK,CAAGvG,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EADqB,CAE7B2D,CAAI,CAAGrL,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBvF,IAAnB,CAAwB,YAAxB,CAFsB,CAIjC,GAAI6H,CAAI,GAAK9E,CAAb,CAAoB,CAChB2E,CAAgB,CAAC3C,CAAD,CACnB,CACDvI,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBvF,IAAnB,CAAwB,YAAxB,CAAsC+C,CAAtC,CACH,CARD,CASH,CAlEM,CAmEV,CApED,IAoEO,CACHpB,CAAY,CAAC0E,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,IAC7BhC,CAAAA,CAAK,CAAGvG,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EADqB,CAE7B2D,CAAI,CAAGrL,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBvF,IAAnB,CAAwB,YAAxB,CAFsB,CAQjC,GAAI6H,CAAI,GAAK9E,CAAb,CAAoB,CAChBD,CAAiB,CAAC3D,CAAD,CAAUtB,CAAV,CAAiBkF,CAAjB,CAAwB3D,CAAxB,CACpB,CACD5C,CAAC,CAACuI,CAAC,CAACQ,aAAH,CAAD,CAAmBvF,IAAnB,CAAwB,YAAxB,CAAsC+C,CAAtC,CACH,CAZD,CAaH,CACJ,CACJ,CAv9B6D,CA+9B1DmC,CAAmB,CAAG,SAAS4C,CAAT,CAAc,CAChC,GAAIzI,CAAAA,CAAU,CAAG,qBAAuByI,CAAxC,CAEAvI,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EAEA,GAAI4F,CAAAA,CAAc,CAAGzI,CAAC,CAACgC,QAAF,EAArB,CAEAyG,CAAc,CACbvE,IADD,CACM,UAAW,CACbnB,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,EAEA,MAAOoI,CAAAA,SAAS,CAAC,CAAD,CACnB,CALD,EAMC5G,KAND,CAMOjE,CAAY,CAACkE,SANpB,EAQA,MAAOmE,CAAAA,CACd,CA/+B6D,CAi/B9D,MAAO,CAmBH8C,OAAO,CAAE,iBAAStC,CAAT,CAAmB5B,CAAnB,CAAyB4C,CAAzB,CAA+BuB,CAA/B,CAA4C3E,CAA5C,CAA2DmD,CAA3D,CAA4EyB,CAA5E,CACSrD,CADT,CACmCsD,CADnC,CACsD,IAEvD/I,CAAAA,CAAO,CAAG,CACVsG,QAAQ,CAAEA,CADA,CAEV5B,IAAI,GAFM,CAGV4C,IAAI,GAHM,CAIVuB,WAAW,CAAEA,CAJH,CAKV3E,aAAa,GALH,CAMVmD,eAAe,GANL,CAOVyB,iBAAiB,CAAEA,CAPT,CAQVtL,SAAS,CAAEH,CAAC,CAACgE,MAAF,CAAS,CACZ2H,KAAK,CAAE,8BADK,CAEZzI,KAAK,CAAE,wCAFK,CAGZ0I,MAAM,CAAE,+BAHI,CAIZC,SAAS,CAAE,kCAJC,CAKZpF,WAAW,CAAE,oCALD,CAAT,CAMJiF,CANI,CARD,CAF6C,CAkBvD7I,CAAU,CAAG,sBAAwBoG,CAlBkB,CAmB3DlG,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EACA,GAAoB,WAAhB,QAAOwE,CAAAA,CAAX,CAAiC,CAC7B1E,CAAO,CAAC0E,IAAR,CAAeA,CAClB,CACD,GAAoB,WAAhB,QAAO4C,CAAAA,CAAX,CAAiC,CAC7BtH,CAAO,CAACsH,IAAR,CAAeA,CAClB,CACD,GAA6B,WAAzB,QAAOpD,CAAAA,CAAX,CAA0C,CACtClE,CAAO,CAACkE,aAAR,CAAwBA,CAC3B,CACD,GAA+B,WAA3B,QAAOmD,CAAAA,CAAX,CAA4C,CACxCrH,CAAO,CAACqH,eAAR,CAA0BA,CAC7B,CACD,GAAiC,WAA7B,QAAOyB,CAAAA,CAAX,CAA8C,CAC1CvL,CAAG,CAACoH,UAAJ,CAAe,aAAf,CAA8B,MAA9B,EAAsCC,IAAtC,CAA2C,SAASkC,CAAT,CAAiB,CACxD9G,CAAO,CAAC8I,iBAAR,CAA4BhC,CAC/B,CAFD,EAEGqC,IAFH,CAEQ1L,CAAY,CAACkE,SAFrB,CAGH,CAGD,GAAI1B,CAAAA,CAAc,CAAG5C,CAAC,CAACiJ,CAAD,CAAtB,CACA,GAAI,CAACrG,CAAL,CAAqB,CACjB3C,CAAG,CAAC8L,KAAJ,CAAU,uBAAyB9C,CAAnC,EACAlG,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,EACA,QACH,CAEDvC,CAAI,CAAC+F,IAAL,CAAUzD,CAAc,CAACf,GAAf,EAAV,EACAe,CAAc,CAACoJ,GAAf,CAAmB,YAAnB,CAAiC,QAAjC,EAKA,GAAI3K,CAAAA,CAAK,CAAG,CACRuH,QAAQ,CAAEhG,CAAc,CAACb,IAAf,CAAoB,IAApB,CADF,CAERe,OAAO,CAAE,2BAA6B9B,CAF9B,CAGRqE,aAAa,CAAE,iCAAmCrE,CAH1C,CAIRS,WAAW,CAAE,+BAAiCT,CAJtC,CAKR2J,WAAW,CAAE,+BAAiC3J,CALtC,CAMRkC,KAAK,CAAE,EANC,CAAZ,CAUAlC,CAAQ,GAER2B,CAAO,CAACqF,QAAR,CAAmBpF,CAAc,CAACb,IAAf,CAAoB,UAApB,CAAnB,CACA,GAAI,CAACY,CAAO,CAACqF,QAAb,CAAuB,CAInBpF,CAAc,CAACqJ,OAAf,CAAuB,UAAvB,CACH,CAED,GAAwC,WAApC,QAAO7D,CAAAA,CAAX,CAAqD,CACjDzF,CAAO,CAACyF,wBAAR,CAAmCA,CACtC,CAFD,IAEO,CAEHzF,CAAO,CAACyF,wBAAR,CAAmC,CAACzF,CAAO,CAACqF,QAC/C,CA7E0D,GA+EvDkE,CAAAA,CAAa,CAAGlM,CAAC,CAAC,QAAUqB,CAAK,CAACuH,QAAhB,CAA2B,GAA5B,CA/EsC,CAiFvDnC,CAAW,CAAG,EAjFyC,CAkF3D7D,CAAc,CAACjB,QAAf,CAAwB,QAAxB,EAAkCyB,IAAlC,CAAuC,SAAShC,CAAT,CAAgBsF,CAAhB,CAAwB,CAC3DD,CAAW,CAACrF,CAAD,CAAX,CAAqB,CAACmC,KAAK,CAAEmD,CAAM,CAACC,SAAf,CAA0BhD,KAAK,CAAE3D,CAAC,CAAC0G,CAAD,CAAD,CAAU3E,IAAV,CAAe,OAAf,CAAjC,CACxB,CAFD,EAKA,GAAIgC,CAAAA,CAAO,CAAG/D,CAAC,CAACgE,MAAF,CAAS,EAAT,CAAarB,CAAb,CAAsBtB,CAAtB,CAAd,CACA0C,CAAO,CAACpB,OAAR,CAAkB8D,CAAlB,CACA1C,CAAO,CAACb,KAAR,CAAgB,EAAhB,CAzF2D,GA4FvDiJ,CAAAA,CAAW,CAAG,EA5FyC,CA8FvDC,CAAY,CAAGjM,CAAS,CAAC8D,MAAV,CAAiBtB,CAAO,CAACxC,SAAR,CAAkByL,MAAnC,CAA2C,EAA3C,EAClB1H,IADkB,CACb,SAAST,CAAT,CAAe,CACjB,MAAOzD,CAAAA,CAAC,CAACyD,CAAD,CACX,CAHkB,CA9FwC,CAmGvD4I,CAAW,CAAGlM,CAAS,CAAC8D,MAAV,CAAiBtB,CAAO,CAACxC,SAAR,CAAkBwL,KAAnC,CAA0C5H,CAA1C,EAAmDG,IAAnD,CAAwD,SAAST,CAAT,CAAeU,CAAf,CAAmB,CACzFgI,CAAW,EAAIhI,CAAf,CACA,MAAOnE,CAAAA,CAAC,CAACyD,CAAD,CACX,CAHiB,CAnGyC,CAwGvD6I,CAAc,CAAGnM,CAAS,CAAC8D,MAAV,CAAiBtB,CAAO,CAACxC,SAAR,CAAkBsG,WAAnC,CAAgD1C,CAAhD,EAAyDG,IAAzD,CAA8D,SAAST,CAAT,CAAeU,CAAf,CAAmB,CAClGgI,CAAW,EAAIhI,CAAf,CACA,MAAOnE,CAAAA,CAAC,CAACyD,CAAD,CACX,CAHoB,CAxGsC,CA6GvD8I,CAAe,CAAGpM,CAAS,CAAC8D,MAAV,CAAiBtB,CAAO,CAACxC,SAAR,CAAkB0L,SAAnC,CAA8C9H,CAA9C,EAAuDG,IAAvD,CAA4D,SAAST,CAAT,CAAeU,CAAf,CAAmB,CACjGgI,CAAW,EAAIhI,CAAf,CACA,MAAOnE,CAAAA,CAAC,CAACyD,CAAD,CACX,CAHqB,CA7GqC,CAkH3D,MAAOzD,CAAAA,CAAC,CAACwM,IAAF,CAAOJ,CAAP,CAAqBC,CAArB,CAAkCC,CAAlC,CAAkDC,CAAlD,EACNrI,IADM,CACD,SAAS0H,CAAT,CAAiBD,CAAjB,CAAwBlF,CAAxB,CAAqCoF,CAArC,CAAgD,CAClDjJ,CAAc,CAACyD,IAAf,GACA,GAAIoG,CAAAA,CAAS,CAAG7J,CAAc,CAACiG,MAAf,EAAhB,CAGA8C,CAAK,CAACpJ,IAAN,CAAW,OAAX,EAAoBR,IAApB,CAAyB,gBAAzB,CAA2C,cAA3C,EAEA0K,CAAS,CAACxE,MAAV,CAAiB2D,CAAjB,EACAa,CAAS,CAAClK,IAAV,CAAe,2CAAf,EAA0DmK,WAA1D,CAAsEf,CAAtE,EACAc,CAAS,CAAClK,IAAV,CAAe,iDAAf,EAAgEmK,WAAhE,CAA4EjG,CAA5E,EACAgG,CAAS,CAAClK,IAAV,CAAe,+CAAf,EAA8DmK,WAA9D,CAA0Eb,CAA1E,EAEA1L,CAAS,CAACwM,aAAV,CAAwBR,CAAxB,EAGAD,CAAa,CAACnK,IAAd,CAAmB,KAAnB,CAA0BV,CAAK,CAACyB,OAAhC,EAEA8G,CAAa,CAACjH,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAAb,CAEA,GAAIwC,CAAAA,CAAkB,CAAGpF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACgE,aAA9B,CAAD,CAA1B,CAEAD,CAAkB,CAACiB,IAAnB,GACA/F,CAAI,CAAC+F,IAAL,CAAUjB,CAAkB,CAACvD,GAAnB,EAAV,CAGH,CA1BM,EA2BNqC,IA3BM,CA2BD,UAAW,CAEb,MAAOxB,CAAAA,CAAmB,CAACC,CAAD,CAAUtB,CAAV,CAAiBuB,CAAjB,CAC7B,CA9BM,EA+BNsB,IA/BM,CA+BD,UAAW,CACb,MAAOnB,CAAAA,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,CACV,CAjCM,EAkCNwB,KAlCM,CAkCA,SAASqF,CAAT,CAAgB,CACnB3G,CAAC,CAACC,IAAF,CAAOa,WAAP,CAAmBhB,CAAnB,EACAzC,CAAY,CAACkE,SAAb,CAAuBoF,CAAvB,CACH,CArCM,CAsCV,CA5KE,CA8KV,CAjqCK,CAAN","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 * Autocomplete wrapper for select2 library.\n *\n * @module core/form-autocomplete\n * @copyright 2015 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.0\n */\ndefine(\n ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\n\n // Private functions and variables.\n /** @var {Object} KEYS - List of keycode constants. */\n var KEYS = {\n DOWN: 40,\n ENTER: 13,\n SPACE: 32,\n ESCAPE: 27,\n COMMA: 44,\n UP: 38,\n LEFT: 37,\n RIGHT: 39\n };\n\n var uniqueId = Date.now();\n\n /**\n * Make an item in the selection list \"active\".\n *\n * @method activateSelection\n * @private\n * @param {Number} index The index in the current (visible) list of selection.\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n */\n var activateSelection = function(index, state) {\n // Find the elements in the DOM.\n var selectionElement = $(document.getElementById(state.selectionId));\n\n // Count the visible items.\n var length = selectionElement.children('[aria-selected=true]').length;\n // Limit the index to the upper/lower bounds of the list (wrap in both directions).\n index = index % length;\n while (index < 0) {\n index += length;\n }\n // Find the specified element.\n var element = $(selectionElement.children('[aria-selected=true]').get(index));\n // Create an id we can assign to this element.\n var itemId = state.selectionId + '-' + index;\n\n // Deselect all the selections.\n selectionElement.children().attr('data-active-selection', null).attr('id', '');\n\n // Select only this suggestion and assign it the id.\n element.attr('data-active-selection', true).attr('id', itemId);\n\n // Tell the input field it has a new active descendant so the item is announced.\n selectionElement.attr('aria-activedescendant', itemId);\n selectionElement.attr('data-active-value', element.attr('data-value'));\n\n return $.Deferred().resolve();\n };\n\n /**\n * Get the actively selected element from the state object.\n *\n * @param {Object} state\n * @returns {jQuery}\n */\n var getActiveElementFromState = function(state) {\n var selectionRegion = $(document.getElementById(state.selectionId));\n var activeId = selectionRegion.attr('aria-activedescendant');\n\n if (activeId) {\n var activeElement = $(document.getElementById(activeId));\n if (activeElement.length) {\n // The active descendent still exists.\n return activeElement;\n }\n }\n\n var activeValue = selectionRegion.attr('data-active-value');\n return selectionRegion.find('[data-value=\"' + activeValue + '\"]');\n };\n\n /**\n * Update the active selection from the given state object.\n *\n * @param {Object} state\n */\n var updateActiveSelectionFromState = function(state) {\n var activeElement = getActiveElementFromState(state);\n var activeValue = activeElement.attr('data-value');\n\n var selectionRegion = $(document.getElementById(state.selectionId));\n if (activeValue) {\n // Find the index of the currently selected index.\n var activeIndex = selectionRegion.find('[aria-selected=true]').index(activeElement);\n\n if (activeIndex !== -1) {\n activateSelection(activeIndex, state);\n return;\n }\n }\n\n // Either the active index was not set, or it could not be found.\n // Select the first value instead.\n activateSelection(0, state);\n };\n\n /**\n * Update the element that shows the currently selected items.\n *\n * @method updateSelectionList\n * @private\n * @param {Object} options Original options for this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var updateSelectionList = function(options, state, originalSelect) {\n var pendingKey = 'form-autocomplete-updateSelectionList-' + state.inputId;\n M.util.js_pending(pendingKey);\n\n // Build up a valid context to re-render the template.\n var items = [];\n var newSelection = $(document.getElementById(state.selectionId));\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).prop('selected')) {\n var label;\n if ($(ele).data('html')) {\n label = $(ele).data('html');\n } else {\n label = $(ele).html();\n }\n if (label !== '') {\n items.push({label: label, value: $(ele).attr('value')});\n }\n }\n });\n\n if (!hasItemListChanged(state, items)) {\n M.util.js_complete(pendingKey);\n return Promise.resolve();\n }\n\n state.items = items;\n\n var context = $.extend(options, state);\n // Render the template.\n return templates.render(options.templates.items, context)\n .then(function(html, js) {\n // Add it to the page.\n templates.replaceNodeContents(newSelection, html, js);\n\n updateActiveSelectionFromState(state);\n\n return;\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(notification.exception);\n };\n\n /**\n * Check whether the list of items stored in the state has changed.\n *\n * @param {Object} state\n * @param {Array} items\n * @returns {Boolean}\n */\n var hasItemListChanged = function(state, items) {\n if (state.items.length !== items.length) {\n return true;\n }\n\n // Check for any items in the state items which are not present in the new items list.\n return state.items.filter(item => items.indexOf(item) === -1).length > 0;\n };\n\n /**\n * Notify of a change in the selection.\n *\n * @param {jQuery} originalSelect The jQuery object matching the hidden select list.\n */\n var notifyChange = function(originalSelect) {\n if (typeof M.core_formchangechecker !== 'undefined') {\n M.core_formchangechecker.set_form_changed();\n }\n\n // Note, jQuery .change() was not working here. Better to\n // use plain JavaScript anyway.\n originalSelect[0].dispatchEvent(new Event('change'));\n };\n\n /**\n * Remove the given item from the list of selected things.\n *\n * @method deselectItem\n * @private\n * @param {Object} options Original options for this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {Element} item The item to be deselected.\n * @param {Element} originalSelect The original select list.\n * @return {Promise}\n */\n var deselectItem = function(options, state, item, originalSelect) {\n var selectedItemValue = $(item).attr('data-value');\n\n // Look for a match, and toggle the selected property if there is a match.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == selectedItemValue) {\n $(ele).prop('selected', false);\n // We remove newly created custom tags from the suggestions list when they are deselected.\n if ($(ele).attr('data-iscustom')) {\n $(ele).remove();\n }\n }\n });\n // Rerender the selection list.\n return updateSelectionList(options, state, originalSelect)\n .then(function() {\n // Notify that the selection changed.\n notifyChange(originalSelect);\n\n return;\n });\n };\n\n /**\n * Make an item in the suggestions \"active\" (about to be selected).\n *\n * @method activateItem\n * @private\n * @param {Number} index The index in the current (visible) list of suggestions.\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n */\n var activateItem = function(index, state) {\n // Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Count the visible items.\n var length = suggestionsElement.children(':not([aria-hidden])').length;\n // Limit the index to the upper/lower bounds of the list (wrap in both directions).\n index = index % length;\n while (index < 0) {\n index += length;\n }\n // Find the specified element.\n var element = $(suggestionsElement.children(':not([aria-hidden])').get(index));\n // Find the index of this item in the full list of suggestions (including hidden).\n var globalIndex = $(suggestionsElement.children('[role=option]')).index(element);\n // Create an id we can assign to this element.\n var itemId = state.suggestionsId + '-' + globalIndex;\n\n // Deselect all the suggestions.\n suggestionsElement.children().attr('aria-selected', false).attr('id', '');\n // Select only this suggestion and assign it the id.\n element.attr('aria-selected', true).attr('id', itemId);\n // Tell the input field it has a new active descendant so the item is announced.\n inputElement.attr('aria-activedescendant', itemId);\n\n // Scroll it into view.\n var scrollPos = element.offset().top\n - suggestionsElement.offset().top\n + suggestionsElement.scrollTop()\n - (suggestionsElement.height() / 2);\n return suggestionsElement.animate({\n scrollTop: scrollPos\n }, 100).promise();\n };\n\n /**\n * Find the index of the current active suggestion, and activate the next one.\n *\n * @method activateNextItem\n * @private\n * @param {Object} state State variable for this auto complete element.\n * @return {Promise}\n */\n var activateNextItem = function(state) {\n // Find the list of suggestions.\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Find the active one.\n var element = suggestionsElement.children('[aria-selected=true]');\n // Find it's index.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n // Activate the next one.\n return activateItem(current + 1, state);\n };\n\n /**\n * Find the index of the current active selection, and activate the previous one.\n *\n * @method activatePreviousSelection\n * @private\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n */\n var activatePreviousSelection = function(state) {\n // Find the list of selections.\n var selectionsElement = $(document.getElementById(state.selectionId));\n // Find the active one.\n var element = selectionsElement.children('[data-active-selection]');\n if (!element) {\n return activateSelection(0, state);\n }\n // Find it's index.\n var current = selectionsElement.children('[aria-selected=true]').index(element);\n // Activate the next one.\n return activateSelection(current - 1, state);\n };\n\n /**\n * Find the index of the current active selection, and activate the next one.\n *\n * @method activateNextSelection\n * @private\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n */\n var activateNextSelection = function(state) {\n // Find the list of selections.\n var selectionsElement = $(document.getElementById(state.selectionId));\n\n // Find the active one.\n var element = selectionsElement.children('[data-active-selection]');\n var current = 0;\n\n if (element) {\n // The element was found. Determine the index and move to the next one.\n current = selectionsElement.children('[aria-selected=true]').index(element);\n current = current + 1;\n } else {\n // No selected item found. Move to the first.\n current = 0;\n }\n\n return activateSelection(current, state);\n };\n\n /**\n * Find the index of the current active suggestion, and activate the previous one.\n *\n * @method activatePreviousItem\n * @private\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n */\n var activatePreviousItem = function(state) {\n // Find the list of suggestions.\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Find the active one.\n var element = suggestionsElement.children('[aria-selected=true]');\n\n // Find it's index.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n // Activate the previous one.\n return activateItem(current - 1, state);\n };\n\n /**\n * Close the list of suggestions.\n *\n * @method closeSuggestions\n * @private\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n */\n var closeSuggestions = function(state) {\n // Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n if (inputElement.attr('aria-expanded') === \"true\") {\n // Announce the list of suggestions was closed.\n inputElement.attr('aria-expanded', false);\n }\n // Read the current list of selections.\n inputElement.attr('aria-activedescendant', state.selectionId);\n\n // Hide the suggestions list (from screen readers too).\n Aria.hide(suggestionsElement.get());\n suggestionsElement.hide();\n\n return $.Deferred().resolve();\n };\n\n /**\n * Rebuild the list of suggestions based on the current values in the select list, and the query.\n *\n * @method updateSuggestions\n * @private\n * @param {Object} options The original options for this autocomplete.\n * @param {Object} state The state variables for this autocomplete.\n * @param {String} query The current text for the search string.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var updateSuggestions = function(options, state, query, originalSelect) {\n var pendingKey = 'form-autocomplete-updateSuggestions-' + state.inputId;\n M.util.js_pending(pendingKey);\n\n // Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Used to track if we found any visible suggestions.\n var matchingElements = false;\n // Options is used by the context when rendering the suggestions from a template.\n var suggestions = [];\n originalSelect.children('option').each(function(index, option) {\n if ($(option).prop('selected') !== true) {\n suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n }\n });\n\n // Re-render the list of suggestions.\n var searchquery = state.caseSensitive ? query : query.toLocaleLowerCase();\n var context = $.extend({options: suggestions}, options, state);\n var returnVal = templates.render(\n 'core/form_autocomplete_suggestions',\n context\n )\n .then(function(html, js) {\n // We have the new template, insert it in the page.\n templates.replaceNode(suggestionsElement, html, js);\n\n // Get the element again.\n suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Show it if it is hidden.\n Aria.unhide(suggestionsElement.get());\n suggestionsElement.show();\n\n // For each option in the list, hide it if it doesn't match the query.\n suggestionsElement.children().each(function(index, node) {\n node = $(node);\n if ((options.caseSensitive && node.text().indexOf(searchquery) > -1) ||\n (!options.caseSensitive && node.text().toLocaleLowerCase().indexOf(searchquery) > -1)) {\n Aria.unhide(node.get());\n node.show();\n matchingElements = true;\n } else {\n node.hide();\n Aria.hide(node.get());\n }\n });\n // If we found any matches, show the list.\n inputElement.attr('aria-expanded', true);\n if (originalSelect.attr('data-notice')) {\n // Display a notice rather than actual suggestions.\n suggestionsElement.html(originalSelect.attr('data-notice'));\n } else if (matchingElements) {\n // We only activate the first item in the list if tags is false,\n // because otherwise \"Enter\" would select the first item, instead of\n // creating a new tag.\n if (!options.tags) {\n activateItem(0, state);\n }\n } else {\n // Nothing matches. Tell them that.\n str.get_string('nosuggestions', 'form').done(function(nosuggestionsstr) {\n suggestionsElement.html(nosuggestionsstr);\n });\n }\n\n return suggestionsElement;\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(notification.exception);\n\n return returnVal;\n };\n\n /**\n * Create a new item for the list (a tag).\n *\n * @method createItem\n * @private\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state State variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var createItem = function(options, state, originalSelect) {\n // Find the element in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n // Get the current text in the input field.\n var query = inputElement.val();\n var tags = query.split(',');\n var found = false;\n\n $.each(tags, function(tagindex, tag) {\n // If we can only select one at a time, deselect any current value.\n tag = tag.trim();\n if (tag !== '') {\n if (!options.multiple) {\n originalSelect.children('option').prop('selected', false);\n }\n // Look for an existing option in the select list that matches this new tag.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == tag) {\n found = true;\n $(ele).prop('selected', true);\n }\n });\n // Only create the item if it's new.\n if (!found) {\n var option = $('');\n option.append(document.createTextNode(tag));\n option.attr('value', tag);\n originalSelect.append(option);\n option.prop('selected', true);\n // We mark newly created custom options as we handle them differently if they are \"deselected\".\n option.attr('data-iscustom', true);\n }\n }\n });\n\n return updateSelectionList(options, state, originalSelect)\n .then(function() {\n // Notify that the selection changed.\n notifyChange(originalSelect);\n\n return;\n })\n .then(function() {\n // Clear the input field.\n inputElement.val('');\n\n return;\n })\n .then(function() {\n // Close the suggestions list.\n return closeSuggestions(state);\n });\n };\n\n /**\n * Select the currently active item from the suggestions list.\n *\n * @method selectCurrentItem\n * @private\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state State variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var selectCurrentItem = function(options, state, originalSelect) {\n // Find the elements in the page.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Here loop through suggestions and set val to join of all selected items.\n\n var selectedItemValue = suggestionsElement.children('[aria-selected=true]').attr('data-value');\n // The select will either be a single or multi select, so the following will either\n // select one or more items correctly.\n // Take care to use 'prop' and not 'attr' for selected properties.\n // If only one can be selected at a time, start by deselecting everything.\n if (!options.multiple) {\n originalSelect.children('option').prop('selected', false);\n }\n // Look for a match, and toggle the selected property if there is a match.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == selectedItemValue) {\n $(ele).prop('selected', true);\n }\n });\n\n return updateSelectionList(options, state, originalSelect)\n .then(function() {\n // Notify that the selection changed.\n notifyChange(originalSelect);\n\n return;\n })\n .then(function() {\n if (options.closeSuggestionsOnSelect) {\n // Clear the input element.\n inputElement.val('');\n // Close the list of suggestions.\n return closeSuggestions(state);\n } else {\n // Focus on the input element so the suggestions does not auto-close.\n inputElement.focus();\n // Remove the last selected item from the suggestions list.\n return updateSuggestions(options, state, inputElement.val(), originalSelect);\n }\n });\n };\n\n /**\n * Fetch a new list of options via ajax.\n *\n * @method updateAjax\n * @private\n * @param {Event} e The event that triggered this update.\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state The state variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @param {Object} ajaxHandler This is a module that does the ajax fetch and translates the results.\n * @return {Promise}\n */\n var updateAjax = function(e, options, state, originalSelect, ajaxHandler) {\n var pendingPromise = addPendingJSPromise('updateAjax');\n // We need to show the indicator outside of the hidden select list.\n // So we get the parent id of the hidden select list.\n var parentElement = $(document.getElementById(state.selectId)).parent();\n LoadingIcon.addIconToContainerRemoveOnCompletion(parentElement, pendingPromise);\n\n // Get the query to pass to the ajax function.\n var query = $(e.currentTarget).val();\n // Call the transport function to do the ajax (name taken from Select2).\n ajaxHandler.transport(options.selector, query, function(results) {\n // We got a result - pass it through the translator before using it.\n var processedResults = ajaxHandler.processResults(options.selector, results);\n var existingValues = [];\n\n // Now destroy all options that are not currently selected.\n if (!options.multiple) {\n originalSelect.children('option').remove();\n }\n originalSelect.children('option').each(function(optionIndex, option) {\n option = $(option);\n if (!option.prop('selected')) {\n option.remove();\n } else {\n existingValues.push(String(option.attr('value')));\n }\n });\n\n if (!options.multiple && originalSelect.children('option').length === 0) {\n // If this is a single select - and there are no current options\n // the first option added will be selected by the browser. This causes a bug!\n // We need to insert an empty option so that none of the real options are selected.\n var option = $(' ');\n originalSelect.append(option);\n }\n if ($.isArray(processedResults)) {\n // Add all the new ones returned from ajax.\n $.each(processedResults, function(resultIndex, result) {\n if (existingValues.indexOf(String(result.value)) === -1) {\n var option = $(' ');\n option.append(result.label);\n option.attr('value', result.value);\n originalSelect.append(option);\n }\n });\n originalSelect.attr('data-notice', '');\n } else {\n // The AJAX handler returned a string instead of the array.\n originalSelect.attr('data-notice', processedResults);\n }\n // Update the list of suggestions now from the new values in the select list.\n pendingPromise.resolve(updateSuggestions(options, state, '', originalSelect));\n }, function(error) {\n pendingPromise.reject(error);\n });\n\n return pendingPromise;\n };\n\n /**\n * Add all the event listeners required for keyboard nav, blur clicks etc.\n *\n * @method addNavigation\n * @private\n * @param {Object} options The options used to create this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n */\n var addNavigation = function(options, state, originalSelect) {\n // Start with the input element.\n var inputElement = $(document.getElementById(state.inputId));\n // Add keyboard nav with keydown.\n inputElement.on('keydown', function(e) {\n var pendingJsPromise = addPendingJSPromise('addNavigation-' + state.inputId + '-' + e.keyCode);\n\n switch (e.keyCode) {\n case KEYS.DOWN:\n // If the suggestion list is open, move to the next item.\n if (!options.showSuggestions) {\n // Do not consume this event.\n pendingJsPromise.resolve();\n return true;\n } else if (inputElement.attr('aria-expanded') === \"true\") {\n pendingJsPromise.resolve(activateNextItem(state));\n } else {\n // Handle ajax population of suggestions.\n if (!inputElement.val() && options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n pendingJsPromise.resolve(updateAjax(e, options, state, originalSelect, ajaxHandler));\n });\n } else {\n // Open the suggestions list.\n pendingJsPromise.resolve(updateSuggestions(options, state, inputElement.val(), originalSelect));\n }\n }\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.UP:\n // Choose the previous active item.\n pendingJsPromise.resolve(activatePreviousItem(state));\n\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.ENTER:\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n if ((inputElement.attr('aria-expanded') === \"true\") &&\n (suggestionsElement.children('[aria-selected=true]').length > 0)) {\n // If the suggestion list has an active item, select it.\n pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\n } else if (options.tags) {\n // If tags are enabled, create a tag.\n pendingJsPromise.resolve(createItem(options, state, originalSelect));\n } else {\n pendingJsPromise.resolve();\n }\n\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.ESCAPE:\n if (inputElement.attr('aria-expanded') === \"true\") {\n // If the suggestion list is open, close it.\n pendingJsPromise.resolve(closeSuggestions(state));\n } else {\n pendingJsPromise.resolve();\n }\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n }\n pendingJsPromise.resolve();\n return true;\n });\n // Support multi lingual COMMA keycode (44).\n inputElement.on('keypress', function(e) {\n\n if (e.keyCode === KEYS.COMMA) {\n if (options.tags) {\n // If we are allowing tags, comma should create a tag (or enter).\n addPendingJSPromise('keypress-' + e.keyCode)\n .resolve(createItem(options, state, originalSelect));\n }\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n }\n return true;\n });\n // Support submitting the form without leaving the autocomplete element,\n // or submitting too quick before the blur handler action is completed.\n inputElement.closest('form').on('submit', function() {\n if (options.tags) {\n // If tags are enabled, create a tag.\n addPendingJSPromise('form-autocomplete-submit')\n .resolve(createItem(options, state, originalSelect));\n }\n\n return true;\n });\n inputElement.on('blur', function() {\n var pendingPromise = addPendingJSPromise('form-autocomplete-blur');\n window.setTimeout(function() {\n // Get the current element with focus.\n var focusElement = $(document.activeElement);\n var timeoutPromise = $.Deferred();\n\n // Only close the menu if the input hasn't regained focus and if the element still exists,\n // and regain focus if the scrollbar is clicked.\n // Due to the half a second delay, it is possible that the input element no longer exist\n // by the time this code is being executed.\n if (focusElement.is(document.getElementById(state.suggestionsId))) {\n inputElement.focus(); // Probably the scrollbar is clicked. Regain focus.\n } else if (!focusElement.is(inputElement) && $(document.getElementById(state.inputId)).length) {\n if (options.tags) {\n timeoutPromise.then(function() {\n return createItem(options, state, originalSelect);\n })\n .catch();\n }\n timeoutPromise.then(function() {\n return closeSuggestions(state);\n })\n .catch();\n }\n\n timeoutPromise.then(function() {\n return pendingPromise.resolve();\n })\n .catch();\n timeoutPromise.resolve();\n }, 500);\n });\n if (options.showSuggestions) {\n var arrowElement = $(document.getElementById(state.downArrowId));\n arrowElement.on('click', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-show-suggestions');\n\n // Prevent the close timer, or we will open, then close the suggestions.\n inputElement.focus();\n\n // Handle ajax population of suggestions.\n if (!inputElement.val() && options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n pendingPromise.resolve(updateAjax(e, options, state, originalSelect, ajaxHandler));\n });\n } else {\n // Else - open the suggestions list.\n pendingPromise.resolve(updateSuggestions(options, state, inputElement.val(), originalSelect));\n }\n });\n }\n\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Remove any click handler first.\n suggestionsElement.parent().prop(\"onclick\", null).off(\"click\");\n suggestionsElement.parent().on('click', `#${state.suggestionsId} [role=option]`, function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-parent');\n // Handle clicks on suggestions.\n var element = $(e.currentTarget).closest('[role=option]');\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Find the index of the clicked on suggestion.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n // Activate it.\n activateItem(current, state)\n .then(function() {\n // And select it.\n return selectCurrentItem(options, state, originalSelect);\n })\n .then(function() {\n return pendingPromise.resolve();\n })\n .catch();\n });\n var selectionElement = $(document.getElementById(state.selectionId));\n\n // Handle clicks on the selected items (will unselect an item).\n selectionElement.on('click', '[role=option]', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-clicks');\n\n // Remove it from the selection.\n pendingPromise.resolve(deselectItem(options, state, $(e.currentTarget), originalSelect));\n });\n\n // When listbox is focused, focus on the first option if there is no focused option.\n selectionElement.on('focus', function() {\n updateActiveSelectionFromState(state);\n });\n\n // Keyboard navigation for the selection list.\n selectionElement.on('keydown', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-keydown-' + e.keyCode);\n switch (e.keyCode) {\n case KEYS.RIGHT:\n case KEYS.DOWN:\n // We handled this event, so prevent it.\n e.preventDefault();\n\n // Choose the next selection item.\n pendingPromise.resolve(activateNextSelection(state));\n return;\n case KEYS.LEFT:\n case KEYS.UP:\n // We handled this event, so prevent it.\n e.preventDefault();\n\n // Choose the previous selection item.\n pendingPromise.resolve(activatePreviousSelection(state));\n return;\n case KEYS.SPACE:\n case KEYS.ENTER:\n // Get the item that is currently selected.\n var selectedItem = $(document.getElementById(state.selectionId)).children('[data-active-selection]');\n if (selectedItem) {\n e.preventDefault();\n\n // Unselect this item.\n pendingPromise.resolve(deselectItem(options, state, selectedItem, originalSelect));\n }\n return;\n }\n\n // Not handled. Resolve the promise.\n pendingPromise.resolve();\n });\n // Whenever the input field changes, update the suggestion list.\n if (options.showSuggestions) {\n // Store the value of the field as its last value, when the field gains focus.\n inputElement.on('focus', function(e) {\n var query = $(e.currentTarget).val();\n $(e.currentTarget).data('last-value', query);\n });\n\n // If this field uses ajax, set it up.\n if (options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n // Creating throttled handlers free of race conditions, and accurate.\n // This code keeps track of a throttleTimeout, which is periodically polled.\n // Once the throttled function is executed, the fact that it is running is noted.\n // If a subsequent request comes in whilst it is running, this request is re-applied.\n var throttleTimeout = null;\n var inProgress = false;\n var pendingKey = 'autocomplete-throttledhandler';\n var handler = function(e) {\n // Empty the current timeout.\n throttleTimeout = null;\n\n // Mark this request as in-progress.\n inProgress = true;\n\n // Process the request.\n updateAjax(e, options, state, originalSelect, ajaxHandler)\n .then(function() {\n // Check if the throttleTimeout is still empty.\n // There's a potential condition whereby the JS request takes long enough to complete that\n // another task has been queued.\n // In this case another task will be kicked off and we must wait for that before marking htis as\n // complete.\n if (null === throttleTimeout) {\n // Mark this task as complete.\n M.util.js_complete(pendingKey);\n }\n inProgress = false;\n\n return arguments[0];\n })\n .catch(notification.exception);\n };\n\n // For input events, we do not want to trigger many, many updates.\n var throttledHandler = function(e) {\n window.clearTimeout(throttleTimeout);\n if (inProgress) {\n // A request is currently ongoing.\n // Delay this request another 100ms.\n throttleTimeout = window.setTimeout(throttledHandler.bind(this, e), 100);\n return;\n }\n\n if (throttleTimeout === null) {\n // There is currently no existing timeout handler, and it has not been recently cleared, so\n // this is the start of a throttling check.\n M.util.js_pending(pendingKey);\n }\n\n // There is currently no existing timeout handler, and it has not been recently cleared, so this\n // is the start of a throttling check.\n // Queue a call to the handler.\n throttleTimeout = window.setTimeout(handler.bind(this, e), 300);\n };\n\n // Trigger an ajax update after the text field value changes.\n inputElement.on('input', function(e) {\n var query = $(e.currentTarget).val();\n var last = $(e.currentTarget).data('last-value');\n // IE11 fires many more input events than required - even when the value has not changed.\n if (last !== query) {\n throttledHandler(e);\n }\n $(e.currentTarget).data('last-value', query);\n });\n });\n } else {\n inputElement.on('input', function(e) {\n var query = $(e.currentTarget).val();\n var last = $(e.currentTarget).data('last-value');\n // IE11 fires many more input events than required - even when the value has not changed.\n // We need to only do this for real value changed events or the suggestions will be\n // unclickable on IE11 (because they will be rebuilt before the click event fires).\n // Note - because of this we cannot close the list when the query is empty or it will break\n // on IE11.\n if (last !== query) {\n updateSuggestions(options, state, query, originalSelect);\n }\n $(e.currentTarget).data('last-value', query);\n });\n }\n }\n };\n\n /**\n * Create and return an unresolved Promise for some pending JS.\n *\n * @param {String} key The unique identifier for this promise\n * @return {Promise}\n */\n var addPendingJSPromise = function(key) {\n var pendingKey = 'form-autocomplete:' + key;\n\n M.util.js_pending(pendingKey);\n\n var pendingPromise = $.Deferred();\n\n pendingPromise\n .then(function() {\n M.util.js_complete(pendingKey);\n\n return arguments[0];\n })\n .catch(notification.exception);\n\n return pendingPromise;\n };\n\n return {\n // Public variables and functions.\n /**\n * Turn a boring select box into an auto-complete beast.\n *\n * @method enhance\n * @param {string} selector The selector that identifies the select box.\n * @param {boolean} tags Whether to allow support for tags (can define new entries).\n * @param {string} ajax Name of an AMD module to handle ajax requests. If specified, the AMD\n * module must expose 2 functions \"transport\" and \"processResults\".\n * These are modeled on Select2 see: https://select2.github.io/options.html#ajax\n * @param {String} placeholder - The text to display before a selection is made.\n * @param {Boolean} caseSensitive - If search has to be made case sensitive.\n * @param {Boolean} showSuggestions - If suggestions should be shown\n * @param {String} noSelectionString - Text to display when there is no selection\n * @param {Boolean} closeSuggestionsOnSelect - Whether to close the suggestions immediately after making a selection.\n * @param {Object} templateOverrides A set of templates to use instead of the standard templates\n * @return {Promise}\n */\n enhance: function(selector, tags, ajax, placeholder, caseSensitive, showSuggestions, noSelectionString,\n closeSuggestionsOnSelect, templateOverrides) {\n // Set some default values.\n var options = {\n selector: selector,\n tags: false,\n ajax: false,\n placeholder: placeholder,\n caseSensitive: false,\n showSuggestions: true,\n noSelectionString: noSelectionString,\n templates: $.extend({\n input: 'core/form_autocomplete_input',\n items: 'core/form_autocomplete_selection_items',\n layout: 'core/form_autocomplete_layout',\n selection: 'core/form_autocomplete_selection',\n suggestions: 'core/form_autocomplete_suggestions',\n }, templateOverrides),\n };\n var pendingKey = 'autocomplete-setup-' + selector;\n M.util.js_pending(pendingKey);\n if (typeof tags !== \"undefined\") {\n options.tags = tags;\n }\n if (typeof ajax !== \"undefined\") {\n options.ajax = ajax;\n }\n if (typeof caseSensitive !== \"undefined\") {\n options.caseSensitive = caseSensitive;\n }\n if (typeof showSuggestions !== \"undefined\") {\n options.showSuggestions = showSuggestions;\n }\n if (typeof noSelectionString === \"undefined\") {\n str.get_string('noselection', 'form').done(function(result) {\n options.noSelectionString = result;\n }).fail(notification.exception);\n }\n\n // Look for the select element.\n var originalSelect = $(selector);\n if (!originalSelect) {\n log.debug('Selector not found: ' + selector);\n M.util.js_complete(pendingKey);\n return false;\n }\n\n Aria.hide(originalSelect.get());\n originalSelect.css('visibility', 'hidden');\n\n // Hide the original select.\n\n // Find or generate some ids.\n var state = {\n selectId: originalSelect.attr('id'),\n inputId: 'form_autocomplete_input-' + uniqueId,\n suggestionsId: 'form_autocomplete_suggestions-' + uniqueId,\n selectionId: 'form_autocomplete_selection-' + uniqueId,\n downArrowId: 'form_autocomplete_downarrow-' + uniqueId,\n items: [],\n };\n\n // Increment the unique counter so we don't get duplicates ever.\n uniqueId++;\n\n options.multiple = originalSelect.attr('multiple');\n if (!options.multiple) {\n // If this is a single select then there is no way to de-select the current value -\n // unless we add a bogus blank option to be selected when nothing else is.\n // This matches similar code in updateAjax above.\n originalSelect.prepend(' ');\n }\n\n if (typeof closeSuggestionsOnSelect !== \"undefined\") {\n options.closeSuggestionsOnSelect = closeSuggestionsOnSelect;\n } else {\n // If not specified, this will close suggestions by default for single-select elements only.\n options.closeSuggestionsOnSelect = !options.multiple;\n }\n\n var originalLabel = $('[for=' + state.selectId + ']');\n // Create the new markup and insert it after the select.\n var suggestions = [];\n originalSelect.children('option').each(function(index, option) {\n suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n });\n\n // Render all the parts of our UI.\n var context = $.extend({}, options, state);\n context.options = suggestions;\n context.items = [];\n\n // Collect rendered inline JS to be executed once the HTML is shown.\n var collectedjs = '';\n\n var renderLayout = templates.render(options.templates.layout, {})\n .then(function(html) {\n return $(html);\n });\n\n var renderInput = templates.render(options.templates.input, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n var renderDatalist = templates.render(options.templates.suggestions, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n var renderSelection = templates.render(options.templates.selection, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n return $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n .then(function(layout, input, suggestions, selection) {\n originalSelect.hide();\n var container = originalSelect.parent();\n\n // Ensure that the data-fieldtype is set for behat.\n input.find('input').attr('data-fieldtype', 'autocomplete');\n\n container.append(layout);\n container.find('[data-region=\"form_autocomplete-input\"]').replaceWith(input);\n container.find('[data-region=\"form_autocomplete-suggestions\"]').replaceWith(suggestions);\n container.find('[data-region=\"form_autocomplete-selection\"]').replaceWith(selection);\n\n templates.runTemplateJS(collectedjs);\n\n // Update the form label to point to the text input.\n originalLabel.attr('for', state.inputId);\n // Add the event handlers.\n addNavigation(options, state, originalSelect);\n\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Hide the suggestions by default.\n suggestionsElement.hide();\n Aria.hide(suggestionsElement.get());\n\n return;\n })\n .then(function() {\n // Show the current values in the selection list.\n return updateSelectionList(options, state, originalSelect);\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(function(error) {\n M.util.js_complete(pendingKey);\n notification.exception(error);\n });\n }\n };\n});\n"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","FormChangeChecker","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","getActiveElementFromState","selectionRegion","activeId","activeElement","activeValue","find","updateActiveSelectionFromState","activeIndex","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","each","ele","prop","label","data","html","push","value","hasItemListChanged","js_complete","Promise","context","extend","render","then","js","replaceNodeContents","catch","exception","filter","item","indexOf","notifyChange","markFormChangedFromNode","dispatchEvent","Event","deselectItem","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","replaceWith","runTemplateJS"],"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 * Autocomplete wrapper for select2 library.\n *\n * @module core/form-autocomplete\n * @copyright 2015 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.0\n */\ndefine([\n 'jquery',\n 'core/log',\n 'core/str',\n 'core/templates',\n 'core/notification',\n 'core/loadingicon',\n 'core/aria',\n 'core_form/changechecker',\n], function(\n $,\n log,\n str,\n templates,\n notification,\n LoadingIcon,\n Aria,\n FormChangeChecker\n) {\n // Private functions and variables.\n /** @var {Object} KEYS - List of keycode constants. */\n var KEYS = {\n DOWN: 40,\n ENTER: 13,\n SPACE: 32,\n ESCAPE: 27,\n COMMA: 44,\n UP: 38,\n LEFT: 37,\n RIGHT: 39\n };\n\n var uniqueId = Date.now();\n\n /**\n * Make an item in the selection list \"active\".\n *\n * @method activateSelection\n * @private\n * @param {Number} index The index in the current (visible) list of selection.\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n */\n var activateSelection = function(index, state) {\n // Find the elements in the DOM.\n var selectionElement = $(document.getElementById(state.selectionId));\n\n // Count the visible items.\n var length = selectionElement.children('[aria-selected=true]').length;\n // Limit the index to the upper/lower bounds of the list (wrap in both directions).\n index = index % length;\n while (index < 0) {\n index += length;\n }\n // Find the specified element.\n var element = $(selectionElement.children('[aria-selected=true]').get(index));\n // Create an id we can assign to this element.\n var itemId = state.selectionId + '-' + index;\n\n // Deselect all the selections.\n selectionElement.children().attr('data-active-selection', null).attr('id', '');\n\n // Select only this suggestion and assign it the id.\n element.attr('data-active-selection', true).attr('id', itemId);\n\n // Tell the input field it has a new active descendant so the item is announced.\n selectionElement.attr('aria-activedescendant', itemId);\n selectionElement.attr('data-active-value', element.attr('data-value'));\n\n return $.Deferred().resolve();\n };\n\n /**\n * Get the actively selected element from the state object.\n *\n * @param {Object} state\n * @returns {jQuery}\n */\n var getActiveElementFromState = function(state) {\n var selectionRegion = $(document.getElementById(state.selectionId));\n var activeId = selectionRegion.attr('aria-activedescendant');\n\n if (activeId) {\n var activeElement = $(document.getElementById(activeId));\n if (activeElement.length) {\n // The active descendent still exists.\n return activeElement;\n }\n }\n\n var activeValue = selectionRegion.attr('data-active-value');\n return selectionRegion.find('[data-value=\"' + activeValue + '\"]');\n };\n\n /**\n * Update the active selection from the given state object.\n *\n * @param {Object} state\n */\n var updateActiveSelectionFromState = function(state) {\n var activeElement = getActiveElementFromState(state);\n var activeValue = activeElement.attr('data-value');\n\n var selectionRegion = $(document.getElementById(state.selectionId));\n if (activeValue) {\n // Find the index of the currently selected index.\n var activeIndex = selectionRegion.find('[aria-selected=true]').index(activeElement);\n\n if (activeIndex !== -1) {\n activateSelection(activeIndex, state);\n return;\n }\n }\n\n // Either the active index was not set, or it could not be found.\n // Select the first value instead.\n activateSelection(0, state);\n };\n\n /**\n * Update the element that shows the currently selected items.\n *\n * @method updateSelectionList\n * @private\n * @param {Object} options Original options for this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var updateSelectionList = function(options, state, originalSelect) {\n var pendingKey = 'form-autocomplete-updateSelectionList-' + state.inputId;\n M.util.js_pending(pendingKey);\n\n // Build up a valid context to re-render the template.\n var items = [];\n var newSelection = $(document.getElementById(state.selectionId));\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).prop('selected')) {\n var label;\n if ($(ele).data('html')) {\n label = $(ele).data('html');\n } else {\n label = $(ele).html();\n }\n if (label !== '') {\n items.push({label: label, value: $(ele).attr('value')});\n }\n }\n });\n\n if (!hasItemListChanged(state, items)) {\n M.util.js_complete(pendingKey);\n return Promise.resolve();\n }\n\n state.items = items;\n\n var context = $.extend(options, state);\n // Render the template.\n return templates.render(options.templates.items, context)\n .then(function(html, js) {\n // Add it to the page.\n templates.replaceNodeContents(newSelection, html, js);\n\n updateActiveSelectionFromState(state);\n\n return;\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(notification.exception);\n };\n\n /**\n * Check whether the list of items stored in the state has changed.\n *\n * @param {Object} state\n * @param {Array} items\n * @returns {Boolean}\n */\n var hasItemListChanged = function(state, items) {\n if (state.items.length !== items.length) {\n return true;\n }\n\n // Check for any items in the state items which are not present in the new items list.\n return state.items.filter(item => items.indexOf(item) === -1).length > 0;\n };\n\n /**\n * Notify of a change in the selection.\n *\n * @param {jQuery} originalSelect The jQuery object matching the hidden select list.\n */\n var notifyChange = function(originalSelect) {\n FormChangeChecker.markFormChangedFromNode(originalSelect[0]);\n\n // Note, jQuery .change() was not working here. Better to\n // use plain JavaScript anyway.\n originalSelect[0].dispatchEvent(new Event('change'));\n };\n\n /**\n * Remove the given item from the list of selected things.\n *\n * @method deselectItem\n * @private\n * @param {Object} options Original options for this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {Element} item The item to be deselected.\n * @param {Element} originalSelect The original select list.\n * @return {Promise}\n */\n var deselectItem = function(options, state, item, originalSelect) {\n var selectedItemValue = $(item).attr('data-value');\n\n // Look for a match, and toggle the selected property if there is a match.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == selectedItemValue) {\n $(ele).prop('selected', false);\n // We remove newly created custom tags from the suggestions list when they are deselected.\n if ($(ele).attr('data-iscustom')) {\n $(ele).remove();\n }\n }\n });\n // Rerender the selection list.\n return updateSelectionList(options, state, originalSelect)\n .then(function() {\n // Notify that the selection changed.\n notifyChange(originalSelect);\n\n return;\n });\n };\n\n /**\n * Make an item in the suggestions \"active\" (about to be selected).\n *\n * @method activateItem\n * @private\n * @param {Number} index The index in the current (visible) list of suggestions.\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n */\n var activateItem = function(index, state) {\n // Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Count the visible items.\n var length = suggestionsElement.children(':not([aria-hidden])').length;\n // Limit the index to the upper/lower bounds of the list (wrap in both directions).\n index = index % length;\n while (index < 0) {\n index += length;\n }\n // Find the specified element.\n var element = $(suggestionsElement.children(':not([aria-hidden])').get(index));\n // Find the index of this item in the full list of suggestions (including hidden).\n var globalIndex = $(suggestionsElement.children('[role=option]')).index(element);\n // Create an id we can assign to this element.\n var itemId = state.suggestionsId + '-' + globalIndex;\n\n // Deselect all the suggestions.\n suggestionsElement.children().attr('aria-selected', false).attr('id', '');\n // Select only this suggestion and assign it the id.\n element.attr('aria-selected', true).attr('id', itemId);\n // Tell the input field it has a new active descendant so the item is announced.\n inputElement.attr('aria-activedescendant', itemId);\n\n // Scroll it into view.\n var scrollPos = element.offset().top\n - suggestionsElement.offset().top\n + suggestionsElement.scrollTop()\n - (suggestionsElement.height() / 2);\n return suggestionsElement.animate({\n scrollTop: scrollPos\n }, 100).promise();\n };\n\n /**\n * Find the index of the current active suggestion, and activate the next one.\n *\n * @method activateNextItem\n * @private\n * @param {Object} state State variable for this auto complete element.\n * @return {Promise}\n */\n var activateNextItem = function(state) {\n // Find the list of suggestions.\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Find the active one.\n var element = suggestionsElement.children('[aria-selected=true]');\n // Find it's index.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n // Activate the next one.\n return activateItem(current + 1, state);\n };\n\n /**\n * Find the index of the current active selection, and activate the previous one.\n *\n * @method activatePreviousSelection\n * @private\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n */\n var activatePreviousSelection = function(state) {\n // Find the list of selections.\n var selectionsElement = $(document.getElementById(state.selectionId));\n // Find the active one.\n var element = selectionsElement.children('[data-active-selection]');\n if (!element) {\n return activateSelection(0, state);\n }\n // Find it's index.\n var current = selectionsElement.children('[aria-selected=true]').index(element);\n // Activate the next one.\n return activateSelection(current - 1, state);\n };\n\n /**\n * Find the index of the current active selection, and activate the next one.\n *\n * @method activateNextSelection\n * @private\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n */\n var activateNextSelection = function(state) {\n // Find the list of selections.\n var selectionsElement = $(document.getElementById(state.selectionId));\n\n // Find the active one.\n var element = selectionsElement.children('[data-active-selection]');\n var current = 0;\n\n if (element) {\n // The element was found. Determine the index and move to the next one.\n current = selectionsElement.children('[aria-selected=true]').index(element);\n current = current + 1;\n } else {\n // No selected item found. Move to the first.\n current = 0;\n }\n\n return activateSelection(current, state);\n };\n\n /**\n * Find the index of the current active suggestion, and activate the previous one.\n *\n * @method activatePreviousItem\n * @private\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n */\n var activatePreviousItem = function(state) {\n // Find the list of suggestions.\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Find the active one.\n var element = suggestionsElement.children('[aria-selected=true]');\n\n // Find it's index.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n // Activate the previous one.\n return activateItem(current - 1, state);\n };\n\n /**\n * Close the list of suggestions.\n *\n * @method closeSuggestions\n * @private\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n */\n var closeSuggestions = function(state) {\n // Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n if (inputElement.attr('aria-expanded') === \"true\") {\n // Announce the list of suggestions was closed.\n inputElement.attr('aria-expanded', false);\n }\n // Read the current list of selections.\n inputElement.attr('aria-activedescendant', state.selectionId);\n\n // Hide the suggestions list (from screen readers too).\n Aria.hide(suggestionsElement.get());\n suggestionsElement.hide();\n\n return $.Deferred().resolve();\n };\n\n /**\n * Rebuild the list of suggestions based on the current values in the select list, and the query.\n *\n * @method updateSuggestions\n * @private\n * @param {Object} options The original options for this autocomplete.\n * @param {Object} state The state variables for this autocomplete.\n * @param {String} query The current text for the search string.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var updateSuggestions = function(options, state, query, originalSelect) {\n var pendingKey = 'form-autocomplete-updateSuggestions-' + state.inputId;\n M.util.js_pending(pendingKey);\n\n // Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Used to track if we found any visible suggestions.\n var matchingElements = false;\n // Options is used by the context when rendering the suggestions from a template.\n var suggestions = [];\n originalSelect.children('option').each(function(index, option) {\n if ($(option).prop('selected') !== true) {\n suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n }\n });\n\n // Re-render the list of suggestions.\n var searchquery = state.caseSensitive ? query : query.toLocaleLowerCase();\n var context = $.extend({options: suggestions}, options, state);\n var returnVal = templates.render(\n 'core/form_autocomplete_suggestions',\n context\n )\n .then(function(html, js) {\n // We have the new template, insert it in the page.\n templates.replaceNode(suggestionsElement, html, js);\n\n // Get the element again.\n suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n // Show it if it is hidden.\n Aria.unhide(suggestionsElement.get());\n suggestionsElement.show();\n\n // For each option in the list, hide it if it doesn't match the query.\n suggestionsElement.children().each(function(index, node) {\n node = $(node);\n if ((options.caseSensitive && node.text().indexOf(searchquery) > -1) ||\n (!options.caseSensitive && node.text().toLocaleLowerCase().indexOf(searchquery) > -1)) {\n Aria.unhide(node.get());\n node.show();\n matchingElements = true;\n } else {\n node.hide();\n Aria.hide(node.get());\n }\n });\n // If we found any matches, show the list.\n inputElement.attr('aria-expanded', true);\n if (originalSelect.attr('data-notice')) {\n // Display a notice rather than actual suggestions.\n suggestionsElement.html(originalSelect.attr('data-notice'));\n } else if (matchingElements) {\n // We only activate the first item in the list if tags is false,\n // because otherwise \"Enter\" would select the first item, instead of\n // creating a new tag.\n if (!options.tags) {\n activateItem(0, state);\n }\n } else {\n // Nothing matches. Tell them that.\n str.get_string('nosuggestions', 'form').done(function(nosuggestionsstr) {\n suggestionsElement.html(nosuggestionsstr);\n });\n }\n\n return suggestionsElement;\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(notification.exception);\n\n return returnVal;\n };\n\n /**\n * Create a new item for the list (a tag).\n *\n * @method createItem\n * @private\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state State variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var createItem = function(options, state, originalSelect) {\n // Find the element in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n // Get the current text in the input field.\n var query = inputElement.val();\n var tags = query.split(',');\n var found = false;\n\n $.each(tags, function(tagindex, tag) {\n // If we can only select one at a time, deselect any current value.\n tag = tag.trim();\n if (tag !== '') {\n if (!options.multiple) {\n originalSelect.children('option').prop('selected', false);\n }\n // Look for an existing option in the select list that matches this new tag.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == tag) {\n found = true;\n $(ele).prop('selected', true);\n }\n });\n // Only create the item if it's new.\n if (!found) {\n var option = $('');\n option.append(document.createTextNode(tag));\n option.attr('value', tag);\n originalSelect.append(option);\n option.prop('selected', true);\n // We mark newly created custom options as we handle them differently if they are \"deselected\".\n option.attr('data-iscustom', true);\n }\n }\n });\n\n return updateSelectionList(options, state, originalSelect)\n .then(function() {\n // Notify that the selection changed.\n notifyChange(originalSelect);\n\n return;\n })\n .then(function() {\n // Clear the input field.\n inputElement.val('');\n\n return;\n })\n .then(function() {\n // Close the suggestions list.\n return closeSuggestions(state);\n });\n };\n\n /**\n * Select the currently active item from the suggestions list.\n *\n * @method selectCurrentItem\n * @private\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state State variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n */\n var selectCurrentItem = function(options, state, originalSelect) {\n // Find the elements in the page.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Here loop through suggestions and set val to join of all selected items.\n\n var selectedItemValue = suggestionsElement.children('[aria-selected=true]').attr('data-value');\n // The select will either be a single or multi select, so the following will either\n // select one or more items correctly.\n // Take care to use 'prop' and not 'attr' for selected properties.\n // If only one can be selected at a time, start by deselecting everything.\n if (!options.multiple) {\n originalSelect.children('option').prop('selected', false);\n }\n // Look for a match, and toggle the selected property if there is a match.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == selectedItemValue) {\n $(ele).prop('selected', true);\n }\n });\n\n return updateSelectionList(options, state, originalSelect)\n .then(function() {\n // Notify that the selection changed.\n notifyChange(originalSelect);\n\n return;\n })\n .then(function() {\n if (options.closeSuggestionsOnSelect) {\n // Clear the input element.\n inputElement.val('');\n // Close the list of suggestions.\n return closeSuggestions(state);\n } else {\n // Focus on the input element so the suggestions does not auto-close.\n inputElement.focus();\n // Remove the last selected item from the suggestions list.\n return updateSuggestions(options, state, inputElement.val(), originalSelect);\n }\n });\n };\n\n /**\n * Fetch a new list of options via ajax.\n *\n * @method updateAjax\n * @private\n * @param {Event} e The event that triggered this update.\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state The state variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @param {Object} ajaxHandler This is a module that does the ajax fetch and translates the results.\n * @return {Promise}\n */\n var updateAjax = function(e, options, state, originalSelect, ajaxHandler) {\n var pendingPromise = addPendingJSPromise('updateAjax');\n // We need to show the indicator outside of the hidden select list.\n // So we get the parent id of the hidden select list.\n var parentElement = $(document.getElementById(state.selectId)).parent();\n LoadingIcon.addIconToContainerRemoveOnCompletion(parentElement, pendingPromise);\n\n // Get the query to pass to the ajax function.\n var query = $(e.currentTarget).val();\n // Call the transport function to do the ajax (name taken from Select2).\n ajaxHandler.transport(options.selector, query, function(results) {\n // We got a result - pass it through the translator before using it.\n var processedResults = ajaxHandler.processResults(options.selector, results);\n var existingValues = [];\n\n // Now destroy all options that are not currently selected.\n if (!options.multiple) {\n originalSelect.children('option').remove();\n }\n originalSelect.children('option').each(function(optionIndex, option) {\n option = $(option);\n if (!option.prop('selected')) {\n option.remove();\n } else {\n existingValues.push(String(option.attr('value')));\n }\n });\n\n if (!options.multiple && originalSelect.children('option').length === 0) {\n // If this is a single select - and there are no current options\n // the first option added will be selected by the browser. This causes a bug!\n // We need to insert an empty option so that none of the real options are selected.\n var option = $(' ');\n originalSelect.append(option);\n }\n if ($.isArray(processedResults)) {\n // Add all the new ones returned from ajax.\n $.each(processedResults, function(resultIndex, result) {\n if (existingValues.indexOf(String(result.value)) === -1) {\n var option = $(' ');\n option.append(result.label);\n option.attr('value', result.value);\n originalSelect.append(option);\n }\n });\n originalSelect.attr('data-notice', '');\n } else {\n // The AJAX handler returned a string instead of the array.\n originalSelect.attr('data-notice', processedResults);\n }\n // Update the list of suggestions now from the new values in the select list.\n pendingPromise.resolve(updateSuggestions(options, state, '', originalSelect));\n }, function(error) {\n pendingPromise.reject(error);\n });\n\n return pendingPromise;\n };\n\n /**\n * Add all the event listeners required for keyboard nav, blur clicks etc.\n *\n * @method addNavigation\n * @private\n * @param {Object} options The options used to create this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n */\n var addNavigation = function(options, state, originalSelect) {\n // Start with the input element.\n var inputElement = $(document.getElementById(state.inputId));\n // Add keyboard nav with keydown.\n inputElement.on('keydown', function(e) {\n var pendingJsPromise = addPendingJSPromise('addNavigation-' + state.inputId + '-' + e.keyCode);\n\n switch (e.keyCode) {\n case KEYS.DOWN:\n // If the suggestion list is open, move to the next item.\n if (!options.showSuggestions) {\n // Do not consume this event.\n pendingJsPromise.resolve();\n return true;\n } else if (inputElement.attr('aria-expanded') === \"true\") {\n pendingJsPromise.resolve(activateNextItem(state));\n } else {\n // Handle ajax population of suggestions.\n if (!inputElement.val() && options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n pendingJsPromise.resolve(updateAjax(e, options, state, originalSelect, ajaxHandler));\n });\n } else {\n // Open the suggestions list.\n pendingJsPromise.resolve(updateSuggestions(options, state, inputElement.val(), originalSelect));\n }\n }\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.UP:\n // Choose the previous active item.\n pendingJsPromise.resolve(activatePreviousItem(state));\n\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.ENTER:\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n if ((inputElement.attr('aria-expanded') === \"true\") &&\n (suggestionsElement.children('[aria-selected=true]').length > 0)) {\n // If the suggestion list has an active item, select it.\n pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\n } else if (options.tags) {\n // If tags are enabled, create a tag.\n pendingJsPromise.resolve(createItem(options, state, originalSelect));\n } else {\n pendingJsPromise.resolve();\n }\n\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.ESCAPE:\n if (inputElement.attr('aria-expanded') === \"true\") {\n // If the suggestion list is open, close it.\n pendingJsPromise.resolve(closeSuggestions(state));\n } else {\n pendingJsPromise.resolve();\n }\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n }\n pendingJsPromise.resolve();\n return true;\n });\n // Support multi lingual COMMA keycode (44).\n inputElement.on('keypress', function(e) {\n\n if (e.keyCode === KEYS.COMMA) {\n if (options.tags) {\n // If we are allowing tags, comma should create a tag (or enter).\n addPendingJSPromise('keypress-' + e.keyCode)\n .resolve(createItem(options, state, originalSelect));\n }\n // We handled this event, so prevent it.\n e.preventDefault();\n return false;\n }\n return true;\n });\n // Support submitting the form without leaving the autocomplete element,\n // or submitting too quick before the blur handler action is completed.\n inputElement.closest('form').on('submit', function() {\n if (options.tags) {\n // If tags are enabled, create a tag.\n addPendingJSPromise('form-autocomplete-submit')\n .resolve(createItem(options, state, originalSelect));\n }\n\n return true;\n });\n inputElement.on('blur', function() {\n var pendingPromise = addPendingJSPromise('form-autocomplete-blur');\n window.setTimeout(function() {\n // Get the current element with focus.\n var focusElement = $(document.activeElement);\n var timeoutPromise = $.Deferred();\n\n // Only close the menu if the input hasn't regained focus and if the element still exists,\n // and regain focus if the scrollbar is clicked.\n // Due to the half a second delay, it is possible that the input element no longer exist\n // by the time this code is being executed.\n if (focusElement.is(document.getElementById(state.suggestionsId))) {\n inputElement.focus(); // Probably the scrollbar is clicked. Regain focus.\n } else if (!focusElement.is(inputElement) && $(document.getElementById(state.inputId)).length) {\n if (options.tags) {\n timeoutPromise.then(function() {\n return createItem(options, state, originalSelect);\n })\n .catch();\n }\n timeoutPromise.then(function() {\n return closeSuggestions(state);\n })\n .catch();\n }\n\n timeoutPromise.then(function() {\n return pendingPromise.resolve();\n })\n .catch();\n timeoutPromise.resolve();\n }, 500);\n });\n if (options.showSuggestions) {\n var arrowElement = $(document.getElementById(state.downArrowId));\n arrowElement.on('click', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-show-suggestions');\n\n // Prevent the close timer, or we will open, then close the suggestions.\n inputElement.focus();\n\n // Handle ajax population of suggestions.\n if (!inputElement.val() && options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n pendingPromise.resolve(updateAjax(e, options, state, originalSelect, ajaxHandler));\n });\n } else {\n // Else - open the suggestions list.\n pendingPromise.resolve(updateSuggestions(options, state, inputElement.val(), originalSelect));\n }\n });\n }\n\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Remove any click handler first.\n suggestionsElement.parent().prop(\"onclick\", null).off(\"click\");\n suggestionsElement.parent().on('click', `#${state.suggestionsId} [role=option]`, function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-parent');\n // Handle clicks on suggestions.\n var element = $(e.currentTarget).closest('[role=option]');\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Find the index of the clicked on suggestion.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n // Activate it.\n activateItem(current, state)\n .then(function() {\n // And select it.\n return selectCurrentItem(options, state, originalSelect);\n })\n .then(function() {\n return pendingPromise.resolve();\n })\n .catch();\n });\n var selectionElement = $(document.getElementById(state.selectionId));\n\n // Handle clicks on the selected items (will unselect an item).\n selectionElement.on('click', '[role=option]', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-clicks');\n\n // Remove it from the selection.\n pendingPromise.resolve(deselectItem(options, state, $(e.currentTarget), originalSelect));\n });\n\n // When listbox is focused, focus on the first option if there is no focused option.\n selectionElement.on('focus', function() {\n updateActiveSelectionFromState(state);\n });\n\n // Keyboard navigation for the selection list.\n selectionElement.on('keydown', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-keydown-' + e.keyCode);\n switch (e.keyCode) {\n case KEYS.RIGHT:\n case KEYS.DOWN:\n // We handled this event, so prevent it.\n e.preventDefault();\n\n // Choose the next selection item.\n pendingPromise.resolve(activateNextSelection(state));\n return;\n case KEYS.LEFT:\n case KEYS.UP:\n // We handled this event, so prevent it.\n e.preventDefault();\n\n // Choose the previous selection item.\n pendingPromise.resolve(activatePreviousSelection(state));\n return;\n case KEYS.SPACE:\n case KEYS.ENTER:\n // Get the item that is currently selected.\n var selectedItem = $(document.getElementById(state.selectionId)).children('[data-active-selection]');\n if (selectedItem) {\n e.preventDefault();\n\n // Unselect this item.\n pendingPromise.resolve(deselectItem(options, state, selectedItem, originalSelect));\n }\n return;\n }\n\n // Not handled. Resolve the promise.\n pendingPromise.resolve();\n });\n // Whenever the input field changes, update the suggestion list.\n if (options.showSuggestions) {\n // Store the value of the field as its last value, when the field gains focus.\n inputElement.on('focus', function(e) {\n var query = $(e.currentTarget).val();\n $(e.currentTarget).data('last-value', query);\n });\n\n // If this field uses ajax, set it up.\n if (options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n // Creating throttled handlers free of race conditions, and accurate.\n // This code keeps track of a throttleTimeout, which is periodically polled.\n // Once the throttled function is executed, the fact that it is running is noted.\n // If a subsequent request comes in whilst it is running, this request is re-applied.\n var throttleTimeout = null;\n var inProgress = false;\n var pendingKey = 'autocomplete-throttledhandler';\n var handler = function(e) {\n // Empty the current timeout.\n throttleTimeout = null;\n\n // Mark this request as in-progress.\n inProgress = true;\n\n // Process the request.\n updateAjax(e, options, state, originalSelect, ajaxHandler)\n .then(function() {\n // Check if the throttleTimeout is still empty.\n // There's a potential condition whereby the JS request takes long enough to complete that\n // another task has been queued.\n // In this case another task will be kicked off and we must wait for that before marking htis as\n // complete.\n if (null === throttleTimeout) {\n // Mark this task as complete.\n M.util.js_complete(pendingKey);\n }\n inProgress = false;\n\n return arguments[0];\n })\n .catch(notification.exception);\n };\n\n // For input events, we do not want to trigger many, many updates.\n var throttledHandler = function(e) {\n window.clearTimeout(throttleTimeout);\n if (inProgress) {\n // A request is currently ongoing.\n // Delay this request another 100ms.\n throttleTimeout = window.setTimeout(throttledHandler.bind(this, e), 100);\n return;\n }\n\n if (throttleTimeout === null) {\n // There is currently no existing timeout handler, and it has not been recently cleared, so\n // this is the start of a throttling check.\n M.util.js_pending(pendingKey);\n }\n\n // There is currently no existing timeout handler, and it has not been recently cleared, so this\n // is the start of a throttling check.\n // Queue a call to the handler.\n throttleTimeout = window.setTimeout(handler.bind(this, e), 300);\n };\n\n // Trigger an ajax update after the text field value changes.\n inputElement.on('input', function(e) {\n var query = $(e.currentTarget).val();\n var last = $(e.currentTarget).data('last-value');\n // IE11 fires many more input events than required - even when the value has not changed.\n if (last !== query) {\n throttledHandler(e);\n }\n $(e.currentTarget).data('last-value', query);\n });\n });\n } else {\n inputElement.on('input', function(e) {\n var query = $(e.currentTarget).val();\n var last = $(e.currentTarget).data('last-value');\n // IE11 fires many more input events than required - even when the value has not changed.\n // We need to only do this for real value changed events or the suggestions will be\n // unclickable on IE11 (because they will be rebuilt before the click event fires).\n // Note - because of this we cannot close the list when the query is empty or it will break\n // on IE11.\n if (last !== query) {\n updateSuggestions(options, state, query, originalSelect);\n }\n $(e.currentTarget).data('last-value', query);\n });\n }\n }\n };\n\n /**\n * Create and return an unresolved Promise for some pending JS.\n *\n * @param {String} key The unique identifier for this promise\n * @return {Promise}\n */\n var addPendingJSPromise = function(key) {\n var pendingKey = 'form-autocomplete:' + key;\n\n M.util.js_pending(pendingKey);\n\n var pendingPromise = $.Deferred();\n\n pendingPromise\n .then(function() {\n M.util.js_complete(pendingKey);\n\n return arguments[0];\n })\n .catch(notification.exception);\n\n return pendingPromise;\n };\n\n return {\n // Public variables and functions.\n /**\n * Turn a boring select box into an auto-complete beast.\n *\n * @method enhance\n * @param {string} selector The selector that identifies the select box.\n * @param {boolean} tags Whether to allow support for tags (can define new entries).\n * @param {string} ajax Name of an AMD module to handle ajax requests. If specified, the AMD\n * module must expose 2 functions \"transport\" and \"processResults\".\n * These are modeled on Select2 see: https://select2.github.io/options.html#ajax\n * @param {String} placeholder - The text to display before a selection is made.\n * @param {Boolean} caseSensitive - If search has to be made case sensitive.\n * @param {Boolean} showSuggestions - If suggestions should be shown\n * @param {String} noSelectionString - Text to display when there is no selection\n * @param {Boolean} closeSuggestionsOnSelect - Whether to close the suggestions immediately after making a selection.\n * @param {Object} templateOverrides A set of templates to use instead of the standard templates\n * @return {Promise}\n */\n enhance: function(selector, tags, ajax, placeholder, caseSensitive, showSuggestions, noSelectionString,\n closeSuggestionsOnSelect, templateOverrides) {\n // Set some default values.\n var options = {\n selector: selector,\n tags: false,\n ajax: false,\n placeholder: placeholder,\n caseSensitive: false,\n showSuggestions: true,\n noSelectionString: noSelectionString,\n templates: $.extend({\n input: 'core/form_autocomplete_input',\n items: 'core/form_autocomplete_selection_items',\n layout: 'core/form_autocomplete_layout',\n selection: 'core/form_autocomplete_selection',\n suggestions: 'core/form_autocomplete_suggestions',\n }, templateOverrides),\n };\n var pendingKey = 'autocomplete-setup-' + selector;\n M.util.js_pending(pendingKey);\n if (typeof tags !== \"undefined\") {\n options.tags = tags;\n }\n if (typeof ajax !== \"undefined\") {\n options.ajax = ajax;\n }\n if (typeof caseSensitive !== \"undefined\") {\n options.caseSensitive = caseSensitive;\n }\n if (typeof showSuggestions !== \"undefined\") {\n options.showSuggestions = showSuggestions;\n }\n if (typeof noSelectionString === \"undefined\") {\n str.get_string('noselection', 'form').done(function(result) {\n options.noSelectionString = result;\n }).fail(notification.exception);\n }\n\n // Look for the select element.\n var originalSelect = $(selector);\n if (!originalSelect) {\n log.debug('Selector not found: ' + selector);\n M.util.js_complete(pendingKey);\n return false;\n }\n\n Aria.hide(originalSelect.get());\n originalSelect.css('visibility', 'hidden');\n\n // Hide the original select.\n\n // Find or generate some ids.\n var state = {\n selectId: originalSelect.attr('id'),\n inputId: 'form_autocomplete_input-' + uniqueId,\n suggestionsId: 'form_autocomplete_suggestions-' + uniqueId,\n selectionId: 'form_autocomplete_selection-' + uniqueId,\n downArrowId: 'form_autocomplete_downarrow-' + uniqueId,\n items: [],\n };\n\n // Increment the unique counter so we don't get duplicates ever.\n uniqueId++;\n\n options.multiple = originalSelect.attr('multiple');\n if (!options.multiple) {\n // If this is a single select then there is no way to de-select the current value -\n // unless we add a bogus blank option to be selected when nothing else is.\n // This matches similar code in updateAjax above.\n originalSelect.prepend(' ');\n }\n\n if (typeof closeSuggestionsOnSelect !== \"undefined\") {\n options.closeSuggestionsOnSelect = closeSuggestionsOnSelect;\n } else {\n // If not specified, this will close suggestions by default for single-select elements only.\n options.closeSuggestionsOnSelect = !options.multiple;\n }\n\n var originalLabel = $('[for=' + state.selectId + ']');\n // Create the new markup and insert it after the select.\n var suggestions = [];\n originalSelect.children('option').each(function(index, option) {\n suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n });\n\n // Render all the parts of our UI.\n var context = $.extend({}, options, state);\n context.options = suggestions;\n context.items = [];\n\n // Collect rendered inline JS to be executed once the HTML is shown.\n var collectedjs = '';\n\n var renderLayout = templates.render(options.templates.layout, {})\n .then(function(html) {\n return $(html);\n });\n\n var renderInput = templates.render(options.templates.input, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n var renderDatalist = templates.render(options.templates.suggestions, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n var renderSelection = templates.render(options.templates.selection, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n return $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n .then(function(layout, input, suggestions, selection) {\n originalSelect.hide();\n var container = originalSelect.parent();\n\n // Ensure that the data-fieldtype is set for behat.\n input.find('input').attr('data-fieldtype', 'autocomplete');\n\n container.append(layout);\n container.find('[data-region=\"form_autocomplete-input\"]').replaceWith(input);\n container.find('[data-region=\"form_autocomplete-suggestions\"]').replaceWith(suggestions);\n container.find('[data-region=\"form_autocomplete-selection\"]').replaceWith(selection);\n\n templates.runTemplateJS(collectedjs);\n\n // Update the form label to point to the text input.\n originalLabel.attr('for', state.inputId);\n // Add the event handlers.\n addNavigation(options, state, originalSelect);\n\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n // Hide the suggestions by default.\n suggestionsElement.hide();\n Aria.hide(suggestionsElement.get());\n\n return;\n })\n .then(function() {\n // Show the current values in the selection list.\n return updateSelectionList(options, state, originalSelect);\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(function(error) {\n M.util.js_complete(pendingKey);\n notification.exception(error);\n });\n }\n };\n});\n"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
diff --git a/lib/amd/src/form-autocomplete.js b/lib/amd/src/form-autocomplete.js
index f234ffff29a..f0119b82a9a 100644
--- a/lib/amd/src/form-autocomplete.js
+++ b/lib/amd/src/form-autocomplete.js
@@ -21,10 +21,25 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.0
*/
-define(
- ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],
-function($, log, str, templates, notification, LoadingIcon, Aria) {
-
+define([
+ 'jquery',
+ 'core/log',
+ 'core/str',
+ 'core/templates',
+ 'core/notification',
+ 'core/loadingicon',
+ 'core/aria',
+ 'core_form/changechecker',
+], function(
+ $,
+ log,
+ str,
+ templates,
+ notification,
+ LoadingIcon,
+ Aria,
+ FormChangeChecker
+) {
// Private functions and variables.
/** @var {Object} KEYS - List of keycode constants. */
var KEYS = {
@@ -202,9 +217,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
* @param {jQuery} originalSelect The jQuery object matching the hidden select list.
*/
var notifyChange = function(originalSelect) {
- if (typeof M.core_formchangechecker !== 'undefined') {
- M.core_formchangechecker.set_form_changed();
- }
+ FormChangeChecker.markFormChangedFromNode(originalSelect[0]);
// Note, jQuery .change() was not working here. Better to
// use plain JavaScript anyway.
diff --git a/lib/form/amd/build/dynamicform.min.js b/lib/form/amd/build/dynamicform.min.js
index 6c46fef4d30..93c1892d3f4 100644
--- a/lib/form/amd/build/dynamicform.min.js
+++ b/lib/form/amd/build/dynamicform.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_form/dynamicform",["exports","core/ajax","core_form/events","core/fragment","core/notification","core/pending","core/templates","core/yui","core/str"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=l(b);c=k(c);d=l(d);e=l(e);f=l(f);g=l(g);h=l(h);function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=j();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 l(a){return a&&a.__esModule?a:{default:a}}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}function o(a){return s(a)||r(a)||q(a)||p()}function p(){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 q(a,b){if(!a)return;if("string"==typeof a)return t(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 t(a,b)}function r(a){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(a))return Array.from(a)}function s(a){if(Array.isArray(a))return t(a)}function t(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 * Display an embedded form, it is only loaded and reloaded inside its container\n *\n * Example:\n * import DynamicForm from 'core_form/dynamicform';\n *\n * const dynamicForm = new DynamicForm(document.querySelector('#mycontainer', 'pluginname\\\\form\\\\formname');\n * dynamicForm.addEventListener(dynamicForm.events.FORM_SUBMITTED, e => {\n * e.preventDefault();\n * window.console.log(e.detail);\n * dynamicForm.container.innerHTML = 'Thank you, your form is submitted!';\n * });\n * dynamicForm.load();\n *\n * See also https://docs.moodle.org/dev/Modal_and_AJAX_forms\n *\n * @module core_form/dynamicform\n * @copyright 2019 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport * as FormEvents from 'core_form/events';\nimport Fragment from 'core/fragment';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Templates from 'core/templates';\nimport Y from 'core/yui';\nimport {get_strings as getStrings} from 'core/str';\n\n/**\n * @class core_form/dynamicform\n */\nexport default class DynamicForm {\n\n /**\n * Various events that can be observed.\n *\n * @type {Object}\n */\n events = {\n // Form was successfully submitted - the response is passed to the event listener.\n // Cancellable (in order to prevent default behavior to clear the container).\n FORM_SUBMITTED: 'core_form_dynamicform_formsubmitted',\n // Cancel button was pressed.\n // Cancellable (in order to prevent default behavior to clear the container).\n FORM_CANCELLED: 'core_form_dynamicform_formcancelled',\n // User attempted to submit the form but there was client-side validation error.\n CLIENT_VALIDATION_ERROR: 'core_form_dynamicform_clientvalidationerror',\n // User attempted to submit the form but server returned validation error.\n SERVER_VALIDATION_ERROR: 'core_form_dynamicform_validationerror',\n // Error occurred while performing request to the server.\n // Cancellable (by default calls Notification.exception).\n ERROR: 'core_form_dynamicform_error',\n // Right after user pressed no-submit button,\n // listen to this event if you want to add JS validation or processing for no-submit button.\n // Cancellable.\n NOSUBMIT_BUTTON_PRESSED: 'core_form_dynamicform_nosubmitbutton',\n // Right after user pressed submit button,\n // listen to this event if you want to add additional JS validation or confirmation dialog.\n // Cancellable.\n SUBMIT_BUTTON_PRESSED: 'core_form_dynamicform_submitbutton',\n // Right after user pressed cancel button,\n // listen to this event if you want to add confirmation dialog.\n // Cancellable.\n CANCEL_BUTTON_PRESSED: 'core_form_dynamicform_cancelbutton',\n };\n\n /**\n * Constructor\n *\n * Creates an instance\n *\n * @param {Element} container - the parent element for the form\n * @param {string} formClass full name of the php class that extends \\core_form\\modal , must be in autoloaded location\n */\n constructor(container, formClass) {\n this.formClass = formClass;\n this.container = container;\n\n // Ensure strings required for shortforms are always available.\n getStrings([\n {key: 'collapseall', component: 'moodle'},\n {key: 'expandall', component: 'moodle'}\n ]).catch(Notification.exception);\n\n // Register delegated events handlers in vanilla JS.\n this.container.addEventListener('click', e => {\n if (e.target.matches('form input[type=submit][data-cancel]')) {\n e.preventDefault();\n const event = this.trigger(this.events.CANCEL_BUTTON_PRESSED, e.target);\n if (!event.defaultPrevented) {\n this.processCancelButton();\n }\n } else if (e.target.matches('form input[type=submit][data-no-submit=\"1\"]')) {\n e.preventDefault();\n const event = this.trigger(this.events.NOSUBMIT_BUTTON_PRESSED, e.target);\n if (!event.defaultPrevented) {\n this.processNoSubmitButton(e.target);\n }\n }\n });\n\n this.container.addEventListener('submit', e => {\n if (e.target.matches('form')) {\n e.preventDefault();\n const event = this.trigger(this.events.SUBMIT_BUTTON_PRESSED);\n if (!event.defaultPrevented) {\n this.submitFormAjax();\n }\n }\n });\n }\n\n /**\n * Loads the form via AJAX and shows it inside a given container\n *\n * @param {Object} args\n * @return {Promise}\n * @public\n */\n load(args = null) {\n const formData = new URLSearchParams(Object.entries(args || {}));\n const pendingPromise = new Pending('core_form/dynamicform:load');\n return this.getBody(formData.toString())\n .then((resp) => this.updateForm(resp))\n .then(pendingPromise.resolve);\n }\n\n /**\n * Triggers a custom event\n *\n * @private\n * @param {String} eventName\n * @param {*} detail\n * @param {Boolean} cancelable\n * @return {CustomEvent}\n */\n trigger(eventName, detail = null, cancelable = true) {\n const e = new CustomEvent(eventName, {detail, cancelable});\n this.container.dispatchEvent(e);\n return e;\n }\n\n /**\n * Add listener for an event\n *\n * Example:\n * const dynamicForm = new DynamicForm(...);\n * dynamicForm.addEventListener(dynamicForm.events.FORM_SUBMITTED, e => {\n * e.preventDefault();\n * window.console.log(e.detail);\n * dynamicForm.container.innerHTML = 'Thank you, your form is submitted!';\n * });\n */\n addEventListener(...args) {\n this.container.addEventListener(...args);\n }\n\n /**\n * Get form body\n *\n * @param {String} formDataString form data in format of a query string\n * @private\n * @return {Promise}\n */\n getBody(formDataString) {\n return Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: {\n formdata: formDataString,\n form: this.formClass,\n }\n }])[0]\n .then(response => {\n return {html: response.html, js: Fragment.processCollectedJavascript(response.javascript)};\n });\n }\n\n /**\n * On form submit\n *\n * @param {*} response Response received from the form's \"process\" method\n */\n onSubmitSuccess(response) {\n const event = this.trigger(this.events.FORM_SUBMITTED, response);\n if (event.defaultPrevented) {\n return;\n }\n\n // Default implementation is to remove the form. Event listener should either remove or reload the form\n // since its contents is no longer correct. For example, if an element was created as a result of\n // form submission, the \"id\" in the form would be still zero. Also the server-side validation\n // errors from the previous submission may still be present.\n this.container.innerHTML = '';\n }\n\n /**\n * On exception during form processing\n *\n * @private\n * @param {Object} exception\n */\n onSubmitError(exception) {\n const event = this.trigger(this.events.ERROR, exception);\n if (event.defaultPrevented) {\n return;\n }\n\n Notification.exception(exception);\n }\n\n /**\n * Click on a \"submit\" button that is marked in the form as registerNoSubmitButton()\n *\n * @method submitButtonPressed\n * @param {Element} button that was pressed\n * @fires event:formSubmittedByJavascript\n */\n processNoSubmitButton(button) {\n const pendingPromise = new Pending('core_form/dynamicform:nosubmit');\n const form = this.getFormNode();\n const formData = new URLSearchParams([...(new FormData(form)).entries()]);\n formData.append(button.getAttribute('name'), button.getAttribute('value'));\n\n FormEvents.notifyFormSubmittedByJavascript(form, true);\n\n // Add the button name to the form data and submit it.\n this.disableButtons();\n\n this.getBody(formData.toString())\n .then(this.updateForm)\n .then(pendingPromise.resolve)\n .catch(this.onSubmitError);\n }\n\n /**\n * Get the form node from the Dialogue.\n *\n * @returns {HTMLFormElement}\n */\n getFormNode() {\n return this.container.querySelector('form');\n }\n\n /**\n * Notifies listeners that form dirty state should be reset.\n *\n * @return {Promise}\n * @fires event:formSubmittedByJavascript\n */\n notifyResetFormChanges() {\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);\n\n return new Promise(resolve => {\n Y.use('event', 'moodle-core-event', 'moodle-core-formchangechecker', () => {\n M.core_formchangechecker.reset_form_dirty_state();\n resolve();\n });\n });\n }\n\n /**\n * Click on a \"cancel\" button\n */\n processCancelButton() {\n // Notify listeners that the form is about to be submitted (this will reset atto autosave).\n this.notifyResetFormChanges()\n .then(() => {\n const event = this.trigger(this.events.FORM_CANCELLED);\n if (!event.defaultPrevented) {\n // By default removes the form from the DOM.\n this.container.innerHTML = '';\n }\n return null;\n })\n .catch(null);\n }\n\n /**\n * Update form contents\n *\n * @param {string} html\n * @param {string} js\n * @returns {Promise}\n */\n updateForm({html, js}) {\n return Templates.replaceNodeContents(this.container, html, js);\n }\n\n /**\n * Validate form elements\n * @return {Boolean} Whether client-side validation has passed, false if there are errors\n * @fires event:formSubmittedByJavascript\n */\n validateElements() {\n // Notify listeners that the form is about to be submitted (this will reset atto autosave).\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode());\n\n // Now the change events have run, see if there are any \"invalid\" form fields.\n const invalid = [...this.container.querySelectorAll('[aria-invalid=\"true\"], .error')];\n\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (invalid.length) {\n invalid[0].focus();\n return false;\n }\n\n return true;\n }\n\n /**\n * Disable buttons during form submission\n */\n disableButtons() {\n this.container.querySelectorAll('form input[type=\"submit\"]')\n .forEach(el => el.setAttribute('disabled', true));\n }\n\n /**\n * Enable buttons after form submission (on validation error)\n */\n enableButtons() {\n this.container.querySelectorAll('form input[type=\"submit\"]')\n .forEach(el => el.removeAttribute('disabled'));\n }\n\n /**\n * Submit the form via AJAX call to the core_form_dynamic_form WS\n */\n async submitFormAjax() {\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (!(await this.validateElements())) {\n this.trigger(this.events.CLIENT_VALIDATION_ERROR, null, false);\n return;\n }\n this.disableButtons();\n\n // Convert all the form elements values to a serialised string.\n const form = this.container.querySelector('form');\n const formData = new URLSearchParams([...(new FormData(form)).entries()]);\n\n // Now we can continue...\n Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: {\n formdata: formData.toString(),\n form: this.formClass\n }\n }])[0]\n .then((response) => {\n if (!response.submitted) {\n // Form was not submitted, it could be either because validation failed or because no-submit button was pressed.\n this.updateForm({html: response.html, js: Fragment.processCollectedJavascript(response.javascript)});\n this.enableButtons();\n this.trigger(this.events.SERVER_VALIDATION_ERROR, null, false);\n } else {\n // Form was submitted properly.\n const data = JSON.parse(response.data);\n this.enableButtons();\n this.notifyResetFormChanges()\n .then(() => this.onSubmitSuccess(data))\n .catch();\n }\n return null;\n })\n .catch(this.onSubmitError);\n }\n}\n"],"file":"dynamicform.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/dynamicform.js"],"names":["DynamicForm","container","formClass","FORM_SUBMITTED","FORM_CANCELLED","CLIENT_VALIDATION_ERROR","SERVER_VALIDATION_ERROR","ERROR","NOSUBMIT_BUTTON_PRESSED","SUBMIT_BUTTON_PRESSED","CANCEL_BUTTON_PRESSED","key","component","catch","Notification","exception","addEventListener","e","target","matches","preventDefault","event","trigger","events","defaultPrevented","processCancelButton","processNoSubmitButton","submitFormAjax","args","formData","URLSearchParams","Object","entries","pendingPromise","Pending","getBody","toString","then","resp","updateForm","resolve","eventName","detail","cancelable","CustomEvent","dispatchEvent","formDataString","Ajax","call","methodname","formdata","form","response","html","js","Fragment","processCollectedJavascript","javascript","innerHTML","button","getFormNode","FormData","append","getAttribute","FormEvents","notifyFormSubmittedByJavascript","disableButtons","onSubmitError","querySelector","FormChangeChecker","resetFormDirtyState","notifyResetFormChanges","Templates","replaceNodeContents","invalid","querySelectorAll","length","focus","forEach","el","setAttribute","removeAttribute","validateElements","submitted","enableButtons","data","JSON","parse","onSubmitSuccess"],"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 * Display an embedded form, it is only loaded and reloaded inside its container\n *\n * Example:\n * import DynamicForm from 'core_form/dynamicform';\n *\n * const dynamicForm = new DynamicForm(document.querySelector('#mycontainer', 'pluginname\\\\form\\\\formname');\n * dynamicForm.addEventListener(dynamicForm.events.FORM_SUBMITTED, e => {\n * e.preventDefault();\n * window.console.log(e.detail);\n * dynamicForm.container.innerHTML = 'Thank you, your form is submitted!';\n * });\n * dynamicForm.load();\n *\n * See also https://docs.moodle.org/dev/Modal_and_AJAX_forms\n *\n * @module core_form/dynamicform\n * @copyright 2019 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as FormChangeChecker from 'core_form/changechecker';\nimport * as FormEvents from 'core_form/events';\nimport Ajax from 'core/ajax';\nimport Fragment from 'core/fragment';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Templates from 'core/templates';\nimport {get_strings as getStrings} from 'core/str';\n\n/**\n * @class core_form/dynamicform\n */\nexport default class DynamicForm {\n\n /**\n * Various events that can be observed.\n *\n * @type {Object}\n */\n events = {\n // Form was successfully submitted - the response is passed to the event listener.\n // Cancellable (in order to prevent default behavior to clear the container).\n FORM_SUBMITTED: 'core_form_dynamicform_formsubmitted',\n // Cancel button was pressed.\n // Cancellable (in order to prevent default behavior to clear the container).\n FORM_CANCELLED: 'core_form_dynamicform_formcancelled',\n // User attempted to submit the form but there was client-side validation error.\n CLIENT_VALIDATION_ERROR: 'core_form_dynamicform_clientvalidationerror',\n // User attempted to submit the form but server returned validation error.\n SERVER_VALIDATION_ERROR: 'core_form_dynamicform_validationerror',\n // Error occurred while performing request to the server.\n // Cancellable (by default calls Notification.exception).\n ERROR: 'core_form_dynamicform_error',\n // Right after user pressed no-submit button,\n // listen to this event if you want to add JS validation or processing for no-submit button.\n // Cancellable.\n NOSUBMIT_BUTTON_PRESSED: 'core_form_dynamicform_nosubmitbutton',\n // Right after user pressed submit button,\n // listen to this event if you want to add additional JS validation or confirmation dialog.\n // Cancellable.\n SUBMIT_BUTTON_PRESSED: 'core_form_dynamicform_submitbutton',\n // Right after user pressed cancel button,\n // listen to this event if you want to add confirmation dialog.\n // Cancellable.\n CANCEL_BUTTON_PRESSED: 'core_form_dynamicform_cancelbutton',\n };\n\n /**\n * Constructor\n *\n * Creates an instance\n *\n * @param {Element} container - the parent element for the form\n * @param {string} formClass full name of the php class that extends \\core_form\\modal , must be in autoloaded location\n */\n constructor(container, formClass) {\n this.formClass = formClass;\n this.container = container;\n\n // Ensure strings required for shortforms are always available.\n getStrings([\n {key: 'collapseall', component: 'moodle'},\n {key: 'expandall', component: 'moodle'}\n ]).catch(Notification.exception);\n\n // Register delegated events handlers in vanilla JS.\n this.container.addEventListener('click', e => {\n if (e.target.matches('form input[type=submit][data-cancel]')) {\n e.preventDefault();\n const event = this.trigger(this.events.CANCEL_BUTTON_PRESSED, e.target);\n if (!event.defaultPrevented) {\n this.processCancelButton();\n }\n } else if (e.target.matches('form input[type=submit][data-no-submit=\"1\"]')) {\n e.preventDefault();\n const event = this.trigger(this.events.NOSUBMIT_BUTTON_PRESSED, e.target);\n if (!event.defaultPrevented) {\n this.processNoSubmitButton(e.target);\n }\n }\n });\n\n this.container.addEventListener('submit', e => {\n if (e.target.matches('form')) {\n e.preventDefault();\n const event = this.trigger(this.events.SUBMIT_BUTTON_PRESSED);\n if (!event.defaultPrevented) {\n this.submitFormAjax();\n }\n }\n });\n }\n\n /**\n * Loads the form via AJAX and shows it inside a given container\n *\n * @param {Object} args\n * @return {Promise}\n * @public\n */\n load(args = null) {\n const formData = new URLSearchParams(Object.entries(args || {}));\n const pendingPromise = new Pending('core_form/dynamicform:load');\n return this.getBody(formData.toString())\n .then((resp) => this.updateForm(resp))\n .then(pendingPromise.resolve);\n }\n\n /**\n * Triggers a custom event\n *\n * @private\n * @param {String} eventName\n * @param {*} detail\n * @param {Boolean} cancelable\n * @return {CustomEvent}\n */\n trigger(eventName, detail = null, cancelable = true) {\n const e = new CustomEvent(eventName, {detail, cancelable});\n this.container.dispatchEvent(e);\n return e;\n }\n\n /**\n * Add listener for an event\n *\n * Example:\n * const dynamicForm = new DynamicForm(...);\n * dynamicForm.addEventListener(dynamicForm.events.FORM_SUBMITTED, e => {\n * e.preventDefault();\n * window.console.log(e.detail);\n * dynamicForm.container.innerHTML = 'Thank you, your form is submitted!';\n * });\n */\n addEventListener(...args) {\n this.container.addEventListener(...args);\n }\n\n /**\n * Get form body\n *\n * @param {String} formDataString form data in format of a query string\n * @private\n * @return {Promise}\n */\n getBody(formDataString) {\n return Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: {\n formdata: formDataString,\n form: this.formClass,\n }\n }])[0]\n .then(response => {\n return {html: response.html, js: Fragment.processCollectedJavascript(response.javascript)};\n });\n }\n\n /**\n * On form submit\n *\n * @param {*} response Response received from the form's \"process\" method\n */\n onSubmitSuccess(response) {\n const event = this.trigger(this.events.FORM_SUBMITTED, response);\n if (event.defaultPrevented) {\n return;\n }\n\n // Default implementation is to remove the form. Event listener should either remove or reload the form\n // since its contents is no longer correct. For example, if an element was created as a result of\n // form submission, the \"id\" in the form would be still zero. Also the server-side validation\n // errors from the previous submission may still be present.\n this.container.innerHTML = '';\n }\n\n /**\n * On exception during form processing\n *\n * @private\n * @param {Object} exception\n */\n onSubmitError(exception) {\n const event = this.trigger(this.events.ERROR, exception);\n if (event.defaultPrevented) {\n return;\n }\n\n Notification.exception(exception);\n }\n\n /**\n * Click on a \"submit\" button that is marked in the form as registerNoSubmitButton()\n *\n * @method submitButtonPressed\n * @param {Element} button that was pressed\n * @fires event:formSubmittedByJavascript\n */\n processNoSubmitButton(button) {\n const pendingPromise = new Pending('core_form/dynamicform:nosubmit');\n const form = this.getFormNode();\n const formData = new URLSearchParams([...(new FormData(form)).entries()]);\n formData.append(button.getAttribute('name'), button.getAttribute('value'));\n\n FormEvents.notifyFormSubmittedByJavascript(form, true);\n\n // Add the button name to the form data and submit it.\n this.disableButtons();\n\n this.getBody(formData.toString())\n .then(this.updateForm)\n .then(pendingPromise.resolve)\n .catch(this.onSubmitError);\n }\n\n /**\n * Get the form node from the Dialogue.\n *\n * @returns {HTMLFormElement}\n */\n getFormNode() {\n return this.container.querySelector('form');\n }\n\n /**\n * Notifies listeners that form dirty state should be reset.\n *\n * @fires event:formSubmittedByJavascript\n */\n notifyResetFormChanges() {\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);\n FormChangeChecker.resetFormDirtyState(this.getFormNode());\n }\n\n /**\n * Click on a \"cancel\" button\n */\n processCancelButton() {\n // Notify listeners that the form is about to be submitted (this will reset atto autosave).\n this.notifyResetFormChanges();\n\n const event = this.trigger(this.events.FORM_CANCELLED);\n if (!event.defaultPrevented) {\n // By default removes the form from the DOM.\n this.container.innerHTML = '';\n }\n }\n\n /**\n * Update form contents\n *\n * @param {string} html\n * @param {string} js\n * @returns {Promise}\n */\n updateForm({html, js}) {\n return Templates.replaceNodeContents(this.container, html, js);\n }\n\n /**\n * Validate form elements\n * @return {Boolean} Whether client-side validation has passed, false if there are errors\n * @fires event:formSubmittedByJavascript\n */\n validateElements() {\n // Notify listeners that the form is about to be submitted (this will reset atto autosave).\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode());\n\n // Now the change events have run, see if there are any \"invalid\" form fields.\n const invalid = [...this.container.querySelectorAll('[aria-invalid=\"true\"], .error')];\n\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (invalid.length) {\n invalid[0].focus();\n return false;\n }\n\n return true;\n }\n\n /**\n * Disable buttons during form submission\n */\n disableButtons() {\n this.container.querySelectorAll('form input[type=\"submit\"]')\n .forEach(el => el.setAttribute('disabled', true));\n }\n\n /**\n * Enable buttons after form submission (on validation error)\n */\n enableButtons() {\n this.container.querySelectorAll('form input[type=\"submit\"]')\n .forEach(el => el.removeAttribute('disabled'));\n }\n\n /**\n * Submit the form via AJAX call to the core_form_dynamic_form WS\n */\n async submitFormAjax() {\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (!(await this.validateElements())) {\n this.trigger(this.events.CLIENT_VALIDATION_ERROR, null, false);\n return;\n }\n this.disableButtons();\n\n // Convert all the form elements values to a serialised string.\n const form = this.container.querySelector('form');\n const formData = new URLSearchParams([...(new FormData(form)).entries()]);\n\n // Now we can continue...\n Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: {\n formdata: formData.toString(),\n form: this.formClass\n }\n }])[0]\n .then((response) => {\n if (!response.submitted) {\n // Form was not submitted, it could be either because validation failed or because no-submit button was pressed.\n this.updateForm({html: response.html, js: Fragment.processCollectedJavascript(response.javascript)});\n this.enableButtons();\n this.trigger(this.events.SERVER_VALIDATION_ERROR, null, false);\n } else {\n // Form was submitted properly.\n const data = JSON.parse(response.data);\n this.enableButtons();\n this.notifyResetFormChanges();\n this.onSubmitSuccess(data);\n }\n return null;\n })\n .catch(this.onSubmitError);\n }\n}\n"],"file":"dynamicform.min.js"}
\ No newline at end of file
diff --git a/lib/form/amd/build/modalform.min.js b/lib/form/amd/build/modalform.min.js
index aff57249e6f..1c5d2f31e54 100644
--- a/lib/form/amd/build/modalform.min.js
+++ b/lib/form/amd/build/modalform.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_form/modalform",["exports","core/ajax","core_form/events","core/fragment","core/modal_events","core/modal_factory","core/notification","core/pending","core/yui"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=l(b);c=k(c);d=l(d);e=l(e);f=l(f);g=l(g);h=l(h);i=l(i);function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=j();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 l(a){return a&&a.__esModule?a:{default:a}}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}function o(a){return s(a)||r(a)||q(a)||p()}function p(){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 q(a,b){if(!a)return;if("string"==typeof a)return t(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 t(a,b)}function r(a){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(a))return Array.from(a)}function s(a){if(Array.isArray(a))return t(a)}function t(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 * Display a form in a modal dialogue\n *\n * Example:\n * import ModalForm from 'core_form/modalform';\n *\n * const modalForm = new ModalForm({\n * formClass: 'pluginname\\\\form\\\\formname',\n * modalConfig: {title: 'Here comes the title'},\n * args: {categoryid: 123},\n * returnFocus: e.target,\n * });\n * modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (c) => window.console.log(c.detail));\n * modalForm.show();\n *\n * See also https://docs.moodle.org/dev/Modal_and_AJAX_forms\n *\n * @module core_form/modalform\n * @copyright 2018 Mitxel Moriana \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport * as FormEvents from 'core_form/events';\nimport Fragment from 'core/fragment';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Y from 'core/yui';\n\nexport default class ModalForm {\n\n /**\n * Various events that can be observed.\n *\n * @type {Object}\n */\n events = {\n // Form was successfully submitted - the response is passed to the event listener.\n // Cancellable (but it's hardly ever needed to cancel this event).\n FORM_SUBMITTED: 'core_form_modalform_formsubmitted',\n // Cancel button was pressed.\n // Cancellable (but it's hardly ever needed to cancel this event).\n FORM_CANCELLED: 'core_form_modalform_formcancelled',\n // User attempted to submit the form but there was client-side validation error.\n CLIENT_VALIDATION_ERROR: 'core_form_modalform_clientvalidationerror',\n // User attempted to submit the form but server returned validation error.\n SERVER_VALIDATION_ERROR: 'core_form_modalform_validationerror',\n // Error occurred while performing request to the server.\n // Cancellable (by default calls Notification.exception).\n ERROR: 'core_form_modalform_error',\n // Right after user pressed no-submit button,\n // listen to this event if you want to add JS validation or processing for no-submit button.\n // Cancellable.\n NOSUBMIT_BUTTON_PRESSED: 'core_form_modalform_nosubmitbutton',\n // Right after user pressed submit button,\n // listen to this event if you want to add additional JS validation or confirmation dialog.\n // Cancellable.\n SUBMIT_BUTTON_PRESSED: 'core_form_modalform_submitbutton',\n // Right after user pressed cancel button,\n // listen to this event if you want to add confirmation dialog.\n // Cancellable.\n CANCEL_BUTTON_PRESSED: 'core_form_modalform_cancelbutton',\n // Modal was loaded and this.modal is available (but the form content may not be loaded yet).\n LOADED: 'core_form_modalform_loaded',\n };\n\n /**\n * Constructor\n *\n * Shows the required form inside a modal dialogue\n *\n * @param {Object} config parameters for the form and modal dialogue:\n * @property {String} config.formClass PHP class name that handles the form (should extend \\core_form\\modal )\n * @property {Object} config.modalConfig modal config - title, type, etc.\n * Default: {removeOnClose: true, type: ModalFactory.types.SAVE_CANCEL}\n * @property {Object} config.args Arguments for the initial form rendering (for example, id of the edited entity)\n * @property {String} config.saveButtonText the text to display on the Modal \"Save\" button (optional)\n * @property {String} config.saveButtonClasses additional CSS classes for the Modal \"Save\" button\n * @property {HTMLElement} config.returnFocus element to return focus to after the dialogue is closed\n */\n constructor(config) {\n this.modal = null;\n this.config = config;\n this.config.modalConfig = {\n removeOnClose: true,\n type: ModalFactory.types.SAVE_CANCEL,\n large: true,\n ...(this.config.modalConfig || {}),\n };\n this.config.args = this.config.args || {};\n this.futureListeners = [];\n }\n\n /**\n * Initialise the modal and shows it\n *\n * @return {Promise}\n */\n show() {\n const pendingPromise = new Pending('core_form/modalform:init');\n return ModalFactory.create(this.config.modalConfig)\n .then((modal) => {\n this.modal = modal;\n\n // Retrieve the form and set the modal body. We can not set the body in the modalConfig,\n // we need to make sure that the modal already exists when we render the form. Some form elements\n // such as date_selector inspect the existing elements on the page to find the highest z-index.\n const formParams = new URLSearchParams(Object.entries(this.config.args || {}));\n const bodyContent = this.getBody(formParams.toString());\n this.modal.setBodyContent(bodyContent);\n bodyContent.catch(Notification.exception);\n\n // After successfull submit, when we press \"Cancel\" or close the dialogue by clicking on X in the top right corner.\n this.modal.getRoot().on(ModalEvents.hidden, () => {\n this.notifyResetFormChanges()\n .then(() => {\n this.modal.destroy();\n // Focus on the element that actually launched the modal.\n if (this.config.returnFocus) {\n this.config.returnFocus.focus();\n }\n return null;\n })\n .catch(() => null);\n });\n\n // Add the class to the modal dialogue.\n this.modal.getModal().addClass('modal-form-dialogue');\n\n // We catch the press on submit buttons in the forms.\n this.modal.getRoot().on('click', 'form input[type=submit][data-no-submit]',\n (e) => {\n e.preventDefault();\n const event = this.trigger(this.events.NOSUBMIT_BUTTON_PRESSED, e.target);\n if (!event.defaultPrevented) {\n this.processNoSubmitButton(e.target);\n }\n });\n\n // We catch the form submit event and use it to submit the form with ajax.\n this.modal.getRoot().on('submit', 'form', (e) => {\n e.preventDefault();\n const event = this.trigger(this.events.SUBMIT_BUTTON_PRESSED);\n if (!event.defaultPrevented) {\n this.submitFormAjax();\n }\n });\n\n // Change the text for the save button.\n if (typeof this.config.saveButtonText !== 'undefined' &&\n typeof this.modal.setSaveButtonText !== 'undefined') {\n this.modal.setSaveButtonText(this.config.saveButtonText);\n }\n // Set classes for the save button.\n if (typeof this.config.saveButtonClasses !== 'undefined') {\n this.setSaveButtonClasses(this.config.saveButtonClasses);\n }\n // When Save button is pressed - submit the form.\n this.modal.getRoot().on(ModalEvents.save, (e) => {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n });\n\n // When Cancel button is pressed - allow to intercept.\n this.modal.getRoot().on(ModalEvents.cancel, (e) => {\n const event = this.trigger(this.events.CANCEL_BUTTON_PRESSED);\n if (event.defaultPrevented) {\n e.preventDefault();\n }\n });\n this.futureListeners.forEach(args => this.modal.getRoot()[0].addEventListener(...args));\n this.futureListeners = [];\n this.trigger(this.events.LOADED, null, false);\n return this.modal.show();\n })\n .then(pendingPromise.resolve);\n }\n\n /**\n * Triggers a custom event\n *\n * @private\n * @param {String} eventName\n * @param {*} detail\n * @param {Boolean} cancelable\n * @return {CustomEvent}\n */\n trigger(eventName, detail = null, cancelable = true) {\n const e = new CustomEvent(eventName, {detail, cancelable});\n this.modal.getRoot()[0].dispatchEvent(e);\n return e;\n }\n\n /**\n * Add listener for an event\n *\n * Example:\n * const modalForm = new ModalForm(...);\n * dynamicForm.addEventListener(modalForm.events.FORM_SUBMITTED, e => {\n * window.console.log(e.detail);\n * });\n */\n addEventListener(...args) {\n if (!this.modal) {\n this.futureListeners.push(args);\n } else {\n this.modal.getRoot()[0].addEventListener(...args);\n }\n }\n\n /**\n * Get form contents (to be used in ModalForm.setBodyContent())\n *\n * @param {String} formDataString form data in format of a query string\n * @method getBody\n * @private\n * @return {Promise}\n */\n getBody(formDataString) {\n const params = {\n formdata: formDataString,\n form: this.config.formClass\n };\n const pendingPromise = new Pending('core_form/modalform:form_body');\n return Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: params\n }])[0]\n .then(response => {\n pendingPromise.resolve();\n return {html: response.html, js: Fragment.processCollectedJavascript(response.javascript)};\n });\n }\n\n /**\n * On exception during form processing. Caller may override\n *\n * @param {Object} exception\n */\n onSubmitError(exception) {\n const event = this.trigger(this.events.ERROR, exception);\n if (event.defaultPrevented) {\n return;\n }\n\n Notification.exception(exception);\n }\n\n /**\n * Notifies listeners that form dirty state should be reset.\n *\n * @return {Promise}\n * @fires event:formSubmittedByJavascript\n */\n notifyResetFormChanges() {\n const form = this.getFormNode();\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);\n\n if (!form) {\n return Promise.resolve();\n }\n\n return new Promise(resolve => {\n Y.use('event', 'moodle-core-event', 'moodle-core-formchangechecker', () => {\n // Ensure that modal contains a form element (it may not if the form class threw an early exception).\n M.core_formchangechecker.reset_form_dirty_state();\n\n resolve();\n });\n });\n }\n\n /**\n * Get the form node from the Dialogue.\n *\n * @returns {HTMLFormElement}\n */\n getFormNode() {\n return this.modal.getRoot().find('form')[0];\n }\n\n /**\n * Click on a \"submit\" button that is marked in the form as registerNoSubmitButton()\n *\n * @param {Element} button button that was pressed\n * @fires event:formSubmittedByJavascript\n */\n processNoSubmitButton(button) {\n const form = this.getFormNode();\n if (!form) {\n return;\n }\n\n FormEvents.notifyFormSubmittedByJavascript(form, true);\n\n // Add the button name to the form data and submit it.\n let formData = this.modal.getRoot().find('form').serialize();\n formData = formData + '&' + encodeURIComponent(button.getAttribute('name')) + '=' +\n encodeURIComponent(button.getAttribute('value'));\n\n const bodyContent = this.getBody(formData);\n this.modal.setBodyContent(bodyContent);\n bodyContent.catch(Notification.exception);\n }\n\n /**\n * Validate form elements\n * @return {Boolean} Whether client-side validation has passed, false if there are errors\n * @fires event:formSubmittedByJavascript\n */\n validateElements() {\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode());\n\n // Now the change events have run, see if there are any \"invalid\" form fields.\n /** @var {jQuery} list of elements with errors */\n const invalid = this.modal.getRoot().find('[aria-invalid=\"true\"], .error');\n\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (invalid.length) {\n invalid.first().focus();\n return false;\n }\n\n return true;\n }\n\n /**\n * Disable buttons during form submission\n */\n disableButtons() {\n this.modal.getFooter().find('[data-action]').attr('disabled', true);\n }\n\n /**\n * Enable buttons after form submission (on validation error)\n */\n enableButtons() {\n this.modal.getFooter().find('[data-action]').removeAttr('disabled');\n }\n\n /**\n * Submit the form via AJAX call to the core_form_dynamic_form WS\n */\n async submitFormAjax() {\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (!this.validateElements()) {\n this.trigger(this.events.CLIENT_VALIDATION_ERROR, null, false);\n return;\n }\n this.disableButtons();\n\n // Convert all the form elements values to a serialised string.\n const formData = this.modal.getRoot().find('form').serialize();\n\n // Now we can continue...\n Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: {\n formdata: formData,\n form: this.config.formClass\n }\n }])[0]\n .then((response) => {\n if (!response.submitted) {\n // Form was not submitted because validation failed.\n const promise = new Promise(\n resolve => resolve({html: response.html, js: Fragment.processCollectedJavascript(response.javascript)}));\n this.modal.setBodyContent(promise);\n this.enableButtons();\n this.trigger(this.events.SERVER_VALIDATION_ERROR);\n } else {\n // Form was submitted properly. Hide the modal and execute callback.\n const data = JSON.parse(response.data);\n return this.notifyResetFormChanges()\n .then(() => {\n const event = this.trigger(this.events.FORM_SUBMITTED, data);\n if (!event.defaultPrevented) {\n this.modal.hide();\n }\n return null;\n });\n }\n return null;\n })\n .catch(this.onSubmitError);\n }\n\n /**\n * Set the classes for the 'save' button.\n *\n * @method setSaveButtonClasses\n * @param {(String)} value The 'save' button classes.\n */\n setSaveButtonClasses(value) {\n const button = this.modal.getFooter().find(\"[data-action='save']\");\n if (!button) {\n throw new Error(\"Unable to find the 'save' button\");\n }\n button.removeClass().addClass(value);\n }\n}\n"],"file":"modalform.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/modalform.js"],"names":["ModalForm","config","FORM_SUBMITTED","FORM_CANCELLED","CLIENT_VALIDATION_ERROR","SERVER_VALIDATION_ERROR","ERROR","NOSUBMIT_BUTTON_PRESSED","SUBMIT_BUTTON_PRESSED","CANCEL_BUTTON_PRESSED","LOADED","modal","modalConfig","removeOnClose","type","ModalFactory","types","SAVE_CANCEL","large","args","futureListeners","pendingPromise","Pending","create","then","formParams","URLSearchParams","Object","entries","bodyContent","getBody","toString","setBodyContent","catch","Notification","exception","getRoot","on","ModalEvents","hidden","notifyResetFormChanges","destroy","returnFocus","focus","getModal","addClass","e","preventDefault","event","trigger","events","target","defaultPrevented","processNoSubmitButton","submitFormAjax","saveButtonText","setSaveButtonText","saveButtonClasses","setSaveButtonClasses","save","find","submit","cancel","forEach","addEventListener","show","resolve","eventName","detail","cancelable","CustomEvent","dispatchEvent","push","formDataString","params","formdata","form","formClass","Ajax","call","methodname","response","html","js","Fragment","processCollectedJavascript","javascript","getFormNode","FormEvents","notifyFormSubmittedByJavascript","FormChangeChecker","resetFormDirtyState","button","formData","serialize","encodeURIComponent","getAttribute","invalid","length","first","getFooter","attr","removeAttr","validateElements","disableButtons","submitted","promise","Promise","enableButtons","data","JSON","parse","hide","onSubmitError","value","Error","removeClass"],"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 * Display a form in a modal dialogue\n *\n * Example:\n * import ModalForm from 'core_form/modalform';\n *\n * const modalForm = new ModalForm({\n * formClass: 'pluginname\\\\form\\\\formname',\n * modalConfig: {title: 'Here comes the title'},\n * args: {categoryid: 123},\n * returnFocus: e.target,\n * });\n * modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (c) => window.console.log(c.detail));\n * modalForm.show();\n *\n * See also https://docs.moodle.org/dev/Modal_and_AJAX_forms\n *\n * @module core_form/modalform\n * @copyright 2018 Mitxel Moriana \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport * as FormChangeChecker from 'core_form/changechecker';\nimport * as FormEvents from 'core_form/events';\nimport Fragment from 'core/fragment';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\n\nexport default class ModalForm {\n\n /**\n * Various events that can be observed.\n *\n * @type {Object}\n */\n events = {\n // Form was successfully submitted - the response is passed to the event listener.\n // Cancellable (but it's hardly ever needed to cancel this event).\n FORM_SUBMITTED: 'core_form_modalform_formsubmitted',\n // Cancel button was pressed.\n // Cancellable (but it's hardly ever needed to cancel this event).\n FORM_CANCELLED: 'core_form_modalform_formcancelled',\n // User attempted to submit the form but there was client-side validation error.\n CLIENT_VALIDATION_ERROR: 'core_form_modalform_clientvalidationerror',\n // User attempted to submit the form but server returned validation error.\n SERVER_VALIDATION_ERROR: 'core_form_modalform_validationerror',\n // Error occurred while performing request to the server.\n // Cancellable (by default calls Notification.exception).\n ERROR: 'core_form_modalform_error',\n // Right after user pressed no-submit button,\n // listen to this event if you want to add JS validation or processing for no-submit button.\n // Cancellable.\n NOSUBMIT_BUTTON_PRESSED: 'core_form_modalform_nosubmitbutton',\n // Right after user pressed submit button,\n // listen to this event if you want to add additional JS validation or confirmation dialog.\n // Cancellable.\n SUBMIT_BUTTON_PRESSED: 'core_form_modalform_submitbutton',\n // Right after user pressed cancel button,\n // listen to this event if you want to add confirmation dialog.\n // Cancellable.\n CANCEL_BUTTON_PRESSED: 'core_form_modalform_cancelbutton',\n // Modal was loaded and this.modal is available (but the form content may not be loaded yet).\n LOADED: 'core_form_modalform_loaded',\n };\n\n /**\n * Constructor\n *\n * Shows the required form inside a modal dialogue\n *\n * @param {Object} config parameters for the form and modal dialogue:\n * @property {String} config.formClass PHP class name that handles the form (should extend \\core_form\\modal )\n * @property {Object} config.modalConfig modal config - title, type, etc.\n * Default: {removeOnClose: true, type: ModalFactory.types.SAVE_CANCEL}\n * @property {Object} config.args Arguments for the initial form rendering (for example, id of the edited entity)\n * @property {String} config.saveButtonText the text to display on the Modal \"Save\" button (optional)\n * @property {String} config.saveButtonClasses additional CSS classes for the Modal \"Save\" button\n * @property {HTMLElement} config.returnFocus element to return focus to after the dialogue is closed\n */\n constructor(config) {\n this.modal = null;\n this.config = config;\n this.config.modalConfig = {\n removeOnClose: true,\n type: ModalFactory.types.SAVE_CANCEL,\n large: true,\n ...(this.config.modalConfig || {}),\n };\n this.config.args = this.config.args || {};\n this.futureListeners = [];\n }\n\n /**\n * Initialise the modal and shows it\n *\n * @return {Promise}\n */\n show() {\n const pendingPromise = new Pending('core_form/modalform:init');\n return ModalFactory.create(this.config.modalConfig)\n .then((modal) => {\n this.modal = modal;\n\n // Retrieve the form and set the modal body. We can not set the body in the modalConfig,\n // we need to make sure that the modal already exists when we render the form. Some form elements\n // such as date_selector inspect the existing elements on the page to find the highest z-index.\n const formParams = new URLSearchParams(Object.entries(this.config.args || {}));\n const bodyContent = this.getBody(formParams.toString());\n this.modal.setBodyContent(bodyContent);\n bodyContent.catch(Notification.exception);\n\n // After successfull submit, when we press \"Cancel\" or close the dialogue by clicking on X in the top right corner.\n this.modal.getRoot().on(ModalEvents.hidden, () => {\n this.notifyResetFormChanges();\n this.modal.destroy();\n // Focus on the element that actually launched the modal.\n if (this.config.returnFocus) {\n this.config.returnFocus.focus();\n }\n });\n\n // Add the class to the modal dialogue.\n this.modal.getModal().addClass('modal-form-dialogue');\n\n // We catch the press on submit buttons in the forms.\n this.modal.getRoot().on('click', 'form input[type=submit][data-no-submit]',\n (e) => {\n e.preventDefault();\n const event = this.trigger(this.events.NOSUBMIT_BUTTON_PRESSED, e.target);\n if (!event.defaultPrevented) {\n this.processNoSubmitButton(e.target);\n }\n });\n\n // We catch the form submit event and use it to submit the form with ajax.\n this.modal.getRoot().on('submit', 'form', (e) => {\n e.preventDefault();\n const event = this.trigger(this.events.SUBMIT_BUTTON_PRESSED);\n if (!event.defaultPrevented) {\n this.submitFormAjax();\n }\n });\n\n // Change the text for the save button.\n if (typeof this.config.saveButtonText !== 'undefined' &&\n typeof this.modal.setSaveButtonText !== 'undefined') {\n this.modal.setSaveButtonText(this.config.saveButtonText);\n }\n // Set classes for the save button.\n if (typeof this.config.saveButtonClasses !== 'undefined') {\n this.setSaveButtonClasses(this.config.saveButtonClasses);\n }\n // When Save button is pressed - submit the form.\n this.modal.getRoot().on(ModalEvents.save, (e) => {\n e.preventDefault();\n this.modal.getRoot().find('form').submit();\n });\n\n // When Cancel button is pressed - allow to intercept.\n this.modal.getRoot().on(ModalEvents.cancel, (e) => {\n const event = this.trigger(this.events.CANCEL_BUTTON_PRESSED);\n if (event.defaultPrevented) {\n e.preventDefault();\n }\n });\n this.futureListeners.forEach(args => this.modal.getRoot()[0].addEventListener(...args));\n this.futureListeners = [];\n this.trigger(this.events.LOADED, null, false);\n return this.modal.show();\n })\n .then(pendingPromise.resolve);\n }\n\n /**\n * Triggers a custom event\n *\n * @private\n * @param {String} eventName\n * @param {*} detail\n * @param {Boolean} cancelable\n * @return {CustomEvent}\n */\n trigger(eventName, detail = null, cancelable = true) {\n const e = new CustomEvent(eventName, {detail, cancelable});\n this.modal.getRoot()[0].dispatchEvent(e);\n return e;\n }\n\n /**\n * Add listener for an event\n *\n * Example:\n * const modalForm = new ModalForm(...);\n * dynamicForm.addEventListener(modalForm.events.FORM_SUBMITTED, e => {\n * window.console.log(e.detail);\n * });\n */\n addEventListener(...args) {\n if (!this.modal) {\n this.futureListeners.push(args);\n } else {\n this.modal.getRoot()[0].addEventListener(...args);\n }\n }\n\n /**\n * Get form contents (to be used in ModalForm.setBodyContent())\n *\n * @param {String} formDataString form data in format of a query string\n * @method getBody\n * @private\n * @return {Promise}\n */\n getBody(formDataString) {\n const params = {\n formdata: formDataString,\n form: this.config.formClass\n };\n const pendingPromise = new Pending('core_form/modalform:form_body');\n return Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: params\n }])[0]\n .then(response => {\n pendingPromise.resolve();\n return {html: response.html, js: Fragment.processCollectedJavascript(response.javascript)};\n });\n }\n\n /**\n * On exception during form processing. Caller may override\n *\n * @param {Object} exception\n */\n onSubmitError(exception) {\n const event = this.trigger(this.events.ERROR, exception);\n if (event.defaultPrevented) {\n return;\n }\n\n Notification.exception(exception);\n }\n\n /**\n * Notifies listeners that form dirty state should be reset.\n *\n * @fires event:formSubmittedByJavascript\n */\n notifyResetFormChanges() {\n const form = this.getFormNode();\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);\n\n if (!form) {\n return;\n }\n\n FormChangeChecker.resetFormDirtyState(this.getFormNode());\n }\n\n /**\n * Get the form node from the Dialogue.\n *\n * @returns {HTMLFormElement}\n */\n getFormNode() {\n return this.modal.getRoot().find('form')[0];\n }\n\n /**\n * Click on a \"submit\" button that is marked in the form as registerNoSubmitButton()\n *\n * @param {Element} button button that was pressed\n * @fires event:formSubmittedByJavascript\n */\n processNoSubmitButton(button) {\n const form = this.getFormNode();\n if (!form) {\n return;\n }\n\n FormEvents.notifyFormSubmittedByJavascript(form, true);\n\n // Add the button name to the form data and submit it.\n let formData = this.modal.getRoot().find('form').serialize();\n formData = formData + '&' + encodeURIComponent(button.getAttribute('name')) + '=' +\n encodeURIComponent(button.getAttribute('value'));\n\n const bodyContent = this.getBody(formData);\n this.modal.setBodyContent(bodyContent);\n bodyContent.catch(Notification.exception);\n }\n\n /**\n * Validate form elements\n * @return {Boolean} Whether client-side validation has passed, false if there are errors\n * @fires event:formSubmittedByJavascript\n */\n validateElements() {\n FormEvents.notifyFormSubmittedByJavascript(this.getFormNode());\n\n // Now the change events have run, see if there are any \"invalid\" form fields.\n /** @var {jQuery} list of elements with errors */\n const invalid = this.modal.getRoot().find('[aria-invalid=\"true\"], .error');\n\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (invalid.length) {\n invalid.first().focus();\n return false;\n }\n\n return true;\n }\n\n /**\n * Disable buttons during form submission\n */\n disableButtons() {\n this.modal.getFooter().find('[data-action]').attr('disabled', true);\n }\n\n /**\n * Enable buttons after form submission (on validation error)\n */\n enableButtons() {\n this.modal.getFooter().find('[data-action]').removeAttr('disabled');\n }\n\n /**\n * Submit the form via AJAX call to the core_form_dynamic_form WS\n */\n async submitFormAjax() {\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (!this.validateElements()) {\n this.trigger(this.events.CLIENT_VALIDATION_ERROR, null, false);\n return;\n }\n this.disableButtons();\n\n // Convert all the form elements values to a serialised string.\n const formData = this.modal.getRoot().find('form').serialize();\n\n // Now we can continue...\n Ajax.call([{\n methodname: 'core_form_dynamic_form',\n args: {\n formdata: formData,\n form: this.config.formClass\n }\n }])[0]\n .then((response) => {\n if (!response.submitted) {\n // Form was not submitted because validation failed.\n const promise = new Promise(\n resolve => resolve({html: response.html, js: Fragment.processCollectedJavascript(response.javascript)}));\n this.modal.setBodyContent(promise);\n this.enableButtons();\n this.trigger(this.events.SERVER_VALIDATION_ERROR);\n } else {\n // Form was submitted properly. Hide the modal and execute callback.\n const data = JSON.parse(response.data);\n this.notifyResetFormChanges();\n const event = this.trigger(this.events.FORM_SUBMITTED, data);\n if (!event.defaultPrevented) {\n this.modal.hide();\n }\n }\n return null;\n })\n .catch(this.onSubmitError);\n }\n\n /**\n * Set the classes for the 'save' button.\n *\n * @method setSaveButtonClasses\n * @param {(String)} value The 'save' button classes.\n */\n setSaveButtonClasses(value) {\n const button = this.modal.getFooter().find(\"[data-action='save']\");\n if (!button) {\n throw new Error(\"Unable to find the 'save' button\");\n }\n button.removeClass().addClass(value);\n }\n}\n"],"file":"modalform.min.js"}
\ No newline at end of file
diff --git a/lib/form/amd/src/dynamicform.js b/lib/form/amd/src/dynamicform.js
index c7ab32bb0b5..ac458bf3a84 100644
--- a/lib/form/amd/src/dynamicform.js
+++ b/lib/form/amd/src/dynamicform.js
@@ -34,13 +34,13 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-import Ajax from 'core/ajax';
+import * as FormChangeChecker from 'core_form/changechecker';
import * as FormEvents from 'core_form/events';
+import Ajax from 'core/ajax';
import Fragment from 'core/fragment';
import Notification from 'core/notification';
import Pending from 'core/pending';
import Templates from 'core/templates';
-import Y from 'core/yui';
import {get_strings as getStrings} from 'core/str';
/**
@@ -261,18 +261,11 @@ export default class DynamicForm {
/**
* Notifies listeners that form dirty state should be reset.
*
- * @return {Promise}
* @fires event:formSubmittedByJavascript
*/
notifyResetFormChanges() {
FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);
-
- return new Promise(resolve => {
- Y.use('event', 'moodle-core-event', 'moodle-core-formchangechecker', () => {
- M.core_formchangechecker.reset_form_dirty_state();
- resolve();
- });
- });
+ FormChangeChecker.resetFormDirtyState(this.getFormNode());
}
/**
@@ -280,16 +273,13 @@ export default class DynamicForm {
*/
processCancelButton() {
// Notify listeners that the form is about to be submitted (this will reset atto autosave).
- this.notifyResetFormChanges()
- .then(() => {
- const event = this.trigger(this.events.FORM_CANCELLED);
- if (!event.defaultPrevented) {
- // By default removes the form from the DOM.
- this.container.innerHTML = '';
- }
- return null;
- })
- .catch(null);
+ this.notifyResetFormChanges();
+
+ const event = this.trigger(this.events.FORM_CANCELLED);
+ if (!event.defaultPrevented) {
+ // By default removes the form from the DOM.
+ this.container.innerHTML = '';
+ }
}
/**
@@ -373,9 +363,8 @@ export default class DynamicForm {
// Form was submitted properly.
const data = JSON.parse(response.data);
this.enableButtons();
- this.notifyResetFormChanges()
- .then(() => this.onSubmitSuccess(data))
- .catch();
+ this.notifyResetFormChanges();
+ this.onSubmitSuccess(data);
}
return null;
})
diff --git a/lib/form/amd/src/modalform.js b/lib/form/amd/src/modalform.js
index bcdb21ff4b4..1b10dee471a 100644
--- a/lib/form/amd/src/modalform.js
+++ b/lib/form/amd/src/modalform.js
@@ -36,13 +36,13 @@
*/
import Ajax from 'core/ajax';
+import * as FormChangeChecker from 'core_form/changechecker';
import * as FormEvents from 'core_form/events';
import Fragment from 'core/fragment';
import ModalEvents from 'core/modal_events';
import ModalFactory from 'core/modal_factory';
import Notification from 'core/notification';
import Pending from 'core/pending';
-import Y from 'core/yui';
export default class ModalForm {
@@ -129,16 +129,12 @@ export default class ModalForm {
// After successfull submit, when we press "Cancel" or close the dialogue by clicking on X in the top right corner.
this.modal.getRoot().on(ModalEvents.hidden, () => {
- this.notifyResetFormChanges()
- .then(() => {
- this.modal.destroy();
- // Focus on the element that actually launched the modal.
- if (this.config.returnFocus) {
- this.config.returnFocus.focus();
- }
- return null;
- })
- .catch(() => null);
+ this.notifyResetFormChanges();
+ this.modal.destroy();
+ // Focus on the element that actually launched the modal.
+ if (this.config.returnFocus) {
+ this.config.returnFocus.focus();
+ }
});
// Add the class to the modal dialogue.
@@ -266,7 +262,6 @@ export default class ModalForm {
/**
* Notifies listeners that form dirty state should be reset.
*
- * @return {Promise}
* @fires event:formSubmittedByJavascript
*/
notifyResetFormChanges() {
@@ -274,17 +269,10 @@ export default class ModalForm {
FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);
if (!form) {
- return Promise.resolve();
+ return;
}
- return new Promise(resolve => {
- Y.use('event', 'moodle-core-event', 'moodle-core-formchangechecker', () => {
- // Ensure that modal contains a form element (it may not if the form class threw an early exception).
- M.core_formchangechecker.reset_form_dirty_state();
-
- resolve();
- });
- });
+ FormChangeChecker.resetFormDirtyState(this.getFormNode());
}
/**
@@ -388,14 +376,11 @@ export default class ModalForm {
} else {
// Form was submitted properly. Hide the modal and execute callback.
const data = JSON.parse(response.data);
- return this.notifyResetFormChanges()
- .then(() => {
- const event = this.trigger(this.events.FORM_SUBMITTED, data);
- if (!event.defaultPrevented) {
- this.modal.hide();
- }
- return null;
- });
+ this.notifyResetFormChanges();
+ const event = this.trigger(this.events.FORM_SUBMITTED, data);
+ if (!event.defaultPrevented) {
+ this.modal.hide();
+ }
}
return null;
})
diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js
index eb6ee68af91..e6c5045812f 100644
--- a/lib/form/filemanager.js
+++ b/lib/form/filemanager.js
@@ -38,12 +38,21 @@
* this.options.itemid
*/
+/* eslint camelcase: off */
-M.form_filemanager = {templates:{}};
+M.form_filemanager = {
+ templates: {},
+ formChangeChecker: null,
+};
+
+require(['core_form/changechecker'], function(FormChangeChecker) {
+ // This is a nasty, hacky, way of doing it but it's the smallest evil.
+ M.form_filemanager.formChangeChecker = FormChangeChecker;
+});
M.form_filemanager.set_templates = function(Y, templates) {
M.form_filemanager.templates = templates;
-}
+};
/**
* This fucntion is called for each file picker on page.
@@ -199,9 +208,7 @@ M.form_filemanager.init = function(Y, options) {
this.filecount++;
this.check_buttons();
this.refresh(this.currentpath);
- if (typeof M.core_formchangechecker != 'undefined') {
- M.core_formchangechecker.set_form_changed();
- }
+ M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.filemanager.getDOMNode());
},
check_buttons: function() {
if (this.filecount>0) {
@@ -328,9 +335,7 @@ M.form_filemanager.init = function(Y, options) {
scope.mkdir_dialog.hide();
scope.refresh(filepath);
Y.one('#fm-newname-'+scope.client_id).set('value', '');
- if (typeof M.core_formchangechecker != 'undefined') {
- M.core_formchangechecker.set_form_changed();
- }
+ M.form_filemanager.formChangeChecker.markFormChangedFromNode(scope.filemanager.getDOMNode());
}
});
};
@@ -460,9 +465,7 @@ M.form_filemanager.init = function(Y, options) {
if (obj && obj.length) {
args.scope.refresh(obj[0]);
}
- if (typeof M.core_formchangechecker != 'undefined') {
- M.core_formchangechecker.set_form_changed();
- }
+ M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.scope.filemanager.getDOMNode());
}
});
};
@@ -853,9 +856,7 @@ M.form_filemanager.init = function(Y, options) {
} else {
args.scope.selectui.hide();
args.scope.refresh((obj && obj.filepath) ? obj.filepath : '/');
- if (typeof M.core_formchangechecker != 'undefined') {
- M.core_formchangechecker.set_form_changed();
- }
+ M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.scope.filemanager.getDOMNode());
}
}
});
@@ -970,9 +971,7 @@ M.form_filemanager.init = function(Y, options) {
//args.scope.selectui.hide();
args.scope.filecount--;
args.scope.refresh(obj.filepath);
- if (typeof M.core_formchangechecker != 'undefined') {
- M.core_formchangechecker.set_form_changed();
- }
+ M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.scope.filemanager.getDOMNode());
}
});
};
diff --git a/lib/formslib.php b/lib/formslib.php
index 8e3775ab15f..f680f5827da 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -1615,7 +1615,7 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
*/
var $_disableShortforms = false;
- /** @var bool whether to automatically initialise M.formchangechecker for this form. */
+ /** @var bool whether to automatically initialise the form change detector this form. */
protected $_use_form_change_checker = true;
/**
@@ -3135,14 +3135,10 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
}
if ($form->is_form_change_checker_enabled()) {
- $PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => $formid,
- 'initialdirtystate' => $form->is_dirty(),
- ))
- );
- $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+ $PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', [$formid]);
+ if ($form->is_dirty()) {
+ $PAGE->requires->js_call_amd('core_form/changechecker', 'markFormAsDirtyById', [$formid]);
+ }
}
if (!empty($this->_collapsibleElements)) {
if (count($this->_collapsibleElements) > 1) {
diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index a4296ee3aca..02271a75e12 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -242,84 +242,84 @@ M.util.show_confirm_dialog = function(e, args) {
e.preventDefault();
}
- YUI().use('moodle-core-notification-confirm', function(Y) {
- var confirmationDialogue = new M.core.confirm({
- width: '300px',
- center: true,
- modal: true,
- visible: false,
- draggable: false,
- title: M.util.get_string('confirmation', 'admin'),
- noLabel: M.util.get_string('cancel', 'moodle'),
- question: args.message
- });
+ require(['core_form/changechecker'], function(FormChangeChecker) {
+ // eslint-disable-next-line no-undef, new-cap
+ YUI().use('moodle-core-notification-confirm', function(Y) {
+ var confirmationDialogue = new M.core.confirm({
+ width: '300px',
+ center: true,
+ modal: true,
+ visible: false,
+ draggable: false,
+ title: M.util.get_string('confirmation', 'admin'),
+ noLabel: M.util.get_string('cancel', 'moodle'),
+ question: args.message
+ });
- // The dialogue was submitted with a positive value indication.
- confirmationDialogue.on('complete-yes', function(e) {
- // Handle any callbacks.
- if (args.callback) {
- if (!Y.Lang.isFunction(args.callback)) {
- Y.log('Callbacks to show_confirm_dialog must now be functions. Please update your code to pass in a function instead.',
- 'warn', 'M.util.show_confirm_dialog');
- return;
- }
-
- var scope = e.target;
- if (Y.Lang.isObject(args.scope)) {
- scope = args.scope;
- }
-
- var callbackargs = args.callbackargs || [];
- args.callback.apply(scope, callbackargs);
- return;
- }
-
- var targetancestor = null,
- targetform = null;
-
- if (target.test('a')) {
- window.location = target.get('href');
-
- } else if ((targetancestor = target.ancestor('a')) !== null) {
- window.location = targetancestor.get('href');
-
- } else if (target.test('input') || target.test('button')) {
- targetform = target.ancestor('form', true);
- if (!targetform) {
- return;
- }
- if (target.get('name') && target.get('value')) {
- targetform.append(' ');
- if (typeof M.core_formchangechecker !== 'undefined') {
- M.core_formchangechecker.set_form_submitted();
+ // The dialogue was submitted with a positive value indication.
+ confirmationDialogue.on('complete-yes', function(e) {
+ // Handle any callbacks.
+ if (args.callback) {
+ if (!Y.Lang.isFunction(args.callback)) {
+ Y.log('Callbacks to show_confirm_dialog must now be functions. ' +
+ 'Please update your code to pass in a function instead.',
+ 'warn', 'M.util.show_confirm_dialog');
+ return;
}
- }
- targetform.submit();
- } else if (target.test('form')) {
- if (typeof M.core_formchangechecker !== 'undefined') {
- M.core_formchangechecker.set_form_submitted();
- }
- target.submit();
+ var scope = e.target;
+ if (Y.Lang.isObject(args.scope)) {
+ scope = args.scope;
+ }
- } else {
- Y.log("Element of type " + target.get('tagName') +
- " is not supported by the M.util.show_confirm_dialog function. Use A, INPUT, BUTTON or FORM",
- 'warn', 'javascript-static');
+ var callbackargs = args.callbackargs || [];
+ args.callback.apply(scope, callbackargs);
+ return;
+ }
+
+ var targetancestor = null,
+ targetform = null;
+
+ if (target.test('a')) {
+ window.location = target.get('href');
+
+ } else if ((targetancestor = target.ancestor('a')) !== null) {
+ window.location = targetancestor.get('href');
+
+ } else if (target.test('input') || target.test('button')) {
+ targetform = target.ancestor('form', true);
+ if (!targetform) {
+ return;
+ }
+ if (target.get('name') && target.get('value')) {
+ targetform.append(' ');
+ FormChangeChecker.markFormAsDirty(targetform);
+ }
+ targetform.submit();
+
+ } else if (target.test('form')) {
+ FormChangeChecker.markFormAsDirty(target);
+ target.submit();
+
+ } else {
+ Y.log("Element of type " + target.get('tagName') +
+ " is not supported by the M.util.show_confirm_dialog function. Use A, INPUT, BUTTON or FORM",
+ 'warn', 'javascript-static');
+ }
+ }, this);
+
+ if (args.cancellabel) {
+ confirmationDialogue.set('noLabel', args.cancellabel);
}
- }, this);
- if (args.cancellabel) {
- confirmationDialogue.set('noLabel', args.cancellabel);
- }
+ if (args.continuelabel) {
+ confirmationDialogue.set('yesLabel', args.continuelabel);
+ }
- if (args.continuelabel) {
- confirmationDialogue.set('yesLabel', args.continuelabel);
- }
-
- confirmationDialogue.render()
- .show();
+ confirmationDialogue.render()
+ .show();
+ });
});
};
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index b20215da4fe..69677c274f6 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -4220,8 +4220,6 @@ EOD;
'page' => $this->page
);
}
-
- $this->page->requires->string_for_js('changesmadereallygoaway', 'moodle');
}
} else {
$heading = null;
diff --git a/mod/assign/amd/build/grading_panel.min.js b/mod/assign/amd/build/grading_panel.min.js
index a60153767e2..0696fb746a8 100644
--- a/mod/assign/amd/build/grading_panel.min.js
+++ b/mod/assign/amd/build/grading_panel.min.js
@@ -1,2 +1,2 @@
-define ("mod_assign/grading_panel",["jquery","core/yui","core/notification","core/templates","core/fragment","core/ajax","core/str","mod_assign/grading_form_change_checker","mod_assign/grading_events","core_form/events","core/toast"],function(a,b,c,d,e,f,g,h,i,j,k){var l=function(b){this._regionSelector=b;this._region=a(b);this._userCache=[];this.registerEventListeners()};l.prototype._regionSelector=null;l.prototype._lastUserId=0;l.prototype._lastAttemptNumber=-1;l.prototype._region=null;l.prototype.nextUserId=null;l.prototype.nextUser=!1;l.prototype._niceReplaceNodeContents=function(b,c,e){var f=a.Deferred();b.fadeOut("fast",function(){d.replaceNodeContents(b,c,e);b.fadeIn("fast",function(){f.resolve()})});return f.promise()};l.prototype._saveFormState=function(){var b=a("[data-region=\"grading-actions-form\"] [name=\"sendstudentnotifications\"]").prop("checked");a(".gradeform [name=\"sendstudentnotifications\"]").val(b)};l.prototype._submitForm=function(b,d,e){var g=document.querySelector(".comment-area");if(g){var h=g.querySelector(".db > textarea");if(""!==h.value){var i=g.querySelector(".fd a[id^=\"comment-action-post-\"]");i.click()}}var k=a(this._region.find("form.gradeform"));a("[data-region=\"overlay\"]").show();k.trigger("save-form-state");j.notifyFormSubmittedByJavascript(k[0]);var l=k.serialize(),m=this._region.attr("data-assignmentid");f.call([{methodname:"mod_assign_submit_grading_form",args:{assignmentid:m,userid:this._lastUserId,jsonformdata:JSON.stringify(l)},done:this._handleFormSubmissionResponse.bind(this,l,d,e),fail:c.exception}])};l.prototype._handleFormSubmissionResponse=function(d,e,f,h){if("undefined"==typeof e){e=this._lastUserId}if(h.length){a(document).trigger("reset",[this._lastUserId,d])}else{g.get_strings([{key:"gradechangessaveddetail",component:"mod_assign"}]).done(function(a){k.add(a[0])}).fail(c.exception);b.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});if(e==this._lastUserId){a(document).trigger("reset",e)}else if(f){a(document).trigger("done-saving-show-next",!0)}else{a(document).trigger("user-changed",e)}}a("[data-region=\"overlay\"]").hide()};l.prototype._resetForm=function(b,c,d){var e=a.Event("custom");if("undefined"==typeof c){c=this._lastUserId}this._lastUserId=0;this._refreshGradingPanel(e,c,d)};l.prototype._chooseAttempt=function(b){var d=a(b.target),e=d.data("submissions"),f=a(document.getElementById(e)),h=f.clone(),i=h.wrap(a("")).html();g.get_strings([{key:"viewadifferentattempt",component:"mod_assign"},{key:"view",component:"core"},{key:"cancel",component:"core"}]).done(function(b){c.confirm(b[0],i,b[1],b[2],function(){var b=a("input:radio[name='select-attemptnumber']:checked").val();this._refreshGradingPanel(null,this._lastUserId,"",b)}.bind(this))}.bind(this)).fail(c.exception)};l.prototype._addPopoutButtons=function(b){var e=a(b);d.render("mod_assign/popout_button",{}).done(function(a){var b=e.find("[data-fieldtype=\"filemanager\"],[data-fieldtype=\"editor\"],[data-fieldtype=\"grading\"]").closest(".fitem");b.addClass("has-popout").find("label").parent().append(a);e.on("click","[data-region=\"popout-button\"]",this._togglePopout.bind(this))}.bind(this)).fail(c.exception)};l.prototype._togglePopout=function(b){b.preventDefault();var c=a(b.target).closest(".fitem");if(c.hasClass("popout")){a(".popout").removeClass("popout")}else{a(".popout").removeClass("popout");c.addClass("popout");c.addClass("moodle-has-zindex")}};l.prototype._refreshGradingPanel=function(b,f,g,i){var j=this._region.attr("data-contextid");if("undefined"==typeof g){g=""}if("undefined"==typeof i){i=-1}if(this._lastUserId==f&&this._lastAttemptNumber==i&&""===g){return}this._lastUserId=f;this._lastAttemptNumber=i;a(document).trigger("start-loading-user");window.M.util.js_pending("mod-assign-loading-user");d.render("mod_assign/loading",{}).done(function(b,d){this._niceReplaceNodeContents(this._region,b,d).done(function(){if(0 textarea");if(""!==h.value){var i=g.querySelector(".fd a[id^=\"comment-action-post-\"]");i.click()}}var k=a(this._region.find("form.gradeform"));a("[data-region=\"overlay\"]").show();l.markFormSubmitted(k[0]);k.trigger("save-form-state");j.notifyFormSubmittedByJavascript(k[0]);var m=k.serialize(),n=this._region.attr("data-assignmentid");f.call([{methodname:"mod_assign_submit_grading_form",args:{assignmentid:n,userid:this._lastUserId,jsonformdata:JSON.stringify(m)},done:this._handleFormSubmissionResponse.bind(this,m,d,e),fail:c.exception}])};m.prototype._handleFormSubmissionResponse=function(b,d,e,f){if("undefined"==typeof d){d=this._lastUserId}if(f.length){a(document).trigger("reset",[this._lastUserId,b])}else{g.get_string("gradechangessaveddetail","mod_assign").then(function(a){k.add(a);return a}).catch(c.exception);var h=a(this._region.find("form.gradeform"));l.resetFormDirtyState(h[0]);if(d==this._lastUserId){a(document).trigger("reset",d)}else if(e){a(document).trigger("done-saving-show-next",!0)}else{a(document).trigger("user-changed",d)}}a("[data-region=\"overlay\"]").hide()};m.prototype._resetForm=function(b,c,d){var e=a.Event("custom");if("undefined"==typeof c){c=this._lastUserId}this._lastUserId=0;this._refreshGradingPanel(e,c,d)};m.prototype._chooseAttempt=function(b){var d=a(b.target),e=d.data("submissions"),f=a(document.getElementById(e)),h=f.clone(),i=h.wrap(a("")).html();g.get_strings([{key:"viewadifferentattempt",component:"mod_assign"},{key:"view",component:"core"},{key:"cancel",component:"core"}]).done(function(b){c.confirm(b[0],i,b[1],b[2],function(){var b=a("input:radio[name='select-attemptnumber']:checked").val();this._refreshGradingPanel(null,this._lastUserId,"",b)}.bind(this))}.bind(this)).fail(c.exception)};m.prototype._addPopoutButtons=function(b){var e=a(b);d.render("mod_assign/popout_button",{}).done(function(a){var b=e.find("[data-fieldtype=\"filemanager\"],[data-fieldtype=\"editor\"],[data-fieldtype=\"grading\"]").closest(".fitem");b.addClass("has-popout").find("label").parent().append(a);e.on("click","[data-region=\"popout-button\"]",this._togglePopout.bind(this))}.bind(this)).fail(c.exception)};m.prototype._togglePopout=function(b){b.preventDefault();var c=a(b.target).closest(".fitem");if(c.hasClass("popout")){a(".popout").removeClass("popout")}else{a(".popout").removeClass("popout");c.addClass("popout");c.addClass("moodle-has-zindex")}};m.prototype._refreshGradingPanel=function(b,f,g,i){var j=this._region.attr("data-contextid");if("undefined"==typeof g){g=""}if("undefined"==typeof i){i=-1}if(this._lastUserId==f&&this._lastAttemptNumber==i&&""===g){return}this._lastUserId=f;this._lastAttemptNumber=i;a(document).trigger("start-loading-user");window.M.util.js_pending("mod-assign-loading-user");d.render("mod_assign/loading",{}).done(function(b,d){this._niceReplaceNodeContents(this._region,b,d).done(function(){if(0 .\n\n/**\n * Javascript controller for the \"Grading\" panel at the right of the page.\n *\n * @module mod_assign/grading_panel\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.1\n */\ndefine([\n 'jquery', 'core/yui', 'core/notification', 'core/templates', 'core/fragment',\n 'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker',\n 'mod_assign/grading_events', 'core_form/events', 'core/toast'\n],\nfunction($, Y, notification, templates, fragment, ajax, str, checker, GradingEvents, FormEvents, Toast) {\n\n /**\n * GradingPanel class.\n *\n * @class mod_assign/grading_panel\n * @param {String} selector The selector for the page region containing the user navigation.\n */\n var GradingPanel = function(selector) {\n this._regionSelector = selector;\n this._region = $(selector);\n this._userCache = [];\n\n this.registerEventListeners();\n };\n\n /** @property {String} Selector for the page region containing the user navigation. */\n GradingPanel.prototype._regionSelector = null;\n\n /** @property {Integer} Remember the last user id to prevent unnessecary reloads. */\n GradingPanel.prototype._lastUserId = 0;\n\n /** @property {Integer} Remember the last attempt number to prevent unnessecary reloads. */\n GradingPanel.prototype._lastAttemptNumber = -1;\n\n /** @property {JQuery} JQuery node for the page region containing the user navigation. */\n GradingPanel.prototype._region = null;\n\n /** @property {Integer} The id of the next user in the grading list */\n GradingPanel.prototype.nextUserId = null;\n\n /** @property {Boolean} Next user exists in the grading list */\n GradingPanel.prototype.nextUser = false;\n\n /**\n * Fade the dom node out, update it, and fade it back.\n *\n * @private\n * @method _niceReplaceNodeContents\n * @param {JQuery} node\n * @param {String} html\n * @param {String} js\n * @return {Deferred} promise resolved when the animations are complete.\n */\n GradingPanel.prototype._niceReplaceNodeContents = function(node, html, js) {\n var promise = $.Deferred();\n\n node.fadeOut(\"fast\", function() {\n templates.replaceNodeContents(node, html, js);\n node.fadeIn(\"fast\", function() {\n promise.resolve();\n });\n });\n\n return promise.promise();\n };\n\n /**\n * Make sure all form fields have the latest saved state.\n * @private\n * @method _saveFormState\n */\n GradingPanel.prototype._saveFormState = function() {\n // Copy data from notify students checkbox which was moved out of the form.\n var checked = $('[data-region=\"grading-actions-form\"] [name=\"sendstudentnotifications\"]').prop(\"checked\");\n $('.gradeform [name=\"sendstudentnotifications\"]').val(checked);\n };\n\n /**\n * Make form submit via ajax.\n *\n * @private\n * @param {Object} event\n * @param {Integer} nextUserId\n * @param {Boolean} nextUser optional. Load next user in the grading list.\n * @method _submitForm\n * @fires event:formSubmittedByJavascript\n */\n GradingPanel.prototype._submitForm = function(event, nextUserId, nextUser) {\n // If the form has data in comment-area, then we need to save that comment\n var commentAreaElement = document.querySelector('.comment-area');\n if (commentAreaElement) {\n var commentTextAreaElement = commentAreaElement.querySelector('.db > textarea');\n if (commentTextAreaElement.value !== '') {\n var commentActionPostElement = commentAreaElement.querySelector('.fd a[id^=\"comment-action-post-\"]');\n commentActionPostElement.click();\n }\n }\n\n // The form was submitted - send it via ajax instead.\n var form = $(this._region.find('form.gradeform'));\n\n $('[data-region=\"overlay\"]').show();\n\n // We call this, so other modules can update the form with the latest state.\n form.trigger('save-form-state');\n\n // Tell all form fields we are about to submit the form.\n FormEvents.notifyFormSubmittedByJavascript(form[0]);\n\n // Now we get all the current values from the form.\n var data = form.serialize();\n var assignmentid = this._region.attr('data-assignmentid');\n\n // Now we can continue...\n ajax.call([{\n methodname: 'mod_assign_submit_grading_form',\n args: {assignmentid: assignmentid, userid: this._lastUserId, jsonformdata: JSON.stringify(data)},\n done: this._handleFormSubmissionResponse.bind(this, data, nextUserId, nextUser),\n fail: notification.exception\n }]);\n };\n\n /**\n * Handle form submission response.\n *\n * @private\n * @method _handleFormSubmissionResponse\n * @param {Array} formdata - submitted values\n * @param {Integer} nextUserId - optional. The id of the user to load after the form is saved.\n * @param {Array} response List of errors.\n * @param {Boolean} nextUser - optional. If true, switch to next user in the grading list.\n */\n GradingPanel.prototype._handleFormSubmissionResponse = function(formdata, nextUserId, nextUser, response) {\n if (typeof nextUserId === \"undefined\") {\n nextUserId = this._lastUserId;\n }\n if (response.length) {\n // There was an error saving the grade. Re-render the form using the submitted data so we can show\n // validation errors.\n $(document).trigger('reset', [this._lastUserId, formdata]);\n } else {\n str.get_strings([\n {key: 'gradechangessaveddetail', component: 'mod_assign'},\n ]).done(function(strs) {\n Toast.add(strs[0]);\n }).fail(notification.exception);\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n if (nextUserId == this._lastUserId) {\n $(document).trigger('reset', nextUserId);\n } else if (nextUser) {\n $(document).trigger('done-saving-show-next', true);\n } else {\n $(document).trigger('user-changed', nextUserId);\n }\n }\n $('[data-region=\"overlay\"]').hide();\n };\n\n /**\n * Refresh form with default values.\n *\n * @private\n * @method _resetForm\n * @param {Event} e\n * @param {Integer} userid\n * @param {Array} formdata\n */\n GradingPanel.prototype._resetForm = function(e, userid, formdata) {\n // The form was cancelled - refresh with default values.\n var event = $.Event(\"custom\");\n if (typeof userid == \"undefined\") {\n userid = this._lastUserId;\n }\n this._lastUserId = 0;\n this._refreshGradingPanel(event, userid, formdata);\n };\n\n /**\n * Open a picker to choose an older attempt.\n *\n * @private\n * @param {Object} e\n * @method _chooseAttempt\n */\n GradingPanel.prototype._chooseAttempt = function(e) {\n // Show a dialog.\n\n // The form is in the element pointed to by data-submissions.\n var link = $(e.target);\n var submissionsId = link.data('submissions');\n var submissionsform = $(document.getElementById(submissionsId));\n var formcopy = submissionsform.clone();\n var formhtml = formcopy.wrap($('')).html();\n\n str.get_strings([\n {key: 'viewadifferentattempt', component: 'mod_assign'},\n {key: 'view', component: 'core'},\n {key: 'cancel', component: 'core'},\n ]).done(function(strs) {\n notification.confirm(strs[0], formhtml, strs[1], strs[2], function() {\n var attemptnumber = $(\"input:radio[name='select-attemptnumber']:checked\").val();\n\n this._refreshGradingPanel(null, this._lastUserId, '', attemptnumber);\n }.bind(this));\n }.bind(this)).fail(notification.exception);\n };\n\n /**\n * Add popout buttons\n *\n * @private\n * @method _addPopoutButtons\n * @param {JQuery} selector The region selector to add popout buttons to.\n */\n GradingPanel.prototype._addPopoutButtons = function(selector) {\n var region = $(selector);\n\n templates.render('mod_assign/popout_button', {}).done(function(html) {\n var parents = region.find('[data-fieldtype=\"filemanager\"],[data-fieldtype=\"editor\"],[data-fieldtype=\"grading\"]')\n .closest('.fitem');\n parents.addClass('has-popout').find('label').parent().append(html);\n\n region.on('click', '[data-region=\"popout-button\"]', this._togglePopout.bind(this));\n }.bind(this)).fail(notification.exception);\n };\n\n /**\n * Make a div \"popout\" or \"popback\".\n *\n * @private\n * @method _togglePopout\n * @param {Event} event\n */\n GradingPanel.prototype._togglePopout = function(event) {\n event.preventDefault();\n var container = $(event.target).closest('.fitem');\n if (container.hasClass('popout')) {\n $('.popout').removeClass('popout');\n } else {\n $('.popout').removeClass('popout');\n container.addClass('popout');\n container.addClass('moodle-has-zindex');\n }\n };\n\n /**\n * Get the user context - re-render the template in the page.\n *\n * @private\n * @method _refreshGradingPanel\n * @param {Event} event\n * @param {Number} userid\n * @param {String} submissiondata serialised submission data.\n * @param {Integer} attemptnumber\n */\n GradingPanel.prototype._refreshGradingPanel = function(event, userid, submissiondata, attemptnumber) {\n var contextid = this._region.attr('data-contextid');\n if (typeof submissiondata === 'undefined') {\n submissiondata = '';\n }\n if (typeof attemptnumber === 'undefined') {\n attemptnumber = -1;\n }\n // Skip reloading if it is the same user.\n if (this._lastUserId == userid && this._lastAttemptNumber == attemptnumber && submissiondata === '') {\n return;\n }\n this._lastUserId = userid;\n this._lastAttemptNumber = attemptnumber;\n $(document).trigger('start-loading-user');\n // Tell behat to back off too.\n window.M.util.js_pending('mod-assign-loading-user');\n // First insert the loading template.\n templates.render('mod_assign/loading', {}).done(function(html, js) {\n // Update the page.\n this._niceReplaceNodeContents(this._region, html, js).done(function() {\n if (userid > 0) {\n this._region.show();\n // Reload the grading form \"fragment\" for this user.\n var params = {userid: userid, attemptnumber: attemptnumber, jsonformdata: JSON.stringify(submissiondata)};\n fragment.loadFragment('mod_assign', 'gradingpanel', contextid, params).done(function(html, js) {\n this._niceReplaceNodeContents(this._region, html, js)\n .done(function() {\n checker.saveFormState('[data-region=\"grade-panel\"] .gradeform');\n $(document).on('editor-content-restored', function() {\n // If the editor has some content that has been restored\n // then save the form state again for comparison.\n checker.saveFormState('[data-region=\"grade-panel\"] .gradeform');\n });\n $('[data-region=\"attempt-chooser\"]').on('click', this._chooseAttempt.bind(this));\n this._addPopoutButtons('[data-region=\"grade-panel\"] .gradeform');\n $(document).trigger('finish-loading-user');\n // Tell behat we are friends again.\n window.M.util.js_complete('mod-assign-loading-user');\n }.bind(this))\n .fail(notification.exception);\n }.bind(this)).fail(notification.exception);\n $('[data-region=\"review-panel\"]').show();\n } else {\n this._region.hide();\n $('[data-region=\"review-panel\"]').hide();\n $(document).trigger('finish-loading-user');\n // Tell behat we are friends again.\n window.M.util.js_complete('mod-assign-loading-user');\n }\n }.bind(this));\n }.bind(this)).fail(notification.exception);\n };\n\n /**\n * Get next user data and store it in global variables\n *\n * @private\n * @method _getNextUser\n * @param {Event} event\n * @param {Object} data Next user's data\n */\n GradingPanel.prototype._getNextUser = function(event, data) {\n this.nextUserId = data.nextUserId;\n this.nextUser = data.nextUser;\n };\n\n /**\n * Handle the save-and-show-next event\n *\n * @private\n * @method _handleSaveAndShowNext\n */\n GradingPanel.prototype._handleSaveAndShowNext = function() {\n this._submitForm(null, this.nextUserId, this.nextUser);\n };\n\n /**\n * Get the grade panel element.\n *\n * @method getPanelElement\n * @return {jQuery}\n */\n GradingPanel.prototype.getPanelElement = function() {\n return $('[data-region=\"grade-panel\"]');\n };\n\n /**\n * Hide the grade panel.\n *\n * @method collapsePanel\n */\n GradingPanel.prototype.collapsePanel = function() {\n this.getPanelElement().addClass('collapsed');\n };\n\n /**\n * Show the grade panel.\n *\n * @method expandPanel\n */\n GradingPanel.prototype.expandPanel = function() {\n this.getPanelElement().removeClass('collapsed');\n };\n\n /**\n * Register event listeners for the grade panel.\n *\n * @method registerEventListeners\n */\n GradingPanel.prototype.registerEventListeners = function() {\n var docElement = $(document);\n var region = $(this._region);\n // Add an event listener to prevent form submission when pressing enter key.\n region.on('submit', 'form', function(e) {\n e.preventDefault();\n });\n\n docElement.on('next-user', this._getNextUser.bind(this));\n docElement.on('user-changed', this._refreshGradingPanel.bind(this));\n docElement.on('save-changes', this._submitForm.bind(this));\n docElement.on('save-and-show-next', this._handleSaveAndShowNext.bind(this));\n docElement.on('reset', this._resetForm.bind(this));\n\n docElement.on('save-form-state', this._saveFormState.bind(this));\n\n docElement.on(GradingEvents.COLLAPSE_GRADE_PANEL, function() {\n this.collapsePanel();\n }.bind(this));\n\n // We should expand if the review panel is collapsed.\n docElement.on(GradingEvents.COLLAPSE_REVIEW_PANEL, function() {\n this.expandPanel();\n }.bind(this));\n\n docElement.on(GradingEvents.EXPAND_GRADE_PANEL, function() {\n this.expandPanel();\n }.bind(this));\n };\n\n return GradingPanel;\n});\n"],"file":"grading_panel.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/grading_panel.js"],"names":["define","$","Y","notification","templates","fragment","ajax","str","checker","GradingEvents","FormEvents","Toast","FormChangeChecker","GradingPanel","selector","_regionSelector","_region","_userCache","registerEventListeners","prototype","_lastUserId","_lastAttemptNumber","nextUserId","nextUser","_niceReplaceNodeContents","node","html","js","promise","Deferred","fadeOut","replaceNodeContents","fadeIn","resolve","_saveFormState","checked","prop","val","_submitForm","event","commentAreaElement","document","querySelector","commentTextAreaElement","value","commentActionPostElement","click","form","find","show","markFormSubmitted","trigger","notifyFormSubmittedByJavascript","data","serialize","assignmentid","attr","call","methodname","args","userid","jsonformdata","JSON","stringify","done","_handleFormSubmissionResponse","bind","fail","exception","formdata","response","length","get_string","then","add","catch","resetFormDirtyState","hide","_resetForm","e","Event","_refreshGradingPanel","_chooseAttempt","link","target","submissionsId","submissionsform","getElementById","formcopy","clone","formhtml","wrap","get_strings","key","component","strs","confirm","attemptnumber","_addPopoutButtons","region","render","parents","closest","addClass","parent","append","on","_togglePopout","preventDefault","container","hasClass","removeClass","submissiondata","contextid","window","M","util","js_pending","params","loadFragment","saveFormState","js_complete","_getNextUser","_handleSaveAndShowNext","getPanelElement","collapsePanel","expandPanel","docElement","COLLAPSE_GRADE_PANEL","COLLAPSE_REVIEW_PANEL","EXPAND_GRADE_PANEL"],"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 * Javascript controller for the \"Grading\" panel at the right of the page.\n *\n * @module mod_assign/grading_panel\n * @copyright 2016 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.1\n */\ndefine([\n 'jquery',\n 'core/yui',\n 'core/notification',\n 'core/templates',\n 'core/fragment',\n 'core/ajax',\n 'core/str',\n 'mod_assign/grading_form_change_checker',\n 'mod_assign/grading_events',\n 'core_form/events',\n 'core/toast',\n 'core_form/changechecker',\n], function(\n $,\n Y,\n notification,\n templates,\n fragment,\n ajax,\n str,\n checker,\n GradingEvents,\n FormEvents,\n Toast,\n FormChangeChecker\n) {\n\n /**\n * GradingPanel class.\n *\n * @class mod_assign/grading_panel\n * @param {String} selector The selector for the page region containing the user navigation.\n */\n var GradingPanel = function(selector) {\n this._regionSelector = selector;\n this._region = $(selector);\n this._userCache = [];\n\n this.registerEventListeners();\n };\n\n /** @property {String} Selector for the page region containing the user navigation. */\n GradingPanel.prototype._regionSelector = null;\n\n /** @property {Integer} Remember the last user id to prevent unnessecary reloads. */\n GradingPanel.prototype._lastUserId = 0;\n\n /** @property {Integer} Remember the last attempt number to prevent unnessecary reloads. */\n GradingPanel.prototype._lastAttemptNumber = -1;\n\n /** @property {JQuery} JQuery node for the page region containing the user navigation. */\n GradingPanel.prototype._region = null;\n\n /** @property {Integer} The id of the next user in the grading list */\n GradingPanel.prototype.nextUserId = null;\n\n /** @property {Boolean} Next user exists in the grading list */\n GradingPanel.prototype.nextUser = false;\n\n /**\n * Fade the dom node out, update it, and fade it back.\n *\n * @private\n * @method _niceReplaceNodeContents\n * @param {JQuery} node\n * @param {String} html\n * @param {String} js\n * @return {Deferred} promise resolved when the animations are complete.\n */\n GradingPanel.prototype._niceReplaceNodeContents = function(node, html, js) {\n var promise = $.Deferred();\n\n node.fadeOut(\"fast\", function() {\n templates.replaceNodeContents(node, html, js);\n node.fadeIn(\"fast\", function() {\n promise.resolve();\n });\n });\n\n return promise.promise();\n };\n\n /**\n * Make sure all form fields have the latest saved state.\n * @private\n * @method _saveFormState\n */\n GradingPanel.prototype._saveFormState = function() {\n // Copy data from notify students checkbox which was moved out of the form.\n var checked = $('[data-region=\"grading-actions-form\"] [name=\"sendstudentnotifications\"]').prop(\"checked\");\n $('.gradeform [name=\"sendstudentnotifications\"]').val(checked);\n };\n\n /**\n * Make form submit via ajax.\n *\n * @private\n * @param {Object} event\n * @param {Integer} nextUserId\n * @param {Boolean} nextUser optional. Load next user in the grading list.\n * @method _submitForm\n * @fires event:formSubmittedByJavascript\n */\n GradingPanel.prototype._submitForm = function(event, nextUserId, nextUser) {\n // If the form has data in comment-area, then we need to save that comment\n var commentAreaElement = document.querySelector('.comment-area');\n if (commentAreaElement) {\n var commentTextAreaElement = commentAreaElement.querySelector('.db > textarea');\n if (commentTextAreaElement.value !== '') {\n var commentActionPostElement = commentAreaElement.querySelector('.fd a[id^=\"comment-action-post-\"]');\n commentActionPostElement.click();\n }\n }\n\n // The form was submitted - send it via ajax instead.\n var form = $(this._region.find('form.gradeform'));\n\n $('[data-region=\"overlay\"]').show();\n\n // Mark the form as submitted in the change checker.\n FormChangeChecker.markFormSubmitted(form[0]);\n\n // We call this, so other modules can update the form with the latest state.\n form.trigger('save-form-state');\n\n // Tell all form fields we are about to submit the form.\n FormEvents.notifyFormSubmittedByJavascript(form[0]);\n\n // Now we get all the current values from the form.\n var data = form.serialize();\n var assignmentid = this._region.attr('data-assignmentid');\n\n // Now we can continue...\n ajax.call([{\n methodname: 'mod_assign_submit_grading_form',\n args: {assignmentid: assignmentid, userid: this._lastUserId, jsonformdata: JSON.stringify(data)},\n done: this._handleFormSubmissionResponse.bind(this, data, nextUserId, nextUser),\n fail: notification.exception\n }]);\n };\n\n /**\n * Handle form submission response.\n *\n * @private\n * @method _handleFormSubmissionResponse\n * @param {Array} formdata - submitted values\n * @param {Number} [nextUserId] The id of the user to load after the form is saved\n * @param {Boolean} [nextUser] - Whether to switch to next user in the grading list.\n * @param {Array} response List of errors.\n */\n GradingPanel.prototype._handleFormSubmissionResponse = function(formdata, nextUserId, nextUser, response) {\n if (typeof nextUserId === \"undefined\") {\n nextUserId = this._lastUserId;\n }\n if (response.length) {\n // There was an error saving the grade. Re-render the form using the submitted data so we can show\n // validation errors.\n $(document).trigger('reset', [this._lastUserId, formdata]);\n } else {\n str.get_string('gradechangessaveddetail', 'mod_assign')\n .then(function(str) {\n Toast.add(str);\n return str;\n })\n .catch(notification.exception);\n\n // Reset the form state.\n var form = $(this._region.find('form.gradeform'));\n FormChangeChecker.resetFormDirtyState(form[0]);\n\n if (nextUserId == this._lastUserId) {\n $(document).trigger('reset', nextUserId);\n } else if (nextUser) {\n $(document).trigger('done-saving-show-next', true);\n } else {\n $(document).trigger('user-changed', nextUserId);\n }\n }\n $('[data-region=\"overlay\"]').hide();\n };\n\n /**\n * Refresh form with default values.\n *\n * @private\n * @method _resetForm\n * @param {Event} e\n * @param {Integer} userid\n * @param {Array} formdata\n */\n GradingPanel.prototype._resetForm = function(e, userid, formdata) {\n // The form was cancelled - refresh with default values.\n var event = $.Event(\"custom\");\n if (typeof userid == \"undefined\") {\n userid = this._lastUserId;\n }\n this._lastUserId = 0;\n this._refreshGradingPanel(event, userid, formdata);\n };\n\n /**\n * Open a picker to choose an older attempt.\n *\n * @private\n * @param {Object} e\n * @method _chooseAttempt\n */\n GradingPanel.prototype._chooseAttempt = function(e) {\n // Show a dialog.\n\n // The form is in the element pointed to by data-submissions.\n var link = $(e.target);\n var submissionsId = link.data('submissions');\n var submissionsform = $(document.getElementById(submissionsId));\n var formcopy = submissionsform.clone();\n var formhtml = formcopy.wrap($('')).html();\n\n str.get_strings([\n {key: 'viewadifferentattempt', component: 'mod_assign'},\n {key: 'view', component: 'core'},\n {key: 'cancel', component: 'core'},\n ]).done(function(strs) {\n notification.confirm(strs[0], formhtml, strs[1], strs[2], function() {\n var attemptnumber = $(\"input:radio[name='select-attemptnumber']:checked\").val();\n\n this._refreshGradingPanel(null, this._lastUserId, '', attemptnumber);\n }.bind(this));\n }.bind(this)).fail(notification.exception);\n };\n\n /**\n * Add popout buttons\n *\n * @private\n * @method _addPopoutButtons\n * @param {JQuery} selector The region selector to add popout buttons to.\n */\n GradingPanel.prototype._addPopoutButtons = function(selector) {\n var region = $(selector);\n\n templates.render('mod_assign/popout_button', {}).done(function(html) {\n var parents = region.find('[data-fieldtype=\"filemanager\"],[data-fieldtype=\"editor\"],[data-fieldtype=\"grading\"]')\n .closest('.fitem');\n parents.addClass('has-popout').find('label').parent().append(html);\n\n region.on('click', '[data-region=\"popout-button\"]', this._togglePopout.bind(this));\n }.bind(this)).fail(notification.exception);\n };\n\n /**\n * Make a div \"popout\" or \"popback\".\n *\n * @private\n * @method _togglePopout\n * @param {Event} event\n */\n GradingPanel.prototype._togglePopout = function(event) {\n event.preventDefault();\n var container = $(event.target).closest('.fitem');\n if (container.hasClass('popout')) {\n $('.popout').removeClass('popout');\n } else {\n $('.popout').removeClass('popout');\n container.addClass('popout');\n container.addClass('moodle-has-zindex');\n }\n };\n\n /**\n * Get the user context - re-render the template in the page.\n *\n * @private\n * @method _refreshGradingPanel\n * @param {Event} event\n * @param {Number} userid\n * @param {String} submissiondata serialised submission data.\n * @param {Integer} attemptnumber\n */\n GradingPanel.prototype._refreshGradingPanel = function(event, userid, submissiondata, attemptnumber) {\n var contextid = this._region.attr('data-contextid');\n if (typeof submissiondata === 'undefined') {\n submissiondata = '';\n }\n if (typeof attemptnumber === 'undefined') {\n attemptnumber = -1;\n }\n // Skip reloading if it is the same user.\n if (this._lastUserId == userid && this._lastAttemptNumber == attemptnumber && submissiondata === '') {\n return;\n }\n this._lastUserId = userid;\n this._lastAttemptNumber = attemptnumber;\n $(document).trigger('start-loading-user');\n // Tell behat to back off too.\n window.M.util.js_pending('mod-assign-loading-user');\n // First insert the loading template.\n templates.render('mod_assign/loading', {}).done(function(html, js) {\n // Update the page.\n this._niceReplaceNodeContents(this._region, html, js).done(function() {\n if (userid > 0) {\n this._region.show();\n // Reload the grading form \"fragment\" for this user.\n var params = {userid: userid, attemptnumber: attemptnumber, jsonformdata: JSON.stringify(submissiondata)};\n fragment.loadFragment('mod_assign', 'gradingpanel', contextid, params).done(function(html, js) {\n this._niceReplaceNodeContents(this._region, html, js)\n .done(function() {\n checker.saveFormState('[data-region=\"grade-panel\"] .gradeform');\n $(document).on('editor-content-restored', function() {\n // If the editor has some content that has been restored\n // then save the form state again for comparison.\n checker.saveFormState('[data-region=\"grade-panel\"] .gradeform');\n });\n $('[data-region=\"attempt-chooser\"]').on('click', this._chooseAttempt.bind(this));\n this._addPopoutButtons('[data-region=\"grade-panel\"] .gradeform');\n $(document).trigger('finish-loading-user');\n // Tell behat we are friends again.\n window.M.util.js_complete('mod-assign-loading-user');\n }.bind(this))\n .fail(notification.exception);\n }.bind(this)).fail(notification.exception);\n $('[data-region=\"review-panel\"]').show();\n } else {\n this._region.hide();\n $('[data-region=\"review-panel\"]').hide();\n $(document).trigger('finish-loading-user');\n // Tell behat we are friends again.\n window.M.util.js_complete('mod-assign-loading-user');\n }\n }.bind(this));\n }.bind(this)).fail(notification.exception);\n };\n\n /**\n * Get next user data and store it in global variables\n *\n * @private\n * @method _getNextUser\n * @param {Event} event\n * @param {Object} data Next user's data\n */\n GradingPanel.prototype._getNextUser = function(event, data) {\n this.nextUserId = data.nextUserId;\n this.nextUser = data.nextUser;\n };\n\n /**\n * Handle the save-and-show-next event\n *\n * @private\n * @method _handleSaveAndShowNext\n */\n GradingPanel.prototype._handleSaveAndShowNext = function() {\n this._submitForm(null, this.nextUserId, this.nextUser);\n };\n\n /**\n * Get the grade panel element.\n *\n * @method getPanelElement\n * @return {jQuery}\n */\n GradingPanel.prototype.getPanelElement = function() {\n return $('[data-region=\"grade-panel\"]');\n };\n\n /**\n * Hide the grade panel.\n *\n * @method collapsePanel\n */\n GradingPanel.prototype.collapsePanel = function() {\n this.getPanelElement().addClass('collapsed');\n };\n\n /**\n * Show the grade panel.\n *\n * @method expandPanel\n */\n GradingPanel.prototype.expandPanel = function() {\n this.getPanelElement().removeClass('collapsed');\n };\n\n /**\n * Register event listeners for the grade panel.\n *\n * @method registerEventListeners\n */\n GradingPanel.prototype.registerEventListeners = function() {\n var docElement = $(document);\n var region = $(this._region);\n // Add an event listener to prevent form submission when pressing enter key.\n region.on('submit', 'form', function(e) {\n e.preventDefault();\n });\n\n docElement.on('next-user', this._getNextUser.bind(this));\n docElement.on('user-changed', this._refreshGradingPanel.bind(this));\n docElement.on('save-changes', this._submitForm.bind(this));\n docElement.on('save-and-show-next', this._handleSaveAndShowNext.bind(this));\n docElement.on('reset', this._resetForm.bind(this));\n\n docElement.on('save-form-state', this._saveFormState.bind(this));\n\n docElement.on(GradingEvents.COLLAPSE_GRADE_PANEL, function() {\n this.collapsePanel();\n }.bind(this));\n\n // We should expand if the review panel is collapsed.\n docElement.on(GradingEvents.COLLAPSE_REVIEW_PANEL, function() {\n this.expandPanel();\n }.bind(this));\n\n docElement.on(GradingEvents.EXPAND_GRADE_PANEL, function() {\n this.expandPanel();\n }.bind(this));\n };\n\n return GradingPanel;\n});\n"],"file":"grading_panel.min.js"}
\ No newline at end of file
diff --git a/mod/assign/amd/build/override_form.min.js b/mod/assign/amd/build/override_form.min.js
index ccd2cf21838..9c07e032b47 100644
--- a/mod/assign/amd/build/override_form.min.js
+++ b/mod/assign/amd/build/override_form.min.js
@@ -1,2 +1,2 @@
-define ("mod_assign/override_form",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a,c){var d=document.getElementById(a),e=d.querySelector("[name=\"".concat(c,"\"]"));(0,b.default)(e).on("change",function(){var a=document.createElement("input");a.setAttribute("type","hidden");a.setAttribute("name","userchange");a.setAttribute("value",!0);d.appendChild(a);if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.reset_form_dirty_state()}d.submit()})};a.init=c});
+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 ("mod_assign/override_form",["exports","jquery","core_form/changechecker"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);c=e(c);function d(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;d=function(){return a};return a}function e(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=d();if(b&&b.has(a)){return b.get(a)}var c={},e=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in a){if(Object.prototype.hasOwnProperty.call(a,f)){var g=e?Object.getOwnPropertyDescriptor(a,f):null;if(g&&(g.get||g.set)){Object.defineProperty(c,f,g)}else{c[f]=a[f]}}}c.default=a;if(b){b.set(a,c)}return c}var f=function(a,d){var e=document.getElementById(a),f=e.querySelector("[name=\"".concat(d,"\"]"));(0,b.default)(f).on("change",function(){var a=document.createElement("input");a.setAttribute("type","hidden");a.setAttribute("name","userchange");a.setAttribute("value",!0);e.appendChild(a);c.markFormSubmitted(a);e.submit()})};a.init=f});
//# sourceMappingURL=override_form.min.js.map
diff --git a/mod/assign/amd/build/override_form.min.js.map b/mod/assign/amd/build/override_form.min.js.map
index e979bf53bf1..98fe67039a2 100644
--- a/mod/assign/amd/build/override_form.min.js.map
+++ b/mod/assign/amd/build/override_form.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/override_form.js"],"names":["init","formId","selectElementName","form","document","getElementById","selectElement","querySelector","on","inputElement","createElement","setAttribute","appendChild","M","core_formchangechecker","reset_form_dirty_state","submit"],"mappings":"kJAsBA,uDAEO,GAAMA,CAAAA,CAAI,CAAG,SAACC,CAAD,CAASC,CAAT,CAA+B,IACzCC,CAAAA,CAAI,CAAGC,QAAQ,CAACC,cAAT,CAAwBJ,CAAxB,CADkC,CAEzCK,CAAa,CAAGH,CAAI,CAACI,aAAL,mBAA6BL,CAA7B,QAFyB,CAI/C,cAAEI,CAAF,EAAiBE,EAAjB,CAAoB,QAApB,CAA8B,UAAM,CAChC,GAAMC,CAAAA,CAAY,CAAGL,QAAQ,CAACM,aAAT,CAAuB,OAAvB,CAArB,CACAD,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,QAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,YAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,OAA1B,KAEAR,CAAI,CAACS,WAAL,CAAiBH,CAAjB,EAEA,GAAwC,WAApC,QAAOI,CAAAA,CAAC,CAACC,sBAAb,CAAqD,CACjDD,CAAC,CAACC,sBAAF,CAAyBC,sBAAzB,EACH,CAEDZ,CAAI,CAACa,MAAL,EACH,CAbD,CAcH,CAlBM,C","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 * A javascript module to enhance the override form.\n *\n * @copyright 2019 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n\nexport const init = (formId, selectElementName) => {\n const form = document.getElementById(formId);\n const selectElement = form.querySelector(`[name=\"${selectElementName}\"]`);\n\n $(selectElement).on('change', () => {\n const inputElement = document.createElement('input');\n inputElement.setAttribute('type', 'hidden');\n inputElement.setAttribute('name', 'userchange');\n inputElement.setAttribute('value', true);\n\n form.appendChild(inputElement);\n\n if (typeof M.core_formchangechecker !== 'undefined') {\n M.core_formchangechecker.reset_form_dirty_state();\n }\n\n form.submit();\n });\n};"],"file":"override_form.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/override_form.js"],"names":["init","formId","selectElementName","form","document","getElementById","selectElement","querySelector","on","inputElement","createElement","setAttribute","appendChild","FormChangeChecker","markFormSubmitted","submit"],"mappings":"idAsBA,uDACA,O,siBAEO,GAAMA,CAAAA,CAAI,CAAG,SAACC,CAAD,CAASC,CAAT,CAA+B,IACzCC,CAAAA,CAAI,CAAGC,QAAQ,CAACC,cAAT,CAAwBJ,CAAxB,CADkC,CAEzCK,CAAa,CAAGH,CAAI,CAACI,aAAL,mBAA6BL,CAA7B,QAFyB,CAI/C,cAAEI,CAAF,EAAiBE,EAAjB,CAAoB,QAApB,CAA8B,UAAM,CAChC,GAAMC,CAAAA,CAAY,CAAGL,QAAQ,CAACM,aAAT,CAAuB,OAAvB,CAArB,CACAD,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,QAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,YAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,OAA1B,KAEAR,CAAI,CAACS,WAAL,CAAiBH,CAAjB,EAEAI,CAAiB,CAACC,iBAAlB,CAAoCL,CAApC,EAEAN,CAAI,CAACY,MAAL,EACH,CAXD,CAYH,CAhBM,C","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 * A javascript module to enhance the override form.\n *\n * @copyright 2019 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as FormChangeChecker from 'core_form/changechecker';\n\nexport const init = (formId, selectElementName) => {\n const form = document.getElementById(formId);\n const selectElement = form.querySelector(`[name=\"${selectElementName}\"]`);\n\n $(selectElement).on('change', () => {\n const inputElement = document.createElement('input');\n inputElement.setAttribute('type', 'hidden');\n inputElement.setAttribute('name', 'userchange');\n inputElement.setAttribute('value', true);\n\n form.appendChild(inputElement);\n\n FormChangeChecker.markFormSubmitted(inputElement);\n\n form.submit();\n });\n};\n"],"file":"override_form.min.js"}
\ No newline at end of file
diff --git a/mod/assign/amd/src/grading_panel.js b/mod/assign/amd/src/grading_panel.js
index 17f0d356d24..d499071df3d 100644
--- a/mod/assign/amd/src/grading_panel.js
+++ b/mod/assign/amd/src/grading_panel.js
@@ -22,11 +22,32 @@
* @since 3.1
*/
define([
- 'jquery', 'core/yui', 'core/notification', 'core/templates', 'core/fragment',
- 'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker',
- 'mod_assign/grading_events', 'core_form/events', 'core/toast'
-],
-function($, Y, notification, templates, fragment, ajax, str, checker, GradingEvents, FormEvents, Toast) {
+ 'jquery',
+ 'core/yui',
+ 'core/notification',
+ 'core/templates',
+ 'core/fragment',
+ 'core/ajax',
+ 'core/str',
+ 'mod_assign/grading_form_change_checker',
+ 'mod_assign/grading_events',
+ 'core_form/events',
+ 'core/toast',
+ 'core_form/changechecker',
+], function(
+ $,
+ Y,
+ notification,
+ templates,
+ fragment,
+ ajax,
+ str,
+ checker,
+ GradingEvents,
+ FormEvents,
+ Toast,
+ FormChangeChecker
+) {
/**
* GradingPanel class.
@@ -120,6 +141,9 @@ function($, Y, notification, templates, fragment, ajax, str, checker, GradingEve
$('[data-region="overlay"]').show();
+ // Mark the form as submitted in the change checker.
+ FormChangeChecker.markFormSubmitted(form[0]);
+
// We call this, so other modules can update the form with the latest state.
form.trigger('save-form-state');
@@ -145,9 +169,9 @@ function($, Y, notification, templates, fragment, ajax, str, checker, GradingEve
* @private
* @method _handleFormSubmissionResponse
* @param {Array} formdata - submitted values
- * @param {Integer} nextUserId - optional. The id of the user to load after the form is saved.
+ * @param {Number} [nextUserId] The id of the user to load after the form is saved
+ * @param {Boolean} [nextUser] - Whether to switch to next user in the grading list.
* @param {Array} response List of errors.
- * @param {Boolean} nextUser - optional. If true, switch to next user in the grading list.
*/
GradingPanel.prototype._handleFormSubmissionResponse = function(formdata, nextUserId, nextUser, response) {
if (typeof nextUserId === "undefined") {
@@ -158,14 +182,17 @@ function($, Y, notification, templates, fragment, ajax, str, checker, GradingEve
// validation errors.
$(document).trigger('reset', [this._lastUserId, formdata]);
} else {
- str.get_strings([
- {key: 'gradechangessaveddetail', component: 'mod_assign'},
- ]).done(function(strs) {
- Toast.add(strs[0]);
- }).fail(notification.exception);
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ str.get_string('gradechangessaveddetail', 'mod_assign')
+ .then(function(str) {
+ Toast.add(str);
+ return str;
+ })
+ .catch(notification.exception);
+
+ // Reset the form state.
+ var form = $(this._region.find('form.gradeform'));
+ FormChangeChecker.resetFormDirtyState(form[0]);
+
if (nextUserId == this._lastUserId) {
$(document).trigger('reset', nextUserId);
} else if (nextUser) {
diff --git a/mod/assign/amd/src/override_form.js b/mod/assign/amd/src/override_form.js
index 62a92be06d2..4d10f7b5eb3 100644
--- a/mod/assign/amd/src/override_form.js
+++ b/mod/assign/amd/src/override_form.js
@@ -21,6 +21,7 @@
*/
import $ from 'jquery';
+import * as FormChangeChecker from 'core_form/changechecker';
export const init = (formId, selectElementName) => {
const form = document.getElementById(formId);
@@ -34,10 +35,8 @@ export const init = (formId, selectElementName) => {
form.appendChild(inputElement);
- if (typeof M.core_formchangechecker !== 'undefined') {
- M.core_formchangechecker.reset_form_dirty_state();
- }
+ FormChangeChecker.markFormSubmitted(inputElement);
form.submit();
});
-};
\ No newline at end of file
+};
diff --git a/mod/feedback/edit_form.php b/mod/feedback/edit_form.php
index 583bc9e4c13..6753bab831c 100644
--- a/mod/feedback/edit_form.php
+++ b/mod/feedback/edit_form.php
@@ -71,12 +71,17 @@ class feedback_edit_use_template_form extends moodleform {
$options[get_string('public', 'feedback')] = $publicoptions;
}
- $attributes = 'onChange="M.core_formchangechecker.set_form_submitted(); this.form.submit()"';
- $elementgroup[] = $mform->createElement('selectgroups',
- 'templateid',
- get_string('using_templates', 'feedback'),
- $options,
- $attributes);
+ $attributes = [
+ 'onChange="this.form.submit()"',
+ 'data-form-change-checker-override="1"',
+ ];
+ $elementgroup[] = $mform->createElement(
+ 'selectgroups',
+ 'templateid',
+ get_string('using_templates', 'feedback'),
+ $options,
+ implode(' ', $attributes)
+ );
$elementgroup[] = $mform->createElement('submit',
'use_template',
diff --git a/mod/forum/amd/build/discussion_nested_v2.min.js b/mod/forum/amd/build/discussion_nested_v2.min.js
index 645ee6ef849..774431c4c26 100644
--- a/mod/forum/amd/build/discussion_nested_v2.min.js
+++ b/mod/forum/amd/build/discussion_nested_v2.min.js
@@ -1,2 +1,2 @@
-define ("mod_forum/discussion_nested_v2",["exports","jquery","core/auto_rows","core/custom_interaction_events","core/notification","core/templates","mod_forum/discussion","mod_forum/inpage_reply","mod_forum/lock_toggle","mod_forum/favourite_toggle","mod_forum/pin_toggle","mod_forum/selectors","mod_forum/subscription_toggle"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=n(b);c=n(c);d=n(d);e=n(e);f=n(f);g=n(g);h=n(h);i=n(i);j=n(j);k=n(k);l=n(l);m=n(m);var t="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function n(a){return a&&a.__esModule?a:{default:a}}function o(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 p(a){for(var b=1,c;b .\n\n/**\n * Module for viewing a discussion in nested v2 view.\n *\n * @module mod_Forum/discussion_nested_v2\n * @copyright 2019 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport $ from 'jquery';\nimport AutoRows from 'core/auto_rows';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport Discussion from 'mod_forum/discussion';\nimport InPageReply from 'mod_forum/inpage_reply';\nimport LockToggle from 'mod_forum/lock_toggle';\nimport FavouriteToggle from 'mod_forum/favourite_toggle';\nimport Pin from 'mod_forum/pin_toggle';\nimport Selectors from 'mod_forum/selectors';\nimport Subscribe from 'mod_forum/subscription_toggle';\n\nconst ANIMATION_DURATION = 150;\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getPostContainer = (element) => {\n return element.closest(Selectors.post.post);\n};\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @param {Number} id Id of the post to find.\n * @return {Object} jQuery element\n */\nconst getPostContainerById = (element, id) => {\n return element.find(`${Selectors.post.post}[data-post-id=${id}]`);\n};\n\n/**\n * Get the parent post container elements from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getParentPostContainers = (element) => {\n return element.parents(Selectors.post.post);\n};\n\n/**\n * Get the post content container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getPostContentContainer = (postContainer) => {\n return postContainer.children().not(Selectors.post.repliesContainer).find(Selectors.post.forumCoreContent);\n};\n\n/**\n * Get the in page reply container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyContainer = (postContainer) => {\n return postContainer.children().filter(Selectors.post.inpageReplyContainer);\n};\n\n/**\n * Get the in page reply form element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyForm = (postContainer) => {\n return getInPageReplyContainer(postContainer).find(Selectors.post.inpageReplyContent);\n};\n\n/**\n * Get the in page reply create (reply) button element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyCreateButton = (postContainer) => {\n return getPostContentContainer(postContainer).find(Selectors.post.inpageReplyCreateButton);\n};\n\n/**\n * Get the replies visibility toggle container (show/hide replies button container) element\n * from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getRepliesVisibilityToggleContainer = (postContainer) => {\n return postContainer.children(Selectors.post.repliesVisibilityToggleContainer);\n};\n\n/**\n * Get the replies container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getRepliesContainer = (postContainer) => {\n return postContainer.children(Selectors.post.repliesContainer);\n};\n\n/**\n * Check if the post has any replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Bool}\n */\nconst hasReplies = (postContainer) => {\n return getRepliesContainer(postContainer).children().length > 0;\n};\n\n/**\n * Get the show replies button element from the replies visibility toggle container element.\n *\n * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container\n * @return {Object} jQuery element\n */\nconst getShowRepliesButton = (replyVisibilityToggleContainer) => {\n return replyVisibilityToggleContainer.find(Selectors.post.showReplies);\n};\n\n/**\n * Get the hide replies button element from the replies visibility toggle container element.\n *\n * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container\n * @return {Object} jQuery element\n */\nconst getHideRepliesButton = (replyVisibilityToggleContainer) => {\n return replyVisibilityToggleContainer.find(Selectors.post.hideReplies);\n};\n\n/**\n * Check if the replies are visible.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Bool}\n */\nconst repliesVisible = (postContainer) => {\n const repliesContainer = getRepliesContainer(postContainer);\n return repliesContainer.is(':visible');\n};\n\n/**\n * Show the post replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @param {Number|null} postIdToSee Id of the post to scroll into view (if any)\n */\nconst showReplies = (postContainer, postIdToSee = null) => {\n const repliesContainer = getRepliesContainer(postContainer);\n const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const showButton = getShowRepliesButton(replyVisibilityToggleContainer);\n const hideButton = getHideRepliesButton(replyVisibilityToggleContainer);\n\n showButton.addClass('hidden');\n hideButton.removeClass('hidden');\n\n repliesContainer.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n if (postIdToSee) {\n const postContainerToSee = getPostContainerById(repliesContainer, postIdToSee);\n if (postContainerToSee.length) {\n postContainerToSee[0].scrollIntoView();\n }\n }\n }\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n};\n\n/**\n * Hide the post replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\nconst hideReplies = (postContainer) => {\n const repliesContainer = getRepliesContainer(postContainer);\n const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const showButton = getShowRepliesButton(replyVisibilityToggleContainer);\n const hideButton = getHideRepliesButton(replyVisibilityToggleContainer);\n\n showButton.removeClass('hidden');\n hideButton.addClass('hidden');\n\n repliesContainer.slideUp({\n duration: ANIMATION_DURATION,\n queue: false\n }).fadeOut(ANIMATION_DURATION);\n};\n\n/** Variable to hold the showInPageReplyForm function after it's built. */\nlet showInPageReplyForm = null;\n\n/**\n * Build the showInPageReplyForm function with the given additional template context.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template.\n * @return {Function}\n */\nconst buildShowInPageReplyFormFunction = (additionalTemplateContext) => {\n /**\n * Show the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\n return async(postContainer) => {\n\n const inPageReplyContainer = getInPageReplyContainer(postContainer);\n const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer);\n\n if (!hasInPageReplyForm(inPageReplyContainer)) {\n try {\n const html = await renderInPageReplyTemplate(additionalTemplateContext, inPageReplyCreateButton, postContainer);\n Templates.appendNodeContents(inPageReplyContainer, html, '');\n } catch (e) {\n Notification.exception(e);\n }\n\n // Load formchangechecker module.\n import('core/yui')\n .then(Y => {\n return new Promise(resolve => {\n Y.use('moodle-core-formchangechecker', Y => {\n resolve(Y);\n });\n });\n })\n .then(Y => {\n M.core_formchangechecker.init({formid: Y.one(postContainer[0].querySelector('form')).generateID()});\n return Y;\n })\n .catch();\n }\n\n inPageReplyCreateButton.fadeOut(ANIMATION_DURATION, () => {\n const inPageReplyForm = getInPageReplyForm(postContainer);\n inPageReplyForm.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n inPageReplyForm.find('textarea').focus();\n }\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n\n if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) {\n repliesVisibilityToggleContainer.fadeIn(ANIMATION_DURATION);\n hideReplies(postContainer);\n }\n });\n };\n};\n\n/**\n * Hide the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @param {Number|null} postIdToSee Id of the post to scroll into view (if any)\n */\nconst hideInPageReplyForm = (postContainer, postIdToSee = null) => {\n const inPageReplyForm = getInPageReplyForm(postContainer);\n const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer);\n const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n\n if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) {\n repliesVisibilityToggleContainer.fadeOut(ANIMATION_DURATION);\n if (!repliesVisible(postContainer)) {\n showReplies(postContainer, postIdToSee);\n }\n }\n\n inPageReplyForm.slideUp({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n inPageReplyCreateButton.fadeIn(ANIMATION_DURATION);\n }\n }).fadeOut(200);\n};\n\n/**\n * Check if the in page reply container contains the in page reply form.\n *\n * @param {Object} inPageReplyContainer jQuery element for the in page reply container\n * @return {Bool}\n */\nconst hasInPageReplyForm = (inPageReplyContainer) => {\n return inPageReplyContainer.find(Selectors.post.inpageReplyContent).length > 0;\n};\n\n/**\n * Render the template to generate the in page reply form HTML.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template\n * @param {Object} button jQuery element for the reply button that was clicked\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery promise\n */\nconst renderInPageReplyTemplate = (additionalTemplateContext, button, postContainer) => {\n const postContentContainer = getPostContentContainer(postContainer);\n const currentSubject = postContentContainer.find(Selectors.post.forumSubject).text();\n const currentAuthorName = postContentContainer.find(Selectors.post.authorName).text();\n const context = {\n postid: postContainer.data('post-id'),\n \"reply_url\": button.attr('data-href'),\n sesskey: M.cfg.sesskey,\n parentsubject: currentSubject,\n parentauthorname: currentAuthorName,\n canreplyprivately: button.data('can-reply-privately'),\n postformat: InPageReply.CONTENT_FORMATS.MOODLE,\n ...additionalTemplateContext\n };\n\n return Templates.render('mod_forum/inpage_reply_v2', context);\n};\n\n/**\n * Increment the total reply count in the show/hide replies buttons for the post.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\nconst incrementTotalReplyCount = (postContainer) => {\n getRepliesVisibilityToggleContainer(postContainer).find(Selectors.post.replyCount).each((index, element) => {\n const currentCount = parseInt(element.innerText, 10);\n element.innerText = currentCount + 1;\n });\n};\n\n/**\n * Create all of the event listeners for the discussion.\n *\n * @param {Object} root jQuery element for the discussion container\n */\nconst registerEventListeners = (root) => {\n CustomEvents.define(root, [CustomEvents.events.activate]);\n // Auto expanding text area for in page reply.\n AutoRows.init(root);\n\n // Reply button is clicked.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCreateButton, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.currentTarget));\n showInPageReplyForm(postContainer);\n });\n\n // Cancel in page reply button.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCancelButton, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.currentTarget));\n hideInPageReplyForm(postContainer);\n });\n\n // Show replies button clicked.\n root.on(CustomEvents.events.activate, Selectors.post.showReplies, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.target));\n showReplies(postContainer);\n });\n\n // Hide replies button clicked.\n root.on(CustomEvents.events.activate, Selectors.post.hideReplies, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.target));\n hideReplies(postContainer);\n });\n\n // Post created with in page reply.\n root.on(InPageReply.EVENTS.POST_CREATED, Selectors.post.inpageSubmitBtn, (e, newPostId) => {\n const currentTarget = $(e.currentTarget);\n const postContainer = getPostContainer(currentTarget);\n const postContainers = getParentPostContainers(currentTarget);\n hideInPageReplyForm(postContainer, newPostId);\n\n postContainers.each((index, container) => {\n incrementTotalReplyCount($(container));\n });\n });\n};\n\n/**\n * Initialise the javascript for the discussion in nested v2 display mode.\n *\n * @param {Object} root jQuery element for the discussion container\n * @param {Object} context Additional render context for the in page reply template\n */\nexport const init = (root, context) => {\n // Build the showInPageReplyForm function with the additional render context.\n showInPageReplyForm = buildShowInPageReplyFormFunction(context);\n // Add discussion event listeners.\n registerEventListeners(root);\n // Initialise default discussion javascript (keyboard nav etc).\n Discussion.init(root);\n // Add in page reply javascript.\n InPageReply.init(root);\n\n // Initialise the settings menu javascript.\n const discussionToolsContainer = root.find(Selectors.discussion.tools);\n LockToggle.init(discussionToolsContainer, false);\n FavouriteToggle.init(discussionToolsContainer, false, (toggleElement, response) => {\n const newTargetState = response.userstate.favourited ? 0 : 1;\n return toggleElement.data('targetstate', newTargetState);\n });\n Pin.init(discussionToolsContainer, false, (toggleElement, response) => {\n const newTargetState = response.pinned ? 0 : 1;\n return toggleElement.data('targetstate', newTargetState);\n });\n Subscribe.init(discussionToolsContainer, false, (toggleElement, response) => {\n const newTargetState = response.userstate.subscribed ? 0 : 1;\n toggleElement.data('targetstate', newTargetState);\n });\n};\n"],"file":"discussion_nested_v2.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/discussion_nested_v2.js"],"names":["getPostContainer","element","closest","Selectors","post","getPostContainerById","id","find","getParentPostContainers","parents","getPostContentContainer","postContainer","children","not","repliesContainer","forumCoreContent","getInPageReplyContainer","filter","inpageReplyContainer","getInPageReplyForm","inpageReplyContent","getInPageReplyCreateButton","inpageReplyCreateButton","getRepliesVisibilityToggleContainer","repliesVisibilityToggleContainer","getRepliesContainer","hasReplies","length","getShowRepliesButton","replyVisibilityToggleContainer","showReplies","getHideRepliesButton","hideReplies","repliesVisible","is","postIdToSee","showButton","hideButton","addClass","removeClass","slideDown","duration","queue","complete","postContainerToSee","scrollIntoView","css","fadeIn","slideUp","fadeOut","showInPageReplyForm","buildShowInPageReplyFormFunction","additionalTemplateContext","inPageReplyContainer","inPageReplyCreateButton","hasInPageReplyForm","renderInPageReplyTemplate","html","Templates","appendNodeContents","Notification","exception","FormChangeChecker","watchForm","querySelector","inPageReplyForm","focus","hideInPageReplyForm","button","postContentContainer","currentSubject","forumSubject","text","currentAuthorName","authorName","context","postid","data","attr","sesskey","M","cfg","parentsubject","parentauthorname","canreplyprivately","postformat","InPageReply","CONTENT_FORMATS","MOODLE","render","incrementTotalReplyCount","replyCount","each","index","currentCount","parseInt","innerText","registerEventListeners","root","CustomEvents","define","events","activate","AutoRows","init","on","e","originalEvent","preventDefault","currentTarget","inpageReplyCancelButton","target","EVENTS","POST_CREATED","inpageSubmitBtn","newPostId","postContainers","container","Discussion","discussionToolsContainer","discussion","tools","LockToggle","FavouriteToggle","toggleElement","response","newTargetState","userstate","favourited","Pin","pinned","Subscribe","subscribed"],"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 for viewing a discussion in nested v2 view.\n *\n * @module mod_Forum/discussion_nested_v2\n * @copyright 2019 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport $ from 'jquery';\nimport AutoRows from 'core/auto_rows';\nimport CustomEvents from 'core/custom_interaction_events';\nimport * as FormChangeChecker from 'core_form/changechecker';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport Discussion from 'mod_forum/discussion';\nimport InPageReply from 'mod_forum/inpage_reply';\nimport LockToggle from 'mod_forum/lock_toggle';\nimport FavouriteToggle from 'mod_forum/favourite_toggle';\nimport Pin from 'mod_forum/pin_toggle';\nimport Selectors from 'mod_forum/selectors';\nimport Subscribe from 'mod_forum/subscription_toggle';\n\nconst ANIMATION_DURATION = 150;\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getPostContainer = (element) => {\n return element.closest(Selectors.post.post);\n};\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @param {Number} id Id of the post to find.\n * @return {Object} jQuery element\n */\nconst getPostContainerById = (element, id) => {\n return element.find(`${Selectors.post.post}[data-post-id=${id}]`);\n};\n\n/**\n * Get the parent post container elements from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getParentPostContainers = (element) => {\n return element.parents(Selectors.post.post);\n};\n\n/**\n * Get the post content container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getPostContentContainer = (postContainer) => {\n return postContainer.children().not(Selectors.post.repliesContainer).find(Selectors.post.forumCoreContent);\n};\n\n/**\n * Get the in page reply container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyContainer = (postContainer) => {\n return postContainer.children().filter(Selectors.post.inpageReplyContainer);\n};\n\n/**\n * Get the in page reply form element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyForm = (postContainer) => {\n return getInPageReplyContainer(postContainer).find(Selectors.post.inpageReplyContent);\n};\n\n/**\n * Get the in page reply create (reply) button element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyCreateButton = (postContainer) => {\n return getPostContentContainer(postContainer).find(Selectors.post.inpageReplyCreateButton);\n};\n\n/**\n * Get the replies visibility toggle container (show/hide replies button container) element\n * from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getRepliesVisibilityToggleContainer = (postContainer) => {\n return postContainer.children(Selectors.post.repliesVisibilityToggleContainer);\n};\n\n/**\n * Get the replies container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getRepliesContainer = (postContainer) => {\n return postContainer.children(Selectors.post.repliesContainer);\n};\n\n/**\n * Check if the post has any replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Bool}\n */\nconst hasReplies = (postContainer) => {\n return getRepliesContainer(postContainer).children().length > 0;\n};\n\n/**\n * Get the show replies button element from the replies visibility toggle container element.\n *\n * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container\n * @return {Object} jQuery element\n */\nconst getShowRepliesButton = (replyVisibilityToggleContainer) => {\n return replyVisibilityToggleContainer.find(Selectors.post.showReplies);\n};\n\n/**\n * Get the hide replies button element from the replies visibility toggle container element.\n *\n * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container\n * @return {Object} jQuery element\n */\nconst getHideRepliesButton = (replyVisibilityToggleContainer) => {\n return replyVisibilityToggleContainer.find(Selectors.post.hideReplies);\n};\n\n/**\n * Check if the replies are visible.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Bool}\n */\nconst repliesVisible = (postContainer) => {\n const repliesContainer = getRepliesContainer(postContainer);\n return repliesContainer.is(':visible');\n};\n\n/**\n * Show the post replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @param {Number|null} postIdToSee Id of the post to scroll into view (if any)\n */\nconst showReplies = (postContainer, postIdToSee = null) => {\n const repliesContainer = getRepliesContainer(postContainer);\n const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const showButton = getShowRepliesButton(replyVisibilityToggleContainer);\n const hideButton = getHideRepliesButton(replyVisibilityToggleContainer);\n\n showButton.addClass('hidden');\n hideButton.removeClass('hidden');\n\n repliesContainer.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n if (postIdToSee) {\n const postContainerToSee = getPostContainerById(repliesContainer, postIdToSee);\n if (postContainerToSee.length) {\n postContainerToSee[0].scrollIntoView();\n }\n }\n }\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n};\n\n/**\n * Hide the post replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\nconst hideReplies = (postContainer) => {\n const repliesContainer = getRepliesContainer(postContainer);\n const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const showButton = getShowRepliesButton(replyVisibilityToggleContainer);\n const hideButton = getHideRepliesButton(replyVisibilityToggleContainer);\n\n showButton.removeClass('hidden');\n hideButton.addClass('hidden');\n\n repliesContainer.slideUp({\n duration: ANIMATION_DURATION,\n queue: false\n }).fadeOut(ANIMATION_DURATION);\n};\n\n/** Variable to hold the showInPageReplyForm function after it's built. */\nlet showInPageReplyForm = null;\n\n/**\n * Build the showInPageReplyForm function with the given additional template context.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template.\n * @return {Function}\n */\nconst buildShowInPageReplyFormFunction = (additionalTemplateContext) => {\n /**\n * Show the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\n return async(postContainer) => {\n\n const inPageReplyContainer = getInPageReplyContainer(postContainer);\n const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer);\n\n if (!hasInPageReplyForm(inPageReplyContainer)) {\n try {\n const html = await renderInPageReplyTemplate(additionalTemplateContext, inPageReplyCreateButton, postContainer);\n Templates.appendNodeContents(inPageReplyContainer, html, '');\n } catch (e) {\n Notification.exception(e);\n }\n\n FormChangeChecker.watchForm(postContainer[0].querySelector('form'));\n }\n\n inPageReplyCreateButton.fadeOut(ANIMATION_DURATION, () => {\n const inPageReplyForm = getInPageReplyForm(postContainer);\n inPageReplyForm.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n inPageReplyForm.find('textarea').focus();\n }\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n\n if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) {\n repliesVisibilityToggleContainer.fadeIn(ANIMATION_DURATION);\n hideReplies(postContainer);\n }\n });\n };\n};\n\n/**\n * Hide the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @param {Number|null} postIdToSee Id of the post to scroll into view (if any)\n */\nconst hideInPageReplyForm = (postContainer, postIdToSee = null) => {\n const inPageReplyForm = getInPageReplyForm(postContainer);\n const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer);\n const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n\n if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) {\n repliesVisibilityToggleContainer.fadeOut(ANIMATION_DURATION);\n if (!repliesVisible(postContainer)) {\n showReplies(postContainer, postIdToSee);\n }\n }\n\n inPageReplyForm.slideUp({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n inPageReplyCreateButton.fadeIn(ANIMATION_DURATION);\n }\n }).fadeOut(200);\n};\n\n/**\n * Check if the in page reply container contains the in page reply form.\n *\n * @param {Object} inPageReplyContainer jQuery element for the in page reply container\n * @return {Bool}\n */\nconst hasInPageReplyForm = (inPageReplyContainer) => {\n return inPageReplyContainer.find(Selectors.post.inpageReplyContent).length > 0;\n};\n\n/**\n * Render the template to generate the in page reply form HTML.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template\n * @param {Object} button jQuery element for the reply button that was clicked\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery promise\n */\nconst renderInPageReplyTemplate = (additionalTemplateContext, button, postContainer) => {\n const postContentContainer = getPostContentContainer(postContainer);\n const currentSubject = postContentContainer.find(Selectors.post.forumSubject).text();\n const currentAuthorName = postContentContainer.find(Selectors.post.authorName).text();\n const context = {\n postid: postContainer.data('post-id'),\n \"reply_url\": button.attr('data-href'),\n sesskey: M.cfg.sesskey,\n parentsubject: currentSubject,\n parentauthorname: currentAuthorName,\n canreplyprivately: button.data('can-reply-privately'),\n postformat: InPageReply.CONTENT_FORMATS.MOODLE,\n ...additionalTemplateContext\n };\n\n return Templates.render('mod_forum/inpage_reply_v2', context);\n};\n\n/**\n * Increment the total reply count in the show/hide replies buttons for the post.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\nconst incrementTotalReplyCount = (postContainer) => {\n getRepliesVisibilityToggleContainer(postContainer).find(Selectors.post.replyCount).each((index, element) => {\n const currentCount = parseInt(element.innerText, 10);\n element.innerText = currentCount + 1;\n });\n};\n\n/**\n * Create all of the event listeners for the discussion.\n *\n * @param {Object} root jQuery element for the discussion container\n */\nconst registerEventListeners = (root) => {\n CustomEvents.define(root, [CustomEvents.events.activate]);\n // Auto expanding text area for in page reply.\n AutoRows.init(root);\n\n // Reply button is clicked.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCreateButton, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.currentTarget));\n showInPageReplyForm(postContainer);\n });\n\n // Cancel in page reply button.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCancelButton, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.currentTarget));\n hideInPageReplyForm(postContainer);\n });\n\n // Show replies button clicked.\n root.on(CustomEvents.events.activate, Selectors.post.showReplies, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.target));\n showReplies(postContainer);\n });\n\n // Hide replies button clicked.\n root.on(CustomEvents.events.activate, Selectors.post.hideReplies, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.target));\n hideReplies(postContainer);\n });\n\n // Post created with in page reply.\n root.on(InPageReply.EVENTS.POST_CREATED, Selectors.post.inpageSubmitBtn, (e, newPostId) => {\n const currentTarget = $(e.currentTarget);\n const postContainer = getPostContainer(currentTarget);\n const postContainers = getParentPostContainers(currentTarget);\n hideInPageReplyForm(postContainer, newPostId);\n\n postContainers.each((index, container) => {\n incrementTotalReplyCount($(container));\n });\n });\n};\n\n/**\n * Initialise the javascript for the discussion in nested v2 display mode.\n *\n * @param {Object} root jQuery element for the discussion container\n * @param {Object} context Additional render context for the in page reply template\n */\nexport const init = (root, context) => {\n // Build the showInPageReplyForm function with the additional render context.\n showInPageReplyForm = buildShowInPageReplyFormFunction(context);\n // Add discussion event listeners.\n registerEventListeners(root);\n // Initialise default discussion javascript (keyboard nav etc).\n Discussion.init(root);\n // Add in page reply javascript.\n InPageReply.init(root);\n\n // Initialise the settings menu javascript.\n const discussionToolsContainer = root.find(Selectors.discussion.tools);\n LockToggle.init(discussionToolsContainer, false);\n FavouriteToggle.init(discussionToolsContainer, false, (toggleElement, response) => {\n const newTargetState = response.userstate.favourited ? 0 : 1;\n return toggleElement.data('targetstate', newTargetState);\n });\n Pin.init(discussionToolsContainer, false, (toggleElement, response) => {\n const newTargetState = response.pinned ? 0 : 1;\n return toggleElement.data('targetstate', newTargetState);\n });\n Subscribe.init(discussionToolsContainer, false, (toggleElement, response) => {\n const newTargetState = response.userstate.subscribed ? 0 : 1;\n toggleElement.data('targetstate', newTargetState);\n });\n};\n"],"file":"discussion_nested_v2.min.js"}
\ No newline at end of file
diff --git a/mod/forum/amd/build/inpage_reply.min.js b/mod/forum/amd/build/inpage_reply.min.js
index 997e1c3957f..9b2a069d76c 100644
--- a/mod/forum/amd/build/inpage_reply.min.js
+++ b/mod/forum/amd/build/inpage_reply.min.js
@@ -1,2 +1,2 @@
-define ("mod_forum/inpage_reply",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,f){var g={NESTED_V2:4,THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},h={POST_CREATED:"mod_forum-post-created"},i={MOODLE:0},j=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer),d=a.outerWidth();a.css("width",d);b.addClass("hidden");c.removeClass("hidden")},k=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer);a.css("width","");b.removeClass("hidden");c.addClass("hidden")},l=function(l){l.on("click",f.post.inpageSubmitBtn,function(m){m.preventDefault();var e=a(m.currentTarget),n=e.parent().find(f.post.inpageReplyButton),o=e.parents(f.post.inpageReplyForm).get(0),p=o.elements.post.value.trim(),q=i.MOODLE,r=o.elements.reply.value,s=o.elements.subject.value,t=e.closest(f.post.post),u=o.elements.privatereply!=void 0?o.elements.privatereply.checked:!1,v=l.find(f.post.modeSelect),w=v.length?parseInt(v.get(0).value):null,x;if(p.length){j(e);n.prop("disabled",!0);d.addDiscussionPost(r,s,p,q,u,!0).then(function(a){var b=a.messages.reduce(function(a,b){if("success"==b.type){a+=""+b.message+"
"}return a},"");c.addNotification({message:b,type:"success"});return a}).then(function(a){o.reset();var c=a.post;x=c.id;switch(w){case g.NESTED_V2:var d=c.capabilities,e=t.children().not(f.post.repliesContainer).find(f.post.authorName).text();c.parentauthorname=e;c.showactionmenu=d.view||d.controlreadstatus||d.edit||d.split||d.delete||d.export||c.urls.viewparent;return b.render("mod_forum/forum_discussion_nested_v2_post_reply",c);case g.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case g.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c);}}).then(function(a,c){var d=t.find(f.post.repliesContainer).first();if(w==g.FLAT_NEWEST_FIRST){return b.prependNodeContents(d,a,c)}else{return b.appendNodeContents(d,a,c)}}).then(function(){e.trigger(h.POST_CREATED,x);k(e);n.prop("disabled",!1);if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.reset_form_dirty_state()}return t.find(f.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+x}).catch(function(a){k(e);n.prop("disabled",!1);return c.exception(a)})}})};return{init:function init(a){l(a)},CONTENT_FORMATS:i,EVENTS:h}});
+define ("mod_forum/inpage_reply",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors","core_form/changechecker"],function(a,b,c,d,f,g){var h={NESTED_V2:4,THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},i={POST_CREATED:"mod_forum-post-created"},j={MOODLE:0},k=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer),d=a.outerWidth();a.css("width",d);b.addClass("hidden");c.removeClass("hidden")},l=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer);a.css("width","");b.removeClass("hidden");c.addClass("hidden")},m=function(m){m.on("click",f.post.inpageSubmitBtn,function(n){n.preventDefault();var e=a(n.currentTarget),o=e.parent().find(f.post.inpageReplyButton),p=e.parents(f.post.inpageReplyForm).get(0),q=p.elements.post.value.trim(),r=j.MOODLE,s=p.elements.reply.value,t=p.elements.subject.value,u=e.closest(f.post.post),v=p.elements.privatereply!=void 0?p.elements.privatereply.checked:!1,w=m.find(f.post.modeSelect),x=w.length?parseInt(w.get(0).value):null,y;if(q.length){k(e);o.prop("disabled",!0);d.addDiscussionPost(s,t,q,r,v,!0).then(function(a){var b=a.messages.reduce(function(a,b){if("success"==b.type){a+=""+b.message+"
"}return a},"");c.addNotification({message:b,type:"success"});return a}).then(function(a){p.reset();var c=a.post;y=c.id;switch(x){case h.NESTED_V2:var d=c.capabilities,e=u.children().not(f.post.repliesContainer).find(f.post.authorName).text();c.parentauthorname=e;c.showactionmenu=d.view||d.controlreadstatus||d.edit||d.split||d.delete||d.export||c.urls.viewparent;return b.render("mod_forum/forum_discussion_nested_v2_post_reply",c);case h.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case h.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c);}}).then(function(a,c){var d=u.find(f.post.repliesContainer).first();if(x==h.FLAT_NEWEST_FIRST){return b.prependNodeContents(d,a,c)}else{return b.appendNodeContents(d,a,c)}}).then(function(){e.trigger(i.POST_CREATED,y);l(e);o.prop("disabled",!1);g.resetFormDirtyState(e[0]);return u.find(f.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+y}).catch(function(a){l(e);o.prop("disabled",!1);return c.exception(a)})}})};return{init:function init(a){m(a)},CONTENT_FORMATS:j,EVENTS:i}});
//# sourceMappingURL=inpage_reply.min.js.map
diff --git a/mod/forum/amd/build/inpage_reply.min.js.map b/mod/forum/amd/build/inpage_reply.min.js.map
index 2637ec754f7..50191c732ea 100644
--- a/mod/forum/amd/build/inpage_reply.min.js.map
+++ b/mod/forum/amd/build/inpage_reply.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/inpage_reply.js"],"names":["define","$","Templates","Notification","Repository","Selectors","DISPLAYCONSTANTS","NESTED_V2","THREADED","NESTED","FLAT_OLDEST_FIRST","FLAT_NEWEST_FIRST","EVENTS","POST_CREATED","CONTENT_FORMATS","MOODLE","showSubmitButtonLoadingIcon","button","textContainer","find","post","inpageSubmitBtnText","loadingIconContainer","width","outerWidth","css","addClass","removeClass","hideSubmitButtonLoadingIcon","registerEventListeners","root","on","inpageSubmitBtn","e","preventDefault","submitButton","currentTarget","allButtons","parent","inpageReplyButton","form","parents","inpageReplyForm","get","message","elements","value","trim","messageformat","postid","reply","subject","currentRoot","closest","isprivatereply","privatereply","checked","modeSelector","modeSelect","mode","length","parseInt","newid","prop","addDiscussionPost","then","context","messages","reduce","carry","type","addNotification","reset","id","capabilities","currentAuthorName","children","not","repliesContainer","authorName","text","parentauthorname","showactionmenu","view","controlreadstatus","edit","split","delete","export","urls","viewparent","render","html","js","repliesnode","first","prependNodeContents","appendNodeContents","trigger","M","core_formchangechecker","reset_form_dirty_state","inpageReplyContent","hide","location","href","catch","error","exception","init"],"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 * This module handles the in page replying to forum posts.\n *\n * @module mod_forum/inpage_reply\n * @copyright 2019 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'mod_forum/repository',\n 'mod_forum/selectors',\n ], function(\n $,\n Templates,\n Notification,\n Repository,\n Selectors\n ) {\n\n var DISPLAYCONSTANTS = {\n NESTED_V2: 4,\n THREADED: 2,\n NESTED: 3,\n FLAT_OLDEST_FIRST: 1,\n FLAT_NEWEST_FIRST: -1\n };\n\n var EVENTS = {\n POST_CREATED: 'mod_forum-post-created'\n };\n\n /**\n * Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php.\n * @type {Object}\n */\n var CONTENT_FORMATS = {\n MOODLE: 0\n };\n /**\n * Show the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var showSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n var width = button.outerWidth();\n // Fix the width so that the button size doesn't change when we show the loading icon.\n button.css('width', width);\n textContainer.addClass('hidden');\n loadingIconContainer.removeClass('hidden');\n };\n\n /**\n * Hide the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var hideSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n // Reset the width back to it's default.\n button.css('width', '');\n textContainer.removeClass('hidden');\n loadingIconContainer.addClass('hidden');\n };\n\n /**\n * Register the event listeners for the submit button of the in page reply.\n *\n * @param {Object} root The discussion container element.\n */\n var registerEventListeners = function(root) {\n root.on('click', Selectors.post.inpageSubmitBtn, function(e) {\n e.preventDefault();\n var submitButton = $(e.currentTarget);\n var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);\n var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);\n var message = form.elements.post.value.trim();\n // For now, we consider the inline reply post written using the FORMAT_MOODLE (because a textarea is displayed).\n // In the future, other formats should be supported, letting users to use their preferred editor and format.\n var messageformat = CONTENT_FORMATS.MOODLE;\n // The message post will be converted from messageformat to FORMAT_HTML.\n var topreferredformat = true;\n var postid = form.elements.reply.value;\n var subject = form.elements.subject.value;\n var currentRoot = submitButton.closest(Selectors.post.post);\n var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;\n var modeSelector = root.find(Selectors.post.modeSelect);\n var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;\n var newid;\n\n if (message.length) {\n showSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', true);\n\n Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)\n .then(function(context) {\n var message = context.messages.reduce(function(carry, message) {\n if (message.type == 'success') {\n carry += '' + message.message + '
';\n }\n return carry;\n }, '');\n Notification.addNotification({\n message: message,\n type: \"success\"\n });\n\n return context;\n })\n .then(function(context) {\n form.reset();\n var post = context.post;\n newid = post.id;\n\n switch (mode) {\n case DISPLAYCONSTANTS.NESTED_V2:\n var capabilities = post.capabilities;\n var currentAuthorName = currentRoot.children()\n .not(Selectors.post.repliesContainer)\n .find(Selectors.post.authorName)\n .text();\n post.parentauthorname = currentAuthorName;\n post.showactionmenu = capabilities.view ||\n capabilities.controlreadstatus ||\n capabilities.edit ||\n capabilities.split ||\n capabilities.delete ||\n capabilities.export ||\n post.urls.viewparent;\n return Templates.render('mod_forum/forum_discussion_nested_v2_post_reply', post);\n case DISPLAYCONSTANTS.THREADED:\n return Templates.render('mod_forum/forum_discussion_threaded_post', post);\n case DISPLAYCONSTANTS.NESTED:\n return Templates.render('mod_forum/forum_discussion_nested_post', post);\n default:\n return Templates.render('mod_forum/forum_discussion_post', post);\n }\n })\n .then(function(html, js) {\n var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();\n\n if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {\n return Templates.prependNodeContents(repliesnode, html, js);\n } else {\n return Templates.appendNodeContents(repliesnode, html, js);\n }\n })\n .then(function() {\n submitButton.trigger(EVENTS.POST_CREATED, newid);\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n\n // Tell formchangechecker we submitted the form.\n if (typeof M.core_formchangechecker !== 'undefined') {\n M.core_formchangechecker.reset_form_dirty_state();\n }\n\n return currentRoot.find(Selectors.post.inpageReplyContent).hide();\n })\n .then(function() {\n location.href = \"#p\" + newid;\n return;\n })\n .catch(function(error) {\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n return Notification.exception(error);\n });\n }\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n },\n CONTENT_FORMATS: CONTENT_FORMATS,\n EVENTS: EVENTS\n };\n});\n"],"file":"inpage_reply.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/inpage_reply.js"],"names":["define","$","Templates","Notification","Repository","Selectors","FormChangeChecker","DISPLAYCONSTANTS","NESTED_V2","THREADED","NESTED","FLAT_OLDEST_FIRST","FLAT_NEWEST_FIRST","EVENTS","POST_CREATED","CONTENT_FORMATS","MOODLE","showSubmitButtonLoadingIcon","button","textContainer","find","post","inpageSubmitBtnText","loadingIconContainer","width","outerWidth","css","addClass","removeClass","hideSubmitButtonLoadingIcon","registerEventListeners","root","on","inpageSubmitBtn","e","preventDefault","submitButton","currentTarget","allButtons","parent","inpageReplyButton","form","parents","inpageReplyForm","get","message","elements","value","trim","messageformat","postid","reply","subject","currentRoot","closest","isprivatereply","privatereply","checked","modeSelector","modeSelect","mode","length","parseInt","newid","prop","addDiscussionPost","then","context","messages","reduce","carry","type","addNotification","reset","id","capabilities","currentAuthorName","children","not","repliesContainer","authorName","text","parentauthorname","showactionmenu","view","controlreadstatus","edit","split","delete","export","urls","viewparent","render","html","js","repliesnode","first","prependNodeContents","appendNodeContents","trigger","resetFormDirtyState","inpageReplyContent","hide","location","href","catch","error","exception","init"],"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 * This module handles the in page replying to forum posts.\n *\n * @module mod_forum/inpage_reply\n * @copyright 2019 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'mod_forum/repository',\n 'mod_forum/selectors',\n 'core_form/changechecker',\n], function(\n $,\n Templates,\n Notification,\n Repository,\n Selectors,\n FormChangeChecker\n) {\n\n var DISPLAYCONSTANTS = {\n NESTED_V2: 4,\n THREADED: 2,\n NESTED: 3,\n FLAT_OLDEST_FIRST: 1,\n FLAT_NEWEST_FIRST: -1\n };\n\n var EVENTS = {\n POST_CREATED: 'mod_forum-post-created'\n };\n\n /**\n * Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php.\n * @type {Object}\n */\n var CONTENT_FORMATS = {\n MOODLE: 0\n };\n /**\n * Show the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var showSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n var width = button.outerWidth();\n // Fix the width so that the button size doesn't change when we show the loading icon.\n button.css('width', width);\n textContainer.addClass('hidden');\n loadingIconContainer.removeClass('hidden');\n };\n\n /**\n * Hide the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var hideSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n // Reset the width back to it's default.\n button.css('width', '');\n textContainer.removeClass('hidden');\n loadingIconContainer.addClass('hidden');\n };\n\n /**\n * Register the event listeners for the submit button of the in page reply.\n *\n * @param {Object} root The discussion container element.\n */\n var registerEventListeners = function(root) {\n root.on('click', Selectors.post.inpageSubmitBtn, function(e) {\n e.preventDefault();\n var submitButton = $(e.currentTarget);\n var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);\n var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);\n var message = form.elements.post.value.trim();\n // For now, we consider the inline reply post written using the FORMAT_MOODLE (because a textarea is displayed).\n // In the future, other formats should be supported, letting users to use their preferred editor and format.\n var messageformat = CONTENT_FORMATS.MOODLE;\n // The message post will be converted from messageformat to FORMAT_HTML.\n var topreferredformat = true;\n var postid = form.elements.reply.value;\n var subject = form.elements.subject.value;\n var currentRoot = submitButton.closest(Selectors.post.post);\n var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;\n var modeSelector = root.find(Selectors.post.modeSelect);\n var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;\n var newid;\n\n if (message.length) {\n showSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', true);\n\n Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)\n .then(function(context) {\n var message = context.messages.reduce(function(carry, message) {\n if (message.type == 'success') {\n carry += '' + message.message + '
';\n }\n return carry;\n }, '');\n Notification.addNotification({\n message: message,\n type: \"success\"\n });\n\n return context;\n })\n .then(function(context) {\n form.reset();\n var post = context.post;\n newid = post.id;\n\n switch (mode) {\n case DISPLAYCONSTANTS.NESTED_V2:\n var capabilities = post.capabilities;\n var currentAuthorName = currentRoot.children()\n .not(Selectors.post.repliesContainer)\n .find(Selectors.post.authorName)\n .text();\n post.parentauthorname = currentAuthorName;\n post.showactionmenu = capabilities.view ||\n capabilities.controlreadstatus ||\n capabilities.edit ||\n capabilities.split ||\n capabilities.delete ||\n capabilities.export ||\n post.urls.viewparent;\n return Templates.render('mod_forum/forum_discussion_nested_v2_post_reply', post);\n case DISPLAYCONSTANTS.THREADED:\n return Templates.render('mod_forum/forum_discussion_threaded_post', post);\n case DISPLAYCONSTANTS.NESTED:\n return Templates.render('mod_forum/forum_discussion_nested_post', post);\n default:\n return Templates.render('mod_forum/forum_discussion_post', post);\n }\n })\n .then(function(html, js) {\n var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();\n\n if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {\n return Templates.prependNodeContents(repliesnode, html, js);\n } else {\n return Templates.appendNodeContents(repliesnode, html, js);\n }\n })\n .then(function() {\n submitButton.trigger(EVENTS.POST_CREATED, newid);\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n\n // Tell formchangechecker we submitted the form.\n FormChangeChecker.resetFormDirtyState(submitButton[0]);\n\n return currentRoot.find(Selectors.post.inpageReplyContent).hide();\n })\n .then(function() {\n location.href = \"#p\" + newid;\n return;\n })\n .catch(function(error) {\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n return Notification.exception(error);\n });\n }\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n },\n CONTENT_FORMATS: CONTENT_FORMATS,\n EVENTS: EVENTS\n };\n});\n"],"file":"inpage_reply.min.js"}
\ No newline at end of file
diff --git a/mod/forum/amd/build/posts_list.min.js b/mod/forum/amd/build/posts_list.min.js
index b8bb0af33c6..12c6c1c7265 100644
--- a/mod/forum/amd/build/posts_list.min.js
+++ b/mod/forum/amd/build/posts_list.min.js
@@ -1,2 +1,2 @@
-define ("mod_forum/posts_list",["jquery","core/templates","core/notification","core/pending","core/yui","mod_forum/selectors","mod_forum/inpage_reply"],function(a,b,c,d,e,f,g){var h=function(h){h.on("click",f.post.inpageReplyLink,function(h){h.preventDefault();if(window.location.hash){var i=window.location.href.split("#")[0];history.pushState({},document.title,i)}var j=new d("inpage-reply"),k=a(h.currentTarget).parents(f.post.forumCoreContent),l=k.find(f.post.forumSubject),m=a(h.currentTarget).parents(f.post.forumContent),n={postid:a(m).data("post-id"),reply_url:a(h.currentTarget).attr("href"),sesskey:M.cfg.sesskey,parentsubject:l.data("replySubject"),canreplyprivately:a(h.currentTarget).data("can-reply-privately"),postformat:g.CONTENT_FORMATS.MOODLE};if(!m.find(f.post.inpageReplyContent).length){b.render("mod_forum/inpage_reply",n).then(function(a,c){return b.appendNodeContents(k,a,c)}).then(function(){return m.find(f.post.inpageReplyContent).slideToggle(300,j.resolve).find("textarea").focus()}).then(function(){e.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.init({formid:"inpage-reply-".concat(n.postid)})})}).fail(c.exception)}else{var o=m.find(f.post.inpageReplyContent);o.slideToggle(300,j.resolve);if(o.is(":visible")){o.find("textarea").focus()}}})};return{init:function init(a){h(a);g.init(a)}}});
+define ("mod_forum/posts_list",["jquery","core/templates","core/notification","core/pending","mod_forum/selectors","mod_forum/inpage_reply","core_form/changechecker"],function(a,b,c,d,f,g,h){var i=function(e){e.on("click",f.post.inpageReplyLink,function(i){i.preventDefault();if(window.location.hash){var e=window.location.href.split("#")[0];history.pushState({},document.title,e)}var j=new d("inpage-reply"),k=a(i.currentTarget).parents(f.post.forumCoreContent),l=k.find(f.post.forumSubject),m=a(i.currentTarget).parents(f.post.forumContent),n={postid:a(m).data("post-id"),reply_url:a(i.currentTarget).attr("href"),sesskey:M.cfg.sesskey,parentsubject:l.data("replySubject"),canreplyprivately:a(i.currentTarget).data("can-reply-privately"),postformat:g.CONTENT_FORMATS.MOODLE};if(!m.find(f.post.inpageReplyContent).length){b.render("mod_forum/inpage_reply",n).then(function(a,c){return b.appendNodeContents(k,a,c)}).then(function(){return m.find(f.post.inpageReplyContent).slideToggle(300,j.resolve).find("textarea").focus()}).then(function(){h.watchFormById("inpage-reply-".concat(n.postid))}).catch(c.exception)}else{var o=m.find(f.post.inpageReplyContent);o.slideToggle(300,j.resolve);if(o.is(":visible")){o.find("textarea").focus()}}})};return{init:function init(a){i(a);g.init(a)}}});
//# sourceMappingURL=posts_list.min.js.map
diff --git a/mod/forum/amd/build/posts_list.min.js.map b/mod/forum/amd/build/posts_list.min.js.map
index 6f6f5d0fc08..77e2018afa6 100644
--- a/mod/forum/amd/build/posts_list.min.js.map
+++ b/mod/forum/amd/build/posts_list.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/posts_list.js"],"names":["define","$","Templates","Notification","Pending","Y","Selectors","InPageReply","registerEventListeners","root","on","post","inpageReplyLink","e","preventDefault","window","location","hash","url","href","split","history","pushState","document","title","pending","currentTarget","parents","forumCoreContent","currentSubject","find","forumSubject","currentRoot","forumContent","context","postid","data","attr","sesskey","M","cfg","parentsubject","canreplyprivately","postformat","CONTENT_FORMATS","MOODLE","inpageReplyContent","length","render","then","html","js","appendNodeContents","slideToggle","resolve","focus","use","core_formchangechecker","init","formid","fail","exception","form","is"],"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 * This module is the highest level module for the calendar. It is\n * responsible for initialising all of the components required for\n * the calendar to run. It also coordinates the interaction between\n * components by listening for and responding to different events\n * triggered within the calendar UI.\n *\n * @module mod_forum/posts_list\n * @copyright 2019 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core/pending',\n 'core/yui',\n 'mod_forum/selectors',\n 'mod_forum/inpage_reply',\n ], function(\n $,\n Templates,\n Notification,\n Pending,\n Y,\n Selectors,\n InPageReply\n ) {\n\n var registerEventListeners = function(root) {\n root.on('click', Selectors.post.inpageReplyLink, function(e) {\n e.preventDefault();\n // After adding a reply a url hash is being generated that scrolls (points) to the newly added reply.\n // The hash being present causes this scrolling behavior to the particular reply to persists even when\n // another, non-related in-page replay link is being clicked which ultimately causes a bad user experience.\n // A particular solution for this problem would be changing the browser's history state when a url hash is\n // present.\n if (window.location.hash) {\n // Remove the fragment identifier from the url.\n var url = window.location.href.split('#')[0];\n history.pushState({}, document.title, url);\n }\n var pending = new Pending('inpage-reply');\n var currentTarget = $(e.currentTarget).parents(Selectors.post.forumCoreContent);\n var currentSubject = currentTarget.find(Selectors.post.forumSubject);\n var currentRoot = $(e.currentTarget).parents(Selectors.post.forumContent);\n var context = {\n postid: $(currentRoot).data('post-id'),\n \"reply_url\": $(e.currentTarget).attr('href'),\n sesskey: M.cfg.sesskey,\n parentsubject: currentSubject.data('replySubject'),\n canreplyprivately: $(e.currentTarget).data('can-reply-privately'),\n postformat: InPageReply.CONTENT_FORMATS.MOODLE\n };\n\n if (!currentRoot.find(Selectors.post.inpageReplyContent).length) {\n Templates.render('mod_forum/inpage_reply', context)\n .then(function(html, js) {\n return Templates.appendNodeContents(currentTarget, html, js);\n })\n .then(function() {\n return currentRoot.find(Selectors.post.inpageReplyContent)\n .slideToggle(300, pending.resolve).find('textarea').focus();\n })\n .then(function() {\n // Load formchangechecker module.\n Y.use('moodle-core-formchangechecker', () => {\n M.core_formchangechecker.init({formid: `inpage-reply-${context.postid}`});\n });\n return;\n })\n .fail(Notification.exception);\n } else {\n var form = currentRoot.find(Selectors.post.inpageReplyContent);\n form.slideToggle(300, pending.resolve);\n if (form.is(':visible')) {\n form.find('textarea').focus();\n }\n }\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n InPageReply.init(root);\n }\n };\n});\n"],"file":"posts_list.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/posts_list.js"],"names":["define","$","Templates","Notification","Pending","Selectors","InPageReply","FormChangeChecker","registerEventListeners","root","on","post","inpageReplyLink","e","preventDefault","window","location","hash","url","href","split","history","pushState","document","title","pending","currentTarget","parents","forumCoreContent","currentSubject","find","forumSubject","currentRoot","forumContent","context","postid","data","attr","sesskey","M","cfg","parentsubject","canreplyprivately","postformat","CONTENT_FORMATS","MOODLE","inpageReplyContent","length","render","then","html","js","appendNodeContents","slideToggle","resolve","focus","watchFormById","catch","exception","form","is","init"],"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 * This module is the highest level module for the calendar. It is\n * responsible for initialising all of the components required for\n * the calendar to run. It also coordinates the interaction between\n * components by listening for and responding to different events\n * triggered within the calendar UI.\n *\n * @module mod_forum/posts_list\n * @copyright 2019 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core/pending',\n 'mod_forum/selectors',\n 'mod_forum/inpage_reply',\n 'core_form/changechecker',\n], function(\n $,\n Templates,\n Notification,\n Pending,\n Selectors,\n InPageReply,\n FormChangeChecker\n) {\n\n var registerEventListeners = function(root) {\n root.on('click', Selectors.post.inpageReplyLink, function(e) {\n e.preventDefault();\n // After adding a reply a url hash is being generated that scrolls (points) to the newly added reply.\n // The hash being present causes this scrolling behavior to the particular reply to persists even when\n // another, non-related in-page replay link is being clicked which ultimately causes a bad user experience.\n // A particular solution for this problem would be changing the browser's history state when a url hash is\n // present.\n if (window.location.hash) {\n // Remove the fragment identifier from the url.\n var url = window.location.href.split('#')[0];\n history.pushState({}, document.title, url);\n }\n var pending = new Pending('inpage-reply');\n var currentTarget = $(e.currentTarget).parents(Selectors.post.forumCoreContent);\n var currentSubject = currentTarget.find(Selectors.post.forumSubject);\n var currentRoot = $(e.currentTarget).parents(Selectors.post.forumContent);\n var context = {\n postid: $(currentRoot).data('post-id'),\n \"reply_url\": $(e.currentTarget).attr('href'),\n sesskey: M.cfg.sesskey,\n parentsubject: currentSubject.data('replySubject'),\n canreplyprivately: $(e.currentTarget).data('can-reply-privately'),\n postformat: InPageReply.CONTENT_FORMATS.MOODLE\n };\n\n if (!currentRoot.find(Selectors.post.inpageReplyContent).length) {\n Templates.render('mod_forum/inpage_reply', context)\n .then(function(html, js) {\n return Templates.appendNodeContents(currentTarget, html, js);\n })\n .then(function() {\n return currentRoot.find(Selectors.post.inpageReplyContent)\n .slideToggle(300, pending.resolve).find('textarea').focus();\n })\n .then(function() {\n FormChangeChecker.watchFormById(`inpage-reply-${context.postid}`);\n return;\n })\n .catch(Notification.exception);\n } else {\n var form = currentRoot.find(Selectors.post.inpageReplyContent);\n form.slideToggle(300, pending.resolve);\n if (form.is(':visible')) {\n form.find('textarea').focus();\n }\n }\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n InPageReply.init(root);\n }\n };\n});\n"],"file":"posts_list.min.js"}
\ No newline at end of file
diff --git a/mod/forum/amd/src/discussion_nested_v2.js b/mod/forum/amd/src/discussion_nested_v2.js
index 4ef64937c0b..0fd42d01a1c 100644
--- a/mod/forum/amd/src/discussion_nested_v2.js
+++ b/mod/forum/amd/src/discussion_nested_v2.js
@@ -23,6 +23,7 @@
import $ from 'jquery';
import AutoRows from 'core/auto_rows';
import CustomEvents from 'core/custom_interaction_events';
+import * as FormChangeChecker from 'core_form/changechecker';
import Notification from 'core/notification';
import Templates from 'core/templates';
import Discussion from 'mod_forum/discussion';
@@ -247,20 +248,7 @@ const buildShowInPageReplyFormFunction = (additionalTemplateContext) => {
Notification.exception(e);
}
- // Load formchangechecker module.
- import('core/yui')
- .then(Y => {
- return new Promise(resolve => {
- Y.use('moodle-core-formchangechecker', Y => {
- resolve(Y);
- });
- });
- })
- .then(Y => {
- M.core_formchangechecker.init({formid: Y.one(postContainer[0].querySelector('form')).generateID()});
- return Y;
- })
- .catch();
+ FormChangeChecker.watchForm(postContainer[0].querySelector('form'));
}
inPageReplyCreateButton.fadeOut(ANIMATION_DURATION, () => {
diff --git a/mod/forum/amd/src/inpage_reply.js b/mod/forum/amd/src/inpage_reply.js
index 2e77c5d74ab..2133840663a 100644
--- a/mod/forum/amd/src/inpage_reply.js
+++ b/mod/forum/amd/src/inpage_reply.js
@@ -21,18 +21,20 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
- 'jquery',
- 'core/templates',
- 'core/notification',
- 'mod_forum/repository',
- 'mod_forum/selectors',
- ], function(
- $,
- Templates,
- Notification,
- Repository,
- Selectors
- ) {
+ 'jquery',
+ 'core/templates',
+ 'core/notification',
+ 'mod_forum/repository',
+ 'mod_forum/selectors',
+ 'core_form/changechecker',
+], function(
+ $,
+ Templates,
+ Notification,
+ Repository,
+ Selectors,
+ FormChangeChecker
+) {
var DISPLAYCONSTANTS = {
NESTED_V2: 4,
@@ -170,9 +172,7 @@ define([
allButtons.prop('disabled', false);
// Tell formchangechecker we submitted the form.
- if (typeof M.core_formchangechecker !== 'undefined') {
- M.core_formchangechecker.reset_form_dirty_state();
- }
+ FormChangeChecker.resetFormDirtyState(submitButton[0]);
return currentRoot.find(Selectors.post.inpageReplyContent).hide();
})
diff --git a/mod/forum/amd/src/posts_list.js b/mod/forum/amd/src/posts_list.js
index 1f671203ca9..83de16840b7 100644
--- a/mod/forum/amd/src/posts_list.js
+++ b/mod/forum/amd/src/posts_list.js
@@ -25,22 +25,22 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
- 'jquery',
- 'core/templates',
- 'core/notification',
- 'core/pending',
- 'core/yui',
- 'mod_forum/selectors',
- 'mod_forum/inpage_reply',
- ], function(
- $,
- Templates,
- Notification,
- Pending,
- Y,
- Selectors,
- InPageReply
- ) {
+ 'jquery',
+ 'core/templates',
+ 'core/notification',
+ 'core/pending',
+ 'mod_forum/selectors',
+ 'mod_forum/inpage_reply',
+ 'core_form/changechecker',
+], function(
+ $,
+ Templates,
+ Notification,
+ Pending,
+ Selectors,
+ InPageReply,
+ FormChangeChecker
+) {
var registerEventListeners = function(root) {
root.on('click', Selectors.post.inpageReplyLink, function(e) {
@@ -78,13 +78,10 @@ define([
.slideToggle(300, pending.resolve).find('textarea').focus();
})
.then(function() {
- // Load formchangechecker module.
- Y.use('moodle-core-formchangechecker', () => {
- M.core_formchangechecker.init({formid: `inpage-reply-${context.postid}`});
- });
+ FormChangeChecker.watchFormById(`inpage-reply-${context.postid}`);
return;
})
- .fail(Notification.exception);
+ .catch(Notification.exception);
} else {
var form = currentRoot.find(Selectors.post.inpageReplyContent);
form.slideToggle(300, pending.resolve);
diff --git a/mod/forum/report/summary/amd/build/filters.min.js b/mod/forum/report/summary/amd/build/filters.min.js
index c2fdef94765..c1563b85e44 100644
--- a/mod/forum/report/summary/amd/build/filters.min.js
+++ b/mod/forum/report/summary/amd/build/filters.min.js
@@ -1,2 +1,2 @@
-define ("forumreport_summary/filters",["exports","jquery","core/popper","core/custom_interaction_events","forumreport_summary/selectors","core/yui","core/ajax","core/key_codes"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=i(b);c=i(c);d=i(d);e=i(e);f=i(f);g=i(g);h=i(h);function i(a){return a&&a.__esModule?a:{default:a}}var j=function(a){var i=(0,b.default)(a);(0,b.default)(document).ready(function(){(0,b.default)(".loading-icon").hide();(0,b.default)("#summaryreport").removeClass("hidden")});var j=function(a,b){var c=document.forms.filtersform.action,d;if(a){a.preventDefault();var e=c.split("?"),f=e[1],g=b.split("&"),h="",i=[],j=[];f.split("&").forEach(function(a){var b=a.split("=");i.push(b[0]);j.push(b[1])});g.forEach(function(a){var b=a.split("="),c=i.indexOf(b[0]);if(-1e){var g=document.getElementById("dates-filter-warning");g.classList.remove("hidden");g.classList.add("d-block")}else{b.elements["datefrom[timestamp]"].value=c;b.elements["datefrom[enabled]"].value=d;b.elements["dateto[timestamp]"].value=e;b.elements["dateto[enabled]"].value=f;l("#filter-dates-popover")}})}});i.on(d.default.events.activate,e.default.filters.date.calendariconfrom,function(){m(e.default.filters.date.calendariconfrom)});i.on(d.default.events.activate,e.default.filters.date.calendariconto,function(){m(e.default.filters.date.calendariconto)})};a.init=j});
+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 ("forumreport_summary/filters",["exports","jquery","core/popper","core/custom_interaction_events","forumreport_summary/selectors","core/ajax","core/key_codes","core_form/changechecker"],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=k(c);d=k(d);e=k(e);f=k(f);g=k(g);h=j(h);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}}var l=function(a){var i=(0,b.default)(a);(0,b.default)(document).ready(function(){(0,b.default)(".loading-icon").hide();(0,b.default)("#summaryreport").removeClass("hidden")});var j=function(a,b){var c=document.forms.filtersform.action,d;if(a){a.preventDefault();var e=c.split("?"),f=e[1],g=b.split("&"),h="",i=[],j=[];f.split("&").forEach(function(a){var b=a.split("=");i.push(b[0]);j.push(b[1])});g.forEach(function(a){var b=a.split("="),c=i.indexOf(b[0]);if(-1e){var f=document.getElementById("dates-filter-warning");f.classList.remove("hidden");f.classList.add("d-block")}else{b.elements["datefrom[timestamp]"].value=c;b.elements["datefrom[enabled]"].value=d;b.elements["dateto[timestamp]"].value=e;b.elements["dateto[enabled]"].value=g;l("#filter-dates-popover")}})}});i.on(d.default.events.activate,e.default.filters.date.calendariconfrom,function(){m(e.default.filters.date.calendariconfrom)});i.on(d.default.events.activate,e.default.filters.date.calendariconto,function(){m(e.default.filters.date.calendariconto)})};a.init=l});
//# sourceMappingURL=filters.min.js.map
diff --git a/mod/forum/report/summary/amd/build/filters.min.js.map b/mod/forum/report/summary/amd/build/filters.min.js.map
index 29b532ab237..0207bef64e7 100644
--- a/mod/forum/report/summary/amd/build/filters.min.js.map
+++ b/mod/forum/report/summary/amd/build/filters.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/filters.js"],"names":["init","root","jqRoot","document","ready","hide","removeClass","generateWithFilters","event","getparams","currentLink","forms","filtersform","action","newLink","preventDefault","currentSplit","split","currentstring","newparamsarray","paramsstring","paramkeys","paramvalues","forEach","param","splitparam","push","paramstring","newparam","existingkey","indexOf","name","key","substr","submit","on","target","search","selectperpage","onsubmit","getparam","elements","perpage","value","downloadForm","getElementById","querySelector","downloadType","getParams","prevAction","submitWithFilter","containerelement","Y","use","M","core_formchangechecker","reset_form_dirty_state","addClass","updateCalendarPosition","referenceid","referenceElement","popperContent","Selectors","filters","date","calendar","style","removeProperty","Popper","placement","closeOpenFilters","openFilterButton","openFilter","classList","add","setAttribute","remove","CustomEvents","events","activate","group","selectall","deselected","querySelectorAll","checkbox","checked","clear","selected","trigger","popover","closeListener","e","id","closest","keyCode","KeyCodes","enter","space","removeEventListener","escCloseListener","addEventListener","escape","save","popcheckboxes","popcheckbox","saveid","getAttribute","exportlink","link","exportbutton","exportlinkform","dataset","url","focus","filtersForm","datesPopover","fromEnabled","toEnabled","args","data","Ajax","call","methodname","done","result","fromTimestamp","toTimestamp","timestamp","warningdiv","calendariconfrom","calendariconto"],"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 responsible for handling forum summary report filters.\n *\n * @module forumreport_summary/filters\n * @copyright 2019 Michael Hawkins \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Popper from 'core/popper';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Selectors from 'forumreport_summary/selectors';\nimport Y from 'core/yui';\nimport Ajax from 'core/ajax';\nimport KeyCodes from 'core/key_codes';\n\nexport const init = (root) => {\n let jqRoot = $(root);\n\n // Hide loading spinner and show report once page is ready.\n // This ensures filters can be applied when sorting by columns.\n $(document).ready(function() {\n $('.loading-icon').hide();\n $('#summaryreport').removeClass('hidden');\n });\n\n // Generic filter handlers.\n\n // Called to override click event to trigger a proper generate request with filtering.\n const generateWithFilters = (event, getparams) => {\n let currentLink = document.forms.filtersform.action,\n newLink;\n\n if (event) {\n event.preventDefault();\n\n let currentSplit = currentLink.split('?'),\n currentstring = currentSplit[1],\n newparamsarray = getparams.split('&'),\n paramsstring = '',\n paramkeys = [],\n paramvalues = [];\n\n // Separate out the existing action GET param string.\n currentstring.split('&').forEach(function(param) {\n let splitparam = param.split('=');\n paramkeys.push(splitparam[0]);\n paramvalues.push(splitparam[1]);\n });\n\n newparamsarray.forEach(function(paramstring) {\n let newparam = paramstring.split('='),\n existingkey = paramkeys.indexOf(newparam[0]);\n\n // Overwrite value if existing, otherwise add new param.\n if (existingkey > -1) {\n paramvalues[existingkey] = newparam[1];\n } else {\n paramkeys.push(newparam[0]);\n paramvalues.push(newparam[1]);\n }\n });\n\n // Build URL.\n paramkeys.forEach(function(name, key) {\n paramsstring += `&${name}=${paramvalues[key]}`;\n });\n\n newLink = currentSplit[0] + '?' + paramsstring.substr(1);\n } else {\n newLink = currentLink;\n }\n\n document.forms.filtersform.action = newLink;\n document.forms.filtersform.submit();\n };\n\n // Override 'reset table preferences' so it generates with filters.\n $('.resettable').on(\"click\", \"a\", function(event) {\n generateWithFilters(event, event.target.search.substr(1));\n });\n\n // Override table heading sort links so they generate with filters.\n $('thead').on(\"click\", \"a\", function(event) {\n generateWithFilters(event, event.target.search.substr(1));\n });\n\n // Override pagination page links so they generate with filters.\n $('.pagination').on(\"click\", \"a\", function(event) {\n generateWithFilters(event, event.target.search.substr(1));\n });\n\n // Override rows per page submission so it generates with filters.\n if (document.forms.selectperpage) {\n document.forms.selectperpage.onsubmit = (event) => {\n let getparam = 'perpage=' + document.forms.selectperpage.elements.perpage.value;\n generateWithFilters(event, getparam);\n };\n }\n\n // Override download link so the file is generated with filters.\n const downloadForm = document.getElementById('summaryreport').querySelector('form.dataformatselector');\n if (downloadForm) {\n downloadForm.onsubmit = (event) => {\n const downloadType = downloadForm.querySelector('#downloadtype_download').value;\n const getParams = `download=${downloadType}`;\n const prevAction = document.forms.filtersform.action;\n\n generateWithFilters(event, getParams);\n\n // Revert action, so re-submitting the form via filter does not trigger a further download.\n document.forms.filtersform.action = prevAction;\n };\n }\n\n // Submit report via filter\n const submitWithFilter = (containerelement) => {\n // Disable the dates filter mform checker to prevent any changes triggering a warning to the user.\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n\n // Close the container (eg popover).\n $(containerelement).addClass('hidden');\n\n // Submit the filter values and re-generate report.\n generateWithFilters(false);\n };\n\n // Use popper to override date mform calendar position.\n const updateCalendarPosition = (referenceid) => {\n let referenceElement = document.querySelector(referenceid),\n popperContent = document.querySelector(Selectors.filters.date.calendar);\n\n popperContent.style.removeProperty(\"z-index\");\n new Popper(referenceElement, popperContent, {placement: 'bottom'});\n };\n\n // Close the relevant filter.\n const closeOpenFilters = (openFilterButton, openFilter) => {\n openFilter.classList.add('hidden');\n openFilter.setAttribute('data-openfilter', 'false');\n\n openFilterButton.classList.add('btn-primary');\n openFilterButton.classList.remove('btn-outline-primary');\n openFilterButton.setAttribute('aria-expanded', false);\n };\n\n // Groups filter specific handlers.\n\n // Event handler for clicking select all groups.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.selectall, function() {\n let deselected = root.querySelectorAll(Selectors.filters.group.checkbox + ':not(:checked)');\n deselected.forEach(function(checkbox) {\n checkbox.checked = true;\n });\n });\n\n // Event handler for clearing filter by clicking option.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.clear, function() {\n // Clear checkboxes.\n let selected = root.querySelectorAll(Selectors.filters.group.checkbox + ':checked');\n selected.forEach(function(checkbox) {\n checkbox.checked = false;\n });\n });\n\n // Event handler for showing groups filter popover.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.trigger, function() {\n // Create popover.\n let referenceElement = root.querySelector(Selectors.filters.group.trigger),\n popperContent = root.querySelector(Selectors.filters.group.popover);\n\n new Popper(referenceElement, popperContent, {placement: 'bottom'});\n\n // Show popover.\n popperContent.classList.remove('hidden');\n popperContent.setAttribute('data-openfilter', 'true');\n\n // Change to outlined button.\n referenceElement.classList.add('btn-outline-primary');\n referenceElement.classList.remove('btn-primary');\n\n // Let screen readers know that it's now expanded.\n referenceElement.setAttribute('aria-expanded', true);\n\n // Add listeners to handle closing filter.\n const closeListener = e => {\n if (e.target.id !== referenceElement.id && popperContent !== e.target.closest('[data-openfilter=\"true\"]') &&\n (typeof e.keyCode === 'undefined' || e.keyCode === KeyCodes.enter || e.keyCode === KeyCodes.space)) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('click', closeListener);\n document.removeEventListener('keyup', closeListener);\n document.removeEventListener('keyup', escCloseListener);\n }\n };\n\n document.addEventListener('click', closeListener);\n document.addEventListener('keyup', closeListener);\n\n const escCloseListener = e => {\n if (e.keyCode === KeyCodes.escape) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('keyup', escCloseListener);\n document.removeEventListener('click', closeListener);\n }\n };\n\n document.addEventListener('keyup', escCloseListener);\n });\n\n // Event handler to click save groups filter.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.save, function() {\n // Copy the saved values into the form before submitting.\n let popcheckboxes = root.querySelectorAll(Selectors.filters.group.checkbox);\n\n popcheckboxes.forEach(function(popcheckbox) {\n let filtersform = document.forms.filtersform,\n saveid = popcheckbox.getAttribute('data-saveid');\n\n filtersform.querySelector(`#${saveid}`).checked = popcheckbox.checked;\n });\n\n submitWithFilter('#filter-groups-popover');\n });\n\n // Listeners for export buttons.\n // These allow fetching of the relevant export URL, before submitting the request with\n // any POST data that is common to all of the export links. This allows filters to be\n // applied that contain potentially a lot of data (eg discussion IDs for groups filtering).\n document.querySelectorAll(Selectors.filters.exportlink.link).forEach(function(exportbutton) {\n exportbutton.addEventListener('click', function(event) {\n document.forms.exportlinkform.action = event.target.dataset.url;\n document.forms.exportlinkform.submit();\n });\n });\n\n // Dates filter specific handlers.\n\n // Event handler for showing dates filter popover.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.trigger, function() {\n\n // Create popover.\n let referenceElement = root.querySelector(Selectors.filters.date.trigger),\n popperContent = root.querySelector(Selectors.filters.date.popover);\n\n new Popper(referenceElement, popperContent, {placement: 'bottom'});\n\n // Show popover and move focus.\n popperContent.classList.remove('hidden');\n popperContent.setAttribute('data-openfilter', 'true');\n popperContent.querySelector('[name=\"filterdatefrompopover[enabled]\"]').focus();\n\n // Change to outlined button.\n referenceElement.classList.add('btn-outline-primary');\n referenceElement.classList.remove('btn-primary');\n\n // Let screen readers know that it's now expanded.\n referenceElement.setAttribute('aria-expanded', true);\n\n // Add listener to handle closing filter.\n const closeListener = e => {\n if (e.target.id !== referenceElement.id && popperContent !== e.target.closest('[data-openfilter=\"true\"]') &&\n (typeof e.keyCode === 'undefined' || e.keyCode === KeyCodes.enter || e.keyCode === KeyCodes.space)) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('click', closeListener);\n document.removeEventListener('keyup', closeListener);\n document.removeEventListener('keyup', escCloseListener);\n }\n };\n\n document.addEventListener('click', closeListener);\n document.addEventListener('keyup', closeListener);\n\n const escCloseListener = e => {\n if (e.keyCode === KeyCodes.escape) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('keyup', escCloseListener);\n document.removeEventListener('click', closeListener);\n }\n };\n\n document.addEventListener('keyup', escCloseListener);\n });\n\n // Event handler to save dates filter.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.save, function() {\n // Populate the hidden form inputs to submit the data.\n let filtersForm = document.forms.filtersform;\n const datesPopover = root.querySelector(Selectors.filters.date.popover);\n const fromEnabled = datesPopover.querySelector('[name=\"filterdatefrompopover[enabled]\"]').checked ? 1 : 0;\n const toEnabled = datesPopover.querySelector('[name=\"filterdatetopopover[enabled]\"]').checked ? 1 : 0;\n\n if (!fromEnabled && !toEnabled) {\n // Update the elements in the filter form.\n filtersForm.elements['datefrom[timestamp]'].value = 0;\n filtersForm.elements['datefrom[enabled]'].value = fromEnabled;\n filtersForm.elements['dateto[timestamp]'].value = 0;\n filtersForm.elements['dateto[enabled]'].value = toEnabled;\n\n // Submit the filter values and re-generate report.\n submitWithFilter('#filter-dates-popover');\n } else {\n let args = {data: []};\n\n if (fromEnabled) {\n args.data.push({\n 'key': 'from',\n 'year': datesPopover.querySelector('[name=\"filterdatefrompopover[year]\"]').value,\n 'month': datesPopover.querySelector('[name=\"filterdatefrompopover[month]\"]').value,\n 'day': datesPopover.querySelector('[name=\"filterdatefrompopover[day]\"]').value,\n 'hour': 0,\n 'minute': 0\n });\n }\n\n if (toEnabled) {\n args.data.push({\n 'key': 'to',\n 'year': datesPopover.querySelector('[name=\"filterdatetopopover[year]\"]').value,\n 'month': datesPopover.querySelector('[name=\"filterdatetopopover[month]\"]').value,\n 'day': datesPopover.querySelector('[name=\"filterdatetopopover[day]\"]').value,\n 'hour': 23,\n 'minute': 59\n });\n }\n\n const request = {\n methodname: 'core_calendar_get_timestamps',\n args: args\n };\n\n Ajax.call([request])[0].done(function(result) {\n let fromTimestamp = 0,\n toTimestamp = 0;\n\n result['timestamps'].forEach(function(data){\n if (data.key === 'from') {\n fromTimestamp = data.timestamp;\n } else if (data.key === 'to') {\n toTimestamp = data.timestamp;\n }\n });\n\n // Display an error if the from date is later than the do date.\n if (toTimestamp > 0 && fromTimestamp > toTimestamp) {\n const warningdiv = document.getElementById('dates-filter-warning');\n warningdiv.classList.remove('hidden');\n warningdiv.classList.add('d-block');\n } else {\n filtersForm.elements['datefrom[timestamp]'].value = fromTimestamp;\n filtersForm.elements['datefrom[enabled]'].value = fromEnabled;\n filtersForm.elements['dateto[timestamp]'].value = toTimestamp;\n filtersForm.elements['dateto[enabled]'].value = toEnabled;\n\n // Submit the filter values and re-generate report.\n submitWithFilter('#filter-dates-popover');\n }\n });\n }\n });\n\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.calendariconfrom, function() {\n updateCalendarPosition(Selectors.filters.date.calendariconfrom);\n });\n\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.calendariconto, function() {\n updateCalendarPosition(Selectors.filters.date.calendariconto);\n });\n};\n"],"file":"filters.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/filters.js"],"names":["init","root","jqRoot","document","ready","hide","removeClass","generateWithFilters","event","getparams","currentLink","forms","filtersform","action","newLink","preventDefault","currentSplit","split","currentstring","newparamsarray","paramsstring","paramkeys","paramvalues","forEach","param","splitparam","push","paramstring","newparam","existingkey","indexOf","name","key","substr","submit","on","target","search","selectperpage","onsubmit","getparam","elements","perpage","value","downloadForm","getElementById","querySelector","downloadType","getParams","prevAction","submitWithFilter","containerelement","FormChangeChecker","unWatchForm","addClass","updateCalendarPosition","referenceid","referenceElement","popperContent","Selectors","filters","date","calendar","style","removeProperty","Popper","placement","closeOpenFilters","openFilterButton","openFilter","classList","add","setAttribute","remove","CustomEvents","events","activate","group","selectall","deselected","querySelectorAll","checkbox","checked","clear","selected","trigger","popover","closeListener","e","id","closest","keyCode","KeyCodes","enter","space","removeEventListener","escCloseListener","addEventListener","escape","save","popcheckboxes","popcheckbox","saveid","getAttribute","exportlink","link","exportbutton","exportlinkform","dataset","url","focus","filtersForm","datesPopover","fromEnabled","toEnabled","args","data","Ajax","call","methodname","done","result","fromTimestamp","toTimestamp","timestamps","timestamp","warningdiv","calendariconfrom","calendariconto"],"mappings":"0kBAuBA,OACA,OACA,OACA,OACA,OACA,OACA,O,ylBAEO,GAAMA,CAAAA,CAAI,CAAG,SAACC,CAAD,CAAU,CAC1B,GAAIC,CAAAA,CAAM,CAAG,cAAED,CAAF,CAAb,CAIA,cAAEE,QAAF,EAAYC,KAAZ,CAAkB,UAAW,CACzB,cAAE,eAAF,EAAmBC,IAAnB,GACA,cAAE,gBAAF,EAAoBC,WAApB,CAAgC,QAAhC,CACH,CAHD,EAQA,GAAMC,CAAAA,CAAmB,CAAG,SAACC,CAAD,CAAQC,CAAR,CAAsB,CAC9C,GAAIC,CAAAA,CAAW,CAAGP,QAAQ,CAACQ,KAAT,CAAeC,WAAf,CAA2BC,MAA7C,CACIC,CADJ,CAGA,GAAIN,CAAJ,CAAW,CACPA,CAAK,CAACO,cAAN,GAED,GAAIC,CAAAA,CAAY,CAAGN,CAAW,CAACO,KAAZ,CAAkB,GAAlB,CAAnB,CACIC,CAAa,CAAGF,CAAY,CAAC,CAAD,CADhC,CAEIG,CAAc,CAAGV,CAAS,CAACQ,KAAV,CAAgB,GAAhB,CAFrB,CAGIG,CAAY,CAAG,EAHnB,CAIIC,CAAS,CAAG,EAJhB,CAKIC,CAAW,CAAG,EALlB,CAQCJ,CAAa,CAACD,KAAd,CAAoB,GAApB,EAAyBM,OAAzB,CAAiC,SAASC,CAAT,CAAgB,CAC7C,GAAIC,CAAAA,CAAU,CAAGD,CAAK,CAACP,KAAN,CAAY,GAAZ,CAAjB,CACAI,CAAS,CAACK,IAAV,CAAeD,CAAU,CAAC,CAAD,CAAzB,EACAH,CAAW,CAACI,IAAZ,CAAiBD,CAAU,CAAC,CAAD,CAA3B,CACH,CAJD,EAMAN,CAAc,CAACI,OAAf,CAAuB,SAASI,CAAT,CAAsB,CACzC,GAAIC,CAAAA,CAAQ,CAAGD,CAAW,CAACV,KAAZ,CAAkB,GAAlB,CAAf,CACIY,CAAW,CAAGR,CAAS,CAACS,OAAV,CAAkBF,CAAQ,CAAC,CAAD,CAA1B,CADlB,CAIA,GAAkB,CAAC,CAAf,CAAAC,CAAJ,CAAsB,CAClBP,CAAW,CAACO,CAAD,CAAX,CAA2BD,CAAQ,CAAC,CAAD,CACtC,CAFD,IAEO,CACHP,CAAS,CAACK,IAAV,CAAeE,CAAQ,CAAC,CAAD,CAAvB,EACAN,CAAW,CAACI,IAAZ,CAAiBE,CAAQ,CAAC,CAAD,CAAzB,CACH,CACJ,CAXD,EAcAP,CAAS,CAACE,OAAV,CAAkB,SAASQ,CAAT,CAAeC,CAAf,CAAoB,CAClCZ,CAAY,aAAQW,CAAR,aAAgBT,CAAW,CAACU,CAAD,CAA3B,CACf,CAFD,EAIAlB,CAAO,CAAGE,CAAY,CAAC,CAAD,CAAZ,CAAkB,GAAlB,CAAwBI,CAAY,CAACa,MAAb,CAAoB,CAApB,CACrC,CApCD,IAoCO,CACHnB,CAAO,CAAGJ,CACb,CAEDP,QAAQ,CAACQ,KAAT,CAAeC,WAAf,CAA2BC,MAA3B,CAAoCC,CAApC,CACAX,QAAQ,CAACQ,KAAT,CAAeC,WAAf,CAA2BsB,MAA3B,EACH,CA9CD,CAiDA,cAAE,aAAF,EAAiBC,EAAjB,CAAoB,OAApB,CAA6B,GAA7B,CAAkC,SAAS3B,CAAT,CAAgB,CAC9CD,CAAmB,CAACC,CAAD,CAAQA,CAAK,CAAC4B,MAAN,CAAaC,MAAb,CAAoBJ,MAApB,CAA2B,CAA3B,CAAR,CACtB,CAFD,EAKA,cAAE,OAAF,EAAWE,EAAX,CAAc,OAAd,CAAuB,GAAvB,CAA4B,SAAS3B,CAAT,CAAgB,CACxCD,CAAmB,CAACC,CAAD,CAAQA,CAAK,CAAC4B,MAAN,CAAaC,MAAb,CAAoBJ,MAApB,CAA2B,CAA3B,CAAR,CACtB,CAFD,EAKA,cAAE,aAAF,EAAiBE,EAAjB,CAAoB,OAApB,CAA6B,GAA7B,CAAkC,SAAS3B,CAAT,CAAgB,CAC9CD,CAAmB,CAACC,CAAD,CAAQA,CAAK,CAAC4B,MAAN,CAAaC,MAAb,CAAoBJ,MAApB,CAA2B,CAA3B,CAAR,CACtB,CAFD,EAKA,GAAI9B,QAAQ,CAACQ,KAAT,CAAe2B,aAAnB,CAAkC,CAC9BnC,QAAQ,CAACQ,KAAT,CAAe2B,aAAf,CAA6BC,QAA7B,CAAwC,SAAC/B,CAAD,CAAW,CAC/C,GAAIgC,CAAAA,CAAQ,CAAG,WAAarC,QAAQ,CAACQ,KAAT,CAAe2B,aAAf,CAA6BG,QAA7B,CAAsCC,OAAtC,CAA8CC,KAA1E,CACApC,CAAmB,CAACC,CAAD,CAAQgC,CAAR,CACtB,CACJ,CAGD,GAAMI,CAAAA,CAAY,CAAGzC,QAAQ,CAAC0C,cAAT,CAAwB,eAAxB,EAAyCC,aAAzC,CAAuD,yBAAvD,CAArB,CACA,GAAIF,CAAJ,CAAkB,CACdA,CAAY,CAACL,QAAb,CAAwB,SAAC/B,CAAD,CAAW,IACzBuC,CAAAA,CAAY,CAAGH,CAAY,CAACE,aAAb,CAA2B,wBAA3B,EAAqDH,KAD3C,CAEzBK,CAAS,oBAAeD,CAAf,CAFgB,CAGzBE,CAAU,CAAG9C,QAAQ,CAACQ,KAAT,CAAeC,WAAf,CAA2BC,MAHf,CAK/BN,CAAmB,CAACC,CAAD,CAAQwC,CAAR,CAAnB,CAGA7C,QAAQ,CAACQ,KAAT,CAAeC,WAAf,CAA2BC,MAA3B,CAAoCoC,CACvC,CACJ,CAjGyB,GAoGpBC,CAAAA,CAAgB,CAAG,SAACC,CAAD,CAAsB,CAE3CC,CAAiB,CAACC,WAAlB,CAA8BlD,QAAQ,CAACQ,KAAT,CAAeC,WAA7C,EAGA,cAAEuC,CAAF,EAAoBG,QAApB,CAA6B,QAA7B,EAGA/C,CAAmB,IACtB,CA7GyB,CAgHpBgD,CAAsB,CAAG,SAACC,CAAD,CAAiB,CAC5C,GAAIC,CAAAA,CAAgB,CAAGtD,QAAQ,CAAC2C,aAAT,CAAuBU,CAAvB,CAAvB,CACIE,CAAa,CAAGvD,QAAQ,CAAC2C,aAAT,CAAuBa,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBC,QAA9C,CADpB,CAGAJ,CAAa,CAACK,KAAd,CAAoBC,cAApB,CAAmC,SAAnC,EACA,GAAIC,UAAJ,CAAWR,CAAX,CAA6BC,CAA7B,CAA4C,CAACQ,SAAS,CAAE,QAAZ,CAA5C,CACH,CAtHyB,CAyHpBC,CAAgB,CAAG,SAACC,CAAD,CAAmBC,CAAnB,CAAkC,CACvDA,CAAU,CAACC,SAAX,CAAqBC,GAArB,CAAyB,QAAzB,EACAF,CAAU,CAACG,YAAX,CAAwB,iBAAxB,CAA2C,OAA3C,EAEAJ,CAAgB,CAACE,SAAjB,CAA2BC,GAA3B,CAA+B,aAA/B,EACAH,CAAgB,CAACE,SAAjB,CAA2BG,MAA3B,CAAkC,qBAAlC,EACAL,CAAgB,CAACI,YAAjB,CAA8B,eAA9B,IACH,CAhIyB,CAqI1BtE,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBC,SAAhE,CAA2E,UAAW,CAClF,GAAIC,CAAAA,CAAU,CAAG9E,CAAI,CAAC+E,gBAAL,CAAsBrB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBI,QAAxB,CAAmC,gBAAzD,CAAjB,CACAF,CAAU,CAACxD,OAAX,CAAmB,SAAS0D,CAAT,CAAmB,CAClCA,CAAQ,CAACC,OAAT,GACH,CAFD,CAGH,CALD,EAQAhF,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBM,KAAhE,CAAuE,UAAW,CAE9E,GAAIC,CAAAA,CAAQ,CAAGnF,CAAI,CAAC+E,gBAAL,CAAsBrB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBI,QAAxB,CAAmC,UAAzD,CAAf,CACAG,CAAQ,CAAC7D,OAAT,CAAiB,SAAS0D,CAAT,CAAmB,CAChCA,CAAQ,CAACC,OAAT,GACH,CAFD,CAGH,CAND,EASAhF,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBQ,OAAhE,CAAyE,UAAW,CAEhF,GAAI5B,CAAAA,CAAgB,CAAGxD,CAAI,CAAC6C,aAAL,CAAmBa,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBQ,OAA3C,CAAvB,CACI3B,CAAa,CAAGzD,CAAI,CAAC6C,aAAL,CAAmBa,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBS,OAA3C,CADpB,CAGA,GAAIrB,UAAJ,CAAWR,CAAX,CAA6BC,CAA7B,CAA4C,CAACQ,SAAS,CAAE,QAAZ,CAA5C,EAGAR,CAAa,CAACY,SAAd,CAAwBG,MAAxB,CAA+B,QAA/B,EACAf,CAAa,CAACc,YAAd,CAA2B,iBAA3B,CAA8C,MAA9C,EAGAf,CAAgB,CAACa,SAAjB,CAA2BC,GAA3B,CAA+B,qBAA/B,EACAd,CAAgB,CAACa,SAAjB,CAA2BG,MAA3B,CAAkC,aAAlC,EAGAhB,CAAgB,CAACe,YAAjB,CAA8B,eAA9B,KAGA,GAAMe,CAAAA,CAAa,CAAG,SAAAC,CAAC,CAAI,CACvB,GAAIA,CAAC,CAACpD,MAAF,CAASqD,EAAT,GAAgBhC,CAAgB,CAACgC,EAAjC,EAAuC/B,CAAa,GAAK8B,CAAC,CAACpD,MAAF,CAASsD,OAAT,CAAiB,4BAAjB,CAAzD,GAC0B,WAArB,QAAOF,CAAAA,CAAC,CAACG,OAAT,EAAoCH,CAAC,CAACG,OAAF,GAAcC,UAASC,KAA3D,EAAoEL,CAAC,CAACG,OAAF,GAAcC,UAASE,KADhG,CAAJ,CAC4G,CACxG3B,CAAgB,CAACV,CAAD,CAAmBC,CAAnB,CAAhB,CACAvD,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCR,CAAtC,EACApF,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCR,CAAtC,EACApF,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCC,CAAtC,CACH,CACJ,CARD,CAUA7F,QAAQ,CAAC8F,gBAAT,CAA0B,OAA1B,CAAmCV,CAAnC,EACApF,QAAQ,CAAC8F,gBAAT,CAA0B,OAA1B,CAAmCV,CAAnC,EAEA,GAAMS,CAAAA,CAAgB,CAAG,SAAAR,CAAC,CAAI,CAC1B,GAAIA,CAAC,CAACG,OAAF,GAAcC,UAASM,MAA3B,CAAmC,CAC/B/B,CAAgB,CAACV,CAAD,CAAmBC,CAAnB,CAAhB,CACAvD,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCC,CAAtC,EACA7F,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCR,CAAtC,CACH,CACJ,CAND,CAQApF,QAAQ,CAAC8F,gBAAT,CAA0B,OAA1B,CAAmCD,CAAnC,CACH,CAzCD,EA4CA9F,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBsB,IAAhE,CAAsE,UAAW,CAE7E,GAAIC,CAAAA,CAAa,CAAGnG,CAAI,CAAC+E,gBAAL,CAAsBrB,UAAUC,OAAV,CAAkBiB,KAAlB,CAAwBI,QAA9C,CAApB,CAEAmB,CAAa,CAAC7E,OAAd,CAAsB,SAAS8E,CAAT,CAAsB,CACxC,GAAIzF,CAAAA,CAAW,CAAGT,QAAQ,CAACQ,KAAT,CAAeC,WAAjC,CACI0F,CAAM,CAAGD,CAAW,CAACE,YAAZ,CAAyB,aAAzB,CADb,CAGA3F,CAAW,CAACkC,aAAZ,YAA8BwD,CAA9B,GAAwCpB,OAAxC,CAAkDmB,CAAW,CAACnB,OACjE,CALD,EAOAhC,CAAgB,CAAC,wBAAD,CACnB,CAZD,EAkBA/C,QAAQ,CAAC6E,gBAAT,CAA0BrB,UAAUC,OAAV,CAAkB4C,UAAlB,CAA6BC,IAAvD,EAA6DlF,OAA7D,CAAqE,SAASmF,CAAT,CAAuB,CACxFA,CAAY,CAACT,gBAAb,CAA8B,OAA9B,CAAuC,SAASzF,CAAT,CAAgB,CACnDL,QAAQ,CAACQ,KAAT,CAAegG,cAAf,CAA8B9F,MAA9B,CAAuCL,CAAK,CAAC4B,MAAN,CAAawE,OAAb,CAAqBC,GAA5D,CACA1G,QAAQ,CAACQ,KAAT,CAAegG,cAAf,CAA8BzE,MAA9B,EACH,CAHD,CAIH,CALD,EAUAhC,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBwB,OAA/D,CAAwE,UAAW,CAG/E,GAAI5B,CAAAA,CAAgB,CAAGxD,CAAI,CAAC6C,aAAL,CAAmBa,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBwB,OAA1C,CAAvB,CACI3B,CAAa,CAAGzD,CAAI,CAAC6C,aAAL,CAAmBa,UAAUC,OAAV,CAAkBC,IAAlB,CAAuByB,OAA1C,CADpB,CAGA,GAAIrB,UAAJ,CAAWR,CAAX,CAA6BC,CAA7B,CAA4C,CAACQ,SAAS,CAAE,QAAZ,CAA5C,EAGAR,CAAa,CAACY,SAAd,CAAwBG,MAAxB,CAA+B,QAA/B,EACAf,CAAa,CAACc,YAAd,CAA2B,iBAA3B,CAA8C,MAA9C,EACAd,CAAa,CAACZ,aAAd,CAA4B,2CAA5B,EAAuEgE,KAAvE,GAGArD,CAAgB,CAACa,SAAjB,CAA2BC,GAA3B,CAA+B,qBAA/B,EACAd,CAAgB,CAACa,SAAjB,CAA2BG,MAA3B,CAAkC,aAAlC,EAGAhB,CAAgB,CAACe,YAAjB,CAA8B,eAA9B,KAGA,GAAMe,CAAAA,CAAa,CAAG,SAAAC,CAAC,CAAI,CACvB,GAAIA,CAAC,CAACpD,MAAF,CAASqD,EAAT,GAAgBhC,CAAgB,CAACgC,EAAjC,EAAuC/B,CAAa,GAAK8B,CAAC,CAACpD,MAAF,CAASsD,OAAT,CAAiB,4BAAjB,CAAzD,GAC0B,WAArB,QAAOF,CAAAA,CAAC,CAACG,OAAT,EAAoCH,CAAC,CAACG,OAAF,GAAcC,UAASC,KAA3D,EAAoEL,CAAC,CAACG,OAAF,GAAcC,UAASE,KADhG,CAAJ,CAC4G,CACxG3B,CAAgB,CAACV,CAAD,CAAmBC,CAAnB,CAAhB,CACAvD,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCR,CAAtC,EACApF,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCR,CAAtC,EACApF,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCC,CAAtC,CACH,CACJ,CARD,CAUA7F,QAAQ,CAAC8F,gBAAT,CAA0B,OAA1B,CAAmCV,CAAnC,EACApF,QAAQ,CAAC8F,gBAAT,CAA0B,OAA1B,CAAmCV,CAAnC,EAEA,GAAMS,CAAAA,CAAgB,CAAG,SAAAR,CAAC,CAAI,CAC1B,GAAIA,CAAC,CAACG,OAAF,GAAcC,UAASM,MAA3B,CAAmC,CAC/B/B,CAAgB,CAACV,CAAD,CAAmBC,CAAnB,CAAhB,CACAvD,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCC,CAAtC,EACA7F,QAAQ,CAAC4F,mBAAT,CAA6B,OAA7B,CAAsCR,CAAtC,CACH,CACJ,CAND,CAQApF,QAAQ,CAAC8F,gBAAT,CAA0B,OAA1B,CAAmCD,CAAnC,CACH,CA3CD,EA8CA9F,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBsC,IAA/D,CAAqE,UAAW,IAExEY,CAAAA,CAAW,CAAG5G,QAAQ,CAACQ,KAAT,CAAeC,WAF2C,CAGtEoG,CAAY,CAAG/G,CAAI,CAAC6C,aAAL,CAAmBa,UAAUC,OAAV,CAAkBC,IAAlB,CAAuByB,OAA1C,CAHuD,CAItE2B,CAAW,CAAGD,CAAY,CAAClE,aAAb,CAA2B,2CAA3B,EAAsEoC,OAAtE,CAAgF,CAAhF,CAAoF,CAJ5B,CAKtEgC,CAAS,CAAGF,CAAY,CAAClE,aAAb,CAA2B,yCAA3B,EAAoEoC,OAApE,CAA8E,CAA9E,CAAkF,CALxB,CAO5E,GAAI,CAAC+B,CAAD,EAAgB,CAACC,CAArB,CAAgC,CAE5BH,CAAW,CAACtE,QAAZ,CAAqB,qBAArB,EAA4CE,KAA5C,CAAoD,CAApD,CACAoE,CAAW,CAACtE,QAAZ,CAAqB,mBAArB,EAA0CE,KAA1C,CAAkDsE,CAAlD,CACAF,CAAW,CAACtE,QAAZ,CAAqB,mBAArB,EAA0CE,KAA1C,CAAkD,CAAlD,CACAoE,CAAW,CAACtE,QAAZ,CAAqB,iBAArB,EAAwCE,KAAxC,CAAgDuE,CAAhD,CAGAhE,CAAgB,CAAC,uBAAD,CACnB,CATD,IASO,CACH,GAAIiE,CAAAA,CAAI,CAAG,CAACC,IAAI,CAAE,EAAP,CAAX,CAEA,GAAIH,CAAJ,CAAiB,CACbE,CAAI,CAACC,IAAL,CAAU1F,IAAV,CAAe,CACX,IAAO,MADI,CAEX,KAAQsF,CAAY,CAAClE,aAAb,CAA2B,wCAA3B,EAAmEH,KAFhE,CAGX,MAASqE,CAAY,CAAClE,aAAb,CAA2B,yCAA3B,EAAoEH,KAHlE,CAIX,IAAOqE,CAAY,CAAClE,aAAb,CAA2B,uCAA3B,EAAkEH,KAJ9D,CAKX,KAAQ,CALG,CAMX,OAAU,CANC,CAAf,CAQH,CAED,GAAIuE,CAAJ,CAAe,CACXC,CAAI,CAACC,IAAL,CAAU1F,IAAV,CAAe,CACX,IAAO,IADI,CAEX,KAAQsF,CAAY,CAAClE,aAAb,CAA2B,sCAA3B,EAAiEH,KAF9D,CAGX,MAASqE,CAAY,CAAClE,aAAb,CAA2B,uCAA3B,EAAkEH,KAHhE,CAIX,IAAOqE,CAAY,CAAClE,aAAb,CAA2B,qCAA3B,EAAgEH,KAJ5D,CAKX,KAAQ,EALG,CAMX,OAAU,EANC,CAAf,CAQH,CAOD0E,UAAKC,IAAL,CAAU,CALM,CACZC,UAAU,CAAE,8BADA,CAEZJ,IAAI,CAAEA,CAFM,CAKN,CAAV,EAAqB,CAArB,EAAwBK,IAAxB,CAA6B,SAASC,CAAT,CAAiB,CAC1C,GAAIC,CAAAA,CAAa,CAAG,CAApB,CACIC,CAAW,CAAG,CADlB,CAGAF,CAAM,CAACG,UAAP,CAAkBrG,OAAlB,CAA0B,SAAS6F,CAAT,CAAe,CACrC,GAAiB,MAAb,GAAAA,CAAI,CAACpF,GAAT,CAAyB,CACrB0F,CAAa,CAAGN,CAAI,CAACS,SACxB,CAFD,IAEO,IAAiB,IAAb,GAAAT,CAAI,CAACpF,GAAT,CAAuB,CAC1B2F,CAAW,CAAGP,CAAI,CAACS,SACtB,CACJ,CAND,EASA,GAAkB,CAAd,CAAAF,CAAW,EAAQD,CAAa,CAAGC,CAAvC,CAAoD,CAChD,GAAMG,CAAAA,CAAU,CAAG3H,QAAQ,CAAC0C,cAAT,CAAwB,sBAAxB,CAAnB,CACAiF,CAAU,CAACxD,SAAX,CAAqBG,MAArB,CAA4B,QAA5B,EACAqD,CAAU,CAACxD,SAAX,CAAqBC,GAArB,CAAyB,SAAzB,CACH,CAJD,IAIO,CACHwC,CAAW,CAACtE,QAAZ,CAAqB,qBAArB,EAA4CE,KAA5C,CAAoD+E,CAApD,CACAX,CAAW,CAACtE,QAAZ,CAAqB,mBAArB,EAA0CE,KAA1C,CAAkDsE,CAAlD,CACAF,CAAW,CAACtE,QAAZ,CAAqB,mBAArB,EAA0CE,KAA1C,CAAkDgF,CAAlD,CACAZ,CAAW,CAACtE,QAAZ,CAAqB,iBAArB,EAAwCE,KAAxC,CAAgDuE,CAAhD,CAGAhE,CAAgB,CAAC,uBAAD,CACnB,CACJ,CA1BD,CA2BH,CACJ,CA1ED,EA4EAhD,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBkE,gBAA/D,CAAiF,UAAW,CACxFxE,CAAsB,CAACI,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBkE,gBAAxB,CACzB,CAFD,EAIA7H,CAAM,CAACiC,EAAP,CAAUuC,UAAaC,MAAb,CAAoBC,QAA9B,CAAwCjB,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBmE,cAA/D,CAA+E,UAAW,CACtFzE,CAAsB,CAACI,UAAUC,OAAV,CAAkBC,IAAlB,CAAuBmE,cAAxB,CACzB,CAFD,CAGH,CA/VM,C","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 responsible for handling forum summary report filters.\n *\n * @module forumreport_summary/filters\n * @copyright 2019 Michael Hawkins \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Popper from 'core/popper';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Selectors from 'forumreport_summary/selectors';\nimport Ajax from 'core/ajax';\nimport KeyCodes from 'core/key_codes';\nimport * as FormChangeChecker from 'core_form/changechecker';\n\nexport const init = (root) => {\n let jqRoot = $(root);\n\n // Hide loading spinner and show report once page is ready.\n // This ensures filters can be applied when sorting by columns.\n $(document).ready(function() {\n $('.loading-icon').hide();\n $('#summaryreport').removeClass('hidden');\n });\n\n // Generic filter handlers.\n\n // Called to override click event to trigger a proper generate request with filtering.\n const generateWithFilters = (event, getparams) => {\n let currentLink = document.forms.filtersform.action,\n newLink;\n\n if (event) {\n event.preventDefault();\n\n let currentSplit = currentLink.split('?'),\n currentstring = currentSplit[1],\n newparamsarray = getparams.split('&'),\n paramsstring = '',\n paramkeys = [],\n paramvalues = [];\n\n // Separate out the existing action GET param string.\n currentstring.split('&').forEach(function(param) {\n let splitparam = param.split('=');\n paramkeys.push(splitparam[0]);\n paramvalues.push(splitparam[1]);\n });\n\n newparamsarray.forEach(function(paramstring) {\n let newparam = paramstring.split('='),\n existingkey = paramkeys.indexOf(newparam[0]);\n\n // Overwrite value if existing, otherwise add new param.\n if (existingkey > -1) {\n paramvalues[existingkey] = newparam[1];\n } else {\n paramkeys.push(newparam[0]);\n paramvalues.push(newparam[1]);\n }\n });\n\n // Build URL.\n paramkeys.forEach(function(name, key) {\n paramsstring += `&${name}=${paramvalues[key]}`;\n });\n\n newLink = currentSplit[0] + '?' + paramsstring.substr(1);\n } else {\n newLink = currentLink;\n }\n\n document.forms.filtersform.action = newLink;\n document.forms.filtersform.submit();\n };\n\n // Override 'reset table preferences' so it generates with filters.\n $('.resettable').on(\"click\", \"a\", function(event) {\n generateWithFilters(event, event.target.search.substr(1));\n });\n\n // Override table heading sort links so they generate with filters.\n $('thead').on(\"click\", \"a\", function(event) {\n generateWithFilters(event, event.target.search.substr(1));\n });\n\n // Override pagination page links so they generate with filters.\n $('.pagination').on(\"click\", \"a\", function(event) {\n generateWithFilters(event, event.target.search.substr(1));\n });\n\n // Override rows per page submission so it generates with filters.\n if (document.forms.selectperpage) {\n document.forms.selectperpage.onsubmit = (event) => {\n let getparam = 'perpage=' + document.forms.selectperpage.elements.perpage.value;\n generateWithFilters(event, getparam);\n };\n }\n\n // Override download link so the file is generated with filters.\n const downloadForm = document.getElementById('summaryreport').querySelector('form.dataformatselector');\n if (downloadForm) {\n downloadForm.onsubmit = (event) => {\n const downloadType = downloadForm.querySelector('#downloadtype_download').value;\n const getParams = `download=${downloadType}`;\n const prevAction = document.forms.filtersform.action;\n\n generateWithFilters(event, getParams);\n\n // Revert action, so re-submitting the form via filter does not trigger a further download.\n document.forms.filtersform.action = prevAction;\n };\n }\n\n // Submit report via filter\n const submitWithFilter = (containerelement) => {\n // Disable the dates filter mform checker to prevent any changes triggering a warning to the user.\n FormChangeChecker.unWatchForm(document.forms.filtersform);\n\n // Close the container (eg popover).\n $(containerelement).addClass('hidden');\n\n // Submit the filter values and re-generate report.\n generateWithFilters(false);\n };\n\n // Use popper to override date mform calendar position.\n const updateCalendarPosition = (referenceid) => {\n let referenceElement = document.querySelector(referenceid),\n popperContent = document.querySelector(Selectors.filters.date.calendar);\n\n popperContent.style.removeProperty(\"z-index\");\n new Popper(referenceElement, popperContent, {placement: 'bottom'});\n };\n\n // Close the relevant filter.\n const closeOpenFilters = (openFilterButton, openFilter) => {\n openFilter.classList.add('hidden');\n openFilter.setAttribute('data-openfilter', 'false');\n\n openFilterButton.classList.add('btn-primary');\n openFilterButton.classList.remove('btn-outline-primary');\n openFilterButton.setAttribute('aria-expanded', false);\n };\n\n // Groups filter specific handlers.\n\n // Event handler for clicking select all groups.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.selectall, function() {\n let deselected = root.querySelectorAll(Selectors.filters.group.checkbox + ':not(:checked)');\n deselected.forEach(function(checkbox) {\n checkbox.checked = true;\n });\n });\n\n // Event handler for clearing filter by clicking option.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.clear, function() {\n // Clear checkboxes.\n let selected = root.querySelectorAll(Selectors.filters.group.checkbox + ':checked');\n selected.forEach(function(checkbox) {\n checkbox.checked = false;\n });\n });\n\n // Event handler for showing groups filter popover.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.trigger, function() {\n // Create popover.\n let referenceElement = root.querySelector(Selectors.filters.group.trigger),\n popperContent = root.querySelector(Selectors.filters.group.popover);\n\n new Popper(referenceElement, popperContent, {placement: 'bottom'});\n\n // Show popover.\n popperContent.classList.remove('hidden');\n popperContent.setAttribute('data-openfilter', 'true');\n\n // Change to outlined button.\n referenceElement.classList.add('btn-outline-primary');\n referenceElement.classList.remove('btn-primary');\n\n // Let screen readers know that it's now expanded.\n referenceElement.setAttribute('aria-expanded', true);\n\n // Add listeners to handle closing filter.\n const closeListener = e => {\n if (e.target.id !== referenceElement.id && popperContent !== e.target.closest('[data-openfilter=\"true\"]') &&\n (typeof e.keyCode === 'undefined' || e.keyCode === KeyCodes.enter || e.keyCode === KeyCodes.space)) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('click', closeListener);\n document.removeEventListener('keyup', closeListener);\n document.removeEventListener('keyup', escCloseListener);\n }\n };\n\n document.addEventListener('click', closeListener);\n document.addEventListener('keyup', closeListener);\n\n const escCloseListener = e => {\n if (e.keyCode === KeyCodes.escape) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('keyup', escCloseListener);\n document.removeEventListener('click', closeListener);\n }\n };\n\n document.addEventListener('keyup', escCloseListener);\n });\n\n // Event handler to click save groups filter.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.save, function() {\n // Copy the saved values into the form before submitting.\n let popcheckboxes = root.querySelectorAll(Selectors.filters.group.checkbox);\n\n popcheckboxes.forEach(function(popcheckbox) {\n let filtersform = document.forms.filtersform,\n saveid = popcheckbox.getAttribute('data-saveid');\n\n filtersform.querySelector(`#${saveid}`).checked = popcheckbox.checked;\n });\n\n submitWithFilter('#filter-groups-popover');\n });\n\n // Listeners for export buttons.\n // These allow fetching of the relevant export URL, before submitting the request with\n // any POST data that is common to all of the export links. This allows filters to be\n // applied that contain potentially a lot of data (eg discussion IDs for groups filtering).\n document.querySelectorAll(Selectors.filters.exportlink.link).forEach(function(exportbutton) {\n exportbutton.addEventListener('click', function(event) {\n document.forms.exportlinkform.action = event.target.dataset.url;\n document.forms.exportlinkform.submit();\n });\n });\n\n // Dates filter specific handlers.\n\n // Event handler for showing dates filter popover.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.trigger, function() {\n\n // Create popover.\n let referenceElement = root.querySelector(Selectors.filters.date.trigger),\n popperContent = root.querySelector(Selectors.filters.date.popover);\n\n new Popper(referenceElement, popperContent, {placement: 'bottom'});\n\n // Show popover and move focus.\n popperContent.classList.remove('hidden');\n popperContent.setAttribute('data-openfilter', 'true');\n popperContent.querySelector('[name=\"filterdatefrompopover[enabled]\"]').focus();\n\n // Change to outlined button.\n referenceElement.classList.add('btn-outline-primary');\n referenceElement.classList.remove('btn-primary');\n\n // Let screen readers know that it's now expanded.\n referenceElement.setAttribute('aria-expanded', true);\n\n // Add listener to handle closing filter.\n const closeListener = e => {\n if (e.target.id !== referenceElement.id && popperContent !== e.target.closest('[data-openfilter=\"true\"]') &&\n (typeof e.keyCode === 'undefined' || e.keyCode === KeyCodes.enter || e.keyCode === KeyCodes.space)) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('click', closeListener);\n document.removeEventListener('keyup', closeListener);\n document.removeEventListener('keyup', escCloseListener);\n }\n };\n\n document.addEventListener('click', closeListener);\n document.addEventListener('keyup', closeListener);\n\n const escCloseListener = e => {\n if (e.keyCode === KeyCodes.escape) {\n closeOpenFilters(referenceElement, popperContent);\n document.removeEventListener('keyup', escCloseListener);\n document.removeEventListener('click', closeListener);\n }\n };\n\n document.addEventListener('keyup', escCloseListener);\n });\n\n // Event handler to save dates filter.\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.save, function() {\n // Populate the hidden form inputs to submit the data.\n let filtersForm = document.forms.filtersform;\n const datesPopover = root.querySelector(Selectors.filters.date.popover);\n const fromEnabled = datesPopover.querySelector('[name=\"filterdatefrompopover[enabled]\"]').checked ? 1 : 0;\n const toEnabled = datesPopover.querySelector('[name=\"filterdatetopopover[enabled]\"]').checked ? 1 : 0;\n\n if (!fromEnabled && !toEnabled) {\n // Update the elements in the filter form.\n filtersForm.elements['datefrom[timestamp]'].value = 0;\n filtersForm.elements['datefrom[enabled]'].value = fromEnabled;\n filtersForm.elements['dateto[timestamp]'].value = 0;\n filtersForm.elements['dateto[enabled]'].value = toEnabled;\n\n // Submit the filter values and re-generate report.\n submitWithFilter('#filter-dates-popover');\n } else {\n let args = {data: []};\n\n if (fromEnabled) {\n args.data.push({\n 'key': 'from',\n 'year': datesPopover.querySelector('[name=\"filterdatefrompopover[year]\"]').value,\n 'month': datesPopover.querySelector('[name=\"filterdatefrompopover[month]\"]').value,\n 'day': datesPopover.querySelector('[name=\"filterdatefrompopover[day]\"]').value,\n 'hour': 0,\n 'minute': 0\n });\n }\n\n if (toEnabled) {\n args.data.push({\n 'key': 'to',\n 'year': datesPopover.querySelector('[name=\"filterdatetopopover[year]\"]').value,\n 'month': datesPopover.querySelector('[name=\"filterdatetopopover[month]\"]').value,\n 'day': datesPopover.querySelector('[name=\"filterdatetopopover[day]\"]').value,\n 'hour': 23,\n 'minute': 59\n });\n }\n\n const request = {\n methodname: 'core_calendar_get_timestamps',\n args: args\n };\n\n Ajax.call([request])[0].done(function(result) {\n let fromTimestamp = 0,\n toTimestamp = 0;\n\n result.timestamps.forEach(function(data) {\n if (data.key === 'from') {\n fromTimestamp = data.timestamp;\n } else if (data.key === 'to') {\n toTimestamp = data.timestamp;\n }\n });\n\n // Display an error if the from date is later than the do date.\n if (toTimestamp > 0 && fromTimestamp > toTimestamp) {\n const warningdiv = document.getElementById('dates-filter-warning');\n warningdiv.classList.remove('hidden');\n warningdiv.classList.add('d-block');\n } else {\n filtersForm.elements['datefrom[timestamp]'].value = fromTimestamp;\n filtersForm.elements['datefrom[enabled]'].value = fromEnabled;\n filtersForm.elements['dateto[timestamp]'].value = toTimestamp;\n filtersForm.elements['dateto[enabled]'].value = toEnabled;\n\n // Submit the filter values and re-generate report.\n submitWithFilter('#filter-dates-popover');\n }\n });\n }\n });\n\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.calendariconfrom, function() {\n updateCalendarPosition(Selectors.filters.date.calendariconfrom);\n });\n\n jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.calendariconto, function() {\n updateCalendarPosition(Selectors.filters.date.calendariconto);\n });\n};\n"],"file":"filters.min.js"}
\ No newline at end of file
diff --git a/mod/forum/report/summary/amd/src/filters.js b/mod/forum/report/summary/amd/src/filters.js
index a06b91282e4..e187babd898 100644
--- a/mod/forum/report/summary/amd/src/filters.js
+++ b/mod/forum/report/summary/amd/src/filters.js
@@ -25,9 +25,9 @@ import $ from 'jquery';
import Popper from 'core/popper';
import CustomEvents from 'core/custom_interaction_events';
import Selectors from 'forumreport_summary/selectors';
-import Y from 'core/yui';
import Ajax from 'core/ajax';
import KeyCodes from 'core/key_codes';
+import * as FormChangeChecker from 'core_form/changechecker';
export const init = (root) => {
let jqRoot = $(root);
@@ -131,9 +131,7 @@ export const init = (root) => {
// Submit report via filter
const submitWithFilter = (containerelement) => {
// Disable the dates filter mform checker to prevent any changes triggering a warning to the user.
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ FormChangeChecker.unWatchForm(document.forms.filtersform);
// Close the container (eg popover).
$(containerelement).addClass('hidden');
@@ -349,7 +347,7 @@ export const init = (root) => {
let fromTimestamp = 0,
toTimestamp = 0;
- result['timestamps'].forEach(function(data){
+ result.timestamps.forEach(function(data) {
if (data.key === 'from') {
fromTimestamp = data.timestamp;
} else if (data.key === 'to') {
diff --git a/mod/quiz/amd/build/modal_add_random_question.min.js b/mod/quiz/amd/build/modal_add_random_question.min.js
index 686fee3869f..c31254378a5 100644
--- a/mod/quiz/amd/build/modal_add_random_question.min.js
+++ b/mod/quiz/amd/build/modal_add_random_question.min.js
@@ -1,2 +1,2 @@
-define ("mod_quiz/modal_add_random_question",["jquery","core/yui","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment","core/templates"],function(a,b,c,d,e,f,g,h){var i=!1,j={EXISTING_CATEGORY_CONTAINER:"[data-region=\"existing-category-container\"]",EXISTING_CATEGORY_FORM_ELEMENT:"#id_existingcategoryheader",NEW_CATEGORY_CONTAINER:"[data-region=\"new-category-container\"]",NEW_CATEGORY_FORM_ELEMENT:"#id_newcategoryheader",TAB_CONTENT:"[data-region=\"tab-content\"]",ADD_ON_PAGE_FORM_ELEMENT:"[name=\"addonpage\"]",SUBMIT_BUTTON_ELEMENT:"input[type=\"submit\"]",CANCEL_BUTTON_ELEMENT:"input[type=\"submit\"][name=\"cancel\"]",FORM_HEADER:"legend",BUTTON_CONTAINER:".fitem"},k=function(a){d.call(this,a);this.contextId=null;this.addOnPageId=null;this.category=null;this.returnUrl=null;this.cmid=null;this.loadedForm=!1};k.TYPE="mod_quiz-quiz-add-random-question";k.prototype=Object.create(d.prototype);k.prototype.constructor=k;k.prototype.setContextId=function(a){this.contextId=a};k.prototype.getContextId=function(){return this.contextId};k.prototype.setAddOnPageId=function(a){this.addOnPageId=a;this.getBody().find(j.ADD_ON_PAGE_FORM_ELEMENT).val(a)};k.prototype.getAddOnPageId=function(){return this.addOnPageId};k.prototype.setCategory=function(a){this.category=a};k.prototype.getCategory=function(){return this.category};k.prototype.setReturnUrl=function(a){this.returnUrl=a};k.prototype.getReturnUrl=function(){return this.returnUrl};k.prototype.setCMID=function(a){this.cmid=a};k.prototype.getCMID=function(){return this.cmid};k.prototype.moveFormElementIntoTab=function(b,c){var d=b.find(j.SUBMIT_BUTTON_ELEMENT),e=a("");b.find(j.FORM_HEADER).addClass("hidden");b.wrap(c);d.closest(j.BUTTON_CONTAINER).remove();d.appendTo(e);e.appendTo(b)};k.prototype.moveTabsIntoTabContent=function(a){var b=this.getBody().find(j.TAB_CONTENT).empty();a.find("[role=\"tabpanel\"]").wrapAll(b)};k.prototype.moveCancelButtonToTabs=function(a){var b=a.find(j.CANCEL_BUTTON_ELEMENT).addClass("ml-1"),c=a.find("[data-region=\"footer\"]");b.closest(j.BUTTON_CONTAINER).remove();b.clone().appendTo(c)};k.prototype.loadForm=function(){return g.loadFragment("mod_quiz","add_random_question_form",this.getContextId(),{addonpage:this.getAddOnPageId(),cat:this.getCategory(),returnurl:this.getReturnUrl(),cmid:this.getCMID()}).then(function(b,c){var d=a(b),e=d.find(j.EXISTING_CATEGORY_FORM_ELEMENT),f=this.getBody().find(j.EXISTING_CATEGORY_CONTAINER),g=d.find(j.NEW_CATEGORY_FORM_ELEMENT),i=this.getBody().find(j.NEW_CATEGORY_CONTAINER);this.moveFormElementIntoTab(e,f);this.moveFormElementIntoTab(g,i);this.moveTabsIntoTabContent(d);this.moveCancelButtonToTabs(d);h.replaceNode(this.getBody().find(j.TAB_CONTENT),d,c)}.bind(this)).then(function(){b.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()})}).fail(c.exception)};k.prototype.show=function(){d.prototype.show.call(this);if(!this.loadedForm){this.loadForm();this.loadedForm=!0}};if(!i){f.register(k.TYPE,k,"mod_quiz/modal_add_random_question");i=!0}return k});
+define ("mod_quiz/modal_add_random_question",["jquery","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment","core/templates","core_form/changechecker"],function(a,b,c,d,e,f,g,h){var i=!1,j={EXISTING_CATEGORY_CONTAINER:"[data-region=\"existing-category-container\"]",EXISTING_CATEGORY_FORM_ELEMENT:"#id_existingcategoryheader",NEW_CATEGORY_CONTAINER:"[data-region=\"new-category-container\"]",NEW_CATEGORY_FORM_ELEMENT:"#id_newcategoryheader",TAB_CONTENT:"[data-region=\"tab-content\"]",ADD_ON_PAGE_FORM_ELEMENT:"[name=\"addonpage\"]",SUBMIT_BUTTON_ELEMENT:"input[type=\"submit\"]",CANCEL_BUTTON_ELEMENT:"input[type=\"submit\"][name=\"cancel\"]",FORM_HEADER:"legend",BUTTON_CONTAINER:".fitem"},k=function(a){c.call(this,a);this.contextId=null;this.addOnPageId=null;this.category=null;this.returnUrl=null;this.cmid=null;this.loadedForm=!1};k.TYPE="mod_quiz-quiz-add-random-question";k.prototype=Object.create(c.prototype);k.prototype.constructor=k;k.prototype.setContextId=function(a){this.contextId=a};k.prototype.getContextId=function(){return this.contextId};k.prototype.setAddOnPageId=function(a){this.addOnPageId=a;this.getBody().find(j.ADD_ON_PAGE_FORM_ELEMENT).val(a)};k.prototype.getAddOnPageId=function(){return this.addOnPageId};k.prototype.setCategory=function(a){this.category=a};k.prototype.getCategory=function(){return this.category};k.prototype.setReturnUrl=function(a){this.returnUrl=a};k.prototype.getReturnUrl=function(){return this.returnUrl};k.prototype.setCMID=function(a){this.cmid=a};k.prototype.getCMID=function(){return this.cmid};k.prototype.moveFormElementIntoTab=function(b,c){var d=b.find(j.SUBMIT_BUTTON_ELEMENT),e=a("");b.find(j.FORM_HEADER).addClass("hidden");b.wrap(c);d.closest(j.BUTTON_CONTAINER).remove();d.appendTo(e);e.appendTo(b)};k.prototype.moveTabsIntoTabContent=function(a){var b=this.getBody().find(j.TAB_CONTENT).empty();a.find("[role=\"tabpanel\"]").wrapAll(b)};k.prototype.moveCancelButtonToTabs=function(a){var b=a.find(j.CANCEL_BUTTON_ELEMENT).addClass("ml-1"),c=a.find("[data-region=\"footer\"]");b.closest(j.BUTTON_CONTAINER).remove();b.clone().appendTo(c)};k.prototype.loadForm=function(){return f.loadFragment("mod_quiz","add_random_question_form",this.getContextId(),{addonpage:this.getAddOnPageId(),cat:this.getCategory(),returnurl:this.getReturnUrl(),cmid:this.getCMID()}).then(function(b,c){var d=a(b),e=d.find(j.EXISTING_CATEGORY_FORM_ELEMENT),f=this.getBody().find(j.EXISTING_CATEGORY_CONTAINER),h=d.find(j.NEW_CATEGORY_FORM_ELEMENT),i=this.getBody().find(j.NEW_CATEGORY_CONTAINER);this.moveFormElementIntoTab(e,f);this.moveFormElementIntoTab(h,i);this.moveTabsIntoTabContent(d);this.moveCancelButtonToTabs(d);g.replaceNode(this.getBody().find(j.TAB_CONTENT),d,c)}.bind(this)).then(function(){h.disableAllChecks()}).fail(b.exception)};k.prototype.show=function(){c.prototype.show.call(this);if(!this.loadedForm){this.loadForm();this.loadedForm=!0}};if(!i){e.register(k.TYPE,k,"mod_quiz/modal_add_random_question");i=!0}return k});
//# sourceMappingURL=modal_add_random_question.min.js.map
diff --git a/mod/quiz/amd/build/modal_add_random_question.min.js.map b/mod/quiz/amd/build/modal_add_random_question.min.js.map
index 138e4f9c59a..1163f91119d 100644
--- a/mod/quiz/amd/build/modal_add_random_question.min.js.map
+++ b/mod/quiz/amd/build/modal_add_random_question.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/modal_add_random_question.js"],"names":["define","$","Y","Notification","Modal","ModalEvents","ModalRegistry","Fragment","Templates","registered","SELECTORS","EXISTING_CATEGORY_CONTAINER","EXISTING_CATEGORY_FORM_ELEMENT","NEW_CATEGORY_CONTAINER","NEW_CATEGORY_FORM_ELEMENT","TAB_CONTENT","ADD_ON_PAGE_FORM_ELEMENT","SUBMIT_BUTTON_ELEMENT","CANCEL_BUTTON_ELEMENT","FORM_HEADER","BUTTON_CONTAINER","ModalAddRandomQuestion","root","call","contextId","addOnPageId","category","returnUrl","cmid","loadedForm","TYPE","prototype","Object","create","constructor","setContextId","id","getContextId","setAddOnPageId","getBody","find","val","getAddOnPageId","setCategory","getCategory","setReturnUrl","url","getReturnUrl","setCMID","getCMID","moveFormElementIntoTab","formElement","tabElement","submitButtons","footer","addClass","wrap","closest","remove","appendTo","moveTabsIntoTabContent","form","tabContent","empty","wrapAll","moveCancelButtonToTabs","cancelButton","tabFooters","clone","loadForm","loadFragment","addonpage","cat","returnurl","then","html","js","existingCategoryFormElement","existingCategoryTab","newCategoryFormElement","newCategoryTab","replaceNode","bind","use","M","core_formchangechecker","reset_form_dirty_state","fail","exception","show","register"],"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 * Contain the logic for the add random question modal.\n *\n * @module mod_quiz/modal_add_random_question\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/yui',\n 'core/notification',\n 'core/modal',\n 'core/modal_events',\n 'core/modal_registry',\n 'core/fragment',\n 'core/templates',\n],\nfunction(\n $,\n Y,\n Notification,\n Modal,\n ModalEvents,\n ModalRegistry,\n Fragment,\n Templates\n) {\n\n var registered = false;\n var SELECTORS = {\n EXISTING_CATEGORY_CONTAINER: '[data-region=\"existing-category-container\"]',\n EXISTING_CATEGORY_FORM_ELEMENT: '#id_existingcategoryheader',\n NEW_CATEGORY_CONTAINER: '[data-region=\"new-category-container\"]',\n NEW_CATEGORY_FORM_ELEMENT: '#id_newcategoryheader',\n TAB_CONTENT: '[data-region=\"tab-content\"]',\n ADD_ON_PAGE_FORM_ELEMENT: '[name=\"addonpage\"]',\n SUBMIT_BUTTON_ELEMENT: 'input[type=\"submit\"]',\n CANCEL_BUTTON_ELEMENT: 'input[type=\"submit\"][name=\"cancel\"]',\n FORM_HEADER: 'legend',\n BUTTON_CONTAINER: '.fitem'\n };\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var ModalAddRandomQuestion = function(root) {\n Modal.call(this, root);\n this.contextId = null;\n this.addOnPageId = null;\n this.category = null;\n this.returnUrl = null;\n this.cmid = null;\n this.loadedForm = false;\n };\n\n ModalAddRandomQuestion.TYPE = 'mod_quiz-quiz-add-random-question';\n ModalAddRandomQuestion.prototype = Object.create(Modal.prototype);\n ModalAddRandomQuestion.prototype.constructor = ModalAddRandomQuestion;\n\n /**\n * Save the Moodle context id that the question bank is being\n * rendered in.\n *\n * @method setContextId\n * @param {int} id\n */\n ModalAddRandomQuestion.prototype.setContextId = function(id) {\n this.contextId = id;\n };\n\n /**\n * Retrieve the saved Moodle context id.\n *\n * @method getContextId\n * @return {int}\n */\n ModalAddRandomQuestion.prototype.getContextId = function() {\n return this.contextId;\n };\n\n /**\n * Set the id of the page that the question should be added to\n * when the user clicks the add to quiz link.\n *\n * @method setAddOnPageId\n * @param {int} id\n */\n ModalAddRandomQuestion.prototype.setAddOnPageId = function(id) {\n this.addOnPageId = id;\n this.getBody().find(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).val(id);\n };\n\n /**\n * Returns the saved page id for the question to be added to.\n *\n * @method getAddOnPageId\n * @return {int}\n */\n ModalAddRandomQuestion.prototype.getAddOnPageId = function() {\n return this.addOnPageId;\n };\n\n /**\n * Set the category for this form. The category is a comma separated\n * category id and category context id.\n *\n * @method setCategory\n * @param {string} category\n */\n ModalAddRandomQuestion.prototype.setCategory = function(category) {\n this.category = category;\n };\n\n /**\n * Returns the saved category.\n *\n * @method getCategory\n * @return {string}\n */\n ModalAddRandomQuestion.prototype.getCategory = function() {\n return this.category;\n };\n\n /**\n * Set the return URL for the form.\n *\n * @method setReturnUrl\n * @param {string} url\n */\n ModalAddRandomQuestion.prototype.setReturnUrl = function(url) {\n this.returnUrl = url;\n };\n\n /**\n * Returns the return URL for the form.\n *\n * @method getReturnUrl\n * @return {string}\n */\n ModalAddRandomQuestion.prototype.getReturnUrl = function() {\n return this.returnUrl;\n };\n\n /**\n * Set the course module id for the form.\n *\n * @method setCMID\n * @param {int} id\n */\n ModalAddRandomQuestion.prototype.setCMID = function(id) {\n this.cmid = id;\n };\n\n /**\n * Returns the course module id for the form.\n *\n * @method getCMID\n * @return {int}\n */\n ModalAddRandomQuestion.prototype.getCMID = function() {\n return this.cmid;\n };\n\n /**\n * Moves a given form element inside (a child of) a given tab element.\n *\n * Hides the 'legend' (e.g. header) element of the form element because the\n * tab has the name.\n *\n * Moves the submit button into a footer element at the bottom of the form\n * element for styling purposes.\n *\n * @method moveFormElementIntoTab\n * @param {jquery} formElement The form element to move into the tab.\n * @param {jquey} tabElement The tab element for the form element to move into.\n */\n ModalAddRandomQuestion.prototype.moveFormElementIntoTab = function(formElement, tabElement) {\n var submitButtons = formElement.find(SELECTORS.SUBMIT_BUTTON_ELEMENT);\n var footer = $('');\n // Hide the header because the tabs show us which part of the form we're\n // looking at.\n formElement.find(SELECTORS.FORM_HEADER).addClass('hidden');\n // Move the element inside a tab.\n formElement.wrap(tabElement);\n // Remove the buttons container element.\n submitButtons.closest(SELECTORS.BUTTON_CONTAINER).remove();\n // Put the button inside a footer.\n submitButtons.appendTo(footer);\n // Add the footer to the end of the category form element.\n footer.appendTo(formElement);\n };\n\n /**\n * Empty the tab content container and move all tabs from the form into the\n * tab container element.\n *\n * @method moveTabsIntoTabContent\n * @param {jquery} form The form element.\n */\n ModalAddRandomQuestion.prototype.moveTabsIntoTabContent = function(form) {\n // Empty it to remove the loading icon.\n var tabContent = this.getBody().find(SELECTORS.TAB_CONTENT).empty();\n // Make sure all tabs are inside the tab content element.\n form.find('[role=\"tabpanel\"]').wrapAll(tabContent);\n };\n\n /**\n * Make sure all of the tabs have a cancel button in their fotter to sit along\n * side the submit button.\n *\n * @method moveCancelButtonToTabs\n * @param {jquey} form The form element.\n */\n ModalAddRandomQuestion.prototype.moveCancelButtonToTabs = function(form) {\n var cancelButton = form.find(SELECTORS.CANCEL_BUTTON_ELEMENT).addClass('ml-1');\n var tabFooters = form.find('[data-region=\"footer\"]');\n // Remove the buttons container element.\n cancelButton.closest(SELECTORS.BUTTON_CONTAINER).remove();\n cancelButton.clone().appendTo(tabFooters);\n };\n\n /**\n * Load the add random question form in a fragement and perform some transformation\n * on the HTML to convert it into tabs for rendering in the modal.\n *\n * @method loadForm\n * @return {promise} Resolved with form HTML and JS.\n */\n ModalAddRandomQuestion.prototype.loadForm = function() {\n return Fragment.loadFragment(\n 'mod_quiz',\n 'add_random_question_form',\n this.getContextId(),\n {\n addonpage: this.getAddOnPageId(),\n cat: this.getCategory(),\n returnurl: this.getReturnUrl(),\n cmid: this.getCMID()\n }\n )\n .then(function(html, js) {\n var form = $(html);\n var existingCategoryFormElement = form.find(SELECTORS.EXISTING_CATEGORY_FORM_ELEMENT);\n var existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER);\n var newCategoryFormElement = form.find(SELECTORS.NEW_CATEGORY_FORM_ELEMENT);\n var newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);\n\n // Transform the form into tabs for better rendering in the modal.\n this.moveFormElementIntoTab(existingCategoryFormElement, existingCategoryTab);\n this.moveFormElementIntoTab(newCategoryFormElement, newCategoryTab);\n this.moveTabsIntoTabContent(form);\n this.moveCancelButtonToTabs(form);\n\n Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js);\n return;\n }.bind(this))\n .then(function() {\n // Make sure the form change checker is disabled otherwise it'll\n // stop the user from navigating away from the page once the modal\n // is hidden.\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n return;\n })\n .fail(Notification.exception);\n };\n\n /**\n * Override the modal show function to load the form when this modal is first\n * shown.\n *\n * @method show\n */\n ModalAddRandomQuestion.prototype.show = function() {\n Modal.prototype.show.call(this);\n\n if (!this.loadedForm) {\n this.loadForm();\n this.loadedForm = true;\n }\n };\n\n // Automatically register with the modal registry the first time this module is\n // imported so that you can create modals of this type using the modal factory.\n if (!registered) {\n ModalRegistry.register(\n ModalAddRandomQuestion.TYPE,\n ModalAddRandomQuestion,\n 'mod_quiz/modal_add_random_question'\n );\n\n registered = true;\n }\n\n return ModalAddRandomQuestion;\n});\n"],"file":"modal_add_random_question.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/modal_add_random_question.js"],"names":["define","$","Notification","Modal","ModalEvents","ModalRegistry","Fragment","Templates","FormChangeChecker","registered","SELECTORS","EXISTING_CATEGORY_CONTAINER","EXISTING_CATEGORY_FORM_ELEMENT","NEW_CATEGORY_CONTAINER","NEW_CATEGORY_FORM_ELEMENT","TAB_CONTENT","ADD_ON_PAGE_FORM_ELEMENT","SUBMIT_BUTTON_ELEMENT","CANCEL_BUTTON_ELEMENT","FORM_HEADER","BUTTON_CONTAINER","ModalAddRandomQuestion","root","call","contextId","addOnPageId","category","returnUrl","cmid","loadedForm","TYPE","prototype","Object","create","constructor","setContextId","id","getContextId","setAddOnPageId","getBody","find","val","getAddOnPageId","setCategory","getCategory","setReturnUrl","url","getReturnUrl","setCMID","getCMID","moveFormElementIntoTab","formElement","tabElement","submitButtons","footer","addClass","wrap","closest","remove","appendTo","moveTabsIntoTabContent","form","tabContent","empty","wrapAll","moveCancelButtonToTabs","cancelButton","tabFooters","clone","loadForm","loadFragment","addonpage","cat","returnurl","then","html","js","existingCategoryFormElement","existingCategoryTab","newCategoryFormElement","newCategoryTab","replaceNode","bind","disableAllChecks","fail","exception","show","register"],"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 * Contain the logic for the add random question modal.\n *\n * @module mod_quiz/modal_add_random_question\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/notification',\n 'core/modal',\n 'core/modal_events',\n 'core/modal_registry',\n 'core/fragment',\n 'core/templates',\n 'core_form/changechecker',\n],\nfunction(\n $,\n Notification,\n Modal,\n ModalEvents,\n ModalRegistry,\n Fragment,\n Templates,\n FormChangeChecker,\n) {\n\n var registered = false;\n var SELECTORS = {\n EXISTING_CATEGORY_CONTAINER: '[data-region=\"existing-category-container\"]',\n EXISTING_CATEGORY_FORM_ELEMENT: '#id_existingcategoryheader',\n NEW_CATEGORY_CONTAINER: '[data-region=\"new-category-container\"]',\n NEW_CATEGORY_FORM_ELEMENT: '#id_newcategoryheader',\n TAB_CONTENT: '[data-region=\"tab-content\"]',\n ADD_ON_PAGE_FORM_ELEMENT: '[name=\"addonpage\"]',\n SUBMIT_BUTTON_ELEMENT: 'input[type=\"submit\"]',\n CANCEL_BUTTON_ELEMENT: 'input[type=\"submit\"][name=\"cancel\"]',\n FORM_HEADER: 'legend',\n BUTTON_CONTAINER: '.fitem'\n };\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var ModalAddRandomQuestion = function(root) {\n Modal.call(this, root);\n this.contextId = null;\n this.addOnPageId = null;\n this.category = null;\n this.returnUrl = null;\n this.cmid = null;\n this.loadedForm = false;\n };\n\n ModalAddRandomQuestion.TYPE = 'mod_quiz-quiz-add-random-question';\n ModalAddRandomQuestion.prototype = Object.create(Modal.prototype);\n ModalAddRandomQuestion.prototype.constructor = ModalAddRandomQuestion;\n\n /**\n * Save the Moodle context id that the question bank is being\n * rendered in.\n *\n * @method setContextId\n * @param {int} id\n */\n ModalAddRandomQuestion.prototype.setContextId = function(id) {\n this.contextId = id;\n };\n\n /**\n * Retrieve the saved Moodle context id.\n *\n * @method getContextId\n * @return {int}\n */\n ModalAddRandomQuestion.prototype.getContextId = function() {\n return this.contextId;\n };\n\n /**\n * Set the id of the page that the question should be added to\n * when the user clicks the add to quiz link.\n *\n * @method setAddOnPageId\n * @param {int} id\n */\n ModalAddRandomQuestion.prototype.setAddOnPageId = function(id) {\n this.addOnPageId = id;\n this.getBody().find(SELECTORS.ADD_ON_PAGE_FORM_ELEMENT).val(id);\n };\n\n /**\n * Returns the saved page id for the question to be added to.\n *\n * @method getAddOnPageId\n * @return {int}\n */\n ModalAddRandomQuestion.prototype.getAddOnPageId = function() {\n return this.addOnPageId;\n };\n\n /**\n * Set the category for this form. The category is a comma separated\n * category id and category context id.\n *\n * @method setCategory\n * @param {string} category\n */\n ModalAddRandomQuestion.prototype.setCategory = function(category) {\n this.category = category;\n };\n\n /**\n * Returns the saved category.\n *\n * @method getCategory\n * @return {string}\n */\n ModalAddRandomQuestion.prototype.getCategory = function() {\n return this.category;\n };\n\n /**\n * Set the return URL for the form.\n *\n * @method setReturnUrl\n * @param {string} url\n */\n ModalAddRandomQuestion.prototype.setReturnUrl = function(url) {\n this.returnUrl = url;\n };\n\n /**\n * Returns the return URL for the form.\n *\n * @method getReturnUrl\n * @return {string}\n */\n ModalAddRandomQuestion.prototype.getReturnUrl = function() {\n return this.returnUrl;\n };\n\n /**\n * Set the course module id for the form.\n *\n * @method setCMID\n * @param {int} id\n */\n ModalAddRandomQuestion.prototype.setCMID = function(id) {\n this.cmid = id;\n };\n\n /**\n * Returns the course module id for the form.\n *\n * @method getCMID\n * @return {int}\n */\n ModalAddRandomQuestion.prototype.getCMID = function() {\n return this.cmid;\n };\n\n /**\n * Moves a given form element inside (a child of) a given tab element.\n *\n * Hides the 'legend' (e.g. header) element of the form element because the\n * tab has the name.\n *\n * Moves the submit button into a footer element at the bottom of the form\n * element for styling purposes.\n *\n * @method moveFormElementIntoTab\n * @param {jquery} formElement The form element to move into the tab.\n * @param {jquey} tabElement The tab element for the form element to move into.\n */\n ModalAddRandomQuestion.prototype.moveFormElementIntoTab = function(formElement, tabElement) {\n var submitButtons = formElement.find(SELECTORS.SUBMIT_BUTTON_ELEMENT);\n var footer = $('');\n // Hide the header because the tabs show us which part of the form we're\n // looking at.\n formElement.find(SELECTORS.FORM_HEADER).addClass('hidden');\n // Move the element inside a tab.\n formElement.wrap(tabElement);\n // Remove the buttons container element.\n submitButtons.closest(SELECTORS.BUTTON_CONTAINER).remove();\n // Put the button inside a footer.\n submitButtons.appendTo(footer);\n // Add the footer to the end of the category form element.\n footer.appendTo(formElement);\n };\n\n /**\n * Empty the tab content container and move all tabs from the form into the\n * tab container element.\n *\n * @method moveTabsIntoTabContent\n * @param {jquery} form The form element.\n */\n ModalAddRandomQuestion.prototype.moveTabsIntoTabContent = function(form) {\n // Empty it to remove the loading icon.\n var tabContent = this.getBody().find(SELECTORS.TAB_CONTENT).empty();\n // Make sure all tabs are inside the tab content element.\n form.find('[role=\"tabpanel\"]').wrapAll(tabContent);\n };\n\n /**\n * Make sure all of the tabs have a cancel button in their fotter to sit along\n * side the submit button.\n *\n * @method moveCancelButtonToTabs\n * @param {jquey} form The form element.\n */\n ModalAddRandomQuestion.prototype.moveCancelButtonToTabs = function(form) {\n var cancelButton = form.find(SELECTORS.CANCEL_BUTTON_ELEMENT).addClass('ml-1');\n var tabFooters = form.find('[data-region=\"footer\"]');\n // Remove the buttons container element.\n cancelButton.closest(SELECTORS.BUTTON_CONTAINER).remove();\n cancelButton.clone().appendTo(tabFooters);\n };\n\n /**\n * Load the add random question form in a fragement and perform some transformation\n * on the HTML to convert it into tabs for rendering in the modal.\n *\n * @method loadForm\n * @return {promise} Resolved with form HTML and JS.\n */\n ModalAddRandomQuestion.prototype.loadForm = function() {\n return Fragment.loadFragment(\n 'mod_quiz',\n 'add_random_question_form',\n this.getContextId(),\n {\n addonpage: this.getAddOnPageId(),\n cat: this.getCategory(),\n returnurl: this.getReturnUrl(),\n cmid: this.getCMID()\n }\n )\n .then(function(html, js) {\n var form = $(html);\n var existingCategoryFormElement = form.find(SELECTORS.EXISTING_CATEGORY_FORM_ELEMENT);\n var existingCategoryTab = this.getBody().find(SELECTORS.EXISTING_CATEGORY_CONTAINER);\n var newCategoryFormElement = form.find(SELECTORS.NEW_CATEGORY_FORM_ELEMENT);\n var newCategoryTab = this.getBody().find(SELECTORS.NEW_CATEGORY_CONTAINER);\n\n // Transform the form into tabs for better rendering in the modal.\n this.moveFormElementIntoTab(existingCategoryFormElement, existingCategoryTab);\n this.moveFormElementIntoTab(newCategoryFormElement, newCategoryTab);\n this.moveTabsIntoTabContent(form);\n this.moveCancelButtonToTabs(form);\n\n Templates.replaceNode(this.getBody().find(SELECTORS.TAB_CONTENT), form, js);\n return;\n }.bind(this))\n .then(function() {\n // Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the\n // page once the modal is hidden.\n FormChangeChecker.disableAllChecks();\n return;\n })\n .fail(Notification.exception);\n };\n\n /**\n * Override the modal show function to load the form when this modal is first\n * shown.\n *\n * @method show\n */\n ModalAddRandomQuestion.prototype.show = function() {\n Modal.prototype.show.call(this);\n\n if (!this.loadedForm) {\n this.loadForm();\n this.loadedForm = true;\n }\n };\n\n // Automatically register with the modal registry the first time this module is\n // imported so that you can create modals of this type using the modal factory.\n if (!registered) {\n ModalRegistry.register(\n ModalAddRandomQuestion.TYPE,\n ModalAddRandomQuestion,\n 'mod_quiz/modal_add_random_question'\n );\n\n registered = true;\n }\n\n return ModalAddRandomQuestion;\n});\n"],"file":"modal_add_random_question.min.js"}
\ No newline at end of file
diff --git a/mod/quiz/amd/build/modal_quiz_question_bank.min.js b/mod/quiz/amd/build/modal_quiz_question_bank.min.js
index 4392f7f1d63..2a785a8aca7 100644
--- a/mod/quiz/amd/build/modal_quiz_question_bank.min.js
+++ b/mod/quiz/amd/build/modal_quiz_question_bank.min.js
@@ -1,2 +1,2 @@
-define ("mod_quiz/modal_quiz_question_bank",["jquery","core/yui","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment"],function(a,b,c,d,e,f,g){var h=!1,i={ADD_TO_QUIZ_CONTAINER:"td.addtoquizaction",ANCHOR:"a[href]",PREVIEW_CONTAINER:"td.previewaction",SEARCH_OPTIONS:"#advancedsearch",DISPLAY_OPTIONS:"#displayoptions",ADD_QUESTIONS_FORM:"form[action=\"edit.php\"]"},j=function(a){d.call(this,a);this.contextId=null;this.addOnPageId=null};j.TYPE="mod_quiz-quiz-question-bank";j.prototype=Object.create(d.prototype);j.prototype.constructor=j;j.prototype.setContextId=function(a){this.contextId=a};j.prototype.getContextId=function(){return this.contextId};j.prototype.setAddOnPageId=function(a){this.addOnPageId=a};j.prototype.getAddOnPageId=function(){return this.addOnPageId};j.prototype.show=function(){this.reloadBodyContent(window.location.search);return d.prototype.show.call(this)};j.prototype.reloadBodyContent=function(a){var b=g.loadFragment("mod_quiz","quiz_question_bank",this.getContextId(),{querystring:a}).fail(c.exception);this.setBody(b)};j.prototype.handleAddToQuizEvent=function(a,b){var c=b.attr("href")+"&addonpage="+this.getAddOnPageId();b.attr("href",c)};j.prototype.handlePreviewContainerEvent=function(a,b){window.openpopup(a,{url:b.attr("href"),name:"questionpreview",options:["height=600","width=800","top=0","left=0","menubar=0","location=0","scrollbars","resizable","toolbar","status","directories=0","fullscreen=0","dependent"].join(",")})};j.prototype.handleDisplayOptionFormEvent=function(b){b.stopPropagation();b.preventDefault();var c=a(b.target).closest(i.DISPLAY_OPTIONS),d="?"+c.serialize();this.reloadBodyContent(d)};j.prototype.registerDisplayOptionListeners=function(){this.getModal().on("change",i.DISPLAY_OPTIONS,function(b){var c=a(b.target);if(c.attr("aria-autocomplete")){return}this.handleDisplayOptionFormEvent(b)}.bind(this));this.getModal().on("submit",i.DISPLAY_OPTIONS,function(a){this.handleDisplayOptionFormEvent(a)}.bind(this))};j.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this);this.registerDisplayOptionListeners();this.getModal().on("submit",i.ADD_QUESTIONS_FORM,function(b){var c=a(b.currentTarget);a(" ").attr("type","hidden").attr("name","addonpage").attr("value",this.getAddOnPageId()).appendTo(c)}.bind(this));this.getModal().on("click",i.ANCHOR,function(b){var c=a(b.currentTarget);if(c.closest(i.ADD_TO_QUIZ_CONTAINER).length){this.handleAddToQuizEvent(b,c);return}if(c.closest(i.PREVIEW_CONTAINER).length){this.handlePreviewContainerEvent(b,c);return}if(c.closest(i.SEARCH_OPTIONS).length){return}b.preventDefault();this.reloadBodyContent(c.prop("search"))}.bind(this));this.getRoot().on(e.bodyRendered,function(){b.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()})})};if(!h){f.register(j.TYPE,j,"core/modal");h=!0}return j});
+define ("mod_quiz/modal_quiz_question_bank",["jquery","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment","core_form/changechecker"],function(a,b,c,d,e,f,g){var h=!1,i={ADD_TO_QUIZ_CONTAINER:"td.addtoquizaction",ANCHOR:"a[href]",PREVIEW_CONTAINER:"td.previewaction",SEARCH_OPTIONS:"#advancedsearch",DISPLAY_OPTIONS:"#displayoptions",ADD_QUESTIONS_FORM:"form[action=\"edit.php\"]"},j=function(a){c.call(this,a);this.contextId=null;this.addOnPageId=null};j.TYPE="mod_quiz-quiz-question-bank";j.prototype=Object.create(c.prototype);j.prototype.constructor=j;j.prototype.setContextId=function(a){this.contextId=a};j.prototype.getContextId=function(){return this.contextId};j.prototype.setAddOnPageId=function(a){this.addOnPageId=a};j.prototype.getAddOnPageId=function(){return this.addOnPageId};j.prototype.show=function(){this.reloadBodyContent(window.location.search);return c.prototype.show.call(this)};j.prototype.reloadBodyContent=function(a){var c=f.loadFragment("mod_quiz","quiz_question_bank",this.getContextId(),{querystring:a}).fail(b.exception);this.setBody(c)};j.prototype.handleAddToQuizEvent=function(a,b){var c=b.attr("href")+"&addonpage="+this.getAddOnPageId();b.attr("href",c)};j.prototype.handlePreviewContainerEvent=function(a,b){window.openpopup(a,{url:b.attr("href"),name:"questionpreview",options:["height=600","width=800","top=0","left=0","menubar=0","location=0","scrollbars","resizable","toolbar","status","directories=0","fullscreen=0","dependent"].join(",")})};j.prototype.handleDisplayOptionFormEvent=function(b){b.stopPropagation();b.preventDefault();var c=a(b.target).closest(i.DISPLAY_OPTIONS),d="?"+c.serialize();this.reloadBodyContent(d)};j.prototype.registerDisplayOptionListeners=function(){this.getModal().on("change",i.DISPLAY_OPTIONS,function(b){var c=a(b.target);if(c.attr("aria-autocomplete")){return}this.handleDisplayOptionFormEvent(b)}.bind(this));this.getModal().on("submit",i.DISPLAY_OPTIONS,function(a){this.handleDisplayOptionFormEvent(a)}.bind(this))};j.prototype.registerEventListeners=function(){c.prototype.registerEventListeners.call(this);this.registerDisplayOptionListeners();this.getModal().on("submit",i.ADD_QUESTIONS_FORM,function(b){var c=a(b.currentTarget);a(" ").attr("type","hidden").attr("name","addonpage").attr("value",this.getAddOnPageId()).appendTo(c)}.bind(this));this.getModal().on("click",i.ANCHOR,function(b){var c=a(b.currentTarget);if(c.closest(i.ADD_TO_QUIZ_CONTAINER).length){this.handleAddToQuizEvent(b,c);return}if(c.closest(i.PREVIEW_CONTAINER).length){this.handlePreviewContainerEvent(b,c);return}if(c.closest(i.SEARCH_OPTIONS).length){return}b.preventDefault();this.reloadBodyContent(c.prop("search"))}.bind(this));this.getRoot().on(d.bodyRendered,function(){g.disableAllChecks()})};if(!h){e.register(j.TYPE,j,"core/modal");h=!0}return j});
//# sourceMappingURL=modal_quiz_question_bank.min.js.map
diff --git a/mod/quiz/amd/build/modal_quiz_question_bank.min.js.map b/mod/quiz/amd/build/modal_quiz_question_bank.min.js.map
index b09ecbc37b5..3e8081fabae 100644
--- a/mod/quiz/amd/build/modal_quiz_question_bank.min.js.map
+++ b/mod/quiz/amd/build/modal_quiz_question_bank.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/modal_quiz_question_bank.js"],"names":["define","$","Y","Notification","Modal","ModalEvents","ModalRegistry","Fragment","registered","SELECTORS","ADD_TO_QUIZ_CONTAINER","ANCHOR","PREVIEW_CONTAINER","SEARCH_OPTIONS","DISPLAY_OPTIONS","ADD_QUESTIONS_FORM","ModalQuizQuestionBank","root","call","contextId","addOnPageId","TYPE","prototype","Object","create","constructor","setContextId","id","getContextId","setAddOnPageId","getAddOnPageId","show","reloadBodyContent","window","location","search","queryString","promise","loadFragment","querystring","fail","exception","setBody","handleAddToQuizEvent","e","anchorElement","href","attr","handlePreviewContainerEvent","openpopup","url","name","options","join","handleDisplayOptionFormEvent","stopPropagation","preventDefault","form","target","closest","serialize","registerDisplayOptionListeners","getModal","on","modifiedElement","bind","registerEventListeners","formElement","currentTarget","appendTo","length","prop","getRoot","bodyRendered","use","M","core_formchangechecker","reset_form_dirty_state","register"],"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 * Contain the logic for the question bank modal.\n *\n * @module mod_quiz/modal_quiz_question_bank\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/yui',\n 'core/notification',\n 'core/modal',\n 'core/modal_events',\n 'core/modal_registry',\n 'core/fragment'\n],\nfunction(\n $,\n Y,\n Notification,\n Modal,\n ModalEvents,\n ModalRegistry,\n Fragment\n) {\n\n var registered = false;\n var SELECTORS = {\n ADD_TO_QUIZ_CONTAINER: 'td.addtoquizaction',\n ANCHOR: 'a[href]',\n PREVIEW_CONTAINER: 'td.previewaction',\n SEARCH_OPTIONS: '#advancedsearch',\n DISPLAY_OPTIONS: '#displayoptions',\n ADD_QUESTIONS_FORM: 'form[action=\"edit.php\"]',\n };\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var ModalQuizQuestionBank = function(root) {\n Modal.call(this, root);\n\n this.contextId = null;\n this.addOnPageId = null;\n };\n\n ModalQuizQuestionBank.TYPE = 'mod_quiz-quiz-question-bank';\n ModalQuizQuestionBank.prototype = Object.create(Modal.prototype);\n ModalQuizQuestionBank.prototype.constructor = ModalQuizQuestionBank;\n\n /**\n * Save the Moodle context id that the question bank is being\n * rendered in.\n *\n * @method setContextId\n * @param {int} id\n */\n ModalQuizQuestionBank.prototype.setContextId = function(id) {\n this.contextId = id;\n };\n\n /**\n * Retrieve the saved Moodle context id.\n *\n * @method getContextId\n * @return {int}\n */\n ModalQuizQuestionBank.prototype.getContextId = function() {\n return this.contextId;\n };\n\n /**\n * Set the id of the page that the question should be added to\n * when the user clicks the add to quiz link.\n *\n * @method setAddOnPageId\n * @param {int} id\n */\n ModalQuizQuestionBank.prototype.setAddOnPageId = function(id) {\n this.addOnPageId = id;\n };\n\n /**\n * Returns the saved page id for the question to be added it.\n *\n * @method getAddOnPageId\n * @return {int}\n */\n ModalQuizQuestionBank.prototype.getAddOnPageId = function() {\n return this.addOnPageId;\n };\n\n /**\n * Override the parent show function.\n *\n * Reload the body contents when the modal is shown. The current\n * window URL is used to inform the new content that should be\n * displayed.\n *\n * @method show\n * @return {void}\n */\n ModalQuizQuestionBank.prototype.show = function() {\n this.reloadBodyContent(window.location.search);\n return Modal.prototype.show.call(this);\n };\n\n /**\n * Replaces the current body contents with a new version of the question\n * bank.\n *\n * The contents of the question bank are generated using the provided\n * query string.\n *\n * @method reloadBodyContent\n * @param {string} queryString URL encoded string.\n */\n ModalQuizQuestionBank.prototype.reloadBodyContent = function(queryString) {\n // Load the question bank fragment to be displayed in the modal.\n var promise = Fragment.loadFragment(\n 'mod_quiz',\n 'quiz_question_bank',\n this.getContextId(),\n {\n querystring: queryString\n }\n ).fail(Notification.exception);\n\n this.setBody(promise);\n };\n\n /**\n * Update the URL of the anchor element that the user clicked on to make\n * sure that the question is added to the correct page.\n *\n * @method handleAddToQuizEvent\n * @param {event} e A JavaScript event\n * @param {object} anchorElement The anchor element that was triggered\n */\n ModalQuizQuestionBank.prototype.handleAddToQuizEvent = function(e, anchorElement) {\n // If the user clicks the plus icon to add the question to the page\n // directly then we need to intercept the click in order to adjust the\n // href and include the correct add on page id before the page is\n // redirected.\n var href = anchorElement.attr('href') + '&addonpage=' + this.getAddOnPageId();\n anchorElement.attr('href', href);\n };\n\n /**\n * Open a popup window to show the preview of the question.\n *\n * @method handlePreviewContainerEvent\n * @param {event} e A JavaScript event\n * @param {object} anchorElement The anchor element that was triggered\n */\n ModalQuizQuestionBank.prototype.handlePreviewContainerEvent = function(e, anchorElement) {\n var popupOptions = [\n 'height=600',\n 'width=800',\n 'top=0',\n 'left=0',\n 'menubar=0',\n 'location=0',\n 'scrollbars',\n 'resizable',\n 'toolbar',\n 'status',\n 'directories=0',\n 'fullscreen=0',\n 'dependent'\n ];\n window.openpopup(e, {\n url: anchorElement.attr('href'),\n name: 'questionpreview',\n options: popupOptions.join(',')\n });\n };\n\n /**\n * Reload the modal body with the new display options the user has selected.\n *\n * A query string is built using the form elements to be used to generate the\n * new body content.\n *\n * @method handleDisplayOptionFormEvent\n * @param {event} e A JavaScript event\n */\n ModalQuizQuestionBank.prototype.handleDisplayOptionFormEvent = function(e) {\n // Stop propagation to prevent other wild event handlers\n // from submitting the form on change.\n e.stopPropagation();\n e.preventDefault();\n\n var form = $(e.target).closest(SELECTORS.DISPLAY_OPTIONS);\n var queryString = '?' + form.serialize();\n this.reloadBodyContent(queryString);\n };\n\n /**\n * Listen for changes to the display options form.\n *\n * This handles the user changing:\n * - The quiz category select box\n * - The tags to filter by\n * - Show/hide questions from sub categories\n * - Show/hide old questions\n *\n * @method registerDisplayOptionListeners\n */\n ModalQuizQuestionBank.prototype.registerDisplayOptionListeners = function() {\n // Listen for changes to the display options form.\n this.getModal().on('change', SELECTORS.DISPLAY_OPTIONS, function(e) {\n // Get the element that was changed.\n var modifiedElement = $(e.target);\n if (modifiedElement.attr('aria-autocomplete')) {\n // If the element that was change is the autocomplete\n // input then we should ignore it because that is for\n // display purposes only.\n return;\n }\n\n this.handleDisplayOptionFormEvent(e);\n }.bind(this));\n\n // Listen for the display options form submission because the tags\n // filter will submit the form when it is changed.\n this.getModal().on('submit', SELECTORS.DISPLAY_OPTIONS, function(e) {\n this.handleDisplayOptionFormEvent(e);\n }.bind(this));\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n ModalQuizQuestionBank.prototype.registerEventListeners = function() {\n // Apply parent event listeners.\n Modal.prototype.registerEventListeners.call(this);\n\n // Set up the event handlers for all of the display options.\n this.registerDisplayOptionListeners();\n\n this.getModal().on('submit', SELECTORS.ADD_QUESTIONS_FORM, function(e) {\n // If the user clicks on the \"Add selected questions to the quiz\" button to add some questions to the page\n // then we need to intercept the submit in order to include the correct \"add on page id\" before the form is\n // submitted.\n var formElement = $(e.currentTarget);\n\n $(' ').attr('type', 'hidden')\n .attr('name', \"addonpage\")\n .attr('value', this.getAddOnPageId())\n .appendTo(formElement);\n }.bind(this));\n\n this.getModal().on('click', SELECTORS.ANCHOR, function(e) {\n var anchorElement = $(e.currentTarget);\n\n // If the anchor element was the add to quiz link.\n if (anchorElement.closest(SELECTORS.ADD_TO_QUIZ_CONTAINER).length) {\n this.handleAddToQuizEvent(e, anchorElement);\n return;\n }\n\n // If the anchor element was a preview question link.\n if (anchorElement.closest(SELECTORS.PREVIEW_CONTAINER).length) {\n this.handlePreviewContainerEvent(e, anchorElement);\n return;\n }\n\n // Click on expand/collaspse search-options. Has its own handler.\n // We should not interfere.\n if (anchorElement.closest(SELECTORS.SEARCH_OPTIONS).length) {\n return;\n }\n\n // Anything else means reload the pop-up contents.\n e.preventDefault();\n this.reloadBodyContent(anchorElement.prop('search'));\n }.bind(this));\n\n // Disable the form change checker when the body is rendered.\n this.getRoot().on(ModalEvents.bodyRendered, function() {\n // Make sure the form change checker is disabled otherwise it'll\n // stop the user from navigating away from the page once the modal\n // is hidden.\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n });\n };\n\n // Automatically register with the modal registry the first time this module is\n // imported so that you can create modals of this type using the modal factory.\n if (!registered) {\n ModalRegistry.register(\n ModalQuizQuestionBank.TYPE,\n ModalQuizQuestionBank,\n 'core/modal'\n );\n\n registered = true;\n }\n\n return ModalQuizQuestionBank;\n});\n"],"file":"modal_quiz_question_bank.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/modal_quiz_question_bank.js"],"names":["define","$","Notification","Modal","ModalEvents","ModalRegistry","Fragment","FormChangeChecker","registered","SELECTORS","ADD_TO_QUIZ_CONTAINER","ANCHOR","PREVIEW_CONTAINER","SEARCH_OPTIONS","DISPLAY_OPTIONS","ADD_QUESTIONS_FORM","ModalQuizQuestionBank","root","call","contextId","addOnPageId","TYPE","prototype","Object","create","constructor","setContextId","id","getContextId","setAddOnPageId","getAddOnPageId","show","reloadBodyContent","window","location","search","queryString","promise","loadFragment","querystring","fail","exception","setBody","handleAddToQuizEvent","e","anchorElement","href","attr","handlePreviewContainerEvent","openpopup","url","name","options","join","handleDisplayOptionFormEvent","stopPropagation","preventDefault","form","target","closest","serialize","registerDisplayOptionListeners","getModal","on","modifiedElement","bind","registerEventListeners","formElement","currentTarget","appendTo","length","prop","getRoot","bodyRendered","disableAllChecks","register"],"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 * Contain the logic for the question bank modal.\n *\n * @module mod_quiz/modal_quiz_question_bank\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/notification',\n 'core/modal',\n 'core/modal_events',\n 'core/modal_registry',\n 'core/fragment',\n 'core_form/changechecker',\n],\nfunction(\n $,\n Notification,\n Modal,\n ModalEvents,\n ModalRegistry,\n Fragment,\n FormChangeChecker,\n) {\n\n var registered = false;\n var SELECTORS = {\n ADD_TO_QUIZ_CONTAINER: 'td.addtoquizaction',\n ANCHOR: 'a[href]',\n PREVIEW_CONTAINER: 'td.previewaction',\n SEARCH_OPTIONS: '#advancedsearch',\n DISPLAY_OPTIONS: '#displayoptions',\n ADD_QUESTIONS_FORM: 'form[action=\"edit.php\"]',\n };\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var ModalQuizQuestionBank = function(root) {\n Modal.call(this, root);\n\n this.contextId = null;\n this.addOnPageId = null;\n };\n\n ModalQuizQuestionBank.TYPE = 'mod_quiz-quiz-question-bank';\n ModalQuizQuestionBank.prototype = Object.create(Modal.prototype);\n ModalQuizQuestionBank.prototype.constructor = ModalQuizQuestionBank;\n\n /**\n * Save the Moodle context id that the question bank is being\n * rendered in.\n *\n * @method setContextId\n * @param {int} id\n */\n ModalQuizQuestionBank.prototype.setContextId = function(id) {\n this.contextId = id;\n };\n\n /**\n * Retrieve the saved Moodle context id.\n *\n * @method getContextId\n * @return {int}\n */\n ModalQuizQuestionBank.prototype.getContextId = function() {\n return this.contextId;\n };\n\n /**\n * Set the id of the page that the question should be added to\n * when the user clicks the add to quiz link.\n *\n * @method setAddOnPageId\n * @param {int} id\n */\n ModalQuizQuestionBank.prototype.setAddOnPageId = function(id) {\n this.addOnPageId = id;\n };\n\n /**\n * Returns the saved page id for the question to be added it.\n *\n * @method getAddOnPageId\n * @return {int}\n */\n ModalQuizQuestionBank.prototype.getAddOnPageId = function() {\n return this.addOnPageId;\n };\n\n /**\n * Override the parent show function.\n *\n * Reload the body contents when the modal is shown. The current\n * window URL is used to inform the new content that should be\n * displayed.\n *\n * @method show\n * @return {void}\n */\n ModalQuizQuestionBank.prototype.show = function() {\n this.reloadBodyContent(window.location.search);\n return Modal.prototype.show.call(this);\n };\n\n /**\n * Replaces the current body contents with a new version of the question\n * bank.\n *\n * The contents of the question bank are generated using the provided\n * query string.\n *\n * @method reloadBodyContent\n * @param {string} queryString URL encoded string.\n */\n ModalQuizQuestionBank.prototype.reloadBodyContent = function(queryString) {\n // Load the question bank fragment to be displayed in the modal.\n var promise = Fragment.loadFragment(\n 'mod_quiz',\n 'quiz_question_bank',\n this.getContextId(),\n {\n querystring: queryString\n }\n ).fail(Notification.exception);\n\n this.setBody(promise);\n };\n\n /**\n * Update the URL of the anchor element that the user clicked on to make\n * sure that the question is added to the correct page.\n *\n * @method handleAddToQuizEvent\n * @param {event} e A JavaScript event\n * @param {object} anchorElement The anchor element that was triggered\n */\n ModalQuizQuestionBank.prototype.handleAddToQuizEvent = function(e, anchorElement) {\n // If the user clicks the plus icon to add the question to the page\n // directly then we need to intercept the click in order to adjust the\n // href and include the correct add on page id before the page is\n // redirected.\n var href = anchorElement.attr('href') + '&addonpage=' + this.getAddOnPageId();\n anchorElement.attr('href', href);\n };\n\n /**\n * Open a popup window to show the preview of the question.\n *\n * @method handlePreviewContainerEvent\n * @param {event} e A JavaScript event\n * @param {object} anchorElement The anchor element that was triggered\n */\n ModalQuizQuestionBank.prototype.handlePreviewContainerEvent = function(e, anchorElement) {\n var popupOptions = [\n 'height=600',\n 'width=800',\n 'top=0',\n 'left=0',\n 'menubar=0',\n 'location=0',\n 'scrollbars',\n 'resizable',\n 'toolbar',\n 'status',\n 'directories=0',\n 'fullscreen=0',\n 'dependent'\n ];\n window.openpopup(e, {\n url: anchorElement.attr('href'),\n name: 'questionpreview',\n options: popupOptions.join(',')\n });\n };\n\n /**\n * Reload the modal body with the new display options the user has selected.\n *\n * A query string is built using the form elements to be used to generate the\n * new body content.\n *\n * @method handleDisplayOptionFormEvent\n * @param {event} e A JavaScript event\n */\n ModalQuizQuestionBank.prototype.handleDisplayOptionFormEvent = function(e) {\n // Stop propagation to prevent other wild event handlers\n // from submitting the form on change.\n e.stopPropagation();\n e.preventDefault();\n\n var form = $(e.target).closest(SELECTORS.DISPLAY_OPTIONS);\n var queryString = '?' + form.serialize();\n this.reloadBodyContent(queryString);\n };\n\n /**\n * Listen for changes to the display options form.\n *\n * This handles the user changing:\n * - The quiz category select box\n * - The tags to filter by\n * - Show/hide questions from sub categories\n * - Show/hide old questions\n *\n * @method registerDisplayOptionListeners\n */\n ModalQuizQuestionBank.prototype.registerDisplayOptionListeners = function() {\n // Listen for changes to the display options form.\n this.getModal().on('change', SELECTORS.DISPLAY_OPTIONS, function(e) {\n // Get the element that was changed.\n var modifiedElement = $(e.target);\n if (modifiedElement.attr('aria-autocomplete')) {\n // If the element that was change is the autocomplete\n // input then we should ignore it because that is for\n // display purposes only.\n return;\n }\n\n this.handleDisplayOptionFormEvent(e);\n }.bind(this));\n\n // Listen for the display options form submission because the tags\n // filter will submit the form when it is changed.\n this.getModal().on('submit', SELECTORS.DISPLAY_OPTIONS, function(e) {\n this.handleDisplayOptionFormEvent(e);\n }.bind(this));\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n ModalQuizQuestionBank.prototype.registerEventListeners = function() {\n // Apply parent event listeners.\n Modal.prototype.registerEventListeners.call(this);\n\n // Set up the event handlers for all of the display options.\n this.registerDisplayOptionListeners();\n\n this.getModal().on('submit', SELECTORS.ADD_QUESTIONS_FORM, function(e) {\n // If the user clicks on the \"Add selected questions to the quiz\" button to add some questions to the page\n // then we need to intercept the submit in order to include the correct \"add on page id\" before the form is\n // submitted.\n var formElement = $(e.currentTarget);\n\n $(' ').attr('type', 'hidden')\n .attr('name', \"addonpage\")\n .attr('value', this.getAddOnPageId())\n .appendTo(formElement);\n }.bind(this));\n\n this.getModal().on('click', SELECTORS.ANCHOR, function(e) {\n var anchorElement = $(e.currentTarget);\n\n // If the anchor element was the add to quiz link.\n if (anchorElement.closest(SELECTORS.ADD_TO_QUIZ_CONTAINER).length) {\n this.handleAddToQuizEvent(e, anchorElement);\n return;\n }\n\n // If the anchor element was a preview question link.\n if (anchorElement.closest(SELECTORS.PREVIEW_CONTAINER).length) {\n this.handlePreviewContainerEvent(e, anchorElement);\n return;\n }\n\n // Click on expand/collaspse search-options. Has its own handler.\n // We should not interfere.\n if (anchorElement.closest(SELECTORS.SEARCH_OPTIONS).length) {\n return;\n }\n\n // Anything else means reload the pop-up contents.\n e.preventDefault();\n this.reloadBodyContent(anchorElement.prop('search'));\n }.bind(this));\n\n // Disable the form change checker when the body is rendered.\n this.getRoot().on(ModalEvents.bodyRendered, function() {\n // Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the\n // page once the modal is hidden.\n FormChangeChecker.disableAllChecks();\n });\n };\n\n // Automatically register with the modal registry the first time this module is\n // imported so that you can create modals of this type using the modal factory.\n if (!registered) {\n ModalRegistry.register(\n ModalQuizQuestionBank.TYPE,\n ModalQuizQuestionBank,\n 'core/modal'\n );\n\n registered = true;\n }\n\n return ModalQuizQuestionBank;\n});\n"],"file":"modal_quiz_question_bank.min.js"}
\ No newline at end of file
diff --git a/mod/quiz/amd/build/preflightcheck.min.js b/mod/quiz/amd/build/preflightcheck.min.js
index d8ceafb49d4..121c08d5ec2 100644
--- a/mod/quiz/amd/build/preflightcheck.min.js
+++ b/mod/quiz/amd/build/preflightcheck.min.js
@@ -1,2 +1,2 @@
-define ("mod_quiz/preflightcheck",["jquery","core/yui"],function(a,b){var c={confirmDialogue:null,init:function init(a,d,e,f){var g=a;b.use("moodle-core-notification",function(){if(b.one(e)){c.confirmDialogue=new M.core.dialogue({headerContent:d,bodyContent:b.one(e),draggable:!0,visible:!1,center:!0,modal:!0,width:null,extraClasses:["mod_quiz_preflight_popup"]});b.one(a).on("click",c.displayDialogue);b.one("#id_cancel").on("click",c.hideDialogue);g=c.confirmDialogue.get("boundingBox").one("[name=\"submitbutton\"]")}if(f){b.one(g).on("click",c.launchQuizPopup,c,f)}})},displayDialogue:function displayDialogue(a){if(a){a.halt()}c.confirmDialogue.show()},hideDialogue:function hideDialogue(a){if(a){a.halt()}c.confirmDialogue.hide(a)},launchQuizPopup:function launchQuizPopup(a,c){a.halt();b.use("moodle-core-formchangechecker","io-form",function(){M.core_formchangechecker.reset_form_dirty_state();var d=a.target.ancestor("form");window.openpopup(a,{url:d.get("action")+"?"+b.IO.stringify(d).replace(/\bcancel=/,"x="),windowname:"quizpopup",options:c,fullscreen:!0})})}};return c});
+define ("mod_quiz/preflightcheck",["jquery","core/yui","core_form/changechecker"],function(a,b,c){var d={confirmDialogue:null,init:function init(a,c,e,f){var g=a;b.use("moodle-core-notification",function(){if(b.one(e)){d.confirmDialogue=new M.core.dialogue({headerContent:c,bodyContent:b.one(e),draggable:!0,visible:!1,center:!0,modal:!0,width:null,extraClasses:["mod_quiz_preflight_popup"]});b.one(a).on("click",d.displayDialogue);b.one("#id_cancel").on("click",d.hideDialogue);g=d.confirmDialogue.get("boundingBox").one("[name=\"submitbutton\"]")}if(f){b.one(g).on("click",d.launchQuizPopup,d,f)}})},displayDialogue:function displayDialogue(a){if(a){a.halt()}d.confirmDialogue.show()},hideDialogue:function hideDialogue(a){if(a){a.halt()}d.confirmDialogue.hide(a)},launchQuizPopup:function launchQuizPopup(a,d){a.halt();b.use("io-form",function(){var e=a.target.ancestor("form");c.resetFormDirtyState(e.getDOMNode());window.openpopup(a,{url:e.get("action")+"?"+b.IO.stringify(e).replace(/\bcancel=/,"x="),windowname:"quizpopup",options:d,fullscreen:!0})})}};return d});
//# sourceMappingURL=preflightcheck.min.js.map
diff --git a/mod/quiz/amd/build/preflightcheck.min.js.map b/mod/quiz/amd/build/preflightcheck.min.js.map
index 8b931686589..ddcf13e20e4 100644
--- a/mod/quiz/amd/build/preflightcheck.min.js.map
+++ b/mod/quiz/amd/build/preflightcheck.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/preflightcheck.js"],"names":["define","$","Y","t","confirmDialogue","init","startButton","confirmationTitle","confirmationForm","popupoptions","finalStartButton","use","one","M","core","dialogue","headerContent","bodyContent","draggable","visible","center","modal","width","extraClasses","on","displayDialogue","hideDialogue","get","launchQuizPopup","e","halt","show","hide","core_formchangechecker","reset_form_dirty_state","form","target","ancestor","window","openpopup","url","IO","stringify","replace","windowname","options","fullscreen"],"mappings":"AA0BAA,OAAM,2BAAC,CAAC,QAAD,CAAW,UAAX,CAAD,CAAyB,SAASC,CAAT,CAAYC,CAAZ,CAAe,CAK1C,GAAIC,CAAAA,CAAC,CAAG,CACJC,eAAe,CAAE,IADb,CAWJC,IAAI,CAAE,cAASC,CAAT,CAAsBC,CAAtB,CAAyCC,CAAzC,CAA2DC,CAA3D,CAAyE,CAC3E,GAAIC,CAAAA,CAAgB,CAAGJ,CAAvB,CAEAJ,CAAC,CAACS,GAAF,CAAM,0BAAN,CAAkC,UAAW,CACzC,GAAIT,CAAC,CAACU,GAAF,CAAMJ,CAAN,CAAJ,CAA6B,CACzBL,CAAC,CAACC,eAAF,CAAoB,GAAIS,CAAAA,CAAC,CAACC,IAAF,CAAOC,QAAX,CAAoB,CACpCC,aAAa,CAAET,CADqB,CAEpCU,WAAW,CAAEf,CAAC,CAACU,GAAF,CAAMJ,CAAN,CAFuB,CAGpCU,SAAS,GAH2B,CAIpCC,OAAO,GAJ6B,CAKpCC,MAAM,GAL8B,CAMpCC,KAAK,GAN+B,CAOpCC,KAAK,CAAE,IAP6B,CAQpCC,YAAY,CAAE,CAAC,0BAAD,CARsB,CAApB,CAApB,CAWArB,CAAC,CAACU,GAAF,CAAMN,CAAN,EAAmBkB,EAAnB,CAAsB,OAAtB,CAA+BrB,CAAC,CAACsB,eAAjC,EACAvB,CAAC,CAACU,GAAF,CAAM,YAAN,EAAoBY,EAApB,CAAuB,OAAvB,CAAgCrB,CAAC,CAACuB,YAAlC,EAEAhB,CAAgB,CAAGP,CAAC,CAACC,eAAF,CAAkBuB,GAAlB,CAAsB,aAAtB,EAAqCf,GAArC,CAAyC,yBAAzC,CACtB,CAED,GAAIH,CAAJ,CAAkB,CACdP,CAAC,CAACU,GAAF,CAAMF,CAAN,EAAwBc,EAAxB,CAA2B,OAA3B,CAAoCrB,CAAC,CAACyB,eAAtC,CAAuDzB,CAAvD,CAA0DM,CAA1D,CACH,CACJ,CAtBD,CAuBH,CArCG,CA2CJgB,eAAe,CAAE,yBAASI,CAAT,CAAY,CACzB,GAAIA,CAAJ,CAAO,CACHA,CAAC,CAACC,IAAF,EACH,CACD3B,CAAC,CAACC,eAAF,CAAkB2B,IAAlB,EACH,CAhDG,CAsDJL,YAAY,CAAE,sBAASG,CAAT,CAAY,CACtB,GAAIA,CAAJ,CAAO,CACHA,CAAC,CAACC,IAAF,EACH,CACD3B,CAAC,CAACC,eAAF,CAAkB4B,IAAlB,CAAuBH,CAAvB,CACH,CA3DG,CAkEJD,eAAe,CAAE,yBAASC,CAAT,CAAYpB,CAAZ,CAA0B,CACvCoB,CAAC,CAACC,IAAF,GACA5B,CAAC,CAACS,GAAF,CAAM,+BAAN,CAAuC,SAAvC,CAAkD,UAAW,CACzDE,CAAC,CAACoB,sBAAF,CAAyBC,sBAAzB,GACA,GAAIC,CAAAA,CAAI,CAAGN,CAAC,CAACO,MAAF,CAASC,QAAT,CAAkB,MAAlB,CAAX,CACAC,MAAM,CAACC,SAAP,CAAiBV,CAAjB,CAAoB,CAChBW,GAAG,CAAEL,CAAI,CAACR,GAAL,CAAS,QAAT,EAAqB,GAArB,CAA2BzB,CAAC,CAACuC,EAAF,CAAKC,SAAL,CAAeP,CAAf,EAAqBQ,OAArB,CAA6B,WAA7B,CAA0C,IAA1C,CADhB,CAEhBC,UAAU,CAAE,WAFI,CAGhBC,OAAO,CAAEpC,CAHO,CAIhBqC,UAAU,GAJM,CAApB,CAMH,CATD,CAUH,CA9EG,CAAR,CAiFA,MAAO3C,CAAAA,CACV,CAvFK,CAAN","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 * This class manages the confirmation pop-up (also called the pre-flight check)\n * that is sometimes shown when a use clicks the start attempt button.\n *\n * This is also responsible for opening the pop-up window, if the quiz requires to be in one.\n *\n * @module mod_quiz/preflightcheck\n * @copyright 2016 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.1\n */\ndefine(['jquery', 'core/yui'], function($, Y) {\n\n /**\n * @alias module:mod_quiz/preflightcheck\n */\n var t = {\n confirmDialogue: null,\n\n /**\n * Initialise the start attempt button.\n *\n * @param {String} startButton the id of the start attempt button that we will be enhancing.\n * @param {String} confirmationTitle the title of the dialogue.\n * @param {String} confirmationForm selector for the confirmation form to show in the dialogue.\n * @param {String} popupoptions If not null, the quiz should be launced in a pop-up.\n */\n init: function(startButton, confirmationTitle, confirmationForm, popupoptions) {\n var finalStartButton = startButton;\n\n Y.use('moodle-core-notification', function() {\n if (Y.one(confirmationForm)) {\n t.confirmDialogue = new M.core.dialogue({\n headerContent: confirmationTitle,\n bodyContent: Y.one(confirmationForm),\n draggable: true,\n visible: false,\n center: true,\n modal: true,\n width: null,\n extraClasses: ['mod_quiz_preflight_popup']\n });\n\n Y.one(startButton).on('click', t.displayDialogue);\n Y.one('#id_cancel').on('click', t.hideDialogue);\n\n finalStartButton = t.confirmDialogue.get('boundingBox').one('[name=\"submitbutton\"]');\n }\n\n if (popupoptions) {\n Y.one(finalStartButton).on('click', t.launchQuizPopup, t, popupoptions);\n }\n });\n },\n\n /**\n * Display the dialogue.\n * @param {Y.EventFacade} e the event being responded to, if any.\n */\n displayDialogue: function(e) {\n if (e) {\n e.halt();\n }\n t.confirmDialogue.show();\n },\n\n /**\n * Hide the dialogue.\n * @param {Y.EventFacade} e the event being responded to, if any.\n */\n hideDialogue: function(e) {\n if (e) {\n e.halt();\n }\n t.confirmDialogue.hide(e);\n },\n\n /**\n * Event handler for the quiz start attempt button.\n * @param {Event} e the event being responded to\n * @param {Object} popupoptions\n */\n launchQuizPopup: function(e, popupoptions) {\n e.halt();\n Y.use('moodle-core-formchangechecker', 'io-form', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n var form = e.target.ancestor('form');\n window.openpopup(e, {\n url: form.get('action') + '?' + Y.IO.stringify(form).replace(/\\bcancel=/, 'x='),\n windowname: 'quizpopup',\n options: popupoptions,\n fullscreen: true,\n });\n });\n }\n };\n\n return t;\n});\n"],"file":"preflightcheck.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/preflightcheck.js"],"names":["define","$","Y","FormChangeChecker","t","confirmDialogue","init","startButton","confirmationTitle","confirmationForm","popupoptions","finalStartButton","use","one","M","core","dialogue","headerContent","bodyContent","draggable","visible","center","modal","width","extraClasses","on","displayDialogue","hideDialogue","get","launchQuizPopup","e","halt","show","hide","form","target","ancestor","resetFormDirtyState","getDOMNode","window","openpopup","url","IO","stringify","replace","windowname","options","fullscreen"],"mappings":"AA0BAA,OAAM,2BAAC,CAAC,QAAD,CAAW,UAAX,CAAuB,yBAAvB,CAAD,CAAoD,SAASC,CAAT,CAAYC,CAAZ,CAAeC,CAAf,CAAkC,CAKxF,GAAIC,CAAAA,CAAC,CAAG,CACJC,eAAe,CAAE,IADb,CAWJC,IAAI,CAAE,cAASC,CAAT,CAAsBC,CAAtB,CAAyCC,CAAzC,CAA2DC,CAA3D,CAAyE,CAC3E,GAAIC,CAAAA,CAAgB,CAAGJ,CAAvB,CAEAL,CAAC,CAACU,GAAF,CAAM,0BAAN,CAAkC,UAAW,CACzC,GAAIV,CAAC,CAACW,GAAF,CAAMJ,CAAN,CAAJ,CAA6B,CACzBL,CAAC,CAACC,eAAF,CAAoB,GAAIS,CAAAA,CAAC,CAACC,IAAF,CAAOC,QAAX,CAAoB,CACpCC,aAAa,CAAET,CADqB,CAEpCU,WAAW,CAAEhB,CAAC,CAACW,GAAF,CAAMJ,CAAN,CAFuB,CAGpCU,SAAS,GAH2B,CAIpCC,OAAO,GAJ6B,CAKpCC,MAAM,GAL8B,CAMpCC,KAAK,GAN+B,CAOpCC,KAAK,CAAE,IAP6B,CAQpCC,YAAY,CAAE,CAAC,0BAAD,CARsB,CAApB,CAApB,CAWAtB,CAAC,CAACW,GAAF,CAAMN,CAAN,EAAmBkB,EAAnB,CAAsB,OAAtB,CAA+BrB,CAAC,CAACsB,eAAjC,EACAxB,CAAC,CAACW,GAAF,CAAM,YAAN,EAAoBY,EAApB,CAAuB,OAAvB,CAAgCrB,CAAC,CAACuB,YAAlC,EAEAhB,CAAgB,CAAGP,CAAC,CAACC,eAAF,CAAkBuB,GAAlB,CAAsB,aAAtB,EAAqCf,GAArC,CAAyC,yBAAzC,CACtB,CAED,GAAIH,CAAJ,CAAkB,CACdR,CAAC,CAACW,GAAF,CAAMF,CAAN,EAAwBc,EAAxB,CAA2B,OAA3B,CAAoCrB,CAAC,CAACyB,eAAtC,CAAuDzB,CAAvD,CAA0DM,CAA1D,CACH,CACJ,CAtBD,CAuBH,CArCG,CA2CJgB,eAAe,CAAE,yBAASI,CAAT,CAAY,CACzB,GAAIA,CAAJ,CAAO,CACHA,CAAC,CAACC,IAAF,EACH,CACD3B,CAAC,CAACC,eAAF,CAAkB2B,IAAlB,EACH,CAhDG,CAsDJL,YAAY,CAAE,sBAASG,CAAT,CAAY,CACtB,GAAIA,CAAJ,CAAO,CACHA,CAAC,CAACC,IAAF,EACH,CACD3B,CAAC,CAACC,eAAF,CAAkB4B,IAAlB,CAAuBH,CAAvB,CACH,CA3DG,CAkEJD,eAAe,CAAE,yBAASC,CAAT,CAAYpB,CAAZ,CAA0B,CACvCoB,CAAC,CAACC,IAAF,GACA7B,CAAC,CAACU,GAAF,CAAM,SAAN,CAAiB,UAAW,CACxB,GAAIsB,CAAAA,CAAI,CAAGJ,CAAC,CAACK,MAAF,CAASC,QAAT,CAAkB,MAAlB,CAAX,CAEAjC,CAAiB,CAACkC,mBAAlB,CAAsCH,CAAI,CAACI,UAAL,EAAtC,EACAC,MAAM,CAACC,SAAP,CAAiBV,CAAjB,CAAoB,CAChBW,GAAG,CAAEP,CAAI,CAACN,GAAL,CAAS,QAAT,EAAqB,GAArB,CAA2B1B,CAAC,CAACwC,EAAF,CAAKC,SAAL,CAAeT,CAAf,EAAqBU,OAArB,CAA6B,WAA7B,CAA0C,IAA1C,CADhB,CAEhBC,UAAU,CAAE,WAFI,CAGhBC,OAAO,CAAEpC,CAHO,CAIhBqC,UAAU,GAJM,CAApB,CAMH,CAVD,CAWH,CA/EG,CAAR,CAkFA,MAAO3C,CAAAA,CACV,CAxFK,CAAN","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 * This class manages the confirmation pop-up (also called the pre-flight check)\n * that is sometimes shown when a use clicks the start attempt button.\n *\n * This is also responsible for opening the pop-up window, if the quiz requires to be in one.\n *\n * @module mod_quiz/preflightcheck\n * @copyright 2016 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.1\n */\ndefine(['jquery', 'core/yui', 'core_form/changechecker'], function($, Y, FormChangeChecker) {\n\n /**\n * @alias module:mod_quiz/preflightcheck\n */\n var t = {\n confirmDialogue: null,\n\n /**\n * Initialise the start attempt button.\n *\n * @param {String} startButton the id of the start attempt button that we will be enhancing.\n * @param {String} confirmationTitle the title of the dialogue.\n * @param {String} confirmationForm selector for the confirmation form to show in the dialogue.\n * @param {String} popupoptions If not null, the quiz should be launced in a pop-up.\n */\n init: function(startButton, confirmationTitle, confirmationForm, popupoptions) {\n var finalStartButton = startButton;\n\n Y.use('moodle-core-notification', function() {\n if (Y.one(confirmationForm)) {\n t.confirmDialogue = new M.core.dialogue({\n headerContent: confirmationTitle,\n bodyContent: Y.one(confirmationForm),\n draggable: true,\n visible: false,\n center: true,\n modal: true,\n width: null,\n extraClasses: ['mod_quiz_preflight_popup']\n });\n\n Y.one(startButton).on('click', t.displayDialogue);\n Y.one('#id_cancel').on('click', t.hideDialogue);\n\n finalStartButton = t.confirmDialogue.get('boundingBox').one('[name=\"submitbutton\"]');\n }\n\n if (popupoptions) {\n Y.one(finalStartButton).on('click', t.launchQuizPopup, t, popupoptions);\n }\n });\n },\n\n /**\n * Display the dialogue.\n * @param {Y.EventFacade} e the event being responded to, if any.\n */\n displayDialogue: function(e) {\n if (e) {\n e.halt();\n }\n t.confirmDialogue.show();\n },\n\n /**\n * Hide the dialogue.\n * @param {Y.EventFacade} e the event being responded to, if any.\n */\n hideDialogue: function(e) {\n if (e) {\n e.halt();\n }\n t.confirmDialogue.hide(e);\n },\n\n /**\n * Event handler for the quiz start attempt button.\n * @param {Event} e the event being responded to\n * @param {Object} popupoptions\n */\n launchQuizPopup: function(e, popupoptions) {\n e.halt();\n Y.use('io-form', function() {\n var form = e.target.ancestor('form');\n\n FormChangeChecker.resetFormDirtyState(form.getDOMNode());\n window.openpopup(e, {\n url: form.get('action') + '?' + Y.IO.stringify(form).replace(/\\bcancel=/, 'x='),\n windowname: 'quizpopup',\n options: popupoptions,\n fullscreen: true,\n });\n });\n }\n };\n\n return t;\n});\n"],"file":"preflightcheck.min.js"}
\ No newline at end of file
diff --git a/mod/quiz/amd/src/modal_add_random_question.js b/mod/quiz/amd/src/modal_add_random_question.js
index 80e71a12f9b..f34a2b5aa07 100644
--- a/mod/quiz/amd/src/modal_add_random_question.js
+++ b/mod/quiz/amd/src/modal_add_random_question.js
@@ -22,23 +22,23 @@
*/
define([
'jquery',
- 'core/yui',
'core/notification',
'core/modal',
'core/modal_events',
'core/modal_registry',
'core/fragment',
'core/templates',
+ 'core_form/changechecker',
],
function(
$,
- Y,
Notification,
Modal,
ModalEvents,
ModalRegistry,
Fragment,
- Templates
+ Templates,
+ FormChangeChecker,
) {
var registered = false;
@@ -272,12 +272,9 @@ function(
return;
}.bind(this))
.then(function() {
- // Make sure the form change checker is disabled otherwise it'll
- // stop the user from navigating away from the page once the modal
- // is hidden.
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ // Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the
+ // page once the modal is hidden.
+ FormChangeChecker.disableAllChecks();
return;
})
.fail(Notification.exception);
diff --git a/mod/quiz/amd/src/modal_quiz_question_bank.js b/mod/quiz/amd/src/modal_quiz_question_bank.js
index bfa34f474de..6c9b61c7949 100644
--- a/mod/quiz/amd/src/modal_quiz_question_bank.js
+++ b/mod/quiz/amd/src/modal_quiz_question_bank.js
@@ -22,21 +22,21 @@
*/
define([
'jquery',
- 'core/yui',
'core/notification',
'core/modal',
'core/modal_events',
'core/modal_registry',
- 'core/fragment'
+ 'core/fragment',
+ 'core_form/changechecker',
],
function(
$,
- Y,
Notification,
Modal,
ModalEvents,
ModalRegistry,
- Fragment
+ Fragment,
+ FormChangeChecker,
) {
var registered = false;
@@ -298,12 +298,9 @@ function(
// Disable the form change checker when the body is rendered.
this.getRoot().on(ModalEvents.bodyRendered, function() {
- // Make sure the form change checker is disabled otherwise it'll
- // stop the user from navigating away from the page once the modal
- // is hidden.
- Y.use('moodle-core-formchangechecker', function() {
- M.core_formchangechecker.reset_form_dirty_state();
- });
+ // Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the
+ // page once the modal is hidden.
+ FormChangeChecker.disableAllChecks();
});
};
diff --git a/mod/quiz/amd/src/preflightcheck.js b/mod/quiz/amd/src/preflightcheck.js
index 1a1e69a434d..7ab4757f5d9 100644
--- a/mod/quiz/amd/src/preflightcheck.js
+++ b/mod/quiz/amd/src/preflightcheck.js
@@ -24,7 +24,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.1
*/
-define(['jquery', 'core/yui'], function($, Y) {
+define(['jquery', 'core/yui', 'core_form/changechecker'], function($, Y, FormChangeChecker) {
/**
* @alias module:mod_quiz/preflightcheck
@@ -97,9 +97,10 @@ define(['jquery', 'core/yui'], function($, Y) {
*/
launchQuizPopup: function(e, popupoptions) {
e.halt();
- Y.use('moodle-core-formchangechecker', 'io-form', function() {
- M.core_formchangechecker.reset_form_dirty_state();
+ Y.use('io-form', function() {
var form = e.target.ancestor('form');
+
+ FormChangeChecker.resetFormDirtyState(form.getDOMNode());
window.openpopup(e, {
url: form.get('action') + '?' + Y.IO.stringify(form).replace(/\bcancel=/, 'x='),
windowname: 'quizpopup',
diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php
index 9cda10953f1..41982de1fc1 100644
--- a/mod/quiz/locallib.php
+++ b/mod/quiz/locallib.php
@@ -1970,14 +1970,13 @@ function quiz_get_js_module() {
'name' => 'mod_quiz',
'fullpath' => '/mod/quiz/module.js',
'requires' => array('base', 'dom', 'event-delegate', 'event-key',
- 'core_question_engine', 'moodle-core-formchangechecker'),
+ 'core_question_engine'),
'strings' => array(
array('cancel', 'moodle'),
array('flagged', 'question'),
array('functiondisabledbysecuremode', 'quiz'),
array('startattempt', 'quiz'),
array('timesup', 'quiz'),
- array('changesmadereallygoaway', 'moodle'),
),
);
}
diff --git a/mod/quiz/module.js b/mod/quiz/module.js
index aae70408361..f48479b532a 100644
--- a/mod/quiz/module.js
+++ b/mod/quiz/module.js
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
+/* eslint camelcase: off */
/**
* JavaScript library for the quiz module.
@@ -27,7 +28,9 @@ M.mod_quiz = M.mod_quiz || {};
M.mod_quiz.init_attempt_form = function(Y) {
M.core_question_engine.init_form(Y, '#responseform');
Y.on('submit', M.mod_quiz.timer.stop, '#responseform');
- M.core_formchangechecker.init({formid: 'responseform'});
+ require(['core_form/changechecker'], function(FormChangeChecker) {
+ FormChangeChecker.watchFormById('responseform');
+ });
};
M.mod_quiz.init_review_form = function(Y) {
@@ -72,6 +75,9 @@ M.mod_quiz.timer = {
M.mod_quiz.timer.preview = preview;
M.mod_quiz.timer.update();
Y.one('#quiz-timer-wrapper').setStyle('display', 'flex');
+ require(['core_form/changechecker'], function(FormChangeChecker) {
+ M.mod_quiz.timer.FormChangeChecker = FormChangeChecker;
+ });
},
/**
@@ -109,7 +115,7 @@ M.mod_quiz.timer = {
if (form.one('input[name=finishattempt]')) {
form.one('input[name=finishattempt]').set('value', 0);
}
- M.core_formchangechecker.set_form_submitted();
+ M.mod_quiz.timer.FormChangeChecker.markFormSubmitted(input.getDOMNode());
form.submit();
return;
}
diff --git a/mod/quiz/report/grading/renderer.php b/mod/quiz/report/grading/renderer.php
index 50e89b0c5e1..624c0a35f05 100644
--- a/mod/quiz/report/grading/renderer.php
+++ b/mod/quiz/report/grading/renderer.php
@@ -170,9 +170,9 @@ class quiz_grading_renderer extends plugin_renderer_base {
]), ['class' => 'mdl-align']);
$output .= html_writer::end_tag('div') . html_writer::end_tag('form');
- $this->page->requires->string_for_js('changesmadereallygoaway', 'moodle');
- $this->page->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init', [['formid' => 'manualgradingform']]);
+ // Add the form change checker.
+ $this->page->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['manualgradingform']);
+
return $output;
}