212 lines
6.1 KiB
JavaScript
212 lines
6.1 KiB
JavaScript
(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:
|
|
* <div uw-modal data-modal-trigger='#trigger' data-modal-closeable>This is the modal content
|
|
* <div id='trigger'>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 modalsWrapper;
|
|
var modalOverlay;
|
|
var modalUrl;
|
|
|
|
function _init() {
|
|
console.log('modalUtil.init', { element });
|
|
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);
|
|
|
|
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: url,
|
|
headers: MODAL_HEADERS,
|
|
accept: HttpClient.ACCEPT.TEXT_HTML,
|
|
}).then(function(response) {
|
|
return HtmlHelpers.parseResponse(response, element.id);
|
|
}).then(processResponse);
|
|
}
|
|
|
|
function processResponse(responseElement) {
|
|
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();
|
|
}
|
|
|
|
element.insertBefore(modalContent, null);
|
|
|
|
// setup any newly arrived utils
|
|
UtilRegistry.setupAll(element);
|
|
}
|
|
|
|
return _init();
|
|
};
|
|
|
|
if (UtilRegistry) {
|
|
UtilRegistry.register({
|
|
name: MODAL_UTIL_NAME,
|
|
selector: MODAL_UTIL_SELECTOR,
|
|
setup: modalUtil
|
|
});
|
|
}
|
|
})();
|