iobroker.alias-workbench 0.9.0 → 0.9.8
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 +44 -5
- package/admin/geraetewissen/tasmota-befehle.json +3 -1
- package/admin/i18n/de.json +17 -6
- package/admin/i18n/en.json +17 -6
- package/admin/js/aufzaehlungen.js +11 -1
- package/admin/js/baum.js +90 -32
- package/admin/js/detail.js +18 -3
- package/admin/js/entwurf.js +176 -42
- package/admin/js/enums.js +50 -7
- package/admin/js/ergebnis.js +47 -10
- package/admin/js/katalog.js +12 -3
- package/admin/js/mqtt.js +76 -13
- package/admin/js/musterwahl.js +10 -0
- package/admin/js/objekte.js +29 -3
- package/admin/js/pruefungen.js +10 -2
- package/admin/js/quellentausch.js +31 -2
- package/admin/js/schreiben.js +209 -24
- package/admin/js/sprache.js +51 -7
- package/admin/js/start.js +32 -2
- package/admin/js/vorlagen.js +92 -4
- package/admin/js/vorlagenblatt.js +193 -23
- package/admin/js/werte.js +113 -6
- package/admin/js/zuordnung.js +30 -9
- package/admin/js/zustandsliste.js +14 -10
- package/admin/tab.html +17 -3
- package/admin/vorlagen/hm-dimmer.json +1 -1
- package/admin/vorlagen/hm-schaltaktor-lampe.json +2 -2
- package/admin/vorlagen/hm-schaltaktor-mehrfach.json +2 -2
- package/admin/vorlagen/hm-schaltaktor-steckdose.json +2 -2
- package/io-package.json +27 -1
- package/package.json +1 -1
package/admin/js/schreiben.js
CHANGED
|
@@ -6,7 +6,7 @@ import { S } from './zustand.js';
|
|
|
6
6
|
import { socket } from './verbindung.js';
|
|
7
7
|
import { $, el } from './basis.js';
|
|
8
8
|
import { tr, txt } from './sprache.js';
|
|
9
|
-
import { enums, ladeEnums } from './enums.js';
|
|
9
|
+
import { enums, ladeEnums, enumsUnbekannt } from './enums.js';
|
|
10
10
|
import { enumsVon } from './aufzaehlungen.js';
|
|
11
11
|
import './katalog.js';
|
|
12
12
|
import { holeZweig, indexNeu , nachziehenErledigt } from './objekte.js';
|
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
kennungtauglich,
|
|
21
21
|
entwurfFuer,
|
|
22
22
|
aliasFuer,
|
|
23
|
-
knotenDa
|
|
23
|
+
knotenDa,
|
|
24
|
+
aboLoesen
|
|
24
25
|
} from './entwurf.js';
|
|
25
26
|
import { zeichneErgebnis } from './ergebnis.js';
|
|
26
27
|
|
|
@@ -221,7 +222,19 @@ export function baueObjekte(e) {
|
|
|
221
222
|
der Versionen haette nichts mehr zu greifen. */
|
|
222
223
|
var altN = (S.objects[ziel] && S.objects[ziel].native) || {};
|
|
223
224
|
var ausAlias = (e.kanal.indexOf('alias.') === 0);
|
|
224
|
-
|
|
225
|
+
/* Wie bei der Rolle eine Zeile weiter unten: mit dem alten Stand
|
|
226
|
+
beginnen und nur ueberschreiben, was wirklich beisteuert wird.
|
|
227
|
+
|
|
228
|
+
Vorher wurde `native` aus der Quellenansicht vollstaendig durch
|
|
229
|
+
`{ quelle }` ersetzt; Vorlage, Version und Geraetetyp kamen nur
|
|
230
|
+
zurueck, wenn gerade eine Vorlage griff. Ist sie geloescht oder
|
|
231
|
+
umbenannt, liefert `vorschlag` `null` — „Alias aktualisieren" bleibt
|
|
232
|
+
aber freigeschaltet, und die Herkunft war danach weg: kein Abzeichen
|
|
233
|
+
„gemerkt", womoeglich eine andere Vorlage bei der naechsten
|
|
234
|
+
Erkennung, und nichts mehr, woran ein Nachziehen der Versionen
|
|
235
|
+
greifen koennte. Gemessen 09.09.2026: aus fuenf Feldern wurde eins. */
|
|
236
|
+
var kanalNative = JSON.parse(JSON.stringify(altN));
|
|
237
|
+
if (!ausAlias) { kanalNative.quelle = e.kanal; }
|
|
225
238
|
if (e.vorlage) {
|
|
226
239
|
kanalNative.vorlage = e.vorlage;
|
|
227
240
|
kanalNative.vorlageVersion = e.vorlageVersion;
|
|
@@ -378,6 +391,36 @@ export function zuSchreiben(alleAusgaenge) {
|
|
|
378
391
|
Entwurf, benannt nach dem Kanal — nicht nach seiner Nummer. Aus
|
|
379
392
|
„Kanal 1" wird `Licht_Bar`, weil das der Name ist, den jemand ihm
|
|
380
393
|
gegeben hat. */
|
|
394
|
+
/* Raum und Funktion gehoeren an jeden Kanal, nicht nur an den
|
|
395
|
+
gezeigten.
|
|
396
|
+
|
|
397
|
+
Die Teil-Entwuerfe entstehen frisch aus `entwurfFuer` bzw.
|
|
398
|
+
`vorschlag` und trugen keins von beidem. `enumAenderungen` baute
|
|
399
|
+
deshalb fuer keinen einzigen Kanal ein Enum-Objekt: Wer oben einen
|
|
400
|
+
Raum einstellte und „Alle erzeugen" drueckte, bekam Kanaele ohne
|
|
401
|
+
Raum — der Einzelweg setzte ihn, der Sammelweg nicht.
|
|
402
|
+
|
|
403
|
+
Schlimmer war der zweite Fall: Fuer einen fremden Ausgang galt
|
|
404
|
+
`gewaehlt === ''`. Stand dessen Alias schon in einem Raum, fand ihn
|
|
405
|
+
`enumsVon`, und das gebaute Objekt trug ihn dort **aus**. Aus „ich
|
|
406
|
+
lege die anderen Ausgaenge auch an" wurde „ich nehme ihnen ihren
|
|
407
|
+
Raum weg" (gemessen 09.09.2026 an der Steckdosenleiste: Ausgang 2
|
|
408
|
+
verlor `enum.rooms.WBG30`).
|
|
409
|
+
|
|
410
|
+
Was ein Kanal schon hat, behaelt er — dieselbe Regel wie ueberall
|
|
411
|
+
sonst: der Bestand schlaegt den Vorschlag. Nur wer keine Zuordnung
|
|
412
|
+
hat, bekommt die eingestellte. */
|
|
413
|
+
var enumsUebertragen = function (v) {
|
|
414
|
+
if (!v || !v.ziel) { return v; }
|
|
415
|
+
[['rooms', 'raum', 'raumHer'], ['functions', 'funktion', 'funktionHer']]
|
|
416
|
+
.forEach(function (a) {
|
|
417
|
+
var eigen = enumsVon(v.ziel, a[0])[0] || '';
|
|
418
|
+
v[a[1]] = eigen || S.entwurf[a[1]] || '';
|
|
419
|
+
v[a[2]] = eigen ? 'bestand' : (v[a[1]] ? 'hand' : '');
|
|
420
|
+
});
|
|
421
|
+
return v;
|
|
422
|
+
};
|
|
423
|
+
|
|
381
424
|
if (alleAusgaenge && S.entwurf.kanalGeraete && S.entwurf.kanalGeraete.length > 1) {
|
|
382
425
|
/* Ein Ordner fuer das Geraet, darunter je Kanal ein Kanal — dieselbe
|
|
383
426
|
Form, die die Tasmota-Mehrfachvorlage seit jeher erzeugt. */
|
|
@@ -387,10 +430,18 @@ export function zuSchreiben(alleAusgaenge) {
|
|
|
387
430
|
var v = entwurfFuer(k.id, gem, S.entwurf.gemeinsamMitPlatz);
|
|
388
431
|
if (!v) { return null; }
|
|
389
432
|
v.zielOrdner = ordner;
|
|
390
|
-
|
|
391
|
-
|
|
433
|
+
/* Die Kennung, nicht der Anzeigename. „Licht Bar, oben" ergab eine
|
|
434
|
+
Kennung mit Leerzeichen und Komma, „Kueche.Decke" sogar eine
|
|
435
|
+
zusaetzliche Ebene samt Zwischenordner. Und der js-controller
|
|
436
|
+
lehnt so etwas nicht ab, er saeubert still: aus
|
|
437
|
+
`alias.0.wb[pruef]` wurde `alias.0.wb_pruef_`, der Rueckruf
|
|
438
|
+
meldete `null`. Das Objekt entstuende also unter einer anderen
|
|
439
|
+
Kennung als angezeigt (gemessen 08.09.2026). Der Name bleibt
|
|
440
|
+
davon unberuehrt — er steht als Beschriftung im Objekt. */
|
|
441
|
+
v.zielName = k.kennung || k.name;
|
|
442
|
+
v.ziel = ordner + '.' + v.zielName;
|
|
392
443
|
uebernehmeBestand(v);
|
|
393
|
-
return v;
|
|
444
|
+
return enumsUebertragen(v);
|
|
394
445
|
}).filter(Boolean);
|
|
395
446
|
}
|
|
396
447
|
if (!alleAusgaenge || !S.entwurf.instanzen || S.entwurf.instanzen.length < 2) { return [S.entwurf]; }
|
|
@@ -401,11 +452,41 @@ export function zuSchreiben(alleAusgaenge) {
|
|
|
401
452
|
v.zielOrdner = S.entwurf.zielOrdner;
|
|
402
453
|
v.zielName = ausgangName(v, n);
|
|
403
454
|
v.ziel = v.zielOrdner + '.' + v.zielName;
|
|
455
|
+
enumsUebertragen(v);
|
|
404
456
|
}
|
|
405
457
|
return v;
|
|
406
458
|
}).filter(Boolean);
|
|
407
459
|
}
|
|
408
460
|
|
|
461
|
+
/* Ein Objekt in die Liste, ohne ein vorhandenes zu verlieren.
|
|
462
|
+
|
|
463
|
+
Bei „Alle erzeugen" bauen mehrere Teil-Entwuerfe dasselbe Enum-Objekt,
|
|
464
|
+
jeder mit seiner eigenen Kennung darin. Die frueher hier stehende
|
|
465
|
+
Zeile `if (!liste.some(x => x.id === o.id)) liste.push(o)` warf das
|
|
466
|
+
zweite weg - von vier Ausgaengen landete einer im Raum, die anderen
|
|
467
|
+
drei fielen still unter den Tisch.
|
|
468
|
+
|
|
469
|
+
Gewoehnliche Objekte bleiben beim ersten: dort ist die Kennung
|
|
470
|
+
eindeutig, ein zweites waere derselbe Kanal. Nur Aufzaehlungen werden
|
|
471
|
+
vereinigt, und dabei gilt: eingetragen schlaegt ausgetragen. Ein
|
|
472
|
+
Mitglied, das ein Entwurf haben will, nimmt ihm kein anderer weg. */
|
|
473
|
+
function sammle(liste, o) {
|
|
474
|
+
var vorh = null;
|
|
475
|
+
liste.forEach(function (x) { if (!vorh && x.id === o.id) { vorh = x; } });
|
|
476
|
+
if (!vorh) { liste.push(o); return; }
|
|
477
|
+
if (!o.istEnum || !vorh.istEnum) { return; }
|
|
478
|
+
var m = ((vorh.obj.common || {}).members || []).slice();
|
|
479
|
+
((o.obj.common || {}).members || []).forEach(function (x) {
|
|
480
|
+
if (m.indexOf(x) === -1) { m.push(x); }
|
|
481
|
+
});
|
|
482
|
+
m.sort();
|
|
483
|
+
vorh.obj.common.members = m;
|
|
484
|
+
vorh.dazu = vorh.dazu || o.dazu;
|
|
485
|
+
vorh.weg = vorh.weg && o.weg;
|
|
486
|
+
vorh.ikonDazu = vorh.ikonDazu || o.ikonDazu;
|
|
487
|
+
vorh.neu = vorh.neu && o.neu;
|
|
488
|
+
}
|
|
489
|
+
|
|
409
490
|
export function zeigeTrockenlauf(alleAusgaenge) {
|
|
410
491
|
if (!S.entwurf) { return; }
|
|
411
492
|
S.trockenAlle = !!alleAusgaenge;
|
|
@@ -420,9 +501,7 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
420
501
|
var liste = [];
|
|
421
502
|
var probleme = [];
|
|
422
503
|
entwuerfe.forEach(function (en) {
|
|
423
|
-
baueObjekte(en).forEach(function (o) {
|
|
424
|
-
if (!liste.some(function (x) { return x.id === o.id; })) { liste.push(o); }
|
|
425
|
-
});
|
|
504
|
+
baueObjekte(en).forEach(function (o) { sammle(liste, o); });
|
|
426
505
|
pruefeSchreiben(en).forEach(function (pr) { probleme.push(pr); });
|
|
427
506
|
});
|
|
428
507
|
|
|
@@ -521,6 +600,17 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
521
600
|
body.appendChild(zwK);
|
|
522
601
|
}
|
|
523
602
|
|
|
603
|
+
/* Die Aufzaehlungen sind gerade nicht bekannt — dann wird auch keine
|
|
604
|
+
geschrieben. Das gehoert hierher und nicht in eine Sperre: der Alias
|
|
605
|
+
selbst braucht sie nicht, und aus einem stillen Datenverlust eine
|
|
606
|
+
stille Blockade zu machen waere kein Fortschritt (P8). */
|
|
607
|
+
if (enumsUnbekannt() && S.entwurf && (S.entwurf.raum || S.entwurf.funktion)) {
|
|
608
|
+
var ek = el('div', 'aside w');
|
|
609
|
+
ek.style.marginBottom = '11px';
|
|
610
|
+
ek.appendChild(el('b', null, tr('write.enumsUnknown')));
|
|
611
|
+
body.appendChild(ek);
|
|
612
|
+
}
|
|
613
|
+
|
|
524
614
|
if (weg.length) {
|
|
525
615
|
var wk = el('div', 'card');
|
|
526
616
|
wk.style.marginBottom = '11px';
|
|
@@ -582,10 +672,20 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
582
672
|
kn2.disabled = true;
|
|
583
673
|
kn2.textContent = tr('write.writing');
|
|
584
674
|
var offen2 = fehlend.length;
|
|
675
|
+
var mqFehler = [];
|
|
585
676
|
fehlend.forEach(function (fid) {
|
|
586
677
|
var t2 = fid.split('.cmnd.');
|
|
587
|
-
mqttEinzelnStill(t2[0], t2[1], function () {
|
|
678
|
+
mqttEinzelnStill(t2[0], t2[1], function (err) {
|
|
679
|
+
if (err) { mqFehler.push(fid + ': ' + err); }
|
|
588
680
|
if (--offen2 === 0) {
|
|
681
|
+
/* Was nicht entstanden ist, wird benannt — nicht gezaehlt.
|
|
682
|
+
Der Trockenlauf sperrt danach ohnehin wieder, aber ohne
|
|
683
|
+
diesen Satz suchte man den Grund am falschen Ende. */
|
|
684
|
+
if (mqFehler.length) {
|
|
685
|
+
kn2.disabled = false;
|
|
686
|
+
kn2.textContent = tr('write.retry');
|
|
687
|
+
kn2.title = mqFehler.join(' | ');
|
|
688
|
+
}
|
|
589
689
|
/* Erst den Entwurf neu aufbauen lassen, dann den
|
|
590
690
|
Trockenlauf noch einmal rechnen. Sofort geoeffnet zeigte
|
|
591
691
|
er den Rohentwurf, weil die Vorlage noch nicht wieder
|
|
@@ -811,6 +911,30 @@ export function zeichneLoeschen() {
|
|
|
811
911
|
hin.textContent = tr('del.hint');
|
|
812
912
|
body.appendChild(hin);
|
|
813
913
|
|
|
914
|
+
/* Liegen eigene Kanaele darunter?
|
|
915
|
+
|
|
916
|
+
Der Umfang nimmt alles unterhalb des Praefixes. Bei einem
|
|
917
|
+
`device`-Container sind das auch fremde Alias-Kanaele — ganze
|
|
918
|
+
Geraete, die mit dem gemeinten nichts zu tun haben. Die Liste zeigt
|
|
919
|
+
sie zwar mit Typ, aber der Hinweistext sprach nur von „Datenpunkten
|
|
920
|
+
darunter", und die Zahl oben sagt nur, wie viele Zeilen es sind.
|
|
921
|
+
Wer sie zaehlt, weiss nicht, dass er drei Geraete mitnimmt. */
|
|
922
|
+
var kanaeleDrunter = alle.filter(function (id) {
|
|
923
|
+
if (id === ziel) { return false; }
|
|
924
|
+
var o = S.objects[id];
|
|
925
|
+
return o && (o.type === 'channel' || o.type === 'device');
|
|
926
|
+
});
|
|
927
|
+
if (kanaeleDrunter.length) {
|
|
928
|
+
var kw = el('div', 'aside w');
|
|
929
|
+
kw.style.marginBottom = '11px';
|
|
930
|
+
kw.appendChild(el('b', null, tr('del.channelsBelow', kanaeleDrunter.length)));
|
|
931
|
+
var kl = el('div', 'hint');
|
|
932
|
+
kl.style.marginTop = '4px';
|
|
933
|
+
kl.textContent = kanaeleDrunter.map(function (x) { return x.slice(ziel.length + 1); }).join(', ');
|
|
934
|
+
kw.appendChild(kl);
|
|
935
|
+
body.appendChild(kw);
|
|
936
|
+
}
|
|
937
|
+
|
|
814
938
|
var gesch = geschwisterVon(ziel);
|
|
815
939
|
if (gesch.length) {
|
|
816
940
|
var gw = el('div', 'aside');
|
|
@@ -888,10 +1012,11 @@ export function loescheAlias() {
|
|
|
888
1012
|
b.disabled = true;
|
|
889
1013
|
b.textContent = tr('write.writing');
|
|
890
1014
|
|
|
891
|
-
var offen = alle.length, fehler = [];
|
|
1015
|
+
var offen = alle.length, fehler = [], wirklichWeg = [];
|
|
892
1016
|
alle.forEach(function (id) {
|
|
893
1017
|
socket.emit('delObject', id, function (err) {
|
|
894
1018
|
if (err) { fehler.push(id + ': ' + err); }
|
|
1019
|
+
else { wirklichWeg.push(id); }
|
|
895
1020
|
if (--offen === 0) {
|
|
896
1021
|
var body = $('#del-body');
|
|
897
1022
|
body.textContent = '';
|
|
@@ -903,8 +1028,23 @@ export function loescheAlias() {
|
|
|
903
1028
|
m.appendChild(el('b', null, tr('del.done', alle.length)));
|
|
904
1029
|
}
|
|
905
1030
|
body.appendChild(m);
|
|
906
|
-
|
|
907
|
-
|
|
1031
|
+
/* Nur austragen, was wirklich weg ist.
|
|
1032
|
+
|
|
1033
|
+
Vorher fielen alle Kennungen aus dem eigenen Bestand, egal ob
|
|
1034
|
+
das Loeschen geklappt hatte. Was in der Datenbank stehenblieb,
|
|
1035
|
+
war danach ueber die Werkbank nicht mehr zu greifen - sie hielt
|
|
1036
|
+
es fuer geloescht (gemessen 09.09.2026: `…Neu.WORKING` stand am
|
|
1037
|
+
System, fehlte aber im Vorrat). */
|
|
1038
|
+
wirklichWeg.forEach(function (x) { delete S.objects[x]; });
|
|
1039
|
+
/* `indexNeu()` statt nur zu sortieren.
|
|
1040
|
+
|
|
1041
|
+
An vier Stellen stand hier `S.keysSorted = Object.keys(...)`,
|
|
1042
|
+
obwohl `indexNeu` importiert ist. Das raeumt zusaetzlich
|
|
1043
|
+
`S.kleinIndex` und zieht die Objektzahl in der Kopfzeile nach.
|
|
1044
|
+
Ohne das behielt die Karte geloeschte Kennungen — `hatPunkt`
|
|
1045
|
+
lieferte Treffer auf Punkte, die es nicht mehr gab —, und die
|
|
1046
|
+
Zahl oben blieb stehen (gefunden 09.09.2026). */
|
|
1047
|
+
indexNeu();
|
|
908
1048
|
|
|
909
1049
|
/* Ordner, die dadurch leer geworden sind, mitnehmen — aber nur
|
|
910
1050
|
die eigenen Zwischenebenen unterhalb von alias.0, und nur
|
|
@@ -920,11 +1060,22 @@ export function loescheAlias() {
|
|
|
920
1060
|
} else {
|
|
921
1061
|
b.hidden = true;
|
|
922
1062
|
}
|
|
1063
|
+
/* Nach einem Teilfehler wird nicht aufgeraeumt und das Ziel
|
|
1064
|
+
bleibt stehen: „Noch einmal versuchen" ruft `loescheAlias`,
|
|
1065
|
+
und das beginnt mit `if (!S.loeschZiel) return;` — ohne Ziel
|
|
1066
|
+
war der Knopf eine Attrappe. Aufraeumen waere ohnehin falsch,
|
|
1067
|
+
solange noch etwas darunter liegt. */
|
|
1068
|
+
if (fehler.length) {
|
|
1069
|
+
zeichneBaum();
|
|
1070
|
+
zeichneErgebnis();
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
923
1073
|
leereEnumsRaeumen(enumsMitzunehmen, alle, function () {
|
|
924
1074
|
leereOrdnerRaeumen(ziel, function () {
|
|
925
1075
|
S.loeschZiel = null;
|
|
926
1076
|
S.entwurf = null;
|
|
927
1077
|
S.current = null;
|
|
1078
|
+
aboLoesen();
|
|
928
1079
|
zeichneBaum();
|
|
929
1080
|
zeichneErgebnis();
|
|
930
1081
|
});
|
|
@@ -1174,11 +1325,28 @@ export function zeigeVerlegen(altVorgabe, zielVorgabe) {
|
|
|
1174
1325
|
b.disabled = true;
|
|
1175
1326
|
return;
|
|
1176
1327
|
}
|
|
1177
|
-
|
|
1328
|
+
/* Ein Ziel, das es schon gibt — auch eines ohne eigenes
|
|
1329
|
+
Kanalobjekt. `S.objects` allein reicht nicht: legt man Aliaspunkte
|
|
1330
|
+
von Hand im Admin an, entsteht `alias.0.X.Y.PUNKT`, ohne dass
|
|
1331
|
+
`alias.0.X.Y` als Objekt existiert. Der Baum zeigt den Knoten
|
|
1332
|
+
trotzdem, und das Verlegen schrieb bisher mitten hinein und
|
|
1333
|
+
ueberschrieb vorhandene Punkte gleichen Namens (E31, T23). */
|
|
1334
|
+
if (knotenDa(neu)) {
|
|
1178
1335
|
vorschau.appendChild(el('div', 'aside w', tr('move.exists', neu)));
|
|
1179
1336
|
b.disabled = true;
|
|
1180
1337
|
return;
|
|
1181
1338
|
}
|
|
1339
|
+
/* Und kein Ziel, das mit der Quelle verschachtelt ist.
|
|
1340
|
+
|
|
1341
|
+
`alias.0.X` nach `alias.0.X.Sub`: `verlegeUmfang` enthaelt
|
|
1342
|
+
`alias.0.X`, und das Loeschen am Ende nimmt genau den Elternknoten
|
|
1343
|
+
des eben verlegten Alias mit. Umgekehrt genauso — dann laege das
|
|
1344
|
+
Ziel im Umfang und wuerde gleich wieder geloescht. */
|
|
1345
|
+
if (neu.indexOf(alt + '.') === 0 || alt.indexOf(neu + '.') === 0) {
|
|
1346
|
+
vorschau.appendChild(el('div', 'aside w', tr('move.nested')));
|
|
1347
|
+
b.disabled = true;
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1182
1350
|
b.disabled = false;
|
|
1183
1351
|
|
|
1184
1352
|
var umfang = verlegeUmfang(alt);
|
|
@@ -1360,7 +1528,7 @@ export function verlegeAlias(alt, neu) {
|
|
|
1360
1528
|
blieb aus, und ein zweites Verlegen war nicht moeglich. */
|
|
1361
1529
|
S.objects[zielId] = o;
|
|
1362
1530
|
}
|
|
1363
|
-
if (--offen === 0) {
|
|
1531
|
+
if (--offen === 0) { indexNeu(); weiter(); }
|
|
1364
1532
|
});
|
|
1365
1533
|
});
|
|
1366
1534
|
|
|
@@ -1386,7 +1554,16 @@ export function verlegeAlias(alt, neu) {
|
|
|
1386
1554
|
enumArbeit.forEach(function (a) {
|
|
1387
1555
|
socket.emit('setObject', a.id, a.obj, function (err) {
|
|
1388
1556
|
if (err) { fehler.push(a.id + ': ' + err); }
|
|
1389
|
-
if (--offen2 === 0) {
|
|
1557
|
+
if (--offen2 === 0) {
|
|
1558
|
+
/* Derselbe Abbruch wie eine Stufe darueber: geht etwas schief,
|
|
1559
|
+
wird nicht geloescht. Vorher lief `loeschen()` trotzdem —
|
|
1560
|
+
der alte Alias war weg, der neue stand in keiner Aufzaehlung,
|
|
1561
|
+
und die Zuordnung war damit verloren (gemessen 09.09.2026:
|
|
1562
|
+
`enum.rooms.WBP3` blieb leer zurueck). Zwei Aliase sind
|
|
1563
|
+
unschoen, aber reparierbar; eine verlorene Zuordnung nicht. */
|
|
1564
|
+
if (fehler.length) { return melden(fehler); }
|
|
1565
|
+
loeschen();
|
|
1566
|
+
}
|
|
1390
1567
|
});
|
|
1391
1568
|
});
|
|
1392
1569
|
}
|
|
@@ -1400,7 +1577,7 @@ export function verlegeAlias(alt, neu) {
|
|
|
1400
1577
|
if (err) { fehler.push(id + ': ' + err); }
|
|
1401
1578
|
if (--offen3 === 0) {
|
|
1402
1579
|
weg.forEach(function (x) { delete S.objects[x]; });
|
|
1403
|
-
|
|
1580
|
+
indexNeu();
|
|
1404
1581
|
leereOrdnerRaeumen(alt, function () {
|
|
1405
1582
|
S.current = neu;
|
|
1406
1583
|
S.entwurf = null;
|
|
@@ -1428,9 +1605,15 @@ export function verlegeAlias(alt, neu) {
|
|
|
1428
1605
|
body.appendChild(m);
|
|
1429
1606
|
/* Nur in diesem Dialog verschwinden lassen - beim naechsten Oeffnen
|
|
1430
1607
|
baut ihn `zeigeVerlegen` wieder auf. Vorher blieb er dauerhaft
|
|
1431
|
-
versteckt, und ein zweites Verlegen ging nicht mehr.
|
|
1432
|
-
|
|
1608
|
+
versteckt, und ein zweites Verlegen ging nicht mehr.
|
|
1609
|
+
|
|
1610
|
+
Nach einem Fehlschlag bleibt er als „Noch einmal versuchen" stehen:
|
|
1611
|
+
das Neue ist dann schon angelegt, das Alte steht noch, und ein
|
|
1612
|
+
zweiter Anlauf schreibt beides gefahrlos nach - genau das, was ein
|
|
1613
|
+
kurzer Aussetzer beim Schreiben der Aufzaehlung braucht. */
|
|
1433
1614
|
b.disabled = false;
|
|
1615
|
+
if (f.length) { b.hidden = false; b.textContent = tr('write.retry'); }
|
|
1616
|
+
else { b.hidden = true; }
|
|
1434
1617
|
ladeEnums(function () {
|
|
1435
1618
|
zeichneBaum();
|
|
1436
1619
|
/* Den Alias unter der neuen Kennung wieder aufschlagen.
|
|
@@ -1473,7 +1656,7 @@ export function leereOrdnerRaeumen(weg, fertig) {
|
|
|
1473
1656
|
if (!o || o.type !== 'folder' || belegt) { return fertig(); }
|
|
1474
1657
|
socket.emit('delObject', pfad, function () {
|
|
1475
1658
|
delete S.objects[pfad];
|
|
1476
|
-
|
|
1659
|
+
indexNeu();
|
|
1477
1660
|
weiter();
|
|
1478
1661
|
});
|
|
1479
1662
|
})();
|
|
@@ -1487,9 +1670,7 @@ export function schreibeObjekte() {
|
|
|
1487
1670
|
var liste = [];
|
|
1488
1671
|
var schlecht = 0;
|
|
1489
1672
|
entwuerfe2.forEach(function (en) {
|
|
1490
|
-
baueObjekte(en).forEach(function (o) {
|
|
1491
|
-
if (!liste.some(function (x) { return x.id === o.id; })) { liste.push(o); }
|
|
1492
|
-
});
|
|
1673
|
+
baueObjekte(en).forEach(function (o) { sammle(liste, o); });
|
|
1493
1674
|
schlecht += pruefeSchreiben(en).length;
|
|
1494
1675
|
});
|
|
1495
1676
|
if (schlecht) { return; }
|
|
@@ -1560,7 +1741,11 @@ export function schreibeObjekte() {
|
|
|
1560
1741
|
}
|
|
1561
1742
|
$('#btn-dry-write').hidden = true;
|
|
1562
1743
|
}
|
|
1563
|
-
|
|
1744
|
+
/* Nur bei Erfolg. Der Wiederholen-Knopf ruft `schreibeObjekte`
|
|
1745
|
+
direkt, und das filtert dann eine leere Liste: die verwaisten
|
|
1746
|
+
Punkte blieben fuer immer stehen, und die Erfolgsmeldung zaehlte
|
|
1747
|
+
sie nicht mehr mit (gemessen 09.09.2026). */
|
|
1748
|
+
if (!fehler.length) { S.loeschListe = []; }
|
|
1564
1749
|
|
|
1565
1750
|
/* Die Marke „geaendert“ hat ihre Aufgabe erfuellt.
|
|
1566
1751
|
|
package/admin/js/sprache.js
CHANGED
|
@@ -55,11 +55,27 @@ export function ladeSprache(fertig) {
|
|
|
55
55
|
var beantwortet = false;
|
|
56
56
|
socket.emit('getObject', 'system.config', function (err, obj) {
|
|
57
57
|
if (beantwortet) { return; }
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
/* Auch eine spaete Antwort gilt noch.
|
|
59
|
+
|
|
60
|
+
Nach 2,5 Sekunden geht es ohne weiter — richtig, sonst haengt der
|
|
61
|
+
Reiter an einem stillen Controller. Die Antwort danach wurde aber
|
|
62
|
+
ganz verworfen, und damit blieb `expertenVorgabe` auf „aus":
|
|
63
|
+
Ohne gesetzten `sessionStorage` fehlten alle Expertenobjekte im
|
|
64
|
+
Baum, ohne dass irgendwo stand, warum. Die Sprache umzustellen,
|
|
65
|
+
nachdem schon beschriftet ist, waere ein Sprung vor den Augen —
|
|
66
|
+
die bleibt beim Naechstbesten; der Expertenmodus wird nachgezogen
|
|
67
|
+
und der Baum neu gezeichnet, wenn er sich unterscheidet. */
|
|
68
|
+
var expNeu = !!(!err && obj && obj.common && obj.common.expertMode);
|
|
62
69
|
var l = (!err && obj && obj.common && obj.common.language) || vorgabe;
|
|
70
|
+
if (beantwortet) {
|
|
71
|
+
if (expNeu !== expertenVorgabe) {
|
|
72
|
+
expertenVorgabe = expNeu;
|
|
73
|
+
if (typeof spaeterExperte === 'function') { spaeterExperte(); }
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
beantwortet = true;
|
|
78
|
+
expertenVorgabe = expNeu;
|
|
63
79
|
weiter(l);
|
|
64
80
|
});
|
|
65
81
|
setTimeout(function () {
|
|
@@ -67,6 +83,12 @@ export function ladeSprache(fertig) {
|
|
|
67
83
|
}, 2500);
|
|
68
84
|
}
|
|
69
85
|
|
|
86
|
+
/* Wer den Baum neu zeichnet, wenn der Expertenmodus spaet eintrifft.
|
|
87
|
+
Von aussen gesetzt, damit `sprache.js` nichts ueber den Baum wissen
|
|
88
|
+
muss. */
|
|
89
|
+
var spaeterExperte = null;
|
|
90
|
+
export function beiSpaetemExperten(fn) { spaeterExperte = fn; }
|
|
91
|
+
|
|
70
92
|
/* Beschriftungen im festen HTML nachziehen. */
|
|
71
93
|
export function beschrifteHtml() {
|
|
72
94
|
document.title = tr('app.title');
|
|
@@ -133,8 +155,30 @@ export function sprachtext(v) {
|
|
|
133
155
|
return String(v);
|
|
134
156
|
}
|
|
135
157
|
|
|
158
|
+
/* Frueher stand hier `v.de || v.en` — die eingestellte Sprache kam
|
|
159
|
+
nicht vor. Auf einem englischen Admin standen mehrsprachig benannte
|
|
160
|
+
Objekte, Raeume und Funktionen deshalb deutsch da, waehrend
|
|
161
|
+
`sprachtext` eine Zeile darueber es richtig machte. Zwei Leser fuer
|
|
162
|
+
dieselbe Frage sind einer zu viel. */
|
|
136
163
|
export function txt(v) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
164
|
+
return sprachtext(v);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Alle Sprachfassungen eines Namens, klein geschrieben.
|
|
168
|
+
|
|
169
|
+
Fuer den Abgleich mit Bestandsnamen: In der Anlage steht „Light",
|
|
170
|
+
von Hand getippt; die Vorlage sagt „Licht". Wer nur eine Fassung
|
|
171
|
+
vergleicht — und die auch noch nach Gross- und Kleinschreibung —,
|
|
172
|
+
legt eine zweite Funktion `enum.functions.light` neben die
|
|
173
|
+
vorhandene. */
|
|
174
|
+
export function alleTexte(v) {
|
|
175
|
+
if (v === undefined || v === null) { return []; }
|
|
176
|
+
var raus = [];
|
|
177
|
+
var dazu = function (x) {
|
|
178
|
+
var t = String(x || '').trim().toLowerCase();
|
|
179
|
+
if (t && raus.indexOf(t) === -1) { raus.push(t); }
|
|
180
|
+
};
|
|
181
|
+
if (typeof v === 'object') { Object.keys(v).forEach(function (k) { dazu(v[k]); }); }
|
|
182
|
+
else { dazu(v); }
|
|
183
|
+
return raus;
|
|
140
184
|
}
|
package/admin/js/start.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import { zeichneErgebnis } from './ergebnis.js';
|
|
5
5
|
import { socket } from './verbindung.js';
|
|
6
6
|
import { $ } from './basis.js';
|
|
7
|
-
import { tr, ladeSprache, beschrifteHtml } from './sprache.js';
|
|
8
|
-
import { ladeObjekte } from './objekte.js';
|
|
7
|
+
import { tr, ladeSprache, beschrifteHtml, beiSpaetemExperten } from './sprache.js';
|
|
8
|
+
import { ladeObjekte, abosErneuern } from './objekte.js';
|
|
9
|
+
import { zeichneBaum } from './baum.js';
|
|
9
10
|
import { ladeBefehlswissen } from './mqtt.js';
|
|
10
11
|
import { ladeVorlagen, setzeMeta } from './vorlagen.js';
|
|
11
12
|
import { ladeMusterNamen } from './musternamen.js';
|
|
@@ -13,6 +14,11 @@ import { S } from './zustand.js';
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
/* ================== Verbindung ================== */
|
|
17
|
+
/* Kommt die Expertenvorgabe erst nach dem Zeitablauf, muss der Baum
|
|
18
|
+
noch einmal gezeichnet werden — sonst fehlen die Expertenobjekte, bis
|
|
19
|
+
jemand den Reiter neu laedt. */
|
|
20
|
+
beiSpaetemExperten(function () { zeichneBaum(); });
|
|
21
|
+
|
|
16
22
|
socket.on('connect', function () {
|
|
17
23
|
var c = $('#conn');
|
|
18
24
|
c.className = 'conn on';
|
|
@@ -32,6 +38,30 @@ socket.on('connect', function () {
|
|
|
32
38
|
});
|
|
33
39
|
});
|
|
34
40
|
});
|
|
41
|
+
/* `connect` feuert genau einmal pro Seitenleben.
|
|
42
|
+
|
|
43
|
+
Der Reiter laedt nicht socket.io, sondern den WebSocket-Shim des
|
|
44
|
+
Admin (`ioBroker WebSockets`, bluefox). Dort steht woertlich:
|
|
45
|
+
`this.wasConnected ? this.reconnectHandlers.forEach(…)
|
|
46
|
+
: (this.connectHandlers.forEach(…), this.wasConnected = true)`.
|
|
47
|
+
Nach dem ersten Mal kommt also nur noch `reconnect` — und das hoerte
|
|
48
|
+
niemand. Folge jedes Aussetzers (Admin-Neustart, Netzwerkhaenger,
|
|
49
|
+
Standby): der Punkt blieb auf „getrennt" stehen, obwohl die
|
|
50
|
+
Verbindung wieder stand, und weder `objectChange` noch `stateChange`
|
|
51
|
+
kamen jemals wieder an (gemessen 09.09.2026 mit einem echten
|
|
52
|
+
`socket.close()`).
|
|
53
|
+
|
|
54
|
+
Neu geladen wird der ganze Bestand, nicht nur nachabonniert:
|
|
55
|
+
waehrend der Trennung kann sich alles geaendert haben, und ohne Abo
|
|
56
|
+
hat es niemand mitbekommen. Sprache, Geraetewissen und Vorlagen
|
|
57
|
+
bleiben, wie sie sind — die aendern sich nicht im Betrieb. */
|
|
58
|
+
socket.on('reconnect', function () {
|
|
59
|
+
var c = $('#conn');
|
|
60
|
+
c.className = 'conn on';
|
|
61
|
+
c.textContent = tr('app.connected');
|
|
62
|
+
abosErneuern();
|
|
63
|
+
ladeObjekte();
|
|
64
|
+
});
|
|
35
65
|
socket.on('disconnect', function () {
|
|
36
66
|
var c = $('#conn');
|
|
37
67
|
c.className = 'conn off';
|
package/admin/js/vorlagen.js
CHANGED
|
@@ -112,6 +112,15 @@ export function ladeVorlagen(fertig) {
|
|
|
112
112
|
sie behauptet dann nicht, es gaebe keine eigenen Vorlagen. */
|
|
113
113
|
setTimeout(function () { schluss([], true); }, 6000);
|
|
114
114
|
socket.emit('getObject', INSTANZ_ID, function (err, o) {
|
|
115
|
+
/* Denselben Weg wie der Timeout eine Zeile darueber: ein Fehler
|
|
116
|
+
heisst nicht „keine eigenen Vorlagen".
|
|
117
|
+
|
|
118
|
+
`err` wurde vorher nicht einmal angesehen. Zwei Folgen: in der
|
|
119
|
+
Kopfzeile fehlte der Warnchip, und `freierSchluessel` hielt
|
|
120
|
+
vergebene Kennungen fuer frei — beim naechsten Speichern haette
|
|
121
|
+
`aendereVorlagen` eine vorhandene Vorlage mit Version 1
|
|
122
|
+
ersetzt. */
|
|
123
|
+
if (err) { return schluss([], true); }
|
|
115
124
|
schluss((o && o.native && o.native.vorlagen) || []);
|
|
116
125
|
});
|
|
117
126
|
}
|
|
@@ -295,6 +304,47 @@ function punktErfuellt(kanal, pfad) {
|
|
|
295
304
|
}
|
|
296
305
|
|
|
297
306
|
/* Passt die Vorlage auf diesen Kanal? Liefert null oder eine Bewertung. */
|
|
307
|
+
/* Der Namenshinweis als Ausdruck — und der wirft nicht.
|
|
308
|
+
|
|
309
|
+
Der Text kommt frei aus dem Vorlagenblatt und aus dem
|
|
310
|
+
Speichern-Dialog; keins der beiden Felder prueft ihn. Ein `Lampe (Bad`
|
|
311
|
+
liess `pruefeVorlage` bei JEDER Geraeteauswahl werfen, kein Aufrufer
|
|
312
|
+
fing das, und die rechte Seite blieb leer — zu reparieren nur ueber
|
|
313
|
+
die Instanzkonfiguration von Hand (gemessen 09.09.2026). `rolleTrifft`
|
|
314
|
+
in `erkennung.js` faengt denselben Fall laengst ab; hier fehlte es.
|
|
315
|
+
|
|
316
|
+
Ein unbrauchbarer Ausdruck heisst „trifft nicht": der Hinweis ist nur
|
|
317
|
+
ein Bonus in der Bewertung, keine Bedingung. Die Vorlage bleibt damit
|
|
318
|
+
brauchbar, statt das ganze Werkzeug mitzureissen. */
|
|
319
|
+
export function hinweisTrifft(hinweis, name) {
|
|
320
|
+
if (!hinweisTaugt(hinweis)) { return false; }
|
|
321
|
+
try { return new RegExp(hinweis, 'i').test(name); }
|
|
322
|
+
catch { return false; }
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Verschachtelte Wiederholungen — `(a+)+`, `(a*)*`, `(a+){2,}`.
|
|
326
|
+
|
|
327
|
+
Die klassische Form, an der eine RegExp-Maschine in die Knie geht:
|
|
328
|
+
`(a+)+$` gegen neunundzwanzig "a" brauchte hier gemessene 3196 ms,
|
|
329
|
+
und der ganze Reiter stand solange (09.09.2026). Ein try/catch faengt
|
|
330
|
+
das nicht — die Syntax ist ja in Ordnung, es dauert nur ewig.
|
|
331
|
+
|
|
332
|
+
Das ist eine Heuristik, kein Beweis: Sie deckt die Form ab, die man
|
|
333
|
+
sich versehentlich baut, nicht jeden denkbaren Fall. Fuer einen
|
|
334
|
+
Namenshinweis reicht das — er soll ein Wort im Geraetenamen finden,
|
|
335
|
+
nicht eine Sprache parsen. */
|
|
336
|
+
function verschachtelt(hinweis) {
|
|
337
|
+
return /\([^()]*[+*][^()]*\)\s*([+*]|\{\s*[0-9]+\s*,)/.test(String(hinweis));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* Taugt der Text als Ausdruck? Fuer die Felder, die ihn aufnehmen. */
|
|
341
|
+
export function hinweisTaugt(hinweis) {
|
|
342
|
+
if (!hinweis) { return true; }
|
|
343
|
+
if (verschachtelt(hinweis)) { return false; }
|
|
344
|
+
try { new RegExp(hinweis, 'i'); return true; }
|
|
345
|
+
catch { return false; }
|
|
346
|
+
}
|
|
347
|
+
|
|
298
348
|
export function pruefeVorlage(v, kanal, instanz) {
|
|
299
349
|
var erk = v.erkennung || {};
|
|
300
350
|
var gruende = [];
|
|
@@ -367,7 +417,7 @@ export function pruefeVorlage(v, kanal, instanz) {
|
|
|
367
417
|
var belege = (erk.erforderlich || []).length *
|
|
368
418
|
(v.mehrfach ? Math.max(1, ausgaenge.length) : 1) +
|
|
369
419
|
Object.keys(erk.inhalt || {}).length;
|
|
370
|
-
var namenstreffer = !!(erk.namenshinweis &&
|
|
420
|
+
var namenstreffer = !!(erk.namenshinweis && hinweisTrifft(erk.namenshinweis, name));
|
|
371
421
|
if (namenstreffer) { gruende.push(tr('tpl.nameHint', sprachtext(v.name))); }
|
|
372
422
|
var eigen = v._quelle === 'benutzer';
|
|
373
423
|
var punkte = belege * 1000000 +
|
|
@@ -469,6 +519,34 @@ export function wendeAn(v, kanal, gruende, instanz, auchOhneTreffer) {
|
|
|
469
519
|
break;
|
|
470
520
|
}
|
|
471
521
|
|
|
522
|
+
/* Ein Tastendruck hat keinen Zustand zum Lesen.
|
|
523
|
+
|
|
524
|
+
`STOP` am Rollladen traegt nur `schreiben` — genau so steht es in
|
|
525
|
+
der Vorlage, mit Begruendung. Diesen Fall kannte das Anwenden
|
|
526
|
+
nicht: Ohne `lesen` fiel der Punkt mit „STOP: undefined fehlt"
|
|
527
|
+
heraus, und KEIN EINZIGER Rollladen-Alias bekam je einen STOP
|
|
528
|
+
(gefunden 09.09.2026). Der Platz im Muster verlangt auch nichts
|
|
529
|
+
weiter als `write: true`. */
|
|
530
|
+
var nurSchreiben = !z.lesen && !!z.schreiben;
|
|
531
|
+
if (nurSchreiben && !quelle) {
|
|
532
|
+
var ziel0 = schreibZiel(z, kanal, auf);
|
|
533
|
+
if (!ziel0) {
|
|
534
|
+
e.uebersprungen.push(tr('tpl.skippedSource', z.name, auf(z.schreiben)));
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
e.states.push({
|
|
538
|
+
n: z.name, on: !z.vorgabeAus, role: z.rolle || '', typ: z.typ || '',
|
|
539
|
+
unit: z.einheit || '', wr: true,
|
|
540
|
+
srcR: '', srcW: ziel0,
|
|
541
|
+
f: '', fw: z.schreibformel ? auf(z.schreibformel) : '',
|
|
542
|
+
caption: z.beschriftung || '',
|
|
543
|
+
dec: z.nachkommastellen === undefined ? undefined : String(z.nachkommastellen),
|
|
544
|
+
states: z.werteliste || undefined,
|
|
545
|
+
manuell: false, ausVorlage: z.name, hinweis: z.hinweis || '', wege: []
|
|
546
|
+
});
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
|
|
472
550
|
if (!quelle) {
|
|
473
551
|
/* Beide Wege nennen, nicht nur den letzten — sonst sucht man an der
|
|
474
552
|
einen Stelle und die Vorlage hatte an zwei geschaut. */
|
|
@@ -481,7 +559,15 @@ export function wendeAn(v, kanal, gruende, instanz, auchOhneTreffer) {
|
|
|
481
559
|
/* Auch in der Formel steht der Platzhalter — ohne Ersetzung suchte
|
|
482
560
|
der Alias nach einem Feld namens POWER%N%. */
|
|
483
561
|
var formel = leseformel ? auf(leseformel) : '';
|
|
484
|
-
|
|
562
|
+
/* Wer eine Formel hinschreibt, bekommt sie auch.
|
|
563
|
+
|
|
564
|
+
`tasmota-rgb` fuehrt an FADE beides: `feld` UND `leseformel`. Die
|
|
565
|
+
Formel wurde verworfen und aus dem Feld eine neue gebaut — bei
|
|
566
|
+
FADE faellt es nicht auf, weil der Zieltyp die Umwandlung
|
|
567
|
+
nachholt, an der naechsten Zeile mit eigener Rechnung aber schon
|
|
568
|
+
(gefunden 09.09.2026). Das Feld bleibt der bequeme Weg; die
|
|
569
|
+
ausdrueckliche Angabe schlaegt ihn. */
|
|
570
|
+
if (feld && !formel) {
|
|
485
571
|
feld = auf(feld);
|
|
486
572
|
/* Mit Fragezeichen-Zugriff: `tele.SENSOR` ist ein Sammeltopf, und
|
|
487
573
|
nicht jede Nachricht darin fuehrt jedes Feld. Ohne Schutz wirft
|
|
@@ -563,8 +649,10 @@ export function vorschlag(kanal, vorlagenId, instanz) {
|
|
|
563
649
|
e.erzwungen = true;
|
|
564
650
|
e.grund = e.grund.concat(gewaehlt.fehler.map(function (f) { return tr('tpl.wouldNeed', f); }));
|
|
565
651
|
}
|
|
566
|
-
e.andere
|
|
567
|
-
|
|
652
|
+
/* Hier stand `e.andere` — die Liste der unterlegenen Vorlagen. Sie
|
|
653
|
+
wurde bei jedem Vorschlag gebaut und von niemandem gelesen
|
|
654
|
+
(gefunden 09.09.2026). Was der Nutzer wirklich braucht, steht im
|
|
655
|
+
Musterwahl-Feld und im Vorlagenblatt. */
|
|
568
656
|
if (vorlagenId) { e.vonHandGewaehlt = true; }
|
|
569
657
|
return merkeHakenVorgabe(e);
|
|
570
658
|
}
|