This commit is contained in:
mark committed 2026-09-08 08:02:21 -04:00
1 parent f041daeda3
commit 9407c26d2d
6 files changed
+301 -33

No files matched your search

+26 -21
View File
@@ -83,6 +83,11 @@ const LIBRARY = [];
const SHELL_CACHE = 'bible-shell-' + VERSION;
const LIBRARY_CACHE = 'bible-library-' + LIBRARY_VERSION;
// The same two values, handed to the shell so a device can be asked what it is
// running. A phone that has kept an old worker is the hardest thing here to
// see from the outside, and these are what say so. See templates/version.njk.
const VERSIONS = { shell: VERSION, library: LIBRARY_VERSION };
// Resolved once, and the set is the test for which cache a response belongs
// in. Membership, not a path pattern: the split is whichever directory the
// file came from, which is a fact only the server has.
@@ -103,17 +108,12 @@ const PRECACHE = [
'./css/bootstrap.min.css',
'./js/app.js',
'./js/htmx.min.js',
'./js/bootstrap.bundle.min.js',
'./templates/base.njk',
'./templates/page.njk',
'./templates/book.njk',
'./templates/index.njk',
'./templates/bookmark.njk',
'./templates/reference.njk',
'./templates/verses.njk',
'./templates/status.njk',
'./templates/notice.njk'
];
'./js/bootstrap.bundle.min.js'
// The templates come from render.js, which is the file that knows what one is
// -- and which loads exactly this list into nunjucks before it renders
// anything. Two lists would be one list and a way for the renderer to be
// asked for a template that was never cached.
].concat(TEMPLATE_URLS);
function cacheFor(req) {
return caches.open(LIBRARY_URLS.has(req.url) ? LIBRARY_CACHE : SHELL_CACHE);
@@ -409,7 +409,8 @@ async function servePage(path, code, call) {
}
try {
return await view.compose(fragment, { mark: await getBookmark(),
reference: reference });
reference: reference,
version: VERSIONS });
} catch (err) {
// A template that will not render is a bug, not a condition to design for,
// but it should not take the text down with it: the bare fragment has no
@@ -457,17 +458,21 @@ router.get('/api/bookmark', () => bookmarkFragment(''));
// under a page boot.html composed once a worker turns up, for nothing extra:
// those requests carry the address bar too.
//
// What the response headers are doing is the whole of what app.js used to do
// on a change event, and htmx has a name for each part of it:
// Two response headers carry what a change means beyond the options:
//
// settle:0 swap the options now. The default waits 20ms, and the point
// of this request is a scroll the reader is waiting on.
// show:#id:top scroll the named anchor to the top -- htmx's scrollBehavior
// is "instant", which is what this app wants everywhere.
// Reboot sets scroll-behavior: smooth, so saying nothing here
// would animate.
// settle:0 swap the options now. The default waits 20ms, and this
// answer is one the reader is waiting on.
// HX-Replace-Url put the anchor in the address bar without stacking a
// history entry per option spun past.
//
// The scroll used to be a third, show:#id:top, and is app.js's again. Not
// because the header was wrong but because the moment was: on iOS the change
// event arrives while the native picker is still drawn over the page, and
// dismissing it restores the scroll offset it opened at -- so a scroll made
// inside the swap is undone before it is seen. The page has to be the one
// doing it, because only the page is still there afterwards to try again.
// See landOnReference() in js/app.js. The address bar above is how it knows
// where to go: htmx updates history before it swaps.
router.get('/api/reference', async (call) => {
const params = call.url.searchParams;
const page = call.currentUrl();
@@ -505,7 +510,7 @@ router.get('/api/reference', async (call) => {
headers: {
'Content-Type': 'text/html; charset=utf-8',
'Cache-Control': 'no-store',
'HX-Reswap': 'innerHTML settle:0 show:#' + target + ':top',
'HX-Reswap': 'innerHTML settle:0',
'HX-Replace-Url': page.pathname + page.search + '#' + target
}
});