186 lines
6.3 KiB
JavaScript
186 lines
6.3 KiB
JavaScript
import { api, escapeAttr, escapeHtml } from "../core.js";
|
|
import { widgetAnmelden, widgetsLaden, widgetsZeichnen } from "./rahmen.js";
|
|
|
|
/* ── Das Bild ──────────────────────────────────────────────────────────────
|
|
*
|
|
* Genau **ein** Bild je Nutzer, hochgeladen oder verlinkt. Ein neues ersetzt
|
|
* das alte, ohne Verwaltung und ohne Liste — das ist der ganze Reiz: Es ist
|
|
* das erste Widget, das nichts abfragt, sondern etwas *ist*.
|
|
*
|
|
* 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 — unter Einstellungen → Bild hochladen oder verlinken.";
|
|
const FORM_ID = "bildForm";
|
|
|
|
let art = ""; // "datei" | "link" | ""
|
|
let quelle = "";
|
|
let stand = ""; // Meldung im Einstellungsfeld
|
|
let linkAuf = false;
|
|
let kaputt = false; // die Adresse liefert kein Bild
|
|
|
|
widgetAnmelden({
|
|
id: "bild",
|
|
titel: "bild",
|
|
// 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() {
|
|
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) {
|
|
// Ein Bild, das nicht kommt, soll es sagen — bei einem Link ist das der
|
|
// Normalfall des Tages, an dem die fremde Seite umzieht.
|
|
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 {
|
|
await api("/api/image", { method: "POST", body: file, headers: { "Content-Type": file.type || "application/octet-stream" } });
|
|
linkAuf = false;
|
|
await widgetsLaden("bild");
|
|
melden("");
|
|
} catch (e) {
|
|
melden(e.message);
|
|
}
|
|
formNeu();
|
|
}
|
|
|
|
async function linkSetzen(adresse) {
|
|
melden(adresse ? "übernehme …" : "entferne …");
|
|
try {
|
|
await api("/api/image", { method: "PUT", body: JSON.stringify({ url: adresse }) });
|
|
linkAuf = false;
|
|
await widgetsLaden("bild");
|
|
melden("");
|
|
} catch (e) {
|
|
melden(e.message);
|
|
}
|
|
formNeu();
|
|
}
|
|
|
|
function melden(s) {
|
|
stand = 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. */
|
|
function neu() {
|
|
document.querySelectorAll('[data-widget="bild"]').forEach((el) => delete el.dataset.zustand);
|
|
widgetsZeichnen();
|
|
}
|