/* * Service Worker des Planers. * * Zwei Aufgaben: Push-Nachrichten anzeigen, und die Seite "Erfassen" auch * ohne Netz bereithalten. * * Zwischengespeichert wird **genau diese eine Seite** und sonst nichts. Ein * halb veralteter Planer wäre schlimmer als gar keiner — ein Eingabefeld * dagegen veraltet nicht, und ohne die Seite nützte die Warteschlange im * Gerät niemandem: Man käme gar nicht erst hin. */ const LAGER = 'planer-erfassen-v1' const OFFLINE_SEITE = '/erfassen' self.addEventListener('install', (ereignis) => { ereignis.waitUntil( caches .open(LAGER) .then((lager) => lager.add(new Request(OFFLINE_SEITE, { cache: 'reload' }))) .catch(() => undefined), ) // Sofort übernehmen, nicht auf das Schließen aller Tabs warten. self.skipWaiting() }) self.addEventListener('activate', (ereignis) => { ereignis.waitUntil( caches .keys() .then((namen) => Promise.all(namen.filter((n) => n !== LAGER).map((n) => caches.delete(n))), ) .then(() => self.clients.claim()), ) }) self.addEventListener('fetch', (ereignis) => { const anfrage = ereignis.request if (anfrage.method !== 'GET') return const adresse = new URL(anfrage.url) if (adresse.origin !== self.location.origin) return if (adresse.pathname !== OFFLINE_SEITE) return // Zuerst das Netz: Wer online ist, bekommt die frische Seite. Erst wenn das // scheitert, kommt die aufgehobene Fassung. ereignis.respondWith( fetch(anfrage) .then((antwort) => { if (antwort.ok) { const kopie = antwort.clone() void caches.open(LAGER).then((lager) => lager.put(OFFLINE_SEITE, kopie)) } return antwort }) .catch(() => caches .match(OFFLINE_SEITE) .then( (aufgehoben) => aufgehoben ?? new Response('Offline und nichts aufgehoben.', { status: 503, headers: { 'Content-Type': 'text/plain; charset=utf-8' }, }), ), ), ) }) self.addEventListener('push', (ereignis) => { let daten = { titel: 'Planer', text: '', pfad: '/' } try { if (ereignis.data) daten = { ...daten, ...ereignis.data.json() } } catch { // Kaputte Nutzlast: lieber eine karge Meldung als gar keine. } ereignis.waitUntil( self.registration.showNotification(daten.titel, { body: daten.text, lang: 'de', // Gleiche Anlässe überschreiben einander, statt sich zu stapeln. tag: daten.anlass || 'planer', data: { pfad: daten.pfad }, }), ) }) self.addEventListener('notificationclick', (ereignis) => { ereignis.notification.close() const pfad = (ereignis.notification.data && ereignis.notification.data.pfad) || '/' ereignis.waitUntil( self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((fenster) => { // Ist der Planer schon offen, dorthin wechseln statt ein zweites // Fenster aufzumachen. for (const f of fenster) { if (f.url.includes(self.location.origin)) { return f.focus().then(() => f.navigate(pfad)) } } return self.clients.openWindow(pfad) }), ) })