From f2d033a2bb209985d2d9df0b00ecc3a7ad4226a8 Mon Sep 17 00:00:00 2001 From: Mathew May Date: Wed, 29 Apr 2020 17:14:38 +0800 Subject: [PATCH] MDL-68529 course: Refactor chooser to include loading --- course/amd/build/activitychooser.min.js | 2 +- course/amd/build/activitychooser.min.js.map | 2 +- .../local/activitychooser/dialogue.min.js | 2 +- .../local/activitychooser/dialogue.min.js.map | 2 +- course/amd/src/activitychooser.js | 53 +++++++----- .../amd/src/local/activitychooser/dialogue.js | 81 ++++++++++--------- lib/amd/build/modal.min.js | 2 +- lib/amd/build/modal.min.js.map | 2 +- lib/amd/src/modal.js | 3 + theme/boost/scss/moodle/core.scss | 8 +- theme/boost/style/moodle.css | 9 ++- theme/classic/style/moodle.css | 9 ++- 12 files changed, 103 insertions(+), 72 deletions(-) diff --git a/course/amd/build/activitychooser.min.js b/course/amd/build/activitychooser.min.js index d9441d48744..2d78a9d01fa 100644 --- a/course/amd/build/activitychooser.min.js +++ b/course/amd/build/activitychooser.min.js @@ -1,2 +1,2 @@ -define ("core_course/activitychooser",["exports","core_course/local/activitychooser/dialogue","core_course/local/activitychooser/repository","core_course/local/activitychooser/selectors","core/custom_interaction_events","core/templates","core/modal_factory","core/str","core/pending"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=k(b);c=k(c);d=j(d);e=j(e);f=k(f);g=k(g);i=j(i);function j(a){return a&&a.__esModule?a:{default:a}}function k(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function l(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function m(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){l(h,d,e,f,g,"next",a)}function g(a){l(h,d,e,f,g,"throw",a)}f(void 0)})}}var n=function(a){var b=new i.default;o(a);b.resolve()};a.init=n;var o=function(a){var f=["click",e.default.events.activate,e.default.events.keyboardActivate],g=function(){var b=null;return function(){if(!b){b=new Promise(function(b){b(c.activityModules(a))})}return b}}();e.default.define(document,f);f.forEach(function(a){document.addEventListener(a,function(){var a=m(regeneratorRuntime.mark(function a(c){var e,f,h,i,j,k,l;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:if(!c.target.closest(d.default.elements.sectionmodchooser)){a.next=13;break}a.next=3;return g();case 3:e=a.sent;f=c.target.closest(d.default.elements.section);h=c.target.closest(d.default.elements.sectionmodchooser);i=f||h;j=u(e,i.dataset.sectionid);k=p(e,i.dataset.sectionid);a.next=11;return q(k);case 11:l=a.sent;b.displayChooser(i,l,k,j);case 13:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}())})},p=function(a,b){var c=JSON.parse(JSON.stringify(a));c.content_items.forEach(function(a){a.link+="§ion="+b});return c.content_items},q=function(a){return s(r(a))},r=function(a){var b=a.filter(function(a){return!0===a.favourite}),c=a.filter(function(a){return!0===a.recommended}),d=!!b.length,e=!!(c.length&&!1===d);return{default:a,favourites:b,recommended:c,favouritesFirst:d,recommendedFirst:e,fallback:!1===d&&!1===e}},s=function(a){return g.create({type:g.types.DEFAULT,title:(0,h.get_string)("addresourceoractivity"),body:f.render("core_course/activitychooser",a),large:!0,templateContext:{classes:"modchooser"}})},t=function(a,b){a.tabIndex=-1;a.classList.add("d-none");if(a.classList.contains("active")){a.classList.remove("active");a.setAttribute("aria-selected","false");var f=b.querySelector(d.default.regions.favouriteTab);f.classList.remove("active");var c=b.querySelector(d.default.regions.recommendedTabNav),e=b.querySelector(d.default.regions.defaultTabNav);if(!1===c.classList.contains("d-none")){c.classList.add("active");c.setAttribute("aria-selected","true");c.tabIndex=0;c.focus();var g=b.querySelector(d.default.regions.recommendedTab);g.classList.add("active")}else{e.classList.add("active");e.setAttribute("aria-selected","true");e.tabIndex=0;e.focus();var h=b.querySelector(d.default.regions.defaultTab);h.classList.add("active")}}},u=function(a,b){return function(){var c=m(regeneratorRuntime.mark(function c(e,g,h){var i,j,k,l,m,n,o,q,r,s,u;return regeneratorRuntime.wrap(function(c){while(1){switch(c.prev=c.next){case 0:i=h.querySelector(d.default.render.favourites);j=h.querySelectorAll("[data-internal=\"".concat(e,"\"] ").concat(d.default.actions.optionActions.manageFavourite));k=h.querySelector(d.default.regions.favouriteTabNav);l=a.content_items.find(function(a){var b=a.name;return b===e});m={};if(!l){c.next=27;break}if(!g){c.next=21;break}l.favourite=!0;m.content_items=a.content_items.filter(function(a){return!0===a.favourite});n=p(m,b);c.next=12;return f.renderForPromise("core_course/local/activitychooser/favourites",{favourites:n});case 12:o=c.sent;q=o.html;r=o.js;c.next=17;return f.replaceNodeContents(i,q,r);case 17:Array.from(j).forEach(function(a){a.classList.remove("text-muted");a.classList.add("text-primary");a.dataset.favourited="true";a.setAttribute("aria-pressed",!0);a.firstElementChild.classList.remove("fa-star-o");a.firstElementChild.classList.add("fa-star")});k.classList.remove("d-none");c.next=27;break;case 21:l.favourite=!1;s=i.querySelector("[data-internal=\"".concat(e,"\"]"));s.parentNode.removeChild(s);Array.from(j).forEach(function(a){a.classList.add("text-muted");a.classList.remove("text-primary");a.dataset.favourited="false";a.setAttribute("aria-pressed",!1);a.firstElementChild.classList.remove("fa-star");a.firstElementChild.classList.add("fa-star-o")});u=a.content_items.filter(function(a){return!0===a.favourite});if(0===u.length){t(k,h)}case 27:case"end":return c.stop();}}},c)}));return function(){return c.apply(this,arguments)}}()}}); +define ("core_course/activitychooser",["exports","core_course/local/activitychooser/dialogue","core_course/local/activitychooser/repository","core_course/local/activitychooser/selectors","core/custom_interaction_events","core/templates","core/modal_factory","core/str","core/pending"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=k(b);c=k(c);d=j(d);e=j(e);f=k(f);g=k(g);i=j(i);function j(a){return a&&a.__esModule?a:{default:a}}function k(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function l(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function m(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){l(h,d,e,f,g,"next",a)}function g(a){l(h,d,e,f,g,"throw",a)}f(void 0)})}}var n=function(a){var b=new i.default;o(a);b.resolve()};a.init=n;var o=function(a){var g=["click",e.default.events.activate,e.default.events.keyboardActivate],h=function(){var b=null;return function(){if(!b){b=new Promise(function(b){b(c.activityModules(a))})}return b}}();e.default.define(document,g);g.forEach(function(a){document.addEventListener(a,function(){var a=m(regeneratorRuntime.mark(function a(c){var e,g,i,j,k,l,m,n;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:if(!c.target.closest(d.default.elements.sectionmodchooser)){a.next=16;break}e=c.target.closest(d.default.elements.section);g=c.target.closest(d.default.elements.sectionmodchooser);i=e||g;k=new Promise(function(a){j=a});l=r(k);a.next=8;return h();case 8:m=a.sent;n=p(m,i.dataset.sectionid);b.displayChooser(l,n,t(m,i.dataset.sectionid));a.t0=j;a.next=14;return f.render("core_course/activitychooser",q(n));case 14:a.t1=a.sent;(0,a.t0)(a.t1);case 16:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}())})},p=function(a,b){var c=JSON.parse(JSON.stringify(a));c.content_items.forEach(function(a){a.link+="§ion="+b});return c.content_items},q=function(a){var b=a.filter(function(a){return!0===a.favourite}),c=a.filter(function(a){return!0===a.recommended}),d=!!b.length,e=!!(c.length&&!1===d);return{default:a,favourites:b,recommended:c,favouritesFirst:d,recommendedFirst:e,fallback:!1===d&&!1===e}},r=function(a){return g.create({type:g.types.DEFAULT,title:(0,h.get_string)("addresourceoractivity"),body:a,large:!0,templateContext:{classes:"modchooser"}}).then(function(a){a.show();return a})},s=function(a,b){a.tabIndex=-1;a.classList.add("d-none");if(a.classList.contains("active")){a.classList.remove("active");a.setAttribute("aria-selected","false");var f=b.querySelector(d.default.regions.favouriteTab);f.classList.remove("active");var c=b.querySelector(d.default.regions.recommendedTabNav),e=b.querySelector(d.default.regions.defaultTabNav);if(!1===c.classList.contains("d-none")){c.classList.add("active");c.setAttribute("aria-selected","true");c.tabIndex=0;c.focus();var g=b.querySelector(d.default.regions.recommendedTab);g.classList.add("active")}else{e.classList.add("active");e.setAttribute("aria-selected","true");e.tabIndex=0;e.focus();var h=b.querySelector(d.default.regions.defaultTab);h.classList.add("active")}}},t=function(a,b){return function(){var c=m(regeneratorRuntime.mark(function c(e,g,h){var i,j,k,l,m,n,o,q,r,t,u;return regeneratorRuntime.wrap(function(c){while(1){switch(c.prev=c.next){case 0:i=h.querySelector(d.default.render.favourites);j=h.querySelectorAll("[data-internal=\"".concat(e,"\"] ").concat(d.default.actions.optionActions.manageFavourite));k=h.querySelector(d.default.regions.favouriteTabNav);l=a.content_items.find(function(a){var b=a.name;return b===e});m={};if(!l){c.next=27;break}if(!g){c.next=21;break}l.favourite=!0;m.content_items=a.content_items.filter(function(a){return!0===a.favourite});n=p(m,b);c.next=12;return f.renderForPromise("core_course/local/activitychooser/favourites",{favourites:n});case 12:o=c.sent;q=o.html;r=o.js;c.next=17;return f.replaceNodeContents(i,q,r);case 17:Array.from(j).forEach(function(a){a.classList.remove("text-muted");a.classList.add("text-primary");a.dataset.favourited="true";a.setAttribute("aria-pressed",!0);a.firstElementChild.classList.remove("fa-star-o");a.firstElementChild.classList.add("fa-star")});k.classList.remove("d-none");c.next=27;break;case 21:l.favourite=!1;t=i.querySelector("[data-internal=\"".concat(e,"\"]"));t.parentNode.removeChild(t);Array.from(j).forEach(function(a){a.classList.add("text-muted");a.classList.remove("text-primary");a.dataset.favourited="false";a.setAttribute("aria-pressed",!1);a.firstElementChild.classList.remove("fa-star");a.firstElementChild.classList.add("fa-star-o")});u=a.content_items.filter(function(a){return!0===a.favourite});if(0===u.length){s(k,h)}case 27:case"end":return c.stop();}}},c)}));return function(){return c.apply(this,arguments)}}()}}); //# sourceMappingURL=activitychooser.min.js.map diff --git a/course/amd/build/activitychooser.min.js.map b/course/amd/build/activitychooser.min.js.map index 3348e197e9b..33594e04d36 100644 --- a/course/amd/build/activitychooser.min.js.map +++ b/course/amd/build/activitychooser.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/activitychooser.js"],"names":["init","courseId","pendingPromise","Pending","registerListenerEvents","resolve","events","CustomEvents","activate","keyboardActivate","fetchModuleData","innerPromise","Promise","Repository","activityModules","define","document","forEach","event","addEventListener","e","target","closest","selectors","elements","sectionmodchooser","data","sectionDiv","section","button","caller","favouriteFunction","partiallyAppliedFavouriteManager","dataset","sectionid","builtModuleData","sectionIdMapper","modalBuilder","sectionModal","ChooserDialogue","displayChooser","webServiceData","id","newData","JSON","parse","stringify","content_items","module","link","buildModal","templateDataBuilder","favourites","filter","mod","favourite","recommended","favouritesFirst","length","recommendedFirst","fallback","ModalFactory","create","type","types","DEFAULT","title","body","Templates","render","large","templateContext","classes","nullFavouriteDomManager","favouriteTabNav","modalBody","tabIndex","classList","add","contains","remove","setAttribute","favouriteTab","querySelector","regions","recommendedTabNav","defaultTabNav","focus","recommendedTab","defaultTab","moduleData","sectionId","internal","favouriteArea","favouriteButtons","querySelectorAll","actions","optionActions","manageFavourite","result","find","name","newFaves","builtFaves","renderForPromise","html","js","replaceNodeContents","Array","from","element","favourited","firstElementChild","nodeToRemove","parentNode","removeChild"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A type of dialogue used as for choosing modules in a course.\n *\n * @module core_course/activitychooser\n * @package core_course\n * @copyright 2020 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as ChooserDialogue from 'core_course/local/activitychooser/dialogue';\nimport * as Repository from 'core_course/local/activitychooser/repository';\nimport selectors from 'core_course/local/activitychooser/selectors';\nimport CustomEvents from 'core/custom_interaction_events';\nimport * as Templates from 'core/templates';\nimport * as ModalFactory from 'core/modal_factory';\nimport {get_string as getString} from 'core/str';\nimport Pending from 'core/pending';\n\n/**\n * Set up the activity chooser.\n *\n * @method init\n * @param {Number} courseId Course ID to use later on in fetchModules()\n */\nexport const init = courseId => {\n const pendingPromise = new Pending();\n\n registerListenerEvents(courseId);\n\n pendingPromise.resolve();\n};\n\n/**\n * Once a selection has been made make the modal & module information and pass it along\n *\n * @method registerListenerEvents\n * @param {Number} courseId\n */\nconst registerListenerEvents = (courseId) => {\n const events = [\n 'click',\n CustomEvents.events.activate,\n CustomEvents.events.keyboardActivate\n ];\n\n const fetchModuleData = (() => {\n let innerPromise = null;\n\n return () => {\n if (!innerPromise) {\n innerPromise = new Promise((resolve) => {\n resolve(Repository.activityModules(courseId));\n });\n }\n\n return innerPromise;\n };\n })();\n\n CustomEvents.define(document, events);\n\n // Display module chooser event listeners.\n events.forEach((event) => {\n document.addEventListener(event, async(e) => {\n if (e.target.closest(selectors.elements.sectionmodchooser)) {\n const data = await fetchModuleData();\n // We need to know who called this.\n // Standard courses use the ID in the main section info.\n const sectionDiv = e.target.closest(selectors.elements.section);\n // Front page courses need some special handling.\n const button = e.target.closest(selectors.elements.sectionmodchooser);\n // If we don't have a section ID use the fallback ID.\n const caller = sectionDiv || button;\n const favouriteFunction = partiallyAppliedFavouriteManager(data, caller.dataset.sectionid);\n const builtModuleData = sectionIdMapper(data, caller.dataset.sectionid);\n const sectionModal = await modalBuilder(builtModuleData);\n\n ChooserDialogue.displayChooser(caller, sectionModal, builtModuleData, favouriteFunction);\n }\n });\n });\n};\n\n/**\n * Given the web service data and an ID we want to make a deep copy\n * of the WS data then add on the section ID to the addoption URL\n *\n * @method sectionIdMapper\n * @param {Object} webServiceData Our original data from the Web service call\n * @param {Array} id The ID of the section we need to append to the links\n * @return {Array} [modules] with URL's built\n */\nconst sectionIdMapper = (webServiceData, id) => {\n // We need to take a fresh deep copy of the original data as an object is a reference type.\n const newData = JSON.parse(JSON.stringify(webServiceData));\n newData.content_items.forEach((module) => {\n module.link += '§ion=' + id;\n });\n return newData.content_items;\n};\n\n/**\n * Build a modal on demand to save page load times\n *\n * @method modalBuilder\n * @param {Array} data our array of modules with section ID's applied in the URL field\n * @return {Object} Our modal that we are going to show the user\n */\nconst modalBuilder = data => buildModal(templateDataBuilder(data));\n\n/**\n * Given an array of modules we want to figure out where & how to place them into our template object\n *\n * @method templateDataBuilder\n * @param {Array} data our modules to manipulate into a Templatable object\n * @return {Object} Our built object ready to render out\n */\nconst templateDataBuilder = (data) => {\n // Filter the incoming data to find favourite & recommended modules.\n const favourites = data.filter(mod => mod.favourite === true);\n const recommended = data.filter(mod => mod.recommended === true);\n\n // Given the results of the above filters lets figure out what tab to set active.\n\n // We have some favourites.\n const favouritesFirst = !!favourites.length;\n // Check if we have no favourites but have some recommended.\n const recommendedFirst = !!(recommended.length && favouritesFirst === false);\n // We have nothing fallback to show all modules.\n const fallback = favouritesFirst === false && recommendedFirst === false;\n\n return {\n 'default': data,\n favourites: favourites,\n recommended: recommended,\n favouritesFirst: favouritesFirst,\n recommendedFirst: recommendedFirst,\n fallback: fallback,\n };\n};\n\n/**\n * Given an object we want to build a modal ready to show\n *\n * @method buildModal\n * @param {Object} data The template data which contains arrays of modules\n * @return {Object} The modal for the calling section with everything already set up\n */\nconst buildModal = data => {\n return ModalFactory.create({\n type: ModalFactory.types.DEFAULT,\n title: getString('addresourceoractivity'),\n body: Templates.render('core_course/activitychooser', data),\n large: true,\n templateContext: {\n classes: 'modchooser'\n }\n });\n};\n\n/**\n * A small helper function to handle the case where there are no more favourites\n * and we need to mess a bit with the available tabs in the chooser\n *\n * @method nullFavouriteDomManager\n * @param {HTMLElement} favouriteTabNav Dom node of the favourite tab nav\n * @param {HTMLElement} modalBody Our current modals' body\n */\nconst nullFavouriteDomManager = (favouriteTabNav, modalBody) => {\n favouriteTabNav.tabIndex = -1;\n favouriteTabNav.classList.add('d-none');\n // Need to set active to an available tab.\n if (favouriteTabNav.classList.contains('active')) {\n favouriteTabNav.classList.remove('active');\n favouriteTabNav.setAttribute('aria-selected', 'false');\n const favouriteTab = modalBody.querySelector(selectors.regions.favouriteTab);\n favouriteTab.classList.remove('active');\n const recommendedTabNav = modalBody.querySelector(selectors.regions.recommendedTabNav);\n const defaultTabNav = modalBody.querySelector(selectors.regions.defaultTabNav);\n if (recommendedTabNav.classList.contains('d-none') === false) {\n recommendedTabNav.classList.add('active');\n recommendedTabNav.setAttribute('aria-selected', 'true');\n recommendedTabNav.tabIndex = 0;\n recommendedTabNav.focus();\n const recommendedTab = modalBody.querySelector(selectors.regions.recommendedTab);\n recommendedTab.classList.add('active');\n } else {\n defaultTabNav.classList.add('active');\n defaultTabNav.setAttribute('aria-selected', 'true');\n defaultTabNav.tabIndex = 0;\n defaultTabNav.focus();\n const defaultTab = modalBody.querySelector(selectors.regions.defaultTab);\n defaultTab.classList.add('active');\n }\n\n }\n};\n\n/**\n * Export a curried function where the builtModules has been applied.\n * We have our array of modules so we can rerender the favourites area and have all of the items sorted.\n *\n * @method partiallyAppliedFavouriteManager\n * @param {Array} moduleData This is our raw WS data that we need to manipulate\n * @param {Number} sectionId We need this to add the sectionID to the URL's in the faves area after rerender\n * @return {Function} partially applied function so we can manipulate DOM nodes easily & update our internal array\n */\nconst partiallyAppliedFavouriteManager = (moduleData, sectionId) => {\n /**\n * Curried function that is being returned.\n *\n * @param {String} internal Internal name of the module to manage\n * @param {Boolean} favourite Is the caller adding a favourite or removing one?\n * @param {HTMLElement} modalBody What we need to update whilst we are here\n */\n return async(internal, favourite, modalBody) => {\n const favouriteArea = modalBody.querySelector(selectors.render.favourites);\n\n // eslint-disable-next-line max-len\n const favouriteButtons = modalBody.querySelectorAll(`[data-internal=\"${internal}\"] ${selectors.actions.optionActions.manageFavourite}`);\n const favouriteTabNav = modalBody.querySelector(selectors.regions.favouriteTabNav);\n const result = moduleData.content_items.find(({name}) => name === internal);\n const newFaves = {};\n if (result) {\n if (favourite) {\n result.favourite = true;\n\n newFaves.content_items = moduleData.content_items.filter(mod => mod.favourite === true);\n\n const builtFaves = sectionIdMapper(newFaves, sectionId);\n\n const {html, js} = await Templates.renderForPromise('core_course/local/activitychooser/favourites',\n {favourites: builtFaves});\n\n await Templates.replaceNodeContents(favouriteArea, html, js);\n\n Array.from(favouriteButtons).forEach((element) => {\n element.classList.remove('text-muted');\n element.classList.add('text-primary');\n element.dataset.favourited = 'true';\n element.setAttribute('aria-pressed', true);\n element.firstElementChild.classList.remove('fa-star-o');\n element.firstElementChild.classList.add('fa-star');\n });\n\n favouriteTabNav.classList.remove('d-none');\n } else {\n result.favourite = false;\n\n const nodeToRemove = favouriteArea.querySelector(`[data-internal=\"${internal}\"]`);\n\n nodeToRemove.parentNode.removeChild(nodeToRemove);\n\n Array.from(favouriteButtons).forEach((element) => {\n element.classList.add('text-muted');\n element.classList.remove('text-primary');\n element.dataset.favourited = 'false';\n element.setAttribute('aria-pressed', false);\n element.firstElementChild.classList.remove('fa-star');\n element.firstElementChild.classList.add('fa-star-o');\n });\n const newFaves = moduleData.content_items.filter(mod => mod.favourite === true);\n\n if (newFaves.length === 0) {\n nullFavouriteDomManager(favouriteTabNav, modalBody);\n }\n }\n }\n };\n};\n"],"file":"activitychooser.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/activitychooser.js"],"names":["init","courseId","pendingPromise","Pending","registerListenerEvents","resolve","events","CustomEvents","activate","keyboardActivate","fetchModuleData","innerPromise","Promise","Repository","activityModules","define","document","forEach","event","addEventListener","e","target","closest","selectors","elements","sectionmodchooser","sectionDiv","section","button","caller","bodyPromise","bodyPromiseResolver","sectionModal","buildModal","data","builtModuleData","sectionIdMapper","dataset","sectionid","ChooserDialogue","displayChooser","partiallyAppliedFavouriteManager","Templates","render","templateDataBuilder","webServiceData","id","newData","JSON","parse","stringify","content_items","module","link","favourites","filter","mod","favourite","recommended","favouritesFirst","length","recommendedFirst","fallback","ModalFactory","create","type","types","DEFAULT","title","body","large","templateContext","classes","then","modal","show","nullFavouriteDomManager","favouriteTabNav","modalBody","tabIndex","classList","add","contains","remove","setAttribute","favouriteTab","querySelector","regions","recommendedTabNav","defaultTabNav","focus","recommendedTab","defaultTab","moduleData","sectionId","internal","favouriteArea","favouriteButtons","querySelectorAll","actions","optionActions","manageFavourite","result","find","name","newFaves","builtFaves","renderForPromise","html","js","replaceNodeContents","Array","from","element","favourited","firstElementChild","nodeToRemove","parentNode","removeChild"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A type of dialogue used as for choosing modules in a course.\n *\n * @module core_course/activitychooser\n * @package core_course\n * @copyright 2020 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as ChooserDialogue from 'core_course/local/activitychooser/dialogue';\nimport * as Repository from 'core_course/local/activitychooser/repository';\nimport selectors from 'core_course/local/activitychooser/selectors';\nimport CustomEvents from 'core/custom_interaction_events';\nimport * as Templates from 'core/templates';\nimport * as ModalFactory from 'core/modal_factory';\nimport {get_string as getString} from 'core/str';\nimport Pending from 'core/pending';\n\n/**\n * Set up the activity chooser.\n *\n * @method init\n * @param {Number} courseId Course ID to use later on in fetchModules()\n */\nexport const init = courseId => {\n const pendingPromise = new Pending();\n\n registerListenerEvents(courseId);\n\n pendingPromise.resolve();\n};\n\n/**\n * Once a selection has been made make the modal & module information and pass it along\n *\n * @method registerListenerEvents\n * @param {Number} courseId\n */\nconst registerListenerEvents = (courseId) => {\n const events = [\n 'click',\n CustomEvents.events.activate,\n CustomEvents.events.keyboardActivate\n ];\n\n const fetchModuleData = (() => {\n let innerPromise = null;\n\n return () => {\n if (!innerPromise) {\n innerPromise = new Promise((resolve) => {\n resolve(Repository.activityModules(courseId));\n });\n }\n\n return innerPromise;\n };\n })();\n\n CustomEvents.define(document, events);\n\n // Display module chooser event listeners.\n events.forEach((event) => {\n document.addEventListener(event, async(e) => {\n if (e.target.closest(selectors.elements.sectionmodchooser)) {\n // We need to know who called this.\n // Standard courses use the ID in the main section info.\n const sectionDiv = e.target.closest(selectors.elements.section);\n // Front page courses need some special handling.\n const button = e.target.closest(selectors.elements.sectionmodchooser);\n // If we don't have a section ID use the fallback ID.\n const caller = sectionDiv || button;\n\n // We want to show the modal instantly but loading whilst waiting for our data.\n let bodyPromiseResolver;\n const bodyPromise = new Promise(resolve => {\n bodyPromiseResolver = resolve;\n });\n\n const sectionModal = buildModal(bodyPromise);\n\n // Now we have a modal we should start fetching data.\n const data = await fetchModuleData();\n\n // Apply the section id to all the module instance links.\n const builtModuleData = sectionIdMapper(data, caller.dataset.sectionid);\n\n ChooserDialogue.displayChooser(\n sectionModal,\n builtModuleData,\n partiallyAppliedFavouriteManager(data, caller.dataset.sectionid),\n );\n\n bodyPromiseResolver(await Templates.render(\n 'core_course/activitychooser',\n templateDataBuilder(builtModuleData)\n ));\n }\n });\n });\n};\n\n/**\n * Given the web service data and an ID we want to make a deep copy\n * of the WS data then add on the section ID to the addoption URL\n *\n * @method sectionIdMapper\n * @param {Object} webServiceData Our original data from the Web service call\n * @param {Number} id The ID of the section we need to append to the links\n * @return {Array} [modules] with URL's built\n */\nconst sectionIdMapper = (webServiceData, id) => {\n // We need to take a fresh deep copy of the original data as an object is a reference type.\n const newData = JSON.parse(JSON.stringify(webServiceData));\n newData.content_items.forEach((module) => {\n module.link += '§ion=' + id;\n });\n return newData.content_items;\n};\n\n/**\n * Given an array of modules we want to figure out where & how to place them into our template object\n *\n * @method templateDataBuilder\n * @param {Array} data our modules to manipulate into a Templatable object\n * @return {Object} Our built object ready to render out\n */\nconst templateDataBuilder = (data) => {\n // Filter the incoming data to find favourite & recommended modules.\n const favourites = data.filter(mod => mod.favourite === true);\n const recommended = data.filter(mod => mod.recommended === true);\n\n // Given the results of the above filters lets figure out what tab to set active.\n\n // We have some favourites.\n const favouritesFirst = !!favourites.length;\n // Check if we have no favourites but have some recommended.\n const recommendedFirst = !!(recommended.length && favouritesFirst === false);\n // We have nothing fallback to show all modules.\n const fallback = favouritesFirst === false && recommendedFirst === false;\n\n return {\n 'default': data,\n favourites: favourites,\n recommended: recommended,\n favouritesFirst: favouritesFirst,\n recommendedFirst: recommendedFirst,\n fallback: fallback,\n };\n};\n\n/**\n * Given an object we want to build a modal ready to show\n *\n * @method buildModal\n * @param {Promise} bodyPromise\n * @return {Object} The modal ready to display immediately and render body in later.\n */\nconst buildModal = bodyPromise => {\n return ModalFactory.create({\n type: ModalFactory.types.DEFAULT,\n title: getString('addresourceoractivity'),\n body: bodyPromise,\n large: true,\n templateContext: {\n classes: 'modchooser'\n }\n })\n .then(modal => {\n modal.show();\n return modal;\n });\n};\n\n/**\n * A small helper function to handle the case where there are no more favourites\n * and we need to mess a bit with the available tabs in the chooser\n *\n * @method nullFavouriteDomManager\n * @param {HTMLElement} favouriteTabNav Dom node of the favourite tab nav\n * @param {HTMLElement} modalBody Our current modals' body\n */\nconst nullFavouriteDomManager = (favouriteTabNav, modalBody) => {\n favouriteTabNav.tabIndex = -1;\n favouriteTabNav.classList.add('d-none');\n // Need to set active to an available tab.\n if (favouriteTabNav.classList.contains('active')) {\n favouriteTabNav.classList.remove('active');\n favouriteTabNav.setAttribute('aria-selected', 'false');\n const favouriteTab = modalBody.querySelector(selectors.regions.favouriteTab);\n favouriteTab.classList.remove('active');\n const recommendedTabNav = modalBody.querySelector(selectors.regions.recommendedTabNav);\n const defaultTabNav = modalBody.querySelector(selectors.regions.defaultTabNav);\n if (recommendedTabNav.classList.contains('d-none') === false) {\n recommendedTabNav.classList.add('active');\n recommendedTabNav.setAttribute('aria-selected', 'true');\n recommendedTabNav.tabIndex = 0;\n recommendedTabNav.focus();\n const recommendedTab = modalBody.querySelector(selectors.regions.recommendedTab);\n recommendedTab.classList.add('active');\n } else {\n defaultTabNav.classList.add('active');\n defaultTabNav.setAttribute('aria-selected', 'true');\n defaultTabNav.tabIndex = 0;\n defaultTabNav.focus();\n const defaultTab = modalBody.querySelector(selectors.regions.defaultTab);\n defaultTab.classList.add('active');\n }\n\n }\n};\n\n/**\n * Export a curried function where the builtModules has been applied.\n * We have our array of modules so we can rerender the favourites area and have all of the items sorted.\n *\n * @method partiallyAppliedFavouriteManager\n * @param {Array} moduleData This is our raw WS data that we need to manipulate\n * @param {Number} sectionId We need this to add the sectionID to the URL's in the faves area after rerender\n * @return {Function} partially applied function so we can manipulate DOM nodes easily & update our internal array\n */\nconst partiallyAppliedFavouriteManager = (moduleData, sectionId) => {\n /**\n * Curried function that is being returned.\n *\n * @param {String} internal Internal name of the module to manage\n * @param {Boolean} favourite Is the caller adding a favourite or removing one?\n * @param {HTMLElement} modalBody What we need to update whilst we are here\n */\n return async(internal, favourite, modalBody) => {\n const favouriteArea = modalBody.querySelector(selectors.render.favourites);\n\n // eslint-disable-next-line max-len\n const favouriteButtons = modalBody.querySelectorAll(`[data-internal=\"${internal}\"] ${selectors.actions.optionActions.manageFavourite}`);\n const favouriteTabNav = modalBody.querySelector(selectors.regions.favouriteTabNav);\n const result = moduleData.content_items.find(({name}) => name === internal);\n const newFaves = {};\n if (result) {\n if (favourite) {\n result.favourite = true;\n\n // eslint-disable-next-line camelcase\n newFaves.content_items = moduleData.content_items.filter(mod => mod.favourite === true);\n\n const builtFaves = sectionIdMapper(newFaves, sectionId);\n\n const {html, js} = await Templates.renderForPromise('core_course/local/activitychooser/favourites',\n {favourites: builtFaves});\n\n await Templates.replaceNodeContents(favouriteArea, html, js);\n\n Array.from(favouriteButtons).forEach((element) => {\n element.classList.remove('text-muted');\n element.classList.add('text-primary');\n element.dataset.favourited = 'true';\n element.setAttribute('aria-pressed', true);\n element.firstElementChild.classList.remove('fa-star-o');\n element.firstElementChild.classList.add('fa-star');\n });\n\n favouriteTabNav.classList.remove('d-none');\n } else {\n result.favourite = false;\n\n const nodeToRemove = favouriteArea.querySelector(`[data-internal=\"${internal}\"]`);\n\n nodeToRemove.parentNode.removeChild(nodeToRemove);\n\n Array.from(favouriteButtons).forEach((element) => {\n element.classList.add('text-muted');\n element.classList.remove('text-primary');\n element.dataset.favourited = 'false';\n element.setAttribute('aria-pressed', false);\n element.firstElementChild.classList.remove('fa-star');\n element.firstElementChild.classList.add('fa-star-o');\n });\n const newFaves = moduleData.content_items.filter(mod => mod.favourite === true);\n\n if (newFaves.length === 0) {\n nullFavouriteDomManager(favouriteTabNav, modalBody);\n }\n }\n }\n };\n};\n"],"file":"activitychooser.min.js"} \ No newline at end of file diff --git a/course/amd/build/local/activitychooser/dialogue.min.js b/course/amd/build/local/activitychooser/dialogue.min.js index 92a8164da3f..af6b17a4e19 100644 --- a/course/amd/build/local/activitychooser/dialogue.min.js +++ b/course/amd/build/local/activitychooser/dialogue.min.js @@ -1,2 +1,2 @@ -define ("core_course/local/activitychooser/dialogue",["exports","jquery","core/modal_events","core_course/local/activitychooser/selectors","core/templates","core/key_codes","core/loadingicon","core_course/local/activitychooser/repository","core/notification","core/utils"],function(a,b,c,d,e,f,g,h,i,j){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.displayChooser=void 0;b=l(b);c=k(c);d=l(d);e=k(e);h=k(h);i=l(i);function k(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function l(a){return a&&a.__esModule?a:{default:a}}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}function o(a,b){return r(a)||q(a,b)||p()}function p(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function q(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 r(a){if(Array.isArray(a))return a}var s=function(a,b){var c=a.find(d.default.regions.help)[0];c.innerHTML="";var f=(0,g.addIconToContainer)(c),h=null,j=new Promise(function(a){h=a}),k=e.renderForPromise("core_course/local/activitychooser/help",b);Promise.all([k,f,j]).then(function(a){var b=o(a,1),d=b[0],f=d.html,g=d.js;return e.replaceNodeContents(c,f,g)}).then(function(){c.querySelector(d.default.regions.chooserSummary.header).focus();return c}).catch(i.default.exception);a.one("slid.bs.carousel",function(){h()});a.carousel("next")},t=function(){var a=n(regeneratorRuntime.mark(function a(b,c,d){var e,f,g,i;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:e=c.dataset.favourited;f=c.dataset.id;g=c.dataset.name;i=c.dataset.internal;if(!("true"===e)){a.next=10;break}a.next=7;return h.unfavouriteModule(g,f);case 7:d(i,!1,b);a.next=13;break;case 10:a.next=12;return h.favouriteModule(g,f);case 12:d(i,!0,b);case 13:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),u=function(a,c,f){var g=function(){var e=n(regeneratorRuntime.mark(function g(h){var e,i,j,k,l,m,n,o,p,q;return regeneratorRuntime.wrap(function(g){while(1){switch(g.prev=g.next){case 0:if(h.target.closest(d.default.actions.optionActions.showSummary)){e=(0,b.default)(a.getBody()[0].querySelector(d.default.regions.carousel));i=h.target.closest(d.default.regions.chooserOption.container);j=i.dataset.modname;k=c.get(j);s(e,k)}if(!h.target.closest(d.default.actions.optionActions.manageFavourite)){g.next=10;break}l=h.target.closest(d.default.actions.optionActions.manageFavourite);g.next=5;return t(a.getBody()[0],l,f);case 5:m=a.getBody()[0].querySelector(d.default.elements.activetab).getAttribute("href");n=a.getBody()[0].querySelector(d.default.regions.getSectionChooserOptions(m));o=n.querySelector(d.default.regions.chooserOption.container);y(o,!0);w(a.getBody()[0],c,n);case 10:if(h.target.matches(d.default.actions.closeOption)){p=(0,b.default)(a.getBody()[0].querySelector(d.default.regions.carousel));p.carousel("prev");p.on("slid.bs.carousel",function(){var b=a.getBody()[0].querySelector(d.default.regions.modules),c=b.querySelector(d.default.regions.getModuleSelector(h.target.dataset.modname));c.focus()})}if(h.target.closest(d.default.actions.clearSearch)){q=a.getBody()[0].querySelector(d.default.actions.search);q.value="";q.focus();B(a.getBody()[0],c,q.value)}case 12:case"end":return g.stop();}}},g)}));return function(){return e.apply(this,arguments)}}();a.getBodyPromise().then(function(a){return a[0]}).then(function(a){(0,b.default)(a.querySelector(d.default.regions.carousel)).carousel({interval:!1,pause:!0,keyboard:!1});return a}).then(function(a){a.addEventListener("click",g);return a}).then(function(a){var b=a.querySelector(d.default.actions.search);b.addEventListener("input",(0,j.debounce)(function(){B(a,c,b.value)},300));return a}).then(function(a){var b=a.querySelector(d.default.elements.activetab).getAttribute("href"),e=a.querySelector(d.default.regions.getSectionChooserOptions(b)),f=e.querySelector(d.default.regions.chooserOption.container);y(f,!0);v(a);w(a,c,e);return a}).catch()},v=function(a){var b=a.querySelector(d.default.regions.favouriteTabNav),c=a.querySelector(d.default.regions.recommendedTabNav),e=a.querySelector(d.default.regions.defaultTabNav);[b,c,e].forEach(function(a){return a.addEventListener("keydown",function(a){var b=a.target.parentElement.querySelector(d.default.elements.visibletabs),c=a.target.parentElement.lastElementChild;if(a.keyCode===f.arrowRight){var e=a.target.nextElementSibling;if(null===e){a.target.tabIndex=-1;b.tabIndex=0;b.focus()}else if(e.classList.contains("d-none")){a.target.tabIndex=-1;c.tabIndex=0;c.focus()}else{a.target.tabIndex=-1;e.tabIndex=0;e.focus()}}if(a.keyCode===f.arrowLeft){var g=a.target.previousElementSibling;if(null===g){a.target.tabIndex=-1;c.tabIndex=0;c.focus()}else if(g.classList.contains("d-none")){a.target.tabIndex=-1;b.tabIndex=0;b.focus()}else{a.target.tabIndex=-1;g.tabIndex=0;g.focus()}}if(a.keyCode===f.home){a.target.tabIndex=-1;b.tabIndex=0;b.focus()}if(a.keyCode===f.end){a.target.tabIndex=-1;c.tabIndex=0;c.focus()}if(a.keyCode===f.space){a.preventDefault();a.target.click()}})})},w=function(a,c,g){var h=g.querySelectorAll(d.default.regions.chooserOption.container);Array.from(h).forEach(function(e){return e.addEventListener("keydown",function(h){if(h.keyCode===f.enter||h.keyCode===f.space){if(h.target.matches(d.default.actions.optionActions.showSummary)){h.preventDefault();var e=h.target.closest(d.default.regions.chooserOption.container),i=e.dataset.modname,j=c.get(i),k=(0,b.default)(a.querySelector(d.default.regions.carousel));k.carousel({interval:!1,pause:!0,keyboard:!1});s(k,j)}}if(h.keyCode===f.arrowRight){h.preventDefault();var l=h.target.closest(d.default.regions.chooserOption.container),m=l.nextElementSibling,n=g.firstElementChild,o=z(m,n);x(o,l)}if(h.keyCode===f.arrowLeft){h.preventDefault();var p=h.target.closest(d.default.regions.chooserOption.container),q=p.previousElementSibling,r=g.lastElementChild,t=z(q,r);x(t,p)}if(h.keyCode===f.home){h.preventDefault();var u=h.target.closest(d.default.regions.chooserOption.container),v=g.firstElementChild;x(v,u)}if(h.keyCode===f.end){h.preventDefault();var w=h.target.closest(d.default.regions.chooserOption.container),y=g.lastElementChild;x(y,w)}})})},x=function(a){var b=1.\n\n/**\n * A type of dialogue used as for choosing options.\n *\n * @module core_course/local/chooser/dialogue\n * @package core\n * @copyright 2019 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as ModalEvents from 'core/modal_events';\nimport selectors from 'core_course/local/activitychooser/selectors';\nimport * as Templates from 'core/templates';\nimport {end, arrowLeft, arrowRight, home, enter, space} from 'core/key_codes';\nimport {addIconToContainer} from 'core/loadingicon';\nimport * as Repository from 'core_course/local/activitychooser/repository';\nimport Notification from 'core/notification';\nimport {debounce} from 'core/utils';\n\n/**\n * Given an event from the main module 'page' navigate to it's help section via a carousel.\n *\n * @method showModuleHelp\n * @param {jQuery} carousel Our initialized carousel to manipulate\n * @param {Object} moduleData Data of the module to carousel to\n */\nconst showModuleHelp = (carousel, moduleData) => {\n const help = carousel.find(selectors.regions.help)[0];\n help.innerHTML = '';\n\n // Add a spinner.\n const spinnerPromise = addIconToContainer(help);\n\n // Used later...\n let transitionPromiseResolver = null;\n const transitionPromise = new Promise(resolve => {\n transitionPromiseResolver = resolve;\n });\n\n // Build up the html & js ready to place into the help section.\n const contentPromise = Templates.renderForPromise('core_course/local/activitychooser/help', moduleData);\n\n // Wait for the content to be ready, and for the transition to be complet.\n Promise.all([contentPromise, spinnerPromise, transitionPromise])\n .then(([{html, js}]) => Templates.replaceNodeContents(help, html, js))\n .then(() => {\n help.querySelector(selectors.regions.chooserSummary.header).focus();\n return help;\n })\n .catch(Notification.exception);\n\n // Move to the next slide, and resolve the transition promise when it's done.\n carousel.one('slid.bs.carousel', () => {\n transitionPromiseResolver();\n });\n // Trigger the transition between 'pages'.\n carousel.carousel('next');\n};\n\n/**\n * Given a user wants to change the favourite state of a module we either add or remove the status.\n * We also propergate this change across our map of modals.\n *\n * @method manageFavouriteState\n * @param {HTMLElement} modalBody The DOM node of the modal to manipulate\n * @param {HTMLElement} caller\n * @param {Function} partialFavourite Partially applied function we need to manage favourite status\n */\nconst manageFavouriteState = async(modalBody, caller, partialFavourite) => {\n const isFavourite = caller.dataset.favourited;\n const id = caller.dataset.id;\n const name = caller.dataset.name;\n const internal = caller.dataset.internal;\n // Switch on fave or not.\n if (isFavourite === 'true') {\n await Repository.unfavouriteModule(name, id);\n\n partialFavourite(internal, false, modalBody);\n } else {\n await Repository.favouriteModule(name, id);\n\n partialFavourite(internal, true, modalBody);\n }\n\n};\n\n/**\n * Register chooser related event listeners.\n *\n * @method registerListenerEvents\n * @param {Promise} modal Our modal that we are working with\n * @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}\n * @param {Function} partialFavourite Partially applied function we need to manage favourite status\n */\nconst registerListenerEvents = (modal, mappedModules, partialFavourite) => {\n const bodyClickListener = async(e) => {\n if (e.target.closest(selectors.actions.optionActions.showSummary)) {\n const carousel = $(modal.getBody()[0].querySelector(selectors.regions.carousel));\n\n const module = e.target.closest(selectors.regions.chooserOption.container);\n const moduleName = module.dataset.modname;\n const moduleData = mappedModules.get(moduleName);\n showModuleHelp(carousel, moduleData);\n }\n\n if (e.target.closest(selectors.actions.optionActions.manageFavourite)) {\n const caller = e.target.closest(selectors.actions.optionActions.manageFavourite);\n await manageFavouriteState(modal.getBody()[0], caller, partialFavourite);\n const activeSectionId = modal.getBody()[0].querySelector(selectors.elements.activetab).getAttribute(\"href\");\n const sectionChooserOptions = modal.getBody()[0]\n .querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));\n const firstChooserOption = sectionChooserOptions\n .querySelector(selectors.regions.chooserOption.container);\n toggleFocusableChooserOption(firstChooserOption, true);\n initChooserOptionsKeyboardNavigation(modal.getBody()[0], mappedModules, sectionChooserOptions);\n }\n\n // From the help screen go back to the module overview.\n if (e.target.matches(selectors.actions.closeOption)) {\n const carousel = $(modal.getBody()[0].querySelector(selectors.regions.carousel));\n\n // Trigger the transition between 'pages'.\n carousel.carousel('prev');\n carousel.on('slid.bs.carousel', () => {\n const allModules = modal.getBody()[0].querySelector(selectors.regions.modules);\n const caller = allModules.querySelector(selectors.regions.getModuleSelector(e.target.dataset.modname));\n caller.focus();\n });\n }\n\n // The \"clear search\" button is triggered.\n if (e.target.closest(selectors.actions.clearSearch)) {\n // Clear the entered search query in the search bar and hide the search results container.\n const searchInput = modal.getBody()[0].querySelector(selectors.actions.search);\n searchInput.value = \"\";\n searchInput.focus();\n toggleSearchResultsView(modal.getBody()[0], mappedModules, searchInput.value);\n }\n };\n\n modal.getBodyPromise()\n\n // The return value of getBodyPromise is a jquery object containing the body NodeElement.\n .then(body => body[0])\n\n // Set up the carousel.\n .then(body => {\n $(body.querySelector(selectors.regions.carousel))\n .carousel({\n interval: false,\n pause: true,\n keyboard: false\n });\n\n return body;\n })\n\n // Add the listener for clicks on the body.\n .then(body => {\n body.addEventListener('click', bodyClickListener);\n return body;\n })\n\n // Add a listener for an input change in the activity chooser's search bar.\n .then(body => {\n const searchInput = body.querySelector(selectors.actions.search);\n // The search input is triggered.\n searchInput.addEventListener('input', debounce(() => {\n // Display the search results.\n toggleSearchResultsView(body, mappedModules, searchInput.value);\n }, 300));\n return body;\n })\n\n // Register event listeners related to the keyboard navigation controls.\n .then(body => {\n // Get the active chooser options section.\n const activeSectionId = body.querySelector(selectors.elements.activetab).getAttribute(\"href\");\n const sectionChooserOptions = body.querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));\n const firstChooserOption = sectionChooserOptions.querySelector(selectors.regions.chooserOption.container);\n toggleFocusableChooserOption(firstChooserOption, true);\n initTabsKeyboardNavigation(body);\n initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions);\n return body;\n })\n .catch();\n\n};\n\n/**\n * Initialise the keyboard navigation controls for the tab list items.\n *\n * @method initTabsKeyboardNavigation\n * @param {HTMLElement} body Our modal that we are working with\n */\nconst initTabsKeyboardNavigation = (body) => {\n // Set up the tab handlers.\n const favTabNav = body.querySelector(selectors.regions.favouriteTabNav);\n const recommendedTabNav = body.querySelector(selectors.regions.recommendedTabNav);\n const defaultTabNav = body.querySelector(selectors.regions.defaultTabNav);\n const tabNavArray = [favTabNav, recommendedTabNav, defaultTabNav];\n tabNavArray.forEach((element) => {\n return element.addEventListener('keydown', (e) => {\n // The first visible navigation tab link.\n const firstLink = e.target.parentElement.querySelector(selectors.elements.visibletabs);\n // The last navigation tab link. It would always be the default activities tab link.\n const lastLink = e.target.parentElement.lastElementChild;\n\n if (e.keyCode === arrowRight) {\n const nextLink = e.target.nextElementSibling;\n if (nextLink === null) {\n e.target.tabIndex = -1;\n firstLink.tabIndex = 0;\n firstLink.focus();\n } else if (nextLink.classList.contains('d-none')) {\n e.target.tabIndex = -1;\n lastLink.tabIndex = 0;\n lastLink.focus();\n } else {\n e.target.tabIndex = -1;\n nextLink.tabIndex = 0;\n nextLink.focus();\n }\n }\n if (e.keyCode === arrowLeft) {\n const previousLink = e.target.previousElementSibling;\n if (previousLink === null) {\n e.target.tabIndex = -1;\n lastLink.tabIndex = 0;\n lastLink.focus();\n } else if (previousLink.classList.contains('d-none')) {\n e.target.tabIndex = -1;\n firstLink.tabIndex = 0;\n firstLink.focus();\n } else {\n e.target.tabIndex = -1;\n previousLink.tabIndex = 0;\n previousLink.focus();\n }\n }\n if (e.keyCode === home) {\n e.target.tabIndex = -1;\n firstLink.tabIndex = 0;\n firstLink.focus();\n }\n if (e.keyCode === end) {\n e.target.tabIndex = -1;\n lastLink.tabIndex = 0;\n lastLink.focus();\n }\n if (e.keyCode === space) {\n e.preventDefault();\n e.target.click();\n }\n });\n });\n};\n\n/**\n * Initialise the keyboard navigation controls for the chooser options.\n *\n * @method initChooserOptionsKeyboardNavigation\n * @param {HTMLElement} body Our modal that we are working with\n * @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}\n * @param {HTMLElement} chooserOptionsContainer The section that contains the chooser items\n */\nconst initChooserOptionsKeyboardNavigation = (body, mappedModules, chooserOptionsContainer) => {\n const chooserOptions = chooserOptionsContainer.querySelectorAll(selectors.regions.chooserOption.container);\n\n Array.from(chooserOptions).forEach((element) => {\n return element.addEventListener('keydown', (e) => {\n\n // Check for enter/ space triggers for showing the help.\n if (e.keyCode === enter || e.keyCode === space) {\n if (e.target.matches(selectors.actions.optionActions.showSummary)) {\n e.preventDefault();\n const module = e.target.closest(selectors.regions.chooserOption.container);\n const moduleName = module.dataset.modname;\n const moduleData = mappedModules.get(moduleName);\n const carousel = $(body.querySelector(selectors.regions.carousel));\n carousel.carousel({\n interval: false,\n pause: true,\n keyboard: false\n });\n showModuleHelp(carousel, moduleData);\n }\n }\n\n // Next.\n if (e.keyCode === arrowRight) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const nextOption = currentOption.nextElementSibling;\n const firstOption = chooserOptionsContainer.firstElementChild;\n const toFocusOption = clickErrorHandler(nextOption, firstOption);\n focusChooserOption(toFocusOption, currentOption);\n }\n\n // Previous.\n if (e.keyCode === arrowLeft) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const previousOption = currentOption.previousElementSibling;\n const lastOption = chooserOptionsContainer.lastElementChild;\n const toFocusOption = clickErrorHandler(previousOption, lastOption);\n focusChooserOption(toFocusOption, currentOption);\n }\n\n if (e.keyCode === home) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const firstOption = chooserOptionsContainer.firstElementChild;\n focusChooserOption(firstOption, currentOption);\n }\n\n if (e.keyCode === end) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const lastOption = chooserOptionsContainer.lastElementChild;\n focusChooserOption(lastOption, currentOption);\n }\n });\n });\n};\n\n/**\n * Focus on a chooser option element and remove the previous chooser element from the focus order\n *\n * @method focusChooserOption\n * @param {HTMLElement} currentChooserOption The current chooser option element that we want to focus\n * @param {HTMLElement|null} previousChooserOption The previous focused option element\n */\nconst focusChooserOption = (currentChooserOption, previousChooserOption = null) => {\n if (previousChooserOption !== null) {\n toggleFocusableChooserOption(previousChooserOption, false);\n }\n\n toggleFocusableChooserOption(currentChooserOption, true);\n currentChooserOption.focus();\n};\n\n/**\n * Add or remove a chooser option from the focus order.\n *\n * @method toggleFocusableChooserOption\n * @param {HTMLElement} chooserOption The chooser option element which should be added or removed from the focus order\n * @param {Boolean} isFocusable Whether the chooser element is focusable or not\n */\nconst toggleFocusableChooserOption = (chooserOption, isFocusable) => {\n const chooserOptionLink = chooserOption.querySelector(selectors.actions.addChooser);\n const chooserOptionHelp = chooserOption.querySelector(selectors.actions.optionActions.showSummary);\n const chooserOptionFavourite = chooserOption.querySelector(selectors.actions.optionActions.manageFavourite);\n\n if (isFocusable) {\n // Set tabindex to 0 to add current chooser option element to the focus order.\n chooserOption.tabIndex = 0;\n chooserOptionLink.tabIndex = 0;\n chooserOptionHelp.tabIndex = 0;\n chooserOptionFavourite.tabIndex = 0;\n } else {\n // Set tabindex to -1 to remove the previous chooser option element from the focus order.\n chooserOption.tabIndex = -1;\n chooserOptionLink.tabIndex = -1;\n chooserOptionHelp.tabIndex = -1;\n chooserOptionFavourite.tabIndex = -1;\n }\n};\n\n/**\n * Small error handling function to make sure the navigated to object exists\n *\n * @method clickErrorHandler\n * @param {HTMLElement} item What we want to check exists\n * @param {HTMLElement} fallback If we dont match anything fallback the focus\n * @return {HTMLElement}\n */\nconst clickErrorHandler = (item, fallback) => {\n if (item !== null) {\n return item;\n } else {\n return fallback;\n }\n};\n\n/**\n * Render the search results in a defined container\n *\n * @method renderSearchResults\n * @param {HTMLElement} searchResultsContainer The container where the data should be rendered\n * @param {Object} searchResultsData Data containing the module items that satisfy the search criteria\n */\nconst renderSearchResults = async(searchResultsContainer, searchResultsData) => {\n const templateData = {\n 'searchresultsnumber': searchResultsData.length,\n 'searchresults': searchResultsData\n };\n // Build up the html & js ready to place into the help section.\n const {html, js} = await Templates.renderForPromise('core_course/local/activitychooser/search_results', templateData);\n await Templates.replaceNodeContents(searchResultsContainer, html, js);\n};\n\n/**\n * Toggle (display/hide) the search results depending on the value of the search query\n *\n * @method toggleSearchResultsView\n * @param {HTMLElement} modalBody The body of the created modal for the section\n * @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}\n * @param {String} searchQuery The search query\n */\nconst toggleSearchResultsView = async(modalBody, mappedModules, searchQuery) => {\n const searchResultsContainer = modalBody.querySelector(selectors.regions.searchResults);\n const chooserContainer = modalBody.querySelector(selectors.regions.chooser);\n const clearSearchButton = modalBody.querySelector(selectors.elements.clearsearch);\n const searchIcon = modalBody.querySelector(selectors.elements.searchicon);\n\n if (searchQuery.length > 0) { // Search query is present.\n const searchResultsData = searchModules(mappedModules, searchQuery);\n await renderSearchResults(searchResultsContainer, searchResultsData);\n const searchResultItemsContainer = searchResultsContainer.querySelector(selectors.regions.searchResultItems);\n const firstSearchResultItem = searchResultItemsContainer.querySelector(selectors.regions.chooserOption.container);\n if (firstSearchResultItem) {\n // Set the first result item to be focusable.\n toggleFocusableChooserOption(firstSearchResultItem, true);\n // Register keyboard events on the created search result items.\n initChooserOptionsKeyboardNavigation(modalBody, mappedModules, searchResultItemsContainer);\n }\n // Display the \"clear\" search button in the activity chooser search bar.\n searchIcon.classList.add('d-none');\n clearSearchButton.classList.remove('d-none');\n // Hide the default chooser options container.\n chooserContainer.setAttribute('hidden', 'hidden');\n // Display the search results container.\n searchResultsContainer.removeAttribute('hidden');\n } else { // Search query is not present.\n // Hide the \"clear\" search button in the activity chooser search bar.\n clearSearchButton.classList.add('d-none');\n searchIcon.classList.remove('d-none');\n // Hide the search results container.\n searchResultsContainer.setAttribute('hidden', 'hidden');\n // Display the default chooser options container.\n chooserContainer.removeAttribute('hidden');\n }\n};\n\n/**\n * Return the list of modules which have a name or description that matches the given search term.\n *\n * @method searchModules\n * @param {Array} modules List of available modules\n * @param {String} searchTerm The search term to match\n * @return {Array}\n */\nconst searchModules = (modules, searchTerm) => {\n if (searchTerm === '') {\n return modules;\n }\n searchTerm = searchTerm.toLowerCase();\n const searchResults = [];\n modules.forEach((activity) => {\n const activityName = activity.title.toLowerCase();\n const activityDesc = activity.help.toLowerCase();\n if (activityName.includes(searchTerm) || activityDesc.includes(searchTerm)) {\n searchResults.push(activity);\n }\n });\n\n return searchResults;\n};\n\n/**\n * Disable the focus of all chooser options in a specific container (section).\n *\n * @method disableFocusAllChooserOptions\n * @param {HTMLElement} sectionChooserOptions The section that contains the chooser items\n */\nconst disableFocusAllChooserOptions = (sectionChooserOptions) => {\n const allChooserOptions = sectionChooserOptions.querySelectorAll(selectors.regions.chooserOption.container);\n allChooserOptions.forEach((chooserOption) => {\n toggleFocusableChooserOption(chooserOption, false);\n });\n};\n\n/**\n * Display the module chooser.\n *\n * @method displayChooser\n * @param {HTMLElement} origin The calling button\n * @param {Object} modal Our created modal for the section\n * @param {Array} sectionModules An array of all of the built module information\n * @param {Function} partialFavourite Partially applied function we need to manage favourite status\n */\nexport const displayChooser = (origin, modal, sectionModules, partialFavourite) => {\n\n // Make a map so we can quickly fetch a specific module's object for either rendering or searching.\n const mappedModules = new Map();\n sectionModules.forEach((module) => {\n mappedModules.set(module.componentname + '_' + module.link, module);\n });\n\n // Register event listeners.\n registerListenerEvents(modal, mappedModules, partialFavourite);\n\n // We want to focus on the action select when the dialog is closed.\n modal.getRoot().on(ModalEvents.hidden, () => {\n modal.destroy();\n });\n\n // We want to focus on the first chooser option element as soon as the modal is opened.\n modal.getRoot().on(ModalEvents.shown, () => {\n modal.getModal()[0].tabIndex = -1;\n\n modal.getBodyPromise()\n .then(body => {\n $(selectors.elements.tab).on('shown.bs.tab', (e) => {\n const activeSectionId = e.target.getAttribute(\"href\");\n const activeSectionChooserOptions = body[0]\n .querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));\n const firstChooserOption = activeSectionChooserOptions\n .querySelector(selectors.regions.chooserOption.container);\n const prevActiveSectionId = e.relatedTarget.getAttribute(\"href\");\n const prevActiveSectionChooserOptions = body[0]\n .querySelector(selectors.regions.getSectionChooserOptions(prevActiveSectionId));\n\n // Disable the focus of every chooser option in the previous active section.\n disableFocusAllChooserOptions(prevActiveSectionChooserOptions);\n // Enable the focus of the first chooser option in the current active section.\n toggleFocusableChooserOption(firstChooserOption, true);\n initChooserOptionsKeyboardNavigation(body[0], mappedModules, activeSectionChooserOptions);\n });\n return;\n })\n .catch(Notification.exception);\n });\n\n modal.show();\n};\n"],"file":"dialogue.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/activitychooser/dialogue.js"],"names":["showModuleHelp","carousel","moduleData","help","find","selectors","regions","innerHTML","classList","add","spinnerPromise","transitionPromiseResolver","transitionPromise","Promise","resolve","contentPromise","Templates","renderForPromise","all","then","html","js","replaceNodeContents","querySelector","chooserSummary","header","focus","catch","Notification","exception","one","manageFavouriteState","modalBody","caller","partialFavourite","isFavourite","dataset","favourited","id","name","internal","Repository","unfavouriteModule","favouriteModule","registerListenerEvents","modal","mappedModules","bodyClickListener","e","target","closest","actions","optionActions","showSummary","getBody","module","chooserOption","container","moduleName","modname","get","manageFavourite","activeSectionId","elements","activetab","getAttribute","sectionChooserOptions","getSectionChooserOptions","firstChooserOption","toggleFocusableChooserOption","initChooserOptionsKeyboardNavigation","matches","closeOption","on","allModules","modules","getModuleSelector","clearSearch","searchInput","search","value","toggleSearchResultsView","getBodyPromise","body","interval","pause","keyboard","addEventListener","initTabsKeyboardNavigation","favTabNav","favouriteTabNav","recommendedTabNav","defaultTabNav","forEach","element","firstLink","parentElement","visibletabs","lastLink","lastElementChild","keyCode","arrowRight","nextLink","nextElementSibling","tabIndex","contains","arrowLeft","previousLink","previousElementSibling","home","end","space","preventDefault","click","chooserOptionsContainer","chooserOptions","querySelectorAll","Array","from","enter","currentOption","nextOption","firstOption","firstElementChild","toFocusOption","clickErrorHandler","focusChooserOption","previousOption","lastOption","currentChooserOption","previousChooserOption","isFocusable","chooserOptionLink","addChooser","chooserOptionHelp","chooserOptionFavourite","item","fallback","renderSearchResults","searchResultsContainer","searchResultsData","templateData","length","searchQuery","searchResults","chooserContainer","chooser","clearSearchButton","clearsearch","searchIcon","searchicon","searchModules","searchResultItemsContainer","searchResultItems","firstSearchResultItem","remove","setAttribute","removeAttribute","searchTerm","toLowerCase","activity","activityName","title","activityDesc","includes","push","setupKeyboardAccessibility","getModal","tab","activeSectionChooserOptions","prevActiveSectionId","relatedTarget","prevActiveSectionChooserOptions","disableFocusAllChooserOptions","allChooserOptions","displayChooser","modalPromise","sectionModules","Map","set","componentname","link","getRoot","ModalEvents","hidden","destroy"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A type of dialogue used as for choosing options.\n *\n * @module core_course/local/chooser/dialogue\n * @package core\n * @copyright 2019 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as ModalEvents from 'core/modal_events';\nimport selectors from 'core_course/local/activitychooser/selectors';\nimport * as Templates from 'core/templates';\nimport {end, arrowLeft, arrowRight, home, enter, space} from 'core/key_codes';\nimport {addIconToContainer} from 'core/loadingicon';\nimport * as Repository from 'core_course/local/activitychooser/repository';\nimport Notification from 'core/notification';\nimport {debounce} from 'core/utils';\n\n/**\n * Given an event from the main module 'page' navigate to it's help section via a carousel.\n *\n * @method showModuleHelp\n * @param {jQuery} carousel Our initialized carousel to manipulate\n * @param {Object} moduleData Data of the module to carousel to\n */\nconst showModuleHelp = (carousel, moduleData) => {\n const help = carousel.find(selectors.regions.help)[0];\n help.innerHTML = '';\n help.classList.add('m-auto');\n\n // Add a spinner.\n const spinnerPromise = addIconToContainer(help);\n\n // Used later...\n let transitionPromiseResolver = null;\n const transitionPromise = new Promise(resolve => {\n transitionPromiseResolver = resolve;\n });\n\n // Build up the html & js ready to place into the help section.\n const contentPromise = Templates.renderForPromise('core_course/local/activitychooser/help', moduleData);\n\n // Wait for the content to be ready, and for the transition to be complet.\n Promise.all([contentPromise, spinnerPromise, transitionPromise])\n .then(([{html, js}]) => Templates.replaceNodeContents(help, html, js))\n .then(() => {\n help.querySelector(selectors.regions.chooserSummary.header).focus();\n return help;\n })\n .catch(Notification.exception);\n\n // Move to the next slide, and resolve the transition promise when it's done.\n carousel.one('slid.bs.carousel', () => {\n transitionPromiseResolver();\n });\n // Trigger the transition between 'pages'.\n carousel.carousel('next');\n};\n\n/**\n * Given a user wants to change the favourite state of a module we either add or remove the status.\n * We also propergate this change across our map of modals.\n *\n * @method manageFavouriteState\n * @param {HTMLElement} modalBody The DOM node of the modal to manipulate\n * @param {HTMLElement} caller\n * @param {Function} partialFavourite Partially applied function we need to manage favourite status\n */\nconst manageFavouriteState = async(modalBody, caller, partialFavourite) => {\n const isFavourite = caller.dataset.favourited;\n const id = caller.dataset.id;\n const name = caller.dataset.name;\n const internal = caller.dataset.internal;\n // Switch on fave or not.\n if (isFavourite === 'true') {\n await Repository.unfavouriteModule(name, id);\n\n partialFavourite(internal, false, modalBody);\n } else {\n await Repository.favouriteModule(name, id);\n\n partialFavourite(internal, true, modalBody);\n }\n\n};\n\n/**\n * Register chooser related event listeners.\n *\n * @method registerListenerEvents\n * @param {Promise} modal Our modal that we are working with\n * @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}\n * @param {Function} partialFavourite Partially applied function we need to manage favourite status\n */\nconst registerListenerEvents = (modal, mappedModules, partialFavourite) => {\n const bodyClickListener = async(e) => {\n if (e.target.closest(selectors.actions.optionActions.showSummary)) {\n const carousel = $(modal.getBody()[0].querySelector(selectors.regions.carousel));\n\n const module = e.target.closest(selectors.regions.chooserOption.container);\n const moduleName = module.dataset.modname;\n const moduleData = mappedModules.get(moduleName);\n showModuleHelp(carousel, moduleData);\n }\n\n if (e.target.closest(selectors.actions.optionActions.manageFavourite)) {\n const caller = e.target.closest(selectors.actions.optionActions.manageFavourite);\n await manageFavouriteState(modal.getBody()[0], caller, partialFavourite);\n const activeSectionId = modal.getBody()[0].querySelector(selectors.elements.activetab).getAttribute(\"href\");\n const sectionChooserOptions = modal.getBody()[0]\n .querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));\n const firstChooserOption = sectionChooserOptions\n .querySelector(selectors.regions.chooserOption.container);\n toggleFocusableChooserOption(firstChooserOption, true);\n initChooserOptionsKeyboardNavigation(modal.getBody()[0], mappedModules, sectionChooserOptions);\n }\n\n // From the help screen go back to the module overview.\n if (e.target.matches(selectors.actions.closeOption)) {\n const carousel = $(modal.getBody()[0].querySelector(selectors.regions.carousel));\n\n // Trigger the transition between 'pages'.\n carousel.carousel('prev');\n carousel.on('slid.bs.carousel', () => {\n const allModules = modal.getBody()[0].querySelector(selectors.regions.modules);\n const caller = allModules.querySelector(selectors.regions.getModuleSelector(e.target.dataset.modname));\n caller.focus();\n });\n }\n\n // The \"clear search\" button is triggered.\n if (e.target.closest(selectors.actions.clearSearch)) {\n // Clear the entered search query in the search bar and hide the search results container.\n const searchInput = modal.getBody()[0].querySelector(selectors.actions.search);\n searchInput.value = \"\";\n searchInput.focus();\n toggleSearchResultsView(modal.getBody()[0], mappedModules, searchInput.value);\n }\n };\n\n modal.getBodyPromise()\n\n // The return value of getBodyPromise is a jquery object containing the body NodeElement.\n .then(body => body[0])\n\n // Set up the carousel.\n .then(body => {\n $(body.querySelector(selectors.regions.carousel))\n .carousel({\n interval: false,\n pause: true,\n keyboard: false\n });\n\n return body;\n })\n\n // Add the listener for clicks on the body.\n .then(body => {\n body.addEventListener('click', bodyClickListener);\n return body;\n })\n\n // Add a listener for an input change in the activity chooser's search bar.\n .then(body => {\n const searchInput = body.querySelector(selectors.actions.search);\n // The search input is triggered.\n searchInput.addEventListener('input', debounce(() => {\n // Display the search results.\n toggleSearchResultsView(body, mappedModules, searchInput.value);\n }, 300));\n return body;\n })\n\n // Register event listeners related to the keyboard navigation controls.\n .then(body => {\n // Get the active chooser options section.\n const activeSectionId = body.querySelector(selectors.elements.activetab).getAttribute(\"href\");\n const sectionChooserOptions = body.querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));\n const firstChooserOption = sectionChooserOptions.querySelector(selectors.regions.chooserOption.container);\n toggleFocusableChooserOption(firstChooserOption, true);\n initTabsKeyboardNavigation(body);\n initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions);\n return body;\n })\n .catch();\n\n};\n\n/**\n * Initialise the keyboard navigation controls for the tab list items.\n *\n * @method initTabsKeyboardNavigation\n * @param {HTMLElement} body Our modal that we are working with\n */\nconst initTabsKeyboardNavigation = (body) => {\n // Set up the tab handlers.\n const favTabNav = body.querySelector(selectors.regions.favouriteTabNav);\n const recommendedTabNav = body.querySelector(selectors.regions.recommendedTabNav);\n const defaultTabNav = body.querySelector(selectors.regions.defaultTabNav);\n const tabNavArray = [favTabNav, recommendedTabNav, defaultTabNav];\n tabNavArray.forEach((element) => {\n return element.addEventListener('keydown', (e) => {\n // The first visible navigation tab link.\n const firstLink = e.target.parentElement.querySelector(selectors.elements.visibletabs);\n // The last navigation tab link. It would always be the default activities tab link.\n const lastLink = e.target.parentElement.lastElementChild;\n\n if (e.keyCode === arrowRight) {\n const nextLink = e.target.nextElementSibling;\n if (nextLink === null) {\n e.target.tabIndex = -1;\n firstLink.tabIndex = 0;\n firstLink.focus();\n } else if (nextLink.classList.contains('d-none')) {\n e.target.tabIndex = -1;\n lastLink.tabIndex = 0;\n lastLink.focus();\n } else {\n e.target.tabIndex = -1;\n nextLink.tabIndex = 0;\n nextLink.focus();\n }\n }\n if (e.keyCode === arrowLeft) {\n const previousLink = e.target.previousElementSibling;\n if (previousLink === null) {\n e.target.tabIndex = -1;\n lastLink.tabIndex = 0;\n lastLink.focus();\n } else if (previousLink.classList.contains('d-none')) {\n e.target.tabIndex = -1;\n firstLink.tabIndex = 0;\n firstLink.focus();\n } else {\n e.target.tabIndex = -1;\n previousLink.tabIndex = 0;\n previousLink.focus();\n }\n }\n if (e.keyCode === home) {\n e.target.tabIndex = -1;\n firstLink.tabIndex = 0;\n firstLink.focus();\n }\n if (e.keyCode === end) {\n e.target.tabIndex = -1;\n lastLink.tabIndex = 0;\n lastLink.focus();\n }\n if (e.keyCode === space) {\n e.preventDefault();\n e.target.click();\n }\n });\n });\n};\n\n/**\n * Initialise the keyboard navigation controls for the chooser options.\n *\n * @method initChooserOptionsKeyboardNavigation\n * @param {HTMLElement} body Our modal that we are working with\n * @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}\n * @param {HTMLElement} chooserOptionsContainer The section that contains the chooser items\n */\nconst initChooserOptionsKeyboardNavigation = (body, mappedModules, chooserOptionsContainer) => {\n const chooserOptions = chooserOptionsContainer.querySelectorAll(selectors.regions.chooserOption.container);\n\n Array.from(chooserOptions).forEach((element) => {\n return element.addEventListener('keydown', (e) => {\n\n // Check for enter/ space triggers for showing the help.\n if (e.keyCode === enter || e.keyCode === space) {\n if (e.target.matches(selectors.actions.optionActions.showSummary)) {\n e.preventDefault();\n const module = e.target.closest(selectors.regions.chooserOption.container);\n const moduleName = module.dataset.modname;\n const moduleData = mappedModules.get(moduleName);\n const carousel = $(body.querySelector(selectors.regions.carousel));\n carousel.carousel({\n interval: false,\n pause: true,\n keyboard: false\n });\n showModuleHelp(carousel, moduleData);\n }\n }\n\n // Next.\n if (e.keyCode === arrowRight) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const nextOption = currentOption.nextElementSibling;\n const firstOption = chooserOptionsContainer.firstElementChild;\n const toFocusOption = clickErrorHandler(nextOption, firstOption);\n focusChooserOption(toFocusOption, currentOption);\n }\n\n // Previous.\n if (e.keyCode === arrowLeft) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const previousOption = currentOption.previousElementSibling;\n const lastOption = chooserOptionsContainer.lastElementChild;\n const toFocusOption = clickErrorHandler(previousOption, lastOption);\n focusChooserOption(toFocusOption, currentOption);\n }\n\n if (e.keyCode === home) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const firstOption = chooserOptionsContainer.firstElementChild;\n focusChooserOption(firstOption, currentOption);\n }\n\n if (e.keyCode === end) {\n e.preventDefault();\n const currentOption = e.target.closest(selectors.regions.chooserOption.container);\n const lastOption = chooserOptionsContainer.lastElementChild;\n focusChooserOption(lastOption, currentOption);\n }\n });\n });\n};\n\n/**\n * Focus on a chooser option element and remove the previous chooser element from the focus order\n *\n * @method focusChooserOption\n * @param {HTMLElement} currentChooserOption The current chooser option element that we want to focus\n * @param {HTMLElement|null} previousChooserOption The previous focused option element\n */\nconst focusChooserOption = (currentChooserOption, previousChooserOption = null) => {\n if (previousChooserOption !== null) {\n toggleFocusableChooserOption(previousChooserOption, false);\n }\n\n toggleFocusableChooserOption(currentChooserOption, true);\n currentChooserOption.focus();\n};\n\n/**\n * Add or remove a chooser option from the focus order.\n *\n * @method toggleFocusableChooserOption\n * @param {HTMLElement} chooserOption The chooser option element which should be added or removed from the focus order\n * @param {Boolean} isFocusable Whether the chooser element is focusable or not\n */\nconst toggleFocusableChooserOption = (chooserOption, isFocusable) => {\n const chooserOptionLink = chooserOption.querySelector(selectors.actions.addChooser);\n const chooserOptionHelp = chooserOption.querySelector(selectors.actions.optionActions.showSummary);\n const chooserOptionFavourite = chooserOption.querySelector(selectors.actions.optionActions.manageFavourite);\n\n if (isFocusable) {\n // Set tabindex to 0 to add current chooser option element to the focus order.\n chooserOption.tabIndex = 0;\n chooserOptionLink.tabIndex = 0;\n chooserOptionHelp.tabIndex = 0;\n chooserOptionFavourite.tabIndex = 0;\n } else {\n // Set tabindex to -1 to remove the previous chooser option element from the focus order.\n chooserOption.tabIndex = -1;\n chooserOptionLink.tabIndex = -1;\n chooserOptionHelp.tabIndex = -1;\n chooserOptionFavourite.tabIndex = -1;\n }\n};\n\n/**\n * Small error handling function to make sure the navigated to object exists\n *\n * @method clickErrorHandler\n * @param {HTMLElement} item What we want to check exists\n * @param {HTMLElement} fallback If we dont match anything fallback the focus\n * @return {HTMLElement}\n */\nconst clickErrorHandler = (item, fallback) => {\n if (item !== null) {\n return item;\n } else {\n return fallback;\n }\n};\n\n/**\n * Render the search results in a defined container\n *\n * @method renderSearchResults\n * @param {HTMLElement} searchResultsContainer The container where the data should be rendered\n * @param {Object} searchResultsData Data containing the module items that satisfy the search criteria\n */\nconst renderSearchResults = async(searchResultsContainer, searchResultsData) => {\n const templateData = {\n 'searchresultsnumber': searchResultsData.length,\n 'searchresults': searchResultsData\n };\n // Build up the html & js ready to place into the help section.\n const {html, js} = await Templates.renderForPromise('core_course/local/activitychooser/search_results', templateData);\n await Templates.replaceNodeContents(searchResultsContainer, html, js);\n};\n\n/**\n * Toggle (display/hide) the search results depending on the value of the search query\n *\n * @method toggleSearchResultsView\n * @param {HTMLElement} modalBody The body of the created modal for the section\n * @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}\n * @param {String} searchQuery The search query\n */\nconst toggleSearchResultsView = async(modalBody, mappedModules, searchQuery) => {\n const searchResultsContainer = modalBody.querySelector(selectors.regions.searchResults);\n const chooserContainer = modalBody.querySelector(selectors.regions.chooser);\n const clearSearchButton = modalBody.querySelector(selectors.elements.clearsearch);\n const searchIcon = modalBody.querySelector(selectors.elements.searchicon);\n\n if (searchQuery.length > 0) { // Search query is present.\n const searchResultsData = searchModules(mappedModules, searchQuery);\n await renderSearchResults(searchResultsContainer, searchResultsData);\n const searchResultItemsContainer = searchResultsContainer.querySelector(selectors.regions.searchResultItems);\n const firstSearchResultItem = searchResultItemsContainer.querySelector(selectors.regions.chooserOption.container);\n if (firstSearchResultItem) {\n // Set the first result item to be focusable.\n toggleFocusableChooserOption(firstSearchResultItem, true);\n // Register keyboard events on the created search result items.\n initChooserOptionsKeyboardNavigation(modalBody, mappedModules, searchResultItemsContainer);\n }\n // Display the \"clear\" search button in the activity chooser search bar.\n searchIcon.classList.add('d-none');\n clearSearchButton.classList.remove('d-none');\n // Hide the default chooser options container.\n chooserContainer.setAttribute('hidden', 'hidden');\n // Display the search results container.\n searchResultsContainer.removeAttribute('hidden');\n } else { // Search query is not present.\n // Hide the \"clear\" search button in the activity chooser search bar.\n clearSearchButton.classList.add('d-none');\n searchIcon.classList.remove('d-none');\n // Hide the search results container.\n searchResultsContainer.setAttribute('hidden', 'hidden');\n // Display the default chooser options container.\n chooserContainer.removeAttribute('hidden');\n }\n};\n\n/**\n * Return the list of modules which have a name or description that matches the given search term.\n *\n * @method searchModules\n * @param {Array} modules List of available modules\n * @param {String} searchTerm The search term to match\n * @return {Array}\n */\nconst searchModules = (modules, searchTerm) => {\n if (searchTerm === '') {\n return modules;\n }\n searchTerm = searchTerm.toLowerCase();\n const searchResults = [];\n modules.forEach((activity) => {\n const activityName = activity.title.toLowerCase();\n const activityDesc = activity.help.toLowerCase();\n if (activityName.includes(searchTerm) || activityDesc.includes(searchTerm)) {\n searchResults.push(activity);\n }\n });\n\n return searchResults;\n};\n\n/**\n * Set up our tabindex information across the chooser.\n *\n * @method setupKeyboardAccessibility\n * @param {Promise} modal Our created modal for the section\n * @param {Map} mappedModules A map of all of the built module information\n */\nconst setupKeyboardAccessibility = (modal, mappedModules) => {\n modal.getModal()[0].tabIndex = -1;\n\n modal.getBodyPromise().then(body => {\n $(selectors.elements.tab).on('shown.bs.tab', (e) => {\n const activeSectionId = e.target.getAttribute(\"href\");\n const activeSectionChooserOptions = body[0]\n .querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));\n const firstChooserOption = activeSectionChooserOptions\n .querySelector(selectors.regions.chooserOption.container);\n const prevActiveSectionId = e.relatedTarget.getAttribute(\"href\");\n const prevActiveSectionChooserOptions = body[0]\n .querySelector(selectors.regions.getSectionChooserOptions(prevActiveSectionId));\n\n // Disable the focus of every chooser option in the previous active section.\n disableFocusAllChooserOptions(prevActiveSectionChooserOptions);\n // Enable the focus of the first chooser option in the current active section.\n toggleFocusableChooserOption(firstChooserOption, true);\n initChooserOptionsKeyboardNavigation(body[0], mappedModules, activeSectionChooserOptions);\n });\n return;\n }).catch(Notification.exception);\n};\n\n/**\n * Disable the focus of all chooser options in a specific container (section).\n *\n * @method disableFocusAllChooserOptions\n * @param {HTMLElement} sectionChooserOptions The section that contains the chooser items\n */\nconst disableFocusAllChooserOptions = (sectionChooserOptions) => {\n const allChooserOptions = sectionChooserOptions.querySelectorAll(selectors.regions.chooserOption.container);\n allChooserOptions.forEach((chooserOption) => {\n toggleFocusableChooserOption(chooserOption, false);\n });\n};\n\n/**\n * Display the module chooser.\n *\n * @method displayChooser\n * @param {Promise} modalPromise Our created modal for the section\n * @param {Array} sectionModules An array of all of the built module information\n * @param {Function} partialFavourite Partially applied function we need to manage favourite status\n */\nexport const displayChooser = (modalPromise, sectionModules, partialFavourite) => {\n // Make a map so we can quickly fetch a specific module's object for either rendering or searching.\n const mappedModules = new Map();\n sectionModules.forEach((module) => {\n mappedModules.set(module.componentname + '_' + module.link, module);\n });\n\n // Register event listeners.\n modalPromise.then(modal => {\n registerListenerEvents(modal, mappedModules, partialFavourite);\n\n // We want to focus on the first chooser option element as soon as the modal is opened.\n setupKeyboardAccessibility(modal, mappedModules);\n\n // We want to focus on the action select when the dialog is closed.\n modal.getRoot().on(ModalEvents.hidden, () => {\n modal.destroy();\n });\n\n return modal;\n })\n .catch();\n};\n"],"file":"dialogue.min.js"} \ No newline at end of file diff --git a/course/amd/src/activitychooser.js b/course/amd/src/activitychooser.js index d3b83d0ff3c..a66560e6177 100644 --- a/course/amd/src/activitychooser.js +++ b/course/amd/src/activitychooser.js @@ -78,7 +78,6 @@ const registerListenerEvents = (courseId) => { events.forEach((event) => { document.addEventListener(event, async(e) => { if (e.target.closest(selectors.elements.sectionmodchooser)) { - const data = await fetchModuleData(); // We need to know who called this. // Standard courses use the ID in the main section info. const sectionDiv = e.target.closest(selectors.elements.section); @@ -86,11 +85,31 @@ const registerListenerEvents = (courseId) => { const button = e.target.closest(selectors.elements.sectionmodchooser); // If we don't have a section ID use the fallback ID. const caller = sectionDiv || button; - const favouriteFunction = partiallyAppliedFavouriteManager(data, caller.dataset.sectionid); - const builtModuleData = sectionIdMapper(data, caller.dataset.sectionid); - const sectionModal = await modalBuilder(builtModuleData); - ChooserDialogue.displayChooser(caller, sectionModal, builtModuleData, favouriteFunction); + // We want to show the modal instantly but loading whilst waiting for our data. + let bodyPromiseResolver; + const bodyPromise = new Promise(resolve => { + bodyPromiseResolver = resolve; + }); + + const sectionModal = buildModal(bodyPromise); + + // Now we have a modal we should start fetching data. + const data = await fetchModuleData(); + + // Apply the section id to all the module instance links. + const builtModuleData = sectionIdMapper(data, caller.dataset.sectionid); + + ChooserDialogue.displayChooser( + sectionModal, + builtModuleData, + partiallyAppliedFavouriteManager(data, caller.dataset.sectionid), + ); + + bodyPromiseResolver(await Templates.render( + 'core_course/activitychooser', + templateDataBuilder(builtModuleData) + )); } }); }); @@ -102,7 +121,7 @@ const registerListenerEvents = (courseId) => { * * @method sectionIdMapper * @param {Object} webServiceData Our original data from the Web service call - * @param {Array} id The ID of the section we need to append to the links + * @param {Number} id The ID of the section we need to append to the links * @return {Array} [modules] with URL's built */ const sectionIdMapper = (webServiceData, id) => { @@ -114,15 +133,6 @@ const sectionIdMapper = (webServiceData, id) => { return newData.content_items; }; -/** - * Build a modal on demand to save page load times - * - * @method modalBuilder - * @param {Array} data our array of modules with section ID's applied in the URL field - * @return {Object} Our modal that we are going to show the user - */ -const modalBuilder = data => buildModal(templateDataBuilder(data)); - /** * Given an array of modules we want to figure out where & how to place them into our template object * @@ -158,18 +168,22 @@ const templateDataBuilder = (data) => { * Given an object we want to build a modal ready to show * * @method buildModal - * @param {Object} data The template data which contains arrays of modules - * @return {Object} The modal for the calling section with everything already set up + * @param {Promise} bodyPromise + * @return {Object} The modal ready to display immediately and render body in later. */ -const buildModal = data => { +const buildModal = bodyPromise => { return ModalFactory.create({ type: ModalFactory.types.DEFAULT, title: getString('addresourceoractivity'), - body: Templates.render('core_course/activitychooser', data), + body: bodyPromise, large: true, templateContext: { classes: 'modchooser' } + }) + .then(modal => { + modal.show(); + return modal; }); }; @@ -240,6 +254,7 @@ const partiallyAppliedFavouriteManager = (moduleData, sectionId) => { if (favourite) { result.favourite = true; + // eslint-disable-next-line camelcase newFaves.content_items = moduleData.content_items.filter(mod => mod.favourite === true); const builtFaves = sectionIdMapper(newFaves, sectionId); diff --git a/course/amd/src/local/activitychooser/dialogue.js b/course/amd/src/local/activitychooser/dialogue.js index 6a476cf2905..42a19b32f2f 100644 --- a/course/amd/src/local/activitychooser/dialogue.js +++ b/course/amd/src/local/activitychooser/dialogue.js @@ -42,6 +42,7 @@ import {debounce} from 'core/utils'; const showModuleHelp = (carousel, moduleData) => { const help = carousel.find(selectors.regions.help)[0]; help.innerHTML = ''; + help.classList.add('m-auto'); // Add a spinner. const spinnerPromise = addIconToContainer(help); @@ -483,6 +484,37 @@ const searchModules = (modules, searchTerm) => { return searchResults; }; +/** + * Set up our tabindex information across the chooser. + * + * @method setupKeyboardAccessibility + * @param {Promise} modal Our created modal for the section + * @param {Map} mappedModules A map of all of the built module information + */ +const setupKeyboardAccessibility = (modal, mappedModules) => { + modal.getModal()[0].tabIndex = -1; + + modal.getBodyPromise().then(body => { + $(selectors.elements.tab).on('shown.bs.tab', (e) => { + const activeSectionId = e.target.getAttribute("href"); + const activeSectionChooserOptions = body[0] + .querySelector(selectors.regions.getSectionChooserOptions(activeSectionId)); + const firstChooserOption = activeSectionChooserOptions + .querySelector(selectors.regions.chooserOption.container); + const prevActiveSectionId = e.relatedTarget.getAttribute("href"); + const prevActiveSectionChooserOptions = body[0] + .querySelector(selectors.regions.getSectionChooserOptions(prevActiveSectionId)); + + // Disable the focus of every chooser option in the previous active section. + disableFocusAllChooserOptions(prevActiveSectionChooserOptions); + // Enable the focus of the first chooser option in the current active section. + toggleFocusableChooserOption(firstChooserOption, true); + initChooserOptionsKeyboardNavigation(body[0], mappedModules, activeSectionChooserOptions); + }); + return; + }).catch(Notification.exception); +}; + /** * Disable the focus of all chooser options in a specific container (section). * @@ -500,13 +532,11 @@ const disableFocusAllChooserOptions = (sectionChooserOptions) => { * Display the module chooser. * * @method displayChooser - * @param {HTMLElement} origin The calling button - * @param {Object} modal Our created modal for the section + * @param {Promise} modalPromise Our created modal for the section * @param {Array} sectionModules An array of all of the built module information * @param {Function} partialFavourite Partially applied function we need to manage favourite status */ -export const displayChooser = (origin, modal, sectionModules, partialFavourite) => { - +export const displayChooser = (modalPromise, sectionModules, partialFavourite) => { // Make a map so we can quickly fetch a specific module's object for either rendering or searching. const mappedModules = new Map(); sectionModules.forEach((module) => { @@ -514,39 +544,18 @@ export const displayChooser = (origin, modal, sectionModules, partialFavourite) }); // Register event listeners. - registerListenerEvents(modal, mappedModules, partialFavourite); + modalPromise.then(modal => { + registerListenerEvents(modal, mappedModules, partialFavourite); - // We want to focus on the action select when the dialog is closed. - modal.getRoot().on(ModalEvents.hidden, () => { - modal.destroy(); - }); + // We want to focus on the first chooser option element as soon as the modal is opened. + setupKeyboardAccessibility(modal, mappedModules); - // We want to focus on the first chooser option element as soon as the modal is opened. - modal.getRoot().on(ModalEvents.shown, () => { - modal.getModal()[0].tabIndex = -1; + // We want to focus on the action select when the dialog is closed. + modal.getRoot().on(ModalEvents.hidden, () => { + modal.destroy(); + }); - modal.getBodyPromise() - .then(body => { - $(selectors.elements.tab).on('shown.bs.tab', (e) => { - const activeSectionId = e.target.getAttribute("href"); - const activeSectionChooserOptions = body[0] - .querySelector(selectors.regions.getSectionChooserOptions(activeSectionId)); - const firstChooserOption = activeSectionChooserOptions - .querySelector(selectors.regions.chooserOption.container); - const prevActiveSectionId = e.relatedTarget.getAttribute("href"); - const prevActiveSectionChooserOptions = body[0] - .querySelector(selectors.regions.getSectionChooserOptions(prevActiveSectionId)); - - // Disable the focus of every chooser option in the previous active section. - disableFocusAllChooserOptions(prevActiveSectionChooserOptions); - // Enable the focus of the first chooser option in the current active section. - toggleFocusableChooserOption(firstChooserOption, true); - initChooserOptionsKeyboardNavigation(body[0], mappedModules, activeSectionChooserOptions); - }); - return; - }) - .catch(Notification.exception); - }); - - modal.show(); + return modal; + }) + .catch(); }; diff --git a/lib/amd/build/modal.min.js b/lib/amd/build/modal.min.js index 642c2ed7ccd..972b779bbec 100644 --- a/lib/amd/build/modal.min.js +++ b/lib/amd/build/modal.min.js @@ -1,2 +1,2 @@ -function _typeof(a){if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core/modal",["jquery","core/templates","core/notification","core/key_codes","core/custom_interaction_events","core/modal_backdrop","core/event","core/modal_events","core/local/aria/focuslock","core/pending"],function(a,b,c,d,e,f,g,h,i,j){var k={CONTAINER:"[data-region=\"modal-container\"]",MODAL:"[data-region=\"modal\"]",HEADER:"[data-region=\"header\"]",TITLE:"[data-region=\"title\"]",BODY:"[data-region=\"body\"]",FOOTER:"[data-region=\"footer\"]",HIDE:"[data-action=\"hide\"]",DIALOG:"[role=dialog]",FORM:"form",MENU_BAR:"[role=menubar]",HAS_Z_INDEX:".moodle-has-zindex",CAN_RECEIVE_FOCUS:"input:not([type=\"hidden\"]), a[href], button, textarea, select, [tabindex]"},l={LOADING:"core/loading",BACKDROP:"core/modal_backdrop"},m,n=0,o=function(b){this.root=a(b);this.modal=this.root.find(k.MODAL);this.header=this.modal.find(k.HEADER);this.headerPromise=a.Deferred();this.title=this.header.find(k.TITLE);this.titlePromise=a.Deferred();this.body=this.modal.find(k.BODY);this.bodyPromise=a.Deferred();this.footer=this.modal.find(k.FOOTER);this.footerPromise=a.Deferred();this.hiddenSiblings=[];this.isAttached=!1;this.bodyJS=null;this.footerJS=null;this.modalCount=n++;if(!this.root.is(k.CONTAINER)){c.exception({message:"Element is not a modal container"})}if(!this.modal.length){c.exception({message:"Container does not contain a modal"})}if(!this.header.length){c.exception({message:"Modal is missing a header region"})}if(!this.title.length){c.exception({message:"Modal header is missing a title region"})}if(!this.body.length){c.exception({message:"Modal is missing a body region"})}if(!this.footer.length){c.exception({message:"Modal is missing a footer region"})}this.registerEventListeners()};o.prototype.attachToDOM=function(){if(this.isAttached){return}a("body").append(this.root);i.trapFocus(this.root[0]);if(this.bodyJS){b.runTemplateJS(this.bodyJS);this.bodyJS=null}if(this.footerJS){b.runTemplateJS(this.footerJS);this.footerJS=null}this.isAttached=!0};o.prototype.countOtherVisibleModals=function(){var b=0;a("body").find(k.CONTAINER).each(function(c,d){d=a(d);if(!this.root.is(d)&&d.hasClass("show")){b++}}.bind(this));return b};o.prototype.getBackdrop=function(){if(!m){m=b.render(l.BACKDROP,{}).then(function(b){var c=a(b);return new f(c)}).fail(c.exception)}return m};o.prototype.getRoot=function(){return this.root};o.prototype.getModal=function(){return this.modal};o.prototype.getTitle=function(){return this.title};o.prototype.getBody=function(){return this.body};o.prototype.getFooter=function(){return this.footer};o.prototype.getTitlePromise=function(){return this.titlePromise};o.prototype.getBodyPromise=function(){return this.bodyPromise};o.prototype.getFooterPromise=function(){return this.footerPromise};o.prototype.getModalCount=function(){return this.modalCount};o.prototype.setTitle=function(b){var d=this.getTitle();this.titlePromise=a.Deferred();this.asyncSet(b,d.html.bind(d)).then(function(){this.titlePromise.resolve(d)}.bind(this)).catch(c.exception)};o.prototype.setBody=function(d){this.bodyPromise=a.Deferred();var e=this.getBody();if("string"==typeof d){e.html(d);g.notifyFilterContentUpdated(e);this.getRoot().trigger(h.bodyRendered,this);this.bodyPromise.resolve(e)}else{var f="amd-modal-js-pending-id-"+this.getModalCount();M.util.js_pending(f);var i=null;e.css("overflow","hidden");if("pending"==d.state()){var j=e.innerHeight();if(100>j){j=100}e.animate({height:j+"px"},150);e.html("");i=b.render(l.LOADING,{}).then(function(b){var c=a(b).hide();e.html(c);c.fadeIn(150);return a.when(c.promise(),d)}).then(function(a){return a.fadeOut(100).promise()}).then(function(){return d})}else{i=d}i.then(function(a,c){var d=null;if(this.isVisible()){e.css("opacity",0);var f=e.innerHeight();e.html(a);e.css("height","");var g=e.innerHeight();e.css("height",f+"px");d=e.animate({height:g+"px",opacity:1},{duration:150,queue:!1}).promise()}else{e.html(a)}if(c){if(this.isAttached){b.runTemplateJS(c)}else{this.bodyJS=c}}return d}.bind(this)).then(function(a){g.notifyFilterContentUpdated(e);this.getRoot().trigger(h.bodyRendered,this);return a}.bind(this)).then(function(){this.bodyPromise.resolve(e)}.bind(this)).fail(c.exception).always(function(){e.css("height","");e.css("overflow","");e.css("opacity","");M.util.js_complete(f)}).fail(c.exception)}};o.prototype.setFooter=function(d){this.showFooter();this.footerPromise=a.Deferred();var e=this.getFooter();if("string"==typeof d){e.html(d);this.footerPromise.resolve(e)}else{b.render(l.LOADING,{}).then(function(a){e.html(a);return d}).then(function(a,c){e.html(a);if(c){if(this.isAttached){b.runTemplateJS(c)}else{this.footerJS=c}}return e}.bind(this)).then(function(a){this.footerPromise.resolve(a)}.bind(this)).catch(c.exception)}};o.prototype.hasFooterContent=function(){return this.getFooter().children().length?!0:!1};o.prototype.hideFooter=function(){this.getFooter().addClass("hidden")};o.prototype.showFooter=function(){this.getFooter().removeClass("hidden")};o.prototype.setLarge=function(){if(this.isLarge()){return}this.getModal().addClass("modal-lg")};o.prototype.isLarge=function(){return this.getModal().hasClass("modal-lg")};o.prototype.setSmall=function(){if(this.isSmall()){return}this.getModal().removeClass("modal-lg")};o.prototype.isSmall=function(){return!this.getModal().hasClass("modal-lg")};o.prototype.calculateZIndex=function(){var b=a(k.DIALOG+", "+k.MENU_BAR+", "+k.HAS_Z_INDEX),c=parseInt(this.root.css("z-index"));b.each(function(b,d){d=a(d);var e=d.css("z-index")?parseInt(d.css("z-index")):0;if(e>c){c=e}});return c};o.prototype.isVisible=function(){return this.root.hasClass("show")};o.prototype.hasFocus=function(){var b=a(document.activeElement);return this.root.is(b)||this.root.has(b).length};o.prototype.hasTransitions=function(){return this.getRoot().hasClass("fade")};o.prototype.show=function(){if(this.isVisible()){return a.Deferred().resolve()}var b=new j("core/modal:show");if(this.hasFooterContent()){this.showFooter()}else{this.hideFooter()}if(!this.isAttached){this.attachToDOM()}return this.getBackdrop().then(function(b){var c=this.calculateZIndex(),d=c+2;this.root.css("z-index",d);b.setZIndex(d-1);b.show();this.root.removeClass("hide").addClass("show");this.accessibilityShow();this.getModal().focus();a("body").addClass("modal-open");this.root.trigger(h.shown,this)}.bind(this)).then(b.resolve)};o.prototype.hideIfNotForm=function(){var a=this.modal.find(k.FORM);if(0==a.length){this.hide()}};o.prototype.hide=function(){this.getBackdrop().done(function(b){i.untrapFocus();if(!this.countOtherVisibleModals()){b.hide();a("body").removeClass("modal-open")}var c=parseInt(this.root.css("z-index"));this.root.css("z-index","");b.setZIndex(c-3);this.accessibilityHide();if(this.hasTransitions()){this.getRoot().one("transitionend webkitTransitionEnd oTransitionEnd",function(){this.getRoot().removeClass("show").addClass("hide")}.bind(this))}else{this.getRoot().removeClass("show").addClass("hide")}this.root.trigger(h.hidden,this)}.bind(this))};o.prototype.destroy=function(){this.hide();this.root.remove();this.root.trigger(h.destroyed,this)};o.prototype.accessibilityShow=function(){a("body").children().each(function(b,c){if(!this.root.is(c)){c=a(c);var d=c.attr("aria-hidden");if("true"!==d){c.data("previous-aria-hidden",d);this.hiddenSiblings.push(c);c.attr("aria-hidden","true")}}}.bind(this));this.root.attr("aria-hidden","false")};o.prototype.accessibilityHide=function(){this.root.attr("aria-hidden","true");a.each(this.hiddenSiblings,function(b,c){c=a(c);var d=c.data("previous-aria-hidden");if("undefined"==typeof d){c.removeAttr("aria-hidden")}else{c.attr("aria-hidden",d)}});this.hiddenSiblings=[]};o.prototype.registerEventListeners=function(){this.getRoot().on("keydown",function(a){if(!this.isVisible()){return}if(a.keyCode==d.escape){this.hide()}}.bind(this));this.getRoot().click(function(b){if(!a(b.target).closest(k.MODAL).length){if(a(b.target).closest(k.CONTAINER).length){this.hideIfNotForm()}}}.bind(this));e.define(this.getModal(),[e.events.activate]);this.getModal().on(e.events.activate,k.HIDE,function(a,b){this.hide();b.originalEvent.preventDefault()}.bind(this))};o.prototype.registerCloseOnCancel=function(){this.getModal().on(e.events.activate,this.getActionSelector("cancel"),function(b,c){var d=a.Event(h.cancel);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){c.originalEvent.preventDefault();if(this.removeOnClose){this.destroy()}else{this.hide()}}}.bind(this))};o.prototype.registerCloseOnSave=function(){this.getModal().on(e.events.activate,this.getActionSelector("save"),function(b,c){var d=a.Event(h.save);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){c.originalEvent.preventDefault();if(this.removeOnClose){this.destroy()}else{this.hide()}}}.bind(this))};o.prototype.asyncSet=function(b,d){var e=b;if("object"!==_typeof(b)||!b.hasOwnProperty("then")){e=a.Deferred();e.resolve(b)}e.then(function(a){d(a)}).fail(c.exception);return e};o.prototype.setButtonText=function(a,b){var c=this.getFooter().find(this.getActionSelector(a));if(!c){throw new Error("Unable to find the '"+a+"' button")}return this.asyncSet(b,c.text.bind(c))};o.prototype.getActionSelector=function(a){return"[data-action='"+a+"']"};o.prototype.setRemoveOnClose=function(a){this.removeOnClose=a};return o}); +function _typeof(a){if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core/modal",["jquery","core/templates","core/notification","core/key_codes","core/custom_interaction_events","core/modal_backdrop","core/event","core/modal_events","core/local/aria/focuslock","core/pending"],function(a,b,c,d,e,f,g,h,i,j){var k={CONTAINER:"[data-region=\"modal-container\"]",MODAL:"[data-region=\"modal\"]",HEADER:"[data-region=\"header\"]",TITLE:"[data-region=\"title\"]",BODY:"[data-region=\"body\"]",FOOTER:"[data-region=\"footer\"]",HIDE:"[data-action=\"hide\"]",DIALOG:"[role=dialog]",FORM:"form",MENU_BAR:"[role=menubar]",HAS_Z_INDEX:".moodle-has-zindex",CAN_RECEIVE_FOCUS:"input:not([type=\"hidden\"]), a[href], button, textarea, select, [tabindex]"},l={LOADING:"core/loading",BACKDROP:"core/modal_backdrop"},m,n=0,o=function(b){this.root=a(b);this.modal=this.root.find(k.MODAL);this.header=this.modal.find(k.HEADER);this.headerPromise=a.Deferred();this.title=this.header.find(k.TITLE);this.titlePromise=a.Deferred();this.body=this.modal.find(k.BODY);this.bodyPromise=a.Deferred();this.footer=this.modal.find(k.FOOTER);this.footerPromise=a.Deferred();this.hiddenSiblings=[];this.isAttached=!1;this.bodyJS=null;this.footerJS=null;this.modalCount=n++;if(!this.root.is(k.CONTAINER)){c.exception({message:"Element is not a modal container"})}if(!this.modal.length){c.exception({message:"Container does not contain a modal"})}if(!this.header.length){c.exception({message:"Modal is missing a header region"})}if(!this.title.length){c.exception({message:"Modal header is missing a title region"})}if(!this.body.length){c.exception({message:"Modal is missing a body region"})}if(!this.footer.length){c.exception({message:"Modal is missing a footer region"})}this.registerEventListeners()};o.prototype.attachToDOM=function(){if(this.isAttached){return}a("body").append(this.root);i.trapFocus(this.root[0]);if(this.bodyJS){b.runTemplateJS(this.bodyJS);this.bodyJS=null}if(this.footerJS){b.runTemplateJS(this.footerJS);this.footerJS=null}this.isAttached=!0};o.prototype.countOtherVisibleModals=function(){var b=0;a("body").find(k.CONTAINER).each(function(c,d){d=a(d);if(!this.root.is(d)&&d.hasClass("show")){b++}}.bind(this));return b};o.prototype.getBackdrop=function(){if(!m){m=b.render(l.BACKDROP,{}).then(function(b){var c=a(b);return new f(c)}).fail(c.exception)}return m};o.prototype.getRoot=function(){return this.root};o.prototype.getModal=function(){return this.modal};o.prototype.getTitle=function(){return this.title};o.prototype.getBody=function(){return this.body};o.prototype.getFooter=function(){return this.footer};o.prototype.getTitlePromise=function(){return this.titlePromise};o.prototype.getBodyPromise=function(){return this.bodyPromise};o.prototype.getFooterPromise=function(){return this.footerPromise};o.prototype.getModalCount=function(){return this.modalCount};o.prototype.setTitle=function(b){var d=this.getTitle();this.titlePromise=a.Deferred();this.asyncSet(b,d.html.bind(d)).then(function(){this.titlePromise.resolve(d)}.bind(this)).catch(c.exception)};o.prototype.setBody=function(d){this.bodyPromise=a.Deferred();var e=this.getBody();if("string"==typeof d){e.html(d);g.notifyFilterContentUpdated(e);this.getRoot().trigger(h.bodyRendered,this);this.bodyPromise.resolve(e)}else{var f="amd-modal-js-pending-id-"+this.getModalCount();M.util.js_pending(f);var i=null;e.css("overflow","hidden");d=a.when(d);if("pending"==d.state()){var j=e.innerHeight();if(100>j){j=100}e.animate({height:j+"px"},150);e.html("");i=b.render(l.LOADING,{}).then(function(b){var c=a(b).hide();e.html(c);c.fadeIn(150);return a.when(c.promise(),d)}).then(function(a){return a.fadeOut(100).promise()}).then(function(){return d})}else{i=d}i.then(function(a,c){var d=null;if(this.isVisible()){e.css("opacity",0);var f=e.innerHeight();e.html(a);e.css("height","");var g=e.innerHeight();e.css("height",f+"px");d=e.animate({height:g+"px",opacity:1},{duration:150,queue:!1}).promise()}else{e.html(a)}if(c){if(this.isAttached){b.runTemplateJS(c)}else{this.bodyJS=c}}return d}.bind(this)).then(function(a){g.notifyFilterContentUpdated(e);this.getRoot().trigger(h.bodyRendered,this);return a}.bind(this)).then(function(){this.bodyPromise.resolve(e)}.bind(this)).fail(c.exception).always(function(){e.css("height","");e.css("overflow","");e.css("opacity","");M.util.js_complete(f)}).fail(c.exception)}};o.prototype.setFooter=function(d){this.showFooter();this.footerPromise=a.Deferred();var e=this.getFooter();if("string"==typeof d){e.html(d);this.footerPromise.resolve(e)}else{b.render(l.LOADING,{}).then(function(a){e.html(a);return d}).then(function(a,c){e.html(a);if(c){if(this.isAttached){b.runTemplateJS(c)}else{this.footerJS=c}}return e}.bind(this)).then(function(a){this.footerPromise.resolve(a)}.bind(this)).catch(c.exception)}};o.prototype.hasFooterContent=function(){return this.getFooter().children().length?!0:!1};o.prototype.hideFooter=function(){this.getFooter().addClass("hidden")};o.prototype.showFooter=function(){this.getFooter().removeClass("hidden")};o.prototype.setLarge=function(){if(this.isLarge()){return}this.getModal().addClass("modal-lg")};o.prototype.isLarge=function(){return this.getModal().hasClass("modal-lg")};o.prototype.setSmall=function(){if(this.isSmall()){return}this.getModal().removeClass("modal-lg")};o.prototype.isSmall=function(){return!this.getModal().hasClass("modal-lg")};o.prototype.calculateZIndex=function(){var b=a(k.DIALOG+", "+k.MENU_BAR+", "+k.HAS_Z_INDEX),c=parseInt(this.root.css("z-index"));b.each(function(b,d){d=a(d);var e=d.css("z-index")?parseInt(d.css("z-index")):0;if(e>c){c=e}});return c};o.prototype.isVisible=function(){return this.root.hasClass("show")};o.prototype.hasFocus=function(){var b=a(document.activeElement);return this.root.is(b)||this.root.has(b).length};o.prototype.hasTransitions=function(){return this.getRoot().hasClass("fade")};o.prototype.show=function(){if(this.isVisible()){return a.Deferred().resolve()}var b=new j("core/modal:show");if(this.hasFooterContent()){this.showFooter()}else{this.hideFooter()}if(!this.isAttached){this.attachToDOM()}return this.getBackdrop().then(function(b){var c=this.calculateZIndex(),d=c+2;this.root.css("z-index",d);b.setZIndex(d-1);b.show();this.root.removeClass("hide").addClass("show");this.accessibilityShow();this.getModal().focus();a("body").addClass("modal-open");this.root.trigger(h.shown,this)}.bind(this)).then(b.resolve)};o.prototype.hideIfNotForm=function(){var a=this.modal.find(k.FORM);if(0==a.length){this.hide()}};o.prototype.hide=function(){this.getBackdrop().done(function(b){i.untrapFocus();if(!this.countOtherVisibleModals()){b.hide();a("body").removeClass("modal-open")}var c=parseInt(this.root.css("z-index"));this.root.css("z-index","");b.setZIndex(c-3);this.accessibilityHide();if(this.hasTransitions()){this.getRoot().one("transitionend webkitTransitionEnd oTransitionEnd",function(){this.getRoot().removeClass("show").addClass("hide")}.bind(this))}else{this.getRoot().removeClass("show").addClass("hide")}this.root.trigger(h.hidden,this)}.bind(this))};o.prototype.destroy=function(){this.hide();this.root.remove();this.root.trigger(h.destroyed,this)};o.prototype.accessibilityShow=function(){a("body").children().each(function(b,c){if(!this.root.is(c)){c=a(c);var d=c.attr("aria-hidden");if("true"!==d){c.data("previous-aria-hidden",d);this.hiddenSiblings.push(c);c.attr("aria-hidden","true")}}}.bind(this));this.root.attr("aria-hidden","false")};o.prototype.accessibilityHide=function(){this.root.attr("aria-hidden","true");a.each(this.hiddenSiblings,function(b,c){c=a(c);var d=c.data("previous-aria-hidden");if("undefined"==typeof d){c.removeAttr("aria-hidden")}else{c.attr("aria-hidden",d)}});this.hiddenSiblings=[]};o.prototype.registerEventListeners=function(){this.getRoot().on("keydown",function(a){if(!this.isVisible()){return}if(a.keyCode==d.escape){this.hide()}}.bind(this));this.getRoot().click(function(b){if(!a(b.target).closest(k.MODAL).length){if(a(b.target).closest(k.CONTAINER).length){this.hideIfNotForm()}}}.bind(this));e.define(this.getModal(),[e.events.activate]);this.getModal().on(e.events.activate,k.HIDE,function(a,b){this.hide();b.originalEvent.preventDefault()}.bind(this))};o.prototype.registerCloseOnCancel=function(){this.getModal().on(e.events.activate,this.getActionSelector("cancel"),function(b,c){var d=a.Event(h.cancel);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){c.originalEvent.preventDefault();if(this.removeOnClose){this.destroy()}else{this.hide()}}}.bind(this))};o.prototype.registerCloseOnSave=function(){this.getModal().on(e.events.activate,this.getActionSelector("save"),function(b,c){var d=a.Event(h.save);this.getRoot().trigger(d,this);if(!d.isDefaultPrevented()){c.originalEvent.preventDefault();if(this.removeOnClose){this.destroy()}else{this.hide()}}}.bind(this))};o.prototype.asyncSet=function(b,d){var e=b;if("object"!==_typeof(b)||!b.hasOwnProperty("then")){e=a.Deferred();e.resolve(b)}e.then(function(a){d(a)}).fail(c.exception);return e};o.prototype.setButtonText=function(a,b){var c=this.getFooter().find(this.getActionSelector(a));if(!c){throw new Error("Unable to find the '"+a+"' button")}return this.asyncSet(b,c.text.bind(c))};o.prototype.getActionSelector=function(a){return"[data-action='"+a+"']"};o.prototype.setRemoveOnClose=function(a){this.removeOnClose=a};return o}); //# sourceMappingURL=modal.min.js.map diff --git a/lib/amd/build/modal.min.js.map b/lib/amd/build/modal.min.js.map index cb5d00f1c77..c8ac6e4b880 100644 --- a/lib/amd/build/modal.min.js.map +++ b/lib/amd/build/modal.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/modal.js"],"names":["define","$","Templates","Notification","KeyCodes","CustomEvents","ModalBackdrop","Event","ModalEvents","FocusLock","Pending","SELECTORS","CONTAINER","MODAL","HEADER","TITLE","BODY","FOOTER","HIDE","DIALOG","FORM","MENU_BAR","HAS_Z_INDEX","CAN_RECEIVE_FOCUS","TEMPLATES","LOADING","BACKDROP","backdropPromise","modalCounter","Modal","root","modal","find","header","headerPromise","Deferred","title","titlePromise","body","bodyPromise","footer","footerPromise","hiddenSiblings","isAttached","bodyJS","footerJS","modalCount","is","exception","message","length","registerEventListeners","prototype","attachToDOM","append","trapFocus","runTemplateJS","countOtherVisibleModals","count","each","index","element","hasClass","bind","getBackdrop","render","then","html","fail","getRoot","getModal","getTitle","getBody","getFooter","getTitlePromise","getBodyPromise","getFooterPromise","getModalCount","setTitle","value","asyncSet","resolve","catch","setBody","notifyFilterContentUpdated","trigger","bodyRendered","jsPendingId","M","util","js_pending","contentPromise","css","state","height","innerHeight","animate","loadingIcon","hide","fadeIn","when","promise","fadeOut","js","result","isVisible","currentHeight","newHeight","opacity","duration","queue","always","js_complete","setFooter","showFooter","hasFooterContent","children","hideFooter","addClass","removeClass","setLarge","isLarge","setSmall","isSmall","calculateZIndex","items","zIndex","parseInt","item","itemZIndex","hasFocus","target","document","activeElement","has","hasTransitions","show","pendingPromise","backdrop","currentIndex","newIndex","setZIndex","accessibilityShow","focus","shown","hideIfNotForm","formElement","done","untrapFocus","accessibilityHide","one","hidden","destroy","remove","destroyed","child","attr","data","push","sibling","previousValue","removeAttr","on","e","keyCode","escape","click","closest","events","activate","originalEvent","preventDefault","registerCloseOnCancel","getActionSelector","cancelEvent","cancel","isDefaultPrevented","removeOnClose","registerCloseOnSave","saveEvent","save","setFunction","p","hasOwnProperty","content","setButtonText","action","button","Error","text","setRemoveOnClose"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Contain the logic for modals.\n *\n * @module core/modal\n * @class modal\n * @package core\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core/key_codes',\n 'core/custom_interaction_events',\n 'core/modal_backdrop',\n 'core/event',\n 'core/modal_events',\n 'core/local/aria/focuslock',\n 'core/pending',\n], function($, Templates, Notification, KeyCodes, CustomEvents, ModalBackdrop, Event, ModalEvents, FocusLock, Pending) {\n\n var SELECTORS = {\n CONTAINER: '[data-region=\"modal-container\"]',\n MODAL: '[data-region=\"modal\"]',\n HEADER: '[data-region=\"header\"]',\n TITLE: '[data-region=\"title\"]',\n BODY: '[data-region=\"body\"]',\n FOOTER: '[data-region=\"footer\"]',\n HIDE: '[data-action=\"hide\"]',\n DIALOG: '[role=dialog]',\n FORM: 'form',\n MENU_BAR: '[role=menubar]',\n HAS_Z_INDEX: '.moodle-has-zindex',\n CAN_RECEIVE_FOCUS: 'input:not([type=\"hidden\"]), a[href], button, textarea, select, [tabindex]',\n };\n\n var TEMPLATES = {\n LOADING: 'core/loading',\n BACKDROP: 'core/modal_backdrop',\n };\n\n /**\n * Module singleton for the backdrop to be reused by all Modal instances.\n */\n var backdropPromise;\n\n /**\n * A counter that gets incremented for each modal created. This can be\n * used to generate unique values for the modals.\n */\n var modalCounter = 0;\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var Modal = function(root) {\n this.root = $(root);\n this.modal = this.root.find(SELECTORS.MODAL);\n this.header = this.modal.find(SELECTORS.HEADER);\n this.headerPromise = $.Deferred();\n this.title = this.header.find(SELECTORS.TITLE);\n this.titlePromise = $.Deferred();\n this.body = this.modal.find(SELECTORS.BODY);\n this.bodyPromise = $.Deferred();\n this.footer = this.modal.find(SELECTORS.FOOTER);\n this.footerPromise = $.Deferred();\n this.hiddenSiblings = [];\n this.isAttached = false;\n this.bodyJS = null;\n this.footerJS = null;\n this.modalCount = modalCounter++;\n\n if (!this.root.is(SELECTORS.CONTAINER)) {\n Notification.exception({message: 'Element is not a modal container'});\n }\n\n if (!this.modal.length) {\n Notification.exception({message: 'Container does not contain a modal'});\n }\n\n if (!this.header.length) {\n Notification.exception({message: 'Modal is missing a header region'});\n }\n\n if (!this.title.length) {\n Notification.exception({message: 'Modal header is missing a title region'});\n }\n\n if (!this.body.length) {\n Notification.exception({message: 'Modal is missing a body region'});\n }\n\n if (!this.footer.length) {\n Notification.exception({message: 'Modal is missing a footer region'});\n }\n\n this.registerEventListeners();\n };\n\n /**\n * Add the modal to the page, if it hasn't already been added. This includes running any\n * javascript that has been cached until now.\n *\n * @method attachToDOM\n */\n Modal.prototype.attachToDOM = function() {\n if (this.isAttached) {\n return;\n }\n\n $('body').append(this.root);\n FocusLock.trapFocus(this.root[0]);\n\n // If we'd cached any JS then we can run it how that the modal is\n // attached to the DOM.\n if (this.bodyJS) {\n Templates.runTemplateJS(this.bodyJS);\n this.bodyJS = null;\n }\n\n if (this.footerJS) {\n Templates.runTemplateJS(this.footerJS);\n this.footerJS = null;\n }\n\n this.isAttached = true;\n };\n\n /**\n * Count the number of other visible modals (not including this one).\n *\n * @method countOtherVisibleModals\n * @return {int}\n */\n Modal.prototype.countOtherVisibleModals = function() {\n var count = 0;\n $('body').find(SELECTORS.CONTAINER).each(function(index, element) {\n element = $(element);\n\n // If we haven't found ourself and the element is visible.\n if (!this.root.is(element) && element.hasClass('show')) {\n count++;\n }\n }.bind(this));\n\n return count;\n };\n\n /**\n * Get the modal backdrop.\n *\n * @method getBackdrop\n * @return {object} jQuery promise\n */\n Modal.prototype.getBackdrop = function() {\n if (!backdropPromise) {\n backdropPromise = Templates.render(TEMPLATES.BACKDROP, {})\n .then(function(html) {\n var element = $(html);\n\n return new ModalBackdrop(element);\n })\n .fail(Notification.exception);\n }\n\n return backdropPromise;\n };\n\n /**\n * Get the root element of this modal.\n *\n * @method getRoot\n * @return {object} jQuery object\n */\n Modal.prototype.getRoot = function() {\n return this.root;\n };\n\n /**\n * Get the modal element of this modal.\n *\n * @method getModal\n * @return {object} jQuery object\n */\n Modal.prototype.getModal = function() {\n return this.modal;\n };\n\n /**\n * Get the modal title element.\n *\n * @method getTitle\n * @return {object} jQuery object\n */\n Modal.prototype.getTitle = function() {\n return this.title;\n };\n\n /**\n * Get the modal body element.\n *\n * @method getBody\n * @return {object} jQuery object\n */\n Modal.prototype.getBody = function() {\n return this.body;\n };\n\n /**\n * Get the modal footer element.\n *\n * @method getFooter\n * @return {object} jQuery object\n */\n Modal.prototype.getFooter = function() {\n return this.footer;\n };\n\n /**\n * Get a promise resolving to the title region.\n *\n * @method getTitlePromise\n * @return {Promise}\n */\n Modal.prototype.getTitlePromise = function() {\n return this.titlePromise;\n };\n\n /**\n * Get a promise resolving to the body region.\n *\n * @method getBodyPromise\n * @return {object} jQuery object\n */\n Modal.prototype.getBodyPromise = function() {\n return this.bodyPromise;\n };\n\n /**\n * Get a promise resolving to the footer region.\n *\n * @method getFooterPromise\n * @return {object} jQuery object\n */\n Modal.prototype.getFooterPromise = function() {\n return this.footerPromise;\n };\n\n /**\n * Get the unique modal count.\n *\n * @method getModalCount\n * @return {int}\n */\n Modal.prototype.getModalCount = function() {\n return this.modalCount;\n };\n\n /**\n * Set the modal title element.\n *\n * This method is overloaded to take either a string value for the title or a jQuery promise that is resolved with\n * HTML most commonly from a Str.get_string call.\n *\n * @method setTitle\n * @param {(string|object)} value The title string or jQuery promise which resolves to the title.\n */\n Modal.prototype.setTitle = function(value) {\n var title = this.getTitle();\n this.titlePromise = $.Deferred();\n\n this.asyncSet(value, title.html.bind(title))\n .then(function() {\n this.titlePromise.resolve(title);\n }.bind(this))\n .catch(Notification.exception);\n };\n\n /**\n * Set the modal body element.\n *\n * This method is overloaded to take either a string value for the body or a jQuery promise that is resolved with\n * HTML and Javascript most commonly from a Templates.render call.\n *\n * @method setBody\n * @param {(string|object)} value The body string or jQuery promise which resolves to the body.\n */\n Modal.prototype.setBody = function(value) {\n this.bodyPromise = $.Deferred();\n\n var body = this.getBody();\n\n if (typeof value === 'string') {\n // Just set the value if it's a string.\n body.html(value);\n Event.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n this.bodyPromise.resolve(body);\n } else {\n var jsPendingId = 'amd-modal-js-pending-id-' + this.getModalCount();\n M.util.js_pending(jsPendingId);\n // Otherwise we assume it's a promise to be resolved with\n // html and javascript.\n var contentPromise = null;\n body.css('overflow', 'hidden');\n\n if (value.state() == 'pending') {\n // We're still waiting for the body promise to resolve so\n // let's show a loading icon.\n var height = body.innerHeight();\n if (height < 100) {\n height = 100;\n }\n\n body.animate({height: height + 'px'}, 150);\n\n body.html('');\n contentPromise = Templates.render(TEMPLATES.LOADING, {})\n .then(function(html) {\n var loadingIcon = $(html).hide();\n body.html(loadingIcon);\n loadingIcon.fadeIn(150);\n\n // We only want the loading icon to fade out\n // when the content for the body has finished\n // loading.\n return $.when(loadingIcon.promise(), value);\n })\n .then(function(loadingIcon) {\n // Once the content has finished loading and\n // the loading icon has been shown then we can\n // fade the icon away to reveal the content.\n return loadingIcon.fadeOut(100).promise();\n })\n .then(function() {\n return value;\n });\n } else {\n // The content is already loaded so let's just display\n // it to the user. No need for a loading icon.\n contentPromise = value;\n }\n\n // Now we can actually display the content.\n contentPromise.then(function(html, js) {\n var result = null;\n\n if (this.isVisible()) {\n // If the modal is visible then we should display\n // the content gracefully for the user.\n body.css('opacity', 0);\n var currentHeight = body.innerHeight();\n body.html(html);\n // We need to clear any height values we've set here\n // in order to measure the height of the content being\n // added. This then allows us to animate the height\n // transition.\n body.css('height', '');\n var newHeight = body.innerHeight();\n body.css('height', currentHeight + 'px');\n result = body.animate(\n {height: newHeight + 'px', opacity: 1},\n {duration: 150, queue: false}\n ).promise();\n } else {\n // Since the modal isn't visible we can just immediately\n // set the content. No need to animate it.\n body.html(html);\n }\n\n if (js) {\n if (this.isAttached) {\n // If we're in the DOM then run the JS immediately.\n Templates.runTemplateJS(js);\n } else {\n // Otherwise cache it to be run when we're attached.\n this.bodyJS = js;\n }\n }\n\n return result;\n }.bind(this))\n .then(function(result) {\n Event.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n return result;\n }.bind(this))\n .then(function() {\n this.bodyPromise.resolve(body);\n return;\n }.bind(this))\n .fail(Notification.exception)\n .always(function() {\n // When we're done displaying all of the content we need\n // to clear the custom values we've set here.\n body.css('height', '');\n body.css('overflow', '');\n body.css('opacity', '');\n M.util.js_complete(jsPendingId);\n\n return;\n })\n .fail(Notification.exception);\n }\n };\n\n /**\n * Set the modal footer element. The footer element is made visible, if it\n * isn't already.\n *\n * This method is overloaded to take either a string\n * value for the body or a jQuery promise that is resolved with HTML and Javascript\n * most commonly from a Templates.render call.\n *\n * @method setFooter\n * @param {(string|object)} value The footer string or jQuery promise\n */\n Modal.prototype.setFooter = function(value) {\n // Make sure the footer is visible.\n this.showFooter();\n this.footerPromise = $.Deferred();\n\n var footer = this.getFooter();\n\n if (typeof value === 'string') {\n // Just set the value if it's a string.\n footer.html(value);\n this.footerPromise.resolve(footer);\n } else {\n // Otherwise we assume it's a promise to be resolved with\n // html and javascript.\n Templates.render(TEMPLATES.LOADING, {})\n .then(function(html) {\n footer.html(html);\n\n return value;\n })\n .then(function(html, js) {\n footer.html(html);\n\n if (js) {\n if (this.isAttached) {\n // If we're in the DOM then run the JS immediately.\n Templates.runTemplateJS(js);\n } else {\n // Otherwise cache it to be run when we're attached.\n this.footerJS = js;\n }\n }\n\n return footer;\n }.bind(this))\n .then(function(footer) {\n this.footerPromise.resolve(footer);\n return;\n }.bind(this))\n .catch(Notification.exception);\n }\n };\n\n /**\n * Check if the footer has any content in it.\n *\n * @method hasFooterContent\n * @return {bool}\n */\n Modal.prototype.hasFooterContent = function() {\n return this.getFooter().children().length ? true : false;\n };\n\n /**\n * Hide the footer element.\n *\n * @method hideFooter\n */\n Modal.prototype.hideFooter = function() {\n this.getFooter().addClass('hidden');\n };\n\n /**\n * Show the footer element.\n *\n * @method showFooter\n */\n Modal.prototype.showFooter = function() {\n this.getFooter().removeClass('hidden');\n };\n\n /**\n * Mark the modal as a large modal.\n *\n * @method setLarge\n */\n Modal.prototype.setLarge = function() {\n if (this.isLarge()) {\n return;\n }\n\n this.getModal().addClass('modal-lg');\n };\n\n /**\n * Check if the modal is a large modal.\n *\n * @method isLarge\n * @return {bool}\n */\n Modal.prototype.isLarge = function() {\n return this.getModal().hasClass('modal-lg');\n };\n\n /**\n * Mark the modal as a small modal.\n *\n * @method setSmall\n */\n Modal.prototype.setSmall = function() {\n if (this.isSmall()) {\n return;\n }\n\n this.getModal().removeClass('modal-lg');\n };\n\n /**\n * Check if the modal is a small modal.\n *\n * @method isSmall\n * @return {bool}\n */\n Modal.prototype.isSmall = function() {\n return !this.getModal().hasClass('modal-lg');\n };\n\n /**\n * Determine the highest z-index value currently on the page.\n *\n * @method calculateZIndex\n * @return {int}\n */\n Modal.prototype.calculateZIndex = function() {\n var items = $(SELECTORS.DIALOG + ', ' + SELECTORS.MENU_BAR + ', ' + SELECTORS.HAS_Z_INDEX);\n var zIndex = parseInt(this.root.css('z-index'));\n\n items.each(function(index, item) {\n item = $(item);\n // Note that webkit browsers won't return the z-index value from the CSS stylesheet\n // if the element doesn't have a position specified. Instead it'll return \"auto\".\n var itemZIndex = item.css('z-index') ? parseInt(item.css('z-index')) : 0;\n\n if (itemZIndex > zIndex) {\n zIndex = itemZIndex;\n }\n });\n\n return zIndex;\n };\n\n /**\n * Check if this modal is visible.\n *\n * @method isVisible\n * @return {bool}\n */\n Modal.prototype.isVisible = function() {\n return this.root.hasClass('show');\n };\n\n /**\n * Check if this modal has focus.\n *\n * @method hasFocus\n * @return {bool}\n */\n Modal.prototype.hasFocus = function() {\n var target = $(document.activeElement);\n return this.root.is(target) || this.root.has(target).length;\n };\n\n /**\n * Check if this modal has CSS transitions applied.\n *\n * @method hasTransitions\n * @return {bool}\n */\n Modal.prototype.hasTransitions = function() {\n return this.getRoot().hasClass('fade');\n };\n\n /**\n * Display this modal. The modal will be attached to the DOM if it hasn't\n * already been.\n *\n * @method show\n * @returns {Promise}\n */\n Modal.prototype.show = function() {\n if (this.isVisible()) {\n return $.Deferred().resolve();\n }\n\n var pendingPromise = new Pending('core/modal:show');\n\n if (this.hasFooterContent()) {\n this.showFooter();\n } else {\n this.hideFooter();\n }\n\n if (!this.isAttached) {\n this.attachToDOM();\n }\n\n return this.getBackdrop()\n .then(function(backdrop) {\n var currentIndex = this.calculateZIndex();\n var newIndex = currentIndex + 2;\n var newBackdropIndex = newIndex - 1;\n this.root.css('z-index', newIndex);\n backdrop.setZIndex(newBackdropIndex);\n backdrop.show();\n\n this.root.removeClass('hide').addClass('show');\n this.accessibilityShow();\n this.getModal().focus();\n $('body').addClass('modal-open');\n this.root.trigger(ModalEvents.shown, this);\n\n return;\n }.bind(this))\n .then(pendingPromise.resolve);\n };\n\n /**\n * Hide this modal if it does not contain a form.\n *\n * @method hideIfNotForm\n */\n Modal.prototype.hideIfNotForm = function() {\n var formElement = this.modal.find(SELECTORS.FORM);\n if (formElement.length == 0) {\n this.hide();\n }\n };\n\n /**\n * Hide this modal.\n *\n * @method hide\n */\n Modal.prototype.hide = function() {\n this.getBackdrop().done(function(backdrop) {\n FocusLock.untrapFocus();\n if (!this.countOtherVisibleModals()) {\n // Hide the backdrop if we're the last open modal.\n backdrop.hide();\n $('body').removeClass('modal-open');\n }\n\n var currentIndex = parseInt(this.root.css('z-index'));\n this.root.css('z-index', '');\n backdrop.setZIndex(currentIndex - 3);\n\n this.accessibilityHide();\n\n if (this.hasTransitions()) {\n // Wait for CSS transitions to complete before hiding the element.\n this.getRoot().one('transitionend webkitTransitionEnd oTransitionEnd', function() {\n this.getRoot().removeClass('show').addClass('hide');\n }.bind(this));\n } else {\n this.getRoot().removeClass('show').addClass('hide');\n }\n\n this.root.trigger(ModalEvents.hidden, this);\n }.bind(this));\n };\n\n /**\n * Remove this modal from the DOM.\n *\n * @method destroy\n */\n Modal.prototype.destroy = function() {\n this.hide();\n this.root.remove();\n this.root.trigger(ModalEvents.destroyed, this);\n };\n\n /**\n * Sets the appropriate aria attributes on this dialogue and the other\n * elements in the DOM to ensure that screen readers are able to navigate\n * the dialogue popup correctly.\n *\n * @method accessibilityShow\n */\n Modal.prototype.accessibilityShow = function() {\n // We need to get a list containing each sibling element and the shallowest\n // non-ancestral nodes in the DOM. We can shortcut this a little by leveraging\n // the fact that this dialogue is always appended to the document body therefore\n // it's siblings are the shallowest non-ancestral nodes. If that changes then\n // this code should also be updated.\n $('body').children().each(function(index, child) {\n // Skip the current modal.\n if (!this.root.is(child)) {\n child = $(child);\n var hidden = child.attr('aria-hidden');\n // If they are already hidden we can ignore them.\n if (hidden !== 'true') {\n // Save their current state.\n child.data('previous-aria-hidden', hidden);\n this.hiddenSiblings.push(child);\n\n // Hide this node from screen readers.\n child.attr('aria-hidden', 'true');\n }\n }\n }.bind(this));\n\n // Make us visible to screen readers.\n this.root.attr('aria-hidden', 'false');\n };\n\n /**\n * Restores the aria visibility on the DOM elements changed when displaying\n * the dialogue popup and makes the dialogue aria hidden to allow screen\n * readers to navigate the main page correctly when the dialogue is closed.\n *\n * @method accessibilityHide\n */\n Modal.prototype.accessibilityHide = function() {\n this.root.attr('aria-hidden', 'true');\n\n // Restore the sibling nodes back to their original values.\n $.each(this.hiddenSiblings, function(index, sibling) {\n sibling = $(sibling);\n var previousValue = sibling.data('previous-aria-hidden');\n // If the element didn't previously have an aria-hidden attribute\n // then we can just remove the one we set.\n if (typeof previousValue == 'undefined') {\n sibling.removeAttr('aria-hidden');\n } else {\n // Otherwise set it back to the old value (which will be false).\n sibling.attr('aria-hidden', previousValue);\n }\n });\n\n // Clear the cache. No longer need to store these.\n this.hiddenSiblings = [];\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n Modal.prototype.registerEventListeners = function() {\n this.getRoot().on('keydown', function(e) {\n if (!this.isVisible()) {\n return;\n }\n\n if (e.keyCode == KeyCodes.escape) {\n this.hide();\n }\n }.bind(this));\n\n // Listen for clicks on the modal container.\n this.getRoot().click(function(e) {\n // If the click wasn't inside the modal element then we should\n // hide the modal.\n if (!$(e.target).closest(SELECTORS.MODAL).length) {\n // The check above fails to detect the click was inside the modal when the DOM tree is already changed.\n // So, we check if we can still find the container element or not. If not, then the DOM tree is changed.\n // It's best not to hide the modal in that case.\n if ($(e.target).closest(SELECTORS.CONTAINER).length) {\n this.hideIfNotForm();\n }\n }\n }.bind(this));\n\n CustomEvents.define(this.getModal(), [CustomEvents.events.activate]);\n this.getModal().on(CustomEvents.events.activate, SELECTORS.HIDE, function(e, data) {\n this.hide();\n data.originalEvent.preventDefault();\n }.bind(this));\n };\n\n /**\n * Register a listener to close the dialogue when the cancel button is pressed.\n *\n * @method registerCloseOnCancel\n */\n Modal.prototype.registerCloseOnCancel = function() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('cancel'), function(e, data) {\n var cancelEvent = $.Event(ModalEvents.cancel);\n this.getRoot().trigger(cancelEvent, this);\n\n if (!cancelEvent.isDefaultPrevented()) {\n data.originalEvent.preventDefault();\n\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n }.bind(this));\n };\n\n /**\n * Register a listener to close the dialogue when the save button is pressed.\n *\n * @method registerCloseOnSave\n */\n Modal.prototype.registerCloseOnSave = function() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('save'), function(e, data) {\n var saveEvent = $.Event(ModalEvents.save);\n this.getRoot().trigger(saveEvent, this);\n\n if (!saveEvent.isDefaultPrevented()) {\n data.originalEvent.preventDefault();\n\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n }.bind(this));\n };\n\n /**\n * Set or resolve and set the value using the function.\n *\n * @method asyncSet\n * @param {(string|object)} value The string or jQuery promise.\n * @param {function} setFunction The setter\n * @return {Promise}\n */\n Modal.prototype.asyncSet = function(value, setFunction) {\n var p = value;\n if (typeof value !== 'object' || !value.hasOwnProperty('then')) {\n p = $.Deferred();\n p.resolve(value);\n }\n\n p.then(function(content) {\n setFunction(content);\n\n return;\n })\n .fail(Notification.exception);\n\n return p;\n };\n\n /**\n * Set the title text of a button.\n *\n * This method is overloaded to take either a string value for the button title or a jQuery promise that is resolved with\n * text most commonly from a Str.get_string call.\n *\n * @param {DOMString} action The action of the button\n * @param {(String|object)} value The button text, or a promise which will resolve to it\n * @returns {Promise}\n */\n Modal.prototype.setButtonText = function(action, value) {\n const button = this.getFooter().find(this.getActionSelector(action));\n\n if (!button) {\n throw new Error(\"Unable to find the '\" + action + \"' button\");\n }\n\n return this.asyncSet(value, button.text.bind(button));\n };\n\n /**\n * Get the Selector for an action.\n *\n * @param {String} action\n * @returns {DOMString}\n */\n Modal.prototype.getActionSelector = function(action) {\n return \"[data-action='\" + action + \"']\";\n };\n\n /**\n * Set the flag to remove the modal from the DOM on close.\n *\n * @param {Boolean} remove\n */\n Modal.prototype.setRemoveOnClose = function(remove) {\n this.removeOnClose = remove;\n };\n\n return Modal;\n});\n"],"file":"modal.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/modal.js"],"names":["define","$","Templates","Notification","KeyCodes","CustomEvents","ModalBackdrop","Event","ModalEvents","FocusLock","Pending","SELECTORS","CONTAINER","MODAL","HEADER","TITLE","BODY","FOOTER","HIDE","DIALOG","FORM","MENU_BAR","HAS_Z_INDEX","CAN_RECEIVE_FOCUS","TEMPLATES","LOADING","BACKDROP","backdropPromise","modalCounter","Modal","root","modal","find","header","headerPromise","Deferred","title","titlePromise","body","bodyPromise","footer","footerPromise","hiddenSiblings","isAttached","bodyJS","footerJS","modalCount","is","exception","message","length","registerEventListeners","prototype","attachToDOM","append","trapFocus","runTemplateJS","countOtherVisibleModals","count","each","index","element","hasClass","bind","getBackdrop","render","then","html","fail","getRoot","getModal","getTitle","getBody","getFooter","getTitlePromise","getBodyPromise","getFooterPromise","getModalCount","setTitle","value","asyncSet","resolve","catch","setBody","notifyFilterContentUpdated","trigger","bodyRendered","jsPendingId","M","util","js_pending","contentPromise","css","when","state","height","innerHeight","animate","loadingIcon","hide","fadeIn","promise","fadeOut","js","result","isVisible","currentHeight","newHeight","opacity","duration","queue","always","js_complete","setFooter","showFooter","hasFooterContent","children","hideFooter","addClass","removeClass","setLarge","isLarge","setSmall","isSmall","calculateZIndex","items","zIndex","parseInt","item","itemZIndex","hasFocus","target","document","activeElement","has","hasTransitions","show","pendingPromise","backdrop","currentIndex","newIndex","setZIndex","accessibilityShow","focus","shown","hideIfNotForm","formElement","done","untrapFocus","accessibilityHide","one","hidden","destroy","remove","destroyed","child","attr","data","push","sibling","previousValue","removeAttr","on","e","keyCode","escape","click","closest","events","activate","originalEvent","preventDefault","registerCloseOnCancel","getActionSelector","cancelEvent","cancel","isDefaultPrevented","removeOnClose","registerCloseOnSave","saveEvent","save","setFunction","p","hasOwnProperty","content","setButtonText","action","button","Error","text","setRemoveOnClose"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Contain the logic for modals.\n *\n * @module core/modal\n * @class modal\n * @package core\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core/key_codes',\n 'core/custom_interaction_events',\n 'core/modal_backdrop',\n 'core/event',\n 'core/modal_events',\n 'core/local/aria/focuslock',\n 'core/pending',\n], function($, Templates, Notification, KeyCodes, CustomEvents, ModalBackdrop, Event, ModalEvents, FocusLock, Pending) {\n\n var SELECTORS = {\n CONTAINER: '[data-region=\"modal-container\"]',\n MODAL: '[data-region=\"modal\"]',\n HEADER: '[data-region=\"header\"]',\n TITLE: '[data-region=\"title\"]',\n BODY: '[data-region=\"body\"]',\n FOOTER: '[data-region=\"footer\"]',\n HIDE: '[data-action=\"hide\"]',\n DIALOG: '[role=dialog]',\n FORM: 'form',\n MENU_BAR: '[role=menubar]',\n HAS_Z_INDEX: '.moodle-has-zindex',\n CAN_RECEIVE_FOCUS: 'input:not([type=\"hidden\"]), a[href], button, textarea, select, [tabindex]',\n };\n\n var TEMPLATES = {\n LOADING: 'core/loading',\n BACKDROP: 'core/modal_backdrop',\n };\n\n /**\n * Module singleton for the backdrop to be reused by all Modal instances.\n */\n var backdropPromise;\n\n /**\n * A counter that gets incremented for each modal created. This can be\n * used to generate unique values for the modals.\n */\n var modalCounter = 0;\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n var Modal = function(root) {\n this.root = $(root);\n this.modal = this.root.find(SELECTORS.MODAL);\n this.header = this.modal.find(SELECTORS.HEADER);\n this.headerPromise = $.Deferred();\n this.title = this.header.find(SELECTORS.TITLE);\n this.titlePromise = $.Deferred();\n this.body = this.modal.find(SELECTORS.BODY);\n this.bodyPromise = $.Deferred();\n this.footer = this.modal.find(SELECTORS.FOOTER);\n this.footerPromise = $.Deferred();\n this.hiddenSiblings = [];\n this.isAttached = false;\n this.bodyJS = null;\n this.footerJS = null;\n this.modalCount = modalCounter++;\n\n if (!this.root.is(SELECTORS.CONTAINER)) {\n Notification.exception({message: 'Element is not a modal container'});\n }\n\n if (!this.modal.length) {\n Notification.exception({message: 'Container does not contain a modal'});\n }\n\n if (!this.header.length) {\n Notification.exception({message: 'Modal is missing a header region'});\n }\n\n if (!this.title.length) {\n Notification.exception({message: 'Modal header is missing a title region'});\n }\n\n if (!this.body.length) {\n Notification.exception({message: 'Modal is missing a body region'});\n }\n\n if (!this.footer.length) {\n Notification.exception({message: 'Modal is missing a footer region'});\n }\n\n this.registerEventListeners();\n };\n\n /**\n * Add the modal to the page, if it hasn't already been added. This includes running any\n * javascript that has been cached until now.\n *\n * @method attachToDOM\n */\n Modal.prototype.attachToDOM = function() {\n if (this.isAttached) {\n return;\n }\n\n $('body').append(this.root);\n FocusLock.trapFocus(this.root[0]);\n\n // If we'd cached any JS then we can run it how that the modal is\n // attached to the DOM.\n if (this.bodyJS) {\n Templates.runTemplateJS(this.bodyJS);\n this.bodyJS = null;\n }\n\n if (this.footerJS) {\n Templates.runTemplateJS(this.footerJS);\n this.footerJS = null;\n }\n\n this.isAttached = true;\n };\n\n /**\n * Count the number of other visible modals (not including this one).\n *\n * @method countOtherVisibleModals\n * @return {int}\n */\n Modal.prototype.countOtherVisibleModals = function() {\n var count = 0;\n $('body').find(SELECTORS.CONTAINER).each(function(index, element) {\n element = $(element);\n\n // If we haven't found ourself and the element is visible.\n if (!this.root.is(element) && element.hasClass('show')) {\n count++;\n }\n }.bind(this));\n\n return count;\n };\n\n /**\n * Get the modal backdrop.\n *\n * @method getBackdrop\n * @return {object} jQuery promise\n */\n Modal.prototype.getBackdrop = function() {\n if (!backdropPromise) {\n backdropPromise = Templates.render(TEMPLATES.BACKDROP, {})\n .then(function(html) {\n var element = $(html);\n\n return new ModalBackdrop(element);\n })\n .fail(Notification.exception);\n }\n\n return backdropPromise;\n };\n\n /**\n * Get the root element of this modal.\n *\n * @method getRoot\n * @return {object} jQuery object\n */\n Modal.prototype.getRoot = function() {\n return this.root;\n };\n\n /**\n * Get the modal element of this modal.\n *\n * @method getModal\n * @return {object} jQuery object\n */\n Modal.prototype.getModal = function() {\n return this.modal;\n };\n\n /**\n * Get the modal title element.\n *\n * @method getTitle\n * @return {object} jQuery object\n */\n Modal.prototype.getTitle = function() {\n return this.title;\n };\n\n /**\n * Get the modal body element.\n *\n * @method getBody\n * @return {object} jQuery object\n */\n Modal.prototype.getBody = function() {\n return this.body;\n };\n\n /**\n * Get the modal footer element.\n *\n * @method getFooter\n * @return {object} jQuery object\n */\n Modal.prototype.getFooter = function() {\n return this.footer;\n };\n\n /**\n * Get a promise resolving to the title region.\n *\n * @method getTitlePromise\n * @return {Promise}\n */\n Modal.prototype.getTitlePromise = function() {\n return this.titlePromise;\n };\n\n /**\n * Get a promise resolving to the body region.\n *\n * @method getBodyPromise\n * @return {object} jQuery object\n */\n Modal.prototype.getBodyPromise = function() {\n return this.bodyPromise;\n };\n\n /**\n * Get a promise resolving to the footer region.\n *\n * @method getFooterPromise\n * @return {object} jQuery object\n */\n Modal.prototype.getFooterPromise = function() {\n return this.footerPromise;\n };\n\n /**\n * Get the unique modal count.\n *\n * @method getModalCount\n * @return {int}\n */\n Modal.prototype.getModalCount = function() {\n return this.modalCount;\n };\n\n /**\n * Set the modal title element.\n *\n * This method is overloaded to take either a string value for the title or a jQuery promise that is resolved with\n * HTML most commonly from a Str.get_string call.\n *\n * @method setTitle\n * @param {(string|object)} value The title string or jQuery promise which resolves to the title.\n */\n Modal.prototype.setTitle = function(value) {\n var title = this.getTitle();\n this.titlePromise = $.Deferred();\n\n this.asyncSet(value, title.html.bind(title))\n .then(function() {\n this.titlePromise.resolve(title);\n }.bind(this))\n .catch(Notification.exception);\n };\n\n /**\n * Set the modal body element.\n *\n * This method is overloaded to take either a string value for the body or a jQuery promise that is resolved with\n * HTML and Javascript most commonly from a Templates.render call.\n *\n * @method setBody\n * @param {(string|object)} value The body string or jQuery promise which resolves to the body.\n */\n Modal.prototype.setBody = function(value) {\n this.bodyPromise = $.Deferred();\n\n var body = this.getBody();\n\n if (typeof value === 'string') {\n // Just set the value if it's a string.\n body.html(value);\n Event.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n this.bodyPromise.resolve(body);\n } else {\n var jsPendingId = 'amd-modal-js-pending-id-' + this.getModalCount();\n M.util.js_pending(jsPendingId);\n // Otherwise we assume it's a promise to be resolved with\n // html and javascript.\n var contentPromise = null;\n body.css('overflow', 'hidden');\n\n // Ensure that the `value` is a jQuery Promise.\n value = $.when(value);\n\n if (value.state() == 'pending') {\n // We're still waiting for the body promise to resolve so\n // let's show a loading icon.\n var height = body.innerHeight();\n if (height < 100) {\n height = 100;\n }\n\n body.animate({height: height + 'px'}, 150);\n\n body.html('');\n contentPromise = Templates.render(TEMPLATES.LOADING, {})\n .then(function(html) {\n var loadingIcon = $(html).hide();\n body.html(loadingIcon);\n loadingIcon.fadeIn(150);\n\n // We only want the loading icon to fade out\n // when the content for the body has finished\n // loading.\n return $.when(loadingIcon.promise(), value);\n })\n .then(function(loadingIcon) {\n // Once the content has finished loading and\n // the loading icon has been shown then we can\n // fade the icon away to reveal the content.\n return loadingIcon.fadeOut(100).promise();\n })\n .then(function() {\n return value;\n });\n } else {\n // The content is already loaded so let's just display\n // it to the user. No need for a loading icon.\n contentPromise = value;\n }\n\n // Now we can actually display the content.\n contentPromise.then(function(html, js) {\n var result = null;\n\n if (this.isVisible()) {\n // If the modal is visible then we should display\n // the content gracefully for the user.\n body.css('opacity', 0);\n var currentHeight = body.innerHeight();\n body.html(html);\n // We need to clear any height values we've set here\n // in order to measure the height of the content being\n // added. This then allows us to animate the height\n // transition.\n body.css('height', '');\n var newHeight = body.innerHeight();\n body.css('height', currentHeight + 'px');\n result = body.animate(\n {height: newHeight + 'px', opacity: 1},\n {duration: 150, queue: false}\n ).promise();\n } else {\n // Since the modal isn't visible we can just immediately\n // set the content. No need to animate it.\n body.html(html);\n }\n\n if (js) {\n if (this.isAttached) {\n // If we're in the DOM then run the JS immediately.\n Templates.runTemplateJS(js);\n } else {\n // Otherwise cache it to be run when we're attached.\n this.bodyJS = js;\n }\n }\n\n return result;\n }.bind(this))\n .then(function(result) {\n Event.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n return result;\n }.bind(this))\n .then(function() {\n this.bodyPromise.resolve(body);\n return;\n }.bind(this))\n .fail(Notification.exception)\n .always(function() {\n // When we're done displaying all of the content we need\n // to clear the custom values we've set here.\n body.css('height', '');\n body.css('overflow', '');\n body.css('opacity', '');\n M.util.js_complete(jsPendingId);\n\n return;\n })\n .fail(Notification.exception);\n }\n };\n\n /**\n * Set the modal footer element. The footer element is made visible, if it\n * isn't already.\n *\n * This method is overloaded to take either a string\n * value for the body or a jQuery promise that is resolved with HTML and Javascript\n * most commonly from a Templates.render call.\n *\n * @method setFooter\n * @param {(string|object)} value The footer string or jQuery promise\n */\n Modal.prototype.setFooter = function(value) {\n // Make sure the footer is visible.\n this.showFooter();\n this.footerPromise = $.Deferred();\n\n var footer = this.getFooter();\n\n if (typeof value === 'string') {\n // Just set the value if it's a string.\n footer.html(value);\n this.footerPromise.resolve(footer);\n } else {\n // Otherwise we assume it's a promise to be resolved with\n // html and javascript.\n Templates.render(TEMPLATES.LOADING, {})\n .then(function(html) {\n footer.html(html);\n\n return value;\n })\n .then(function(html, js) {\n footer.html(html);\n\n if (js) {\n if (this.isAttached) {\n // If we're in the DOM then run the JS immediately.\n Templates.runTemplateJS(js);\n } else {\n // Otherwise cache it to be run when we're attached.\n this.footerJS = js;\n }\n }\n\n return footer;\n }.bind(this))\n .then(function(footer) {\n this.footerPromise.resolve(footer);\n return;\n }.bind(this))\n .catch(Notification.exception);\n }\n };\n\n /**\n * Check if the footer has any content in it.\n *\n * @method hasFooterContent\n * @return {bool}\n */\n Modal.prototype.hasFooterContent = function() {\n return this.getFooter().children().length ? true : false;\n };\n\n /**\n * Hide the footer element.\n *\n * @method hideFooter\n */\n Modal.prototype.hideFooter = function() {\n this.getFooter().addClass('hidden');\n };\n\n /**\n * Show the footer element.\n *\n * @method showFooter\n */\n Modal.prototype.showFooter = function() {\n this.getFooter().removeClass('hidden');\n };\n\n /**\n * Mark the modal as a large modal.\n *\n * @method setLarge\n */\n Modal.prototype.setLarge = function() {\n if (this.isLarge()) {\n return;\n }\n\n this.getModal().addClass('modal-lg');\n };\n\n /**\n * Check if the modal is a large modal.\n *\n * @method isLarge\n * @return {bool}\n */\n Modal.prototype.isLarge = function() {\n return this.getModal().hasClass('modal-lg');\n };\n\n /**\n * Mark the modal as a small modal.\n *\n * @method setSmall\n */\n Modal.prototype.setSmall = function() {\n if (this.isSmall()) {\n return;\n }\n\n this.getModal().removeClass('modal-lg');\n };\n\n /**\n * Check if the modal is a small modal.\n *\n * @method isSmall\n * @return {bool}\n */\n Modal.prototype.isSmall = function() {\n return !this.getModal().hasClass('modal-lg');\n };\n\n /**\n * Determine the highest z-index value currently on the page.\n *\n * @method calculateZIndex\n * @return {int}\n */\n Modal.prototype.calculateZIndex = function() {\n var items = $(SELECTORS.DIALOG + ', ' + SELECTORS.MENU_BAR + ', ' + SELECTORS.HAS_Z_INDEX);\n var zIndex = parseInt(this.root.css('z-index'));\n\n items.each(function(index, item) {\n item = $(item);\n // Note that webkit browsers won't return the z-index value from the CSS stylesheet\n // if the element doesn't have a position specified. Instead it'll return \"auto\".\n var itemZIndex = item.css('z-index') ? parseInt(item.css('z-index')) : 0;\n\n if (itemZIndex > zIndex) {\n zIndex = itemZIndex;\n }\n });\n\n return zIndex;\n };\n\n /**\n * Check if this modal is visible.\n *\n * @method isVisible\n * @return {bool}\n */\n Modal.prototype.isVisible = function() {\n return this.root.hasClass('show');\n };\n\n /**\n * Check if this modal has focus.\n *\n * @method hasFocus\n * @return {bool}\n */\n Modal.prototype.hasFocus = function() {\n var target = $(document.activeElement);\n return this.root.is(target) || this.root.has(target).length;\n };\n\n /**\n * Check if this modal has CSS transitions applied.\n *\n * @method hasTransitions\n * @return {bool}\n */\n Modal.prototype.hasTransitions = function() {\n return this.getRoot().hasClass('fade');\n };\n\n /**\n * Display this modal. The modal will be attached to the DOM if it hasn't\n * already been.\n *\n * @method show\n * @returns {Promise}\n */\n Modal.prototype.show = function() {\n if (this.isVisible()) {\n return $.Deferred().resolve();\n }\n\n var pendingPromise = new Pending('core/modal:show');\n\n if (this.hasFooterContent()) {\n this.showFooter();\n } else {\n this.hideFooter();\n }\n\n if (!this.isAttached) {\n this.attachToDOM();\n }\n\n return this.getBackdrop()\n .then(function(backdrop) {\n var currentIndex = this.calculateZIndex();\n var newIndex = currentIndex + 2;\n var newBackdropIndex = newIndex - 1;\n this.root.css('z-index', newIndex);\n backdrop.setZIndex(newBackdropIndex);\n backdrop.show();\n\n this.root.removeClass('hide').addClass('show');\n this.accessibilityShow();\n this.getModal().focus();\n $('body').addClass('modal-open');\n this.root.trigger(ModalEvents.shown, this);\n\n return;\n }.bind(this))\n .then(pendingPromise.resolve);\n };\n\n /**\n * Hide this modal if it does not contain a form.\n *\n * @method hideIfNotForm\n */\n Modal.prototype.hideIfNotForm = function() {\n var formElement = this.modal.find(SELECTORS.FORM);\n if (formElement.length == 0) {\n this.hide();\n }\n };\n\n /**\n * Hide this modal.\n *\n * @method hide\n */\n Modal.prototype.hide = function() {\n this.getBackdrop().done(function(backdrop) {\n FocusLock.untrapFocus();\n if (!this.countOtherVisibleModals()) {\n // Hide the backdrop if we're the last open modal.\n backdrop.hide();\n $('body').removeClass('modal-open');\n }\n\n var currentIndex = parseInt(this.root.css('z-index'));\n this.root.css('z-index', '');\n backdrop.setZIndex(currentIndex - 3);\n\n this.accessibilityHide();\n\n if (this.hasTransitions()) {\n // Wait for CSS transitions to complete before hiding the element.\n this.getRoot().one('transitionend webkitTransitionEnd oTransitionEnd', function() {\n this.getRoot().removeClass('show').addClass('hide');\n }.bind(this));\n } else {\n this.getRoot().removeClass('show').addClass('hide');\n }\n\n this.root.trigger(ModalEvents.hidden, this);\n }.bind(this));\n };\n\n /**\n * Remove this modal from the DOM.\n *\n * @method destroy\n */\n Modal.prototype.destroy = function() {\n this.hide();\n this.root.remove();\n this.root.trigger(ModalEvents.destroyed, this);\n };\n\n /**\n * Sets the appropriate aria attributes on this dialogue and the other\n * elements in the DOM to ensure that screen readers are able to navigate\n * the dialogue popup correctly.\n *\n * @method accessibilityShow\n */\n Modal.prototype.accessibilityShow = function() {\n // We need to get a list containing each sibling element and the shallowest\n // non-ancestral nodes in the DOM. We can shortcut this a little by leveraging\n // the fact that this dialogue is always appended to the document body therefore\n // it's siblings are the shallowest non-ancestral nodes. If that changes then\n // this code should also be updated.\n $('body').children().each(function(index, child) {\n // Skip the current modal.\n if (!this.root.is(child)) {\n child = $(child);\n var hidden = child.attr('aria-hidden');\n // If they are already hidden we can ignore them.\n if (hidden !== 'true') {\n // Save their current state.\n child.data('previous-aria-hidden', hidden);\n this.hiddenSiblings.push(child);\n\n // Hide this node from screen readers.\n child.attr('aria-hidden', 'true');\n }\n }\n }.bind(this));\n\n // Make us visible to screen readers.\n this.root.attr('aria-hidden', 'false');\n };\n\n /**\n * Restores the aria visibility on the DOM elements changed when displaying\n * the dialogue popup and makes the dialogue aria hidden to allow screen\n * readers to navigate the main page correctly when the dialogue is closed.\n *\n * @method accessibilityHide\n */\n Modal.prototype.accessibilityHide = function() {\n this.root.attr('aria-hidden', 'true');\n\n // Restore the sibling nodes back to their original values.\n $.each(this.hiddenSiblings, function(index, sibling) {\n sibling = $(sibling);\n var previousValue = sibling.data('previous-aria-hidden');\n // If the element didn't previously have an aria-hidden attribute\n // then we can just remove the one we set.\n if (typeof previousValue == 'undefined') {\n sibling.removeAttr('aria-hidden');\n } else {\n // Otherwise set it back to the old value (which will be false).\n sibling.attr('aria-hidden', previousValue);\n }\n });\n\n // Clear the cache. No longer need to store these.\n this.hiddenSiblings = [];\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n Modal.prototype.registerEventListeners = function() {\n this.getRoot().on('keydown', function(e) {\n if (!this.isVisible()) {\n return;\n }\n\n if (e.keyCode == KeyCodes.escape) {\n this.hide();\n }\n }.bind(this));\n\n // Listen for clicks on the modal container.\n this.getRoot().click(function(e) {\n // If the click wasn't inside the modal element then we should\n // hide the modal.\n if (!$(e.target).closest(SELECTORS.MODAL).length) {\n // The check above fails to detect the click was inside the modal when the DOM tree is already changed.\n // So, we check if we can still find the container element or not. If not, then the DOM tree is changed.\n // It's best not to hide the modal in that case.\n if ($(e.target).closest(SELECTORS.CONTAINER).length) {\n this.hideIfNotForm();\n }\n }\n }.bind(this));\n\n CustomEvents.define(this.getModal(), [CustomEvents.events.activate]);\n this.getModal().on(CustomEvents.events.activate, SELECTORS.HIDE, function(e, data) {\n this.hide();\n data.originalEvent.preventDefault();\n }.bind(this));\n };\n\n /**\n * Register a listener to close the dialogue when the cancel button is pressed.\n *\n * @method registerCloseOnCancel\n */\n Modal.prototype.registerCloseOnCancel = function() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('cancel'), function(e, data) {\n var cancelEvent = $.Event(ModalEvents.cancel);\n this.getRoot().trigger(cancelEvent, this);\n\n if (!cancelEvent.isDefaultPrevented()) {\n data.originalEvent.preventDefault();\n\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n }.bind(this));\n };\n\n /**\n * Register a listener to close the dialogue when the save button is pressed.\n *\n * @method registerCloseOnSave\n */\n Modal.prototype.registerCloseOnSave = function() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('save'), function(e, data) {\n var saveEvent = $.Event(ModalEvents.save);\n this.getRoot().trigger(saveEvent, this);\n\n if (!saveEvent.isDefaultPrevented()) {\n data.originalEvent.preventDefault();\n\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n }.bind(this));\n };\n\n /**\n * Set or resolve and set the value using the function.\n *\n * @method asyncSet\n * @param {(string|object)} value The string or jQuery promise.\n * @param {function} setFunction The setter\n * @return {Promise}\n */\n Modal.prototype.asyncSet = function(value, setFunction) {\n var p = value;\n if (typeof value !== 'object' || !value.hasOwnProperty('then')) {\n p = $.Deferred();\n p.resolve(value);\n }\n\n p.then(function(content) {\n setFunction(content);\n\n return;\n })\n .fail(Notification.exception);\n\n return p;\n };\n\n /**\n * Set the title text of a button.\n *\n * This method is overloaded to take either a string value for the button title or a jQuery promise that is resolved with\n * text most commonly from a Str.get_string call.\n *\n * @param {DOMString} action The action of the button\n * @param {(String|object)} value The button text, or a promise which will resolve to it\n * @returns {Promise}\n */\n Modal.prototype.setButtonText = function(action, value) {\n const button = this.getFooter().find(this.getActionSelector(action));\n\n if (!button) {\n throw new Error(\"Unable to find the '\" + action + \"' button\");\n }\n\n return this.asyncSet(value, button.text.bind(button));\n };\n\n /**\n * Get the Selector for an action.\n *\n * @param {String} action\n * @returns {DOMString}\n */\n Modal.prototype.getActionSelector = function(action) {\n return \"[data-action='\" + action + \"']\";\n };\n\n /**\n * Set the flag to remove the modal from the DOM on close.\n *\n * @param {Boolean} remove\n */\n Modal.prototype.setRemoveOnClose = function(remove) {\n this.removeOnClose = remove;\n };\n\n return Modal;\n});\n"],"file":"modal.min.js"} \ No newline at end of file diff --git a/lib/amd/src/modal.js b/lib/amd/src/modal.js index 154f9746fef..d04924f9e02 100644 --- a/lib/amd/src/modal.js +++ b/lib/amd/src/modal.js @@ -322,6 +322,9 @@ define([ var contentPromise = null; body.css('overflow', 'hidden'); + // Ensure that the `value` is a jQuery Promise. + value = $.when(value); + if (value.state() == 'pending') { // We're still waiting for the body promise to resolve so // let's show a loading icon. diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index b6f91f185f0..9ad3d5b8264 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -1511,7 +1511,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { */ .modchooser .modal-body { padding: 0; - height: 640px; + min-height: 640px; overflow-y: auto; .loading-icon { @@ -1521,9 +1521,11 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { font-size: 3em; height: 1em; width: 1em; - margin: 5em auto; } } + .carousel-item .loading-icon .icon { + margin: 5em auto; + } } .modchoosercontainer.noscroll { @@ -1582,7 +1584,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { background-color: $white; overflow-x: hidden; overflow-y: auto; - height: 640px; + min-height: 640px; .content { overflow-y: auto; diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 74d9792212b..76689d4ba81 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -10653,7 +10653,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { */ .modchooser .modal-body { padding: 0; - height: 640px; + min-height: 640px; overflow-y: auto; } .modchooser .modal-body .loading-icon { opacity: 1; } @@ -10661,8 +10661,9 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { display: block; font-size: 3em; height: 1em; - width: 1em; - margin: 5em auto; } + width: 1em; } + .modchooser .modal-body .carousel-item .loading-icon .icon { + margin: 5em auto; } .modchoosercontainer.noscroll { overflow-y: hidden; } @@ -10708,7 +10709,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { background-color: #fff; overflow-x: hidden; overflow-y: auto; - height: 640px; } + min-height: 640px; } .modchooser .modal-body .optionsummary .content { overflow-y: auto; } .modchooser .modal-body .optionsummary .content .heading .icon { diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 42a7c53efb5..da0106c2fd9 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -10861,7 +10861,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { */ .modchooser .modal-body { padding: 0; - height: 640px; + min-height: 640px; overflow-y: auto; } .modchooser .modal-body .loading-icon { opacity: 1; } @@ -10869,8 +10869,9 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { display: block; font-size: 3em; height: 1em; - width: 1em; - margin: 5em auto; } + width: 1em; } + .modchooser .modal-body .carousel-item .loading-icon .icon { + margin: 5em auto; } .modchoosercontainer.noscroll { overflow-y: hidden; } @@ -10916,7 +10917,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { background-color: #fff; overflow-x: hidden; overflow-y: auto; - height: 640px; } + min-height: 640px; } .modchooser .modal-body .optionsummary .content { overflow-y: auto; } .modchooser .modal-body .optionsummary .content .heading .icon {