diora-web/static/js/app/28-serviceworker.js
mrwnslz 656520fe8e
Some checks failed
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 8m23s
Test / e2e (push) Failing after 1m54s
Refactoring Schritt 2: app.js nach Bereichen in static/js/app/ aufgeteilt; sw v106
32 klassische Skripte in der alten Reihenfolge (01-core … 99-init), ohne
Änderung am Code darin: geschnitten nur zwischen Anweisungen, je Datei
'use strict' wie vorher für die ganze Datei. Geprüft (acorn): kein Code, der
beim Laden läuft, braucht einen Namen aus einer späteren Datei. Globale
Funktionen und let/const bleiben global, die App-Schichten (native.js,
native-eink.js, …) umhüllen sie wie bisher. Template und sw.js-SHELL listen
die Dateien; diora-android build_web nimmt static/js rekursiv.

Getestet: 14 Browser-Tests (e2e), Desktop-App (Buch, Lesestand, Leiste im
Reader, Hell/Dunkel).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:30:43 +02:00

46 lines
2 KiB
JavaScript

'use strict';
// ---------------------------------------------------------------------------
// Service Worker
// ---------------------------------------------------------------------------
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
// Registered from '/sw.js' (root), not '/static/js/sw.js': a service
// worker's default scope is its own script's directory, so registering
// it from under /static/js/ would only ever let it control requests
// under that path — page navigations to '/', '/books/' etc. would never
// be intercepted, breaking offline entirely.
navigator.serviceWorker.register('/sw.js', {scope: '/'}).catch(err => {
console.warn('Service worker registration failed:', err);
});
// Drop any leftover registration from the old, wrongly-scoped '/static/js/sw.js'
// path so it doesn't keep running or fight the new root-scoped worker.
navigator.serviceWorker.getRegistrations().then(regs => {
regs.forEach(r => { if (r.scope.endsWith('/static/js/')) r.unregister(); });
});
});
// When a new SW activates it sends SW_ACTIVATED — reload to get fresh assets,
// but never in the middle of something: not while a book is open, radio or a
// podcast plays, or a text field has the focus — then as soon as that's over.
let reloadPending = false;
const busy = () => {
if (currentBookId || isPlaying) return true;
const host = window.DioraPodcastHost;
if (host && host.playerState) {
try { if (JSON.parse(host.playerState()).playing) return true; } catch (_) {}
}
const el = document.activeElement;
return !!el && (el.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName));
};
const reloadWhenIdle = () => {
if (busy()) setTimeout(reloadWhenIdle, 5000);
else window.location.reload();
};
navigator.serviceWorker.addEventListener('message', e => {
if (e.data?.type === 'SW_ACTIVATED' && !reloadPending) {
reloadPending = true;
reloadWhenIdle();
}
});
}