Geraeteauswahl: nach Art gruppiert, Namen geputzt
Nach dem Discovery-Lauf stehen 51 Geraete in der Ausloeser-Liste und 40 in der Aktions-Liste, flach und alphabetisch. Dreizehn Thermostate und elf Jalousien sind darin vierundzwanzig gleich aussehende Zeilen. Die Liste ist jetzt nach Geraeteart gruppiert (optgroup, das koennen auch die Handy-Browser nativ). Arten mit nur einem Geraet bekommen keine eigene Ueberschrift - fuenfzehn Gruppen mit je einem Eintrag waeren unuebersichtlicher als die flache Liste -, sie sammeln sich am Ende unter "Einzelne". Dazu ein Namensputz fuer die Anzeige, ohne die Datenbank anzufassen: das u_-Praefix aus den Tahoma-Beschriftungen faellt weg, ebenso eine angehaengte einstellige Kanalnummer, und Unterstriche werden zu Leerzeichen. Aus "u_Wozi Terrassentuer" wird "Wozi Terrassentuer", aus "Power_EG_EM_0" wird "Power EG EM". Bewusst nur die einstellige Endung - "go-eCharger_270003" traegt seine Seriennummer und behaelt sie. Beschriftungen, die danach doppelt waeren, bekommen die Geraeteart dazu: die Tahoma-Box nennt sowohl den Rollladen als auch den Sonnenenergie-Sensor "Terasse", in der Liste untereinander waren sie nicht zu unterscheiden. Daraus wird "Terasse (Rollladen)" und "Terasse (Licht)". Die Beschriftung entsteht an einer Stelle und wird von Editor und Uebersicht geteilt - sonst stuende in der Auswahlliste "Wozi Terrassentuer" und im Satz darunter weiter "u_Wozi Terrassentuer". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+57
-13
@@ -63,12 +63,60 @@ function ersterBefehl() {
|
||||
|
||||
function optionListe(select, eintraege, gewaehlt) {
|
||||
select.innerHTML = "";
|
||||
eintraege.forEach(e => {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = e.value;
|
||||
opt.text = e.text;
|
||||
if (String(e.value) === String(gewaehlt)) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
eintraege.forEach(e => select.appendChild(option(e, gewaehlt)));
|
||||
}
|
||||
|
||||
function option(e, gewaehlt) {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = e.value;
|
||||
opt.text = e.text;
|
||||
if (String(e.value) === String(gewaehlt)) opt.selected = true;
|
||||
return opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Geraeteliste nach Geraeteart gruppiert.
|
||||
*
|
||||
* Bei ueber fuenfzig Geraeten ist die flache Liste der Engpass: dreizehn
|
||||
* Thermostate und elf Jalousien stehen sonst als vierundzwanzig gleich
|
||||
* aussehende Zeilen untereinander. Arten mit nur einem Geraet bekommen
|
||||
* keine eigene Ueberschrift - fuenfzehn Gruppen mit je einem Eintrag waeren
|
||||
* unuebersichtlicher als die flache Liste. Sie sammeln sich am Ende.
|
||||
*/
|
||||
function geraeteGruppen(geraete) {
|
||||
const nachArt = new Map();
|
||||
geraete.forEach(d => {
|
||||
if (!nachArt.has(d.type)) nachArt.set(d.type, []);
|
||||
nachArt.get(d.type).push(d);
|
||||
});
|
||||
const gruppen = [];
|
||||
const einzelne = [];
|
||||
Array.from(nachArt.keys()).sort((a, b) => a.localeCompare(b, "de")).forEach(art => {
|
||||
const liste = nachArt.get(art);
|
||||
if (liste.length > 1) gruppen.push({ titel: art + " (" + liste.length + ")", geraete: liste });
|
||||
else einzelne.push(liste[0]);
|
||||
});
|
||||
if (einzelne.length) {
|
||||
einzelne.sort((a, b) => a.label.localeCompare(b.label, "de"));
|
||||
gruppen.push({ titel: "Einzelne", geraete: einzelne });
|
||||
}
|
||||
return gruppen;
|
||||
}
|
||||
|
||||
/** Auswahlliste mit Zwischenueberschriften je Geraeteart fuellen. */
|
||||
function geraeteListe(select, geraete, gewaehlt) {
|
||||
select.innerHTML = "";
|
||||
const gruppen = geraeteGruppen(geraete);
|
||||
// Nur eine Gruppe? Dann waere die Ueberschrift blosse Zierde.
|
||||
if (gruppen.length < 2) {
|
||||
geraete.forEach(d => select.appendChild(option({ value: d.id, text: d.label }, gewaehlt)));
|
||||
return;
|
||||
}
|
||||
gruppen.forEach(g => {
|
||||
const kopf = document.createElement("optgroup");
|
||||
kopf.label = g.titel;
|
||||
g.geraete.forEach(d => kopf.appendChild(option({ value: d.id, text: d.label }, gewaehlt)));
|
||||
select.appendChild(kopf);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,9 +224,7 @@ function conditionRow(gi, bi, bed) {
|
||||
// Geraet
|
||||
const geraet = document.createElement("select");
|
||||
geraet.className = "form-select";
|
||||
optionListe(geraet, autoDevices.filter(d => d.states.length)
|
||||
.map(d => ({ value: d.id, text: d.name })),
|
||||
dev ? dev.id : "");
|
||||
geraeteListe(geraet, autoDevices.filter(d => d.states.length), dev ? dev.id : "");
|
||||
geraet.onchange = () => {
|
||||
const neu = deviceById(Number(geraet.value));
|
||||
if (!neu || !neu.states.length) return;
|
||||
@@ -257,7 +303,7 @@ function conditionText() {
|
||||
const text = gruppe.map(bed => {
|
||||
const treffer = stateById(bed.state_id);
|
||||
if (!treffer) return "?";
|
||||
let s = treffer.device.name + ": " + treffer.state.name + " "
|
||||
let s = treffer.device.label + ": " + treffer.state.name + " "
|
||||
+ operatorLabel(treffer.state, bed.operator) + " " + bed.value;
|
||||
if (treffer.state.unit) s += " " + treffer.state.unit;
|
||||
return s;
|
||||
@@ -292,9 +338,7 @@ function actionRow(ai, aktion) {
|
||||
|
||||
const geraet = document.createElement("select");
|
||||
geraet.className = "form-select";
|
||||
optionListe(geraet, autoDevices.filter(d => d.commands.length)
|
||||
.map(d => ({ value: d.id, text: d.name })),
|
||||
dev ? dev.id : "");
|
||||
geraeteListe(geraet, autoDevices.filter(d => d.commands.length), dev ? dev.id : "");
|
||||
geraet.onchange = () => {
|
||||
const neu = deviceById(Number(geraet.value));
|
||||
if (!neu || !neu.commands.length) return;
|
||||
|
||||
Reference in New Issue
Block a user