Quelltext des aktuellen Standes
/**
* IT-Docs Service Worker
* Verarbeitet Web Push-Benachrichtigungen und ermoeglicht PWA-Installation.
*/
'use strict';
const CACHE_NAME = 'itdocs-v1';
// Statische Assets cachen (optional, fuer Offline-Folie)
const PRECACHE_ASSETS = [
'/',
'/assets/css/tokens.css',
'/assets/css/app.css',
'/assets/css/responsive.css',
'/icons/icon-192.svg',
'/icons/icon-512.svg',
];
// ===== Install =====
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
// Nur nicht-kritische Assets precachen – Fehler ignorieren
return Promise.allSettled(
PRECACHE_ASSETS.map(function(url) {
return cache.add(url).catch(function() {});
})
);
}).then(function() {
return self.skipWaiting();
})
);
});
// ===== Activate =====
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames
.filter(function(name) { return name !== CACHE_NAME; })
.map(function(name) { return caches.delete(name); })
);
}).then(function() {
return self.clients.claim();
})
);
});
// ===== Fetch (Network-First fuer HTML, Cache-First fuer Assets) =====
self.addEventListener('fetch', function(event) {
var url = new URL(event.request.url);
// Nur GET-Anfragen auf derselben Origin behandeln
if (event.request.method !== 'GET' || url.origin !== self.location.origin) {
return;
}
// API- und Admin-Anfragen immer direkt ans Netzwerk
if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/admin')) {
return;
}
// Statische Assets: Cache-First
if (url.pathname.startsWith('/assets/') || url.pathname.startsWith('/icons/')) {
event.respondWith(
caches.match(event.request).then(function(cached) {
return cached || fetch(event.request).then(function(response) {
if (response.ok) {
var clone = response.clone();
caches.open(CACHE_NAME).then(function(cache) {
cache.put(event.request, clone);
});
}
return response;
});
})
);
return;
}
// HTML-Seiten: Network-First mit Cache-Fallback
event.respondWith(
fetch(event.request)
.then(function(response) { return response; })
.catch(function() {
return caches.match(event.request).then(function(cached) {
return cached || caches.match('/');
});
})
);
});
// ===== Push-Benachrichtigungen empfangen =====
self.addEventListener('push', function(event) {
var data = {};
try {
data = event.data ? event.data.json() : {};
} catch (e) {
data = { title: 'OpenNIT', body: event.data ? event.data.text() : 'Neue Benachrichtigung' };
}
var title = data.title || 'OpenNIT';
var body = data.body || '';
var url = data.url || '/';
var type = data.type || 'system';
var icon = '/icons/icon-192.svg';
var badge = '/icons/icon-192.svg';
var options = {
body: body,
icon: icon,
badge: badge,
tag: 'itdocs-' + type, // Gleicher Tag ersetzt vorherige Nachricht desselben Typs
renotify: true, // Trotzdem vibrieren/klingeln
requireInteraction: false,
data: { url: url },
actions: [
{ action: 'open', title: 'Oeffnen' },
{ action: 'dismiss', title: 'Schliessen' },
],
};
event.waitUntil(
self.registration.showNotification(title, options)
);
});
// ===== Klick auf Push-Benachrichtigung =====
self.addEventListener('notificationclick', function(event) {
event.notification.close();
if (event.action === 'dismiss') {
return;
}
var targetUrl = (event.notification.data && event.notification.data.url)
? event.notification.data.url
: '/';
event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(windowClients) {
// Vorhandenes IT-Docs-Fenster fokussieren
for (var i = 0; i < windowClients.length; i++) {
var client = windowClients[i];
var clientUrl = new URL(client.url);
if (clientUrl.origin === self.location.origin) {
client.focus();
client.navigate(targetUrl);
return;
}
}
// Neues Fenster oeffnen
return clients.openWindow(targetUrl);
})
);
});
// ===== Push-Abonnement abgelaufen =====
self.addEventListener('pushsubscriptionchange', function(event) {
event.waitUntil(
self.registration.pushManager.subscribe({
userVisibleOnly: true,
// applicationServerKey wird vom Client beim erneuten Anmelden gesetzt
}).catch(function() {})
);
});