Merge branch 'modal-migration' into 'master'
Move modal JS to static Closes #304 See merge request !148
This commit is contained in:
commit
7e457c50fa
@ -1019,23 +1019,27 @@ siteLayout' headingOverride widget = do
|
||||
-- JavaScript utils
|
||||
addScript $ StaticR js_utils_alerts_js
|
||||
addScript $ StaticR js_utils_asidenav_js
|
||||
addScript $ StaticR js_utils_asyncForm_js
|
||||
addScript $ StaticR js_utils_asyncTable_js
|
||||
addScript $ StaticR js_utils_checkAll_js
|
||||
addScript $ StaticR js_utils_httpClient_js
|
||||
addScript $ StaticR js_utils_form_js
|
||||
addScript $ StaticR js_utils_inputs_js
|
||||
addScript $ StaticR js_utils_modal_js
|
||||
addScript $ StaticR js_utils_setup_js
|
||||
addScript $ StaticR js_utils_showHide_js
|
||||
addScript $ StaticR js_utils_tabber_js
|
||||
addStylesheet $ StaticR css_utils_alerts_scss
|
||||
addStylesheet $ StaticR css_utils_asidenav_scss
|
||||
addStylesheet $ StaticR css_utils_asyncForm_scss
|
||||
addStylesheet $ StaticR css_utils_form_scss
|
||||
addStylesheet $ StaticR css_utils_inputs_scss
|
||||
addStylesheet $ StaticR css_utils_modal_scss
|
||||
addStylesheet $ StaticR css_utils_showHide_scss
|
||||
addStylesheet $ StaticR css_utils_tabber_scss
|
||||
addStylesheet $ StaticR css_utils_tooltip_scss
|
||||
-- widgets
|
||||
$(widgetFile "default-layout")
|
||||
$(widgetFile "standalone/modal")
|
||||
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
|
||||
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ postAdminTestR = do
|
||||
(FormFailure errs) -> forM_ errs $ addMessage Error . toHtml
|
||||
|
||||
let emailWidget' = [whamlet|
|
||||
<form method=post action=@{AdminTestR} enctype=#{emailEnctype}>
|
||||
<form method=post action=@{AdminTestR} enctype=#{emailEnctype} data-ajax-submit>
|
||||
^{emailWidget}
|
||||
|]
|
||||
|
||||
|
||||
9
static/css/utils/asyncForm.scss
Normal file
9
static/css/utils/asyncForm.scss
Normal file
@ -0,0 +1,9 @@
|
||||
.async-form-response {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.async-form-loading {
|
||||
opacity: 0.1;
|
||||
transition: opacity 800ms ease-in-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -13,6 +13,7 @@
|
||||
color: var(--color-font);
|
||||
padding: 0 65px 0 20px;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
transition:
|
||||
opacity .2s .1s ease-in-out,
|
||||
transform .3s ease-in-out;
|
||||
60
static/js/utils/asyncForm.js
Normal file
60
static/js/utils/asyncForm.js
Normal file
@ -0,0 +1,60 @@
|
||||
(function collonadeClosure() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
var ASYNC_FORM_RESPONSE_CLASS = 'async-form-response';
|
||||
var ASYNC_FORM_LOADING_CLASS = 'async-form-loading';
|
||||
var ASYNC_FORM_MIN_DELAY = 600;
|
||||
|
||||
window.utils.asyncForm = function(formElement, options) {
|
||||
|
||||
var lastRequestTimestamp = 0;
|
||||
|
||||
function setup() {
|
||||
formElement.addEventListener('submit', submitHandler);
|
||||
}
|
||||
|
||||
function processResponse(response) {
|
||||
var responseElement = document.createElement('div');
|
||||
responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS);
|
||||
responseElement.innerHTML = response.content;
|
||||
var parentElement = formElement.parentElement;
|
||||
|
||||
// make sure there is a delay between click and response
|
||||
var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now());
|
||||
setTimeout(function() {
|
||||
parentElement.insertBefore(responseElement, formElement);
|
||||
formElement.remove();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function submitHandler(event) {
|
||||
event.preventDefault();
|
||||
|
||||
formElement.classList.add(ASYNC_FORM_LOADING_CLASS)
|
||||
lastRequestTimestamp = Date.now();
|
||||
|
||||
var url = formElement.getAttribute('action');
|
||||
var headers = { };
|
||||
var body = new FormData(formElement);
|
||||
|
||||
if (options && options.headers) {
|
||||
Object.keys(options.headers).forEach(function(headerKey) {
|
||||
headers[headerKey] = options.headers[headerKey];
|
||||
});
|
||||
}
|
||||
|
||||
window.utils.httpClient.post(url, headers, body)
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
}).then(function(response) {
|
||||
processResponse(response[0])
|
||||
}).catch(function(error) {
|
||||
console.error('could not fetch or process response from ' + url, { error });
|
||||
});
|
||||
}
|
||||
|
||||
setup();
|
||||
};
|
||||
})();
|
||||
@ -139,14 +139,16 @@
|
||||
|
||||
// fetches new sorted table from url with params and replaces contents of current table
|
||||
function updateTableFrom(url, tableOptions) {
|
||||
if (!window.utils.httpClient) {
|
||||
throw new Error('httpClient not found!');
|
||||
}
|
||||
|
||||
tableOptions = tableOptions || {};
|
||||
fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Accept': 'text/html',
|
||||
[shortCircuitHeader]: tableIdent
|
||||
}
|
||||
}).then(function(response) {
|
||||
var headers = {
|
||||
'Accept': 'text/html',
|
||||
[shortCircuitHeader]: tableIdent
|
||||
};
|
||||
window.utils.httpClient.get(url, headers).then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error('Looks like there was a problem fetching ' + url.href + '. Status Code: ' + response.status);
|
||||
}
|
||||
@ -195,6 +197,9 @@
|
||||
Array.from(wrapper.querySelectorAll('form')).forEach(function(form) {
|
||||
window.utils.setup('form', form);
|
||||
});
|
||||
Array.from(wrapper.querySelectorAll('.modal')).forEach(function(modal) {
|
||||
window.utils.setup('modal', modal);
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
@ -3,9 +3,10 @@
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
var JS_INITIALIZED = 'js-initialized';
|
||||
var JS_INITIALIZED = 'js-form-initialized';
|
||||
var SUBMIT_BUTTON_SELECTOR = '[type="submit"]:not([formnovalidate])';
|
||||
var AUTOSUBMIT_BUTTON_SELECTOR = '[type="submit"][data-autosubmit]';
|
||||
var AJAX_SUBMIT_FLAG = 'ajaxSubmit';
|
||||
|
||||
function formValidator(inputs) {
|
||||
var done = true;
|
||||
@ -23,7 +24,6 @@
|
||||
if (form.classList.contains(JS_INITIALIZED)) {
|
||||
return false;
|
||||
}
|
||||
form.classList.add(JS_INITIALIZED);
|
||||
|
||||
// reactive buttons
|
||||
var submitBtn = form.querySelector(SUBMIT_BUTTON_SELECTOR);
|
||||
@ -37,6 +37,13 @@
|
||||
|
||||
// hide autoSubmit submit button
|
||||
window.utils.setup('autoSubmit', form, options);
|
||||
|
||||
// async form
|
||||
if (AJAX_SUBMIT_FLAG in form.dataset) {
|
||||
window.utils.setup('asyncForm', form, options);
|
||||
}
|
||||
|
||||
form.classList.add(JS_INITIALIZED);
|
||||
};
|
||||
|
||||
// registers input-listener for each element in <inputs> (array) and
|
||||
|
||||
32
static/js/utils/httpClient.js
Normal file
32
static/js/utils/httpClient.js
Normal file
@ -0,0 +1,32 @@
|
||||
(function collonadeClosure() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
window.utils.httpClient = (function() {
|
||||
|
||||
function _fetch(url, method, additionalHeaders, body) {
|
||||
var requestOptions = {
|
||||
credentials: 'same-origin',
|
||||
headers: { },
|
||||
method: method,
|
||||
body: body,
|
||||
};
|
||||
|
||||
Object.keys(additionalHeaders).forEach(function(headerKey) {
|
||||
requestOptions.headers[headerKey] = additionalHeaders[headerKey];
|
||||
});
|
||||
|
||||
return fetch(url, requestOptions);
|
||||
}
|
||||
|
||||
return {
|
||||
get: function(url, headers) {
|
||||
return _fetch(url, 'GET', headers);
|
||||
},
|
||||
post: function(url, headers, body) {
|
||||
return _fetch(url, 'POST', headers, body);
|
||||
},
|
||||
}
|
||||
})();
|
||||
})();
|
||||
127
static/js/utils/modal.js
Normal file
127
static/js/utils/modal.js
Normal file
@ -0,0 +1,127 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
var JS_INITIALIZED_CLASS = 'js-modal-initialized';
|
||||
var MODAL_OPEN_CLASS = 'modal--open';
|
||||
var MODAL_TRIGGER_CLASS = 'modal__trigger';
|
||||
var MODAL_CONTENT_CLASS = 'modal__content';
|
||||
var MAIN_CONTENT_CLASS = 'main__content-body'
|
||||
var MODAL_CLOSABLE_FLAG = 'closeable';
|
||||
var MODAL_DYNAMIC_FLAG = 'dynamic';
|
||||
var MODAL_HEADERS = {
|
||||
'Is-Modal': 'True',
|
||||
};
|
||||
var OVERLAY_CLASS = 'modal__overlay';
|
||||
var OVERLAY_OPEN_CLASS = 'modal__overlay--open';
|
||||
var CLOSER_CLASS = 'modal__closer';
|
||||
|
||||
window.utils.modal = function(modalElement, options) {
|
||||
|
||||
if (!modalElement || modalElement.classList.contains(JS_INITIALIZED_CLASS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var overlayElement = document.createElement('div');
|
||||
var closerElement = document.createElement('div');
|
||||
var triggerElement = document.querySelector('#' + modalElement.dataset.trigger);
|
||||
|
||||
function setup() {
|
||||
document.body.insertBefore(modalElement, null);
|
||||
|
||||
setupForm();
|
||||
setupCloser();
|
||||
|
||||
triggerElement.classList.add(MODAL_TRIGGER_CLASS);
|
||||
triggerElement.addEventListener('click', openHandler, false);
|
||||
|
||||
modalElement.classList.add(JS_INITIALIZED_CLASS);
|
||||
}
|
||||
|
||||
function openHandler(event) {
|
||||
event.preventDefault();
|
||||
open();
|
||||
}
|
||||
|
||||
function open() {
|
||||
modalElement.classList.add(MODAL_OPEN_CLASS);
|
||||
overlayElement.classList.add(OVERLAY_CLASS);
|
||||
document.body.insertBefore(overlayElement, modalElement);
|
||||
overlayElement.classList.add(OVERLAY_OPEN_CLASS);
|
||||
|
||||
var modalUrl = triggerElement.getAttribute('href');
|
||||
if (modalUrl && MODAL_DYNAMIC_FLAG in modalElement.dataset) {
|
||||
fillModal(modalUrl);
|
||||
}
|
||||
|
||||
document.addEventListener('keyup', keyupHandler);
|
||||
}
|
||||
|
||||
function closeHandler(event) {
|
||||
event.preventDefault();
|
||||
close();
|
||||
}
|
||||
|
||||
function close() {
|
||||
overlayElement.classList.remove(OVERLAY_OPEN_CLASS);
|
||||
modalElement.classList.remove(MODAL_OPEN_CLASS);
|
||||
|
||||
document.removeEventListener('keyup', keyupHandler);
|
||||
};
|
||||
|
||||
function setupForm() {
|
||||
var form = modalElement.querySelector('form');
|
||||
if (form) {
|
||||
window.utils.setup('form', form, { headers: MODAL_HEADERS });
|
||||
}
|
||||
}
|
||||
|
||||
function setupCloser() {
|
||||
if (MODAL_CLOSABLE_FLAG in modalElement.dataset) {
|
||||
modalElement.insertBefore(closerElement, null);
|
||||
closerElement.classList.add(CLOSER_CLASS);
|
||||
closerElement.addEventListener('click', closeHandler, false);
|
||||
overlayElement.addEventListener('click', closeHandler, false);
|
||||
}
|
||||
}
|
||||
|
||||
function fillModal(url) {
|
||||
if (!window.utils.httpClient) {
|
||||
throw new Error('httpClient not found! Can\' fetch modal content from ' + url);
|
||||
}
|
||||
|
||||
window.utils.httpClient.get(url, MODAL_HEADERS)
|
||||
.then(function(response) {
|
||||
response.text().then(processResponse);
|
||||
});
|
||||
}
|
||||
|
||||
function processResponse(reponseBody) {
|
||||
var modalContent = document.createElement('div');
|
||||
modalContent.classList.add(MODAL_CONTENT_CLASS);
|
||||
modalContent.innerHTML = reponseBody;
|
||||
|
||||
var contentBody = modalContent.querySelector('.' + MAIN_CONTENT_CLASS);
|
||||
|
||||
if (contentBody) {
|
||||
modalContent.innerHTML = contentBody.innerHTML;
|
||||
}
|
||||
|
||||
var previousModalContent = modalElement.querySelector('.' + MODAL_CONTENT_CLASS);
|
||||
if (previousModalContent) {
|
||||
previousModalContent.remove();
|
||||
}
|
||||
modalElement.insertBefore(modalContent, null);
|
||||
setupForm();
|
||||
}
|
||||
|
||||
function keyupHandler(event) {
|
||||
if (event.key === 'Escape') {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
setup();
|
||||
};
|
||||
})();
|
||||
@ -5,9 +5,16 @@
|
||||
|
||||
var registeredSetupListeners = {};
|
||||
|
||||
window.utils.setup = function(utilType, scope, options) {
|
||||
/**
|
||||
* setup function to initiate a util (utilName) on a scope (sope) with options (options).
|
||||
*
|
||||
* Utils need to be defined as property of `window.utils` and need to accept a scope and (optionally) options.
|
||||
* Example: `window.utils.autoSubmit = function(scope, options) { ... };`
|
||||
*/
|
||||
|
||||
if (!utilType || !scope) {
|
||||
window.utils.setup = function(utilName, scope, options) {
|
||||
|
||||
if (!utilName || !scope) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -15,44 +22,44 @@
|
||||
|
||||
var listener = function(event) {
|
||||
|
||||
if (event.detail.targetUtil !== utilType) {
|
||||
if (event.detail.targetUtil !== utilName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.setupFunction) {
|
||||
options.setupFunction(scope, options);
|
||||
} else {
|
||||
var util = window.utils[utilType];
|
||||
var util = window.utils[utilName];
|
||||
if (!util) {
|
||||
throw new Error('"' + utilType + '" is not a known js util');
|
||||
throw new Error('"' + utilName + '" is not a known js util');
|
||||
}
|
||||
|
||||
util(scope, options);
|
||||
}
|
||||
};
|
||||
|
||||
if (registeredSetupListeners[utilType] && !options.singleton) {
|
||||
registeredSetupListeners[utilType].push(listener);
|
||||
if (registeredSetupListeners[utilName] && !options.singleton) {
|
||||
registeredSetupListeners[utilName].push(listener);
|
||||
} else {
|
||||
window.utils.teardown(utilType);
|
||||
registeredSetupListeners[utilType] = [ listener ];
|
||||
window.utils.teardown(utilName);
|
||||
registeredSetupListeners[utilName] = [ listener ];
|
||||
}
|
||||
|
||||
document.addEventListener('setup', listener);
|
||||
|
||||
document.dispatchEvent(new CustomEvent('setup', {
|
||||
detail: { targetUtil: utilType, module: 'none' },
|
||||
detail: { targetUtil: utilName, module: 'none' },
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}));
|
||||
};
|
||||
|
||||
window.utils.teardown = function(utilType) {
|
||||
if (registeredSetupListeners[utilType]) {
|
||||
registeredSetupListeners[utilType].forEach(function(listener) {
|
||||
window.utils.teardown = function(utilName) {
|
||||
if (registeredSetupListeners[utilName]) {
|
||||
registeredSetupListeners[utilName].forEach(function(listener) {
|
||||
document.removeEventListener('setup', listener);
|
||||
});
|
||||
delete registeredSetupListeners[utilType];
|
||||
delete registeredSetupListeners[utilName];
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@ -29,8 +29,8 @@ $if not isModal
|
||||
<!-- actual content -->
|
||||
^{widget}
|
||||
|
||||
<!-- alerts -->
|
||||
^{alerts}
|
||||
<!-- alerts -->
|
||||
^{alerts}
|
||||
|
||||
<!-- footer -->
|
||||
$if not isModal
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
_{MsgHelpIntroduction}
|
||||
|
||||
<form method=post action=@{HelpR} enctype=#{formEnctype} :isModal:data-ajax-submit>
|
||||
<div>_{MsgHelpIntroduction}
|
||||
^{formWidget}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
<!-- only here to be able to include modal using `toWidget` -->
|
||||
@ -1,300 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
window.utils.modal = function(modal) {
|
||||
var overlay = document.createElement('div');
|
||||
var closer = document.createElement('div');
|
||||
var trigger = document.querySelector('#' + modal.dataset.trigger);
|
||||
// var origParent = modal.parentNode;
|
||||
|
||||
function open(event) {
|
||||
if (!modal.classList.contains('js-modal-initialized')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// disable modals for narrow screens
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
modal.classList.add('modal--open');
|
||||
overlay.classList.add('modal__overlay');
|
||||
// document.body.insertBefore(modal, null);
|
||||
document.body.insertBefore(overlay, modal);
|
||||
overlay.classList.add('modal__overlay--open');
|
||||
|
||||
if ('closeable' in modal.dataset) {
|
||||
closer.classList.add('modal__closer');
|
||||
modal.insertBefore(closer, null);
|
||||
closer.addEventListener('click', close, false);
|
||||
overlay.addEventListener('click', close, false);
|
||||
}
|
||||
}
|
||||
|
||||
// you can open this modal via event
|
||||
// example: document.dispatchEvent(new CustomEvent('modal-open', { details: { for: 'modal-[id]' }}))
|
||||
function openOnEvent(event) {
|
||||
if (event.detail.for === modal.getAttribute('id')) {
|
||||
open();
|
||||
}
|
||||
}
|
||||
|
||||
function close(event) {
|
||||
overlay.remove();
|
||||
// origParent.insertBefore(modal, null);
|
||||
modal.classList.remove('modal--open');
|
||||
closer.removeEventListener('click', close, false);
|
||||
};
|
||||
|
||||
function setup() {
|
||||
document.body.insertBefore(modal, null);
|
||||
|
||||
// every modal can be openend via document-wide event, see openOnEvent
|
||||
document.addEventListener('modal-open', openOnEvent, false);
|
||||
|
||||
if ('dynamic' in modal.dataset) {
|
||||
function fetchModal(url, init) {
|
||||
function responseHtml(body) {
|
||||
var modalContent = document.createElement('div');
|
||||
modalContent.innerHTML = body;
|
||||
|
||||
var contentBody = modalContent.querySelector('.main__content-body');
|
||||
var scriptTags = [];
|
||||
if (contentBody) {
|
||||
modalContent.querySelectorAll('script').forEach(function(scriptTag) {
|
||||
var existsAlready = Array.from(document.body.querySelectorAll('script')).some(function(haystack) {
|
||||
if (haystack.text === scriptTag.text && haystack.getAttribute('src') === scriptTag.getAttribute('src')) {
|
||||
scriptTags.push(haystack);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (existsAlready)
|
||||
return;
|
||||
|
||||
var scriptClone = document.createElement('script');
|
||||
if (scriptTag.text)
|
||||
scriptClone.text = scriptTag.text;
|
||||
if (scriptTag.hasAttributes()) {
|
||||
var attrs = scriptTag.attributes;
|
||||
for (var i = attrs.length - 1; i >= 0; i--) {
|
||||
scriptClone.setAttribute(attrs[i].name, attrs[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
document.body.insertBefore(scriptClone, null);
|
||||
scriptTags.push(scriptClone);
|
||||
});
|
||||
|
||||
modalContent.querySelectorAll('style').forEach(function(styleTag) {
|
||||
if (Array.from(document.head.querySelectorAll('style')).some(function(haystack) {
|
||||
return haystack.innerText === styleTag.innerText;
|
||||
})) { return }
|
||||
|
||||
document.head.insertBefore(styleTag, null);
|
||||
});
|
||||
|
||||
modalContent.querySelectorAll('link').forEach(function(linkTag) {
|
||||
if (linkTag.getAttribute('rel') !== 'stylesheet')
|
||||
return;
|
||||
|
||||
if (Array.from(document.head.querySelectorAll('link')).some(function(haystack) {
|
||||
return haystack.getAttribute('href') === linkTag.getAttribute('href');
|
||||
})) { return }
|
||||
|
||||
|
||||
document.head.insertBefore(linkTag, null);
|
||||
});
|
||||
|
||||
var modalAlertsEl = modalContent.querySelector('#alerts');
|
||||
var alertsEl = document.body.querySelector('#alerts');
|
||||
if (alertsEl && modalAlertsEl) {
|
||||
var modalAlerts = Array.from(modalAlertsEl.childNodes);
|
||||
|
||||
modalAlerts.forEach(function(alertEl) {
|
||||
alertsEl.insertBefore(alertEl, alertsEl.querySelector('.alerts__toggler'));
|
||||
});
|
||||
|
||||
if (modalAlerts.length !== 0)
|
||||
document.dispatchEvent(new CustomEvent('setup', { detail: { scope: alertsEl } }));
|
||||
|
||||
contentBody.removeChild(modalAlertsEl);
|
||||
}
|
||||
|
||||
modalContent = contentBody;
|
||||
}
|
||||
modalContent.classList.add('modal__content');
|
||||
|
||||
var nudgeAttr = function(attr, x) {
|
||||
var oldVal = x.getAttribute(attr);
|
||||
var newVal = modal.getAttribute('id') + '__' + oldVal;
|
||||
|
||||
// console.log(oldVal, newVal);
|
||||
x.setAttribute(attr, newVal);
|
||||
};
|
||||
|
||||
var idAttrs = ['id', 'for', 'data-conditional-id'];
|
||||
idAttrs.map(function(attr) {
|
||||
modalContent.querySelectorAll('[' + attr + ']').forEach(function(x) { nudgeAttr(attr, x); });
|
||||
});
|
||||
|
||||
modal.querySelectorAll('.modal__content').forEach(function(prev) { modal.removeChild(prev); });
|
||||
modal.insertBefore(modalContent, null);
|
||||
|
||||
var triggerContentLoad = function() {
|
||||
console.log('contentReady', modal);
|
||||
|
||||
document.dispatchEvent(new CustomEvent('setup', {
|
||||
detail: { scope: modal },
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
}));
|
||||
}
|
||||
|
||||
scriptTags.forEach(function(t) { t.addEventListener('load', triggerContentLoad); });
|
||||
triggerContentLoad();
|
||||
|
||||
return 'html';
|
||||
}
|
||||
|
||||
function responseJson(data) {
|
||||
var alertsEl = document.querySelector('#alerts');
|
||||
if (!alertsEl)
|
||||
return null;
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var alert = document.createElement('div');
|
||||
alert.classList.add('alert', 'alert-' + data[i].class);
|
||||
var alertContent = document.createElement('div');
|
||||
alertContent.classList.add('alert__content');
|
||||
alertContent.innerHTML = data[i].content;
|
||||
alert.appendChild(alertContent);
|
||||
|
||||
alertsEl.insertBefore(alert, alertsEl.querySelector('.alerts__toggler'));
|
||||
}
|
||||
|
||||
document.dispatchEvent(new CustomEvent('setup', { detail: { scope: alertsEl }, bubbles: true, cancelable: true }));
|
||||
|
||||
return 'json';
|
||||
}
|
||||
|
||||
|
||||
return fetch(url, init).then(function(response) {
|
||||
var contentType = response.headers.get('Content-Type')
|
||||
if (contentType && contentType.includes('text/html')) {
|
||||
return response.text().then(responseHtml);
|
||||
} else if (contentType && contentType.includes('application/json')) {
|
||||
return response.json().then(responseJson);
|
||||
} else {
|
||||
console.log(response);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
modal.addEventListener('modal-fetch', function(event) {
|
||||
var dynamicContentURL = (event.detail && event.detail.url) || trigger.getAttribute('href');
|
||||
|
||||
var fetchInit = (event.detail && event.detail.init) || {
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
#{String (toPathPiece HeaderIsModal)}: 'True'
|
||||
}
|
||||
};
|
||||
|
||||
if (dynamicContentURL.length > 0) {
|
||||
fetchModal(dynamicContentURL, fetchInit).then((event.detail && event.detail.then) || (function(){}));
|
||||
}
|
||||
});
|
||||
modal.dispatchEvent(new CustomEvent('modal-fetch', {
|
||||
detail: {
|
||||
then: (function() {
|
||||
if (!trigger)
|
||||
return;
|
||||
|
||||
trigger.classList.add('modal__trigger');
|
||||
trigger.addEventListener('click', open, false);
|
||||
})
|
||||
}
|
||||
}));
|
||||
} else if (trigger) { // if modal has trigger assigned to it open modal on click
|
||||
trigger.classList.add('modal__trigger');
|
||||
trigger.addEventListener('click', open, false);
|
||||
}
|
||||
|
||||
|
||||
// tell further modals, that this one already got initialized
|
||||
modal.classList.add('js-modal-initialized');
|
||||
|
||||
modal.addEventListener('modal-close', close);
|
||||
}
|
||||
|
||||
setup();
|
||||
};
|
||||
|
||||
window.utils.ajaxSubmit = function(modal, form) {
|
||||
function doSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var modalContent = modal.querySelector('.modal__content');
|
||||
modalContent.style.pointerEvents = 'none';
|
||||
modalContent.style.opacity = 0.5;
|
||||
|
||||
modal.dispatchEvent(new CustomEvent('modal-fetch', {
|
||||
detail: {
|
||||
url: form.target,
|
||||
init: {
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
#{String (toPathPiece HeaderIsModal)}: 'True'
|
||||
},
|
||||
method: form.method,
|
||||
body: new FormData(form)
|
||||
},
|
||||
then: (function(typ) {
|
||||
modal.dispatchEvent(new CustomEvent('modal-close'));
|
||||
|
||||
modalContent.style.pointerEvents = 'auto';
|
||||
modalContent.style.opacity = 1;
|
||||
|
||||
if (typ === 'json') {
|
||||
modal.dispatchEvent(new CustomEvent('modal-fetch'));
|
||||
}
|
||||
})
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
}));
|
||||
};
|
||||
|
||||
form.addEventListener('submit', doSubmit);
|
||||
form.classList.add('js-ajax-initialized');
|
||||
};
|
||||
})();
|
||||
|
||||
document.addEventListener('setup', function(e) {
|
||||
if (e.detail.module && e.detail.module !== 'modal')
|
||||
return;
|
||||
|
||||
Array.from(e.detail.scope.querySelectorAll('.js-modal:not(.js-modal-initialized)')).forEach(function(modal) {
|
||||
window.utils.modal(modal);
|
||||
});
|
||||
|
||||
if (e.detail.scope.classList.contains('js-modal')) {
|
||||
Array.from(e.detail.scope.querySelectorAll('form[data-ajax-submit]:not(.js-ajax-initialized)')).forEach(function(form) {
|
||||
window.utils.ajaxSubmit(e.detail.scope, form);
|
||||
});
|
||||
} else {
|
||||
Array.from(e.detail.scope.querySelectorAll('.js-modal')).map(function(modal) {
|
||||
Array.from(modal.querySelectorAll('form[data-ajax-submit]:not(.js-ajax-initialized)')).forEach(function(form) {
|
||||
window.utils.ajaxSubmit(modal, form);
|
||||
});
|
||||
});
|
||||
};
|
||||
}, false);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.dispatchEvent(new CustomEvent('setup', { detail: { scope: document.body, module: 'modal' }, bubbles: true, cancelable: true }))
|
||||
});
|
||||
7
templates/widgets/modal/modal.julius
Normal file
7
templates/widgets/modal/modal.julius
Normal file
@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// TODO: replace for loop with one precise query for this specific modal instance
|
||||
var modalElements = Array.from(document.querySelectorAll('.modal'));
|
||||
modalElements.forEach(function(modal) {
|
||||
window.utils.setup('modal', modal);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user