Bild einstellen gehoert in die Einstellungen, nicht ins Widget

This commit is contained in:
marc committed 2026-08-31 20:12:21 +02:00
1 parent e2988f7ee9
commit 75df4e0833
5 files changed
+151 -65

No files matched your search

+113 -62
View File
@@ -10,92 +10,142 @@ import { widgetAnmelden, widgetsLaden, widgetsZeichnen } from "./rahmen.js";
* Hochgeladen wird zum eigenen Server; verlinkt wird auf eine fremde Adresse.
* Der Unterschied ist keiner der Bequemlichkeit: Ein Link holt bei jedem
* Aufbau des Schreibtischs etwas von woanders, ein Upload nie.
*
* DAS WIDGET ZEIGT, DIE EINSTELLUNGEN STELLEN EIN.
*
* Hochladen, Verlinken und Entfernen standen erst im Widget selbst. Das ist die
* Ausnahme gewesen, nicht die Regel: Der Ort des Wetters wird auch nicht in der
* Wetterkachel gesucht. Ein Schild auf dem Schreibtisch, das zu drei Vierteln
* aus Knöpfen besteht, zeigt vor allem sich selbst.
*
* Also: Das Widget zeigt nur noch das Bild. Die Knöpfe stehen unter
* *Einstellungen → Bild* — dieselbe Datei, aber ein zweiter Ausgang
* (`bildFormularHtml` / `bildFormularMontieren`), den os.js einhängt.
*/
const LEER = "Kein Bild — hochladen oder Adresse einfügen.";
const LEER = "Kein Bild — unter Einstellungen → Bild hochladen oder verlinken.";
const FORM_ID = "bildForm";
let art = ""; // "datei" | "link" | ""
let quelle = "";
let stand = ""; // Meldung unter dem Bild
let stand = ""; // Meldung im Einstellungsfeld
let linkAuf = false;
let kaputt = false; // die Adresse liefert kein Bild
widgetAnmelden({
id: "bild",
titel: "bild",
// Hält ein Dateifeld und ein Eingabefeld: Der Rahmen darf den Inhalt nicht
// unter den Fingern austauschen.
// Das Bild soll beim Neuzeichnen nicht neu geladen werden — ein Bild, das
// alle zwei Minuten kurz weiß aufblitzt, wäre schlechter als keines.
stabil: true,
async laden() {
const d = await api("/api/image/info");
art = (d && d.art) || "";
quelle = (d && d.url) || "";
kaputt = false;
},
inhalt() {
const bild = quelle
? `<img class="bildw-bild" src="${escapeAttr(quelle)}" alt="" />`
: `<p class="w-zustand">${LEER}</p>`;
return `
<div class="bildw">${bild}</div>
${
linkAuf
? `<div class="bildw-linkzeile">
<input class="bildw-url" type="url" spellcheck="false"
placeholder="https://…" value="${escapeAttr(art === "link" ? quelle : "")}" />
<button class="btn bildw-uebernehmen">setzen</button>
</div>`
: ""
}
<div class="w-fuss">
<span class="w-stand">${escapeHtml(stand)}</span>
<span class="bildw-knoepfe">
<input class="bildw-datei" type="file" accept="image/png,image/jpeg,image/webp,image/gif" hidden />
<button class="btn bildw-waehlen">${quelle ? "ersetzen" : "hochladen"}</button>
<button class="btn bildw-link">link</button>
${quelle ? `<button class="btn bildw-weg">entfernen</button>` : ""}
</span>
</div>`;
if (kaputt) {
return `<div class="bildw"><p class="w-zustand">${
art === "link" ? "Adresse liefert kein Bild" : "Bild nicht lesbar"
}</p></div>`;
}
return `<div class="bildw">${
quelle
? `<img class="bildw-bild" src="${escapeAttr(quelle)}" alt="" />`
: `<p class="w-zustand">${LEER}</p>`
}</div>`;
},
montiert(el) {
const datei = el.querySelector(".bildw-datei");
el.querySelector(".bildw-waehlen").addEventListener("click", () => datei.click());
datei.addEventListener("change", () => datei.files[0] && hochladen(datei.files[0]));
el.querySelector(".bildw-link").addEventListener("click", () => {
linkAuf = !linkAuf;
neu();
});
const url = el.querySelector(".bildw-url");
if (url) {
url.focus();
const setzen = () => linkSetzen(url.value.trim());
el.querySelector(".bildw-uebernehmen").addEventListener("click", setzen);
url.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
setzen();
}
});
}
const weg = el.querySelector(".bildw-weg");
if (weg) weg.addEventListener("click", () => linkSetzen(""));
// Ein Bild, das nicht kommt, soll es sagen — bei einem Link ist das der
// Normalfall des Tages, an dem die fremde Seite umzieht.
const img = el.querySelector(".bildw-bild");
if (img) {
img.addEventListener("error", () => {
melden(art === "link" ? "Adresse liefert kein Bild" : "Bild nicht lesbar");
});
}
el.querySelector(".bildw-bild")?.addEventListener("error", () => {
kaputt = true;
melden(art === "link" ? "Adresse liefert kein Bild" : "Bild nicht lesbar");
neu();
});
},
});
/* ── Der Ausgang in die Einstellungen ──────────────────────────────────── */
/** Das Feld für *Einstellungen → Bild*. os.js hängt es ein, kennt es aber nicht. */
export function bildFormularHtml() {
return `<div id="${FORM_ID}">${formInhalt()}</div>`;
}
/** Nach dem Einhängen verdrahten. */
export function bildFormularMontieren(root) {
const el = root.querySelector(`#${FORM_ID}`);
if (el) verdrahte(el);
}
function formInhalt() {
const vorschau = quelle
? `<img class="bildset-bild" src="${escapeAttr(quelle)}" alt="" />`
: `<span class="bildset-leer">kein bild</span>`;
return `
<div class="bildset">
<span class="bildset-vorschau">${vorschau}</span>
<div class="bildset-rechts">
<div class="bildset-knoepfe">
<input class="bildw-datei" type="file" accept="image/png,image/jpeg,image/webp,image/gif" hidden />
<button type="button" class="btn bildw-waehlen">${quelle ? "ersetzen" : "hochladen"}</button>
<button type="button" class="btn bildw-link">link</button>
${quelle ? `<button type="button" class="btn bildw-weg">entfernen</button>` : ""}
</div>
<span class="w-stand">${escapeHtml(stand)}</span>
</div>
</div>
${
linkAuf
? `<div class="bildw-linkzeile">
<input class="bildw-url" type="url" spellcheck="false"
placeholder="https://…" value="${escapeAttr(art === "link" ? quelle : "")}" />
<button type="button" class="btn bildw-uebernehmen">setzen</button>
</div>`
: ""
}`;
}
function verdrahte(el) {
const datei = el.querySelector(".bildw-datei");
el.querySelector(".bildw-waehlen").addEventListener("click", () => datei.click());
datei.addEventListener("change", () => datei.files[0] && hochladen(datei.files[0]));
el.querySelector(".bildw-link").addEventListener("click", () => {
linkAuf = !linkAuf;
formNeu();
});
const url = el.querySelector(".bildw-url");
if (url) {
url.focus();
const setzen = () => linkSetzen(url.value.trim());
el.querySelector(".bildw-uebernehmen").addEventListener("click", setzen);
url.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
setzen();
}
});
}
el.querySelector(".bildw-weg")?.addEventListener("click", () => linkSetzen(""));
}
/** Das Einstellungsfeld neu zeichnen — es steht nicht unter dem Widget-Rahmen. */
function formNeu() {
const el = document.getElementById(FORM_ID);
if (!el) return;
el.innerHTML = formInhalt();
verdrahte(el);
}
async function hochladen(file) {
melden("lädt hoch …");
try {
@@ -106,6 +156,7 @@ async function hochladen(file) {
} catch (e) {
melden(e.message);
}
formNeu();
}
async function linkSetzen(adresse) {
@@ -118,13 +169,13 @@ async function linkSetzen(adresse) {
} catch (e) {
melden(e.message);
}
formNeu();
}
function melden(s) {
stand = s;
document.querySelectorAll('[data-widget="bild"] .w-stand').forEach((el) => {
el.textContent = s;
});
const el = document.querySelector(`#${FORM_ID} .w-stand`);
if (el) el.textContent = s;
}
/** Neu zeichnen — stabile Widgets lässt der Rahmen sonst in Ruhe. */