iobroker.alias-workbench 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -98
- package/admin/css/werkbank.css +88 -0
- package/admin/i18n/de.json +766 -1
- package/admin/i18n/en.json +766 -1
- package/admin/i18n/es.json +766 -1
- package/admin/i18n/fr.json +766 -1
- package/admin/i18n/it.json +766 -1
- package/admin/i18n/nl.json +766 -1
- package/admin/i18n/pl.json +766 -1
- package/admin/i18n/pt.json +766 -1
- package/admin/i18n/ru.json +766 -1
- package/admin/i18n/uk.json +766 -1
- package/admin/i18n/zh-cn.json +766 -1
- package/admin/js/ablage.js +118 -0
- package/admin/js/attrappe.js +749 -0
- package/admin/js/baum.js +52 -5
- package/admin/js/detail.js +64 -3
- package/admin/js/entwurf.js +246 -31
- package/admin/js/ergebnis.js +77 -2
- package/admin/js/katalog.js +235 -40
- package/admin/js/mqtt.js +297 -27
- package/admin/js/musternamen.js +70 -26
- package/admin/js/objekte.js +2 -0
- package/admin/js/quellentausch.js +823 -16
- package/admin/js/schreiben.js +3 -2
- package/admin/js/sprache.js +11 -8
- package/admin/js/vorlagen.js +8 -3
- package/admin/js/vorlagenblatt.js +228 -64
- package/admin/js/werte.js +294 -5
- package/admin/js/zielleiste.js +19 -10
- package/admin/js/zuordnung.js +8 -7
- package/admin/js/zustand.js +32 -0
- package/admin/js/zustandsliste.js +9 -2
- package/admin/tab.html +24 -0
- package/admin/vorlagen/hm-dimmer.json +32 -8
- package/admin/vorlagen/hm-fensterkontakt-hm.json +20 -5
- package/admin/vorlagen/hm-fensterkontakt-hmip.json +28 -7
- package/admin/vorlagen/hm-heizgruppe.json +38 -11
- package/admin/vorlagen/hm-heizkoerper.json +42 -12
- package/admin/vorlagen/hm-rollladen.json +28 -7
- package/admin/vorlagen/hm-schaltaktor-lampe.json +24 -6
- package/admin/vorlagen/hm-schaltaktor-mehrfach.json +32 -8
- package/admin/vorlagen/hm-schaltaktor-steckdose.json +24 -6
- package/admin/vorlagen/hm-temperatur-feuchte.json +8 -2
- package/admin/vorlagen/hm-wandthermostat.json +36 -9
- package/admin/vorlagen/messpunkt.json +40 -10
- package/admin/vorlagen/tasmota-lampe.json +48 -12
- package/admin/vorlagen/tasmota-mehrfach.json +40 -10
- package/admin/vorlagen/tasmota-rgb.json +36 -9
- package/admin/vorlagen/tasmota-steckdose.json +56 -14
- package/io-package.json +41 -28
- package/package.json +3 -3
- package/admin/sprachen/de.json +0 -685
- package/admin/sprachen/en.json +0 -685
package/admin/js/schreiben.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
waehle,
|
|
18
18
|
ordnerUnterAlias,
|
|
19
19
|
kennungtauglich,
|
|
20
|
+
ohneUmlaute,
|
|
20
21
|
kanalGruppen,
|
|
21
22
|
teilEntwurf,
|
|
22
23
|
aufteilBehaelter,
|
|
@@ -1448,8 +1449,8 @@ export function zeigeVerlegen(altVorgabe, zielVorgabe) {
|
|
|
1448
1449
|
body.appendChild(vorschau);
|
|
1449
1450
|
|
|
1450
1451
|
var saeubern = function (t) {
|
|
1451
|
-
return
|
|
1452
|
-
.replace(/[^\w.\-
|
|
1452
|
+
return ohneUmlaute(t).trim()
|
|
1453
|
+
.replace(/[^\w.\- ]/g, '_')
|
|
1453
1454
|
.replace(/\s+/g, '_')
|
|
1454
1455
|
.replace(/\.{2,}/g, '.')
|
|
1455
1456
|
.replace(/^\.+|\.+$/g, '');
|
package/admin/js/sprache.js
CHANGED
|
@@ -11,13 +11,12 @@ import { $ } from './basis.js';
|
|
|
11
11
|
export var expertenVorgabe = false;
|
|
12
12
|
|
|
13
13
|
/* ================== Sprachen ==================
|
|
14
|
-
Woerterbuch
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export var SPRACHEN = ['de', 'en'];
|
|
14
|
+
Ein Woerterbuch unter admin/i18n/, dieselben Dateien wie die
|
|
15
|
+
Einstellungsseite. Der Admin laedt sie fuer die Seite, der Reiter
|
|
16
|
+
hier per fetch. Eine Sprache gilt, wenn sie hier steht und die Datei
|
|
17
|
+
da ist. Faellt eine Uebersetzung aus, greift Englisch, danach der
|
|
18
|
+
Schluessel selbst — so bleibt die Oberflaeche bedienbar statt leer. */
|
|
19
|
+
export var SPRACHEN = ['en', 'de', 'ru', 'pt', 'nl', 'fr', 'it', 'es', 'pl', 'uk', 'zh-cn'];
|
|
21
20
|
var woerter = {};
|
|
22
21
|
var woerterEn = {};
|
|
23
22
|
export var sprache = 'en';
|
|
@@ -40,7 +39,7 @@ export function ladeSprache(fertig) {
|
|
|
40
39
|
var vorgabe = (navigator.language || 'en').slice(0, 2).toLowerCase();
|
|
41
40
|
|
|
42
41
|
function hole(code, ziel, danach) {
|
|
43
|
-
fetch('./
|
|
42
|
+
fetch('./i18n/' + code + '.json')
|
|
44
43
|
.then(function (r) { return r.ok ? r.json() : {}; })
|
|
45
44
|
.then(function (d) { Object.keys(d).forEach(function (k) { ziel[k] = d[k]; }); danach(); })
|
|
46
45
|
.catch(function () { danach(); });
|
|
@@ -149,6 +148,10 @@ export function beschrifteHtml() {
|
|
|
149
148
|
setz('#res .empty', tr('help.sources'));
|
|
150
149
|
setz('#btn-dry-write', tr('write.now'));
|
|
151
150
|
setz('#dlg-checks h3', tr('check.title'));
|
|
151
|
+
setz('#mock-titel', tr('tree.exportMock'));
|
|
152
|
+
setz('#btn-mock-go', tr('mock.save'));
|
|
153
|
+
setz('#mockin-titel', tr('tree.importMock'));
|
|
154
|
+
setz('#btn-mockin-go', tr('mockin.create'));
|
|
152
155
|
document.querySelectorAll('dialog [data-close]').forEach(function (b) {
|
|
153
156
|
b.textContent = tr('write.close');
|
|
154
157
|
});
|
package/admin/js/vorlagen.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { S } from './zustand.js';
|
|
8
8
|
import { D, $, el } from './basis.js';
|
|
9
|
-
import { hatPunkt, jsonVon, feldWert,
|
|
9
|
+
import { hatPunkt, jsonVon, feldWert, geraetePunkte, feldFormel } from './werte.js';
|
|
10
10
|
import { eigenerKanalName, merkeHakenVorgabe, kennungtauglich } from './entwurf.js';
|
|
11
11
|
import { tasmotaBefehle } from './mqtt.js';
|
|
12
12
|
import { socket } from './verbindung.js';
|
|
@@ -170,7 +170,7 @@ export function instanzenVon(v, kanal) {
|
|
|
170
170
|
var erf = (v.erkennung || {}).erforderlich || [];
|
|
171
171
|
var mitPh = erf.filter(function (e) { return e.indexOf(ph) > -1; });
|
|
172
172
|
|
|
173
|
-
var kurzNamen =
|
|
173
|
+
var kurzNamen = geraetePunkte(kanal).map(function (p) { return p.rel; });
|
|
174
174
|
|
|
175
175
|
/* Die Nummern der Ausgaenge muessen nicht als eigene Objekte
|
|
176
176
|
dastehen. Eine Tasmota meldet POWER1..POWER4 in tele/STATE, lange
|
|
@@ -575,7 +575,11 @@ export function wendeAn(v, kanal, gruende, instanz, auchOhneTreffer) {
|
|
|
575
575
|
caption: z.beschriftung || '',
|
|
576
576
|
dec: z.nachkommastellen === undefined ? undefined : String(z.nachkommastellen),
|
|
577
577
|
states: z.werteliste || undefined,
|
|
578
|
-
manuell: false, ausVorlage: z.name,
|
|
578
|
+
manuell: false, ausVorlage: z.name,
|
|
579
|
+
/* Zeichenkette oder { de, en }. Ganz mitnehmen, nicht aufloesen:
|
|
580
|
+
beim Speichern zurueck in eine Vorlage bleiben beide Sprachen,
|
|
581
|
+
und die Anzeige waehlt ueber sprachtext. */
|
|
582
|
+
hinweis: z.hinweis || '', wege: []
|
|
579
583
|
});
|
|
580
584
|
return;
|
|
581
585
|
}
|
|
@@ -650,6 +654,7 @@ export function wendeAn(v, kanal, gruende, instanz, auchOhneTreffer) {
|
|
|
650
654
|
states: z.werteliste || undefined,
|
|
651
655
|
manuell: false,
|
|
652
656
|
ausVorlage: z.name,
|
|
657
|
+
/* Wie oben: das Sprachobjekt bleibt ganz, sprachtext waehlt. */
|
|
653
658
|
hinweis: z.hinweis || '',
|
|
654
659
|
/* Alle Lesewege mitnehmen, nicht nur den, der heute gegriffen hat.
|
|
655
660
|
Wer aus diesem Geraet eine Vorlage macht, soll die Ersatzquellen
|
|
@@ -145,6 +145,124 @@ function vAendern(feld, wert) {
|
|
|
145
145
|
zeichneErgebnis();
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
/* Das Feld „Geraetetyp" — ein Suchfeld mit eigener Liste, nicht mehr ein
|
|
149
|
+
<select> mit 52 Eintraegen (C33).
|
|
150
|
+
|
|
151
|
+
Ein <select> laesst sich nicht durchsuchen. Die Beschriftung beginnt
|
|
152
|
+
mit dem deutschen Namen („Steckdose · socket"), also fand die
|
|
153
|
+
Tipp-Navigation des Browsers den Rohnamen nicht: wer `socket` tippte,
|
|
154
|
+
landete nirgends. Die Musterwahl beim Alias kann beides seit jeher;
|
|
155
|
+
hier nicht, und das war der Unterschied, ueber den Ricardo am
|
|
156
|
+
20.09.2026 gestolpert ist.
|
|
157
|
+
|
|
158
|
+
Dieselbe Bauart wie `musterwahl.js`: Eingabefeld plus eigene Liste,
|
|
159
|
+
kein <datalist> — dessen Fenster malt das Betriebssystem, und in
|
|
160
|
+
eingebetteten Ansichten landet es neben dem Fenster. Ohne Bewertung
|
|
161
|
+
allerdings: hier wird eine Vorlage bearbeitet, es gibt kein Geraet,
|
|
162
|
+
gegen das sich etwas bewerten liesse. */
|
|
163
|
+
function geraetetypFeld(v, eigen) {
|
|
164
|
+
var alle = (D ? Object.keys(D.patterns).sort() : []).map(function (m) {
|
|
165
|
+
/* Der Wert ist der TYP, nicht der Musterschluessel — und beschriftet
|
|
166
|
+
wird ebenfalls nach dem Typ. Fuer die drei Muster, die anders
|
|
167
|
+
heissen als ihr Typ (`blinds`, `mediaPlayer`, `levelSlider`),
|
|
168
|
+
kennt der Admin zum Schluessel keinen Beinamen, und im Feld stand
|
|
169
|
+
am Rollladen deshalb „blinds" statt „Jalousien · blind" (I37,
|
|
170
|
+
15.09.2026). */
|
|
171
|
+
return D.patterns[m].type || m;
|
|
172
|
+
}).filter(function (t, n, arr) { return arr.indexOf(t) === n; });
|
|
173
|
+
|
|
174
|
+
var wrap = el('div', 'feldwrap');
|
|
175
|
+
var feldEin = el('input', 'tx musterwahl');
|
|
176
|
+
feldEin.type = 'text';
|
|
177
|
+
feldEin.setAttribute('autocomplete', 'off');
|
|
178
|
+
feldEin.disabled = !eigen;
|
|
179
|
+
feldEin.value = v.geraetetyp ? musterZeile(v.geraetetyp) : '';
|
|
180
|
+
feldEin.placeholder = tr('tpls.noType');
|
|
181
|
+
wrap.appendChild(feldEin);
|
|
182
|
+
var liste = el('div', 'vorschlaege musterliste');
|
|
183
|
+
liste.hidden = true;
|
|
184
|
+
wrap.appendChild(liste);
|
|
185
|
+
|
|
186
|
+
var markiert = -1;
|
|
187
|
+
var treffer = [];
|
|
188
|
+
|
|
189
|
+
var setzen = function (typ) {
|
|
190
|
+
liste.hidden = true;
|
|
191
|
+
feldEin.value = typ ? musterZeile(typ) : '';
|
|
192
|
+
vAendern(function (x, w) { x.geraetetyp = w || undefined; }, typ);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
var malen = function () {
|
|
196
|
+
/* Beim Aufklappen steht der gewaehlte Typ im Feld — das ist kein
|
|
197
|
+
Suchtext, sonst saehe man nur den einen Eintrag und muesste erst
|
|
198
|
+
loeschen, um wechseln zu koennen. */
|
|
199
|
+
var roh = String(feldEin.value || '').trim();
|
|
200
|
+
var such = (roh && roh !== musterZeile(v.geraetetyp)) ? roh.toLowerCase() : '';
|
|
201
|
+
treffer = such
|
|
202
|
+
? alle.filter(function (t) {
|
|
203
|
+
/* Ueber Rohnamen UND Beinamen: „steckdose" findet socket,
|
|
204
|
+
„socket" auch. */
|
|
205
|
+
return t.toLowerCase().indexOf(such) > -1
|
|
206
|
+
|| String(musterName(t) || '').toLowerCase().indexOf(such) > -1;
|
|
207
|
+
})
|
|
208
|
+
: alle.slice();
|
|
209
|
+
|
|
210
|
+
liste.textContent = '';
|
|
211
|
+
/* „kein Typ" gehoert dazu — eine Vorlage ohne Geraetetyp ist
|
|
212
|
+
erlaubt, und ohne diesen Eintrag kaeme man nicht mehr zurueck. */
|
|
213
|
+
if (!such) {
|
|
214
|
+
var z0 = el('div', 'vz' + (v.geraetetyp ? '' : ' gewaehlt'));
|
|
215
|
+
z0.appendChild(el('span', null, tr('tpls.noType')));
|
|
216
|
+
z0.addEventListener('mousedown', function (ev) { ev.preventDefault(); setzen(''); });
|
|
217
|
+
liste.appendChild(z0);
|
|
218
|
+
}
|
|
219
|
+
if (!treffer.length) {
|
|
220
|
+
var leer = el('div', 'vz zurueck');
|
|
221
|
+
leer.appendChild(el('span', null, tr('pattern.noMatch', feldEin.value)));
|
|
222
|
+
liste.appendChild(leer);
|
|
223
|
+
}
|
|
224
|
+
treffer.forEach(function (t, n) {
|
|
225
|
+
var z = el('div', 'vz' + (n === markiert ? ' an' : '') + (t === v.geraetetyp ? ' gewaehlt' : ''));
|
|
226
|
+
z.appendChild(el('span', null, musterZeile(t)));
|
|
227
|
+
/* mousedown statt click: sonst greift der Fokusverlust zuerst und
|
|
228
|
+
die Liste ist weg, bevor der Klick ankommt. */
|
|
229
|
+
z.addEventListener('mousedown', function (ev) { ev.preventDefault(); setzen(t); });
|
|
230
|
+
liste.appendChild(z);
|
|
231
|
+
});
|
|
232
|
+
liste.hidden = false;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
feldEin.addEventListener('focus', function () { markiert = -1; malen(); });
|
|
236
|
+
feldEin.addEventListener('input', function () { markiert = -1; malen(); });
|
|
237
|
+
feldEin.addEventListener('blur', function () {
|
|
238
|
+
/* Was im Feld steht, ist nur Suchtext — gespeichert wird beim
|
|
239
|
+
Klicken. Beim Verlassen also den gewaehlten Typ zurueckschreiben,
|
|
240
|
+
sonst bliebe ein halbgetippter Rest stehen. */
|
|
241
|
+
setTimeout(function () {
|
|
242
|
+
liste.hidden = true;
|
|
243
|
+
feldEin.value = v.geraetetyp ? musterZeile(v.geraetetyp) : '';
|
|
244
|
+
}, 150);
|
|
245
|
+
});
|
|
246
|
+
feldEin.addEventListener('keydown', function (ev) {
|
|
247
|
+
if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {
|
|
248
|
+
ev.preventDefault();
|
|
249
|
+
if (liste.hidden) { malen(); return; }
|
|
250
|
+
markiert += (ev.key === 'ArrowDown' ? 1 : -1);
|
|
251
|
+
if (markiert < 0) { markiert = treffer.length - 1; }
|
|
252
|
+
if (markiert >= treffer.length) { markiert = 0; }
|
|
253
|
+
malen();
|
|
254
|
+
} else if (ev.key === 'Enter') {
|
|
255
|
+
ev.preventDefault();
|
|
256
|
+
if (treffer[markiert]) { setzen(treffer[markiert]); }
|
|
257
|
+
else if (treffer.length === 1) { setzen(treffer[0]); }
|
|
258
|
+
} else if (ev.key === 'Escape') {
|
|
259
|
+
liste.hidden = true;
|
|
260
|
+
feldEin.value = v.geraetetyp ? musterZeile(v.geraetetyp) : '';
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
return wrap;
|
|
264
|
+
}
|
|
265
|
+
|
|
148
266
|
export function zeichneVorlagenBlatt(host) {
|
|
149
267
|
/* Die Knoepfe unten gehoeren zum Geraet, nicht zur Vorlage. In dieser
|
|
150
268
|
Sicht waeren sie sonst noch auf das Geraet scharf, das vor dem
|
|
@@ -184,6 +302,17 @@ export function zeichneVorlagenBlatt(host) {
|
|
|
184
302
|
head.appendChild(links);
|
|
185
303
|
host.appendChild(head);
|
|
186
304
|
|
|
305
|
+
/* Der Kopfhinweis ist { de, en } oder eine Zeichenkette. Dieselbe
|
|
306
|
+
Wahl wie beim Namen: eingestellte Sprache, sonst Englisch. */
|
|
307
|
+
var kopfHinweis = sprachtext(v.hinweis);
|
|
308
|
+
if (kopfHinweis) {
|
|
309
|
+
var khw = el('div', 'hint');
|
|
310
|
+
khw.style.margin = '0 0 11px';
|
|
311
|
+
khw.style.whiteSpace = 'pre-wrap';
|
|
312
|
+
khw.textContent = kopfHinweis;
|
|
313
|
+
host.appendChild(khw);
|
|
314
|
+
}
|
|
315
|
+
|
|
187
316
|
/* --- Was das Einlesen bewirken wuerde --- */
|
|
188
317
|
if (vEinlesen) {
|
|
189
318
|
var iw = el('div', 'aside w');
|
|
@@ -294,31 +423,7 @@ export function zeichneVorlagenBlatt(host) {
|
|
|
294
423
|
|
|
295
424
|
var lt = el('label', 'feld');
|
|
296
425
|
lt.appendChild(el('span', 'feldlabel', tr('tpls.deviceType')));
|
|
297
|
-
|
|
298
|
-
st.disabled = !eigen;
|
|
299
|
-
st.appendChild(opt('', tr('tpls.noType')));
|
|
300
|
-
/* Wie im Speichern-Dialog: der Wert ist der Typ, nicht der
|
|
301
|
-
Musterschluessel. musterwahl.js loest es seit laengerem so. */
|
|
302
|
-
(D ? Object.keys(D.patterns).sort() : []).forEach(function (m) {
|
|
303
|
-
var typ = D.patterns[m].type || m;
|
|
304
|
-
/* Beschriftet wird nach dem TYP, nicht nach dem Musterschluessel.
|
|
305
|
-
|
|
306
|
-
Der Wert stand seit dem 11.09.2026 richtig da, die Beschriftung
|
|
307
|
-
nicht: `musterZeile(m)` schlug den Schluessel nach, und fuer die
|
|
308
|
-
drei Muster, die anders heissen als ihr Typ (`blinds`,
|
|
309
|
-
`mediaPlayer`, `levelSlider`), kennt der Admin keinen Beinamen.
|
|
310
|
-
Im Feld stand am Rollladen deshalb „blinds" statt „Jalousien ·
|
|
311
|
-
blind" - der Musterschluessel, den der Nutzer nirgends sonst
|
|
312
|
-
sieht. Die Musterwahl (musterwahl.js) geht seit jeher ueber den
|
|
313
|
-
Typ. Gefunden produktiv am 15.09.2026 (I37). */
|
|
314
|
-
var o = opt(typ, musterZeile(typ));
|
|
315
|
-
if (typ === v.geraetetyp) { o.selected = true; }
|
|
316
|
-
st.appendChild(o);
|
|
317
|
-
});
|
|
318
|
-
st.addEventListener('change', function () {
|
|
319
|
-
vAendern(function (x, w) { x.geraetetyp = w || undefined; }, st.value);
|
|
320
|
-
});
|
|
321
|
-
lt.appendChild(st);
|
|
426
|
+
lt.appendChild(geraetetypFeld(v, eigen));
|
|
322
427
|
kb.appendChild(lt);
|
|
323
428
|
|
|
324
429
|
/* Wozu das Geraet zaehlt.
|
|
@@ -376,6 +481,14 @@ export function zeichneVorlagenBlatt(host) {
|
|
|
376
481
|
ek.appendChild(eh);
|
|
377
482
|
var eb = el('div');
|
|
378
483
|
eb.style.padding = '9px 12px 11px';
|
|
484
|
+
var erkHinweis = sprachtext((v.erkennung || {}).hinweis);
|
|
485
|
+
if (erkHinweis) {
|
|
486
|
+
var ehw = el('div', 'hint');
|
|
487
|
+
ehw.style.whiteSpace = 'pre-wrap';
|
|
488
|
+
ehw.style.marginBottom = '9px';
|
|
489
|
+
ehw.textContent = erkHinweis;
|
|
490
|
+
eb.appendChild(ehw);
|
|
491
|
+
}
|
|
379
492
|
var listenFeld = function (label, wert, setzen, hilfe) {
|
|
380
493
|
var w = el('div');
|
|
381
494
|
w.style.marginBottom = '9px';
|
|
@@ -418,15 +531,25 @@ export function zeichneVorlagenBlatt(host) {
|
|
|
418
531
|
var zh = el('div', 'ch');
|
|
419
532
|
zh.appendChild(el('span', 'typ', tr('tpls.states')));
|
|
420
533
|
zh.appendChild(el('span', 'chip mut', tr('tpls.statesCount', (v.zustaende || []).length)));
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
534
|
+
/* Aufklappen geht bei allen Vorlagen, auch bei den mitgelieferten —
|
|
535
|
+
dort nur zum Ansehen.
|
|
536
|
+
|
|
537
|
+
Vorher war die Zeilenansicht an `eigen` gebunden: wer sehen wollte,
|
|
538
|
+
welche Ersatzquellen oder Formeln eine mitgelieferte Vorlage fuehrt,
|
|
539
|
+
musste erst „Eigene Kopie zum Bearbeiten" druecken und hatte danach
|
|
540
|
+
eine Kopie im Bestand, die er gar nicht wollte. Aufgefallen beim
|
|
541
|
+
Beheben von H9: der vierte Leseweg fuer die IP liess sich in der
|
|
542
|
+
Vorlagendatei ergaenzen, im Reiter aber nur ueber diesen Umweg
|
|
543
|
+
nachsehen (Ricardo, 20.09.2026). */
|
|
544
|
+
zh.appendChild(el('span', 'luecke'));
|
|
545
|
+
zh.appendChild(el('span', 'hint', eigen ? tr('tv.clickRow') : tr('tv.clickRowRead')));
|
|
425
546
|
zk.appendChild(zh);
|
|
426
547
|
(v.zustaende || []).forEach(function (z, nr) {
|
|
427
548
|
var auf = (vOffeneZeile === nr);
|
|
428
|
-
var r = el('div', 'slot
|
|
549
|
+
var r = el('div', 'slot vklick' + (auf ? ' offen' : ''));
|
|
429
550
|
r.style.gridTemplateColumns = '1fr 1.1fr 1.2fr 90px 15px';
|
|
551
|
+
var zeilenHinweis = sprachtext(z.hinweis);
|
|
552
|
+
if (zeilenHinweis) { r.title = zeilenHinweis; }
|
|
430
553
|
r.appendChild(el('span', 'sn', z.name));
|
|
431
554
|
r.appendChild(el('span', 'rx', z.rolle || '\u2014'));
|
|
432
555
|
var pw = el('span', 'rx');
|
|
@@ -436,23 +559,30 @@ export function zeichneVorlagenBlatt(host) {
|
|
|
436
559
|
Statusmarke - als Chip las er sich wie \u201eVorgabe" daneben. */
|
|
437
560
|
if (z.schreiben) { pw.appendChild(el('span', 'leise', ' \u2192 ' + z.schreiben)); }
|
|
438
561
|
if (z.absolut) { pw.appendChild(el('span', 'chip warn', tr('tpls.absolute'))); }
|
|
562
|
+
/* Dass eine Zeile Ersatzwege hat, stand hier nicht \u2014 man sah nur den
|
|
563
|
+
ersten (\u201eIP \u00b7 text \u00b7 tele.STATE \u00b7 IPAddress") und haette nie
|
|
564
|
+
vermutet, dass drei weitere dahinterliegen. Die Zahl ist die
|
|
565
|
+
Auskunft, die den Unterschied macht; welche es sind, steht
|
|
566
|
+
aufgeklappt (Ricardo, 20.09.2026). */
|
|
567
|
+
var ersatzZahl = ersatzListe(z).length;
|
|
568
|
+
if (ersatzZahl) {
|
|
569
|
+
pw.appendChild(el('span', 'chip mut', tr('tpls.fallbacks', ersatzZahl)));
|
|
570
|
+
}
|
|
439
571
|
r.appendChild(pw);
|
|
440
572
|
/* Dieselben zwei Angaben wie im Speichern-Dialog, gleiche Richtung
|
|
441
573
|
und dieselben Woerter — vorher stand hier „Pflicht/freiwillig"
|
|
442
574
|
und dort „Vorgabe / muss da sein", fuer genau dieselbe Sache. */
|
|
443
575
|
var mm = el('span', 'rx');
|
|
444
576
|
if (!z.vorgabeAus) { mm.appendChild(el('span', 'chip mut', tr('tpls.colDefault'))); }
|
|
445
|
-
if (istPflichtpunkt(
|
|
577
|
+
if (istPflichtpunkt(z)) { mm.appendChild(el('span', 'chip ok', tr('tpls.colRequired'))); }
|
|
446
578
|
r.appendChild(mm);
|
|
447
|
-
r.appendChild(el('span', 'ca2',
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
});
|
|
453
|
-
}
|
|
579
|
+
r.appendChild(el('span', 'ca2', auf ? '\u25be' : '\u25b8'));
|
|
580
|
+
r.addEventListener('click', function () {
|
|
581
|
+
vOffeneZeile = auf ? null : nr;
|
|
582
|
+
zeichneErgebnis();
|
|
583
|
+
});
|
|
454
584
|
zk.appendChild(r);
|
|
455
|
-
if (
|
|
585
|
+
if (auf) { zk.appendChild(vZeilenDetail(z, nr, eigen)); }
|
|
456
586
|
});
|
|
457
587
|
|
|
458
588
|
if (eigen) {
|
|
@@ -696,9 +826,28 @@ function anzeigeBlock(hole, setze, platzhalter) {
|
|
|
696
826
|
|
|
697
827
|
/* Zaehlt dieser Datenpunkt fuer die Erkennung? Nicht aus optional
|
|
698
828
|
abgelesen, sondern aus der Pflichtliste — die ist die Wahrheit. */
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
829
|
+
/* Ist diese Zeile Pflicht? Das steht an der Zeile selbst (`optional`),
|
|
830
|
+
nicht in der Erkennungsliste.
|
|
831
|
+
|
|
832
|
+
Bis zum 02.10.2026 las diese Funktion `erkennung.erforderlich` — also
|
|
833
|
+
die Frage „muss das Geraet diesen Punkt haben, damit die Vorlage
|
|
834
|
+
ueberhaupt greift". Das ist eine andere Frage als „darf diese Zeile
|
|
835
|
+
beim Anwenden fehlen", und beide Antworten gehen in den Vorlagen
|
|
836
|
+
weit auseinander: an der HmIP-Heizgruppe sind SET, ACTUAL, HUMIDITY
|
|
837
|
+
und VALVE Pflicht, in der Erkennungsliste steht aber nur
|
|
838
|
+
`1.SET_POINT_TEMPERATURE` — also stand eine Marke statt vier
|
|
839
|
+
(Ricardo, 02.10.2026). Nachgezaehlt wichen **16 von 17** Vorlagen ab.
|
|
840
|
+
|
|
841
|
+
Teils ist das Absicht: `tasmota-lampe` schreibt eigens, `stat.POWER`
|
|
842
|
+
stehe bewusst nicht in der Erkennungsliste, weil der mqtt-Adapter den
|
|
843
|
+
Punkt erst beim ersten Schalten anlegt — gelesen wird ersatzweise aus
|
|
844
|
+
`tele.STATE`. Pflicht ist die Zeile trotzdem, und ueber den Hauptweg
|
|
845
|
+
war das nie zu sehen.
|
|
846
|
+
|
|
847
|
+
Die Erkennungsbedingungen stehen eigens im Kasten „Erkennung" darueber,
|
|
848
|
+
samt Zaehler; sie brauchen diese Marke nicht. */
|
|
849
|
+
function istPflichtpunkt(z) {
|
|
850
|
+
return !z.optional;
|
|
702
851
|
}
|
|
703
852
|
|
|
704
853
|
/* lesenSonst darf ein Punktname, ein Objekt oder eine Liste sein — alle
|
|
@@ -720,9 +869,16 @@ function schreibeErsatz(z, liste) {
|
|
|
720
869
|
z.lesenSonst = (liste.length === 1) ? liste[0] : liste;
|
|
721
870
|
}
|
|
722
871
|
|
|
723
|
-
function vZeilenDetail(z, nr) {
|
|
872
|
+
function vZeilenDetail(z, nr, eigen) {
|
|
724
873
|
var v = vArbeitsstand();
|
|
725
874
|
var d = el('div', 'detail');
|
|
875
|
+
var zeilenHinweis = sprachtext(z.hinweis);
|
|
876
|
+
if (zeilenHinweis) {
|
|
877
|
+
var hw0 = el('div', 'hint');
|
|
878
|
+
hw0.style.whiteSpace = 'pre-wrap';
|
|
879
|
+
hw0.textContent = zeilenHinweis;
|
|
880
|
+
d.appendChild(hw0);
|
|
881
|
+
}
|
|
726
882
|
|
|
727
883
|
/* Genau der Aufbau des Detailblocks am Geraet: Name, liest aus,
|
|
728
884
|
schreibt nach, Formel, Schreibformel, Rolle, Anzeige. Nur was ein
|
|
@@ -894,27 +1050,20 @@ function vZeilenDetail(z, nr) {
|
|
|
894
1050
|
zeile2.appendChild(haken(tr('tpls.colDefault'), !z.vorgabeAus,
|
|
895
1051
|
function (zz, an) { if (an) { delete zz.vorgabeAus; } else { zz.vorgabeAus = true; } }));
|
|
896
1052
|
|
|
897
|
-
/*
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
} else {
|
|
912
|
-
zz.optional = true;
|
|
913
|
-
if (i > -1) { liste.splice(i, 1); }
|
|
914
|
-
var j = zz.schreiben ? liste.indexOf(zz.schreiben) : -1;
|
|
915
|
-
if (j > -1) { liste.splice(j, 1); }
|
|
916
|
-
}
|
|
917
|
-
w.erkennung.erforderlich = liste;
|
|
1053
|
+
/* Der Haken setzt nur noch `optional` an der Zeile — also genau das,
|
|
1054
|
+
was er behauptet.
|
|
1055
|
+
|
|
1056
|
+
Vorher schrieb er zusaetzlich in `erkennung.erforderlich`, „damit
|
|
1057
|
+
Liste und Zeile nicht Verschiedenes behaupten". Das sind aber zwei
|
|
1058
|
+
verschiedene Fragen: ob ein Geraet einen Punkt haben muss, damit die
|
|
1059
|
+
Vorlage ueberhaupt greift, und ob eine Zeile beim Anwenden fehlen
|
|
1060
|
+
darf. Wer hier hakte, verengte unbemerkt die Erkennung — bei
|
|
1061
|
+
`tasmota-lampe` haette das Anhaken von SET die Vorlage an
|
|
1062
|
+
`stat.POWER` gebunden, das es an einem frisch eingebundenen Geraet
|
|
1063
|
+
noch gar nicht gibt. Die Erkennungsliste wird im Kasten „Erkennung"
|
|
1064
|
+
darueber gepflegt, mit eigenem Feld. */
|
|
1065
|
+
zeile2.appendChild(haken(tr('tpls.colRequired'), istPflichtpunkt(z), function (zz, an) {
|
|
1066
|
+
if (an) { delete zz.optional; } else { zz.optional = true; }
|
|
918
1067
|
}));
|
|
919
1068
|
|
|
920
1069
|
zeile2.appendChild(haken(tr('tpls.absolute'), !!z.absolut,
|
|
@@ -929,6 +1078,21 @@ function vZeilenDetail(z, nr) {
|
|
|
929
1078
|
var hw = el('div', 'sugg');
|
|
930
1079
|
hw.textContent = tr('tv.flagsHelp');
|
|
931
1080
|
dtZeile(d, '', hw);
|
|
1081
|
+
|
|
1082
|
+
/* Eine mitgelieferte Vorlage wird angesehen, nicht geaendert.
|
|
1083
|
+
|
|
1084
|
+
Gesperrt wird am fertigen Block, nicht an jedem der rund dreissig
|
|
1085
|
+
Felder einzeln: so kann keines vergessen werden, wenn spaeter eines
|
|
1086
|
+
dazukommt. Ohne Eingabemoeglichkeit feuert auch kein `change`, also
|
|
1087
|
+
entsteht gar kein Arbeitsstand — wer nur nachsieht, hat hinterher
|
|
1088
|
+
keine ungewollte Kopie im Bestand. */
|
|
1089
|
+
if (!eigen) {
|
|
1090
|
+
Array.prototype.forEach.call(d.querySelectorAll('input, select, textarea, button'),
|
|
1091
|
+
function (x) { x.disabled = true; });
|
|
1092
|
+
var ro = el('div', 'hint');
|
|
1093
|
+
ro.textContent = tr('tv.readOnlyRow');
|
|
1094
|
+
d.insertBefore(ro, d.firstChild);
|
|
1095
|
+
}
|
|
932
1096
|
return d;
|
|
933
1097
|
}
|
|
934
1098
|
|