/* ===================================================================== Service Worker des Creator Workspace. Er hat GENAU EINE Aufgabe: Benachrichtigungen entgegennehmen und anzeigen. ⚠️ BEWUSST OHNE ZWISCHENSPEICHER. Der naheliegende Zusatz waere, hier auch Seiten und Dateien vorzuhalten ("offline verfuegbar"). Genau das waere hier falsch: * Der Workspace liegt hinter einer Anmeldung. Ein Service Worker, der Antworten aufhebt, hebt damit AUCH persoenliche Daten auf -- auf einem Geraet, das jemand anderem gehoeren kann. * Die Seiten aendern sich haeufig. Ein Zwischenspeicher, der etwas Falsches zeigt, ist schlimmer als gar keiner -- man glaubt ihm ja. Die Versionsstempel loesen das Problem bereits. Wer spaeter Offline-Faehigkeit will, faengt hier NICHT einfach an, sondern klaert vorher, was zwischengespeichert werden darf. ===================================================================== */ /* Beim Einbauen sofort uebernehmen, statt auf das Schliessen aller Reiter zu warten. Ohne diese zwei Zeilen wuerde eine neue Fassung erst Tage spaeter aktiv -- und niemand wuesste, welche gerade laeuft. */ self.addEventListener("install", (e) => { self.skipWaiting(); }); self.addEventListener("activate", (e) => { e.waitUntil(self.clients.claim()); }); /* --------------------------------------------------------------------- Eine Benachrichtigung kommt an. ------------------------------------------------------------------ */ self.addEventListener("push", (e) => { /* Ohne Daten trotzdem etwas anzeigen: Manche Push-Dienste schicken im Zweifel eine leere Nachricht, und ein Browser, der eine Push-Berechtigung hat, MUSS etwas anzeigen -- sonst entzieht er sie nach mehrmaligem Schweigen wieder. */ let d = { titel: "Creator Workspace", text: "Es gibt etwas Neues.", ziel: "/workspace/start.html" }; try { if (e.data) d = { ...d, ...e.data.json() }; } catch { try { d.text = e.data.text() || d.text; } catch { /* dann die Vorgabe */ } } /* ================================================================= EIN ANRUF IST KEINE MELDUNG WIE JEDE ANDERE (19.09.2026) Filipe: „irgendwas klappt mit dem telefonieren nicht." Nachgemessen am Protokoll des Servers: 24 Anrufe gestartet, jeder nach 7 bis 39 Sekunden beendet, und im Chat steht danach jedes Mal „Verpasster Anruf". Die Gegenseite schrieb: „Hab keinen Anrufeingang gehabt und keine Benachrichtigung." Die Benachrichtigung WAR zugestellt -- `zuletzt_ok` am Geraet stand auf genau die Anrufminute. Sie hat nur nicht geklingelt, und der Grund stand hier: tag: d.art alle Anrufe teilen sich die Kennung „anruf" renotify: false eine zweite Meldung mit derselben Kennung ersetzt die erste LAUTLOS -- kein Ton, keine Vibration kein vibrate das Handy zuckt nicht kein requireInteraction der Kasten verschwindet von selbst Fuer „Aufgabe ueberfaellig" ist das genau richtig -- der Satz daneben stimmt, eine Meldung, die stehen bleibt, ist eine Zumutung. Fuer ein klingelndes Telefon ist es das Gegenteil. Also: Alles bleibt, wie es war -- ausser beim Anruf. ============================================================== */ const istAnruf = d.art === "anruf"; e.waitUntil(self.registration.showNotification(d.titel, { body: d.text, icon: "/assets/img/app-symbole/workspace-192.png", badge: "/assets/img/app-symbole/workspace-192.png", /* Gleiche Art ersetzt sich gegenseitig, statt sich zu stapeln -- drei Meldungen "Aufgabe ueberfaellig" untereinander helfen niemandem. BEIM ANRUF EINE EIGENE KENNUNG JE ANRUF: Sonst haette der zweite Versuch den ersten stillschweigend ersetzt, und zwar genau in dem Moment, in dem jemand noch einmal anruft, WEIL nicht abgehoben wurde. */ tag: istAnruf ? ("anruf-" + Date.now()) : (d.art || "workspace"), /* Und er meldet sich hoerbar, auch wenn schon einer dasteht. */ renotify: istAnruf, /* ZWEIMAL LANG, WIE EIN TELEFON. Kurze Stupser gehen im Alltag unter; dieses Muster kennt man. */ vibrate: istAnruf ? [400, 200, 400, 200, 400] : undefined, /* Der einzige Fall, in dem eine Meldung stehen bleiben SOLL: Ein Anruf, den man nicht sieht, ist keiner. Sie verschwindet, sobald man sie antippt oder wegwischt. */ requireInteraction: istAnruf, data: { ziel: d.ziel || "/workspace/start.html" }, })); }); /* --------------------------------------------------------------------- Jemand tippt die Benachrichtigung an. Ist der Workspace schon offen, wird DIESES Fenster benutzt und dort hingesteuert -- sonst sammeln sich mit der Zeit fuenf Reiter mit derselben Seite. Nur wenn keines offen ist, wird eines geoeffnet. ------------------------------------------------------------------ */ self.addEventListener("notificationclick", (e) => { e.notification.close(); const ziel = e.notification.data?.ziel || "/workspace/start.html"; e.waitUntil((async () => { const fenster = await self.clients.matchAll({ type: "window", includeUncontrolled: true }); for (const f of fenster) { if (f.url.includes("/workspace/")) { await f.focus(); if ("navigate" in f) { try { await f.navigate(ziel); } catch { /* schon dort */ } } return; } } await self.clients.openWindow(ziel); })()); });