52 lines
1.5 KiB
JavaScript
52 lines
1.5 KiB
JavaScript
// Ein einziger Zustandsspeicher. Ansichten lesen daraus und zeichnen sich
|
|
// neu, wenn er sich ändert - niemand fasst fremde DOM-Knoten an.
|
|
//
|
|
// Das ist im Kern das, was ein Framework auch tut. Der Unterschied ist,
|
|
// dass hier nichts passiert, was nicht in dieser Datei steht.
|
|
"use strict";
|
|
|
|
const listeners = new Set();
|
|
|
|
export const state = {
|
|
/** Aus /api/config, mit Rückfallwert für den ersten Start ohne Netz. */
|
|
appName: "Einkaufsliste",
|
|
user: null,
|
|
lists: [],
|
|
/** Ansicht der geöffneten Liste, so wie /view sie liefert. */
|
|
view: null,
|
|
markets: [],
|
|
categories: [],
|
|
online: navigator.onLine,
|
|
/** "ok" | "offline" | "error" */
|
|
syncState: navigator.onLine ? "ok" : "offline",
|
|
/** Einmalige Meldung aus der Synchronisation, wird von der Ansicht
|
|
* abgeholt und zurückgesetzt. */
|
|
syncProblem: null,
|
|
lastSync: null,
|
|
};
|
|
|
|
export function subscribe(fn) {
|
|
listeners.add(fn);
|
|
return () => listeners.delete(fn);
|
|
}
|
|
|
|
/** Nach jeder Zustandsänderung genau einmal aufrufen. Mehrere Aufrufe im
|
|
* selben Tick werden zusammengefasst, damit nicht mehrfach gezeichnet wird. */
|
|
let scheduled = false;
|
|
export function notify() {
|
|
if (scheduled) return;
|
|
scheduled = true;
|
|
queueMicrotask(() => {
|
|
scheduled = false;
|
|
for (const fn of listeners) fn(state);
|
|
});
|
|
}
|
|
|
|
export function set(patch) {
|
|
Object.assign(state, patch);
|
|
notify();
|
|
}
|
|
|
|
window.addEventListener("online", () => set({ online: true }));
|
|
window.addEventListener("offline", () => set({ online: false }));
|