Notiz zeigt sich sofort gesetzt, Widgets nach Wunsch des Nutzers
Aus dem Zettel wird die Notiz: Der Text steht immer formatiert da, roh ist nur
die Zeile mit der Schreibmarke. Dazu eine kleine Werkzeugleiste (Aufgabe,
Aufzaehlung, Nummer, Ueberschrift, fett, Linie), Enter fuehrt Listen fort,
Backspace am Zeilenanfang nimmt erst den Vorsatz. Fuer groessere Umbauten
bleibt der Quelltext-Knopf.
Kein contenteditable: Der Quelltext bleibt die Wahrheit und wird nie aus dem
HTML zurueckgerechnet, das der Browser beim Tippen erzeugt.
Reihenfolge und An/Aus der Widgets liegen jetzt je Nutzer auf dem Server, in
einer Einstellung ("benutzer,notiz,-system,wetter,bild"). Der Schalter fuer das
Wetter auf dem Schreibtisch faellt damit weg — es ist ein Widget wie jedes
andere.
Die Einstellungen sind in Abschnitte sortiert (Darstellung, HoneyBar, Widgets,
Wetter, Programme, Konto), Beschriftung links, Schalter rechts.
This commit is contained in:
1 parent
c0abfbb491
commit
3807ddca24
12 files changed
+806
-220
No files matched your search
+74
-13
@@ -28,12 +28,15 @@
|
||||
* als Aufklappfeld in der HoneyBar leben können — deshalb erzeugt `inhalt()`
|
||||
* nur den Kern, und die Verpackung entsteht hier.
|
||||
*/
|
||||
import { $, state } from "../core.js";
|
||||
import { $, saveSettings, state } from "../core.js";
|
||||
|
||||
const REGISTER = [];
|
||||
/** id → "laedt" | "fertig" | "leer" | "fehler" */
|
||||
const zustand = {};
|
||||
const uhren = {};
|
||||
/** Was schon einmal geladen wurde — ein Widget, das erst später eingeschaltet
|
||||
* wird, holt seine Daten dann nach. */
|
||||
const geladen = new Set();
|
||||
|
||||
export function widgetAnmelden(def) {
|
||||
REGISTER.push(def);
|
||||
@@ -55,9 +58,9 @@ export function widgetListe() {
|
||||
* anderen schon durchlaufen. Der Systemzustand braucht keine Symbole und stand
|
||||
* deshalb vor dem Benutzer, obwohl er darunter importiert wird.
|
||||
*
|
||||
* Hier ist die Reihenfolge damit eine Angabe statt einer Nebenwirkung — und
|
||||
* genau die Stelle, an der später die im Server gespeicherte Reihenfolge
|
||||
* einhaken kann.
|
||||
* Hier ist die Reihenfolge damit eine Angabe statt einer Nebenwirkung. Sie ist
|
||||
* die **Grundstellung**: Was der Nutzer selbst sortiert hat, steht in seinen
|
||||
* Einstellungen und schlägt sie (siehe widgetPlan).
|
||||
*/
|
||||
export function widgetsOrdnen(ids) {
|
||||
const platz = (w) => {
|
||||
@@ -67,6 +70,53 @@ export function widgetsOrdnen(ids) {
|
||||
REGISTER.sort((a, b) => platz(a) - platz(b));
|
||||
}
|
||||
|
||||
/* ── Was der Nutzer eingestellt hat ────────────────────────────────────────
|
||||
*
|
||||
* Reihenfolge und An/Aus stehen in **einer** Einstellung, als Liste von IDs mit
|
||||
* einem Minus vor dem, was aus ist:
|
||||
*
|
||||
* widgets = "benutzer,system,-wetter,notiz,bild"
|
||||
*
|
||||
* Ein Feld statt zwei, weil beides zusammen gehört: Wer ein Widget ausschaltet,
|
||||
* soll seinen Platz behalten, wenn er es wieder einschaltet. Und weil die
|
||||
* Einstellungen ohnehin schon je Nutzer auf dem Server liegen, braucht es dafür
|
||||
* weder eine neue Tabelle noch einen neuen Endpunkt.
|
||||
*
|
||||
* Die gespeicherte Liste ist ein Wunsch, kein Gesetz: Unbekannte IDs fallen
|
||||
* weg (ein Widget kann verschwinden), neue hängen sich hinten an und sind an.
|
||||
*/
|
||||
const AUS = "-";
|
||||
|
||||
/** Die Widgets in der Reihenfolge des Nutzers: [{id, titel, wo, an}]. */
|
||||
export function widgetPlan() {
|
||||
const aus = new Set();
|
||||
const reihe = [];
|
||||
String(state.settings.widgets || "")
|
||||
.split(",")
|
||||
.map((e) => e.trim())
|
||||
.filter(Boolean)
|
||||
.forEach((e) => {
|
||||
const id = e.startsWith(AUS) ? e.slice(1) : e;
|
||||
if (e.startsWith(AUS)) aus.add(id);
|
||||
if (!reihe.includes(id) && REGISTER.some((w) => w.id === id)) reihe.push(id);
|
||||
});
|
||||
REGISTER.forEach((w) => reihe.includes(w.id) || reihe.push(w.id));
|
||||
|
||||
return reihe.map((id) => {
|
||||
const w = REGISTER.find((x) => x.id === id);
|
||||
return { id, titel: w.titel, wo: w.wo, an: !aus.has(id) };
|
||||
});
|
||||
}
|
||||
|
||||
/** Übernimmt einen geänderten Plan: speichern, nachladen, neu zeichnen. */
|
||||
export function widgetPlanSetzen(plan) {
|
||||
state.settings.widgets = plan.map((p) => (p.an ? "" : AUS) + p.id).join(",");
|
||||
saveSettings();
|
||||
widgetsZeichnen();
|
||||
// Ein gerade erst eingeschaltetes Widget hat seine Daten noch nie geholt.
|
||||
widgetsLaden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt ein Widget (oder alle) und zeichnet neu.
|
||||
*
|
||||
@@ -75,9 +125,15 @@ export function widgetsOrdnen(ids) {
|
||||
* anderen Widgets mitreißen.
|
||||
*/
|
||||
export async function widgetsLaden(nurId) {
|
||||
const dran = REGISTER.filter((w) => w.laden && (!nurId || w.id === nurId));
|
||||
const an = new Set(widgetPlan().filter((p) => p.an).map((p) => p.id));
|
||||
const dran = REGISTER.filter((w) => {
|
||||
if (!w.laden) return false;
|
||||
if (nurId) return w.id === nurId;
|
||||
return an.has(w.id) && !geladen.has(w.id);
|
||||
});
|
||||
await Promise.all(
|
||||
dran.map(async (w) => {
|
||||
geladen.add(w.id);
|
||||
zustand[w.id] = "laedt";
|
||||
widgetsZeichnen();
|
||||
try {
|
||||
@@ -94,7 +150,9 @@ export async function widgetsLaden(nurId) {
|
||||
export function widgetsStarten() {
|
||||
REGISTER.forEach((w) => {
|
||||
if (!w.takt || uhren[w.id]) return;
|
||||
uhren[w.id] = setInterval(() => widgetsLaden(w.id), w.takt);
|
||||
uhren[w.id] = setInterval(() => {
|
||||
if (widgetPlan().find((p) => p.id === w.id)?.an) widgetsLaden(w.id);
|
||||
}, w.takt);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -175,13 +233,16 @@ export function widgetsZeichnen() {
|
||||
const schilder = $("deskwidgets");
|
||||
if (!spalte || !schilder) return;
|
||||
|
||||
const dran = REGISTER.filter((w) => {
|
||||
if (w.wo && !w.wo.includes(modus)) return false;
|
||||
if (w.sichtbar && !w.sichtbar()) return false;
|
||||
// „nichts da" heißt bei manchen Widgets: gar nicht erst hinstellen. Eine
|
||||
// leere Wetterkachel wäre schlechter als keine.
|
||||
return !(zustand[w.id] === "leer" && w.leer === "verbergen");
|
||||
});
|
||||
const dran = widgetPlan()
|
||||
.filter((p) => p.an)
|
||||
.map((p) => REGISTER.find((w) => w.id === p.id))
|
||||
.filter((w) => {
|
||||
if (w.wo && !w.wo.includes(modus)) return false;
|
||||
if (w.sichtbar && !w.sichtbar()) return false;
|
||||
// „nichts da" heißt bei manchen Widgets: gar nicht erst hinstellen. Eine
|
||||
// leere Wetterkachel wäre schlechter als keine.
|
||||
return !(zustand[w.id] === "leer" && w.leer === "verbergen");
|
||||
});
|
||||
|
||||
baue(spalte, desktop ? [] : dran, true);
|
||||
baue(schilder, desktop ? dran : [], false);
|
||||
|
||||
Reference in new issue
Block a user