tarinai/js/game_dialogs.js
2026-07-15 14:44:29 +09:00

77 lines
3.2 KiB
JavaScript

"use strict";
(function (global) {
const queue = [];
let active = null;
function ensureDialog() {
let dialog = document.getElementById("gameConfirmDialog");
if (dialog) return dialog;
dialog = document.createElement("div");
dialog.id = "gameConfirmDialog";
dialog.className = "field-dialog game-confirm-dialog hidden";
dialog.setAttribute("role", "alertdialog");
dialog.setAttribute("aria-modal", "true");
dialog.setAttribute("aria-labelledby", "gameConfirmDialogTitle");
dialog.setAttribute("aria-describedby", "gameConfirmDialogMessage");
dialog.innerHTML = `
<div class="field-dialog-panel game-confirm-panel">
<h2 id="gameConfirmDialogTitle"></h2>
<p id="gameConfirmDialogMessage" class="field-dialog-lead game-confirm-message"></p>
<div class="field-dialog-actions game-confirm-actions">
<button class="btn" data-game-dialog-cancel type="button"></button>
<button class="btn primary" data-game-dialog-confirm type="button"></button>
</div>
</div>`;
document.body.appendChild(dialog);
dialog.addEventListener("click", event => {
if (!active) return;
if (event.target === dialog || event.target.closest("[data-game-dialog-cancel]")) settle(false);
else if (event.target.closest("[data-game-dialog-confirm]")) settle(true);
});
document.addEventListener("keydown", event => {
if (!active || dialog.classList.contains("hidden")) return;
if (event.key === "Escape") { event.preventDefault(); event.stopImmediatePropagation?.(); settle(false); }
}, true);
return dialog;
}
function pump() {
if (active || !queue.length) return;
active = queue.shift();
const dialog = ensureDialog();
const title = dialog.querySelector("#gameConfirmDialogTitle");
const message = dialog.querySelector("#gameConfirmDialogMessage");
const confirmButton = dialog.querySelector("[data-game-dialog-confirm]");
const cancelButton = dialog.querySelector("[data-game-dialog-cancel]");
if (title) title.textContent = active.options.title || "\u78ba\u8a8d";
if (message) message.textContent = active.options.message || "";
if (confirmButton) {
confirmButton.textContent = active.options.confirmText || "\u5b9f\u884c";
confirmButton.classList.toggle("danger", Boolean(active.options.danger));
confirmButton.classList.toggle("primary", !active.options.danger);
}
if (cancelButton) cancelButton.textContent = active.options.cancelText || "\u30ad\u30e3\u30f3\u30bb\u30eb";
dialog.classList.remove("hidden");
global.setTimeout(() => confirmButton?.focus?.(), 0);
}
function settle(accepted) {
if (!active) return;
const current = active;
active = null;
document.getElementById("gameConfirmDialog")?.classList.add("hidden");
current.restoreFocus?.focus?.();
current.resolve(Boolean(accepted));
global.setTimeout(pump, 0);
}
function confirm(options = {}) {
return new Promise(resolve => {
queue.push({ options: { ...options }, resolve, restoreFocus: document.activeElement || null });
pump();
});
}
global.TarinaiGameDialogs = Object.freeze({ confirm });
})(typeof window !== "undefined" ? window : globalThis);