This repository has been archived on 2024-10-24. You can view files and clone it, but cannot push or open issues or pull requests.
fradrive-old/frontend/src/utils/modal/modal.js
2019-12-18 11:47:25 +01:00

183 lines
5.1 KiB
JavaScript

import { Utility } from '../../core/utility';
import './modal.sass';
const MODAL_HEADERS = {
'Is-Modal': 'True',
};
const MODAL_INITIALIZED_CLASS = 'modal--initialized';
const MODAL_CLASS = 'modal';
const MODAL_OPEN_CLASS = 'modal--open';
const MODAL_TRIGGER_CLASS = 'modal__trigger';
const MODAL_CONTENT_CLASS = 'modal__content';
const MODAL_OVERLAY_CLASS = 'modal__overlay';
const MODAL_OVERLAY_OPEN_CLASS = 'modal__overlay--open';
const MODAL_CLOSER_CLASS = 'modal__closer';
const 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
const MODALS_WRAPPER_CLASS = 'modals-wrapper';
const MODALS_WRAPPER_SELECTOR = '.' + MODALS_WRAPPER_CLASS;
const MODALS_WRAPPER_OPEN_CLASS = 'modals-wrapper--open';
@Utility({
selector: '[uw-modal]',
})
export class Modal {
_element;
_app;
_modalsWrapper;
_modalOverlay;
_modalUrl;
constructor(element, app) {
if (!element) {
throw new Error('Modal utility cannot be setup without an element!');
}
this._element = element;
this._app = app;
if (this._element.classList.contains(MODAL_INITIALIZED_CLASS)) {
return false;
}
this._ensureModalWrapper();
// param modalTrigger
if (!this._element.dataset.modalTrigger) {
throw new Error('Modal utility cannot be setup without a trigger element!');
} else {
this._setupTrigger();
}
// param modalCloseable
if (this._element.dataset.modalCloseable !== undefined) {
this._setupCloser();
}
// mark as initialized and add modal class for styling
this._element.classList.add(MODAL_INITIALIZED_CLASS, MODAL_CLASS);
}
destroy() {
// TODO
}
_ensureModalWrapper() {
this._modalsWrapper = document.querySelector(MODALS_WRAPPER_SELECTOR);
if (!this._modalsWrapper) {
// create modal wrapper
this._modalsWrapper = document.createElement('div');
this._modalsWrapper.classList.add(MODALS_WRAPPER_CLASS);
document.body.appendChild(this._modalsWrapper);
}
this._modalOverlay = this._modalsWrapper.querySelector('.' + MODAL_OVERLAY_CLASS);
if (!this._modalOverlay) {
// create modal overlay
this._modalOverlay = document.createElement('div');
this._modalOverlay.classList.add(MODAL_OVERLAY_CLASS);
this._modalsWrapper.appendChild(this._modalOverlay);
}
}
_setupTrigger() {
let triggerSelector = this._element.dataset.modalTrigger;
if (!triggerSelector.startsWith('#')) {
triggerSelector = '#' + triggerSelector;
}
const 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', this._onTriggerClicked, false);
this._modalUrl = triggerElement.getAttribute('href');
}
_setupCloser() {
const closerElement = document.createElement('div');
this._element.insertBefore(closerElement, null);
closerElement.classList.add(MODAL_CLOSER_CLASS);
closerElement.addEventListener('click', this._onCloseClicked, false);
this._modalOverlay.addEventListener('click', this._onCloseClicked, false);
}
_onTriggerClicked = (event) => {
event.preventDefault();
this._open();
}
_onCloseClicked = (event) => {
event.preventDefault();
this._close();
}
_onKeyUp = (event) => {
if (event.key === 'Escape') {
this._close();
}
}
_open() {
this._element.classList.add(MODAL_OPEN_CLASS);
this._modalOverlay.classList.add(MODAL_OVERLAY_OPEN_CLASS);
this._modalsWrapper.classList.add(MODALS_WRAPPER_OPEN_CLASS);
this._modalsWrapper.appendChild(this._element);
if (this._modalUrl) {
this._fillModal(this._modalUrl);
}
document.addEventListener('keyup', this._onKeyUp);
}
_close() {
this._modalOverlay.classList.remove(MODAL_OVERLAY_OPEN_CLASS);
this._element.classList.remove(MODAL_OPEN_CLASS);
this._modalsWrapper.classList.remove(MODALS_WRAPPER_OPEN_CLASS);
document.removeEventListener('keyup', this._onKeyUp);
};
_fillModal(url) {
this._app.httpClient.get({
url: url,
headers: MODAL_HEADERS,
}).then(
(response) => this._app.htmlHelpers.parseResponse(response)
).then(
(response) => this._processResponse(response.element)
);
}
_processResponse(responseElement) {
const modalContent = document.createElement('div');
modalContent.classList.add(MODAL_CONTENT_CLASS);
const contentBody = responseElement.querySelector('.' + MAIN_CONTENT_CLASS);
if (contentBody) {
modalContent.innerHTML = contentBody.innerHTML;
}
const previousModalContent = this._element.querySelector('.' + MODAL_CONTENT_CLASS);
if (previousModalContent) {
previousModalContent.remove();
}
this._element.insertBefore(modalContent, null);
// setup any newly arrived utils
this._app.utilRegistry.setupAll(this._element);
}
}