/** * This file is part of Haketilo. * * Function: Showing and error/info/confirmation dialog. * * Copyright (C) 2022 Wojtek Kosior * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * As additional permission under GNU GPL version 3 section 7, you * may distribute forms of that code without the copy of the GNU * GPL normally required by section 4, provided you include this * license notice and, in case of non-source distribution, a URL * through which recipients can access the Corresponding Source. * If you modify file(s) with this exception, you may extend this * exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. * * As a special exception to the GPL, any HTML file which merely * makes function calls to this code, and for that purpose * includes it by reference shall be deemed a separate work for * copyright law purposes. If you modify this code, you may extend * this exception to your version of the code, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * I, Wojtek Kosior, thereby promise not to sue for violation of this file's * license. Although I request that you do not make use of this code in a * proprietary program, I am not going to enforce this in court. */ #FROM html/DOM_helpers.js IMPORT clone_template #FROM common/lock.js IMPORT make_lock, lock, try_lock, unlock function make(on_dialog_show, on_dialog_hide) { const dialog_context = clone_template("dialog"); Object.assign(dialog_context, { on_dialog_show, on_dialog_hide, shown: false, queue: 0, lock: make_lock(), callback: null }); for (const [id, val] of [["yes", true], ["no", false], ["ok", undefined]]) { const but = dialog_context[`${id}_but`]; but.haketilo_dialog_result = val; but.addEventListener("click", e => close_dialog(dialog_context, e)); } return dialog_context; } #EXPORT make function close_dialog(dialog_context, event) { if (event && event.target.parentElement.classList.contains("hide")) return; const result = event ? event.target.haketilo_dialog_result : undefined; if (dialog_context.queue > 0) dialog_context.callback(result); } #EXPORT close_dialog AS close async function show_dialog(dialog_context, shown_buts_id, msg) { dialog_context.queue++; if (!dialog_context.shown) { dialog_context.shown = true; dialog_context.on_dialog_show(); } /* * We want the dialog to be ready for calling close() right after * show_dialog() gets called. For this, we want locking to happen * synchronously if possible. If impossible (lock taken), this means dialog * is already open, hence it's also ready for close()'ing. */ if (!try_lock(dialog_context.lock)) await lock(dialog_context.lock); [...dialog_context.msg.childNodes].forEach(n => n.remove()); dialog_context.msg.append(...msg); for (const buts_id of ["ask_buts", "conf_buts"]) { const action = buts_id === shown_buts_id ? "remove" : "add"; dialog_context[buts_id].classList[action]("hide"); } const result = await new Promise(cb => dialog_context.callback = cb); if (--dialog_context.queue == 0) { dialog_context.shown = false; dialog_context.on_dialog_hide(); } unlock(dialog_context.lock); return result; } const error = (ctx, ...msg) => show_dialog(ctx, "conf_buts", msg); #EXPORT error /* info() and error() are the same for now, we might later change that. */ const info = error; #EXPORT info const ask = (ctx, ...msg) => show_dialog(ctx, "ask_buts", msg); #EXPORT ask const loader = (ctx, ...msg) => show_dialog(ctx, null, msg); #EXPORT loader