This commit is contained in:
mark committed 2026-09-04 09:43:19 -04:00
1 parent 2fea308b38
commit f5fd8e632d
4 files changed
+91 -18

No files matched your search

+54 -9
View File
@@ -121,26 +121,71 @@
}
});
// Close the modal once a bookmark write has come back and swapped, leaving
// the status line up long enough to be read.
document.body.addEventListener('htmx:afterSwap', function (event) {
markVerses(event.target);
if (event.detail.target && event.detail.target.id === 'bookmark') {
setTimeout(hideModal, 900);
}
var target = event.detail.target;
if (!target) return;
// Close the modal once a bookmark write has come back and swapped, leaving
// the status line up long enough to be read.
if (target.id === 'bookmark') return setTimeout(hideModal, 900);
if (target.id === 'content') land();
});
// A history restore does not go through the request pipeline -- htmx swaps
// the element straight in and fires this instead -- so the work afterSwap
// does has to be repeated here or a page reached by the back button arrives
// with dead verse numbers.
document.body.addEventListener('htmx:historyRestore', function () {
markVerses();
land();
});
// -- startup ------------------------------------------------------------
function hashTarget() {
if (!location.hash) return null;
return document.getElementById(decodeURIComponent(location.hash.slice(1)));
}
// Every scroll here is a correction, not a gesture: the page is meant to
// arrive already in position. So they all say instant.
//
// Saying nothing would not mean instant. The default is "auto", which means
// "whatever scroll-behavior computes to" -- and Bootstrap's Reboot sets
// :root { scroll-behavior: smooth }, so the default animates. Bootstrap
// wraps that in prefers-reduced-motion, which is the right call for the
// chapter nav's own anchors; these are not that.
function jumpTo(el) {
el.scrollIntoView({ block: 'start', behavior: 'instant' });
}
// A worker-composed page is an ordinary document and the browser scrolls to
// the anchor itself. One composed by boot.html is not: it replaced a
// document the browser had already finished with, so the fragment identifier
// has been spent. Repeating it costs nothing in the first case and is what
// makes a link to GEN.html#v1_1 land on the verse in the second.
// makes a link to GEN#v1_1 land on the verse in the second.
function scrollToHash() {
if (!location.hash) return;
var el = document.getElementById(decodeURIComponent(location.hash.slice(1)));
if (el) el.scrollIntoView();
var el = hashTarget();
if (el) jumpTo(el);
}
// Where a swapped-in page should sit before it is ever seen.
//
// htmx does this itself -- scrolling to the anchor a boosted href named, or
// to the top of the target when it named none -- but from the settle
// callback, which is a setTimeout of defaultSettleDelay, 20ms. The browser
// paints the new content at the old scroll offset first, so the jump is
// visible every time. Here it runs in the same task as the swap, before any
// paint, so the page simply appears where it belongs. htmx's own scroll
// still follows and finds nothing left to do.
//
// htmx has already pushed the new URL by this point -- history is updated
// before the swap, not after -- so location.hash is the anchor that was
// asked for.
function land() {
var el = hashTarget();
if (el) jumpTo(el);
else window.scrollTo({ top: 0, behavior: 'instant' });
}
// api/bookmark has no origin server -- it is answered by the worker -- so