iobroker.alias-workbench 0.9.8 → 0.9.10
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/LICENSE +1 -1
- package/README.md +27 -2
- package/admin/css/werkbank.css +8 -3
- package/admin/i18n/de.json +12 -588
- package/admin/i18n/en.json +12 -588
- package/admin/i18n/es.json +14 -0
- package/admin/i18n/fr.json +14 -0
- package/admin/i18n/it.json +14 -0
- package/admin/i18n/nl.json +14 -0
- package/admin/i18n/pl.json +14 -0
- package/admin/i18n/pt.json +14 -0
- package/admin/i18n/ru.json +14 -0
- package/admin/i18n/uk.json +14 -0
- package/admin/i18n/zh-cn.json +14 -0
- package/admin/js/detail.js +31 -6
- package/admin/js/entwurf.js +47 -17
- package/admin/js/ergebnis.js +49 -4
- package/admin/js/erkennung.js +133 -2
- package/admin/js/musterwahl.js +40 -6
- package/admin/js/quellentausch.js +179 -19
- package/admin/js/schreiben.js +98 -3
- package/admin/js/sprache.js +10 -3
- package/admin/js/vorlagen.js +12 -2
- package/admin/js/vorlagenblatt.js +123 -20
- package/admin/js/werte.js +63 -1
- package/admin/js/zuordnung.js +29 -35
- package/admin/js/zustandsliste.js +37 -4
- package/admin/jsonConfig.json +13 -157
- package/admin/sprachen/de.json +607 -0
- package/admin/sprachen/en.json +607 -0
- package/admin/vorlagen/messpunkt.json +2 -1
- package/admin/vorlagen/tasmota-lampe.json +2 -1
- package/admin/vorlagen/tasmota-mehrfach.json +2 -1
- package/admin/vorlagen/tasmota-rgb.json +2 -1
- package/admin/vorlagen/tasmota-steckdose.json +2 -1
- package/io-package.json +47 -47
- package/package.json +2 -2
|
@@ -92,6 +92,15 @@ function ausVorlage(punktId, neuKanal) {
|
|
|
92
92
|
|
|
93
93
|
/* Stufe 3: gleicher Punktname irgendwo unter dem neuen Geraet, oder
|
|
94
94
|
gleiche Rolle. Bewusst schwach - deshalb nur als Vorschlag. */
|
|
95
|
+
/* Und WORUEBER geraten wurde, wird mitgegeben.
|
|
96
|
+
|
|
97
|
+
„vermutet" allein sagt nur, dass die Zuordnung schwach ist - nicht,
|
|
98
|
+
woran sie haengt. Ueber den Namen geraten heisst: irgendein Punkt
|
|
99
|
+
heisst hinten gleich; das kann weit danebenliegen (ein Fensterkontakt
|
|
100
|
+
`…1.STATE` landete so auf `…tele.STATE`, dem Telemetrie-JSON einer
|
|
101
|
+
Tasmota). Ueber die Rolle geraten ist etwas anderes und muss anders
|
|
102
|
+
geprueft werden. Der Tooltip an der Marke sagt es jetzt (Ricardo,
|
|
103
|
+
12.09.2026). */
|
|
95
104
|
function geraten(altQuelle, neuKanal) {
|
|
96
105
|
var name = altQuelle.split('.').pop();
|
|
97
106
|
var kandidaten = kindZustaende(neuKanal);
|
|
@@ -99,7 +108,7 @@ function geraten(altQuelle, neuKanal) {
|
|
|
99
108
|
kandidaten.forEach(function (id) {
|
|
100
109
|
if (!treffer && id.split('.').pop() === name) { treffer = id; }
|
|
101
110
|
});
|
|
102
|
-
if (treffer) { return treffer; }
|
|
111
|
+
if (treffer) { return { id: treffer, ueber: 'name' }; }
|
|
103
112
|
var altO = S.objects[altQuelle];
|
|
104
113
|
var rolle = altO && altO.common && altO.common.role;
|
|
105
114
|
if (rolle) {
|
|
@@ -108,7 +117,7 @@ function geraten(altQuelle, neuKanal) {
|
|
|
108
117
|
if (!treffer && o && o.common && o.common.role === rolle) { treffer = id; }
|
|
109
118
|
});
|
|
110
119
|
}
|
|
111
|
-
return treffer;
|
|
120
|
+
return treffer ? { id: treffer, ueber: 'rolle', rolle: rolle } : null;
|
|
112
121
|
}
|
|
113
122
|
|
|
114
123
|
/* Die Zuordnungstabelle: je Alias-Punkt, was heute gilt und was danach
|
|
@@ -158,10 +167,14 @@ export function tauschPlan(kanal, neuKanal) {
|
|
|
158
167
|
/* 3. geraten */
|
|
159
168
|
if (!zeile.neuR && zeile.altR) {
|
|
160
169
|
var g = geraten(zeile.altR, neuKanal);
|
|
161
|
-
if (g) {
|
|
170
|
+
if (g) {
|
|
171
|
+
zeile.neuR = g.id; zeile.stufe = 3;
|
|
172
|
+
zeile.geratenUeber = g.ueber; zeile.geratenRolle = g.rolle || '';
|
|
173
|
+
}
|
|
162
174
|
}
|
|
163
175
|
if (!zeile.neuW && zeile.altW) {
|
|
164
|
-
var
|
|
176
|
+
var gwT = geraten(zeile.altW, neuKanal);
|
|
177
|
+
var gw = gwT && gwT.id;
|
|
165
178
|
/* Was hier geraten wird, muss ein anderer Punkt sein als die
|
|
166
179
|
Lesequelle. Bei getrennten Quellen heissen Melder und Befehl oft
|
|
167
180
|
gleich - `stat.POWER` und `cmnd.POWER` -, und das Raten greift
|
|
@@ -172,6 +185,21 @@ export function tauschPlan(kanal, neuKanal) {
|
|
|
172
185
|
(gemessen 09.09.2026). Lieber kein Treffer als dieser. */
|
|
173
186
|
if (gw && gw !== zeile.neuR) { zeile.neuW = gw; }
|
|
174
187
|
}
|
|
188
|
+
/* Bei getrennten Quellen darf das Schreibziel nie die Lesequelle
|
|
189
|
+
sein - egal, aus welcher der drei Stufen es kam.
|
|
190
|
+
|
|
191
|
+
Beim Raten stand diese Regel schon (siehe oben), beim PFADTREFFER
|
|
192
|
+
fehlte sie: `suchePfad` probiert als letzte Form den blossen
|
|
193
|
+
Punktnamen, und `cmnd.POWER` findet so `…Stumm.stat.POWER` - den
|
|
194
|
+
Melder. Sichtbar wird es, wenn man beim Tauschen nicht das Geraet,
|
|
195
|
+
sondern einen Unterknoten waehlt (`…Stumm.stat` statt `…Stumm`):
|
|
196
|
+
dann verschwand der rote Hinweis, der Knopf wurde frei, und
|
|
197
|
+
geschrieben haette der Alias auf seine eigene Lesequelle - genau
|
|
198
|
+
der Fehler, den W20 abschaffen sollte (Ricardo, 12.09.2026).
|
|
199
|
+
|
|
200
|
+
Danach steht `neuW` leer, und die Sperre aus W20 greift: der
|
|
201
|
+
Nutzer entscheidet, ob der Punkt entfernt wird. */
|
|
202
|
+
if (!zeile.einfach && zeile.neuW && zeile.neuW === zeile.neuR) { zeile.neuW = ''; }
|
|
175
203
|
/* Bei einfacher Quelle gilt die Lesequelle fuer beides. */
|
|
176
204
|
if (zeile.einfach && zeile.neuR) { zeile.neuW = zeile.neuR; }
|
|
177
205
|
return zeile;
|
|
@@ -339,6 +367,25 @@ function zeichneAuswahlbaum(host, filter, beiWahl) {
|
|
|
339
367
|
if (!host.childNodes.length) {
|
|
340
368
|
host.appendChild(el('div', 'empty', tr('swap.noDevice')));
|
|
341
369
|
}
|
|
370
|
+
|
|
371
|
+
/* Die Liste bleibt stehen, wo sie stand.
|
|
372
|
+
|
|
373
|
+
Beim Aufklappen fiel das nicht auf: derselbe Behaelter, nur neu
|
|
374
|
+
gefuellt, und `scrollTop` ueberlebt das. Beim WAEHLEN schon -
|
|
375
|
+
`zeichneTausch` baut den ganzen Dialog neu, der Baum ist danach ein
|
|
376
|
+
anderes Element und faengt bei 0 an. Wer weit unten ein Geraet
|
|
377
|
+
anklickte, sah danach den Anfang der Liste und seinen eben
|
|
378
|
+
gewaehlten Eintrag gar nicht mehr (Ricardo, 12.09.2026, an einer
|
|
379
|
+
Liste mit 42 Zeilen: scrollTop 700 -> 0).
|
|
380
|
+
|
|
381
|
+
Gemerkt wird an `S`, nicht am Element: das Element gibt es beim
|
|
382
|
+
naechsten Zeichnen nicht mehr. `block: 'nearest'` schiebt nur, wenn
|
|
383
|
+
die Zeile wirklich draussen ist - sonst springt die Liste bei jedem
|
|
384
|
+
Klick ein Stueck, und das waere die naechste Unruhe. */
|
|
385
|
+
if (S.tauschScroll) { host.scrollTop = S.tauschScroll; }
|
|
386
|
+
var gewaehlteZeile = host.querySelector('.node.sel');
|
|
387
|
+
if (gewaehlteZeile) { gewaehlteZeile.scrollIntoView({ block: 'nearest' }); }
|
|
388
|
+
host.addEventListener('scroll', function () { S.tauschScroll = host.scrollTop; });
|
|
342
389
|
}
|
|
343
390
|
|
|
344
391
|
export function zeigeTausch() {
|
|
@@ -355,6 +402,9 @@ export function zeigeTausch() {
|
|
|
355
402
|
schlimmsten Fall genau dann, wenn im Feld noch das eben getauschte,
|
|
356
403
|
inzwischen geloeschte Geraet stand (W13, gemessen 26.08.2026). */
|
|
357
404
|
S.tauschFilter = '';
|
|
405
|
+
/* Und die Liste faengt oben an - sonst startet der naechste Tausch
|
|
406
|
+
dort, wo der letzte aufgehoert hat. */
|
|
407
|
+
S.tauschScroll = 0;
|
|
358
408
|
var b = $('#btn-swap-go');
|
|
359
409
|
if (b) { b.hidden = false; b.textContent = tr('swap.now'); }
|
|
360
410
|
zeichneTausch();
|
|
@@ -420,6 +470,10 @@ function zeichneTausch() {
|
|
|
420
470
|
zeichneAuswahlbaum(baumHost, S.tauschFilter, gewaehlt);
|
|
421
471
|
feld.addEventListener('input', function () {
|
|
422
472
|
S.tauschFilter = feld.value;
|
|
473
|
+
/* Andere Suche, andere Liste - die alte Scrollhoehe passt nicht mehr
|
|
474
|
+
und zeigte sonst ins Leere. */
|
|
475
|
+
S.tauschScroll = 0;
|
|
476
|
+
baumHost.scrollTop = 0;
|
|
423
477
|
zeichneAuswahlbaum(baumHost, S.tauschFilter, gewaehlt);
|
|
424
478
|
});
|
|
425
479
|
|
|
@@ -434,6 +488,40 @@ function zeichneTausch() {
|
|
|
434
488
|
/* Die Zuordnung, Zeile fuer Zeile. */
|
|
435
489
|
if (!S.tauschPlan) { S.tauschPlan = tauschPlan(kanal, S.tauschNeu); }
|
|
436
490
|
var plan = S.tauschPlan;
|
|
491
|
+
|
|
492
|
+
/* Steht die Wahl eine Ebene zu tief?
|
|
493
|
+
|
|
494
|
+
Der Baum laesst jeden Knoten waehlen, unter dem Datenpunkte haengen -
|
|
495
|
+
absichtlich, denn welche Ebene beim fremden Adapter das Geraet ist,
|
|
496
|
+
kann die Werkbank nicht wissen; bei einem flachen Adapter ist der
|
|
497
|
+
Kanal die richtige (Kommentar in `tauschPlan`). Bei MQTT sind
|
|
498
|
+
`stat`, `tele` und `cmnd` aber Themenordner, keine Geraete, und wer
|
|
499
|
+
dort landet, bekommt schlechtere Treffer: am RGB-Deckenlicht fanden
|
|
500
|
+
ueber das Geraet alle sieben Punkte ein Ziel, ueber `…Licht.tele`
|
|
501
|
+
nur fuenf - die beiden aus `stat` gar nichts (12.09.2026).
|
|
502
|
+
|
|
503
|
+
Verboten wird nichts. Aber die Werkbank kann nachrechnen, was eine
|
|
504
|
+
Ebene hoeher herauskaeme, und es sagen - sonst hakt man zwei Punkte
|
|
505
|
+
zum Entfernen an und opfert seinen Schalter, statt den Knoten
|
|
506
|
+
darueber zu nehmen (Ricardos Frage, 12.09.2026). */
|
|
507
|
+
var eltern = S.tauschNeu.split('.').slice(0, -1).join('.');
|
|
508
|
+
if (eltern.split('.').length > 2 && S.tauschNeu !== alt) {
|
|
509
|
+
var trefferHier = plan.filter(function (z) { return z.neuR; }).length;
|
|
510
|
+
var planOben = tauschPlan(kanal, eltern);
|
|
511
|
+
var trefferOben = planOben.filter(function (z) { return z.neuR; }).length;
|
|
512
|
+
if (trefferOben > trefferHier) {
|
|
513
|
+
var eb = el('div', 'aside w');
|
|
514
|
+
eb.style.borderLeftColor = 'var(--warn)';
|
|
515
|
+
eb.appendChild(el('b', null, tr('swap.higherLevel',
|
|
516
|
+
eltern, trefferOben, plan.length, trefferHier)));
|
|
517
|
+
var knopf = el('button', 'btn mini wichtig', tr('swap.goHigher'));
|
|
518
|
+
knopf.style.marginTop = '5px';
|
|
519
|
+
knopf.addEventListener('click', function () { gewaehlt(eltern); });
|
|
520
|
+
eb.appendChild(el('div', null, ''));
|
|
521
|
+
eb.appendChild(knopf);
|
|
522
|
+
body.appendChild(eb);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
437
525
|
var k = el('div', 'card');
|
|
438
526
|
k.style.marginTop = '11px';
|
|
439
527
|
var ch = el('div', 'ch');
|
|
@@ -460,9 +548,49 @@ function zeichneTausch() {
|
|
|
460
548
|
&& (z.einfach || (z.neuW || '') === (z.altW || ''));
|
|
461
549
|
var nm = el('span', 'sn', z.name);
|
|
462
550
|
if (gleich) { nm.appendChild(el('span', 'rat', tr('swap.unchanged'))); }
|
|
463
|
-
else if (z.stufe === 3) {
|
|
551
|
+
else if (z.stufe === 3) {
|
|
552
|
+
/* Die Marke sagt jetzt auch, WORUEBER geraten wurde - ueber den
|
|
553
|
+
blossen Punktnamen oder ueber die Rolle. Das sind zwei sehr
|
|
554
|
+
verschiedene Vermutungen, und sie pruefen sich verschieden. */
|
|
555
|
+
var rm = el('span', 'rat', tr('guess.mark'));
|
|
556
|
+
rm.title = z.geratenUeber === 'rolle'
|
|
557
|
+
? tr('swap.guessedByRole', z.geratenRolle || '?')
|
|
558
|
+
: tr('swap.guessedByName', (z.altR || '').split('.').pop());
|
|
559
|
+
nm.appendChild(rm);
|
|
560
|
+
}
|
|
464
561
|
r.appendChild(nm);
|
|
465
562
|
var rechts = el('span');
|
|
563
|
+
/* Das Kaestchen „entfernen" - an zwei Stellen gebraucht, deshalb hier.
|
|
564
|
+
|
|
565
|
+
Es gab es bisher nur, wenn GAR NICHTS gefunden wurde. Der zweite
|
|
566
|
+
Fall braucht es genauso: Lesequelle gefunden, Schreibziel nicht.
|
|
567
|
+
Ein Punkt mit Schreibrecht ohne Schreibziel laesst sich in ioBroker
|
|
568
|
+
nicht ausdruecken - jede Form, die der js-controller annimmt,
|
|
569
|
+
schreibt irgendwohin, und `{read: X}` ohne `write` lehnt er ab
|
|
570
|
+
(„The id is empty", gemessen 12.09.2026). Also entscheidet der
|
|
571
|
+
Nutzer: mitnehmen geht nicht, entfernen schon (Ricardo). */
|
|
572
|
+
var entfernenKaestchen = function () {
|
|
573
|
+
var lb = document.createElement('label');
|
|
574
|
+
lb.style.display = 'flex';
|
|
575
|
+
lb.style.gap = '6px';
|
|
576
|
+
lb.style.alignItems = 'center';
|
|
577
|
+
lb.style.marginTop = '3px';
|
|
578
|
+
lb.style.cursor = 'pointer';
|
|
579
|
+
var cb = document.createElement('input');
|
|
580
|
+
cb.type = 'checkbox';
|
|
581
|
+
cb.checked = !!S.tauschWeg[z.id];
|
|
582
|
+
cb.addEventListener('change', function () {
|
|
583
|
+
S.tauschWeg[z.id] = cb.checked;
|
|
584
|
+
/* Der Knopf haengt daran - also neu rechnen, nicht erst beim
|
|
585
|
+
naechsten Oeffnen. `zeichneTausch`, nicht `zeigeTausch`: das
|
|
586
|
+
zweite setzt Auswahl, Plan und Haken zurueck und faengt von
|
|
587
|
+
vorn an. */
|
|
588
|
+
zeichneTausch();
|
|
589
|
+
});
|
|
590
|
+
lb.appendChild(cb);
|
|
591
|
+
lb.appendChild(el('span', 'hint', tr('swap.removeIt')));
|
|
592
|
+
return lb;
|
|
593
|
+
};
|
|
466
594
|
/* Beschriftet, sonst raet man, welche der beiden Zeilen die neue ist. */
|
|
467
595
|
var paarZeile = function (beschriftung, text, klasse, farbe) {
|
|
468
596
|
var zz = el('div');
|
|
@@ -489,6 +617,7 @@ function zeichneTausch() {
|
|
|
489
617
|
kw.style.color = 'var(--bad)';
|
|
490
618
|
kw.textContent = tr('swap.noWriteMatch');
|
|
491
619
|
rechts.appendChild(kw);
|
|
620
|
+
rechts.appendChild(entfernenKaestchen());
|
|
492
621
|
}
|
|
493
622
|
} else {
|
|
494
623
|
var fehlt = el('div');
|
|
@@ -497,19 +626,7 @@ function zeichneTausch() {
|
|
|
497
626
|
rechts.appendChild(fehlt);
|
|
498
627
|
/* Was nichts findet, laesst sich mit entfernen - sonst bliebe ein
|
|
499
628
|
Punkt zurueck, der ins Leere zeigt (Ricardos Wahl, 25.08.2026). */
|
|
500
|
-
|
|
501
|
-
lb.style.display = 'flex';
|
|
502
|
-
lb.style.gap = '6px';
|
|
503
|
-
lb.style.alignItems = 'center';
|
|
504
|
-
lb.style.marginTop = '3px';
|
|
505
|
-
lb.style.cursor = 'pointer';
|
|
506
|
-
var cb = document.createElement('input');
|
|
507
|
-
cb.type = 'checkbox';
|
|
508
|
-
cb.checked = !!S.tauschWeg[z.id];
|
|
509
|
-
cb.addEventListener('change', function () { S.tauschWeg[z.id] = cb.checked; });
|
|
510
|
-
lb.appendChild(cb);
|
|
511
|
-
lb.appendChild(el('span', 'hint', tr('swap.removeIt')));
|
|
512
|
-
rechts.appendChild(lb);
|
|
629
|
+
rechts.appendChild(entfernenKaestchen());
|
|
513
630
|
}
|
|
514
631
|
r.appendChild(rechts);
|
|
515
632
|
k.appendChild(r);
|
|
@@ -556,7 +673,39 @@ function zeichneTausch() {
|
|
|
556
673
|
if (plan.some(function (z) { return z.stufe === 3; })) {
|
|
557
674
|
body.appendChild(el('div', 'aside', tr('swap.guessHint')));
|
|
558
675
|
}
|
|
559
|
-
|
|
676
|
+
|
|
677
|
+
/* Punkte, die nicht mitkoennen, halten den Tausch auf - bis der Nutzer
|
|
678
|
+
sagt, was mit ihnen geschehen soll.
|
|
679
|
+
|
|
680
|
+
Zwei Faelle, beide mit demselben Ausgang (das Kaestchen daneben):
|
|
681
|
+
gar kein Treffer, oder getrennte Quellen mit Lesetreffer und ohne
|
|
682
|
+
Schreibziel. Frueher lief der Tausch in beiden Faellen los. Der
|
|
683
|
+
zweite endete dabei im Fehler des js-controllers, und weil
|
|
684
|
+
`tauscheAus` Objekt fuer Objekt schrieb, stand der Alias danach
|
|
685
|
+
halb auf der alten und halb auf der neuen Quelle (W20, gemessen
|
|
686
|
+
12.09.2026). Der erste lief still durch und liess den Punkt auf der
|
|
687
|
+
alten Quelle stehen - derselbe Mischzustand, nur ohne Meldung.
|
|
688
|
+
|
|
689
|
+
Gesperrt wird mit Begruendung am Knopf, nicht bloss grau: ein
|
|
690
|
+
Knopf, der nicht sagt warum, ist der Fehler aus I32. */
|
|
691
|
+
var offeneStolper = plan.filter(function (z) {
|
|
692
|
+
if (S.tauschWeg[z.id]) { return false; }
|
|
693
|
+
if (!z.neuR) { return true; }
|
|
694
|
+
return !!(z.altW && z.altW !== z.altR && !z.neuW);
|
|
695
|
+
});
|
|
696
|
+
if (go) {
|
|
697
|
+
if (offeneStolper.length) {
|
|
698
|
+
go.disabled = true;
|
|
699
|
+
go.title = tr('swap.blocked', offeneStolper.map(function (z) { return z.name; }).join(', '));
|
|
700
|
+
var sp = el('div', 'aside w');
|
|
701
|
+
sp.style.borderLeftColor = 'var(--bad)';
|
|
702
|
+
sp.appendChild(el('b', null, go.title));
|
|
703
|
+
body.appendChild(sp);
|
|
704
|
+
} else {
|
|
705
|
+
go.disabled = false;
|
|
706
|
+
go.title = '';
|
|
707
|
+
}
|
|
708
|
+
}
|
|
560
709
|
}
|
|
561
710
|
|
|
562
711
|
export function tauscheAus() {
|
|
@@ -585,6 +734,17 @@ export function tauscheAus() {
|
|
|
585
734
|
};
|
|
586
735
|
|
|
587
736
|
var weiter = function () {
|
|
737
|
+
/* Schlug beim Umschreiben etwas fehl, wird nichts geloescht.
|
|
738
|
+
|
|
739
|
+
Dieselbe Regel wie beim Verlegen (T11): erst alles Neue, und geht
|
|
740
|
+
dabei etwas schief, bleibt der Rest unberuehrt. Hier fehlte sie -
|
|
741
|
+
`weiter` loeschte auch dann, wenn die Haelfte der Punkte noch auf
|
|
742
|
+
der alten Quelle stand. Zurueck kann die Werkbank nichts nehmen,
|
|
743
|
+
aber sie kann aufhoeren, es schlimmer zu machen: der Nutzer sieht
|
|
744
|
+
die Fehler und drueckt „Noch einmal versuchen", und die schon
|
|
745
|
+
umgeschriebenen Punkte stoeren dabei nicht - sie stehen ja bereits
|
|
746
|
+
richtig (12.09.2026). */
|
|
747
|
+
if (fehler.length) { return fertig(); }
|
|
588
748
|
if (!loeschen.length) { return fertig(); }
|
|
589
749
|
var offen2 = loeschen.length;
|
|
590
750
|
loeschen.forEach(function (id) {
|
package/admin/js/schreiben.js
CHANGED
|
@@ -445,12 +445,31 @@ export function zuSchreiben(alleAusgaenge) {
|
|
|
445
445
|
}).filter(Boolean);
|
|
446
446
|
}
|
|
447
447
|
if (!alleAusgaenge || !S.entwurf.instanzen || S.entwurf.instanzen.length < 2) { return [S.entwurf]; }
|
|
448
|
+
/* Der Kanalname wird zur Kennung - und zwei koennen dabei gleich werden.
|
|
449
|
+
|
|
450
|
+
`ausgangName` saeubert seit dem 12.09.2026 selbst (G31), und damit
|
|
451
|
+
ergeben „Licht Bar" und „Licht, Bar" beide `Licht_Bar`: der zweite
|
|
452
|
+
Kanal ueberschriebe den ersten, still und ohne Meldung. Deshalb
|
|
453
|
+
wird hier mitgezaehlt, was schon vergeben ist - der zweite bekommt
|
|
454
|
+
`_2`, der dritte `_3`. Der Anzeigename bleibt der des Kanals. */
|
|
455
|
+
var vergeben = {};
|
|
456
|
+
var eindeutig = function (name) {
|
|
457
|
+
if (!vergeben[name]) { vergeben[name] = 1; return name; }
|
|
458
|
+
var z = 1, n2;
|
|
459
|
+
do { z++; n2 = name + '_' + z; } while (vergeben[n2]);
|
|
460
|
+
vergeben[n2] = 1;
|
|
461
|
+
return n2;
|
|
462
|
+
};
|
|
448
463
|
return S.entwurf.instanzen.map(function (n) {
|
|
449
|
-
if (String(n) === String(S.entwurf.instanz)) {
|
|
464
|
+
if (String(n) === String(S.entwurf.instanz)) {
|
|
465
|
+
S.entwurf.zielName = eindeutig(S.entwurf.zielName);
|
|
466
|
+
S.entwurf.ziel = S.entwurf.zielOrdner + '.' + S.entwurf.zielName;
|
|
467
|
+
return S.entwurf;
|
|
468
|
+
}
|
|
450
469
|
var v = vorschlag(S.current, S.entwurf.vorlage, n);
|
|
451
470
|
if (v) {
|
|
452
471
|
v.zielOrdner = S.entwurf.zielOrdner;
|
|
453
|
-
v.zielName = ausgangName(v, n);
|
|
472
|
+
v.zielName = eindeutig(ausgangName(v, n));
|
|
454
473
|
v.ziel = v.zielOrdner + '.' + v.zielName;
|
|
455
474
|
enumsUebertragen(v);
|
|
456
475
|
}
|
|
@@ -487,6 +506,35 @@ function sammle(liste, o) {
|
|
|
487
506
|
vorh.neu = vorh.neu && o.neu;
|
|
488
507
|
}
|
|
489
508
|
|
|
509
|
+
/* Eine selbst angelegte Aufzaehlung, die durch diesen Schreibvorgang
|
|
510
|
+
leer wird, geht mit.
|
|
511
|
+
|
|
512
|
+
Beim LOESCHEN eines Alias tut das `enumsDieLeerWuerden` seit jeher.
|
|
513
|
+
Beim blossen WECHSEL der Funktion nicht: wer „Stehlampe" waehlte,
|
|
514
|
+
schrieb, dann auf „Licht" umstellte, hinterliess ein leeres
|
|
515
|
+
`enum.functions.floor_lamp` - von der Werkbank angelegt, von der
|
|
516
|
+
Werkbank geleert, und trotzdem stehengeblieben (gemessen 12.09.2026).
|
|
517
|
+
|
|
518
|
+
Dieselbe Regel wie dort: nur was `angelegtVon` traegt, und nur wenn
|
|
519
|
+
hinterher kein Mitglied uebrig ist. Der Eintrag wandert aus der
|
|
520
|
+
Schreibliste in die Loeschliste - sonst schriebe ihn `setObject`
|
|
521
|
+
parallel zum `delObject` wieder hin.
|
|
522
|
+
|
|
523
|
+
Gerufen von `zeigeTrockenlauf` UND `schreibeObjekte`: beide bauen ihre
|
|
524
|
+
Liste selbst, und was der Trockenlauf zeigt, muss das Schreiben tun. */
|
|
525
|
+
function leereEigeneEnums(liste, weg) {
|
|
526
|
+
liste.slice().forEach(function (x) {
|
|
527
|
+
if (!x.istEnum || !x.weg) { return; }
|
|
528
|
+
var o = enums[x.id];
|
|
529
|
+
if (!o || !o.native || o.native.angelegtVon !== 'alias-workbench') { return; }
|
|
530
|
+
if (((x.obj.common || {}).members || []).length) { return; }
|
|
531
|
+
liste.splice(liste.indexOf(x), 1);
|
|
532
|
+
if (!weg.some(function (y) { return y.id === x.id; })) {
|
|
533
|
+
weg.push({ id: x.id, vorgabe: true, grund: tr('enums.nowEmpty') });
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
490
538
|
export function zeigeTrockenlauf(alleAusgaenge) {
|
|
491
539
|
if (!S.entwurf) { return; }
|
|
492
540
|
S.trockenAlle = !!alleAusgaenge;
|
|
@@ -532,6 +580,7 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
532
580
|
if (!weg.some(function (x) { return x.id === v.id; })) { weg.push(v); }
|
|
533
581
|
});
|
|
534
582
|
});
|
|
583
|
+
leereEigeneEnums(liste, weg);
|
|
535
584
|
S.loeschListe = weg;
|
|
536
585
|
var body = $('#dry-body');
|
|
537
586
|
body.textContent = '';
|
|
@@ -600,6 +649,20 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
600
649
|
body.appendChild(zwK);
|
|
601
650
|
}
|
|
602
651
|
|
|
652
|
+
/* Was beim letzten Anlegen der Sendepunkte schiefging - hier oben, wo
|
|
653
|
+
man es sieht, und nicht als Tooltip an einem Knopf, den derselbe
|
|
654
|
+
Rueckruf gleich wieder wegwirft (H17). */
|
|
655
|
+
if (S.mqFehler && S.mqFehler.length) {
|
|
656
|
+
var mk = el('div', 'aside w');
|
|
657
|
+
mk.style.borderLeftColor = 'var(--bad)';
|
|
658
|
+
mk.style.marginBottom = '11px';
|
|
659
|
+
mk.appendChild(el('b', null, tr('write.failed', S.mqFehler.length)));
|
|
660
|
+
var mul = el('ul');
|
|
661
|
+
S.mqFehler.forEach(function (x) { mul.appendChild(el('li', null, x)); });
|
|
662
|
+
mk.appendChild(mul);
|
|
663
|
+
body.appendChild(mk);
|
|
664
|
+
}
|
|
665
|
+
|
|
603
666
|
/* Die Aufzaehlungen sind gerade nicht bekannt — dann wird auch keine
|
|
604
667
|
geschrieben. Das gehoert hierher und nicht in eine Sperre: der Alias
|
|
605
668
|
selbst braucht sie nicht, und aus einem stillen Datenverlust eine
|
|
@@ -618,7 +681,12 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
618
681
|
var wch = el('div', 'ch');
|
|
619
682
|
wch.appendChild(el('span', 'typ', tr('write.remove')));
|
|
620
683
|
wch.appendChild(el('span', 'chip bad', tr('write.removeCount', weg.length)));
|
|
621
|
-
|
|
684
|
+
/* Der Satz gilt fuer Datenpunkte. Steht eine leer gewordene
|
|
685
|
+
Aufzaehlung mit in der Liste, waere er dort falsch - die liegt
|
|
686
|
+
nicht im Alias und stand nie im Entwurf (12.09.2026). */
|
|
687
|
+
if (weg.some(function (v) { return String(v.id).indexOf('enum.') !== 0; })) {
|
|
688
|
+
wch.appendChild(el('span', 'chip mut', tr('write.removeHint')));
|
|
689
|
+
}
|
|
622
690
|
wk.appendChild(wch);
|
|
623
691
|
weg.forEach(function (v, i) {
|
|
624
692
|
var r = el('div', 'slot');
|
|
@@ -685,6 +753,19 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
685
753
|
kn2.disabled = false;
|
|
686
754
|
kn2.textContent = tr('write.retry');
|
|
687
755
|
kn2.title = mqFehler.join(' | ');
|
|
756
|
+
/* Und zwar so, dass es den Neuaufbau ueberlebt.
|
|
757
|
+
|
|
758
|
+
Drei Zeilen weiter unten wird der Entwurf neu gebaut
|
|
759
|
+
und der Trockenlauf noch einmal gerechnet - dabei
|
|
760
|
+
verschwindet dieser Knopf samt seiner Begruendung aus
|
|
761
|
+
dem DOM. Gemessen 12.09.2026: nach rund 120 ms war er
|
|
762
|
+
weg. Der neue Dialog sperrte wieder und sagte, welcher
|
|
763
|
+
Sendepunkt fehlt, aber nicht mehr, WARUM er nicht
|
|
764
|
+
entstanden ist (H17). Am Zustand gemerkt, zeichnet
|
|
765
|
+
`zeigeTrockenlauf` ihn oben wieder hin. */
|
|
766
|
+
S.mqFehler = mqFehler.slice();
|
|
767
|
+
} else {
|
|
768
|
+
S.mqFehler = null;
|
|
688
769
|
}
|
|
689
770
|
/* Erst den Entwurf neu aufbauen lassen, dann den
|
|
690
771
|
Trockenlauf noch einmal rechnen. Sofort geoeffnet zeigte
|
|
@@ -1024,6 +1105,16 @@ export function loescheAlias() {
|
|
|
1024
1105
|
m.style.fontSize = '13px';
|
|
1025
1106
|
if (fehler.length) {
|
|
1026
1107
|
m.appendChild(el('b', null, tr('write.failed', fehler.length)));
|
|
1108
|
+
/* Und WAS schiefging, nicht nur wie viel.
|
|
1109
|
+
|
|
1110
|
+
Beim Schreiben steht die Liste seit jeher da (`melden` beim
|
|
1111
|
+
Verlegen, der Trockenlauf-Dialog beim Anlegen); beim Loeschen
|
|
1112
|
+
fehlte sie, und zurueck blieb die blosse Zahl. Wer wissen
|
|
1113
|
+
will, welcher Punkt haengt — etwa weil ein Skript ihn sperrt
|
|
1114
|
+
—, erfuhr es nicht (G44, gemessen 12.09.2026). */
|
|
1115
|
+
var ul = el('ul');
|
|
1116
|
+
fehler.forEach(function (x) { ul.appendChild(el('li', null, x)); });
|
|
1117
|
+
m.appendChild(ul);
|
|
1027
1118
|
} else {
|
|
1028
1119
|
m.appendChild(el('b', null, tr('del.done', alle.length)));
|
|
1029
1120
|
}
|
|
@@ -1674,6 +1765,10 @@ export function schreibeObjekte() {
|
|
|
1674
1765
|
schlecht += pruefeSchreiben(en).length;
|
|
1675
1766
|
});
|
|
1676
1767
|
if (schlecht) { return; }
|
|
1768
|
+
/* Dieselbe Bereinigung wie im Trockenlauf - diese Liste entsteht neu,
|
|
1769
|
+
und ohne den Griff hier schriebe `setObject` die leere Aufzaehlung
|
|
1770
|
+
parallel zum `delObject` wieder hin. */
|
|
1771
|
+
leereEigeneEnums(liste, S.loeschListe);
|
|
1677
1772
|
|
|
1678
1773
|
var body = $('#dry-body');
|
|
1679
1774
|
var offen = liste.length;
|
package/admin/js/sprache.js
CHANGED
|
@@ -11,7 +11,9 @@ import { $ } from './basis.js';
|
|
|
11
11
|
export var expertenVorgabe = false;
|
|
12
12
|
|
|
13
13
|
/* ================== Sprachen ==================
|
|
14
|
-
Woerterbuch als flache Schluessel-Text-Karte unter admin/
|
|
14
|
+
Woerterbuch als flache Schluessel-Text-Karte unter admin/sprachen/.
|
|
15
|
+
(Nicht admin/i18n/ - dort liegt das Woerterbuch der Einstellungsseite,
|
|
16
|
+
das der Admin selbst laedt.)
|
|
15
17
|
Neue Sprache = neue Datei, sonst nichts. Faellt eine Uebersetzung
|
|
16
18
|
aus, greift Englisch, danach der Schluessel selbst — so bleibt die
|
|
17
19
|
Oberflaeche bedienbar statt leer. */
|
|
@@ -38,7 +40,7 @@ export function ladeSprache(fertig) {
|
|
|
38
40
|
var vorgabe = (navigator.language || 'en').slice(0, 2).toLowerCase();
|
|
39
41
|
|
|
40
42
|
function hole(code, ziel, danach) {
|
|
41
|
-
fetch('./
|
|
43
|
+
fetch('./sprachen/' + code + '.json')
|
|
42
44
|
.then(function (r) { return r.ok ? r.json() : {}; })
|
|
43
45
|
.then(function (d) { Object.keys(d).forEach(function (k) { ziel[k] = d[k]; }); danach(); })
|
|
44
46
|
.catch(function () { danach(); });
|
|
@@ -54,7 +56,12 @@ export function ladeSprache(fertig) {
|
|
|
54
56
|
|
|
55
57
|
var beantwortet = false;
|
|
56
58
|
socket.emit('getObject', 'system.config', function (err, obj) {
|
|
57
|
-
if (beantwortet) { return; }
|
|
59
|
+
/* Hier stand `if (beantwortet) { return; }` - der Waechter aus der
|
|
60
|
+
Zeit vor dem Nachziehen. Er stieg genau im Fall aus, fuer den der
|
|
61
|
+
Zweig weiter unten gebaut wurde, und machte ihn zu totem Text
|
|
62
|
+
(gemessen 12.09.2026: mit `expertMode: true` am System und einer
|
|
63
|
+
um 4 s verzoegerten Antwort blieb `expertenVorgabe` auch nach
|
|
64
|
+
zehn Sekunden auf `false`). */
|
|
58
65
|
/* Auch eine spaete Antwort gilt noch.
|
|
59
66
|
|
|
60
67
|
Nach 2,5 Sekunden geht es ohne weiter — richtig, sonst haengt der
|
package/admin/js/vorlagen.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { S } from './zustand.js';
|
|
8
8
|
import { D, $, el } from './basis.js';
|
|
9
9
|
import { hatPunkt, jsonVon, feldWert, kindZustaende, feldFormel } from './werte.js';
|
|
10
|
-
import { eigenerKanalName, merkeHakenVorgabe } from './entwurf.js';
|
|
10
|
+
import { eigenerKanalName, merkeHakenVorgabe, kennungtauglich } from './entwurf.js';
|
|
11
11
|
import { tasmotaBefehle } from './mqtt.js';
|
|
12
12
|
import { socket } from './verbindung.js';
|
|
13
13
|
|
|
@@ -271,7 +271,17 @@ export function setzeInstanz(text, v, n) {
|
|
|
271
271
|
export function ausgangName(e, n) {
|
|
272
272
|
if (e && e.kanal) {
|
|
273
273
|
var eigen = eigenerKanalName(e.kanal + '.' + n);
|
|
274
|
-
|
|
274
|
+
/* Der Kanalname wird hier zur KENNUNG - also durch dieselbe
|
|
275
|
+
Saeuberung wie ueberall sonst.
|
|
276
|
+
|
|
277
|
+
Vorher stand hier nur `replace(/\./g, '_')`. Leerzeichen und
|
|
278
|
+
Kommas blieben damit stehen, und der js-controller lehnt so etwas
|
|
279
|
+
nicht ab, er saeubert still: aus dem Kanalnamen „Licht, Bar" wurde
|
|
280
|
+
`alias.0.…Licht_ Bar`, waehrend die Werkbank „Licht, Bar" anzeigte
|
|
281
|
+
und in die Aufzaehlungen eintrug - eine Kennung, die es nie gab
|
|
282
|
+
(G31, gemessen 12.09.2026). Der Name selbst bleibt unberuehrt: er
|
|
283
|
+
steht als Beschriftung im Objekt. */
|
|
284
|
+
if (eigen) { return kennungtauglich(eigen) || eigen.replace(/\./g, '_'); }
|
|
275
285
|
}
|
|
276
286
|
if (!e || !e.kanalnameRoh) { return 'POWER' + n; }
|
|
277
287
|
return String(e.kanalnameRoh).split(e.platzhalter || '%N%').join(n);
|