{"version":3,"file":"modal.min.js","sources":["https:\/\/courses.fincert.org\/lib\/amd\/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 * as ModalRegistry from 'core\/modal_registry';\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';\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 * 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 ModalRegistry.register(\n this.TYPE,\n this,\n this.TEMPLATE,\n );\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_factory: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 (ModalRegistry.has(this.TYPE)) {\n \/\/ Note: This is provided as an interim backwards-compatability layer and will be removed four releases after 4.3.\n window.console.warning(\n 'Use of core\/modal_registry is deprecated. ' +\n 'Please define your modal template in a new static TEMPLATE property on your modal class.',\n );\n const config = ModalRegistry.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 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 this.root.trigger(ModalEvents.shown, this);\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 }\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-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","ModalRegistry","register","modalConfig","pendingModalPromise","Pending","type","templateName","_getTemplateName","templateContext","html","js","Templates","renderForPromise","setTemplateJS","configure","resolve","template","has","window","console","warning","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","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"],"mappings":"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\/B,cAAc8E,MAAMR,WACrB\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\/C1N,KAAK4G,SAAS5B,MAAO2I,OAAOC,KAAK\/G,KAAK8G,SASjDf,kBAAkBc,cACP,iBAAmBA,OAAS,KAQvCtJ,iBAAiBiF,aACRvF,cAAgBuF,OAQzBhF,iBAAiBsB,cACRjE,aAAeiE,QASxBkI,kBAAkBH,OAAQI,gBAChBH,OAAS3N,KAAKuG,YAAYlG,KAAKL,KAAK4M,kBAAkBc,aAEvDC,aACK,IAAIxL,MAAM,uBAAyBuL,OAAS,YAElDI,SACAH,OAAOI,KAAK,WAAY,IAExBJ,OAAOK,WAAW,YAQ1B9K,cAAcH,SACLpB,WAAaoB,kDAjoCLjD,aAEH,2BAFGA,iBAKC,8BALDA,wBAQQ,sBARRA,qBAcK"}