rastrillo / aviso Public

Clone
git clone https://amadan.net/rastrillo/aviso

Plain git — no account needed to clone.

Download

Download this file

1// The page half, as SKILL.md shows it. The buttons start disabled and
2// are enabled only once they can do something: after the worker is
3// active and the key is fetched. On a browser without push they stay
4// disabled, with the reason logged, rather than sitting there inert.
5import { enable, reconcile, disable, capabilities, status } from "/static/aviso/push.mjs";
6
7const log = (line) => { document.getElementById("log").textContent += line + "\n"; };
8const button = (id) => document.getElementById(id);
9const post = (path) => (body) => fetch(path, {
10 method: "POST", credentials: "same-origin",
11 headers: { "Content-Type": "application/json" }, body: JSON.stringify(body),
12});
13const save = post("/aviso/subscribe");
14const remove = post("/aviso/unsubscribe");
15
16const caps = capabilities();
17log("capabilities: " + JSON.stringify(caps));
18if (!caps.standalone && /iPhone|iPad/.test(navigator.userAgent)) {
19 document.getElementById("coach").style.display = "block";
20}
21if (!caps.serviceWorker || !caps.push) {
22 log("this browser cannot do push; the buttons stay disabled");
23} else {
24 await navigator.serviceWorker.register("/sw.js");
25 // Active, not merely registered: subscribe() on an installing
26 // worker rejects with InvalidStateError.
27 const registration = await navigator.serviceWorker.ready;
28 const { publicKey } = await (await fetch("/aviso/public-key")).json();
29
30 // Every load: repair without prompting, and keep the server's
31 // confirmation moving.
32 const repaired = await reconcile({ registration, publicKey, save }).catch((e) => { log("reconcile: " + e.message); return null; });
33 log("subscribed: " + !!repaired);
34
35 // From the click, synchronously: enable prompts before its first await.
36 button("enable").onclick = () => {
37 enable({ registration, publicKey, save })
38 .then((sub) => log(sub ? "enabled: " + sub.endpoint.slice(0, 40) + "…" : "permission denied"))
39 .catch((e) => log("enable: " + e.message));
40 };
41 button("disable").onclick = async () => {
42 try { await disable({ registration, remove }); log("disabled"); } catch (e) { log("disable: " + e.message); }
43 };
44 button("notify").onclick = async () => {
45 const r = await fetch("/notify", { method: "POST", credentials: "same-origin" });
46 log("notify: " + r.status + " " + await r.text());
47 };
48 for (const id of ["enable", "disable", "notify"]) button(id).disabled = false;
49 const s = await status(registration);
50 log("permission: " + s.permission);
51}
52