From 819fd0218975b64f8f38fe543dbf9b841678c3e7 Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Wed, 25 Feb 2026 11:55:23 +0100 Subject: [PATCH] MDL-88070 javascript: Respect removeOnClose --- public/lib/amd/build/modal.min.js | 2 +- public/lib/amd/build/modal.min.js.map | 2 +- public/lib/amd/src/modal.js | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/public/lib/amd/build/modal.min.js b/public/lib/amd/build/modal.min.js index 1f3ddfa1719..e3091af1c39 100644 --- a/public/lib/amd/build/modal.min.js +++ b/public/lib/amd/build/modal.min.js @@ -1,3 +1,3 @@ -define("core/modal",["exports","jquery","core/templates","core/notification","core/key_codes","core/modal_backdrop","core/modal_events","core/pending","core/custom_interaction_events","core_filters/events","core/local/aria/focuslock","core/aria","core/fullscreen","./toast","core/event_dispatcher","core/prefetch"],(function(_exports,_jquery,Templates,Notification,KeyCodes,_modal_backdrop,_modal_events,_pending,CustomEvents,FilterEvents,FocusLock,Aria,Fullscreen,_toast,_event_dispatcher,Prefetch){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),Templates=_interopRequireWildcard(Templates),Notification=_interopRequireWildcard(Notification),KeyCodes=_interopRequireWildcard(KeyCodes),_modal_backdrop=_interopRequireDefault(_modal_backdrop),_modal_events=_interopRequireDefault(_modal_events),_pending=_interopRequireDefault(_pending),CustomEvents=_interopRequireWildcard(CustomEvents),FilterEvents=_interopRequireWildcard(FilterEvents),FocusLock=_interopRequireWildcard(FocusLock),Aria=_interopRequireWildcard(Aria),Fullscreen=_interopRequireWildcard(Fullscreen),Prefetch=_interopRequireWildcard(Prefetch);const SELECTORS_CONTAINER='[data-region="modal-container"]',SELECTORS_MODAL='[data-region="modal"]',SELECTORS_HEADER='[data-region="header"]',SELECTORS_TITLE='[data-region="title"]',SELECTORS_BODY='[data-region="body"]',SELECTORS_FOOTER='[data-region="footer"]',SELECTORS_HIDE='[data-action="hide"]',SELECTORS_DIALOG="[role=dialog]",SELECTORS_FORM="form",SELECTORS_MENU_BAR="[role=menubar]",SELECTORS_HAS_Z_INDEX=".moodle-has-zindex",TEMPLATES_LOADING="core/loading",TEMPLATES_BACKDROP="core/modal_backdrop";class Modal{get root(){return(0,_jquery.default)(this._root.filter(SELECTORS_CONTAINER))}set root(root){this._root=root}constructor(root){this.root=(0,_jquery.default)(root),this.modal=this.root.find(SELECTORS_MODAL),this.header=this.modal.find(SELECTORS_HEADER),this.headerPromise=_jquery.default.Deferred(),this.title=this.header.find(SELECTORS_TITLE),this.titlePromise=_jquery.default.Deferred(),this.body=this.modal.find(SELECTORS_BODY),this.bodyPromise=_jquery.default.Deferred(),this.footer=this.modal.find(SELECTORS_FOOTER),this.footerPromise=_jquery.default.Deferred(),this.hiddenSiblings=[],this.isAttached=!1,this.bodyJS=null,this.footerJS=null,this.modalCount=Modal.modalCounter++,this.attachmentPoint=document.createElement("div"),document.body.append(this.attachmentPoint),this.focusOnClose=null,this.templateJS=null,this.root.is(SELECTORS_CONTAINER)||Notification.exception({message:"Element is not a modal container"}),this.modal.length||Notification.exception({message:"Container does not contain a modal"}),this.header.length||Notification.exception({message:"Modal is missing a header region"}),this.title.length||Notification.exception({message:"Modal header is missing a title region"}),this.body.length||Notification.exception({message:"Modal is missing a body region"}),this.footer.length||Notification.exception({message:"Modal is missing a footer region"}),this.registerEventListeners()}static registerModalType(){if(!this.TYPE)throw new Error("Unknown modal type",this);if(!this.TEMPLATE)throw new Error("Unknown modal template",this);this.register(this.TYPE,this,this.TEMPLATE)}static async create(){let modalConfig=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingModalPromise=new _pending.default("core/modal:create");modalConfig.type=this.TYPE;const templateName=this._getTemplateName(modalConfig),templateContext=modalConfig.templateContext||{},{html:html,js:js}=await Templates.renderForPromise(templateName,templateContext),modal=new this(html);return js&&modal.setTemplateJS(js),modal.configure(modalConfig),pendingModalPromise.resolve(),modal}static _getTemplateName(modalConfig){if(modalConfig.template)return modalConfig.template;if(this.TEMPLATE)return this.TEMPLATE;if(this.registry.has(this.TYPE)){return this.registry.get(this.TYPE).template}throw new Error("Unable to determine template name for modal ".concat(this.TYPE))}configure(){let{show:show=!1,large:large=!1,isVerticallyCentered:isVerticallyCentered=!1,removeOnClose:removeOnClose=!1,scrollable:scrollable=!0,returnElement:returnElement,title:title,body:body,footer:footer,buttons:buttons={}}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};large&&this.setLarge(),isVerticallyCentered&&this.setVerticallyCentered(),this.setRemoveOnClose(removeOnClose),this.setReturnElement(returnElement),this.setScrollable(scrollable),void 0!==title&&this.setTitle(title),void 0!==body&&this.setBody(body),void 0!==footer&&this.setFooter(footer),Object.entries(buttons).forEach((_ref=>{let[key,value]=_ref;return this.setButtonText(key,value)})),show&&this.show()}attachToDOM(){this.getAttachmentPoint().append(this._root),this.isAttached||(FocusLock.trapFocus(this.root[0]),this.templateJS&&(Templates.runTemplateJS(this.templateJS),this.templateJS=null),this.bodyJS&&(Templates.runTemplateJS(this.bodyJS),this.bodyJS=null),this.footerJS&&(Templates.runTemplateJS(this.footerJS),this.footerJS=null),this.isAttached=!0)}countOtherVisibleModals(){let count=0;return(0,_jquery.default)("body").find(SELECTORS_CONTAINER).each(((index,element)=>{element=(0,_jquery.default)(element),!this.root.is(element)&&element.hasClass("show")&&count++})),count}getBackdrop(){return Modal.backdropPromise||(Modal.backdropPromise=Templates.render(TEMPLATES_BACKDROP,{}).then((html=>new _modal_backdrop.default((0,_jquery.default)(html)))).catch(Notification.exception)),Modal.backdropPromise}getRoot(){return this.root}getModal(){return this.modal}getTitle(){return this.title}getBody(){return this.body}getFooter(){return this.footer}getTitlePromise(){return this.titlePromise}getBodyPromise(){return this.bodyPromise}getFooterPromise(){return this.footerPromise}getModalCount(){return this.modalCount}setTitle(value){const title=this.getTitle();this.titlePromise=_jquery.default.Deferred(),this.asyncSet(value,title.html.bind(title)).then((()=>{this.titlePromise.resolve(title)})).catch(Notification.exception)}setBody(value){this.bodyPromise=_jquery.default.Deferred();const body=this.getBody();if("string"==typeof value)body.html(value),FilterEvents.notifyFilterContentUpdated(body),this.getRoot().trigger(_modal_events.default.bodyRendered,this),this.bodyPromise.resolve(body);else{const modalPromise=new _pending.default("amd-modal-js-pending-id-".concat(this.getModalCount()));let contentPromise=null;if(body.css("overflow","hidden"),"pending"==(value=_jquery.default.when(value)).state()){let height=body.innerHeight();height<100&&(height=100),body.animate({height:"".concat(height,"px")},150),body.html(""),contentPromise=Templates.render(TEMPLATES_LOADING,{}).then((html=>{const loadingIcon=(0,_jquery.default)(html).hide();return body.html(loadingIcon),loadingIcon.fadeIn(150),_jquery.default.when(loadingIcon.promise(),value)})).then((loadingIcon=>loadingIcon.fadeOut(100).promise())).then((()=>value))}else contentPromise=value;contentPromise.then(((html,js)=>{let result=null;if(this.isVisible()){body.css("opacity",0);const currentHeight=body.innerHeight();body.html(html),body.css("height","");const newHeight=body.innerHeight();body.css("height","".concat(currentHeight,"px")),result=body.animate({height:"".concat(newHeight,"px"),opacity:1},{duration:150,queue:!1}).promise()}else body.html(html);return js&&(this.isAttached?Templates.runTemplateJS(js):this.bodyJS=js),result})).then((result=>(FilterEvents.notifyFilterContentUpdated(body),this.getRoot().trigger(_modal_events.default.bodyRendered,this),(0,_event_dispatcher.dispatchEvent)("core/modal:bodyRendered",this,this.modal[0]),result))).then((()=>{this.bodyPromise.resolve(body)})).catch(Notification.exception).always((()=>{body.css("height",""),body.css("overflow",""),body.css("opacity",""),modalPromise.resolve()}))}}setBodyContent(promise){return promise.then((_ref2=>{let{html:html,js:js}=_ref2;return this.setBody(_jquery.default.when(html,js))})).catch((exception=>{throw this.hide(),exception}))}setFooter(value){this.showFooter(),this.footerPromise=_jquery.default.Deferred();const footer=this.getFooter();"string"==typeof value?(footer.html(value),this.footerPromise.resolve(footer)):Templates.render(TEMPLATES_LOADING,{}).then((html=>(footer.html(html),value))).then(((html,js)=>(footer.html(html),js&&(this.isAttached?Templates.runTemplateJS(js):this.footerJS=js),footer))).then((footer=>{this.footerPromise.resolve(footer),this.showFooter()})).catch(Notification.exception)}hasFooterContent(){return!!this.getFooter().children().length}hideFooter(){this.getFooter().addClass("hidden")}showFooter(){this.getFooter().removeClass("hidden")}setLarge(){this.isLarge()||this.getModal().addClass("modal-lg")}setVerticallyCentered(){this.isVerticallyCentered()||this.getModal().addClass("modal-dialog-centered")}isLarge(){return this.getModal().hasClass("modal-lg")}isVerticallyCentered(){return this.getModal().hasClass("modal-dialog-centered")}setSmall(){this.isSmall()||this.getModal().removeClass("modal-lg")}isSmall(){return!this.getModal().hasClass("modal-lg")}setScrollable(value){value?this.getModal()[0].classList.add("modal-dialog-scrollable"):this.getModal()[0].classList.remove("modal-dialog-scrollable")}calculateZIndex(){const items=(0,_jquery.default)("".concat(SELECTORS_DIALOG,", ").concat(SELECTORS_MENU_BAR,", ").concat(SELECTORS_HAS_Z_INDEX));let zIndex=parseInt(this.root.css("z-index"));return items.each(((index,item)=>{if(!(item=(0,_jquery.default)(item)).is(":visible"))return;const itemZIndex=item.css("z-index")?parseInt(item.css("z-index")):0;itemZIndex>zIndex&&(zIndex=itemZIndex)})),zIndex}isVisible(){return this.root.hasClass("show")}hasFocus(){const target=(0,_jquery.default)(document.activeElement);return this.root.is(target)||this.root.has(target).length}hasTransitions(){return this.getRoot().hasClass("fade")}getAttachmentPoint(){return(0,_jquery.default)(Fullscreen.getElement()||this.attachmentPoint)}show(){if(this.isVisible())return _jquery.default.Deferred().resolve();const pendingPromise=new _pending.default("core/modal:show");return this.hasFooterContent()?this.showFooter():this.hideFooter(),this.attachToDOM(),!this.focusOnClose&&document.activeElement&&(this.focusOnClose=document.activeElement),this.getBackdrop().then((backdrop=>{const newIndex=this.calculateZIndex()+2,newBackdropIndex=newIndex-1;this.root.css("z-index",newIndex),backdrop.setZIndex(newBackdropIndex),backdrop.show(),this.root.removeClass("hide").addClass("show"),this.accessibilityShow(),this.getModal().focus(),(0,_jquery.default)("body").addClass("modal-open");const scrollbarWidth=window.innerWidth-document.documentElement.clientWidth;(0,_jquery.default)("body").css({overflow:"hidden",paddingRight:"".concat(scrollbarWidth,"px")}),this.root.trigger(_modal_events.default.shown,this),(0,_event_dispatcher.dispatchEvent)("core/modal:shown",this,this.modal[0])})).then(pendingPromise.resolve)}hideIfNotForm(){0==this.modal.find(SELECTORS_FORM).length&&this.hide()}hide(){this.getBackdrop().done((backdrop=>{FocusLock.untrapFocus(),this.countOtherVisibleModals()||(backdrop.hide(),(0,_jquery.default)("body").removeClass("modal-open"),(0,_jquery.default)("body").css({overflow:"",paddingRight:""}));const currentIndex=parseInt(this.root.css("z-index"));this.root.css("z-index",""),backdrop.setZIndex(currentIndex-3),this.accessibilityHide(),this.hasTransitions()?this.getRoot().one("transitionend webkitTransitionEnd oTransitionEnd",(()=>{this.getRoot().removeClass("show").addClass("hide")})):this.getRoot().removeClass("show").addClass("hide"),(0,_jquery.default)(document.body).find(this.getRoot()).length&&(0,_jquery.default)(document.body).append(this.getRoot()),this.getRoot().find('[data-bs-toggle="popover"]').each((function(){var _document$getElementB;null===(_document$getElementB=document.getElementById(this.getAttribute("aria-describedby")))||void 0===_document$getElementB||_document$getElementB.remove()})),this.root.trigger(_modal_events.default.hidden,this)}))}destroy(){this.hide(),(0,_toast.removeToastRegion)(this.getBody().get(0)),this.root.remove(),this.root.trigger(_modal_events.default.destroyed,this),this.attachmentPoint.remove()}accessibilityShow(){Aria.unhide(this.root.get()),Aria.hideSiblings(this.root.get()[0])}accessibilityHide(){Aria.unhideSiblings(this.root.get()[0]),Aria.hide(this.root.get())}registerEventListeners(){this.getRoot().on("keydown",(e=>{this.isVisible()&&e.keyCode==KeyCodes.escape&&(this.removeOnClose?this.destroy():this.hide())})),this.getRoot().click((e=>{if(!(0,_jquery.default)(e.target).closest(SELECTORS_MODAL).length&&(0,_jquery.default)(e.target).closest(SELECTORS_CONTAINER).length){const outsideClickEvent=_jquery.default.Event(_modal_events.default.outsideClick);this.getRoot().trigger(outsideClickEvent,this),outsideClickEvent.isDefaultPrevented()||this.hideIfNotForm()}})),CustomEvents.define(this.getModal(),[CustomEvents.events.activate]),this.getModal().on(CustomEvents.events.activate,SELECTORS_HIDE,((e,data)=>{this.removeOnClose?this.destroy():this.hide(),data.originalEvent.preventDefault()})),this.getRoot().on(_modal_events.default.hidden,(()=>{this.focusOnClose&&this.focusOnClose.focus()}))}registerCloseOnCancel(){this.getModal().on(CustomEvents.events.activate,this.getActionSelector("cancel"),((e,data)=>{const cancelEvent=_jquery.default.Event(_modal_events.default.cancel);this.getRoot().trigger(cancelEvent,this),cancelEvent.isDefaultPrevented()||(data.originalEvent.preventDefault(),this.removeOnClose?this.destroy():this.hide())}))}registerCloseOnSave(){this.getModal().on(CustomEvents.events.activate,this.getActionSelector("save"),((e,data)=>{const saveEvent=_jquery.default.Event(_modal_events.default.save);this.getRoot().trigger(saveEvent,this),saveEvent.isDefaultPrevented()||(data.originalEvent.preventDefault(),this.removeOnClose?this.destroy():this.hide())}))}registerCloseOnDelete(){this.getModal().on(CustomEvents.events.activate,this.getActionSelector("delete"),((e,data)=>{const deleteEvent=_jquery.default.Event(_modal_events.default.delete);this.getRoot().trigger(deleteEvent,this),deleteEvent.isDefaultPrevented()||(data.originalEvent.preventDefault(),this.removeOnClose?this.destroy():this.hide())}))}asyncSet(value,setFunction){return(value=>value instanceof Promise?_jquery.default.when(value):"object"==typeof value&&value.hasOwnProperty("then")?value:_jquery.default.Deferred().resolve(value))(value).then((content=>setFunction(content))).catch(Notification.exception)}setButtonText(action,value){const button=this.getFooter().find(this.getActionSelector(action));if(!button)throw new Error("Unable to find the '"+action+"' button");return this.asyncSet(value,button.text.bind(button))}getActionSelector(action){return"[data-action='"+action+"']"}setRemoveOnClose(remove){this.removeOnClose=remove}setReturnElement(element){this.focusOnClose=element}setButtonDisabled(action,disabled){const button=this.getFooter().find(this.getActionSelector(action));if(!button)throw new Error("Unable to find the '"+action+"' button");disabled?button.attr("disabled",""):button.removeAttr("disabled")}setTemplateJS(js){this.templateJS=js}}return _exports.default=Modal,_defineProperty(Modal,"TYPE","default"),_defineProperty(Modal,"TEMPLATE","core/modal"),_defineProperty(Modal,"backdropPromise",null),_defineProperty(Modal,"modalCounter",0),_defineProperty(Modal,"registry",new Map),_defineProperty(Modal,"register",((type,module,template)=>{const existing=Modal.registry.get(type);existing&&existing.module!==module&&Notification.exception({message:"Modal of type '".concat(type,"' is already registered")}),module&&"function"==typeof module||Notification.exception({message:"You must provide a modal module"}),template||Notification.exception({message:"You must provide a modal template"}),Modal.registry.set(type,{module:module,template:template}),Prefetch.prefetchTemplate(template)})),_exports.default})); +define("core/modal",["exports","jquery","core/templates","core/notification","core/key_codes","core/modal_backdrop","core/modal_events","core/pending","core/custom_interaction_events","core_filters/events","core/local/aria/focuslock","core/aria","core/fullscreen","./toast","core/event_dispatcher","core/prefetch"],(function(_exports,_jquery,Templates,Notification,KeyCodes,_modal_backdrop,_modal_events,_pending,CustomEvents,FilterEvents,FocusLock,Aria,Fullscreen,_toast,_event_dispatcher,Prefetch){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),Templates=_interopRequireWildcard(Templates),Notification=_interopRequireWildcard(Notification),KeyCodes=_interopRequireWildcard(KeyCodes),_modal_backdrop=_interopRequireDefault(_modal_backdrop),_modal_events=_interopRequireDefault(_modal_events),_pending=_interopRequireDefault(_pending),CustomEvents=_interopRequireWildcard(CustomEvents),FilterEvents=_interopRequireWildcard(FilterEvents),FocusLock=_interopRequireWildcard(FocusLock),Aria=_interopRequireWildcard(Aria),Fullscreen=_interopRequireWildcard(Fullscreen),Prefetch=_interopRequireWildcard(Prefetch);const SELECTORS_CONTAINER='[data-region="modal-container"]',SELECTORS_MODAL='[data-region="modal"]',SELECTORS_HEADER='[data-region="header"]',SELECTORS_TITLE='[data-region="title"]',SELECTORS_BODY='[data-region="body"]',SELECTORS_FOOTER='[data-region="footer"]',SELECTORS_HIDE='[data-action="hide"]',SELECTORS_DIALOG="[role=dialog]",SELECTORS_FORM="form",SELECTORS_MENU_BAR="[role=menubar]",SELECTORS_HAS_Z_INDEX=".moodle-has-zindex",TEMPLATES_LOADING="core/loading",TEMPLATES_BACKDROP="core/modal_backdrop";class Modal{get root(){return(0,_jquery.default)(this._root.filter(SELECTORS_CONTAINER))}set root(root){this._root=root}constructor(root){this.root=(0,_jquery.default)(root),this.modal=this.root.find(SELECTORS_MODAL),this.header=this.modal.find(SELECTORS_HEADER),this.headerPromise=_jquery.default.Deferred(),this.title=this.header.find(SELECTORS_TITLE),this.titlePromise=_jquery.default.Deferred(),this.body=this.modal.find(SELECTORS_BODY),this.bodyPromise=_jquery.default.Deferred(),this.footer=this.modal.find(SELECTORS_FOOTER),this.footerPromise=_jquery.default.Deferred(),this.hiddenSiblings=[],this.isAttached=!1,this.bodyJS=null,this.footerJS=null,this.modalCount=Modal.modalCounter++,this.attachmentPoint=document.createElement("div"),document.body.append(this.attachmentPoint),this.focusOnClose=null,this.templateJS=null,this.root.is(SELECTORS_CONTAINER)||Notification.exception({message:"Element is not a modal container"}),this.modal.length||Notification.exception({message:"Container does not contain a modal"}),this.header.length||Notification.exception({message:"Modal is missing a header region"}),this.title.length||Notification.exception({message:"Modal header is missing a title region"}),this.body.length||Notification.exception({message:"Modal is missing a body region"}),this.footer.length||Notification.exception({message:"Modal is missing a footer region"}),this.registerEventListeners()}static registerModalType(){if(!this.TYPE)throw new Error("Unknown modal type",this);if(!this.TEMPLATE)throw new Error("Unknown modal template",this);this.register(this.TYPE,this,this.TEMPLATE)}static async create(){let modalConfig=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingModalPromise=new _pending.default("core/modal:create");modalConfig.type=this.TYPE;const templateName=this._getTemplateName(modalConfig),templateContext=modalConfig.templateContext||{},{html:html,js:js}=await Templates.renderForPromise(templateName,templateContext),modal=new this(html);return js&&modal.setTemplateJS(js),modal.configure(modalConfig),pendingModalPromise.resolve(),modal}static _getTemplateName(modalConfig){if(modalConfig.template)return modalConfig.template;if(this.TEMPLATE)return this.TEMPLATE;if(this.registry.has(this.TYPE)){return this.registry.get(this.TYPE).template}throw new Error("Unable to determine template name for modal ".concat(this.TYPE))}configure(){let{show:show=!1,large:large=!1,isVerticallyCentered:isVerticallyCentered=!1,removeOnClose:removeOnClose=!1,scrollable:scrollable=!0,returnElement:returnElement,title:title,body:body,footer:footer,buttons:buttons={}}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};large&&this.setLarge(),isVerticallyCentered&&this.setVerticallyCentered(),this.setRemoveOnClose(removeOnClose),this.setReturnElement(returnElement),this.setScrollable(scrollable),void 0!==title&&this.setTitle(title),void 0!==body&&this.setBody(body),void 0!==footer&&this.setFooter(footer),Object.entries(buttons).forEach((_ref=>{let[key,value]=_ref;return this.setButtonText(key,value)})),show&&this.show()}attachToDOM(){this.getAttachmentPoint().append(this._root),this.isAttached||(FocusLock.trapFocus(this.root[0]),this.templateJS&&(Templates.runTemplateJS(this.templateJS),this.templateJS=null),this.bodyJS&&(Templates.runTemplateJS(this.bodyJS),this.bodyJS=null),this.footerJS&&(Templates.runTemplateJS(this.footerJS),this.footerJS=null),this.isAttached=!0)}countOtherVisibleModals(){let count=0;return(0,_jquery.default)("body").find(SELECTORS_CONTAINER).each(((index,element)=>{element=(0,_jquery.default)(element),!this.root.is(element)&&element.hasClass("show")&&count++})),count}getBackdrop(){return Modal.backdropPromise||(Modal.backdropPromise=Templates.render(TEMPLATES_BACKDROP,{}).then((html=>new _modal_backdrop.default((0,_jquery.default)(html)))).catch(Notification.exception)),Modal.backdropPromise}getRoot(){return this.root}getModal(){return this.modal}getTitle(){return this.title}getBody(){return this.body}getFooter(){return this.footer}getTitlePromise(){return this.titlePromise}getBodyPromise(){return this.bodyPromise}getFooterPromise(){return this.footerPromise}getModalCount(){return this.modalCount}setTitle(value){const title=this.getTitle();this.titlePromise=_jquery.default.Deferred(),this.asyncSet(value,title.html.bind(title)).then((()=>{this.titlePromise.resolve(title)})).catch(Notification.exception)}setBody(value){this.bodyPromise=_jquery.default.Deferred();const body=this.getBody();if("string"==typeof value)body.html(value),FilterEvents.notifyFilterContentUpdated(body),this.getRoot().trigger(_modal_events.default.bodyRendered,this),this.bodyPromise.resolve(body);else{const modalPromise=new _pending.default("amd-modal-js-pending-id-".concat(this.getModalCount()));let contentPromise=null;if(body.css("overflow","hidden"),"pending"==(value=_jquery.default.when(value)).state()){let height=body.innerHeight();height<100&&(height=100),body.animate({height:"".concat(height,"px")},150),body.html(""),contentPromise=Templates.render(TEMPLATES_LOADING,{}).then((html=>{const loadingIcon=(0,_jquery.default)(html).hide();return body.html(loadingIcon),loadingIcon.fadeIn(150),_jquery.default.when(loadingIcon.promise(),value)})).then((loadingIcon=>loadingIcon.fadeOut(100).promise())).then((()=>value))}else contentPromise=value;contentPromise.then(((html,js)=>{let result=null;if(this.isVisible()){body.css("opacity",0);const currentHeight=body.innerHeight();body.html(html),body.css("height","");const newHeight=body.innerHeight();body.css("height","".concat(currentHeight,"px")),result=body.animate({height:"".concat(newHeight,"px"),opacity:1},{duration:150,queue:!1}).promise()}else body.html(html);return js&&(this.isAttached?Templates.runTemplateJS(js):this.bodyJS=js),result})).then((result=>(FilterEvents.notifyFilterContentUpdated(body),this.getRoot().trigger(_modal_events.default.bodyRendered,this),(0,_event_dispatcher.dispatchEvent)("core/modal:bodyRendered",this,this.modal[0]),result))).then((()=>{this.bodyPromise.resolve(body)})).catch(Notification.exception).always((()=>{body.css("height",""),body.css("overflow",""),body.css("opacity",""),modalPromise.resolve()}))}}setBodyContent(promise){return promise.then((_ref2=>{let{html:html,js:js}=_ref2;return this.setBody(_jquery.default.when(html,js))})).catch((exception=>{throw this.hide(),exception}))}setFooter(value){this.showFooter(),this.footerPromise=_jquery.default.Deferred();const footer=this.getFooter();"string"==typeof value?(footer.html(value),this.footerPromise.resolve(footer)):Templates.render(TEMPLATES_LOADING,{}).then((html=>(footer.html(html),value))).then(((html,js)=>(footer.html(html),js&&(this.isAttached?Templates.runTemplateJS(js):this.footerJS=js),footer))).then((footer=>{this.footerPromise.resolve(footer),this.showFooter()})).catch(Notification.exception)}hasFooterContent(){return!!this.getFooter().children().length}hideFooter(){this.getFooter().addClass("hidden")}showFooter(){this.getFooter().removeClass("hidden")}setLarge(){this.isLarge()||this.getModal().addClass("modal-lg")}setVerticallyCentered(){this.isVerticallyCentered()||this.getModal().addClass("modal-dialog-centered")}isLarge(){return this.getModal().hasClass("modal-lg")}isVerticallyCentered(){return this.getModal().hasClass("modal-dialog-centered")}setSmall(){this.isSmall()||this.getModal().removeClass("modal-lg")}isSmall(){return!this.getModal().hasClass("modal-lg")}setScrollable(value){value?this.getModal()[0].classList.add("modal-dialog-scrollable"):this.getModal()[0].classList.remove("modal-dialog-scrollable")}calculateZIndex(){const items=(0,_jquery.default)("".concat(SELECTORS_DIALOG,", ").concat(SELECTORS_MENU_BAR,", ").concat(SELECTORS_HAS_Z_INDEX));let zIndex=parseInt(this.root.css("z-index"));return items.each(((index,item)=>{if(!(item=(0,_jquery.default)(item)).is(":visible"))return;const itemZIndex=item.css("z-index")?parseInt(item.css("z-index")):0;itemZIndex>zIndex&&(zIndex=itemZIndex)})),zIndex}isVisible(){return this.root.hasClass("show")}hasFocus(){const target=(0,_jquery.default)(document.activeElement);return this.root.is(target)||this.root.has(target).length}hasTransitions(){return this.getRoot().hasClass("fade")}getAttachmentPoint(){return(0,_jquery.default)(Fullscreen.getElement()||this.attachmentPoint)}show(){if(this.isVisible())return _jquery.default.Deferred().resolve();const pendingPromise=new _pending.default("core/modal:show");return this.hasFooterContent()?this.showFooter():this.hideFooter(),this.attachToDOM(),!this.focusOnClose&&document.activeElement&&(this.focusOnClose=document.activeElement),this.getBackdrop().then((backdrop=>{const newIndex=this.calculateZIndex()+2,newBackdropIndex=newIndex-1;this.root.css("z-index",newIndex),backdrop.setZIndex(newBackdropIndex),backdrop.show(),this.root.removeClass("hide").addClass("show"),this.accessibilityShow(),this.getModal().focus(),(0,_jquery.default)("body").addClass("modal-open");const scrollbarWidth=window.innerWidth-document.documentElement.clientWidth;(0,_jquery.default)("body").css({overflow:"hidden",paddingRight:"".concat(scrollbarWidth,"px")}),this.root.trigger(_modal_events.default.shown,this),(0,_event_dispatcher.dispatchEvent)("core/modal:shown",this,this.modal[0])})).then(pendingPromise.resolve)}hideIfNotForm(){0==this.modal.find(SELECTORS_FORM).length&&(this.removeOnClose?this.destroy():this.hide())}hide(){this.getBackdrop().done((backdrop=>{FocusLock.untrapFocus(),this.countOtherVisibleModals()||(backdrop.hide(),(0,_jquery.default)("body").removeClass("modal-open"),(0,_jquery.default)("body").css({overflow:"",paddingRight:""}));const currentIndex=parseInt(this.root.css("z-index"));this.root.css("z-index",""),backdrop.setZIndex(currentIndex-3),this.accessibilityHide(),this.hasTransitions()?this.getRoot().one("transitionend webkitTransitionEnd oTransitionEnd",(()=>{this.getRoot().removeClass("show").addClass("hide")})):this.getRoot().removeClass("show").addClass("hide"),(0,_jquery.default)(document.body).find(this.getRoot()).length&&(0,_jquery.default)(document.body).append(this.getRoot()),this.getRoot().find('[data-bs-toggle="popover"]').each((function(){var _document$getElementB;null===(_document$getElementB=document.getElementById(this.getAttribute("aria-describedby")))||void 0===_document$getElementB||_document$getElementB.remove()})),this.root.trigger(_modal_events.default.hidden,this)}))}destroy(){this.hide(),(0,_toast.removeToastRegion)(this.getBody().get(0)),this.root.remove(),this.root.trigger(_modal_events.default.destroyed,this),this.attachmentPoint.remove()}accessibilityShow(){Aria.unhide(this.root.get()),Aria.hideSiblings(this.root.get()[0])}accessibilityHide(){Aria.unhideSiblings(this.root.get()[0]),Aria.hide(this.root.get())}registerEventListeners(){this.getRoot().on("keydown",(e=>{this.isVisible()&&e.keyCode==KeyCodes.escape&&(this.removeOnClose?this.destroy():this.hide())})),this.getRoot().click((e=>{if(!(0,_jquery.default)(e.target).closest(SELECTORS_MODAL).length&&(0,_jquery.default)(e.target).closest(SELECTORS_CONTAINER).length){const outsideClickEvent=_jquery.default.Event(_modal_events.default.outsideClick);this.getRoot().trigger(outsideClickEvent,this),outsideClickEvent.isDefaultPrevented()||this.hideIfNotForm()}})),CustomEvents.define(this.getModal(),[CustomEvents.events.activate]),this.getModal().on(CustomEvents.events.activate,SELECTORS_HIDE,((e,data)=>{this.removeOnClose?this.destroy():this.hide(),data.originalEvent.preventDefault()})),this.getRoot().on(_modal_events.default.hidden,(()=>{this.focusOnClose&&this.focusOnClose.focus()}))}registerCloseOnCancel(){this.getModal().on(CustomEvents.events.activate,this.getActionSelector("cancel"),((e,data)=>{const cancelEvent=_jquery.default.Event(_modal_events.default.cancel);this.getRoot().trigger(cancelEvent,this),cancelEvent.isDefaultPrevented()||(data.originalEvent.preventDefault(),this.removeOnClose?this.destroy():this.hide())}))}registerCloseOnSave(){this.getModal().on(CustomEvents.events.activate,this.getActionSelector("save"),((e,data)=>{const saveEvent=_jquery.default.Event(_modal_events.default.save);this.getRoot().trigger(saveEvent,this),saveEvent.isDefaultPrevented()||(data.originalEvent.preventDefault(),this.removeOnClose?this.destroy():this.hide())}))}registerCloseOnDelete(){this.getModal().on(CustomEvents.events.activate,this.getActionSelector("delete"),((e,data)=>{const deleteEvent=_jquery.default.Event(_modal_events.default.delete);this.getRoot().trigger(deleteEvent,this),deleteEvent.isDefaultPrevented()||(data.originalEvent.preventDefault(),this.removeOnClose?this.destroy():this.hide())}))}asyncSet(value,setFunction){return(value=>value instanceof Promise?_jquery.default.when(value):"object"==typeof value&&value.hasOwnProperty("then")?value:_jquery.default.Deferred().resolve(value))(value).then((content=>setFunction(content))).catch(Notification.exception)}setButtonText(action,value){const button=this.getFooter().find(this.getActionSelector(action));if(!button)throw new Error("Unable to find the '"+action+"' button");return this.asyncSet(value,button.text.bind(button))}getActionSelector(action){return"[data-action='"+action+"']"}setRemoveOnClose(remove){this.removeOnClose=remove}setReturnElement(element){this.focusOnClose=element}setButtonDisabled(action,disabled){const button=this.getFooter().find(this.getActionSelector(action));if(!button)throw new Error("Unable to find the '"+action+"' button");disabled?button.attr("disabled",""):button.removeAttr("disabled")}setTemplateJS(js){this.templateJS=js}}return _exports.default=Modal,_defineProperty(Modal,"TYPE","default"),_defineProperty(Modal,"TEMPLATE","core/modal"),_defineProperty(Modal,"backdropPromise",null),_defineProperty(Modal,"modalCounter",0),_defineProperty(Modal,"registry",new Map),_defineProperty(Modal,"register",((type,module,template)=>{const existing=Modal.registry.get(type);existing&&existing.module!==module&&Notification.exception({message:"Modal of type '".concat(type,"' is already registered")}),module&&"function"==typeof module||Notification.exception({message:"You must provide a modal module"}),template||Notification.exception({message:"You must provide a modal template"}),Modal.registry.set(type,{module:module,template:template}),Prefetch.prefetchTemplate(template)})),_exports.default})); //# sourceMappingURL=modal.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/modal.min.js.map b/public/lib/amd/build/modal.min.js.map index c2e6178378b..0fd38ae425e 100644 --- a/public/lib/amd/build/modal.min.js.map +++ b/public/lib/amd/build/modal.min.js.map @@ -1 +1 @@ -{"version":3,"file":"modal.min.js","sources":["../src/modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Contain the logic for modals.\n *\n * @module core/modal\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as Templates from 'core/templates';\nimport * as Notification from 'core/notification';\nimport * as KeyCodes from 'core/key_codes';\nimport ModalBackdrop from 'core/modal_backdrop';\nimport ModalEvents from 'core/modal_events';\nimport Pending from 'core/pending';\nimport * as CustomEvents from 'core/custom_interaction_events';\nimport * as FilterEvents from 'core_filters/events';\nimport * as FocusLock from 'core/local/aria/focuslock';\nimport * as Aria from 'core/aria';\nimport * as Fullscreen from 'core/fullscreen';\nimport {removeToastRegion} from './toast';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport * as Prefetch from 'core/prefetch';\n\n/**\n * A configuration to provide to the modal.\n *\n * @typedef {Object} ModalConfig\n *\n * @property {string} [type] The type of modal to create.\n * @property {string|Promise} [title] The title of the modal.\n * @property {string|Promise} [body] The body of the modal.\n * @property {string|Promise} [footer] The footer of the modal.\n * @property {boolean} [show=false] Whether to show the modal immediately.\n * @property {boolean} [scrollable=true] Whether the modal should be scrollable.\n * @property {boolean} [removeOnClose=true] Whether the modal should be removed from the DOM when it is closed.\n * @property {Element|jQuery} [returnElement] The element to focus when closing the modal.\n * @property {boolean} [large=false] Whether the modal should be a large modal.\n * @property {boolean} [isVerticallyCentered=false] Whether the modal should be vertically centered.\n * @property {object} [buttons={}] The buttons to display in the footer as a key => title pair.\n */\n\nconst 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\nconst TEMPLATES = {\n LOADING: 'core/loading',\n BACKDROP: 'core/modal_backdrop',\n};\n\nexport default class Modal {\n /** @var {string} The type of modal */\n static TYPE = 'default';\n\n /** @var {string} The template to use for this modal */\n static TEMPLATE = 'core/modal';\n\n /** @var {Promise} Module singleton for the backdrop to be reused by all Modal instances */\n static backdropPromise = null;\n\n /**\n * @var {Number} A counter that gets incremented for each modal created.\n * This can be used to generate unique values for the modals.\n */\n static modalCounter = 0;\n\n /**\n * @var {Number} A singleton registry for all modules to access. Allows types to be\n * added at runtime.\n */\n static registry = new Map();\n\n /**\n * Getter method for .root element.\n * @return {object} jQuery object\n */\n get root() {\n return $(this._root.filter(SELECTORS.CONTAINER));\n }\n\n /**\n * Setter method for .root element.\n * @param {object} root jQuery object\n */\n set root(root) {\n this._root = root;\n }\n\n /**\n * Constructor for the Modal.\n *\n * @param {HTMLElement} root The HTMLElement at the root of the Modal content\n */\n constructor(root) {\n this.root = $(root);\n\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 = Modal.modalCounter++;\n this.attachmentPoint = document.createElement('div');\n document.body.append(this.attachmentPoint);\n this.focusOnClose = null;\n this.templateJS = null;\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 * Register a modal with the legacy modal registry.\n *\n * This is provided to allow backwards-compatibility with existing code that uses the legacy modal registry.\n * It is not necessary to register modals for code only present in Moodle 4.3 and later.\n */\n static registerModalType() {\n if (!this.TYPE) {\n throw new Error(`Unknown modal type`, this);\n }\n\n if (!this.TEMPLATE) {\n throw new Error(`Unknown modal template`, this);\n }\n\n this.register(\n this.TYPE,\n this,\n this.TEMPLATE,\n );\n }\n\n /**\n * Register a modal.\n *\n * @param {string} type The type of modal (must be unique)\n * @param {function} module The modal module (must be a constructor function of type core/modal)\n * @param {string} template The template name of the modal\n */\n static register = (type, module, template) => {\n const existing = this.registry.get(type);\n if (existing && existing.module !== module) {\n Notification.exception({\n message: `Modal of type '${type}' is already registered`,\n });\n }\n\n if (!module || typeof module !== 'function') {\n Notification.exception({message: \"You must provide a modal module\"});\n }\n\n if (!template) {\n Notification.exception({message: \"You must provide a modal template\"});\n }\n\n this.registry.set(type, {module, template});\n\n // Prefetch the template.\n Prefetch.prefetchTemplate(template);\n };\n\n /**\n * Create a new modal using the ModalFactory.\n * This is a shortcut to creating the modal.\n * Create a new modal using the supplied configuration.\n *\n * @param {ModalConfig} modalConfig\n * @returns {Promise}\n */\n static async create(modalConfig = {}) {\n const pendingModalPromise = new Pending('core/modal:create');\n modalConfig.type = this.TYPE;\n\n const templateName = this._getTemplateName(modalConfig);\n const templateContext = modalConfig.templateContext || {};\n const {html, js} = await Templates.renderForPromise(templateName, templateContext);\n\n const modal = new this(html);\n if (js) {\n modal.setTemplateJS(js);\n }\n modal.configure(modalConfig);\n\n pendingModalPromise.resolve();\n\n return modal;\n }\n\n /**\n * A helper to get the template name for this modal.\n *\n * @param {ModalConfig} modalConfig\n * @returns {string}\n * @protected\n */\n static _getTemplateName(modalConfig) {\n if (modalConfig.template) {\n return modalConfig.template;\n }\n\n if (this.TEMPLATE) {\n return this.TEMPLATE;\n }\n\n if (this.registry.has(this.TYPE)) {\n const config = this.registry.get(this.TYPE);\n return config.template;\n }\n\n throw new Error(`Unable to determine template name for modal ${this.TYPE}`);\n }\n\n /**\n * Configure the modal.\n *\n * @param {ModalConfig} param0 The configuration options\n */\n configure({\n show = false,\n large = false,\n isVerticallyCentered = false,\n removeOnClose = false,\n scrollable = true,\n returnElement,\n title,\n body,\n footer,\n buttons = {},\n } = {}) {\n if (large) {\n this.setLarge();\n }\n\n if (isVerticallyCentered) {\n this.setVerticallyCentered();\n }\n\n // If configured remove the modal when hiding it.\n // Ideally this should be true, but we need to identify places that this breaks first.\n this.setRemoveOnClose(removeOnClose);\n this.setReturnElement(returnElement);\n this.setScrollable(scrollable);\n\n if (title !== undefined) {\n this.setTitle(title);\n }\n\n if (body !== undefined) {\n this.setBody(body);\n }\n\n if (footer !== undefined) {\n this.setFooter(footer);\n }\n\n Object.entries(buttons).forEach(([key, value]) => this.setButtonText(key, value));\n\n // If configured show the modal.\n if (show) {\n this.show();\n }\n }\n\n /**\n * Attach the modal to the correct part of the page.\n *\n * If it hasn't already been added it runs any\n * javascript that has been cached until now.\n *\n * @method attachToDOM\n */\n attachToDOM() {\n this.getAttachmentPoint().append(this._root);\n\n if (this.isAttached) {\n return;\n }\n\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.templateJS) {\n Templates.runTemplateJS(this.templateJS);\n this.templateJS = null;\n }\n\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 countOtherVisibleModals() {\n let count = 0;\n $('body').find(SELECTORS.CONTAINER).each((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 });\n\n return count;\n }\n\n /**\n * Get the modal backdrop.\n *\n * @method getBackdrop\n * @return {object} jQuery promise\n */\n getBackdrop() {\n if (!Modal.backdropPromise) {\n Modal.backdropPromise = Templates.render(TEMPLATES.BACKDROP, {})\n .then((html) => new ModalBackdrop($(html)))\n .catch(Notification.exception);\n }\n\n return Modal.backdropPromise;\n }\n\n /**\n * Get the root element of this modal.\n *\n * @method getRoot\n * @return {object} jQuery object\n */\n getRoot() {\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 getModal() {\n return this.modal;\n }\n\n /**\n * Get the modal title element.\n *\n * @method getTitle\n * @return {object} jQuery object\n */\n getTitle() {\n return this.title;\n }\n\n /**\n * Get the modal body element.\n *\n * @method getBody\n * @return {object} jQuery object\n */\n getBody() {\n return this.body;\n }\n\n /**\n * Get the modal footer element.\n *\n * @method getFooter\n * @return {object} jQuery object\n */\n getFooter() {\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 getTitlePromise() {\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 getBodyPromise() {\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 getFooterPromise() {\n return this.footerPromise;\n }\n\n /**\n * Get the unique modal count.\n *\n * @method getModalCount\n * @return {int}\n */\n getModalCount() {\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 setTitle(value) {\n const title = this.getTitle();\n this.titlePromise = $.Deferred();\n\n this.asyncSet(value, title.html.bind(title))\n .then(() => {\n this.titlePromise.resolve(title);\n return;\n })\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 * @fires event:filterContentUpdated\n */\n setBody(value) {\n this.bodyPromise = $.Deferred();\n\n const body = this.getBody();\n\n if (typeof value === 'string') {\n // Just set the value if it's a string.\n body.html(value);\n FilterEvents.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n this.bodyPromise.resolve(body);\n } else {\n const modalPromise = new Pending(`amd-modal-js-pending-id-${this.getModalCount()}`);\n // Otherwise we assume it's a promise to be resolved with\n // html and javascript.\n let 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 let 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((html) => {\n const 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((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(() => {\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((html, js) => {\n let 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 const 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 const 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 })\n .then((result) => {\n FilterEvents.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n dispatchEvent('core/modal:bodyRendered', this, this.modal[0]);\n return result;\n })\n .then(() => {\n this.bodyPromise.resolve(body);\n return;\n })\n .catch(Notification.exception)\n .always(() => {\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 modalPromise.resolve();\n\n return;\n });\n }\n }\n\n /**\n * Alternative to setBody() that can be used from non-Jquery modules\n *\n * @param {Promise} promise promise that returns {html, js} object\n * @return {Promise}\n */\n setBodyContent(promise) {\n // Call the leegacy API for now and pass it a jQuery Promise.\n // This is a non-spec feature of jQuery and cannot be produced with spec promises.\n // We can encourage people to migrate to this approach, and in future we can swap\n // it so that setBody() calls setBodyPromise().\n return promise.then(({html, js}) => this.setBody($.when(html, js)))\n .catch(exception => {\n this.hide();\n throw 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 setFooter(value) {\n // Make sure the footer is visible.\n this.showFooter();\n this.footerPromise = $.Deferred();\n\n const 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((html) => {\n footer.html(html);\n\n return value;\n })\n .then((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 })\n .then((footer) => {\n this.footerPromise.resolve(footer);\n this.showFooter();\n return;\n })\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 hasFooterContent() {\n return this.getFooter().children().length ? true : false;\n }\n\n /**\n * Hide the footer element.\n *\n * @method hideFooter\n */\n hideFooter() {\n this.getFooter().addClass('hidden');\n }\n\n /**\n * Show the footer element.\n *\n * @method showFooter\n */\n showFooter() {\n this.getFooter().removeClass('hidden');\n }\n\n /**\n * Mark the modal as a large modal.\n *\n * @method setLarge\n */\n setLarge() {\n if (this.isLarge()) {\n return;\n }\n\n this.getModal().addClass('modal-lg');\n }\n\n /**\n * Mark the modal as a centered modal.\n *\n * @method setVerticallyCentered\n */\n setVerticallyCentered() {\n if (this.isVerticallyCentered()) {\n return;\n }\n this.getModal().addClass('modal-dialog-centered');\n }\n\n /**\n * Check if the modal is a large modal.\n *\n * @method isLarge\n * @return {bool}\n */\n isLarge() {\n return this.getModal().hasClass('modal-lg');\n }\n\n /**\n * Check if the modal is vertically centered.\n *\n * @method isVerticallyCentered\n * @return {bool}\n */\n isVerticallyCentered() {\n return this.getModal().hasClass('modal-dialog-centered');\n }\n\n /**\n * Mark the modal as a small modal.\n *\n * @method setSmall\n */\n setSmall() {\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 isSmall() {\n return !this.getModal().hasClass('modal-lg');\n }\n\n /**\n * Set this modal to be scrollable or not.\n *\n * @method setScrollable\n * @param {bool} value Whether the modal is scrollable or not\n */\n setScrollable(value) {\n if (!value) {\n this.getModal()[0].classList.remove('modal-dialog-scrollable');\n return;\n }\n\n this.getModal()[0].classList.add('modal-dialog-scrollable');\n }\n\n\n /**\n * Determine the highest z-index value currently on the page.\n *\n * @method calculateZIndex\n * @return {int}\n */\n calculateZIndex() {\n const items = $(`${SELECTORS.DIALOG}, ${SELECTORS.MENU_BAR}, ${SELECTORS.HAS_Z_INDEX}`);\n let zIndex = parseInt(this.root.css('z-index'));\n\n items.each((index, item) => {\n item = $(item);\n if (!item.is(':visible')) {\n // Do not include items which are not visible in the z-index calculation.\n // This is important because some dialogues are not removed from the DOM.\n return;\n }\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 const 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 isVisible() {\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 hasFocus() {\n const 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 hasTransitions() {\n return this.getRoot().hasClass('fade');\n }\n\n /**\n * Gets the jQuery wrapped node that the Modal should be attached to.\n *\n * @returns {jQuery}\n */\n getAttachmentPoint() {\n return $(Fullscreen.getElement() || this.attachmentPoint);\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 show() {\n if (this.isVisible()) {\n return $.Deferred().resolve();\n }\n\n const pendingPromise = new Pending('core/modal:show');\n\n if (this.hasFooterContent()) {\n this.showFooter();\n } else {\n this.hideFooter();\n }\n\n this.attachToDOM();\n\n // If the focusOnClose was not set. Set the focus back to triggered element.\n if (!this.focusOnClose && document.activeElement) {\n this.focusOnClose = document.activeElement;\n }\n\n return this.getBackdrop()\n .then((backdrop) => {\n const currentIndex = this.calculateZIndex();\n const newIndex = currentIndex + 2;\n const 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 const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n $('body').css({overflow: \"hidden\", paddingRight: `${scrollbarWidth}px`});\n this.root.trigger(ModalEvents.shown, this);\n dispatchEvent('core/modal:shown', this, this.modal[0]);\n\n return;\n })\n .then(pendingPromise.resolve);\n }\n\n /**\n * Hide this modal if it does not contain a form.\n *\n * @method hideIfNotForm\n */\n hideIfNotForm() {\n const 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 hide() {\n this.getBackdrop().done((backdrop) => {\n FocusLock.untrapFocus();\n\n if (!this.countOtherVisibleModals()) {\n // Hide the backdrop if we're the last open modal.\n backdrop.hide();\n $('body').removeClass('modal-open');\n $('body').css({overflow: \"\", paddingRight: \"\"});\n }\n\n const 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', () => {\n this.getRoot().removeClass('show').addClass('hide');\n });\n } else {\n this.getRoot().removeClass('show').addClass('hide');\n }\n\n // Ensure the modal is moved onto the body node if it is still attached to the DOM.\n if ($(document.body).find(this.getRoot()).length) {\n $(document.body).append(this.getRoot());\n }\n\n // Closes popover elements that are inside the modal at the time the modal is closed.\n this.getRoot().find('[data-bs-toggle=\"popover\"]').each(function() {\n document.getElementById(this.getAttribute('aria-describedby'))?.remove();\n });\n\n this.root.trigger(ModalEvents.hidden, this);\n });\n }\n\n /**\n * Remove this modal from the DOM.\n *\n * @method destroy\n */\n destroy() {\n this.hide();\n removeToastRegion(this.getBody().get(0));\n this.root.remove();\n this.root.trigger(ModalEvents.destroyed, this);\n this.attachmentPoint.remove();\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 accessibilityShow() {\n // Make us visible to screen readers.\n Aria.unhide(this.root.get());\n\n // Hide siblings.\n Aria.hideSiblings(this.root.get()[0]);\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 accessibilityHide() {\n // Unhide siblings.\n Aria.unhideSiblings(this.root.get()[0]);\n\n // Hide this modal.\n Aria.hide(this.root.get());\n }\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n registerEventListeners() {\n this.getRoot().on('keydown', (e) => {\n if (!this.isVisible()) {\n return;\n }\n\n if (e.keyCode == KeyCodes.escape) {\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n });\n\n // Listen for clicks on the modal container.\n this.getRoot().click((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 const outsideClickEvent = $.Event(ModalEvents.outsideClick);\n this.getRoot().trigger(outsideClickEvent, this);\n\n if (!outsideClickEvent.isDefaultPrevented()) {\n this.hideIfNotForm();\n }\n }\n }\n });\n\n CustomEvents.define(this.getModal(), [CustomEvents.events.activate]);\n this.getModal().on(CustomEvents.events.activate, SELECTORS.HIDE, (e, data) => {\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n data.originalEvent.preventDefault();\n });\n\n this.getRoot().on(ModalEvents.hidden, () => {\n if (this.focusOnClose) {\n // Focus on the element that actually triggers the modal.\n this.focusOnClose.focus();\n }\n });\n }\n\n /**\n * Register a listener to close the dialogue when the cancel button is pressed.\n *\n * @method registerCloseOnCancel\n */\n registerCloseOnCancel() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('cancel'), (e, data) => {\n const 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 });\n }\n\n /**\n * Register a listener to close the dialogue when the save button is pressed.\n *\n * @method registerCloseOnSave\n */\n registerCloseOnSave() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('save'), (e, data) => {\n const 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 });\n }\n\n\n /**\n * Register a listener to close the dialogue when the delete button is pressed.\n *\n * @method registerCloseOnDelete\n */\n registerCloseOnDelete() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('delete'), (e, data) => {\n const deleteEvent = $.Event(ModalEvents.delete);\n this.getRoot().trigger(deleteEvent, this);\n\n if (!deleteEvent.isDefaultPrevented()) {\n data.originalEvent.preventDefault();\n\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n });\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 asyncSet(value, setFunction) {\n const getWrappedValue = (value) => {\n if (value instanceof Promise) {\n return $.when(value);\n }\n\n if (typeof value !== 'object' || !value.hasOwnProperty('then')) {\n return $.Deferred().resolve(value);\n }\n\n return value;\n };\n\n return getWrappedValue(value)\n .then((content) => setFunction(content))\n .catch(Notification.exception);\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 setButtonText(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 getActionSelector(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 setRemoveOnClose(remove) {\n this.removeOnClose = remove;\n }\n\n /**\n * Set the return element for the modal.\n *\n * @param {Element|jQuery} element Element to focus when the modal is closed\n */\n setReturnElement(element) {\n this.focusOnClose = element;\n }\n\n /**\n * Set the a button enabled or disabled.\n *\n * @param {DOMString} action The action of the button\n * @param {Boolean} disabled the new disabled value\n */\n setButtonDisabled(action, disabled) {\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 if (disabled) {\n button.attr('disabled', '');\n } else {\n button.removeAttr('disabled');\n }\n }\n\n /**\n * Set the template JS for this modal.\n * @param {String} js The JavaScript to run when the modal is attached to the DOM.\n */\n setTemplateJS(js) {\n this.templateJS = js;\n }\n}\n"],"names":["SELECTORS","TEMPLATES","Modal","root","this","_root","filter","constructor","modal","find","header","headerPromise","$","Deferred","title","titlePromise","body","bodyPromise","footer","footerPromise","hiddenSiblings","isAttached","bodyJS","footerJS","modalCount","modalCounter","attachmentPoint","document","createElement","append","focusOnClose","templateJS","is","Notification","exception","message","length","registerEventListeners","TYPE","Error","TEMPLATE","register","modalConfig","pendingModalPromise","Pending","type","templateName","_getTemplateName","templateContext","html","js","Templates","renderForPromise","setTemplateJS","configure","resolve","template","registry","has","get","show","large","isVerticallyCentered","removeOnClose","scrollable","returnElement","buttons","setLarge","setVerticallyCentered","setRemoveOnClose","setReturnElement","setScrollable","undefined","setTitle","setBody","setFooter","Object","entries","forEach","_ref","key","value","setButtonText","attachToDOM","getAttachmentPoint","FocusLock","trapFocus","runTemplateJS","countOtherVisibleModals","count","each","index","element","hasClass","getBackdrop","backdropPromise","render","then","ModalBackdrop","catch","getRoot","getModal","getTitle","getBody","getFooter","getTitlePromise","getBodyPromise","getFooterPromise","getModalCount","asyncSet","bind","FilterEvents","notifyFilterContentUpdated","trigger","ModalEvents","bodyRendered","modalPromise","contentPromise","css","when","state","height","innerHeight","animate","loadingIcon","hide","fadeIn","promise","fadeOut","result","isVisible","currentHeight","newHeight","opacity","duration","queue","always","setBodyContent","_ref2","showFooter","hasFooterContent","children","hideFooter","addClass","removeClass","isLarge","setSmall","isSmall","classList","add","remove","calculateZIndex","items","zIndex","parseInt","item","itemZIndex","hasFocus","target","activeElement","hasTransitions","Fullscreen","getElement","pendingPromise","backdrop","newIndex","newBackdropIndex","setZIndex","accessibilityShow","focus","scrollbarWidth","window","innerWidth","documentElement","clientWidth","overflow","paddingRight","shown","hideIfNotForm","done","untrapFocus","currentIndex","accessibilityHide","one","getElementById","getAttribute","hidden","destroy","destroyed","Aria","unhide","hideSiblings","unhideSiblings","on","e","keyCode","KeyCodes","escape","click","closest","outsideClickEvent","Event","outsideClick","isDefaultPrevented","CustomEvents","define","events","activate","data","originalEvent","preventDefault","registerCloseOnCancel","getActionSelector","cancelEvent","cancel","registerCloseOnSave","saveEvent","save","registerCloseOnDelete","deleteEvent","delete","setFunction","Promise","hasOwnProperty","getWrappedValue","content","action","button","text","setButtonDisabled","disabled","attr","removeAttr","Map","module","existing","set","Prefetch","prefetchTemplate"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"modal.min.js","sources":["../src/modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Contain the logic for modals.\n *\n * @module core/modal\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as Templates from 'core/templates';\nimport * as Notification from 'core/notification';\nimport * as KeyCodes from 'core/key_codes';\nimport ModalBackdrop from 'core/modal_backdrop';\nimport ModalEvents from 'core/modal_events';\nimport Pending from 'core/pending';\nimport * as CustomEvents from 'core/custom_interaction_events';\nimport * as FilterEvents from 'core_filters/events';\nimport * as FocusLock from 'core/local/aria/focuslock';\nimport * as Aria from 'core/aria';\nimport * as Fullscreen from 'core/fullscreen';\nimport {removeToastRegion} from './toast';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport * as Prefetch from 'core/prefetch';\n\n/**\n * A configuration to provide to the modal.\n *\n * @typedef {Object} ModalConfig\n *\n * @property {string} [type] The type of modal to create.\n * @property {string|Promise} [title] The title of the modal.\n * @property {string|Promise} [body] The body of the modal.\n * @property {string|Promise} [footer] The footer of the modal.\n * @property {boolean} [show=false] Whether to show the modal immediately.\n * @property {boolean} [scrollable=true] Whether the modal should be scrollable.\n * @property {boolean} [removeOnClose=true] Whether the modal should be removed from the DOM when it is closed.\n * @property {Element|jQuery} [returnElement] The element to focus when closing the modal.\n * @property {boolean} [large=false] Whether the modal should be a large modal.\n * @property {boolean} [isVerticallyCentered=false] Whether the modal should be vertically centered.\n * @property {object} [buttons={}] The buttons to display in the footer as a key => title pair.\n */\n\nconst 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\nconst TEMPLATES = {\n LOADING: 'core/loading',\n BACKDROP: 'core/modal_backdrop',\n};\n\nexport default class Modal {\n /** @var {string} The type of modal */\n static TYPE = 'default';\n\n /** @var {string} The template to use for this modal */\n static TEMPLATE = 'core/modal';\n\n /** @var {Promise} Module singleton for the backdrop to be reused by all Modal instances */\n static backdropPromise = null;\n\n /**\n * @var {Number} A counter that gets incremented for each modal created.\n * This can be used to generate unique values for the modals.\n */\n static modalCounter = 0;\n\n /**\n * @var {Number} A singleton registry for all modules to access. Allows types to be\n * added at runtime.\n */\n static registry = new Map();\n\n /**\n * Getter method for .root element.\n * @return {object} jQuery object\n */\n get root() {\n return $(this._root.filter(SELECTORS.CONTAINER));\n }\n\n /**\n * Setter method for .root element.\n * @param {object} root jQuery object\n */\n set root(root) {\n this._root = root;\n }\n\n /**\n * Constructor for the Modal.\n *\n * @param {HTMLElement} root The HTMLElement at the root of the Modal content\n */\n constructor(root) {\n this.root = $(root);\n\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 = Modal.modalCounter++;\n this.attachmentPoint = document.createElement('div');\n document.body.append(this.attachmentPoint);\n this.focusOnClose = null;\n this.templateJS = null;\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 * Register a modal with the legacy modal registry.\n *\n * This is provided to allow backwards-compatibility with existing code that uses the legacy modal registry.\n * It is not necessary to register modals for code only present in Moodle 4.3 and later.\n */\n static registerModalType() {\n if (!this.TYPE) {\n throw new Error(`Unknown modal type`, this);\n }\n\n if (!this.TEMPLATE) {\n throw new Error(`Unknown modal template`, this);\n }\n\n this.register(\n this.TYPE,\n this,\n this.TEMPLATE,\n );\n }\n\n /**\n * Register a modal.\n *\n * @param {string} type The type of modal (must be unique)\n * @param {function} module The modal module (must be a constructor function of type core/modal)\n * @param {string} template The template name of the modal\n */\n static register = (type, module, template) => {\n const existing = this.registry.get(type);\n if (existing && existing.module !== module) {\n Notification.exception({\n message: `Modal of type '${type}' is already registered`,\n });\n }\n\n if (!module || typeof module !== 'function') {\n Notification.exception({message: \"You must provide a modal module\"});\n }\n\n if (!template) {\n Notification.exception({message: \"You must provide a modal template\"});\n }\n\n this.registry.set(type, {module, template});\n\n // Prefetch the template.\n Prefetch.prefetchTemplate(template);\n };\n\n /**\n * Create a new modal using the ModalFactory.\n * This is a shortcut to creating the modal.\n * Create a new modal using the supplied configuration.\n *\n * @param {ModalConfig} modalConfig\n * @returns {Promise}\n */\n static async create(modalConfig = {}) {\n const pendingModalPromise = new Pending('core/modal:create');\n modalConfig.type = this.TYPE;\n\n const templateName = this._getTemplateName(modalConfig);\n const templateContext = modalConfig.templateContext || {};\n const {html, js} = await Templates.renderForPromise(templateName, templateContext);\n\n const modal = new this(html);\n if (js) {\n modal.setTemplateJS(js);\n }\n modal.configure(modalConfig);\n\n pendingModalPromise.resolve();\n\n return modal;\n }\n\n /**\n * A helper to get the template name for this modal.\n *\n * @param {ModalConfig} modalConfig\n * @returns {string}\n * @protected\n */\n static _getTemplateName(modalConfig) {\n if (modalConfig.template) {\n return modalConfig.template;\n }\n\n if (this.TEMPLATE) {\n return this.TEMPLATE;\n }\n\n if (this.registry.has(this.TYPE)) {\n const config = this.registry.get(this.TYPE);\n return config.template;\n }\n\n throw new Error(`Unable to determine template name for modal ${this.TYPE}`);\n }\n\n /**\n * Configure the modal.\n *\n * @param {ModalConfig} param0 The configuration options\n */\n configure({\n show = false,\n large = false,\n isVerticallyCentered = false,\n removeOnClose = false,\n scrollable = true,\n returnElement,\n title,\n body,\n footer,\n buttons = {},\n } = {}) {\n if (large) {\n this.setLarge();\n }\n\n if (isVerticallyCentered) {\n this.setVerticallyCentered();\n }\n\n // If configured remove the modal when hiding it.\n // Ideally this should be true, but we need to identify places that this breaks first.\n this.setRemoveOnClose(removeOnClose);\n this.setReturnElement(returnElement);\n this.setScrollable(scrollable);\n\n if (title !== undefined) {\n this.setTitle(title);\n }\n\n if (body !== undefined) {\n this.setBody(body);\n }\n\n if (footer !== undefined) {\n this.setFooter(footer);\n }\n\n Object.entries(buttons).forEach(([key, value]) => this.setButtonText(key, value));\n\n // If configured show the modal.\n if (show) {\n this.show();\n }\n }\n\n /**\n * Attach the modal to the correct part of the page.\n *\n * If it hasn't already been added it runs any\n * javascript that has been cached until now.\n *\n * @method attachToDOM\n */\n attachToDOM() {\n this.getAttachmentPoint().append(this._root);\n\n if (this.isAttached) {\n return;\n }\n\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.templateJS) {\n Templates.runTemplateJS(this.templateJS);\n this.templateJS = null;\n }\n\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 countOtherVisibleModals() {\n let count = 0;\n $('body').find(SELECTORS.CONTAINER).each((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 });\n\n return count;\n }\n\n /**\n * Get the modal backdrop.\n *\n * @method getBackdrop\n * @return {object} jQuery promise\n */\n getBackdrop() {\n if (!Modal.backdropPromise) {\n Modal.backdropPromise = Templates.render(TEMPLATES.BACKDROP, {})\n .then((html) => new ModalBackdrop($(html)))\n .catch(Notification.exception);\n }\n\n return Modal.backdropPromise;\n }\n\n /**\n * Get the root element of this modal.\n *\n * @method getRoot\n * @return {object} jQuery object\n */\n getRoot() {\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 getModal() {\n return this.modal;\n }\n\n /**\n * Get the modal title element.\n *\n * @method getTitle\n * @return {object} jQuery object\n */\n getTitle() {\n return this.title;\n }\n\n /**\n * Get the modal body element.\n *\n * @method getBody\n * @return {object} jQuery object\n */\n getBody() {\n return this.body;\n }\n\n /**\n * Get the modal footer element.\n *\n * @method getFooter\n * @return {object} jQuery object\n */\n getFooter() {\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 getTitlePromise() {\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 getBodyPromise() {\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 getFooterPromise() {\n return this.footerPromise;\n }\n\n /**\n * Get the unique modal count.\n *\n * @method getModalCount\n * @return {int}\n */\n getModalCount() {\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 setTitle(value) {\n const title = this.getTitle();\n this.titlePromise = $.Deferred();\n\n this.asyncSet(value, title.html.bind(title))\n .then(() => {\n this.titlePromise.resolve(title);\n return;\n })\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 * @fires event:filterContentUpdated\n */\n setBody(value) {\n this.bodyPromise = $.Deferred();\n\n const body = this.getBody();\n\n if (typeof value === 'string') {\n // Just set the value if it's a string.\n body.html(value);\n FilterEvents.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n this.bodyPromise.resolve(body);\n } else {\n const modalPromise = new Pending(`amd-modal-js-pending-id-${this.getModalCount()}`);\n // Otherwise we assume it's a promise to be resolved with\n // html and javascript.\n let 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 let 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((html) => {\n const 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((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(() => {\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((html, js) => {\n let 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 const 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 const 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 })\n .then((result) => {\n FilterEvents.notifyFilterContentUpdated(body);\n this.getRoot().trigger(ModalEvents.bodyRendered, this);\n dispatchEvent('core/modal:bodyRendered', this, this.modal[0]);\n return result;\n })\n .then(() => {\n this.bodyPromise.resolve(body);\n return;\n })\n .catch(Notification.exception)\n .always(() => {\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 modalPromise.resolve();\n\n return;\n });\n }\n }\n\n /**\n * Alternative to setBody() that can be used from non-Jquery modules\n *\n * @param {Promise} promise promise that returns {html, js} object\n * @return {Promise}\n */\n setBodyContent(promise) {\n // Call the leegacy API for now and pass it a jQuery Promise.\n // This is a non-spec feature of jQuery and cannot be produced with spec promises.\n // We can encourage people to migrate to this approach, and in future we can swap\n // it so that setBody() calls setBodyPromise().\n return promise.then(({html, js}) => this.setBody($.when(html, js)))\n .catch(exception => {\n this.hide();\n throw 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 setFooter(value) {\n // Make sure the footer is visible.\n this.showFooter();\n this.footerPromise = $.Deferred();\n\n const 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((html) => {\n footer.html(html);\n\n return value;\n })\n .then((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 })\n .then((footer) => {\n this.footerPromise.resolve(footer);\n this.showFooter();\n return;\n })\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 hasFooterContent() {\n return this.getFooter().children().length ? true : false;\n }\n\n /**\n * Hide the footer element.\n *\n * @method hideFooter\n */\n hideFooter() {\n this.getFooter().addClass('hidden');\n }\n\n /**\n * Show the footer element.\n *\n * @method showFooter\n */\n showFooter() {\n this.getFooter().removeClass('hidden');\n }\n\n /**\n * Mark the modal as a large modal.\n *\n * @method setLarge\n */\n setLarge() {\n if (this.isLarge()) {\n return;\n }\n\n this.getModal().addClass('modal-lg');\n }\n\n /**\n * Mark the modal as a centered modal.\n *\n * @method setVerticallyCentered\n */\n setVerticallyCentered() {\n if (this.isVerticallyCentered()) {\n return;\n }\n this.getModal().addClass('modal-dialog-centered');\n }\n\n /**\n * Check if the modal is a large modal.\n *\n * @method isLarge\n * @return {bool}\n */\n isLarge() {\n return this.getModal().hasClass('modal-lg');\n }\n\n /**\n * Check if the modal is vertically centered.\n *\n * @method isVerticallyCentered\n * @return {bool}\n */\n isVerticallyCentered() {\n return this.getModal().hasClass('modal-dialog-centered');\n }\n\n /**\n * Mark the modal as a small modal.\n *\n * @method setSmall\n */\n setSmall() {\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 isSmall() {\n return !this.getModal().hasClass('modal-lg');\n }\n\n /**\n * Set this modal to be scrollable or not.\n *\n * @method setScrollable\n * @param {bool} value Whether the modal is scrollable or not\n */\n setScrollable(value) {\n if (!value) {\n this.getModal()[0].classList.remove('modal-dialog-scrollable');\n return;\n }\n\n this.getModal()[0].classList.add('modal-dialog-scrollable');\n }\n\n\n /**\n * Determine the highest z-index value currently on the page.\n *\n * @method calculateZIndex\n * @return {int}\n */\n calculateZIndex() {\n const items = $(`${SELECTORS.DIALOG}, ${SELECTORS.MENU_BAR}, ${SELECTORS.HAS_Z_INDEX}`);\n let zIndex = parseInt(this.root.css('z-index'));\n\n items.each((index, item) => {\n item = $(item);\n if (!item.is(':visible')) {\n // Do not include items which are not visible in the z-index calculation.\n // This is important because some dialogues are not removed from the DOM.\n return;\n }\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 const 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 isVisible() {\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 hasFocus() {\n const 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 hasTransitions() {\n return this.getRoot().hasClass('fade');\n }\n\n /**\n * Gets the jQuery wrapped node that the Modal should be attached to.\n *\n * @returns {jQuery}\n */\n getAttachmentPoint() {\n return $(Fullscreen.getElement() || this.attachmentPoint);\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 show() {\n if (this.isVisible()) {\n return $.Deferred().resolve();\n }\n\n const pendingPromise = new Pending('core/modal:show');\n\n if (this.hasFooterContent()) {\n this.showFooter();\n } else {\n this.hideFooter();\n }\n\n this.attachToDOM();\n\n // If the focusOnClose was not set. Set the focus back to triggered element.\n if (!this.focusOnClose && document.activeElement) {\n this.focusOnClose = document.activeElement;\n }\n\n return this.getBackdrop()\n .then((backdrop) => {\n const currentIndex = this.calculateZIndex();\n const newIndex = currentIndex + 2;\n const 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 const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n $('body').css({overflow: \"hidden\", paddingRight: `${scrollbarWidth}px`});\n this.root.trigger(ModalEvents.shown, this);\n dispatchEvent('core/modal:shown', this, this.modal[0]);\n\n return;\n })\n .then(pendingPromise.resolve);\n }\n\n /**\n * Hide this modal if it does not contain a form.\n *\n * @method hideIfNotForm\n */\n hideIfNotForm() {\n const formElement = this.modal.find(SELECTORS.FORM);\n if (formElement.length == 0) {\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n }\n\n /**\n * Hide this modal.\n *\n * @method hide\n */\n hide() {\n this.getBackdrop().done((backdrop) => {\n FocusLock.untrapFocus();\n\n if (!this.countOtherVisibleModals()) {\n // Hide the backdrop if we're the last open modal.\n backdrop.hide();\n $('body').removeClass('modal-open');\n $('body').css({overflow: \"\", paddingRight: \"\"});\n }\n\n const 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', () => {\n this.getRoot().removeClass('show').addClass('hide');\n });\n } else {\n this.getRoot().removeClass('show').addClass('hide');\n }\n\n // Ensure the modal is moved onto the body node if it is still attached to the DOM.\n if ($(document.body).find(this.getRoot()).length) {\n $(document.body).append(this.getRoot());\n }\n\n // Closes popover elements that are inside the modal at the time the modal is closed.\n this.getRoot().find('[data-bs-toggle=\"popover\"]').each(function() {\n document.getElementById(this.getAttribute('aria-describedby'))?.remove();\n });\n\n this.root.trigger(ModalEvents.hidden, this);\n });\n }\n\n /**\n * Remove this modal from the DOM.\n *\n * @method destroy\n */\n destroy() {\n this.hide();\n removeToastRegion(this.getBody().get(0));\n this.root.remove();\n this.root.trigger(ModalEvents.destroyed, this);\n this.attachmentPoint.remove();\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 accessibilityShow() {\n // Make us visible to screen readers.\n Aria.unhide(this.root.get());\n\n // Hide siblings.\n Aria.hideSiblings(this.root.get()[0]);\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 accessibilityHide() {\n // Unhide siblings.\n Aria.unhideSiblings(this.root.get()[0]);\n\n // Hide this modal.\n Aria.hide(this.root.get());\n }\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n registerEventListeners() {\n this.getRoot().on('keydown', (e) => {\n if (!this.isVisible()) {\n return;\n }\n\n if (e.keyCode == KeyCodes.escape) {\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n });\n\n // Listen for clicks on the modal container.\n this.getRoot().click((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 const outsideClickEvent = $.Event(ModalEvents.outsideClick);\n this.getRoot().trigger(outsideClickEvent, this);\n\n if (!outsideClickEvent.isDefaultPrevented()) {\n this.hideIfNotForm();\n }\n }\n }\n });\n\n CustomEvents.define(this.getModal(), [CustomEvents.events.activate]);\n this.getModal().on(CustomEvents.events.activate, SELECTORS.HIDE, (e, data) => {\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n data.originalEvent.preventDefault();\n });\n\n this.getRoot().on(ModalEvents.hidden, () => {\n if (this.focusOnClose) {\n // Focus on the element that actually triggers the modal.\n this.focusOnClose.focus();\n }\n });\n }\n\n /**\n * Register a listener to close the dialogue when the cancel button is pressed.\n *\n * @method registerCloseOnCancel\n */\n registerCloseOnCancel() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('cancel'), (e, data) => {\n const 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 });\n }\n\n /**\n * Register a listener to close the dialogue when the save button is pressed.\n *\n * @method registerCloseOnSave\n */\n registerCloseOnSave() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('save'), (e, data) => {\n const 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 });\n }\n\n\n /**\n * Register a listener to close the dialogue when the delete button is pressed.\n *\n * @method registerCloseOnDelete\n */\n registerCloseOnDelete() {\n // Handle the clicking of the Cancel button.\n this.getModal().on(CustomEvents.events.activate, this.getActionSelector('delete'), (e, data) => {\n const deleteEvent = $.Event(ModalEvents.delete);\n this.getRoot().trigger(deleteEvent, this);\n\n if (!deleteEvent.isDefaultPrevented()) {\n data.originalEvent.preventDefault();\n\n if (this.removeOnClose) {\n this.destroy();\n } else {\n this.hide();\n }\n }\n });\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 asyncSet(value, setFunction) {\n const getWrappedValue = (value) => {\n if (value instanceof Promise) {\n return $.when(value);\n }\n\n if (typeof value !== 'object' || !value.hasOwnProperty('then')) {\n return $.Deferred().resolve(value);\n }\n\n return value;\n };\n\n return getWrappedValue(value)\n .then((content) => setFunction(content))\n .catch(Notification.exception);\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 setButtonText(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 getActionSelector(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 setRemoveOnClose(remove) {\n this.removeOnClose = remove;\n }\n\n /**\n * Set the return element for the modal.\n *\n * @param {Element|jQuery} element Element to focus when the modal is closed\n */\n setReturnElement(element) {\n this.focusOnClose = element;\n }\n\n /**\n * Set the a button enabled or disabled.\n *\n * @param {DOMString} action The action of the button\n * @param {Boolean} disabled the new disabled value\n */\n setButtonDisabled(action, disabled) {\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 if (disabled) {\n button.attr('disabled', '');\n } else {\n button.removeAttr('disabled');\n }\n }\n\n /**\n * Set the template JS for this modal.\n * @param {String} js The JavaScript to run when the modal is attached to the DOM.\n */\n setTemplateJS(js) {\n this.templateJS = js;\n }\n}\n"],"names":["SELECTORS","TEMPLATES","Modal","root","this","_root","filter","constructor","modal","find","header","headerPromise","$","Deferred","title","titlePromise","body","bodyPromise","footer","footerPromise","hiddenSiblings","isAttached","bodyJS","footerJS","modalCount","modalCounter","attachmentPoint","document","createElement","append","focusOnClose","templateJS","is","Notification","exception","message","length","registerEventListeners","TYPE","Error","TEMPLATE","register","modalConfig","pendingModalPromise","Pending","type","templateName","_getTemplateName","templateContext","html","js","Templates","renderForPromise","setTemplateJS","configure","resolve","template","registry","has","get","show","large","isVerticallyCentered","removeOnClose","scrollable","returnElement","buttons","setLarge","setVerticallyCentered","setRemoveOnClose","setReturnElement","setScrollable","undefined","setTitle","setBody","setFooter","Object","entries","forEach","_ref","key","value","setButtonText","attachToDOM","getAttachmentPoint","FocusLock","trapFocus","runTemplateJS","countOtherVisibleModals","count","each","index","element","hasClass","getBackdrop","backdropPromise","render","then","ModalBackdrop","catch","getRoot","getModal","getTitle","getBody","getFooter","getTitlePromise","getBodyPromise","getFooterPromise","getModalCount","asyncSet","bind","FilterEvents","notifyFilterContentUpdated","trigger","ModalEvents","bodyRendered","modalPromise","contentPromise","css","when","state","height","innerHeight","animate","loadingIcon","hide","fadeIn","promise","fadeOut","result","isVisible","currentHeight","newHeight","opacity","duration","queue","always","setBodyContent","_ref2","showFooter","hasFooterContent","children","hideFooter","addClass","removeClass","isLarge","setSmall","isSmall","classList","add","remove","calculateZIndex","items","zIndex","parseInt","item","itemZIndex","hasFocus","target","activeElement","hasTransitions","Fullscreen","getElement","pendingPromise","backdrop","newIndex","newBackdropIndex","setZIndex","accessibilityShow","focus","scrollbarWidth","window","innerWidth","documentElement","clientWidth","overflow","paddingRight","shown","hideIfNotForm","destroy","done","untrapFocus","currentIndex","accessibilityHide","one","getElementById","getAttribute","hidden","destroyed","Aria","unhide","hideSiblings","unhideSiblings","on","e","keyCode","KeyCodes","escape","click","closest","outsideClickEvent","Event","outsideClick","isDefaultPrevented","CustomEvents","define","events","activate","data","originalEvent","preventDefault","registerCloseOnCancel","getActionSelector","cancelEvent","cancel","registerCloseOnSave","saveEvent","save","registerCloseOnDelete","deleteEvent","delete","setFunction","Promise","hasOwnProperty","getWrappedValue","content","action","button","text","setButtonDisabled","disabled","attr","removeAttr","Map","module","existing","set","Prefetch","prefetchTemplate"],"mappings":"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"} \ No newline at end of file diff --git a/public/lib/amd/src/modal.js b/public/lib/amd/src/modal.js index 700b9ed9e3d..56403caa2df 100644 --- a/public/lib/amd/src/modal.js +++ b/public/lib/amd/src/modal.js @@ -947,7 +947,11 @@ export default class Modal { hideIfNotForm() { const formElement = this.modal.find(SELECTORS.FORM); if (formElement.length == 0) { - this.hide(); + if (this.removeOnClose) { + this.destroy(); + } else { + this.hide(); + } } }