ulogger-server/js/modal.js
2019-05-22 15:41:39 +02:00

127 lines
3.4 KiB
JavaScript

import { lang } from './constants.js';
/**
* @typedef {Object} ModalResult
* @property {boolean} cancelled Was dialog cancelled
* @property {string} [action] Click action name
* @property {Object} [data] Additional data
*/
/**
* @callback ModalCallback
* @param {ModalResult} result
*/
export default class uModal {
/**
* Builds modal dialog
* Positive click handlers bound to elements with class 'button-resolve'.
* Negative click handlers bound to elements with class 'button-reject'.
* Optional attribute 'data-action' value is returned in {@link ModalResult.action}
* @param {(string|Node|NodeList|Array.<Node>)} content
*/
constructor(content) {
const modal = document.createElement('div');
modal.setAttribute('id', 'modal');
const modalHeader = document.createElement('div');
modalHeader.setAttribute('id', 'modal-header');
const buttonClose = document.createElement('button');
buttonClose.setAttribute('id', 'modal-close');
buttonClose.setAttribute('type', 'button');
buttonClose.setAttribute('class', 'button-reject');
const img = document.createElement('img');
img.setAttribute('src', 'images/close.svg');
img.setAttribute('alt', lang.strings['close']);
buttonClose.append(img);
modalHeader.append(buttonClose);
modal.append(modalHeader);
const modalBody = document.createElement('div');
modalBody.setAttribute('id', 'modal-body');
if (typeof content === 'string') {
modalBody.innerHTML = content;
} else if (content instanceof NodeList || content instanceof Array) {
for (const node of content) {
modalBody.append(node);
}
} else {
modalBody.append(content);
}
modal.append(modalBody);
this._modal = modal;
this.visible = false;
}
/**
* @return {HTMLDivElement}
*/
get modal() {
return this._modal;
}
/**
* Show modal dialog
* @returns {Promise<ModalResult>}
*/
show() {
return new Promise((resolve) => {
this.addListeners(resolve);
if (!this.visible) {
document.body.append(this._modal);
}
});
}
/**
* Add listeners
* @param {ModalCallback} resolve callback
*/
addListeners(resolve) {
this._modal.querySelectorAll('.button-resolve').forEach((el) => {
el.addEventListener('click', () => {
uModal.onClick(el, resolve, { cancelled: false, action: el.getAttribute('data-action') });
});
});
this._modal.querySelectorAll('.button-reject').forEach((el) => {
el.addEventListener('click', () => {
uModal.onClick(el, resolve, { cancelled: true });
});
});
}
/**
* On click action
* Handles optional confirmation dialog
* @param {Element} el Clicked element
* @param {ModalCallback} resolve callback
* @param {ModalResult} result
*/
static onClick(el, resolve, result) {
const confirm = el.getAttribute('data-confirm');
let proceed = true;
if (confirm) {
proceed = this.isConfirmed(confirm);
}
if (proceed) {
resolve(result);
}
}
/**
* Show confirmation dialog and return user decision
* @param {string} message
* @return {boolean} True if confirmed, false otherwise
*/
static isConfirmed(message) {
return confirm(message);
}
/**
* Remove modal dialog
*/
hide() {
document.body.removeChild(this._modal);
this.visible = false
}
}