iobroker.alias-workbench 0.8.2 → 0.9.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 +77 -0
- package/admin/css/werkbank.css +57 -8
- package/admin/detector.js +1 -1
- package/admin/i18n/de.json +13 -0
- package/admin/i18n/en.json +13 -0
- package/admin/js/baum.js +27 -4
- package/admin/js/detail.js +58 -6
- package/admin/js/entwurf.js +140 -4
- package/admin/js/ergebnis.js +124 -35
- package/admin/js/erkennung.js +54 -5
- package/admin/js/musternamen.js +91 -26
- package/admin/js/quellentausch.js +2 -2
- package/admin/js/schreiben.js +25 -7
- package/admin/js/sprache.js +3 -0
- package/admin/js/vorlagen.js +22 -2
- package/admin/js/vorlagenblatt.js +2 -3
- package/admin/js/werte.js +20 -0
- package/admin/js/zielleiste.js +5 -2
- package/admin/js/zuordnung.js +139 -15
- package/admin/js/zustand.js +7 -1
- package/admin/js/zustandsliste.js +144 -17
- package/admin/tab.html +8 -0
- package/io-package.json +27 -1
- package/package.json +1 -1
package/admin/js/erkennung.js
CHANGED
|
@@ -4,6 +4,55 @@
|
|
|
4
4
|
import { S } from './zustand.js';
|
|
5
5
|
import { D } from './basis.js';
|
|
6
6
|
|
|
7
|
+
/* Der Ausdruck eines Platzes als blosser Text — ohne Schraegstriche.
|
|
8
|
+
|
|
9
|
+
Der Detector liefert seine Muster ueber `ChannelDetector.getPatterns()`
|
|
10
|
+
(so haengt `src/detector-bundle.js` sie an `window`), und diese Funktion
|
|
11
|
+
gibt `role` nicht als RegExp weiter, sondern als `role.toString()` —
|
|
12
|
+
also MIT den Schraegstrichen:
|
|
13
|
+
|
|
14
|
+
/^indicator(\.maintenance)?\.(lowbat|battery)$/
|
|
15
|
+
|
|
16
|
+
Das ist bei uns der Normalfall, nicht die Ausnahme: ein RegExp bekommen
|
|
17
|
+
wir nur, wenn jemand die Muster direkt aus `typePatterns` liest, etwa
|
|
18
|
+
ein Test. Wer bloss `.source` abfragt und sonst `String(r)` nimmt, haelt
|
|
19
|
+
die Schraegstriche fuer Teil des Ausdrucks und findet danach weder den
|
|
20
|
+
Anker `^` noch das Ende `$`.
|
|
21
|
+
|
|
22
|
+
Gefunden am 08.09.2026 am Produktivsystem, und der eine Fehler zog weit:
|
|
23
|
+
`ROLLEN` hatte 210 statt 232 Eintraege (E27) — `indicator.lowbat` fehlte,
|
|
24
|
+
die Rolle, die hm-rpc schreibt —, `BRIGHTNESS` bekam in sechs Mustern gar
|
|
25
|
+
keine Rolle (E6), `plaetzeFuerRollen` fand zu keiner einzigen Rolle einen
|
|
26
|
+
Platz, und die Abweichungskarte behauptete „haette ohnehin nicht
|
|
27
|
+
gezaehlt" ueber Punkte mit Platz. Die Node-Tests sahen nichts davon: sie
|
|
28
|
+
fuettern die Zerlegung mit echten RegExp-Literalen.
|
|
29
|
+
|
|
30
|
+
Deshalb geht seither jede Stelle, die einen Platzausdruck liest, hier
|
|
31
|
+
durch — es sind sieben. */
|
|
32
|
+
export function ausdruckText(r) {
|
|
33
|
+
if (!r) { return ''; }
|
|
34
|
+
if (r.source !== undefined) { return r.source; }
|
|
35
|
+
var q = String(r);
|
|
36
|
+
var m = /^\/(.*)\/[a-z]*$/.exec(q);
|
|
37
|
+
return m ? m[1] : q;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Der Ausdruck als RegExp — fuer alle, die damit pruefen wollen. Wirft
|
|
41
|
+
nicht: ein unbrauchbarer Ausdruck gibt `null`, und der Aufrufer
|
|
42
|
+
entscheidet, was das heisst. */
|
|
43
|
+
export function ausdruckRegExp(r) {
|
|
44
|
+
var q = ausdruckText(r);
|
|
45
|
+
if (!q) { return null; }
|
|
46
|
+
try { return new RegExp(q); } catch { return null; }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Passt eine Rolle auf den Ausdruck eines Platzes? */
|
|
50
|
+
export function rolleTrifft(r, rolle) {
|
|
51
|
+
if (!rolle) { return false; }
|
|
52
|
+
var re = ausdruckRegExp(r);
|
|
53
|
+
return re ? re.test(rolle) : false;
|
|
54
|
+
}
|
|
55
|
+
|
|
7
56
|
/* Die Rollen kommen aus dem Paket, nicht aus einer eigenen Liste —
|
|
8
57
|
sonst pflegt man eine zweite Wahrheit, die auseinanderlaeuft. */
|
|
9
58
|
/* Manche Plaetze nennen keine Standardrolle, sondern nur einen
|
|
@@ -13,8 +62,8 @@ import { D } from './basis.js';
|
|
|
13
62
|
liess sich beliebig oft hinzufuegen, und die Rolle fehlte auch in der
|
|
14
63
|
Auswahlliste — der Platz war auf keinem Weg zu befuellen. */
|
|
15
64
|
export function rolleAusAusdruck(r) {
|
|
16
|
-
|
|
17
|
-
|
|
65
|
+
var q = ausdruckText(r);
|
|
66
|
+
if (!q) { return ''; }
|
|
18
67
|
if (q.charAt(0) !== '^' || q.slice(-1) !== '$') { return ''; }
|
|
19
68
|
var t = q.slice(1, -1).split(String.fromCharCode(92)).join('');
|
|
20
69
|
return /^[A-Za-z0-9_]+([.][A-Za-z0-9_]+)*$/.test(t) ? t : '';
|
|
@@ -41,8 +90,8 @@ export function rolleVonPlatz(st) { return st.defaultRole || rolleAusAusdruck(st
|
|
|
41
90
|
dann bleibt es bei der Vorgaberolle. Lieber eine Schreibweise zu wenig
|
|
42
91
|
als eine erfundene in der Liste. */
|
|
43
92
|
export function schreibweisenAus(r) {
|
|
44
|
-
|
|
45
|
-
|
|
93
|
+
var q = ausdruckText(r);
|
|
94
|
+
if (!q) { return []; }
|
|
46
95
|
if (q.charAt(0) !== '^' || q.slice(-1) !== '$') { return []; }
|
|
47
96
|
q = q.slice(1, -1);
|
|
48
97
|
|
|
@@ -160,7 +209,7 @@ export function plaetzeFuerRollen(musterName) {
|
|
|
160
209
|
ROLLEN.forEach(function (r) {
|
|
161
210
|
mu.states.forEach(function (st) {
|
|
162
211
|
if (raus[r] || !st.role) { return; }
|
|
163
|
-
|
|
212
|
+
if (rolleTrifft(st.role, r)) { raus[r] = st.name; }
|
|
164
213
|
});
|
|
165
214
|
});
|
|
166
215
|
return raus;
|
package/admin/js/musternamen.js
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
|
-
/* Die uebersetzten Namen der Muster, angezapft beim
|
|
1
|
+
/* Die uebersetzten Namen der Muster, angezapft beim Admin.
|
|
2
2
|
|
|
3
|
-
Der type-detector kennt nur rohe Typnamen (socket, thermostat)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
Der type-detector kennt nur rohe Typnamen (socket, thermostat) und
|
|
4
|
+
bringt selbst KEINE Uebersetzung mit - er ist eine Bibliothek
|
|
5
|
+
(`@iobroker/type-detector`), kein Adapter. Uebersetzt werden seine
|
|
6
|
+
Typen nur in den Sprachdateien der Adapter, die ihn benutzen, und
|
|
7
|
+
jeder schleppt seine eigene Kopie mit. Ein Block je Sprache, jeder
|
|
8
|
+
gibt sich am Eintrag "type-Device type" selbst zu erkennen; wir holen
|
|
9
|
+
den der Oberflaechensprache und schlagen darin nach. Eine eigene
|
|
10
|
+
Liste wuerde bei jedem type-detector-Update altern (Ricardos Punkt 13,
|
|
11
|
+
25.08.2026 - Weg 2, wie der Raum/Funktion-Katalog).
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
Gefragt wird ausschliesslich der ADMIN. Bis zum 08.09.2026 war es der
|
|
14
|
+
Geraete-Adapter; Ricardos Begruendung fuer den Wechsel: Der Admin ist
|
|
15
|
+
immer installiert, `devices` nicht, und er wird besser gepflegt. Was
|
|
16
|
+
er nicht uebersetzt, bleibt eben roh - gemessen am 08.09.2026:
|
|
17
|
+
Admin 8.0.11 kennt alle 53 Typen, Admin 7.8.23 nur 44.
|
|
18
|
+
|
|
19
|
+
Der Weg dorthin geht ueber zwei Verzeichnisse, weil keines allein
|
|
20
|
+
reicht: `index.html` nennt bei Admin 8 das richtige Buendel, bei
|
|
21
|
+
Admin 7 aber nur vier Bootstrap-Haeppchen, und die fuehren nicht
|
|
22
|
+
weiter (34 Dateien durchsucht, nichts gefunden). Dort steht die Karte
|
|
23
|
+
in einer Datei, die erst `mf-manifest.json` nennt - der Admin laedt
|
|
24
|
+
seine Oberflaeche ueber Module Federation. Also beide Listen
|
|
25
|
+
zusammen, kurze Dateien zuerst.
|
|
26
|
+
|
|
27
|
+
Bricht die Kette - Aufbau geaendert, Datei zu gross -, bleibt die
|
|
28
|
+
Karte leer und ueberall steht der rohe Name. Kein Fehler, nur weniger
|
|
29
|
+
Komfort. Beide Schreibweisen werden verstanden: Werte in Backticks
|
|
30
|
+
(Admin 8) und als JSON-Strings (Admin 7). */
|
|
16
31
|
|
|
17
32
|
import { sprache } from './sprache.js';
|
|
18
33
|
import { holeText } from './basis.js';
|
|
@@ -44,26 +59,76 @@ function ziehe(src) {
|
|
|
44
59
|
return Object.keys(raus).length ? raus : null;
|
|
45
60
|
}
|
|
46
61
|
|
|
62
|
+
/* Welche Dateien der Admin ueberhaupt ausliefert. Zwei Verzeichnisse,
|
|
63
|
+
zusammengelegt und ohne Doppel - siehe Kopf: keines allein reicht
|
|
64
|
+
fuer beide Admin-Fassungen. */
|
|
65
|
+
function adminDateien() {
|
|
66
|
+
var raus = [];
|
|
67
|
+
function dazu(f) {
|
|
68
|
+
/* Fuehrendes `./` weg, sonst zaehlt dieselbe Datei zweimal: das
|
|
69
|
+
Manifest schreibt `assets/lib-….js`, das index.html
|
|
70
|
+
`./assets/lib-….js`. Ohne dieses Abschneiden stuenden 30 Eintraege
|
|
71
|
+
in einer Liste, die nach 25 abgeschnitten wird - und die gesuchte
|
|
72
|
+
Datei faellt genauso heraus wie damals bei der Sortierung nach
|
|
73
|
+
Namenslaenge. */
|
|
74
|
+
f = f.replace(/^\.\//, '');
|
|
75
|
+
if (raus.indexOf(f) === -1) { raus.push(f); }
|
|
76
|
+
}
|
|
77
|
+
/* Gesucht werden PFADE, keine blossen Dateinamen.
|
|
78
|
+
|
|
79
|
+
Beide Verzeichnisse schreiben den Ordner dazu, wo einer gehoert:
|
|
80
|
+
`"sync":["assets/lib-DSjRYjfP.js"]` im Manifest, `assets/…js` im
|
|
81
|
+
index.html. Wer nur den Dateinamen aufsammelt und stur `assets/`
|
|
82
|
+
davorsetzt, erfindet zwei Pfade, die es nicht gibt: das Manifest
|
|
83
|
+
nennt unter `remoteEntry` und `ssrRemoteEntry` je einen Namen mit
|
|
84
|
+
ausdruecklich leerem `"path":""` - die zwei Dateien liegen unter `/`.
|
|
85
|
+
Das gab beim Laden zwei 404 in der Konsole (A1, gefunden 08.09.2026
|
|
86
|
+
produktiv). Geholfen haben sie ohnehin nie: hinter remoteEntry steckt
|
|
87
|
+
der Einstieg von Module Federation, nicht die Sprachkarte.
|
|
88
|
+
|
|
89
|
+
Der Schraegstrich im Muster ist zugleich die Bedingung - ein nackter
|
|
90
|
+
Name kommt so gar nicht erst in die Liste, und ein Admin, der seine
|
|
91
|
+
Buendel eines Tages woanders ablegt, wird trotzdem gefunden. */
|
|
92
|
+
var pfade = /[A-Za-z0-9_\-.]+\/[A-Za-z0-9_\-./]+\.js/g;
|
|
93
|
+
return holeText('/mf-manifest.json')['catch'](function () { return ''; })
|
|
94
|
+
.then(function (mf) {
|
|
95
|
+
(mf.match(pfade) || []).forEach(dazu);
|
|
96
|
+
return holeText('/index.html')['catch'](function () { return ''; });
|
|
97
|
+
})
|
|
98
|
+
.then(function (html) {
|
|
99
|
+
(html.match(pfade) || []).forEach(dazu);
|
|
100
|
+
/* Reihenfolge bleibt, wie die Verzeichnisse sie nennen. Erst
|
|
101
|
+
wurde nach Namenslaenge sortiert - uebernommen vom
|
|
102
|
+
Aufzaehlungskatalog, wo es das Riesenbuendel nach hinten
|
|
103
|
+
schiebt. Hier war es genau falsch: der Name der gesuchten Datei
|
|
104
|
+
ist bei Admin 8 mit 143 Zeichen der laengste ueberhaupt, sie
|
|
105
|
+
rutschte ans Ende und fiel aus der Auswahl. Ungeordnet steht
|
|
106
|
+
sie an fuenfter Stelle von 21, bei Admin 7 an vierter von 19 -
|
|
107
|
+
beide Verzeichnisse nennen das Wichtige zuerst (gemessen
|
|
108
|
+
08.09.2026). Das Groessenlimit unten haelt die dicken Buendel
|
|
109
|
+
ohnehin heraus. */
|
|
110
|
+
return raus.slice(0, 25);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
47
114
|
export function ladeMusterNamen(nachher) {
|
|
48
115
|
if (geholt) { return; }
|
|
49
116
|
geholt = true;
|
|
50
|
-
|
|
51
|
-
/* Die tab.html nennt mehrere Bausteine (Bootstrap-Haeppchen,
|
|
52
|
-
Vendor, Hauptbundle). Die Karte steckt im Hauptbundle - das
|
|
53
|
-
heisst in beiden bekannten Fassungen index-<hash>.js, also
|
|
54
|
-
dieses zuerst, die uebrigen als Rueckfall der Reihe nach. */
|
|
55
|
-
var dateien = (html.match(/assets\/[A-Za-z0-9_\-.]+\.js/g) || [])
|
|
56
|
-
.filter(function (x, i, a) { return a.indexOf(x) === i; })
|
|
57
|
-
.sort(function (a, b) {
|
|
58
|
-
return (b.indexOf('assets/index-') === 0 ? 1 : 0)
|
|
59
|
-
- (a.indexOf('assets/index-') === 0 ? 1 : 0);
|
|
60
|
-
})
|
|
61
|
-
.slice(0, 8);
|
|
117
|
+
adminDateien().then(function (dateien) {
|
|
62
118
|
if (!dateien.length) { throw new Error('kein Bundle'); }
|
|
63
119
|
return dateien.reduce(function (kette, f) {
|
|
64
120
|
return kette.then(function (fertig) {
|
|
65
121
|
if (fertig) { return true; }
|
|
66
|
-
return holeText('/
|
|
122
|
+
return holeText('/' + f).then(function (src) {
|
|
123
|
+
/* Die Grenze liegt hoeher als beim Aufzaehlungskatalog (3 MB):
|
|
124
|
+
bei Admin 8 steckt die Karte ausgerechnet im grossen
|
|
125
|
+
GUI-Buendel, gemessen 8,4 MB (08.09.2026). Mit der alten
|
|
126
|
+
Grenze wurde genau diese Datei uebersprungen und produktiv
|
|
127
|
+
blieb jeder Beiname roh. Teuer ist es nicht: derselbe Admin
|
|
128
|
+
hat das Buendel gerade selbst geladen, der zweite Griff
|
|
129
|
+
kommt aus dem Zwischenspeicher des Browsers. Alles darueber
|
|
130
|
+
ist kein Buendel mehr, sondern ein Versehen. */
|
|
131
|
+
if (src.length > 12000000) { return false; }
|
|
67
132
|
var karte = ziehe(src);
|
|
68
133
|
if (karte) { musterNamen = karte; return true; }
|
|
69
134
|
return false;
|
|
@@ -23,7 +23,7 @@ import { tr, txt } from './sprache.js';
|
|
|
23
23
|
import { socket } from './verbindung.js';
|
|
24
24
|
import { aliasQuellen, kindZustaende } from './werte.js';
|
|
25
25
|
import { holeZweig, indexNeu } from './objekte.js';
|
|
26
|
-
import { waehle } from './entwurf.js';
|
|
26
|
+
import { waehle, knotenDa } from './entwurf.js';
|
|
27
27
|
import { zeichneErgebnis } from './ergebnis.js';
|
|
28
28
|
|
|
29
29
|
/* Die Punkte des Alias, die ueberhaupt eine Quelle haben. */
|
|
@@ -325,7 +325,7 @@ export function zeigeTausch() {
|
|
|
325
325
|
/* Wie bei zeigeVerlegen und zeigeLoeschen: an der Quelle ist
|
|
326
326
|
S.current die Quelle, gemeint ist das Ziel des Entwurfs (T1). */
|
|
327
327
|
var ziel = (S.entwurf && (S.entwurf.ziel || S.entwurf.kanal)) || S.current;
|
|
328
|
-
if (!ziel || ziel.indexOf('alias.') !== 0 || !
|
|
328
|
+
if (!ziel || ziel.indexOf('alias.') !== 0 || !knotenDa(ziel)) { return; }
|
|
329
329
|
S.tauschZiel = ziel;
|
|
330
330
|
S.tauschNeu = '';
|
|
331
331
|
S.tauschWeg = {};
|
package/admin/js/schreiben.js
CHANGED
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
gemeinsameKanaele,
|
|
20
20
|
kennungtauglich,
|
|
21
21
|
entwurfFuer,
|
|
22
|
-
aliasFuer
|
|
22
|
+
aliasFuer,
|
|
23
|
+
knotenDa
|
|
23
24
|
} from './entwurf.js';
|
|
24
25
|
import { zeichneErgebnis } from './ergebnis.js';
|
|
25
26
|
|
|
@@ -163,8 +164,22 @@ export function objektText(o, geordnet) {
|
|
|
163
164
|
return JSON.stringify(geordnet ? ordne(k, '') : k, null, 2);
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
/* Der gespeicherte Stand zu einer Kennung.
|
|
168
|
+
|
|
169
|
+
Aufzaehlungen liegen nicht in `S.objects` - die Werkbank haelt sie in
|
|
170
|
+
einem eigenen Vorrat, weil der Admin sie getrennt ausliefert. Der
|
|
171
|
+
Trockenlauf las trotzdem nur `S.objects`, und so blieb die Spalte
|
|
172
|
+
„bisher" bei jeder Aufzaehlung leer: verglichen wurde gegen nichts,
|
|
173
|
+
also stand rechts jede Zeile als neu da - auch die zehn Mitglieder,
|
|
174
|
+
die laengst drin waren (Ricardo, 08.09.2026). */
|
|
175
|
+
export function bestandsObjekt(id) {
|
|
176
|
+
if (S.objects[id]) { return S.objects[id]; }
|
|
177
|
+
if (String(id).indexOf('enum.') === 0 && enums[id]) { return enums[id]; }
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
166
181
|
export function unveraendert(id, obj) {
|
|
167
|
-
var alt =
|
|
182
|
+
var alt = bestandsObjekt(id);
|
|
168
183
|
if (!alt) { return false; }
|
|
169
184
|
var putz = function (x) {
|
|
170
185
|
var k = JSON.parse(JSON.stringify(x || {}));
|
|
@@ -301,7 +316,9 @@ export function baueObjekte(e) {
|
|
|
301
316
|
das wird nicht ungefragt geloescht. */
|
|
302
317
|
export function verwaiste(e) {
|
|
303
318
|
var ziel = e.ziel || e.kanal;
|
|
304
|
-
|
|
319
|
+
/* Auch ohne Kanalobjekt kann darunter ein Alias liegen - dann gibt es
|
|
320
|
+
dort auch verwaiste Punkte zu finden. */
|
|
321
|
+
if (!knotenDa(ziel)) { return []; }
|
|
305
322
|
var behalten = {};
|
|
306
323
|
e.states.forEach(function (st) {
|
|
307
324
|
if (st.on && st.n) { behalten[ziel + '.' + st.n] = 1; }
|
|
@@ -473,7 +490,8 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
473
490
|
verspraeche er eine Wirkung, die er nicht hat. */
|
|
474
491
|
var vergleichbar = liste.filter(function (x) { return !x.neu && !x.gleich; });
|
|
475
492
|
var rohAnders = vergleichbar.some(function (x) {
|
|
476
|
-
|
|
493
|
+
var b0 = bestandsObjekt(x.id);
|
|
494
|
+
return objektText(b0, false) !== objektText(b0, true)
|
|
477
495
|
|| objektText(x.obj, false) !== objektText(x.obj, true);
|
|
478
496
|
});
|
|
479
497
|
if (vergleichbar.length && rohAnders) {
|
|
@@ -672,7 +690,7 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
672
690
|
var vgl = el('div', 'dvgl');
|
|
673
691
|
vgl.appendChild(el('span', 'dkopf', tr('write.diffOld')));
|
|
674
692
|
vgl.appendChild(el('span', 'dkopf', tr('write.diffNew')));
|
|
675
|
-
zeilenVergleich(objektText(
|
|
693
|
+
zeilenVergleich(objektText(bestandsObjekt(x.id), !S.trockenRoh),
|
|
676
694
|
objektText(x.obj, !S.trockenRoh))
|
|
677
695
|
.forEach(function (z) {
|
|
678
696
|
vgl.appendChild(el('span', 'dz l ' + z.art, z.l === undefined ? '' : z.l));
|
|
@@ -693,7 +711,7 @@ export function zeigeTrockenlauf(alleAusgaenge) {
|
|
|
693
711
|
var zt = $('#dry-titel');
|
|
694
712
|
if (zt) {
|
|
695
713
|
var zielName = S.entwurf.ziel || S.entwurf.kanal;
|
|
696
|
-
zt.textContent = (
|
|
714
|
+
zt.textContent = (knotenDa(zielName) ? tr('write.dryTitleUpdate') : tr('write.dryTitleCreate')) +
|
|
697
715
|
(entwuerfe.length > 1 ? tr('write.dryOutputs', entwuerfe.length) : '');
|
|
698
716
|
}
|
|
699
717
|
/* Beim Oeffnen wieder herstellen: der Dialog wird wiederverwendet, und
|
|
@@ -729,7 +747,7 @@ function geschwisterVon(ziel) {
|
|
|
729
747
|
|
|
730
748
|
export function zeigeLoeschen() {
|
|
731
749
|
var ziel = (S.entwurf && (S.entwurf.ziel || S.entwurf.kanal)) || S.current;
|
|
732
|
-
if (!ziel || ziel.indexOf('alias.') !== 0 || !
|
|
750
|
+
if (!ziel || ziel.indexOf('alias.') !== 0 || !knotenDa(ziel)) { return; }
|
|
733
751
|
S.loeschZiel = ziel;
|
|
734
752
|
S.loeschAlleAusgaenge = false;
|
|
735
753
|
zeichneLoeschen();
|
package/admin/js/sprache.js
CHANGED
|
@@ -110,6 +110,9 @@ export function beschrifteHtml() {
|
|
|
110
110
|
setz('#tpl-titel', tr('tpls.title', ''));
|
|
111
111
|
setz('#btn-tpl-save', tr('tpls.saveNew'));
|
|
112
112
|
setz('#mqtt-titel', tr('mq.dialogTitle'));
|
|
113
|
+
/* Der Titel des Info-Dialogs traegt den Musternamen und wird beim
|
|
114
|
+
Oeffnen gesetzt; hier steht nur der Rueckfall ohne Muster. */
|
|
115
|
+
setz('#info-titel', tr('info.dlgTitle', ''));
|
|
113
116
|
setz('#guess-titel', tr('guess.tplTitle'));
|
|
114
117
|
setz('#btn-guess-go', tr('guess.tplGo'));
|
|
115
118
|
setz('#tree .empty', tr('tree.loading'));
|
package/admin/js/vorlagen.js
CHANGED
|
@@ -12,7 +12,7 @@ import { tasmotaBefehle } from './mqtt.js';
|
|
|
12
12
|
import { socket } from './verbindung.js';
|
|
13
13
|
|
|
14
14
|
import { tr, sprachtext } from './sprache.js';
|
|
15
|
-
import { musterVon } from './erkennung.js';
|
|
15
|
+
import { musterVon, rolleTrifft } from './erkennung.js';
|
|
16
16
|
|
|
17
17
|
/* Welche Instanz — der Reiter wird mit ?<instanz>&noFooter geladen. */
|
|
18
18
|
var INSTANZ = (function () {
|
|
@@ -29,6 +29,24 @@ export function zeigeObjektzahl() {
|
|
|
29
29
|
if (z) { z.textContent = tr('app.objectsCount', S.keysSorted.length); }
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/* Wie viele Wertabos laufen gerade? Steht neben der Objektzahl.
|
|
33
|
+
|
|
34
|
+
Nicht aus Neugier: die Abos werden beim Wechsel des Knotens abgemeldet
|
|
35
|
+
und neu gesetzt, und ob dabei wirklich alle wieder verschwinden, sieht
|
|
36
|
+
man sonst nirgends. Bleibt die Zahl beim Durchklicken stabil, stimmt
|
|
37
|
+
es; waechst sie, sammelt sich etwas an (Ricardo, 08.09.2026). */
|
|
38
|
+
export function zeigeAbozahl() {
|
|
39
|
+
var z = $('#meta-abos');
|
|
40
|
+
if (!z) { return; }
|
|
41
|
+
var n = (S.abo || []).length;
|
|
42
|
+
z.textContent = ' \u00b7 ' + (n === 1 ? tr('app.subsCount1') : tr('app.subsCount', n));
|
|
43
|
+
/* Die Muster gehoeren dazu, sonst ist die Zahl ein Raetsel: „2 Abos"
|
|
44
|
+
bei zwanzig sichtbaren Werten liest sich falsch, bis man sieht, dass
|
|
45
|
+
ein Muster einen ganzen Zweig deckt (Ricardo, 08.09.2026). */
|
|
46
|
+
z.title = tr('app.subsHint') + String.fromCharCode(10) +
|
|
47
|
+
(S.abo || []).map(function (mu) { return ' ' + mu; }).join(String.fromCharCode(10));
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
export function setzeMeta() {
|
|
33
51
|
var m = $('#meta');
|
|
34
52
|
if (!m) { return; }
|
|
@@ -41,6 +59,8 @@ export function setzeMeta() {
|
|
|
41
59
|
steht sie neben ihresgleichen; ein eigener Span, damit das Abo sie
|
|
42
60
|
nachfuehren kann, ohne die ganze Zeile neu zu bauen. */
|
|
43
61
|
m.appendChild(el('span', null, tr('app.objectsCount', S.keysSorted.length))).id = 'meta-objekte';
|
|
62
|
+
m.appendChild(el('span', null, '')).id = 'meta-abos';
|
|
63
|
+
zeigeAbozahl();
|
|
44
64
|
if (S.vorlagenUnvollstaendig) {
|
|
45
65
|
var w = el('span', 'chip bad', tr('tpls.loadFailed'));
|
|
46
66
|
w.style.marginLeft = '8px';
|
|
@@ -559,7 +579,7 @@ export function anMusterAnpassen(e, neuTyp) {
|
|
|
559
579
|
var s = null;
|
|
560
580
|
muster.states.forEach(function (st) {
|
|
561
581
|
if (s || !st.role) { return; }
|
|
562
|
-
|
|
582
|
+
if (rolleTrifft(st.role, rolle)) { s = st; } /* eine kaputte Rolle macht die Vorlage nicht passend */
|
|
563
583
|
});
|
|
564
584
|
return s;
|
|
565
585
|
}
|
|
@@ -9,7 +9,7 @@ import { D, $, el, kurz } from './basis.js';
|
|
|
9
9
|
import { tr, sprachtext, sprache } from './sprache.js';
|
|
10
10
|
import { katalogFehlt } from './katalog.js';
|
|
11
11
|
import { funktionsAuswahl, kennungZuFunktion } from './aufzaehlungen.js';
|
|
12
|
-
import { musterVon } from './erkennung.js';
|
|
12
|
+
import { musterVon, rolleTrifft } from './erkennung.js';
|
|
13
13
|
import { musterZeile, musterName } from './musternamen.js';
|
|
14
14
|
import { ladeVorlagen, aendereVorlagen, setzeMeta, pruefeVorlage, INSTANZ_ID } from './vorlagen.js';
|
|
15
15
|
import { kindZustaende, hatPunkt, feldAusFormel } from './werte.js';
|
|
@@ -551,8 +551,7 @@ function rollenBlock(rolle, geraetetyp, setzen) {
|
|
|
551
551
|
if (must) {
|
|
552
552
|
var treffer = null;
|
|
553
553
|
must.states.forEach(function (pp) {
|
|
554
|
-
if (!treffer && pp.role && rolle
|
|
555
|
-
new RegExp(pp.role.source ? pp.role.source : pp.role).test(rolle)) { treffer = pp; }
|
|
554
|
+
if (!treffer && pp.role && rolleTrifft(pp.role, rolle)) { treffer = pp; }
|
|
556
555
|
});
|
|
557
556
|
var hin = el('div', 'sugg');
|
|
558
557
|
if (treffer) {
|
package/admin/js/werte.js
CHANGED
|
@@ -93,6 +93,26 @@ export function holeWerte(kanal, extraIds, fertig) {
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/* Nur diese Kennungen, ohne den Rundumschlag ueber einen Kanal.
|
|
97
|
+
|
|
98
|
+
Gebraucht dort, wo Zeilen erst spaeter dazukommen und ihre Quelle
|
|
99
|
+
ausserhalb des angeklickten Knotens liegt - dann ist der Kanal
|
|
100
|
+
laengst abgefragt, und ein zweites `getForeignStates` darauf braechte
|
|
101
|
+
nichts als Last. */
|
|
102
|
+
export function holeEinzelne(ids, fertig) {
|
|
103
|
+
var eindeutig = {};
|
|
104
|
+
(ids || []).forEach(function (i) { if (i) { eindeutig[i] = 1; } });
|
|
105
|
+
var liste = Object.keys(eindeutig);
|
|
106
|
+
if (!liste.length) { if (typeof fertig === 'function') { fertig(false); } return; }
|
|
107
|
+
var offen = liste.length, etwas = false;
|
|
108
|
+
liste.forEach(function (id) {
|
|
109
|
+
socket.emit('getState', id, function (err, st) {
|
|
110
|
+
if (!err && st) { S.werte[id] = st; etwas = true; }
|
|
111
|
+
if (--offen <= 0 && typeof fertig === 'function') { fertig(etwas); }
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
96
116
|
/* ================== Formel und Wert ================== */
|
|
97
117
|
export function auswerten(formel, roh) {
|
|
98
118
|
if (roh === undefined || roh === null) { return { ok: false, txt: tr('detail.noValue') }; }
|
package/admin/js/zielleiste.js
CHANGED
|
@@ -11,7 +11,7 @@ import { el } from './basis.js';
|
|
|
11
11
|
import { tr } from './sprache.js';
|
|
12
12
|
import { enumListe } from './aufzaehlungen.js';
|
|
13
13
|
import { enumZeile, setzeZiel } from './zuordnung.js';
|
|
14
|
-
import { aliasFuer, ordnerUnterAlias, kennungtauglich } from './entwurf.js';
|
|
14
|
+
import { aliasFuer, ordnerUnterAlias, kennungtauglich, knotenDa } from './entwurf.js';
|
|
15
15
|
import { zeichneErgebnis, entwurfAngefasst, angebotFrisch } from './ergebnis.js';
|
|
16
16
|
import { zeigeVerlegen } from './schreiben.js';
|
|
17
17
|
|
|
@@ -303,7 +303,10 @@ export function baueZielleiste(host, e) {
|
|
|
303
303
|
/* Beide Faelle, an einer Stelle. Vorher stand „wird neu angelegt"
|
|
304
304
|
oben im Kopf und „gibt es schon" hier — zwei Formulierungen fuer
|
|
305
305
|
dieselbe Auskunft, an zwei Orten. */
|
|
306
|
-
|
|
306
|
+
/* `knotenDa`, nicht `S.objects`: ein Alias, dessen Punkte von Hand
|
|
307
|
+
angelegt wurden, hat oft kein Kanalobjekt - der Chip meldete dort
|
|
308
|
+
„wird neu angelegt", obwohl geaendert wird (Ricardo, 08.09.2026). */
|
|
309
|
+
var gibtsZiel = knotenDa(e.ziel);
|
|
307
310
|
var ch2 = el('span', 'chip ' + (gibtsZiel ? 'warn' : 'ok'),
|
|
308
311
|
gibtsZiel ? tr('target.exists') : tr('result.newlyCreated'));
|
|
309
312
|
ch2.style.marginLeft = '7px';
|