Merge branch 'MDL-68409-master' of git://github.com/andrewnicols/moodle

This commit is contained in:
Jun Pataleta
2020-05-04 15:22:12 +08:00
30 changed files with 546 additions and 391 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core_calendar/crud",["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/modal_event_form","core_calendar/repository","core_calendar/events","core_calendar/modal_delete","core_calendar/selectors","core/pending"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(d,e,f){var i=[{key:"deleteevent",component:"calendar"}];f=parseInt(f,10);var m,o=1<f;if(o){i.push({key:"confirmeventseriesdelete",component:"calendar",param:{name:e,count:f}});m=g.create({type:l.TYPE})}else{i.push({key:"confirmeventdelete",component:"calendar",param:e});m=g.create({type:g.types.SAVE_CANCEL})}var p=b.get_strings(i),q=a.when(p,m).then(function(b,e){e.setTitle(b[0]);e.setBody(b[1]);if(!o){e.setSaveButtonText(b[0])}e.show();e.getRoot().on(h.save,function(){var b=new n("calendar/crud:initModal:deletedevent");j.deleteEvent(d,!1).then(function(){a("body").trigger(k.deleted,[d,!1])}).then(b.resolve).catch(c.exception)});e.getRoot().on(k.deleteAll,function(){var b=new n("calendar/crud:initModal:deletedallevent");j.deleteEvent(d,!0).then(function(){a("body").trigger(k.deleted,[d,!0])}).then(b.resolve).catch(c.exception)});return e}).catch(c.exception);return q}return{registerRemove:function(b){b.on("click",m.actions.remove,function(b){var c=a(this).closest(m.eventItem),d=c.data("eventId"),e=c.data("eventTitle"),f=c.data("eventCount");o(d,e,f);b.preventDefault()})},registerEditListeners:function(b,d){d.then(function(c){a("body").on(k.editEvent,function(a,d){var e=b.find(m.wrapper);c.setEventId(d);c.setContextId(e.data("contextId"));c.show();a.stopImmediatePropagation()})}).fail(c.exception);return d},registerEventFormModal:function registerEventFormModal(b){var d=g.create({type:i.TYPE,large:!0});b.on("click",m.actions.create,function(a){d.then(function(a){var c=b.find(m.wrapper),d=c.data("categoryid");if("undefined"!=typeof d){a.setCategoryId(d)}var e=b.find(m.today),f=b.find(m.day);if(!e.length&&f.length){a.setStartTime(f.data("newEventTimestamp"))}a.setContextId(c.data("contextId"));a.setCourseId(c.data("courseid"));a.show()}).fail(c.exception);a.preventDefault()});b.on("click",m.actions.edit,function(b){b.preventDefault();var e=a(b.currentTarget),f=e.closest(m.wrapper),g=e.closest(m.eventItem);d.then(function(a){a.setEventId(g.data("eventId"));a.setContextId(f.data("contextId"));a.show();b.stopImmediatePropagation()}).fail(c.exception)});return d}}});
define ("core_calendar/crud",["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/modal_event_form","core_calendar/repository","core_calendar/events","core_calendar/modal_delete","core_calendar/selectors","core/pending"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(d,e,f){var i=new n("core_calendar/crud:confirmDeletion"),m=[{key:"deleteevent",component:"calendar"}];f=parseInt(f,10);var o,p=1<f;if(p){m.push({key:"confirmeventseriesdelete",component:"calendar",param:{name:e,count:f}});o=g.create({type:l.TYPE})}else{m.push({key:"confirmeventdelete",component:"calendar",param:e});o=g.create({type:g.types.SAVE_CANCEL})}var q=b.get_strings(m),r=a.when(q,o).then(function(b,e){e.setTitle(b[0]);e.setBody(b[1]);if(!p){e.setSaveButtonText(b[0])}e.show();e.getRoot().on(h.save,function(){var b=new n("calendar/crud:initModal:deletedevent");j.deleteEvent(d,!1).then(function(){a("body").trigger(k.deleted,[d,!1])}).then(b.resolve).catch(c.exception)});e.getRoot().on(k.deleteAll,function(){var b=new n("calendar/crud:initModal:deletedallevent");j.deleteEvent(d,!0).then(function(){a("body").trigger(k.deleted,[d,!0])}).then(b.resolve).catch(c.exception)});return e}).then(function(a){i.resolve();return a}).catch(c.exception);return r}return{registerRemove:function(b){b.on("click",m.actions.remove,function(b){var c=a(this).closest(m.eventItem),d=c.data("eventId"),e=c.data("eventTitle"),f=c.data("eventCount");o(d,e,f);b.preventDefault()})},registerEditListeners:function(b,d){d.then(function(c){a("body").on(k.editEvent,function(a,d){var e=b.find(m.wrapper);c.setEventId(d);c.setContextId(e.data("contextId"));c.show();a.stopImmediatePropagation()})}).fail(c.exception);return d},registerEventFormModal:function registerEventFormModal(b){var d=g.create({type:i.TYPE,large:!0});b.on("click",m.actions.create,function(a){d.then(function(a){var c=b.find(m.wrapper),d=c.data("categoryid");if("undefined"!=typeof d){a.setCategoryId(d)}var e=b.find(m.today),f=b.find(m.day);if(!e.length&&f.length){a.setStartTime(f.data("newEventTimestamp"))}a.setContextId(c.data("contextId"));a.setCourseId(c.data("courseid"));a.show()}).fail(c.exception);a.preventDefault()});b.on("click",m.actions.edit,function(b){b.preventDefault();var e=a(b.currentTarget),f=e.closest(m.wrapper),g=e.closest(m.eventItem);d.then(function(a){a.setEventId(g.data("eventId"));a.setContextId(f.data("contextId"));a.show();b.stopImmediatePropagation()}).fail(c.exception)});return d}}});
//# sourceMappingURL=crud.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core_calendar/modal_delete",["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_events","core/modal_registry","core_calendar/events"],function(a,b,c,d,f,g,h){var i=!1,j={DELETE_ONE_BUTTON:"[data-action=\"deleteone\"]",DELETE_ALL_BUTTON:"[data-action=\"deleteall\"]",CANCEL_BUTTON:"[data-action=\"cancel\"]"},k=function(a){d.call(this,a)};k.TYPE="core_calendar-modal_delete";k.prototype=Object.create(d.prototype);k.prototype.constructor=k;k.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this);this.getModal().on(c.events.activate,j.DELETE_ONE_BUTTON,function(b,c){var d=a.Event(f.save);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this));this.getModal().on(c.events.activate,j.DELETE_ALL_BUTTON,function(b,c){var d=a.Event(h.deleteAll);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this));this.getModal().on(c.events.activate,j.CANCEL_BUTTON,function(b,c){var d=a.Event(f.cancel);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this))};if(!i){g.register(k.TYPE,k,"calendar/event_delete_modal");i=!0}return k});
define ("core_calendar/modal_delete",["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_events","core/modal_registry","core_calendar/events"],function(a,b,c,d,f,g,h){var i=!1,j={DELETE_ONE_BUTTON:"[data-action=\"deleteone\"]",DELETE_ALL_BUTTON:"[data-action=\"deleteall\"]",CANCEL_BUTTON:"[data-action=\"cancel\"]"},k=function(a){d.call(this,a);this.setRemoveOnClose(!0)};k.TYPE="core_calendar-modal_delete";k.prototype=Object.create(d.prototype);k.prototype.constructor=k;k.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this);this.getModal().on(c.events.activate,j.DELETE_ONE_BUTTON,function(b,c){var d=a.Event(f.save);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this));this.getModal().on(c.events.activate,j.DELETE_ALL_BUTTON,function(b,c){var d=a.Event(h.deleteAll);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this));this.getModal().on(c.events.activate,j.CANCEL_BUTTON,function(b,c){var d=a.Event(f.cancel);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this))};if(!i){g.register(k.TYPE,k,"calendar/event_delete_modal");i=!0}return k});
//# sourceMappingURL=modal_delete.min.js.map
File diff suppressed because one or more lines are too long
+6
View File
@@ -63,6 +63,7 @@ function(
* @return {Promise}
*/
function confirmDeletion(eventId, eventTitle, eventCount) {
var pendingPromise = new Pending('core_calendar/crud:confirmDeletion');
var deleteStrings = [
{
key: 'deleteevent',
@@ -139,6 +140,11 @@ function(
return deleteModal;
})
.then(function(modal) {
pendingPromise.resolve();
return modal;
})
.catch(Notification.exception);
return finalPromise;
+2
View File
@@ -55,6 +55,8 @@ function(
*/
var ModalDelete = function(root) {
Modal.call(this, root);
this.setRemoveOnClose(true);
};
ModalDelete.TYPE = 'core_calendar-modal_delete';
+1
View File
@@ -1499,6 +1499,7 @@ $string['numwords'] = '{$a} words';
$string['numyear'] = '{$a} year';
$string['numyears'] = '{$a} years';
$string['ok'] = 'OK';
$string['okay'] = 'Ok';
$string['oldpassword'] = 'Current password';
$string['olduserdirectory'] = 'This is the OLD users directory, and is no longer needed. You may safely delete it. The files it contains have been copied to the NEW user directory.';
$string['optional'] = 'optional';
+2
View File
@@ -0,0 +1,2 @@
define ("core/local/modal/alert",["exports","core/modal"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a){if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){c=function(a){return typeof a}}else{c=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return c(a)}function d(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function e(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function f(a,b,c){if(b)e(a.prototype,b);if(c)e(a,c);return a}function g(a,b){if(b&&("object"===c(b)||"function"==typeof b)){return b}return h(a)}function h(a){if(void 0===a){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return a}function i(a,b,c){if("undefined"!=typeof Reflect&&Reflect.get){i=Reflect.get}else{i=function(a,b,c){var d=j(a,b);if(!d)return;var e=Object.getOwnPropertyDescriptor(d,b);if(e.get){return e.get.call(c)}return e.value}}return i(a,b,c||a)}function j(a,b){while(!Object.prototype.hasOwnProperty.call(a,b)){a=k(a);if(null===a)break}return a}function k(a){k=Object.setPrototypeOf?Object.getPrototypeOf:function(a){return a.__proto__||Object.getPrototypeOf(a)};return k(a)}function l(a,b){if("function"!=typeof b&&null!==b){throw new TypeError("Super expression must either be null or a function")}a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,writable:!0,configurable:!0}});if(b)m(a,b)}function m(a,b){m=Object.setPrototypeOf||function(a,b){a.__proto__=b;return a};return m(a,b)}var n=function(a){l(b,a);function b(){d(this,b);return g(this,k(b).apply(this,arguments))}f(b,[{key:"registerEventListeners",value:function registerEventListeners(){i(k(b.prototype),"registerEventListeners",this).call(this);this.registerCloseOnCancel()}}]);return b}(b.default);a.default=n;return a.default});
//# sourceMappingURL=alert.min.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/local/modal/alert.js"],"names":["registerCloseOnCancel","Modal"],"mappings":"uJAyBA,uD,2rDAM6B,CAErB,2DAGA,KAAKA,qBAAL,EACH,C,cAVwBC,S","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Alert modal.\n *\n * @module core/modal_alert\n * @class modal_alert\n * @package core\n * @copyright 2020 Andrew Nicols <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Modal from 'core/modal';\n\nexport default class extends Modal {\n /**\n * Register all event listeners.\n */\n registerEventListeners() {\n // Call the parent registration.\n super.registerEventListeners();\n\n // Register to close on cancel.\n this.registerCloseOnCancel();\n }\n}\n"],"file":"alert.min.js"}
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core/modal_cancel",["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_events"],function(a,b,c,d,f){var g={CANCEL_BUTTON:"[data-action=\"cancel\"]"},h=function(a){d.call(this,a);if(!this.getFooter().find(g.CANCEL_BUTTON).length){b.exception({message:"No cancel button found"})}};h.prototype=Object.create(d.prototype);h.prototype.constructor=h;h.prototype.setFooter=function(){b.exception({message:"Can not change the footer of a cancel modal"})};h.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this);this.getModal().on(c.events.activate,g.CANCEL_BUTTON,function(b,c){var d=a.Event(f.cancel);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this))};return h});
define ("core/modal_cancel",["exports","core/modal"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a){if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){c=function(a){return typeof a}}else{c=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return c(a)}function d(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function e(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function f(a,b,c){if(b)e(a.prototype,b);if(c)e(a,c);return a}function g(a,b){if(b&&("object"===c(b)||"function"==typeof b)){return b}return h(a)}function h(a){if(void 0===a){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return a}function i(a,b,c){if("undefined"!=typeof Reflect&&Reflect.get){i=Reflect.get}else{i=function(a,b,c){var d=j(a,b);if(!d)return;var e=Object.getOwnPropertyDescriptor(d,b);if(e.get){return e.get.call(c)}return e.value}}return i(a,b,c||a)}function j(a,b){while(!Object.prototype.hasOwnProperty.call(a,b)){a=k(a);if(null===a)break}return a}function k(a){k=Object.setPrototypeOf?Object.getPrototypeOf:function(a){return a.__proto__||Object.getPrototypeOf(a)};return k(a)}function l(a,b){if("function"!=typeof b&&null!==b){throw new TypeError("Super expression must either be null or a function")}a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,writable:!0,configurable:!0}});if(b)m(a,b)}function m(a,b){m=Object.setPrototypeOf||function(a,b){a.__proto__=b;return a};return m(a,b)}var n=function(a){l(b,a);function b(a){var c;d(this,b);c=g(this,k(b).call(this,a));if(!c.getFooter().find(c.getActionSelector("cancel")).length){Notification.exception({message:"No cancel button found"})}return c}f(b,[{key:"registerEventListeners",value:function registerEventListeners(){i(k(b.prototype),"registerEventListeners",this).call(this);this.registerCloseOnCancel()}}]);return b}(b.default);a.default=n;return a.default});
//# sourceMappingURL=modal_cancel.min.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../src/modal_cancel.js"],"names":["define","$","Notification","CustomEvents","Modal","ModalEvents","SELECTORS","CANCEL_BUTTON","ModalCancel","root","call","getFooter","find","length","exception","message","prototype","Object","create","constructor","setFooter","registerEventListeners","getModal","on","events","activate","e","data","cancelEvent","Event","cancel","getRoot","trigger","isDefaultPrevented","hide","originalEvent","preventDefault","bind"],"mappings":"AAwBAA,OAAM,qBAAC,CAAC,QAAD,CAAW,mBAAX,CAAgC,gCAAhC,CAAkE,YAAlE,CAAgF,mBAAhF,CAAD,CACE,SAASC,CAAT,CAAYC,CAAZ,CAA0BC,CAA1B,CAAwCC,CAAxC,CAA+CC,CAA/C,CAA4D,IAE5DC,CAAAA,CAAS,CAAG,CACZC,aAAa,CAAE,0BADH,CAFgD,CAW5DC,CAAW,CAAG,SAASC,CAAT,CAAe,CAC7BL,CAAK,CAACM,IAAN,CAAW,IAAX,CAAiBD,CAAjB,EAEA,GAAI,CAAC,KAAKE,SAAL,GAAiBC,IAAjB,CAAsBN,CAAS,CAACC,aAAhC,EAA+CM,MAApD,CAA4D,CACxDX,CAAY,CAACY,SAAb,CAAuB,CAACC,OAAO,CAAE,wBAAV,CAAvB,CACH,CACJ,CAjB+D,CAmBhEP,CAAW,CAACQ,SAAZ,CAAwBC,MAAM,CAACC,MAAP,CAAcd,CAAK,CAACY,SAApB,CAAxB,CACAR,CAAW,CAACQ,SAAZ,CAAsBG,WAAtB,CAAoCX,CAApC,CAKAA,CAAW,CAACQ,SAAZ,CAAsBI,SAAtB,CAAkC,UAAW,CACzClB,CAAY,CAACY,SAAb,CAAuB,CAACC,OAAO,CAAE,6CAAV,CAAvB,CAEH,CAHD,CAUAP,CAAW,CAACQ,SAAZ,CAAsBK,sBAAtB,CAA+C,UAAW,CAEtDjB,CAAK,CAACY,SAAN,CAAgBK,sBAAhB,CAAuCX,IAAvC,CAA4C,IAA5C,EAEA,KAAKY,QAAL,GAAgBC,EAAhB,CAAmBpB,CAAY,CAACqB,MAAb,CAAoBC,QAAvC,CAAiDnB,CAAS,CAACC,aAA3D,CAA0E,SAASmB,CAAT,CAAYC,CAAZ,CAAkB,CACxF,GAAIC,CAAAA,CAAW,CAAG3B,CAAC,CAAC4B,KAAF,CAAQxB,CAAW,CAACyB,MAApB,CAAlB,CACA,KAAKC,OAAL,GAAeC,OAAf,CAAuBJ,CAAvB,CAAoC,IAApC,EAEA,GAAI,CAACA,CAAW,CAACK,kBAAZ,EAAL,CAAuC,CACnC,KAAKC,IAAL,GACAP,CAAI,CAACQ,aAAL,CAAmBC,cAAnB,EACH,CACJ,CARyE,CAQxEC,IARwE,CAQnE,IARmE,CAA1E,CASH,CAbD,CAeA,MAAO7B,CAAAA,CACV,CApDK,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 <http://www.gnu.org/licenses/>.\n\n/**\n * Contain the logic for the cancel modal.\n *\n * @module core/modal_cancel\n * @class modal_cancel\n * @package core\n * @copyright 2016 Ryan Wyllie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/modal', 'core/modal_events'],\n function($, Notification, CustomEvents, Modal, ModalEvents) {\n\n var SELECTORS = {\n CANCEL_BUTTON: '[data-action=\"cancel\"]',\n };\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var ModalCancel = function(root) {\n Modal.call(this, root);\n\n if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) {\n Notification.exception({message: 'No cancel button found'});\n }\n };\n\n ModalCancel.prototype = Object.create(Modal.prototype);\n ModalCancel.prototype.constructor = ModalCancel;\n\n /**\n * Override parent implementation to prevent changing the footer content.\n */\n ModalCancel.prototype.setFooter = function() {\n Notification.exception({message: 'Can not change the footer of a cancel modal'});\n return;\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n ModalCancel.prototype.registerEventListeners = function() {\n // Apply parent event listeners.\n Modal.prototype.registerEventListeners.call(this);\n\n this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {\n var cancelEvent = $.Event(ModalEvents.cancel);\n this.getRoot().trigger(cancelEvent, this);\n\n if (!cancelEvent.isDefaultPrevented()) {\n this.hide();\n data.originalEvent.preventDefault();\n }\n }.bind(this));\n };\n\n return ModalCancel;\n});\n"],"file":"modal_cancel.min.js"}
{"version":3,"sources":["../src/modal_cancel.js"],"names":["root","getFooter","find","getActionSelector","length","Notification","exception","message","registerCloseOnCancel","Modal"],"mappings":"kJAwBA,uD,gjDAGI,WAAYA,CAAZ,CAAkB,iBACd,wBAAMA,CAAN,GAEA,GAAI,CAAC,EAAKC,SAAL,GAAiBC,IAAjB,CAAsB,EAAKC,iBAAL,CAAuB,QAAvB,CAAtB,EAAwDC,MAA7D,CAAqE,CACjEC,YAAY,CAACC,SAAb,CAAuB,CAACC,OAAO,CAAE,wBAAV,CAAvB,CACH,CALa,QAMjB,C,0EAKwB,CAErB,2DAGA,KAAKC,qBAAL,EACH,C,cAlBwBC,S","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Contain the logic for the cancel modal.\n *\n * @module core/modal_cancel\n * @class modal_cancel\n * @package core\n * @copyright 2016 Ryan Wyllie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Modal from 'core/modal';\n\nexport default class extends Modal {\n constructor(root) {\n super(root);\n\n if (!this.getFooter().find(this.getActionSelector('cancel')).length) {\n Notification.exception({message: 'No cancel button found'});\n }\n }\n\n /**\n * Register all event listeners.\n */\n registerEventListeners() {\n // Call the parent registration.\n super.registerEventListeners();\n\n // Register to close on cancel.\n this.registerCloseOnCancel();\n }\n}\n"],"file":"modal_cancel.min.js"}
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core/modal_factory",["jquery","core/modal_events","core/modal_registry","core/modal","core/modal_save_cancel","core/modal_cancel","core/templates","core/notification","core/custom_interaction_events","core/pending"],function(a,b,c,d,e,f,g,h,i,j){var k={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CANCEL:"core/modal_cancel"},l={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CANCEL:"CANCEL"};c.register(l.DEFAULT,d,k.DEFAULT);c.register(l.SAVE_CANCEL,e,k.SAVE_CANCEL);c.register(l.CANCEL,f,k.CANCEL);var m=function(c,d,e){var f=null,g="function"==typeof e.preShowCallback,h=function(b,d){var h=new j("core/modal_factory:setUpTrigger:triggeredCallback");f=a(b.currentTarget);c.then(function(a){if(g){e.preShowCallback(f,a)}a.show();return a}).then(h.resolve);d.originalEvent.preventDefault()};if(Array.isArray(d)){var k=d[1];d=d[0];i.define(d,[i.events.activate]);d.on(i.events.activate,k,h)}else{i.define(d,[i.events.activate]);d.on(i.events.activate,h)}c.then(function(a){a.getRoot().on(b.hidden,function(){if(null!==f){f.focus()}});return a})},n=function(b,c){c=a(c);var d=b.module,e=new d(c);return e},o=function(b,c){var d=b.template,e=g.render(d,c).then(function(c){var d=a(c);return n(b,d)}).fail(h.exception);return e};return{create:function create(a,b){var d=a.type||l.DEFAULT,e=a.large?!0:!1,f=null,g={};f=c.get(d);if(!f){h.exception({message:"Unable to find modal of type: "+d})}if("undefined"!=typeof a.templateContext){g=a.templateContext}var i=o(f,g).then(function(b){if("undefined"!=typeof a.title){b.setTitle(a.title)}if("undefined"!=typeof a.body){b.setBody(a.body)}if("undefined"!=typeof a.footer){b.setFooter(a.footer)}if(e){b.setLarge()}return b});if("undefined"!=typeof b){m(i,b,a)}return i},types:l}});
function _slicedToArray(a,b){return _arrayWithHoles(a)||_iterableToArrayLimit(a,b)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function _iterableToArrayLimit(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function _arrayWithHoles(a){if(Array.isArray(a))return a}define ("core/modal_factory",["jquery","core/modal_events","core/modal_registry","core/modal","core/modal_save_cancel","core/modal_cancel","core/local/modal/alert","core/templates","core/notification","core/custom_interaction_events","core/pending"],function(a,b,c,d,e,f,g,h,i,j,k){var l={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CANCEL:"core/modal_cancel",ALERT:"core/local/modal/alert"},m={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CANCEL:"CANCEL",ALERT:"ALERT"};c.register(m.DEFAULT,d,l.DEFAULT);c.register(m.SAVE_CANCEL,e,l.SAVE_CANCEL);c.register(m.CANCEL,f,l.CANCEL);c.register(m.ALERT,g,l.ALERT);var n=function(c,d,e){var f=null,g="function"==typeof e.preShowCallback,h=function(b,d){var h=new k("core/modal_factory:setUpTrigger:triggeredCallback");f=a(b.currentTarget);c.then(function(a){if(g){e.preShowCallback(f,a)}a.show();return a}).then(h.resolve);d.originalEvent.preventDefault()};if(Array.isArray(d)){var i=d[1];d=d[0];j.define(d,[j.events.activate]);d.on(j.events.activate,i,h)}else{j.define(d,[j.events.activate]);d.on(j.events.activate,h)}c.then(function(a){a.getRoot().on(b.hidden,function(){if(null!==f){f.focus()}});return a})},o=function(b,c){c=a(c);var d=b.module,e=new d(c);return e},p=function(b,c){var d=b.template,e=h.render(d,c).then(function(c){var d=a(c);return o(b,d)}).fail(i.exception);return e};return{create:function create(a,b){var d=a.type||m.DEFAULT,e=a.large?!0:!1,f=null,g={};f=c.get(d);if(!f){i.exception({message:"Unable to find modal of type: "+d})}if("undefined"!=typeof a.templateContext){g=a.templateContext}var h=p(f,g).then(function(b){if("undefined"!=typeof a.title){b.setTitle(a.title)}if("undefined"!=typeof a.body){b.setBody(a.body)}if("undefined"!=typeof a.footer){b.setFooter(a.footer)}if(a.buttons){Object.entries(a.buttons).forEach(function(a){var c=_slicedToArray(a,2),d=c[0],e=c[1];b.setButtonText(d,e)})}if(e){b.setLarge()}if("undefined"!=typeof a.removeOnClose){b.setRemoveOnClose(a.removeOnClose)}return b});if("undefined"!=typeof b){n(h,b,a)}return h},types:m}});
//# sourceMappingURL=modal_factory.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core/modal_save_cancel",["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_events"],function(a,b,c,d,f){var g={SAVE_BUTTON:"[data-action=\"save\"]",CANCEL_BUTTON:"[data-action=\"cancel\"]"},h=function(a){d.call(this,a);if(!this.getFooter().find(g.SAVE_BUTTON).length){b.exception({message:"No save button found"})}if(!this.getFooter().find(g.CANCEL_BUTTON).length){b.exception({message:"No cancel button found"})}};h.prototype=Object.create(d.prototype);h.prototype.constructor=h;h.prototype.setFooter=function(){b.exception({message:"Can not change the footer of a save cancel modal"})};h.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this);this.getModal().on(c.events.activate,g.SAVE_BUTTON,function(b,c){var d=a.Event(f.save);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this));this.getModal().on(c.events.activate,g.CANCEL_BUTTON,function(b,c){var d=a.Event(f.cancel);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){this.hide();c.originalEvent.preventDefault()}}.bind(this))};h.prototype.setSaveButtonText=function(a){var b=this.getFooter().find(g.SAVE_BUTTON);this.asyncSet(a,b.text.bind(b))};return h});
define ("core/modal_save_cancel",["exports","core/modal"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a){if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){c=function(a){return typeof a}}else{c=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return c(a)}function d(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function e(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function f(a,b,c){if(b)e(a.prototype,b);if(c)e(a,c);return a}function g(a,b){if(b&&("object"===c(b)||"function"==typeof b)){return b}return h(a)}function h(a){if(void 0===a){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return a}function i(a,b,c){if("undefined"!=typeof Reflect&&Reflect.get){i=Reflect.get}else{i=function(a,b,c){var d=j(a,b);if(!d)return;var e=Object.getOwnPropertyDescriptor(d,b);if(e.get){return e.get.call(c)}return e.value}}return i(a,b,c||a)}function j(a,b){while(!Object.prototype.hasOwnProperty.call(a,b)){a=k(a);if(null===a)break}return a}function k(a){k=Object.setPrototypeOf?Object.getPrototypeOf:function(a){return a.__proto__||Object.getPrototypeOf(a)};return k(a)}function l(a,b){if("function"!=typeof b&&null!==b){throw new TypeError("Super expression must either be null or a function")}a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,writable:!0,configurable:!0}});if(b)m(a,b)}function m(a,b){m=Object.setPrototypeOf||function(a,b){a.__proto__=b;return a};return m(a,b)}var n=function(a){l(b,a);function b(a){var c;d(this,b);c=g(this,k(b).call(this,a));if(!c.getFooter().find(c.getActionSelector("save")).length){Notification.exception({message:"No save button found"})}if(!c.getFooter().find(c.getActionSelector("cancel")).length){Notification.exception({message:"No cancel button found"})}return c}f(b,[{key:"registerEventListeners",value:function registerEventListeners(){i(k(b.prototype),"registerEventListeners",this).call(this);this.registerCloseOnSave();this.registerCloseOnCancel()}},{key:"setFooter",value:function setFooter(){Notification.exception({message:"Can not change the footer of a save cancel modal"})}},{key:"setSaveButtonText",value:function setSaveButtonText(a){return this.setButtonText("save",a)}}]);return b}(b.default);a.default=n;return a.default});
//# sourceMappingURL=modal_save_cancel.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+39
View File
@@ -0,0 +1,39 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Alert modal.
*
* @module core/modal_alert
* @class modal_alert
* @package core
* @copyright 2020 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Modal from 'core/modal';
export default class extends Modal {
/**
* Register all event listeners.
*/
registerEventListeners() {
// Call the parent registration.
super.registerEventListeners();
// Register to close on cancel.
this.registerCloseOnCancel();
}
}
+89 -2
View File
@@ -610,10 +610,11 @@ define([
* already been.
*
* @method show
* @returns {Promise}
*/
Modal.prototype.show = function() {
if (this.isVisible()) {
return;
return $.Deferred().resolve();
}
var pendingPromise = new Pending('core/modal:show');
@@ -628,7 +629,7 @@ define([
this.attachToDOM();
}
this.getBackdrop()
return this.getBackdrop()
.then(function(backdrop) {
var currentIndex = this.calculateZIndex();
var newIndex = currentIndex + 2;
@@ -699,6 +700,7 @@ define([
* @method destroy
*/
Modal.prototype.destroy = function() {
this.hide();
this.root.remove();
this.root.trigger(ModalEvents.destroyed, this);
};
@@ -802,6 +804,52 @@ define([
}.bind(this));
};
/**
* Register a listener to close the dialogue when the cancel button is pressed.
*
* @method registerCloseOnCancel
*/
Modal.prototype.registerCloseOnCancel = function() {
// Handle the clicking of the Cancel button.
this.getModal().on(CustomEvents.events.activate, this.getActionSelector('cancel'), function(e, data) {
var cancelEvent = $.Event(ModalEvents.cancel);
this.getRoot().trigger(cancelEvent, this);
if (!cancelEvent.isDefaultPrevented()) {
data.originalEvent.preventDefault();
if (this.removeOnClose) {
this.destroy();
} else {
this.hide();
}
}
}.bind(this));
};
/**
* Register a listener to close the dialogue when the save button is pressed.
*
* @method registerCloseOnSave
*/
Modal.prototype.registerCloseOnSave = function() {
// Handle the clicking of the Cancel button.
this.getModal().on(CustomEvents.events.activate, this.getActionSelector('save'), function(e, data) {
var saveEvent = $.Event(ModalEvents.save);
this.getRoot().trigger(saveEvent, this);
if (!saveEvent.isDefaultPrevented()) {
data.originalEvent.preventDefault();
if (this.removeOnClose) {
this.destroy();
} else {
this.hide();
}
}
}.bind(this));
};
/**
* Set or resolve and set the value using the function.
*
@@ -827,5 +875,44 @@ define([
return p;
};
/**
* Set the title text of a button.
*
* This method is overloaded to take either a string value for the button title or a jQuery promise that is resolved with
* text most commonly from a Str.get_string call.
*
* @param {DOMString} action The action of the button
* @param {(String|object)} value The button text, or a promise which will resolve to it
* @returns {Promise}
*/
Modal.prototype.setButtonText = function(action, value) {
const button = this.getFooter().find(this.getActionSelector(action));
if (!button) {
throw new Error("Unable to find the '" + action + "' button");
}
return this.asyncSet(value, button.text.bind(button));
};
/**
* Get the Selector for an action.
*
* @param {String} action
* @returns {DOMString}
*/
Modal.prototype.getActionSelector = function(action) {
return "[data-action='" + action + "']";
};
/**
* Set the flag to remove the modal from the DOM on close.
*
* @param {Boolean} remove
*/
Modal.prototype.setRemoveOnClose = function(remove) {
this.removeOnClose = remove;
};
return Modal;
});
+14 -45
View File
@@ -22,56 +22,25 @@
* @copyright 2016 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/modal', 'core/modal_events'],
function($, Notification, CustomEvents, Modal, ModalEvents) {
import Modal from 'core/modal';
var SELECTORS = {
CANCEL_BUTTON: '[data-action="cancel"]',
};
export default class extends Modal {
constructor(root) {
super(root);
/**
* Constructor for the Modal.
*
* @param {object} root The root jQuery element for the modal
*/
var ModalCancel = function(root) {
Modal.call(this, root);
if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) {
if (!this.getFooter().find(this.getActionSelector('cancel')).length) {
Notification.exception({message: 'No cancel button found'});
}
};
ModalCancel.prototype = Object.create(Modal.prototype);
ModalCancel.prototype.constructor = ModalCancel;
}
/**
* Override parent implementation to prevent changing the footer content.
* Register all event listeners.
*/
ModalCancel.prototype.setFooter = function() {
Notification.exception({message: 'Can not change the footer of a cancel modal'});
return;
};
registerEventListeners() {
// Call the parent registration.
super.registerEventListeners();
/**
* Set up all of the event handling for the modal.
*
* @method registerEventListeners
*/
ModalCancel.prototype.registerEventListeners = function() {
// Apply parent event listeners.
Modal.prototype.registerEventListeners.call(this);
this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {
var cancelEvent = $.Event(ModalEvents.cancel);
this.getRoot().trigger(cancelEvent, this);
if (!cancelEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
};
return ModalCancel;
});
// Register to close on cancel.
this.registerCloseOnCancel();
}
}
+16 -2
View File
@@ -23,17 +23,18 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
'core/modal_save_cancel', 'core/modal_cancel',
'core/modal_save_cancel', 'core/modal_cancel', 'core/local/modal/alert',
'core/templates', 'core/notification', 'core/custom_interaction_events',
'core/pending'],
function($, ModalEvents, ModalRegistry, Modal, ModalSaveCancel,
ModalCancel, Templates, Notification, CustomEvents, Pending) {
ModalCancel, ModalAlert, Templates, Notification, CustomEvents, Pending) {
// The templates for each type of modal.
var TEMPLATES = {
DEFAULT: 'core/modal',
SAVE_CANCEL: 'core/modal_save_cancel',
CANCEL: 'core/modal_cancel',
ALERT: 'core/local/modal/alert',
};
// The available types of modals.
@@ -41,12 +42,14 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
DEFAULT: 'DEFAULT',
SAVE_CANCEL: 'SAVE_CANCEL',
CANCEL: 'CANCEL',
ALERT: 'ALERT',
};
// Register the common set of modals.
ModalRegistry.register(TYPES.DEFAULT, Modal, TEMPLATES.DEFAULT);
ModalRegistry.register(TYPES.SAVE_CANCEL, ModalSaveCancel, TEMPLATES.SAVE_CANCEL);
ModalRegistry.register(TYPES.CANCEL, ModalCancel, TEMPLATES.CANCEL);
ModalRegistry.register(TYPES.ALERT, ModalAlert, TEMPLATES.ALERT);
/**
* Set up the events required to show the modal and return focus when the modal
@@ -185,10 +188,21 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
modal.setFooter(modalConfig.footer);
}
if (modalConfig.buttons) {
Object.entries(modalConfig.buttons).forEach(function([key, value]) {
modal.setButtonText(key, value);
});
}
if (isLarge) {
modal.setLarge();
}
if (typeof modalConfig.removeOnClose !== 'undefined') {
// If configured remove the modal when hiding it.
modal.setRemoveOnClose(modalConfig.removeOnClose);
}
return modal;
});
+27 -64
View File
@@ -22,85 +22,48 @@
* @copyright 2016 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/modal', 'core/modal_events'],
function($, Notification, CustomEvents, Modal, ModalEvents) {
import Modal from 'core/modal';
var SELECTORS = {
SAVE_BUTTON: '[data-action="save"]',
CANCEL_BUTTON: '[data-action="cancel"]',
};
export default class extends Modal {
constructor(root) {
super(root);
/**
* Constructor for the Modal.
*
* @param {object} root The root jQuery element for the modal
*/
var ModalSaveCancel = function(root) {
Modal.call(this, root);
if (!this.getFooter().find(SELECTORS.SAVE_BUTTON).length) {
if (!this.getFooter().find(this.getActionSelector('save')).length) {
Notification.exception({message: 'No save button found'});
}
if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) {
if (!this.getFooter().find(this.getActionSelector('cancel')).length) {
Notification.exception({message: 'No cancel button found'});
}
};
}
ModalSaveCancel.prototype = Object.create(Modal.prototype);
ModalSaveCancel.prototype.constructor = ModalSaveCancel;
/**
* Register all event listeners.
*/
registerEventListeners() {
// Call the parent registration.
super.registerEventListeners();
// Register to close on save/cancel.
this.registerCloseOnSave();
this.registerCloseOnCancel();
}
/**
* Override parent implementation to prevent changing the footer content.
*/
ModalSaveCancel.prototype.setFooter = function() {
setFooter() {
Notification.exception({message: 'Can not change the footer of a save cancel modal'});
return;
};
}
/**
* Set up all of the event handling for the modal.
* Set the title of the save button.
*
* @method registerEventListeners
* @param {String|Promise} value The button text, or a Promise which will resolve it
* @returns{Promise}
*/
ModalSaveCancel.prototype.registerEventListeners = function() {
// Apply parent event listeners.
Modal.prototype.registerEventListeners.call(this);
this.getModal().on(CustomEvents.events.activate, SELECTORS.SAVE_BUTTON, function(e, data) {
var saveEvent = $.Event(ModalEvents.save);
this.getRoot().trigger(saveEvent, this);
if (!saveEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {
var cancelEvent = $.Event(ModalEvents.cancel);
this.getRoot().trigger(cancelEvent, this);
if (!cancelEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
};
/**
* Allows to overwrite the text of "Save changes" button.
*
* This method is overloaded to take either a string value for the button title or a jQuery promise that is resolved with
* text most commonly from a Str.get_string call.
*
* @param {(String|object)} value The button text, or a jQuery promise which will resolve it
*/
ModalSaveCancel.prototype.setSaveButtonText = function(value) {
var button = this.getFooter().find(SELECTORS.SAVE_BUTTON);
this.asyncSet(value, button.text.bind(button));
};
return ModalSaveCancel;
});
setSaveButtonText(value) {
return this.setButtonText('save', value);
}
}
+283 -260
View File
@@ -13,283 +13,306 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A system for displaying notifications to users from the session.
*
* Wrapper for the YUI M.core.notification class. Allows us to
* use the YUI version in AMD code until it is replaced.
*
* @module core/notification
* @class notification
* @package core
* @copyright 2015 Damyon Wiese <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 2.9
*/
define(['core/yui', 'jquery', 'core/log', 'core/pending'],
function(Y, $, log, Pending) {
var notificationModule = {
types: {
'success': 'core/notification_success',
'info': 'core/notification_info',
'warning': 'core/notification_warning',
'error': 'core/notification_error',
},
import Pending from 'core/pending';
import Log from 'core/log';
fieldName: 'user-notifications',
let currentContextId = M.cfg.contextid;
fetchNotifications: function() {
var pendingPromise = new Pending('core/notification:fetchNotifications');
const notificationTypes = {
success: 'core/notification_success',
info: 'core/notification_info',
warning: 'core/notification_warning',
error: 'core/notification_error',
};
require(['core/ajax'], function(ajax) {
var promises = ajax.call([{
methodname: 'core_fetch_notifications',
args: {
contextid: notificationModule.contextid
}
}]);
const notificationRegionId = 'user-notifications';
// This currently fails when not logged in.
// eslint-disable-next-line promise/catch-or-return
promises[0]
.then(notificationModule.addNotifications)
.always(pendingPromise.resolve);
});
},
const Selectors = {
notificationRegion: `#${notificationRegionId}`,
fallbackRegionParents: [
'#region-main',
'[role="main"]',
'body',
],
};
addNotifications: function(notifications) {
var pendingPromise = new Pending('core/notification:addNotifications');
const setupTargetRegion = () => {
let targetRegion = getNotificationRegion();
if (targetRegion) {
return false;
}
if (!notifications) {
notifications = [];
}
const newRegion = document.createElement('span');
newRegion.id = notificationRegionId;
$.each(notifications, function(i, notification) {
notificationModule.renderNotification(notification.template, notification.variables);
});
return Selectors.fallbackRegionParents.some(selector => {
const targetRegion = document.querySelector(selector);
pendingPromise.resolve();
},
setupTargetRegion: function() {
var targetRegion = $('#' + notificationModule.fieldName);
if (targetRegion.length) {
return false;
}
var newRegion = $('<span>').attr('id', notificationModule.fieldName);
targetRegion = $('#region-main');
if (targetRegion.length) {
return targetRegion.prepend(newRegion);
}
targetRegion = $('[role="main"]');
if (targetRegion.length) {
return targetRegion.prepend(newRegion);
}
targetRegion = $('body');
return targetRegion.prepend(newRegion);
},
addNotification: function(notification) {
var pendingPromise = new Pending('core/notification:addNotifications');
var template = notificationModule.types.error;
notification = $.extend({
closebutton: true,
announce: true,
type: 'error'
}, notification);
if (notification.template) {
template = notification.template;
delete notification.template;
} else if (notification.type) {
if (typeof notificationModule.types[notification.type] !== 'undefined') {
template = notificationModule.types[notification.type];
}
delete notification.type;
}
pendingPromise.resolve();
return notificationModule.renderNotification(template, notification);
},
renderNotification: function(template, variables) {
if (typeof variables.message === 'undefined' || !variables.message) {
log.debug('Notification received without content. Skipping.');
return;
}
var pendingPromise = new Pending('core/notification:renderNotification');
require(['core/templates'], function(templates) {
templates.render(template, variables)
.then(function(html, js) {
$('#' + notificationModule.fieldName).prepend(html);
templates.runTemplateJS(js);
return;
})
.always(pendingPromise.resolve)
.catch(notificationModule.exception);
});
},
alert: function(title, message, yesLabel) {
var pendingPromise = new Pending('core/notification:alert');
// Here we are wrapping YUI. This allows us to start transitioning, but
// wait for a good alternative without having inconsistent dialogues.
Y.use('moodle-core-notification-alert', function() {
var alert = new M.core.alert({
title: title,
message: message,
yesLabel: yesLabel
});
alert.show();
pendingPromise.resolve();
});
},
confirm: function(title, question, yesLabel, noLabel, yesCallback, noCallback) {
var pendingPromise = new Pending('core/notification:confirm');
// Here we are wrapping YUI. This allows us to start transitioning, but
// wait for a good alternative without having inconsistent dialogues.
Y.use('moodle-core-notification-confirm', function() {
var modal = new M.core.confirm({
title: title,
question: question,
yesLabel: yesLabel,
noLabel: noLabel
});
modal.on('complete-yes', function() {
yesCallback();
});
if (noCallback) {
modal.on('complete-no', function() {
noCallback();
});
}
modal.show();
pendingPromise.resolve();
});
},
exception: function(ex) {
var pendingPromise = new Pending('core/notification:addNotifications');
// Fudge some parameters.
if (typeof ex.stack == 'undefined') {
ex.stack = '';
}
if (ex.debuginfo) {
ex.stack += ex.debuginfo + '\n';
}
if (!ex.backtrace && ex.stacktrace) {
ex.backtrace = ex.stacktrace;
}
if (ex.backtrace) {
ex.stack += ex.backtrace;
var ln = ex.backtrace.match(/line ([^ ]*) of/);
var fn = ex.backtrace.match(/ of ([^:]*): /);
if (ln && ln[1]) {
ex.lineNumber = ln[1];
}
if (fn && fn[1]) {
ex.fileName = fn[1];
if (ex.fileName.length > 30) {
ex.fileName = '...' + ex.fileName.substr(ex.fileName.length - 27);
}
}
}
if (typeof ex.name == 'undefined' && ex.errorcode) {
ex.name = ex.errorcode;
}
Y.use('moodle-core-notification-exception', function() {
var modal = new M.core.exception(ex);
modal.show();
pendingPromise.resolve();
});
if (targetRegion) {
targetRegion.prepend(newRegion);
return true;
}
return false;
});
};
/**
* Poll the server for any new notifications.
*
* @returns {Promise}
*/
export const fetchNotifications = async() => {
const Ajax = await import('core/ajax');
return Ajax.call([{
methodname: 'core_fetch_notifications',
args: {
contextid: currentContextId
}
}])[0]
.then(addNotifications);
};
/**
* Add all of the supplied notifications.
*
* @param {Array} notifications The list of notificaitons
* @returns {Promise}
*/
const addNotifications = notifications => {
if (!notifications.length) {
return Promise.resolve();
}
const pendingPromise = new Pending('core/notification:addNotifications');
notifications.forEach(notification => renderNotification(notification.template, notification.variables));
return pendingPromise.resolve();
};
/**
* Add a notification to the page.
*
* Note: This does not cause the notification to be added to the session.
*
* @param {Object} notification The notification to add.
* @param {string} notification.message The body of the notification
* @param {string} notification.type The type of notification to add (error, warning, info, success).
* @param {Boolean} notification.closebutton Whether to show the close button.
* @param {Boolean} notification.announce Whether to announce to screen readers.
* @returns {Promise}
*/
export const addNotification = notification => {
const pendingPromise = new Pending('core/notification:addNotifications');
let template = notificationTypes.error;
notification = {
closebutton: true,
announce: true,
type: 'error',
...notification,
};
return /** @alias module:core/notification */{
init: function(contextid, notifications) {
notificationModule.contextid = contextid;
if (notification.template) {
template = notification.template;
delete notification.template;
} else if (notification.type) {
if (typeof notificationTypes[notification.type] !== 'undefined') {
template = notificationTypes[notification.type];
}
delete notification.type;
}
// Setup the message target region if it isn't setup already
notificationModule.setupTargetRegion();
return renderNotification(template, notification)
.then(pendingPromise.resolve);
};
// Add provided notifications.
notificationModule.addNotifications(notifications);
const renderNotification = async(template, variables) => {
if (typeof variables.message === 'undefined' || !variables.message) {
Log.debug('Notification received without content. Skipping.');
return;
}
// Poll for any new notifications.
notificationModule.fetchNotifications();
const pendingPromise = new Pending('core/notification:renderNotification');
const Templates = await import('core/templates');
Templates.renderForPromise(template, variables)
.then(({html, js = ''}) => {
Templates.prependNodeContents(getNotificationRegion(), html, js);
return;
})
.then(pendingPromise.resolve)
.catch(exception);
};
const getNotificationRegion = () => document.querySelector(Selectors.notificationRegion);
/**
* Alert dialogue.
*
* @param {String|Promise} title
* @param {String|Promise} message
* @param {String|Promise} cancelText
* @returns {Promise}
*/
export const alert = async(title, message, cancelText) => {
var pendingPromise = new Pending('core/notification:alert');
const ModalFactory = await import('core/modal_factory');
return ModalFactory.create({
type: ModalFactory.types.ALERT,
body: message,
title: title,
buttons: {
cancel: cancelText,
},
removeOnClose: true,
})
.then(function(modal) {
modal.show();
/**
* Poll the server for any new notifications.
*
* @method fetchNotifications
*/
fetchNotifications: notificationModule.fetchNotifications,
pendingPromise.resolve();
return modal;
});
};
/**
* Add a notification to the page.
*
* Note: This does not cause the notification to be added to the session.
*
* @method addNotification
* @param {Object} notification The notification to add.
* @param {string} notification.message The body of the notification
* @param {string} notification.type The type of notification to add (error, warning, info, success).
* @param {Boolean} notification.closebutton Whether to show the close button.
* @param {Boolean} notification.announce Whether to announce to screen readers.
*/
addNotification: notificationModule.addNotification,
/**
* The confirm has now been replaced with a save and cancel dialogue.
*
* @param {String|Promise} title
* @param {String|Promise} question
* @param {String|Promise} saveLabel
* @param {String|Promise} noLabel
* @param {String|Promise} saveCallback
* @param {String|Promise} cancelCallback
* @returns {Promise}
*/
export const confirm = (title, question, saveLabel, noLabel, saveCallback, cancelCallback) =>
saveCancel(title, question, saveLabel, saveCallback, cancelCallback);
/**
* Wrap M.core.alert.
*
* @method alert
* @param {string} title
* @param {string} message
* @param {string} yesLabel
*/
alert: notificationModule.alert,
/**
* The Save and Cancel dialogue helper.
*
* @param {String|Promise} title
* @param {String|Promise} question
* @param {String|Promise} saveLabel
* @param {String|Promise} saveCallback
* @param {String|Promise} cancelCallback
* @returns {Promise}
*/
export const saveCancel = async(title, question, saveLabel, saveCallback, cancelCallback) => {
const pendingPromise = new Pending('core/notification:confirm');
/**
* Wrap M.core.confirm.
*
* @method confirm
* @param {string} title
* @param {string} question
* @param {string} yesLabel
* @param {string} noLabel
* @param {function} yesCallback
* @param {function} noCallback Optional parameter to be called if the user presses cancel.
*/
confirm: notificationModule.confirm,
const [
ModalFactory,
ModalEvents,
] = await Promise.all([
import('core/modal_factory'),
import('core/modal_events'),
]);
/**
* Wrap M.core.exception.
*
* @method exception
* @param {Error} ex
*/
exception: notificationModule.exception
};
});
return ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: title,
body: question,
buttons: {
// Note: The noLabel is no longer supported.
save: saveLabel,
},
removeOnClose: true,
})
.then(function(modal) {
modal.show();
modal.getRoot().on(ModalEvents.save, saveCallback);
modal.getRoot().on(ModalEvents.cancel, cancelCallback);
pendingPromise.resolve();
return modal;
});
};
/**
* Wrap M.core.exception.
*
* @param {Error} ex
*/
export const exception = async ex => {
const pendingPromise = new Pending('core/notification:displayException');
// Fudge some parameters.
if (!ex.stack) {
ex.stack = '';
}
if (ex.debuginfo) {
ex.stack += ex.debuginfo + '\n';
}
if (!ex.backtrace && ex.stacktrace) {
ex.backtrace = ex.stacktrace;
}
if (ex.backtrace) {
ex.stack += ex.backtrace;
const ln = ex.backtrace.match(/line ([^ ]*) of/);
const fn = ex.backtrace.match(/ of ([^:]*): /);
if (ln && ln[1]) {
ex.lineNumber = ln[1];
}
if (fn && fn[1]) {
ex.fileName = fn[1];
if (ex.fileName.length > 30) {
ex.fileName = '...' + ex.fileName.substr(ex.fileName.length - 27);
}
}
}
if (typeof ex.name === 'undefined' && ex.errorcode) {
ex.name = ex.errorcode;
}
const Y = await import('core/yui');
Y.use('moodle-core-notification-exception', function() {
var modal = new M.core.exception(ex);
modal.show();
pendingPromise.resolve();
});
};
/**
* Initialise the page for the suppled context, and displaying the supplied notifications.
*
* @param {Number} contextId
* @param {Array} notificationList
*/
export const init = (contextId, notificationList) => {
currentContextId = contextId;
// Setup the message target region if it isn't setup already
setupTargetRegion();
// Add provided notifications.
addNotifications(notificationList);
// Perform an initial poll for any new notifications.
fetchNotifications();
};
// To maintain backwards compatability we export default here.
export default {
init,
fetchNotifications,
addNotification,
alert,
confirm,
saveCancel,
exception,
};
+45
View File
@@ -0,0 +1,45 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core/local/modal/alert
Moodle modal template with one oaky button.
The purpose of this template is to render an alert modal with an acceptance option.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* title A cleaned string (use clean_text()) to display.
* body HTML content for the boday
Example context (json):
{
"title": "Example cancel modal",
"body": "Some example content for the body"
}
}}
{{< core/modal }}
{{$footer}}
<button type="button" class="btn btn-primary" data-action="cancel">{{#str}}okay, moodle{{/str}}</button>
{{/footer}}
{{/ core/modal }}
+3
View File
@@ -49,6 +49,9 @@ information provided here is intended especially for developers.
* Implement a more direct xsendfile_file() method for an alternative_file_system_class
* A new `dynamic` table interface has been defined, which allows any `flexible_table` to be converted into a table which
is updatable via ajax calls. See MDL-68495 and `\core_table\dynamic` for further information.
* The core/notification module has been updated to use AMD modals for its confirmation and alert dialogues.
The confirmation dialogue no longer has a configurable "No" button as per similar changes in MDL-59759.
This set of confirmation modals was unintentionally missed from that deprecation process.
=== 3.8 ===
* Add CLI option to notify all cron tasks to stop: admin/cli/cron.php --stop
@@ -56,7 +56,7 @@ Feature: In an assignment, teacher can view the feedback for a previous attempt.
And I should see "The changes to the grade and feedback were saved"
And I press "Ok"
And I follow "View a different attempt"
And I click on "//div[contains(@class, 'moodle-dialogue-bd')]//label[2]" "xpath_element"
And I click on "Attempt 1" "radio" in the "View a different attempt" "dialogue"
And I press "View"
And I wait until the page is ready
And I should see "You are editing the feedback for a previous attempt. This is attempt 1 out of 2."
@@ -60,7 +60,7 @@ Feature: In an assignment, teachers can edit feedback for a students previous su
And I navigate to "View all submissions" in current page administration
And I click on "Grade" "link" in the "Student 2" "table_row"
And I click on "View a different attempt" "link"
And I click on "//div[contains(concat(' ', normalize-space(@class), ' '), ' confirmation-dialogue ')]//input[@value='0']" "xpath_element"
And I click on "Attempt 1" "radio" in the "View a different attempt" "dialogue"
And I click on "View" "button"
And I set the following fields to these values:
| Grade | 50 |
+2 -2
View File
@@ -53,7 +53,7 @@ Feature: Manager is able to delete tags
And I follow "Default collection"
And I click on "Delete" "link" in the "Turtle" "table_row"
Then I should see "Are you sure you want to delete this tag?"
And I press "No"
And I click on "Cancel" "button" in the "Delete" "dialogue"
And I should not see "Tag(s) deleted"
And I should see "Turtle"
And I click on "Delete" "link" in the "Dog" "table_row"
@@ -81,7 +81,7 @@ Feature: Manager is able to delete tags
| Select tag Cat | 1 |
And I press "Delete selected"
And I should see "Are you sure you want to delete selected tags?"
And I press "No"
And I click on "Cancel" "button" in the "Delete" "dialogue"
And I should not see "Tag(s) deleted"
And I should see "Cat"
And I set the following fields to these values: