diff --git a/l4d2web/static/js/modal.js b/l4d2web/static/js/modal.js index e354ce5..e263719 100644 --- a/l4d2web/static/js/modal.js +++ b/l4d2web/static/js/modal.js @@ -1,27 +1,34 @@ -document.addEventListener("DOMContentLoaded", () => { - document.querySelectorAll("[data-modal-open]").forEach((trigger) => { - trigger.addEventListener("click", (event) => { - const targetId = trigger.getAttribute("data-modal-open"); - const dialog = document.getElementById(targetId); - if (dialog && typeof dialog.showModal === "function") { - event.preventDefault(); - dialog.showModal(); - } - }); - }); +// Event delegation on document so partials swapped in via HTMX (or any +// later DOM mutation) still get modal behaviour without re-binding. The +// previous per-element wiring on DOMContentLoaded silently broke for +// buttons that didn't exist at page load — e.g., the server-detail +// Actions partial reloads its reset/delete triggers on every state +// change, and only the very first ones were ever wired up. - document.querySelectorAll("dialog.modal").forEach((dialog) => { - dialog.querySelectorAll("[data-modal-close]").forEach((closer) => { - closer.addEventListener("click", (event) => { - event.preventDefault(); - dialog.close(); - }); - }); +document.addEventListener("click", (event) => { + const opener = event.target.closest("[data-modal-open]"); + if (opener) { + const dialog = document.getElementById(opener.getAttribute("data-modal-open")); + if (dialog && typeof dialog.showModal === "function") { + event.preventDefault(); + dialog.showModal(); + } + return; + } - dialog.addEventListener("click", (event) => { - if (event.target === dialog) { - dialog.close(); - } - }); - }); + const closer = event.target.closest("[data-modal-close]"); + if (closer) { + const dialog = closer.closest("dialog.modal"); + if (dialog) { + event.preventDefault(); + dialog.close(); + } + return; + } + + // Backdrop click: target IS the dialog (clicks on inner content + // don't bubble up as the dialog itself). + if (event.target.matches && event.target.matches("dialog.modal")) { + event.target.close(); + } });