127 lines
3.4 KiB
JavaScript
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
|
|
}
|
|
}
|