72 lines
3.7 KiB
JavaScript
72 lines
3.7 KiB
JavaScript
/*
|
||
* Copyright (C) 2026 Mateusz Gruszczyński @linuxiarz.pl
|
||
* Source-Available Code / Dual-Licensed.
|
||
*
|
||
* Free for non-commercial and evaluation use under terms of BSL/GPLv3.
|
||
* Commercial or production use requires a valid paid license.
|
||
* See LICENSE file in repository root for details.
|
||
*/
|
||
|
||
function ensureDialog() {
|
||
let dialog = document.querySelector("#system-dialog");
|
||
if (dialog) return dialog;
|
||
dialog = document.createElement("dialog");
|
||
dialog.id = "system-dialog";
|
||
dialog.className = "app-dialog";
|
||
dialog.innerHTML = `<form method="dialog" class="dialog-panel system-dialog-panel">
|
||
<button class="modal-close" value="cancel" aria-label="Close dialog">×</button>
|
||
<h2 data-title></h2><p class="dialog-copy" data-message></p>
|
||
<label data-input-wrap hidden><span data-input-label></span><input data-input name="modal-input" data-bwignore="true"></label>
|
||
<div class="dialog-actions"><button class="secondary-button" value="cancel" data-cancel>Cancel</button><button class="primary-button" value="confirm" data-confirm>OK</button></div>
|
||
</form>`;
|
||
document.body.append(dialog);
|
||
dialog.addEventListener("click", event => { if (event.target === dialog) dialog.close("cancel"); });
|
||
return dialog;
|
||
}
|
||
|
||
export function showMessage(message, { title = "Information", button = "OK" } = {}) {
|
||
const dialog = ensureDialog();
|
||
dialog.querySelector("[data-title]").textContent = title;
|
||
dialog.querySelector("[data-message]").textContent = message;
|
||
dialog.querySelector("[data-input-wrap]").hidden = true;
|
||
dialog.querySelector("[data-cancel]").hidden = true;
|
||
dialog.querySelector("[data-confirm]").textContent = button;
|
||
dialog.showModal();
|
||
return new Promise(resolve => dialog.addEventListener("close", () => resolve(), { once: true }));
|
||
}
|
||
|
||
export function askConfirm(message, { title = "Confirm", confirmText = "Confirm", danger = false } = {}) {
|
||
const dialog = ensureDialog();
|
||
dialog.querySelector("[data-title]").textContent = title;
|
||
dialog.querySelector("[data-message]").textContent = message;
|
||
dialog.querySelector("[data-input-wrap]").hidden = true;
|
||
dialog.querySelector("[data-cancel]").hidden = false;
|
||
const confirm = dialog.querySelector("[data-confirm]");
|
||
confirm.textContent = confirmText;
|
||
confirm.classList.toggle("danger-button", danger);
|
||
dialog.showModal();
|
||
return new Promise(resolve => dialog.addEventListener("close", () => {
|
||
confirm.classList.remove("danger-button");
|
||
resolve(dialog.returnValue === "confirm");
|
||
}, { once: true }));
|
||
}
|
||
|
||
export function askInput({ title, message = "", label, type = "text", autocomplete = "off", minLength, placeholder = "", confirmText = "Continue", bitwardenIgnore = false }) {
|
||
const dialog = ensureDialog();
|
||
dialog.querySelector("[data-title]").textContent = title;
|
||
dialog.querySelector("[data-message]").textContent = message;
|
||
const wrap = dialog.querySelector("[data-input-wrap]");
|
||
const input = dialog.querySelector("[data-input]");
|
||
wrap.hidden = false;
|
||
dialog.querySelector("[data-input-label]").textContent = label;
|
||
input.type = type; input.value = ""; input.autocomplete = autocomplete; input.placeholder = placeholder;
|
||
input.name = type === "password" ? "new-password" : type === "email" ? "email" : "modal-input";
|
||
if (bitwardenIgnore) input.setAttribute("data-bwignore", "true"); else input.removeAttribute("data-bwignore");
|
||
input.minLength = minLength || 0;
|
||
dialog.querySelector("[data-cancel]").hidden = false;
|
||
dialog.querySelector("[data-confirm]").textContent = confirmText;
|
||
dialog.showModal();
|
||
queueMicrotask(() => input.focus());
|
||
return new Promise(resolve => dialog.addEventListener("close", () => resolve(dialog.returnValue === "confirm" ? input.value : null), { once: true }));
|
||
}
|