Files
adminandClaude Opus 5 df48432133 Benachrichtigungen: Geraet, Abos und der Reiter Meldungen
Der Geraetesuchlauf legt "Benachrichtigungen" an (benachrichtigung_module.py),
ein Kommando je Kanal. Damit kann jede Automatik melden, ohne dass Editor,
Zeitleiste oder Datenbank etwas davon wissen muessten.

Fuer die Meldung aufs Handy braucht es keine App: Der Browser meldet sich
unter Einstellungen -> Meldungen selbst an (sw.js, ajax/push.php), das Abo
steht in homeMesh.push_abos, verschickt wird vom Runner. Auf dem iPhone geht
es erst ab der Ablage auf dem Home-Bildschirm - der Reiter sagt das auch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 08:37:31 +02:00

55 lines
2.2 KiB
JavaScript

/*
* Service Worker - nur für Benachrichtigungen.
*
* Er liegt bewusst im Wurzelverzeichnis der Anwendung: Ein Service Worker
* gilt nur für Adressen unterhalb seines eigenen Ortes, und die Abos sollen
* für die ganze Seite gelten, nicht nur für /js/.
*
* Was er NICHT tut: Seiten zwischenspeichern. Das Dashboard lebt von
* aktuellen Werten, und ein Cache, der eine alte Fassung ausliefert, wäre
* hier kein Vorteil, sondern eine Fehlerquelle. Deshalb gibt es kein
* fetch-Ereignis - der Browser holt alles wie ohne Service Worker.
*
* Geschickt wird vom Runner (BenachrichtigungTransport in
* SolarManager/autoActions/transports.py), verschlüsselt und mit dem
* VAPID-Schlüssel unterschrieben.
*/
self.addEventListener("install", () => self.skipWaiting());
self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()));
self.addEventListener("push", (ereignis) => {
let daten = { titel: "Smart controller", text: "", url: "index.php" };
try {
if (ereignis.data) Object.assign(daten, ereignis.data.json());
} catch (fehler) {
// Kein JSON: dann ist die Nutzlast der Text.
if (ereignis.data) daten.text = ereignis.data.text();
}
ereignis.waitUntil(self.registration.showNotification(daten.titel, {
body: daten.text,
icon: "assets/img/favicon.png",
badge: "assets/img/favicon.png",
// Gleiche Kennung ersetzt die vorherige Meldung, statt sie zu stapeln -
// eine Automatik, die dreimal meldet, soll nicht dreimal im Schirm stehen.
tag: daten.kennung || undefined,
timestamp: Date.now(),
data: { url: daten.url },
}));
});
self.addEventListener("notificationclick", (ereignis) => {
ereignis.notification.close();
const ziel = new URL((ereignis.notification.data && ereignis.notification.data.url) || "index.php",
self.registration.scope).href;
ereignis.waitUntil(self.clients.matchAll({ type: "window", includeUncontrolled: true })
.then((fenster) => {
// Ist die Seite schon offen, wird sie nach vorn geholt statt ein
// zweites Mal geöffnet.
for (const f of fenster) {
if (f.url.startsWith(self.registration.scope) && "focus" in f) return f.focus();
}
return self.clients.openWindow(ziel);
}));
});