Raum-Modal Licht: Preset als Chips, Effekt als durchsuchbarer Picker, WLED-Zustand live

Die native Auswahlliste zeichnete Chrome hell auf hell. Welcher Effekt und
welches Preset gerade laufen, liest room.php?action=wled direkt von der Lampe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 22:27:40 +02:00
co-authored by Claude Opus 5
parent d5d2d8f336
commit 0eb01403c5
5 changed files with 173 additions and 42 deletions
+79 -11
View File
@@ -620,18 +620,86 @@ function rfLampeStarten(karte) {
eigen.addEventListener("change", () => setzen(eigen.value));
}
// Effekt und Preset: Chips oder - bei langen Listen - eine Auswahl.
karte.querySelectorAll(".rf-effekte .rf-chips[data-cmd]").forEach(gruppe => {
gruppe.querySelectorAll("[data-wert]").forEach(k => k.addEventListener("click", () => {
gruppe.querySelectorAll("[data-wert]").forEach(x => x.setAttribute("aria-pressed", String(x === k)));
// Preset, Effekt und andere Listen: Chips, lange Listen im aufklappbaren
// Picker mit Suche.
karte.querySelectorAll(".rf-liste").forEach(liste => {
const knopf = liste.querySelector(".rf-picker-knopf");
const picker = liste.querySelector(".rf-picker");
const suche = liste.querySelector(".rf-suche");
const auf = offen => {
if (!picker) return;
picker.hidden = !offen;
knopf.setAttribute("aria-expanded", String(offen));
if (offen) {
suche.value = "";
liste.querySelectorAll("[data-wert]").forEach(k => { k.hidden = false; });
const gewaehlt = liste.querySelector("[data-wert][aria-pressed='true']");
if (gewaehlt) gewaehlt.scrollIntoView({ block: "nearest" });
suche.focus({ preventScroll: true });
}
};
if (knopf) knopf.addEventListener("click", () => auf(picker.hidden));
if (suche) {
suche.addEventListener("input", () => {
const text = suche.value.trim().toLowerCase();
liste.querySelectorAll("[data-wert]").forEach(k => { k.hidden = text !== "" && !k.textContent.toLowerCase().includes(text); });
});
suche.addEventListener("keydown", e => {
if (e.key === "Escape") { e.stopPropagation(); auf(false); knopf.focus(); }
if (e.key === "Enter") {
const erster = [...liste.querySelectorAll("[data-wert]")].find(k => !k.hidden);
if (erster) erster.click();
}
});
}
liste.querySelectorAll("[data-wert]").forEach(k => k.addEventListener("click", () => {
rfListeSetzen(liste, k.dataset.wert);
auf(false);
const params = {};
params[gruppe.dataset.param] = k.dataset.wert;
rfKommando(Number(gruppe.dataset.cmd), params, gruppe);
params[liste.dataset.param] = k.dataset.wert;
rfKommando(Number(liste.dataset.cmd), params, liste);
}));
});
karte.querySelectorAll(".rf-effekte select[data-cmd]").forEach(auswahl => auswahl.addEventListener("change", () => {
const params = {};
params[auswahl.dataset.param] = auswahl.value;
rfKommando(Number(auswahl.dataset.cmd), params, auswahl);
}));
if (karte.dataset.wled) rfWledLesen(karte);
}
/** Einen Eintrag einer Liste als gewaehlt zeigen; null = keiner. */
function rfListeSetzen(liste, wert) {
let name = null;
liste.querySelectorAll("[data-wert]").forEach(k => {
const ja = wert !== null && k.dataset.wert === String(wert);
k.setAttribute("aria-pressed", String(ja));
if (ja) name = k.textContent;
});
const anzeige = liste.querySelector("[data-rf-picker-wert]");
if (anzeige) anzeige.textContent = name === null ? "" : name;
}
/**
* Den wirklichen Zustand einer WLED-Lampe holen. In der Datenbank stehen nur
* an/aus, Helligkeit und Farbe vom letzten Poll; welcher Effekt und welches
* Preset laufen, weiss nur die Lampe selbst.
*/
function rfWledLesen(karte) {
rfRequest("wled", { actor: Number(karte.dataset.actor) }).then(stand => {
if (!stand || stand.error || !document.body.contains(karte)) return;
karte.dataset.an = stand.an ? "1" : "";
const hell = karte.querySelector(".rf-hell");
if (hell && stand.bri !== null && document.activeElement !== hell) hell.value = stand.bri;
if (stand.farbe && (stand.farbe[0] || stand.farbe[1] || stand.farbe[2])) {
const hex = "#" + stand.farbe.map(v => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
karte.style.setProperty("--farbe", hex);
const eigen = karte.querySelector(".rf-farbe-eigen input");
if (eigen) eigen.value = hex;
karte.querySelectorAll("[data-farbe]").forEach(k => k.setAttribute("aria-pressed", String(k.dataset.farbe === hex)));
}
karte.querySelectorAll(".rf-liste").forEach(liste => {
const wert = stand[liste.dataset.feld];
// WLED meldet ps = -1, wenn kein Preset aktiv ist.
if (typeof wert !== "undefined") rfListeSetzen(liste, wert === null || wert < 0 ? null : wert);
});
rfLampeZeichnen(karte);
rfStatus();
});
}