diff --git a/backup/util/ui/base_moodleform.class.php b/backup/util/ui/base_moodleform.class.php
index 4d2aefb2892..af011480baa 100644
--- a/backup/util/ui/base_moodleform.class.php
+++ b/backup/util/ui/base_moodleform.class.php
@@ -134,7 +134,36 @@ abstract class base_moodleform extends moodleform {
$buttonarray[] = $this->_form->createElement('submit', 'oneclickbackup', get_string('jumptofinalstep', 'backup'),
array('class' => 'oneclickbackup'));
}
- $buttonarray[] = $this->_form->createElement('cancel', 'cancel', get_string('cancel'), array('class' => 'confirmcancel'));
+
+ $cancelparams = [
+ 'data-modal' => 'confirmation',
+ 'data-modal-content-str' => json_encode([
+ 'confirmcancelquestion',
+ 'backup',
+ ]),
+ 'data-modal-yes-button-str' => json_encode([
+ 'yes',
+ 'moodle',
+ ]),
+ ];
+ if ($this->uistage->get_ui() instanceof import_ui) {
+ $cancelparams['data-modal-title-str'] = json_encode([
+ 'confirmcancelimport',
+ 'backup',
+ ]);
+ } else if ($this->uistage->get_ui() instanceof restore_ui) {
+ $cancelparams['data-modal-title-str'] = json_encode([
+ 'confirmcancelrestore',
+ 'backup',
+ ]);
+ } else {
+ $cancelparams['data-modal-title-str'] = json_encode([
+ 'confirmcancel',
+ 'backup',
+ ]);
+ }
+
+ $buttonarray[] = $this->_form->createElement('cancel', 'cancel', get_string('cancel'), $cancelparams);
$buttonarray[] = $this->_form->createElement(
'submit',
'submitbutton',
@@ -383,24 +412,6 @@ abstract class base_moodleform extends moodleform {
$this->require_definition_after_data();
- $config = new stdClass;
- if ($this->uistage->get_ui() instanceof import_ui) {
- $config->title = get_string('confirmcancelimport', 'backup');
- } else if ($this->uistage->get_ui() instanceof restore_ui) {
- $config->title = get_string('confirmcancelrestore', 'backup');
- } else {
- $config->title = get_string('confirmcancel', 'backup');
- }
- $config->question = get_string('confirmcancelquestion', 'backup');
- $config->yesLabel = $config->title;
- $config->noLabel = get_string('confirmcancelno', 'backup');
- $config->closeButtonTitle = get_string('close', 'editor');
- $PAGE->requires->yui_module(
- 'moodle-backup-confirmcancel',
- 'M.core_backup.confirmcancel.watch_cancel_buttons',
- array($config)
- );
-
// Get list of module types on course.
$modinfo = get_fast_modinfo($COURSE);
$modnames = array_map('strval', $modinfo->get_used_module_names(true));
diff --git a/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel-debug.js b/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel-debug.js
deleted file mode 100644
index 713ac2c2dc8..00000000000
--- a/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel-debug.js
+++ /dev/null
@@ -1,91 +0,0 @@
-YUI.add('moodle-backup-confirmcancel', function (Y, NAME) {
-
-/**
- * Add a confirmation dialogue when cancelling a backup.
- *
- * @module moodle-backup-confirmcancel
- */
-
-/**
- * Add a confirmation dialogue when cancelling a backup.
- *
- * @class M.core_backup.confirmcancel
- */
-
-
-// Namespace for the backup.
-M.core_backup = M.core_backup || {};
-
-M.core_backup.confirmcancel = {
- /**
- * An array of EventHandlers which call the confirm_cancel dialogue.
- *
- * @property listeners
- * @protected
- * @type Array
- */
- listeners: [],
-
- /**
- * The configuration supplied to this instance.
- *
- * @property config
- * @protected
- * @type Object
- */
- config: {},
-
- /**
- * Initializer to watch all cancel buttons.
- *
- * @method watch_cancel_buttons
- * @param {Object} config The configuration for the confirmation dialogue.
- */
- watch_cancel_buttons: function(config) {
- this.config = config;
-
- this.listeners.push(
- Y.one(Y.config.doc.body).delegate('click', this.confirm_cancel, '.confirmcancel', this)
- );
- },
-
- /**
- * Display the confirmation dialogue.
- *
- * @method confirm_cancel
- * @protected
- * @param {EventFacade} e
- */
- confirm_cancel: function(e) {
- // Prevent the default event (submit) from firing.
- e.preventDefault();
-
- // Create the confirmation dialogue.
- var confirm = new M.core.confirm(this.config);
-
- // If the user clicks yes.
- confirm.on('complete-yes', function() {
- // Detach the listeners for the confirm box so they don't fire again.
- new Y.EventHandle(M.core_backup.confirmcancel.listeners).detach();
-
- // The currentTarget is a div surrounding the form elements. Simulating a click on the div is
- // not going to submit a form so we need to find the form element to click.
- var element = e.currentTarget.one('input, select, button');
-
- // Simulate the original cancel button click.
- if (element) {
- element.simulate('click');
- } else {
- // Backwards compatibility only.
- e.currentTarget.simulate('click');
- }
- }, this);
-
-
- // Show the confirm box.
- confirm.show();
- }
-};
-
-
-}, '@VERSION@', {"requires": ["node", "node-event-simulate", "moodle-core-notification-confirm"]});
diff --git a/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel-min.js b/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel-min.js
deleted file mode 100644
index f6e5b92364f..00000000000
--- a/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel-min.js
+++ /dev/null
@@ -1 +0,0 @@
-YUI.add("moodle-backup-confirmcancel",function(n,c){M.core_backup=M.core_backup||{},M.core_backup.confirmcancel={listeners:[],config:{},watch_cancel_buttons:function(c){this.config=c,this.listeners.push(n.one(n.config.doc.body).delegate("click",this.confirm_cancel,".confirmcancel",this))},confirm_cancel:function(e){e.preventDefault();var c=new M.core.confirm(this.config);c.on("complete-yes",function(){new n.EventHandle(M.core_backup.confirmcancel.listeners).detach();var c=e.currentTarget.one("input, select, button");(c||e.currentTarget).simulate("click")},this),c.show()}}},"@VERSION@",{requires:["node","node-event-simulate","moodle-core-notification-confirm"]});
\ No newline at end of file
diff --git a/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel.js b/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel.js
deleted file mode 100644
index 713ac2c2dc8..00000000000
--- a/backup/util/ui/yui/build/moodle-backup-confirmcancel/moodle-backup-confirmcancel.js
+++ /dev/null
@@ -1,91 +0,0 @@
-YUI.add('moodle-backup-confirmcancel', function (Y, NAME) {
-
-/**
- * Add a confirmation dialogue when cancelling a backup.
- *
- * @module moodle-backup-confirmcancel
- */
-
-/**
- * Add a confirmation dialogue when cancelling a backup.
- *
- * @class M.core_backup.confirmcancel
- */
-
-
-// Namespace for the backup.
-M.core_backup = M.core_backup || {};
-
-M.core_backup.confirmcancel = {
- /**
- * An array of EventHandlers which call the confirm_cancel dialogue.
- *
- * @property listeners
- * @protected
- * @type Array
- */
- listeners: [],
-
- /**
- * The configuration supplied to this instance.
- *
- * @property config
- * @protected
- * @type Object
- */
- config: {},
-
- /**
- * Initializer to watch all cancel buttons.
- *
- * @method watch_cancel_buttons
- * @param {Object} config The configuration for the confirmation dialogue.
- */
- watch_cancel_buttons: function(config) {
- this.config = config;
-
- this.listeners.push(
- Y.one(Y.config.doc.body).delegate('click', this.confirm_cancel, '.confirmcancel', this)
- );
- },
-
- /**
- * Display the confirmation dialogue.
- *
- * @method confirm_cancel
- * @protected
- * @param {EventFacade} e
- */
- confirm_cancel: function(e) {
- // Prevent the default event (submit) from firing.
- e.preventDefault();
-
- // Create the confirmation dialogue.
- var confirm = new M.core.confirm(this.config);
-
- // If the user clicks yes.
- confirm.on('complete-yes', function() {
- // Detach the listeners for the confirm box so they don't fire again.
- new Y.EventHandle(M.core_backup.confirmcancel.listeners).detach();
-
- // The currentTarget is a div surrounding the form elements. Simulating a click on the div is
- // not going to submit a form so we need to find the form element to click.
- var element = e.currentTarget.one('input, select, button');
-
- // Simulate the original cancel button click.
- if (element) {
- element.simulate('click');
- } else {
- // Backwards compatibility only.
- e.currentTarget.simulate('click');
- }
- }, this);
-
-
- // Show the confirm box.
- confirm.show();
- }
-};
-
-
-}, '@VERSION@', {"requires": ["node", "node-event-simulate", "moodle-core-notification-confirm"]});
diff --git a/backup/util/ui/yui/src/confirmcancel/build.json b/backup/util/ui/yui/src/confirmcancel/build.json
deleted file mode 100644
index 603210ce673..00000000000
--- a/backup/util/ui/yui/src/confirmcancel/build.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "moodle-backup-confirmcancel",
- "builds": {
- "moodle-backup-confirmcancel": {
- "jsfiles": [
- "confirmcancel.js"
- ]
- }
- }
-}
diff --git a/backup/util/ui/yui/src/confirmcancel/js/confirmcancel.js b/backup/util/ui/yui/src/confirmcancel/js/confirmcancel.js
deleted file mode 100644
index 6d300562ec3..00000000000
--- a/backup/util/ui/yui/src/confirmcancel/js/confirmcancel.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Add a confirmation dialogue when cancelling a backup.
- *
- * @module moodle-backup-confirmcancel
- */
-
-/**
- * Add a confirmation dialogue when cancelling a backup.
- *
- * @class M.core_backup.confirmcancel
- */
-
-
-// Namespace for the backup.
-M.core_backup = M.core_backup || {};
-
-M.core_backup.confirmcancel = {
- /**
- * An array of EventHandlers which call the confirm_cancel dialogue.
- *
- * @property listeners
- * @protected
- * @type Array
- */
- listeners: [],
-
- /**
- * The configuration supplied to this instance.
- *
- * @property config
- * @protected
- * @type Object
- */
- config: {},
-
- /**
- * Initializer to watch all cancel buttons.
- *
- * @method watch_cancel_buttons
- * @param {Object} config The configuration for the confirmation dialogue.
- */
- watch_cancel_buttons: function(config) {
- this.config = config;
-
- this.listeners.push(
- Y.one(Y.config.doc.body).delegate('click', this.confirm_cancel, '.confirmcancel', this)
- );
- },
-
- /**
- * Display the confirmation dialogue.
- *
- * @method confirm_cancel
- * @protected
- * @param {EventFacade} e
- */
- confirm_cancel: function(e) {
- // Prevent the default event (submit) from firing.
- e.preventDefault();
-
- // Create the confirmation dialogue.
- var confirm = new M.core.confirm(this.config);
-
- // If the user clicks yes.
- confirm.on('complete-yes', function() {
- // Detach the listeners for the confirm box so they don't fire again.
- new Y.EventHandle(M.core_backup.confirmcancel.listeners).detach();
-
- // The currentTarget is a div surrounding the form elements. Simulating a click on the div is
- // not going to submit a form so we need to find the form element to click.
- var element = e.currentTarget.one('input, select, button');
-
- // Simulate the original cancel button click.
- if (element) {
- element.simulate('click');
- } else {
- // Backwards compatibility only.
- e.currentTarget.simulate('click');
- }
- }, this);
-
-
- // Show the confirm box.
- confirm.show();
- }
-};
diff --git a/backup/util/ui/yui/src/confirmcancel/meta/confirmcancel.json b/backup/util/ui/yui/src/confirmcancel/meta/confirmcancel.json
deleted file mode 100644
index e352bdf474b..00000000000
--- a/backup/util/ui/yui/src/confirmcancel/meta/confirmcancel.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "moodle-backup-confirmcancel": {
- "requires": [
- "node",
- "node-event-simulate",
- "moodle-core-notification-confirm"
- ]
- }
-}
diff --git a/lib/amd/build/utility.min.js b/lib/amd/build/utility.min.js
index 2c85e2d66d0..488f26848d5 100644
--- a/lib/amd/build/utility.min.js
+++ b/lib/amd/build/utility.min.js
@@ -1,3 +1,3 @@
-define("core/utility",["core/str","core/pending","core/toast","core/notification"],(function(Str,_pending,_toast,_notification){var obj;Str=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Str),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};var _systemImportTransformerGlobalIdentifier="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}let registered=!1;const getModalString=(dataset,type,field)=>dataset["".concat(type).concat(field,"Str")]?Str.get_string.apply(null,JSON.parse(dataset["".concat(type).concat(field,"Str")])):Promise.resolve(dataset["".concat(type).concat(field)]),displayConfirmation=(source,type)=>{let confirmationPromise=null;return confirmationPromise="".concat(type,"Type")in source.dataset&&"delete"===source.dataset["".concat(type,"Type")]?(0,_notification.deleteCancelPromise)(getModalString(source.dataset,type,"Title"),getModalString(source.dataset,type,"Content"),getModalString(source.dataset,type,"YesButton")):(0,_notification.saveCancelPromise)(getModalString(source.dataset,type,"Title"),getModalString(source.dataset,type,"Content"),getModalString(source.dataset,type,"YesButton")),confirmationPromise.then((()=>{if("true"===source.dataset["".concat(type,"Toast")]){const stringForToast=getModalString(source.dataset,type,"ToastConfirmation");"string"==typeof stringForToast?(0,_toast.add)(stringForToast):stringForToast.then((str=>(0,_toast.add)(str))).catch((e=>(0,_notification.exception)(e)))}window.location.href=source.dataset["".concat(type,"Destination")]})).catch((()=>{}))};registered||((()=>{document.addEventListener("click",(e=>{const confirmRequest=e.target.closest('[data-confirmation="modal"]');confirmRequest&&(e.preventDefault(),displayConfirmation(confirmRequest,"confirmation"));const modalConfirmation=e.target.closest('[data-modal="confirmation"]');modalConfirmation&&(e.preventDefault(),displayConfirmation(modalConfirmation,"modal"));const alertRequest=e.target.closest('[data-modal="alert"]');alertRequest&&(e.preventDefault(),(async(title,content)=>{const pendingPromise=new _pending.default("core/confirm:alert"),ModalFactory=await("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require(["core/modal_factory"],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require("core/modal_factory")):Promise.resolve(_systemImportTransformerGlobalIdentifier["core/modal_factory"]));ModalFactory.create({type:ModalFactory.types.ALERT,title:title,body:content,removeOnClose:!0}).then((function(modal){return modal.show(),pendingPromise.resolve(),modal}))})(getModalString(alertRequest.dataset,"modal","Title"),getModalString(alertRequest.dataset,"modal","Content")))}))})(),registered=!0)}));
+define("core/utility",["core/str","core/pending","core/toast","core/notification"],(function(Str,_pending,_toast,_notification){var obj;Str=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Str),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};var _systemImportTransformerGlobalIdentifier="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}let registered=!1;const getModalString=(dataset,type,field)=>dataset["".concat(type).concat(field,"Str")]?Str.get_string.apply(null,JSON.parse(dataset["".concat(type).concat(field,"Str")])):Promise.resolve(dataset["".concat(type).concat(field)]),displayConfirmation=(source,type)=>{let confirmationPromise=null;return confirmationPromise="".concat(type,"Type")in source.dataset&&"delete"===source.dataset["".concat(type,"Type")]?(0,_notification.deleteCancelPromise)(getModalString(source.dataset,type,"Title"),getModalString(source.dataset,type,"Content"),getModalString(source.dataset,type,"YesButton")):(0,_notification.saveCancelPromise)(getModalString(source.dataset,type,"Title"),getModalString(source.dataset,type,"Content"),getModalString(source.dataset,type,"YesButton")),confirmationPromise.then((()=>{if("true"===source.dataset["".concat(type,"Toast")]){const stringForToast=getModalString(source.dataset,type,"ToastConfirmation");"string"==typeof stringForToast?(0,_toast.add)(stringForToast):stringForToast.then((str=>(0,_toast.add)(str))).catch((e=>(0,_notification.exception)(e)))}if(source.dataset["".concat(type,"Destination")])window.location.href=source.dataset["".concat(type,"Destination")];else{if(!source.closest("form"))throw new Error("No destination found for confirmation action");source.dataset.confirmation="none",source.dataset.modal="none",source.click()}})).catch((()=>{}))};registered||((()=>{document.addEventListener("click",(e=>{const confirmRequest=e.target.closest('[data-confirmation="modal"]');confirmRequest&&(e.preventDefault(),displayConfirmation(confirmRequest,"confirmation"));const modalConfirmation=e.target.closest('[data-modal="confirmation"]');modalConfirmation&&(e.preventDefault(),displayConfirmation(modalConfirmation,"modal"));const alertRequest=e.target.closest('[data-modal="alert"]');alertRequest&&(e.preventDefault(),(async(title,content)=>{const pendingPromise=new _pending.default("core/confirm:alert"),ModalFactory=await("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require(["core/modal_factory"],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require("core/modal_factory")):Promise.resolve(_systemImportTransformerGlobalIdentifier["core/modal_factory"]));ModalFactory.create({type:ModalFactory.types.ALERT,title:title,body:content,removeOnClose:!0}).then((function(modal){return modal.show(),pendingPromise.resolve(),modal}))})(getModalString(alertRequest.dataset,"modal","Title"),getModalString(alertRequest.dataset,"modal","Content")))}))})(),registered=!0)}));
//# sourceMappingURL=utility.min.js.map
\ No newline at end of file
diff --git a/lib/amd/build/utility.min.js.map b/lib/amd/build/utility.min.js.map
index e65990969f5..10c19e976c8 100644
--- a/lib/amd/build/utility.min.js.map
+++ b/lib/amd/build/utility.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"utility.min.js","sources":["../src/utility.js"],"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 handling for HTML attributes. This module gets autoloaded on page load.\n *\n * With the appropriate HTML attributes, various functionalities defined in this module can be used such as a displaying\n * an alert or a confirmation modal, etc.\n *\n * @module core/utility\n * @copyright 2021 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n *\n * @example Calling the confirmation modal to delete a block\n *\n * // The following is an example of how to use this module via an indirect PHP call with a button.\n *\n * $controls[] = new action_menu_link_secondary(\n * $deleteactionurl,\n * new pix_icon('t/delete', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')),\n * $str,\n * [\n * 'class' => 'editing_delete',\n * 'data-modal' => 'confirmation', // Needed so this module will pick it up in the click handler.\n * 'data-modal-title-str' => json_encode(['deletecheck_modal', 'block']),\n * 'data-modal-content-str' => json_encode(['deleteblockcheck', 'block', $blocktitle]),\n * 'data-modal-yes-button-str' => json_encode(['delete', 'core']),\n * 'data-modal-toast' => 'true', // Can be set to inform the user that their action was a success.\n * 'data-modal-toast-confirmation-str' => json_encode(['deleteblockinprogress', 'block', $blocktitle]),\n * 'data-modal-destination' => $deleteconfirmationurl->out(false), // Where do you want to direct the user?\n * ]\n * );\n */\n\nimport * as Str from 'core/str';\nimport Pending from 'core/pending';\nimport {add as addToast} from 'core/toast';\nimport {saveCancelPromise, deleteCancelPromise, exception} from 'core/notification';\n\n// We want to ensure that we only initialize the listeners only once.\nlet registered = false;\n\n/**\n * Either fetch the string or return it from the dom node.\n *\n * @method getConfirmationString\n * @private\n * @param {HTMLElement} dataset The page element to fetch dataset items in\n * @param {String} type The type of string to fetch\n * @param {String} field The dataset field name to fetch the contents of\n * @return {Promise}\n *\n */\nconst getModalString = (dataset, type, field) => {\n if (dataset[`${type}${field}Str`]) {\n return Str.get_string.apply(null, JSON.parse(dataset[`${type}${field}Str`]));\n }\n return Promise.resolve(dataset[`${type}${field}`]);\n};\n\n/**\n * Display a save/cancel confirmation.\n *\n * @private\n * @param {HTMLElement} source The title of the confirmation\n * @param {String} type The content of the confirmation\n * @returns {Promise}\n */\nconst displayConfirmation = (source, type) => {\n let confirmationPromise = null;\n if (`${type}Type` in source.dataset && source.dataset[`${type}Type`] === 'delete') {\n confirmationPromise = deleteCancelPromise(\n getModalString(source.dataset, type, 'Title'),\n getModalString(source.dataset, type, 'Content'),\n getModalString(source.dataset, type, 'YesButton'),\n );\n } else {\n confirmationPromise = saveCancelPromise(\n getModalString(source.dataset, type, 'Title'),\n getModalString(source.dataset, type, 'Content'),\n getModalString(source.dataset, type, 'YesButton'),\n );\n }\n return confirmationPromise.then(() => {\n if (source.dataset[`${type}Toast`] === 'true') {\n const stringForToast = getModalString(source.dataset, type, 'ToastConfirmation');\n if (typeof stringForToast === \"string\") {\n addToast(stringForToast);\n } else {\n stringForToast.then(str => addToast(str)).catch(e => exception(e));\n }\n }\n window.location.href = source.dataset[`${type}Destination`];\n return;\n }).catch(() => {\n return;\n });\n};\n\n/**\n * Display an alert and return the promise from it.\n *\n * @private\n * @param {String} title The title of the alert\n * @param {String} content The content of the alert\n * @returns {Promise}\n */\nconst displayAlert = async(title, content) => {\n const pendingPromise = new Pending('core/confirm:alert');\n\n const ModalFactory = await import('core/modal_factory');\n\n return ModalFactory.create({\n type: ModalFactory.types.ALERT,\n title: title,\n body: content,\n removeOnClose: true,\n })\n .then(function(modal) {\n modal.show();\n pendingPromise.resolve();\n\n return modal;\n });\n};\n\n/**\n * Set up the listeners for the confirmation modal widget within the page.\n *\n * @method registerConfirmationListeners\n * @private\n */\nconst registerConfirmationListeners = () => {\n document.addEventListener('click', e => {\n const confirmRequest = e.target.closest('[data-confirmation=\"modal\"]');\n if (confirmRequest) {\n e.preventDefault();\n displayConfirmation(confirmRequest, 'confirmation');\n }\n\n const modalConfirmation = e.target.closest('[data-modal=\"confirmation\"]');\n if (modalConfirmation) {\n e.preventDefault();\n displayConfirmation(modalConfirmation, 'modal');\n }\n\n const alertRequest = e.target.closest('[data-modal=\"alert\"]');\n if (alertRequest) {\n e.preventDefault();\n displayAlert(\n getModalString(alertRequest.dataset, 'modal', 'Title'),\n getModalString(alertRequest.dataset, 'modal', 'Content'),\n );\n }\n });\n};\n\nif (!registered) {\n registerConfirmationListeners();\n registered = true;\n}\n"],"names":["registered","getModalString","dataset","type","field","Str","get_string","apply","JSON","parse","Promise","resolve","displayConfirmation","source","confirmationPromise","then","stringForToast","str","catch","e","window","location","href","document","addEventListener","confirmRequest","target","closest","preventDefault","modalConfirmation","alertRequest","async","title","content","pendingPromise","Pending","ModalFactory","create","types","ALERT","body","removeOnClose","modal","show","displayAlert","registerConfirmationListeners"],"mappings":"iwCAqDIA,YAAa,QAaXC,eAAiB,CAACC,QAASC,KAAMC,QAC/BF,kBAAWC,aAAOC,cACXC,IAAIC,WAAWC,MAAM,KAAMC,KAAKC,MAAMP,kBAAWC,aAAOC,gBAE5DM,QAAQC,QAAQT,kBAAWC,aAAOC,SAWvCQ,oBAAsB,CAACC,OAAQV,YAC7BW,oBAAsB,YAEtBA,oBADA,UAAGX,eAAcU,OAAOX,SAA6C,WAAlCW,OAAOX,kBAAWC,eAC/B,qCAClBF,eAAeY,OAAOX,QAASC,KAAM,SACrCF,eAAeY,OAAOX,QAASC,KAAM,WACrCF,eAAeY,OAAOX,QAASC,KAAM,eAGnB,mCAClBF,eAAeY,OAAOX,QAASC,KAAM,SACrCF,eAAeY,OAAOX,QAASC,KAAM,WACrCF,eAAeY,OAAOX,QAASC,KAAM,cAGtCW,oBAAoBC,MAAK,QACW,SAAnCF,OAAOX,kBAAWC,eAAyB,OACrCa,eAAiBf,eAAeY,OAAOX,QAASC,KAAM,qBAC9B,iBAAnBa,8BACEA,gBAETA,eAAeD,MAAKE,MAAO,cAASA,OAAMC,OAAMC,IAAK,2BAAUA,KAGvEC,OAAOC,SAASC,KAAOT,OAAOX,kBAAWC,wBAE1Ce,OAAM,UA+DRlB,aAzBiC,MAClCuB,SAASC,iBAAiB,SAASL,UACzBM,eAAiBN,EAAEO,OAAOC,QAAQ,+BACpCF,iBACAN,EAAES,iBACFhB,oBAAoBa,eAAgB,uBAGlCI,kBAAoBV,EAAEO,OAAOC,QAAQ,+BACvCE,oBACAV,EAAES,iBACFhB,oBAAoBiB,kBAAmB,gBAGrCC,aAAeX,EAAEO,OAAOC,QAAQ,wBAClCG,eACAX,EAAES,iBAzCOG,OAAMC,MAAOC,iBACxBC,eAAiB,IAAIC,iBAAQ,sBAE7BC,2nBAECA,aAAaC,OAAO,CACvBlC,KAAMiC,aAAaE,MAAMC,MACzBP,MAAOA,MACPQ,KAAMP,QACNQ,eAAe,IAElB1B,MAAK,SAAS2B,cACXA,MAAMC,OACNT,eAAevB,UAER+B,UA2BHE,CACI3C,eAAe6B,aAAa5B,QAAS,QAAS,SAC9CD,eAAe6B,aAAa5B,QAAS,QAAS,iBAO1D2C,GACA7C,YAAa"}
\ No newline at end of file
+{"version":3,"file":"utility.min.js","sources":["../src/utility.js"],"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 handling for HTML attributes. This module gets autoloaded on page load.\n *\n * With the appropriate HTML attributes, various functionalities defined in this module can be used such as a displaying\n * an alert or a confirmation modal, etc.\n *\n * @module core/utility\n * @copyright 2021 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n *\n * @example Calling the confirmation modal to delete a block\n *\n * // The following is an example of how to use this module via an indirect PHP call with a button.\n *\n * $controls[] = new action_menu_link_secondary(\n * $deleteactionurl,\n * new pix_icon('t/delete', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')),\n * $str,\n * [\n * 'class' => 'editing_delete',\n * 'data-modal' => 'confirmation', // Needed so this module will pick it up in the click handler.\n * 'data-modal-title-str' => json_encode(['deletecheck_modal', 'block']),\n * 'data-modal-content-str' => json_encode(['deleteblockcheck', 'block', $blocktitle]),\n * 'data-modal-yes-button-str' => json_encode(['delete', 'core']),\n * 'data-modal-toast' => 'true', // Can be set to inform the user that their action was a success.\n * 'data-modal-toast-confirmation-str' => json_encode(['deleteblockinprogress', 'block', $blocktitle]),\n * 'data-modal-destination' => $deleteconfirmationurl->out(false), // Where do you want to direct the user?\n * ]\n * );\n */\n\nimport * as Str from 'core/str';\nimport Pending from 'core/pending';\nimport {add as addToast} from 'core/toast';\nimport {saveCancelPromise, deleteCancelPromise, exception} from 'core/notification';\n\n// We want to ensure that we only initialize the listeners only once.\nlet registered = false;\n\n/**\n * Either fetch the string or return it from the dom node.\n *\n * @method getConfirmationString\n * @private\n * @param {HTMLElement} dataset The page element to fetch dataset items in\n * @param {String} type The type of string to fetch\n * @param {String} field The dataset field name to fetch the contents of\n * @return {Promise}\n *\n */\nconst getModalString = (dataset, type, field) => {\n if (dataset[`${type}${field}Str`]) {\n return Str.get_string.apply(null, JSON.parse(dataset[`${type}${field}Str`]));\n }\n return Promise.resolve(dataset[`${type}${field}`]);\n};\n\n/**\n * Display a save/cancel confirmation.\n *\n * @private\n * @param {HTMLElement} source The title of the confirmation\n * @param {String} type The content of the confirmation\n * @returns {Promise}\n */\nconst displayConfirmation = (source, type) => {\n let confirmationPromise = null;\n if (`${type}Type` in source.dataset && source.dataset[`${type}Type`] === 'delete') {\n confirmationPromise = deleteCancelPromise(\n getModalString(source.dataset, type, 'Title'),\n getModalString(source.dataset, type, 'Content'),\n getModalString(source.dataset, type, 'YesButton'),\n );\n } else {\n confirmationPromise = saveCancelPromise(\n getModalString(source.dataset, type, 'Title'),\n getModalString(source.dataset, type, 'Content'),\n getModalString(source.dataset, type, 'YesButton'),\n );\n }\n return confirmationPromise.then(() => {\n if (source.dataset[`${type}Toast`] === 'true') {\n const stringForToast = getModalString(source.dataset, type, 'ToastConfirmation');\n if (typeof stringForToast === \"string\") {\n addToast(stringForToast);\n } else {\n stringForToast.then(str => addToast(str)).catch(e => exception(e));\n }\n }\n\n if (source.dataset[`${type}Destination`]) {\n window.location.href = source.dataset[`${type}Destination`];\n } else if (source.closest('form')) {\n // Update the modal and confirmation data fields so that we don't loop.\n source.dataset.confirmation = 'none';\n source.dataset.modal = 'none';\n\n // Click on the button again.\n // Note: Do not use the form.submit() because it will not work for cancel buttons.\n source.click();\n } else {\n throw new Error(\"No destination found for confirmation action\");\n }\n return;\n }).catch(() => {\n return;\n });\n};\n\n/**\n * Display an alert and return the promise from it.\n *\n * @private\n * @param {String} title The title of the alert\n * @param {String} content The content of the alert\n * @returns {Promise}\n */\nconst displayAlert = async(title, content) => {\n const pendingPromise = new Pending('core/confirm:alert');\n\n const ModalFactory = await import('core/modal_factory');\n\n return ModalFactory.create({\n type: ModalFactory.types.ALERT,\n title: title,\n body: content,\n removeOnClose: true,\n })\n .then(function(modal) {\n modal.show();\n pendingPromise.resolve();\n\n return modal;\n });\n};\n\n/**\n * Set up the listeners for the confirmation modal widget within the page.\n *\n * @method registerConfirmationListeners\n * @private\n */\nconst registerConfirmationListeners = () => {\n document.addEventListener('click', e => {\n const confirmRequest = e.target.closest('[data-confirmation=\"modal\"]');\n if (confirmRequest) {\n e.preventDefault();\n displayConfirmation(confirmRequest, 'confirmation');\n }\n\n const modalConfirmation = e.target.closest('[data-modal=\"confirmation\"]');\n if (modalConfirmation) {\n e.preventDefault();\n displayConfirmation(modalConfirmation, 'modal');\n }\n\n const alertRequest = e.target.closest('[data-modal=\"alert\"]');\n if (alertRequest) {\n e.preventDefault();\n displayAlert(\n getModalString(alertRequest.dataset, 'modal', 'Title'),\n getModalString(alertRequest.dataset, 'modal', 'Content'),\n );\n }\n });\n};\n\nif (!registered) {\n registerConfirmationListeners();\n registered = true;\n}\n"],"names":["registered","getModalString","dataset","type","field","Str","get_string","apply","JSON","parse","Promise","resolve","displayConfirmation","source","confirmationPromise","then","stringForToast","str","catch","e","window","location","href","closest","Error","confirmation","modal","click","document","addEventListener","confirmRequest","target","preventDefault","modalConfirmation","alertRequest","async","title","content","pendingPromise","Pending","ModalFactory","create","types","ALERT","body","removeOnClose","show","displayAlert","registerConfirmationListeners"],"mappings":"iwCAqDIA,YAAa,QAaXC,eAAiB,CAACC,QAASC,KAAMC,QAC/BF,kBAAWC,aAAOC,cACXC,IAAIC,WAAWC,MAAM,KAAMC,KAAKC,MAAMP,kBAAWC,aAAOC,gBAE5DM,QAAQC,QAAQT,kBAAWC,aAAOC,SAWvCQ,oBAAsB,CAACC,OAAQV,YAC7BW,oBAAsB,YAEtBA,oBADA,UAAGX,eAAcU,OAAOX,SAA6C,WAAlCW,OAAOX,kBAAWC,eAC/B,qCAClBF,eAAeY,OAAOX,QAASC,KAAM,SACrCF,eAAeY,OAAOX,QAASC,KAAM,WACrCF,eAAeY,OAAOX,QAASC,KAAM,eAGnB,mCAClBF,eAAeY,OAAOX,QAASC,KAAM,SACrCF,eAAeY,OAAOX,QAASC,KAAM,WACrCF,eAAeY,OAAOX,QAASC,KAAM,cAGtCW,oBAAoBC,MAAK,QACW,SAAnCF,OAAOX,kBAAWC,eAAyB,OACrCa,eAAiBf,eAAeY,OAAOX,QAASC,KAAM,qBAC9B,iBAAnBa,8BACEA,gBAETA,eAAeD,MAAKE,MAAO,cAASA,OAAMC,OAAMC,IAAK,2BAAUA,QAInEN,OAAOX,kBAAWC,qBAClBiB,OAAOC,SAASC,KAAOT,OAAOX,kBAAWC,yBACtC,CAAA,IAAIU,OAAOU,QAAQ,cAShB,IAAIC,MAAM,gDAPhBX,OAAOX,QAAQuB,aAAe,OAC9BZ,OAAOX,QAAQwB,MAAQ,OAIvBb,OAAOc,YAKZT,OAAM,UA+DRlB,aAzBiC,MAClC4B,SAASC,iBAAiB,SAASV,UACzBW,eAAiBX,EAAEY,OAAOR,QAAQ,+BACpCO,iBACAX,EAAEa,iBACFpB,oBAAoBkB,eAAgB,uBAGlCG,kBAAoBd,EAAEY,OAAOR,QAAQ,+BACvCU,oBACAd,EAAEa,iBACFpB,oBAAoBqB,kBAAmB,gBAGrCC,aAAef,EAAEY,OAAOR,QAAQ,wBAClCW,eACAf,EAAEa,iBAzCOG,OAAMC,MAAOC,iBACxBC,eAAiB,IAAIC,iBAAQ,sBAE7BC,2nBAECA,aAAaC,OAAO,CACvBtC,KAAMqC,aAAaE,MAAMC,MACzBP,MAAOA,MACPQ,KAAMP,QACNQ,eAAe,IAElB9B,MAAK,SAASW,cACXA,MAAMoB,OACNR,eAAe3B,UAERe,UA2BHqB,CACI9C,eAAeiC,aAAahC,QAAS,QAAS,SAC9CD,eAAeiC,aAAahC,QAAS,QAAS,iBAO1D8C,GACAhD,YAAa"}
\ No newline at end of file
diff --git a/lib/amd/src/utility.js b/lib/amd/src/utility.js
index 1cfa1a2ca4f..feb0d70332a 100644
--- a/lib/amd/src/utility.js
+++ b/lib/amd/src/utility.js
@@ -103,7 +103,20 @@ const displayConfirmation = (source, type) => {
stringForToast.then(str => addToast(str)).catch(e => exception(e));
}
}
- window.location.href = source.dataset[`${type}Destination`];
+
+ if (source.dataset[`${type}Destination`]) {
+ window.location.href = source.dataset[`${type}Destination`];
+ } else if (source.closest('form')) {
+ // Update the modal and confirmation data fields so that we don't loop.
+ source.dataset.confirmation = 'none';
+ source.dataset.modal = 'none';
+
+ // Click on the button again.
+ // Note: Do not use the form.submit() because it will not work for cancel buttons.
+ source.click();
+ } else {
+ throw new Error("No destination found for confirmation action");
+ }
return;
}).catch(() => {
return;