breakout71/src/asyncAlert.ts

151 lines
3.8 KiB
TypeScript
Raw Normal View History

2025-03-16 17:45:29 +01:00
import { t } from "./i18n/i18n";
export let alertsOpen = 0,
2025-03-16 17:45:29 +01:00
closeModal: null | (() => void) = null;
export type AsyncAlertAction<t> = {
2025-03-16 17:45:29 +01:00
text?: string;
value?: t;
help?: string;
disabled?: boolean;
icon?: string;
className?: string;
};
2025-03-20 18:44:46 +01:00
const popupWrap = document.getElementById("popup") as HTMLDivElement;
const closeModaleButton = document.getElementById(
"close-modale",
) as HTMLButtonElement;
closeModaleButton.addEventListener("click", (e) => {
e.preventDefault();
if (closeModal) closeModal();
});
closeModaleButton.title = t("play.close_modale_window_tooltip");
let lastClickedItemIndex = -1;
export async function asyncAlert<t>({
2025-03-16 17:45:29 +01:00
title,
text,
actions,
allowClose = true,
textAfterButtons = "",
actionsAsGrid = false,
}: {
title?: string;
text?: string;
actions?: AsyncAlertAction<t>[];
textAfterButtons?: string;
allowClose?: boolean;
actionsAsGrid?: boolean;
}): Promise<t | void> {
2025-03-20 18:44:46 +01:00
updateAlertsOpen(+1);
2025-03-16 17:45:29 +01:00
return new Promise((resolve) => {
2025-03-20 18:44:46 +01:00
popupWrap.className = actionsAsGrid ? " " : "";
closeModaleButton.style.display = allowClose ? "" : "none";
2025-03-20 18:44:46 +01:00
const popup = document.createElement("div");
2025-03-20 21:02:51 +01:00
let closed = false;
2025-03-16 17:45:29 +01:00
function closeWithResult(value: t | undefined) {
2025-03-20 21:02:51 +01:00
if (closed) return;
closed = true;
2025-03-20 22:50:50 +01:00
Array.prototype.forEach.call(
popup.querySelectorAll("button:not([disabled])"),
(b) => (b.disabled = true),
);
2025-03-20 18:44:46 +01:00
document.body.style.minHeight = document.body.scrollHeight + "px";
2025-03-20 22:50:50 +01:00
setTimeout(() => (document.body.style.minHeight = ""), 0);
2025-03-20 18:44:46 +01:00
popup.remove();
2025-03-16 17:45:29 +01:00
resolve(value);
}
2025-03-16 17:45:29 +01:00
if (allowClose) {
closeModal = () => {
closeWithResult(undefined);
};
2025-03-20 18:44:46 +01:00
} else {
closeModal = null;
2025-03-16 17:45:29 +01:00
}
2025-03-16 17:45:29 +01:00
if (title) {
const p = document.createElement("h2");
p.innerHTML = title;
popup.appendChild(p);
}
2025-03-16 17:45:29 +01:00
if (text) {
const p = document.createElement("div");
p.innerHTML = text;
popup.appendChild(p);
}
2025-03-16 17:45:29 +01:00
const buttons = document.createElement("section");
2025-03-20 18:44:46 +01:00
buttons.className = "actions";
2025-03-16 17:45:29 +01:00
popup.appendChild(buttons);
2025-03-16 17:45:29 +01:00
actions
?.filter((i) => i)
2025-03-20 18:44:46 +01:00
.forEach(
({ text, value, help, disabled, className = "", icon = "" }, index) => {
const button = document.createElement("button");
2025-03-20 18:44:46 +01:00
button.innerHTML = `
${icon}
<div>
<strong>${text}</strong>
<em>${help || ""}</em>
</div>`;
2025-03-20 18:44:46 +01:00
if (disabled) {
button.setAttribute("disabled", "disabled");
} else {
button.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
closeWithResult(value);
// Focus "same" button if it's still there
lastClickedItemIndex = index;
});
}
2025-03-16 17:45:29 +01:00
2025-03-20 18:44:46 +01:00
button.className =
className + (lastClickedItemIndex === index ? " needs-focus" : "");
buttons.appendChild(button);
},
);
2025-03-16 17:45:29 +01:00
if (textAfterButtons) {
const p = document.createElement("div");
p.className = "textAfterButtons";
p.innerHTML = textAfterButtons;
popup.appendChild(p);
}
2025-03-16 17:45:29 +01:00
popupWrap.appendChild(popup);
(
2025-03-20 18:44:46 +01:00
popupWrap.querySelector(
`section.actions > button.needs-focus`,
) as HTMLButtonElement
2025-03-16 17:45:29 +01:00
)?.focus();
2025-03-20 18:44:46 +01:00
lastClickedItemIndex = -1;
2025-03-16 17:45:29 +01:00
}).then(
(v: unknown) => {
2025-03-20 18:44:46 +01:00
updateAlertsOpen(-1);
2025-03-16 17:45:29 +01:00
closeModal = null;
return v as t | undefined;
},
() => {
closeModal = null;
2025-03-20 18:44:46 +01:00
updateAlertsOpen(-1);
2025-03-16 17:45:29 +01:00
},
);
}
2025-03-20 18:44:46 +01:00
function updateAlertsOpen(delta: number) {
alertsOpen += delta;
if (alertsOpen > 1) {
2025-03-20 21:02:51 +01:00
alert("Two alerts where opened at once");
2025-03-20 18:44:46 +01:00
}
document.body.classList[alertsOpen ? "add" : "remove"]("has-alert-open");
}