const CACHE = 'klassenportal-v2'; const PRECACHE = [ '/', '/login.html', '/app.html', '/manifest.json', '/favicon.svg', '/icons/icon-192.png', '/icons/icon-512.png', '/icons/apple-touch-icon.png', ]; self.addEventListener('install', e => { e.waitUntil( caches.open(CACHE) .then(c => c.addAll(PRECACHE)) .then(() => self.skipWaiting()) ); }); self.addEventListener('activate', e => { e.waitUntil( caches.keys() .then(keys => Promise.all( keys.filter(k => k !== CACHE).map(k => caches.delete(k)) )) .then(() => self.clients.claim()) ); }); self.addEventListener('push', e => { let data = { title: 'Klassenportal', body: '' }; try { data = e.data ? e.data.json() : data; } catch {} e.waitUntil( self.registration.showNotification(data.title, { body: data.body, icon: '/icons/icon-192.png', badge: '/icons/icon-192.png', tag: data.tag || 'kp', renotify: true, data: { url: data.url || '/app' }, }) ); }); self.addEventListener('notificationclick', e => { e.notification.close(); const url = e.notification.data?.url || '/app'; e.waitUntil( clients.matchAll({ type: 'window', includeUncontrolled: true }).then(list => { const found = list.find(c => c.url.includes(self.location.origin)); return found ? found.focus() : clients.openWindow(url); }) ); }); self.addEventListener('fetch', e => { const url = new URL(e.request.url); // Only handle same-origin GET requests if (url.origin !== self.location.origin) return; if (e.request.method !== 'GET') return; // API calls: always network, never cache if (url.pathname.startsWith('/api/')) return; // Page navigations: network-first, fallback to cache if (e.request.mode === 'navigate') { e.respondWith( fetch(e.request) .then(r => { const clone = r.clone(); caches.open(CACHE).then(c => c.put(e.request, clone)); return r; }) .catch(() => caches.match(e.request).then(r => r || caches.match('/login.html')) ) ); return; } // Static assets: cache-first, populate on miss e.respondWith( caches.match(e.request).then(cached => { if (cached) return cached; return fetch(e.request).then(r => { if (r.ok) { const clone = r.clone(); caches.open(CACHE).then(c => c.put(e.request, clone)); } return r; }); }) ); });