182 lines
5.5 KiB
JavaScript
182 lines
5.5 KiB
JavaScript
import { t } from "./i18n.js";
|
|
import { toast } from "./dom.js";
|
|
import { escapeHtml } from "./ui-utils.js";
|
|
|
|
export function openLightbox(url, title) {
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "lightbox";
|
|
const safeTitle = escapeHtml(title || "");
|
|
overlay.innerHTML = `
|
|
<div class="lightbox-content">
|
|
<button class="lightbox-close" aria-label="${t("lightbox.close")}">✕</button>
|
|
<img src="${url}" alt="${safeTitle}" />
|
|
<p>${safeTitle}</p>
|
|
</div>
|
|
`;
|
|
overlay.addEventListener("click", (e) => {
|
|
if (
|
|
e.target.classList.contains("lightbox") ||
|
|
e.target.classList.contains("lightbox-close")
|
|
) {
|
|
overlay.remove();
|
|
}
|
|
});
|
|
document.body.appendChild(overlay);
|
|
}
|
|
|
|
export function openConfirmModal({
|
|
title,
|
|
body,
|
|
confirmLabel,
|
|
cancelLabel = t("modal.cancel"),
|
|
onConfirm,
|
|
}) {
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "edit-modal";
|
|
const panel = document.createElement("div");
|
|
panel.className = "edit-panel";
|
|
panel.innerHTML = `
|
|
<div class="edit-header">
|
|
<h3>${title}</h3>
|
|
<button class="lightbox-close" aria-label="${t("modal.close")}">x</button>
|
|
</div>
|
|
<div class="edit-body">
|
|
<p>${body}</p>
|
|
</div>
|
|
`;
|
|
const close = () => overlay.remove();
|
|
const actions = document.createElement("div");
|
|
actions.className = "stack horizontal";
|
|
const confirmBtn = document.createElement("button");
|
|
confirmBtn.textContent = confirmLabel ?? t("modal.confirm");
|
|
actions.append(confirmBtn);
|
|
if (cancelLabel !== null && cancelLabel !== undefined) {
|
|
const cancelBtn = document.createElement("button");
|
|
cancelBtn.className = "ghost";
|
|
cancelBtn.type = "button";
|
|
cancelBtn.textContent = cancelLabel;
|
|
actions.append(cancelBtn);
|
|
cancelBtn.addEventListener("click", close);
|
|
}
|
|
panel.querySelector(".edit-body")?.appendChild(actions);
|
|
|
|
overlay.addEventListener("click", (e) => {
|
|
if (
|
|
e.target.classList.contains("edit-modal") ||
|
|
e.target.classList.contains("lightbox-close")
|
|
) {
|
|
close();
|
|
}
|
|
});
|
|
confirmBtn.addEventListener("click", async () => {
|
|
try {
|
|
await onConfirm?.(close);
|
|
} catch (err) {
|
|
toast(err.message, true);
|
|
}
|
|
});
|
|
|
|
overlay.appendChild(panel);
|
|
document.body.appendChild(overlay);
|
|
}
|
|
|
|
export function openPasswordConfirmModal({
|
|
title,
|
|
body,
|
|
confirmLabel,
|
|
cancelLabel = t("modal.cancel"),
|
|
onConfirm,
|
|
}) {
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "edit-modal";
|
|
const panel = document.createElement("div");
|
|
panel.className = "edit-panel";
|
|
panel.innerHTML = `
|
|
<div class="edit-header">
|
|
<h3>${title}</h3>
|
|
<button class="lightbox-close" aria-label="${t("modal.close")}">x</button>
|
|
</div>
|
|
<div class="edit-body">
|
|
<p>${body}</p>
|
|
</div>
|
|
`;
|
|
|
|
const close = () => overlay.remove();
|
|
const bodyWrap = panel.querySelector(".edit-body");
|
|
const fieldWrap = document.createElement("label");
|
|
fieldWrap.className = "stack";
|
|
fieldWrap.innerHTML = `
|
|
<span class="label">${t("admin.passwordLabel")}</span>
|
|
<input type="password" autocomplete="current-password" />
|
|
`;
|
|
bodyWrap?.appendChild(fieldWrap);
|
|
const passwordInput = fieldWrap.querySelector("input");
|
|
|
|
const actions = document.createElement("div");
|
|
actions.className = "stack horizontal";
|
|
const confirmBtn = document.createElement("button");
|
|
confirmBtn.className = "danger";
|
|
confirmBtn.textContent = confirmLabel ?? t("modal.confirm");
|
|
actions.append(confirmBtn);
|
|
|
|
if (cancelLabel !== null && cancelLabel !== undefined) {
|
|
const cancelBtn = document.createElement("button");
|
|
cancelBtn.className = "ghost";
|
|
cancelBtn.type = "button";
|
|
cancelBtn.textContent = cancelLabel;
|
|
actions.append(cancelBtn);
|
|
cancelBtn.addEventListener("click", close);
|
|
}
|
|
bodyWrap?.appendChild(actions);
|
|
|
|
overlay.addEventListener("click", (e) => {
|
|
if (
|
|
e.target.classList.contains("edit-modal") ||
|
|
e.target.classList.contains("lightbox-close")
|
|
) {
|
|
close();
|
|
}
|
|
});
|
|
|
|
confirmBtn.addEventListener("click", async () => {
|
|
const password = passwordInput?.value ?? "";
|
|
if (!password.trim()) {
|
|
toast(t("admin.passwordRequired"), true);
|
|
passwordInput?.focus();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await onConfirm?.(password, close);
|
|
} catch (err) {
|
|
toast(err.message, true);
|
|
}
|
|
});
|
|
|
|
overlay.appendChild(panel);
|
|
document.body.appendChild(overlay);
|
|
passwordInput?.focus();
|
|
}
|
|
|
|
export function openResultsRelockModal() {
|
|
openConfirmModal({
|
|
title: t("results.relockedTitle"),
|
|
body: t("results.relockedBody"),
|
|
confirmLabel: t("results.relockedConfirm"),
|
|
cancelLabel: null,
|
|
onConfirm: (close) => close(),
|
|
});
|
|
}
|
|
|
|
export function openSuggestionsChangedModal(names) {
|
|
const uniq = Array.from(new Set(names)).filter(Boolean);
|
|
if (uniq.length === 0) return;
|
|
openConfirmModal({
|
|
title: t("vote.listUpdatedTitle"),
|
|
body: t("vote.listUpdatedBody", { names: uniq.join(", ") }),
|
|
confirmLabel: t("vote.listUpdatedConfirm"),
|
|
cancelLabel: null,
|
|
onConfirm: (close) => close(),
|
|
});
|
|
}
|