109 lines
3.1 KiB
JavaScript
109 lines
3.1 KiB
JavaScript
|
/**
|
||
|
* Alert and Confirm modals.
|
||
|
*
|
||
|
* Usage:
|
||
|
*
|
||
|
* modalAlert({message: "Hello world!"}).then(callback);
|
||
|
* modalConfirm({message: "Are you sure?"}).then(callback);
|
||
|
*
|
||
|
* Available options for modalAlert:
|
||
|
* - message
|
||
|
* - title: Alert
|
||
|
*
|
||
|
* Available options for modalConfirm:
|
||
|
* - message
|
||
|
* - title: Confirm
|
||
|
* - buttons: ["Ok", "Cancel"]
|
||
|
* - event (pass `event` for easy inline onclick handlers)
|
||
|
* - element (pass `this` for easy inline onclick handlers)
|
||
|
*
|
||
|
* Example onclick for modalConfirm:
|
||
|
*
|
||
|
* <button onclick="modalConfirm({message: 'Are you sure?', event, element}">Delete</button>
|
||
|
*
|
||
|
* The `element` is used to find the nearest <form> and submit it on OK.
|
||
|
* The `event` is used to cancel the submit button's default.
|
||
|
*/
|
||
|
document.addEventListener('DOMContentLoaded', () => {
|
||
|
const $modal = document.querySelector("#nonshy-alert-modal"),
|
||
|
$ok = $modal.querySelector("button.nonshy-alert-ok-button"),
|
||
|
$cancel = $modal.querySelector("button.nonshy-alert-cancel-button"),
|
||
|
$title = $modal.querySelector("#nonshy-alert-modal-title"),
|
||
|
$body = $modal.querySelector("#nonshy-alert-modal-body"),
|
||
|
cls = 'is-active';
|
||
|
|
||
|
// Current caller's promise.
|
||
|
var currentPromise = null;
|
||
|
|
||
|
const hideModal = () => {
|
||
|
currentPromise = null;
|
||
|
$modal.classList.remove(cls);
|
||
|
};
|
||
|
|
||
|
const showModal = ({
|
||
|
message,
|
||
|
title="Alert",
|
||
|
isConfirm=false,
|
||
|
buttons=["Ok", "Cancel"],
|
||
|
}) => {
|
||
|
$ok.innerHTML = buttons[0];
|
||
|
$cancel.innerHTML = buttons[1];
|
||
|
$cancel.style.display = isConfirm ? "" : "none";
|
||
|
|
||
|
// Strip HTML from message but allow line breaks.
|
||
|
message = message.replace(/</g, "<");
|
||
|
message = message.replace(/>/g, ">");
|
||
|
message = message.replace(/\n/g, "<br>");
|
||
|
|
||
|
$title.innerHTML = title;
|
||
|
$body.innerHTML = message;
|
||
|
|
||
|
// Show the modal.
|
||
|
$modal.classList.add(cls);
|
||
|
|
||
|
// Return as a promise.
|
||
|
return new Promise((resolve, reject) => {
|
||
|
currentPromise = resolve;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// Click events for the modal buttons.
|
||
|
$ok.addEventListener('click', (e) => {
|
||
|
if (currentPromise !== null) {
|
||
|
currentPromise();
|
||
|
}
|
||
|
hideModal();
|
||
|
});
|
||
|
$cancel.addEventListener('click', (e) => {
|
||
|
hideModal();
|
||
|
});
|
||
|
|
||
|
// Key bindings to dismiss the modal.
|
||
|
window.addEventListener('keydown', (e) => {
|
||
|
if ($modal.classList.contains(cls)) {
|
||
|
if (e.key == 'Enter') {
|
||
|
$ok.click();
|
||
|
} else if (e.key == 'Escape') {
|
||
|
$cancel.click();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Exported global functions to invoke the modal.
|
||
|
window.modalAlert = async ({ message, title="Alert" }) => {
|
||
|
return showModal({
|
||
|
message,
|
||
|
title,
|
||
|
isConfirm: false,
|
||
|
});
|
||
|
};
|
||
|
window.modalConfirm = async ({ message, title="Confirm", buttons=["Ok", "Cancel"] }) => {
|
||
|
return showModal({
|
||
|
message,
|
||
|
title,
|
||
|
isConfirm: true,
|
||
|
buttons,
|
||
|
});
|
||
|
};
|
||
|
});
|