(function() { 'use strict'; /** * * Modal Utility * * Attribute: uw-modal * * Params: * data-modal-trigger: string * Selector for the element that toggles the modal. * If trigger element has "href" attribute the modal will be dynamically loaded from the referenced page * data-modal-closeable: boolean property * If the param is present the modal will have a close-icon and can also be closed by clicking anywhere on the overlay * * Example usage: *
This is the modal content *
Click me to open the modal */ var MODAL_UTIL_NAME = 'modal'; var MODAL_UTIL_SELECTOR = '[uw-modal]'; var MODAL_HEADERS = { 'Is-Modal': 'True', }; var MODAL_INITIALIZED_CLASS = 'modal--initialized'; var MODAL_CLASS = 'modal'; var MODAL_OPEN_CLASS = 'modal--open'; var MODAL_TRIGGER_CLASS = 'modal__trigger'; var MODAL_CONTENT_CLASS = 'modal__content'; var MODAL_OVERLAY_CLASS = 'modal__overlay'; var MODAL_OVERLAY_OPEN_CLASS = 'modal__overlay--open'; var MODAL_CLOSER_CLASS = 'modal__closer'; var MAIN_CONTENT_CLASS = 'main__content-body' // one singleton wrapper to keep all the modals to avoid CSS bug // with blurry text due to `transform: translate(-50%, -50%)` // will be created (and reused) for the first modal that gets initialized var MODALS_WRAPPER_CLASS = 'modals-wrapper'; var MODALS_WRAPPER_SELECTOR = '.' + MODALS_WRAPPER_CLASS; var MODALS_WRAPPER_OPEN_CLASS = 'modals-wrapper--open'; var modalUtil = function(element) { var modalOverlay; var modalUrl; var modalsWrapper; function _init() { if (!element) { throw new Error('Modal utility cannot be setup without an element!'); } if (element.classList.contains(MODAL_INITIALIZED_CLASS)) { return false; } ensureModalWrapper(); // param modalTrigger if (!element.dataset.modalTrigger) { throw new Error('Modal utility cannot be setup without a trigger element!'); } else { setupTrigger(); } // param modalCloseable if (element.dataset.modalCloseable !== undefined) { setupCloser(); } // mark as initialized and add modal class for styling element.classList.add(MODAL_INITIALIZED_CLASS, MODAL_CLASS); return { name: MODAL_UTIL_NAME, element: element, destroy: function() {} }; } function ensureModalWrapper() { modalsWrapper = document.querySelector(MODALS_WRAPPER_SELECTOR); if (!modalsWrapper) { // create modal wrapper modalsWrapper = document.createElement('div'); modalsWrapper.classList.add(MODALS_WRAPPER_CLASS); document.body.appendChild(modalsWrapper); } modalOverlay = modalsWrapper.querySelector('.' + MODAL_OVERLAY_CLASS); if (!modalOverlay) { // create modal overlay modalOverlay = document.createElement('div'); modalOverlay.classList.add(MODAL_OVERLAY_CLASS); modalsWrapper.appendChild(modalOverlay); } } function setupTrigger() { var triggerSelector = element.dataset.modalTrigger; if (!triggerSelector.startsWith('#')) { triggerSelector = '#' + triggerSelector; } var triggerElement = document.querySelector(triggerSelector); if (!triggerElement) { throw new Error('Trigger element for Modal not found: "' + triggerSelector + '"'); } triggerElement.classList.add(MODAL_TRIGGER_CLASS); triggerElement.addEventListener('click', onTriggerClicked, false); modalUrl = triggerElement.getAttribute('href'); } function setupCloser() { var closerElement = document.createElement('div'); element.insertBefore(closerElement, null); closerElement.classList.add(MODAL_CLOSER_CLASS); closerElement.addEventListener('click', onCloseClicked, false); modalOverlay.addEventListener('click', onCloseClicked, false); } function onTriggerClicked(event) { event.preventDefault(); open(); } function onCloseClicked(event) { event.preventDefault(); close(); } function onKeyUp(event) { if (event.key === 'Escape') { close(); } } function open() { element.classList.add(MODAL_OPEN_CLASS); modalOverlay.classList.add(MODAL_OVERLAY_OPEN_CLASS); modalsWrapper.classList.add(MODALS_WRAPPER_OPEN_CLASS); modalsWrapper.appendChild(element); console.log({ modalsWrapper }); if (modalUrl) { fillModal(modalUrl); } document.addEventListener('keyup', onKeyUp); } function close() { modalOverlay.classList.remove(MODAL_OVERLAY_OPEN_CLASS); element.classList.remove(MODAL_OPEN_CLASS); modalsWrapper.classList.remove(MODALS_WRAPPER_OPEN_CLASS); document.removeEventListener('keyup', onKeyUp); }; function fillModal(url) { if (!HttpClient) { throw new Error('HttpClient not found! Can\'t fetch modal content from ' + url); } HttpClient.get(url, MODAL_HEADERS) .then(function(response) { response.text().then(processResponse); }); } function processResponse(responseBody) { var responseElement = document.createElement('div'); responseElement.innerHTML = responseBody; var modalContent = document.createElement('div'); modalContent.classList.add(MODAL_CONTENT_CLASS); var contentBody = responseElement.querySelector('.' + MAIN_CONTENT_CLASS); if (contentBody) { modalContent.innerHTML = contentBody.innerHTML; } var previousModalContent = element.querySelector('.' + MODAL_CONTENT_CLASS); if (previousModalContent) { previousModalContent.remove(); } modalContent = withPrefixedInputIDs(modalContent); element.insertBefore(modalContent, null); // setup any newly arrived utils UtilRegistry.setupAll(element); } function withPrefixedInputIDs(modalContent) { var idAttrs = ['id', 'for', 'data-conditional-input']; idAttrs.forEach(function(attr) { Array.from(modalContent.querySelectorAll('[' + attr + ']')).forEach(function(input) { var value = element.id + '__' + input.getAttribute(attr); input.setAttribute(attr, value); }); }); return modalContent; } return _init(); }; if (UtilRegistry) { UtilRegistry.register({ name: MODAL_UTIL_NAME, selector: MODAL_UTIL_SELECTOR, setup: modalUtil }); } })();