{"version":3,"file":"modal-BVFLN7FV.js","sources":["../../../app/frontend/javascript/components/modal.js"],"sourcesContent":["import Loader from \"@/javascript/components/loader\"\nimport { slideTransition } from \"@/javascript/components/animations/slide\"\nimport { fadeOut } from \"@/javascript/components/animations/fade\"\nimport { closest } from \"@/javascript/components/tools/closest\"\nimport CSRFFetch from \"@/javascript/components/tools/fetch\"\nimport reportError from \"@/javascript/components/errors\"\n\nlet openModal = null\n\nconst preventDefault = (e) => {\n e = e || window.event\n if(e.preventDefault) {\n e.preventDefault()\n }\n e.returnValue = false\n}\n\nexport default class Modal {\n static defaultOptions = {\n // Title to be displayed at the top of the modal\n title: undefined,\n // URL to fetch content of the modal\n url: undefined,\n // Error message to display when content loading encounters the error\n errorMessage: \"This page couldn't be loaded. Please close the modal and try again.\",\n // Class to add to modal, for extra styling.\n class: undefined,\n // CSS selector which will select and set an HTML element from the\n // loaded HTML as the Title of the modal.\n titleSelector: 'header.modal-title',\n // HTTP method to use to open the modal\n method: 'get'\n }\n\n static overlay () {\n if(this._overlay) {\n return this._overlay\n }\n\n this._overlay = document.createElement('div')\n this._overlay.classList.add('modal-overlay')\n document.body.appendChild(this._overlay)\n return this._overlay\n }\n\n constructor (opts) {\n this.options = {}\n Object.entries(this.constructor.defaultOptions).forEach((entry) => {\n const [key, defaultValue] = entry\n this.options[key] = opts[key] || defaultValue\n })\n\n this.parent = document.body\n this.overlay = this.constructor.overlay()\n this.overlay.modal = this\n this.events = {}\n }\n\n bindToElem (button) {\n button.addEventListener('click', (e) => {\n preventDefault(e)\n if(openModal) {\n openModal.close()\n }\n this.open()\n })\n }\n\n on (event, handler) {\n this.events[event] ||= []\n this.events[event].push(handler)\n }\n\n trigger (event, ...args) {\n Promise.all(\n (this.events[event] || []).map((handler) => {\n return new Promise((resolve) => {\n handler(...args)\n resolve()\n })\n })\n )\n }\n\n open() {\n this._buildWrapper()\n .then(() => {\n this.parent.classList.add('with-modal')\n this.overlay.classList.add('open')\n this.wrapper.style.setProperty('visibility', 'hidden')\n this.wrapper.style.removeProperty('visibility')\n openModal = this\n return this.container\n })\n .then(() => this.trigger('open', this))\n .then(() => {\n if(this.options.url) {\n slideTransition(this.container, 300, this._loadContent())\n }\n })\n }\n\n close() {\n if(document.querySelector('.modal-overlay .js-refresh-page-on-modal-close') != null) {\n window.location.reload()\n }\n\n this.parent.classList.remove('with-modal')\n // Selectize controls live outside of the modal, at the bottom of the document, so we have\n // to manually destroy any selectize controls in the modal as they won't be garbage collected\n this.container.querySelectorAll('select.selectized').forEach((select) => {\n select.selectize.destroy()\n })\n this.container.innerHTML = ''\n this.overlay.classList.remove('open')\n this.overlay.innerHTML = ''\n this.trigger('close')\n openModal = null\n }\n\n _buildWrapper() {\n return new Promise((resolve) => {\n this.wrapper = document.createElement('div')\n this.wrapper.classList.add('modal')\n this.wrapper.classList.add('loading')\n this.header = document.createElement('header')\n if(this.options.title) {\n const title = document.createElement('h3')\n title.innerHTML = this.options.title\n this.header.appendChild(title)\n }\n if(this.options.class) {\n this.wrapper.classList.add(this.options.class)\n }\n this.wrapper.appendChild(this.header)\n this.containerWrapper = document.createElement('div')\n this.containerWrapper.classList.add('container-wrapper')\n this.container = document.createElement('article')\n this.containerWrapper.appendChild(this.container)\n this.wrapper.appendChild(this.containerWrapper)\n\n const closeButton = document.createElement('div')\n closeButton.classList.add('modal-close')\n closeButton.addEventListener('click', (e) => {\n preventDefault(e)\n this.close()\n })\n this.wrapper.appendChild(closeButton)\n this.overlay.appendChild(this.wrapper)\n resolve(this.wrapper)\n })\n }\n\n _loadContent() {\n const loader = document.createElement('div')\n loader.classList.add('loader')\n this.containerWrapper.appendChild(loader)\n\n return CSRFFetch(this.options.url, {method: this.options.method})\n .then((response) => {\n if(!response.ok) {\n throw Error(response.statusText)\n }\n return response.text()\n })\n .then((html) => {\n const json = this.resolveJson(html)\n if(typeof(json) == 'object' && json.redirect) {\n return window.location = json.redirect\n }\n return html\n })\n .then((html) => this.setContent(html))\n .then((container) => new Loader(this.container).all())\n .then((container) => this.trigger('load', container))\n .then(() => this.removeLoading())\n .catch((e) => {\n reportError(e)\n this.container.innerHTML = `${this.options.errorMessage}`\n this.removeLoading()\n })\n }\n\n resolveJson (data) {\n try {\n return JSON.parse(data)\n } catch {\n return data\n }\n }\n\n setContent (html) {\n this.container.innerHTML = html\n this.setModalTitle(this.container)\n return this.container\n }\n\n setModalTitle (_html) {\n if(!this.options.titleSelector) {\n return\n }\n\n const newHeader = this.container.querySelector(this.options.titleSelector)\n if(!newHeader) {\n return\n }\n\n const currentHeader = this.wrapper.querySelector('header')\n while(currentHeader.firstChild) {\n currentHeader.firstChild.remove()\n }\n while(newHeader.firstChild) {\n currentHeader.appendChild(newHeader.firstChild)\n }\n newHeader.remove()\n }\n\n removeLoading() {\n const loader = this.containerWrapper.querySelector('.loader')\n if (loader) {\n fadeOut(loader, 200)\n }\n this.wrapper.classList.remove('loading')\n }\n\n isScrollable() {\n return this.containerWrapper.clientHeight < this.container.clientHeight\n }\n}\n\n// TODO: Figure out how JS garbage collector collect our DOM elements!\n// See: https://stackoverflow.com/questions/45466055/js-garbage-collector-going-crazy\nlet elements = []\n\n\nexport function initModalLink (element) {\n if(element.modal) {\n return element.modal\n }\n const options = {\n url: element.dataset.url || element.href,\n title: element.dataset.title,\n class: element.dataset.class,\n titleSelector: element.dataset.titleselector,\n method: element.hasAttribute('method') && element.attributes['method'].value\n }\n elements.push(element)\n element.modal = new Modal(options)\n element.modal.bindToElem(element)\n return element.modal\n}\n\nLoader.functional((content, resolve) => {\n content.querySelectorAll('[data-modal]').forEach((elem) => {\n initModalLink(elem)\n })\n resolve()\n})\n\ndocument.addEventListener('formReloaded', (e) => {\n const target = e.target\n const modal = closest(target, '.modal')\n if(!modal) {\n return\n }\n\n let targetScroll = target.offsetTop - 30\n if(targetScroll < 0) {\n targetScroll = 0\n }\n openModal.container.scrollTop = targetScroll\n})\n\ndocument.addEventListener('formSubmitted', (e) => {\n if(!e.detail.success) {\n return\n }\n\n const target = e.target\n const modal = closest(target, '.modal')\n if(!modal) {\n return\n }\n openModal.setModalTitle(e.detail.response)\n})\n\ndocument.addEventListener('click', (e) => {\n const event = e || window.event\n const target = e.target\n if(!closest(target, '.modal-close')) {\n return\n }\n\n const modal = closest(target, '.modal-overlay')\n if(!modal) {\n return\n }\n\n e.preventDefault()\n if(openModal) {\n openModal.close()\n }\n})\n"],"names":["openModal","preventDefault","e","Modal","opts","entry","key","defaultValue","button","event","handler","_a","args","resolve","slideTransition","select","title","closeButton","loader","CSRFFetch","response","html","json","container","Loader","reportError","data","_html","newHeader","currentHeader","fadeOut","__publicField","initModalLink","element","options","content","elem","target","closest","targetScroll"],"mappings":"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"}