OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

sw.js

5 KB
/**
 * 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() {})
    );
});