feat(modals): click intercept + openModal + fetchAndShow
a[data-modal] clicks push ?modal=<path> to URL and trigger htmx.ajax into #modal-content with the HX-Modal header. window.openModal exposed for non-<a> trigger sites (files-overlay row clicks). Race guard via currentModalPath token. Close/popstate/bootstrap follow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8df130a607
commit
bc8edbcd50
1 changed files with 48 additions and 3 deletions
|
|
@ -1,6 +1,51 @@
|
|||
// URL-addressable modal router (see docs/superpowers/specs/2026-05-17-url-addressable-modals-design.md).
|
||||
// Implementation lands in subsequent tasks; this stub keeps base.html's
|
||||
// script include from 404'ing during the staged rollout.
|
||||
// URL-addressable modal router (see spec 2026-05-17-url-addressable-modals).
|
||||
// Click intercept on a[data-modal] → ?modal=<path> in URL → htmx swap into
|
||||
// #modal-content → showModal(). Close/popstate/bootstrap in later tasks.
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
let currentModalPath = null; // race-guard against stale swaps
|
||||
|
||||
function openModal(path) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("modal", path);
|
||||
history.pushState({ modal: path }, "", url.toString());
|
||||
fetchAndShow(path);
|
||||
}
|
||||
|
||||
function fetchAndShow(path) {
|
||||
currentModalPath = path;
|
||||
if (typeof window.htmx === "undefined") {
|
||||
console.error("[modal-router] htmx not loaded; cannot fetch modal");
|
||||
return;
|
||||
}
|
||||
window.htmx.ajax("GET", path, {
|
||||
target: "#modal-content",
|
||||
swap: "innerHTML",
|
||||
headers: { "HX-Modal": "1" },
|
||||
}).then(() => {
|
||||
// Race guard: if the user clicked again during the fetch, abandon
|
||||
// this swap; the newer click will win.
|
||||
if (currentModalPath !== path) return;
|
||||
const dlg = document.getElementById("modal-container");
|
||||
if (dlg && !dlg.open) dlg.showModal();
|
||||
}).catch((err) => {
|
||||
console.error("[modal-router] fetch failed", err);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
const link = event.target.closest("a[data-modal]");
|
||||
if (!link) return;
|
||||
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
||||
if (event.button !== 0) return;
|
||||
const href = link.getAttribute("href");
|
||||
if (!href) return;
|
||||
event.preventDefault();
|
||||
openModal(href);
|
||||
});
|
||||
|
||||
// Public API — used by files-overlay.js to open the editor from row clicks
|
||||
// that aren't a literal <a data-modal> (existing event delegation).
|
||||
window.openModal = openModal;
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in a new issue