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.
Files changed (54) hide show
  1. package/README.md +58 -98
  2. package/admin/css/werkbank.css +88 -0
  3. package/admin/i18n/de.json +766 -1
  4. package/admin/i18n/en.json +766 -1
  5. package/admin/i18n/es.json +766 -1
  6. package/admin/i18n/fr.json +766 -1
  7. package/admin/i18n/it.json +766 -1
  8. package/admin/i18n/nl.json +766 -1
  9. package/admin/i18n/pl.json +766 -1
  10. package/admin/i18n/pt.json +766 -1
  11. package/admin/i18n/ru.json +766 -1
  12. package/admin/i18n/uk.json +766 -1
  13. package/admin/i18n/zh-cn.json +766 -1
  14. package/admin/js/ablage.js +118 -0
  15. package/admin/js/attrappe.js +749 -0
  16. package/admin/js/baum.js +52 -5
  17. package/admin/js/detail.js +64 -3
  18. package/admin/js/entwurf.js +246 -31
  19. package/admin/js/ergebnis.js +77 -2
  20. package/admin/js/katalog.js +235 -40
  21. package/admin/js/mqtt.js +297 -27
  22. package/admin/js/musternamen.js +70 -26
  23. package/admin/js/objekte.js +2 -0
  24. package/admin/js/quellentausch.js +823 -16
  25. package/admin/js/schreiben.js +3 -2
  26. package/admin/js/sprache.js +11 -8
  27. package/admin/js/vorlagen.js +8 -3
  28. package/admin/js/vorlagenblatt.js +228 -64
  29. package/admin/js/werte.js +294 -5
  30. package/admin/js/zielleiste.js +19 -10
  31. package/admin/js/zuordnung.js +8 -7
  32. package/admin/js/zustand.js +32 -0
  33. package/admin/js/zustandsliste.js +9 -2
  34. package/admin/tab.html +24 -0
  35. package/admin/vorlagen/hm-dimmer.json +32 -8
  36. package/admin/vorlagen/hm-fensterkontakt-hm.json +20 -5
  37. package/admin/vorlagen/hm-fensterkontakt-hmip.json +28 -7
  38. package/admin/vorlagen/hm-heizgruppe.json +38 -11
  39. package/admin/vorlagen/hm-heizkoerper.json +42 -12
  40. package/admin/vorlagen/hm-rollladen.json +28 -7
  41. package/admin/vorlagen/hm-schaltaktor-lampe.json +24 -6
  42. package/admin/vorlagen/hm-schaltaktor-mehrfach.json +32 -8
  43. package/admin/vorlagen/hm-schaltaktor-steckdose.json +24 -6
  44. package/admin/vorlagen/hm-temperatur-feuchte.json +8 -2
  45. package/admin/vorlagen/hm-wandthermostat.json +36 -9
  46. package/admin/vorlagen/messpunkt.json +40 -10
  47. package/admin/vorlagen/tasmota-lampe.json +48 -12
  48. package/admin/vorlagen/tasmota-mehrfach.json +40 -10
  49. package/admin/vorlagen/tasmota-rgb.json +36 -9
  50. package/admin/vorlagen/tasmota-steckdose.json +56 -14
  51. package/io-package.json +41 -28
  52. package/package.json +3 -3
  53. package/admin/sprachen/de.json +0 -685
  54. package/admin/sprachen/en.json +0 -685
@@ -1,5 +1,6 @@
1
- import { holeText } from './basis.js';
2
- import { txt, alleTexte } from './sprache.js';
1
+ import { el, holeText } from './basis.js';
2
+ import { leseAblage, ergaenzeAblage, stempelAus } from './ablage.js';
3
+ import { tr, txt, alleTexte } from './sprache.js';
3
4
  import { einst } from './einstellungen.js';
4
5
  import './enums.js';
5
6
 
@@ -12,9 +13,11 @@ import './enums.js';
12
13
  aus dem Bundle, in dem sie ohnehin liegen. Wir laufen in derselben
13
14
  Herkunft wie der Admin, `fetch` genuegt.
14
15
 
15
- Der Weg fuehrt ueber drei Vite-Eigenheiten: die Bundles tragen Hashes
16
- im Namen, der Chunk heisst „Enums", und die Listen stehen darin als
17
- JSON.parse mit Backticks. Bricht eine davon, bleiben die Listen leer
16
+ Der Weg haengt am Bauwerkzeug des Admin, und das wechselt: bis 7.8.23
17
+ lagen die Listen als JSON.parse mit Rueckstrichen in einem „Enums"-
18
+ Chunk, seit 8.0.x als gewoehnliches JavaScript in einem Riesenmodul.
19
+ Beide Bauarten werden gelesen, das Ergebnis liegt danach im
20
+ Dateibereich. Bricht trotzdem etwas, bleiben die Listen leer
18
21
  und das Feld zeigt nur den Bestand - wie vorher. Kein Fehler, keine
19
22
  Meldung, nur weniger Auswahl. Deshalb faengt hier alles ab, was
20
23
  schiefgehen kann, ohne ein Wort zu verlieren. */
@@ -123,47 +126,239 @@ function ordneListenZu(text) {
123
126
  return enumVorlagen.rooms.length && enumVorlagen.functions.length;
124
127
  }
125
128
 
129
+ /* ---------------- Die zweite Bauart: alles in einem Riesenmodul ----------------
130
+
131
+ Admin 8.0.14 hat sein Bündel auf „Module Federation" umgestellt. Der
132
+ Inhalt ist derselbe geblieben — gemessen am 07.10.2026: dieselben 58
133
+ Räume und 62 Funktionen, Kennung für Kennung identisch, dieselben 120
134
+ Bilder —, aber er steckt jetzt in **einer** Datei von 7,9 MB statt in
135
+ vielen kleinen. Zwei Dinge haben uns daran gehindert, ihn zu finden:
136
+
137
+ * Die Zeile `if (t.length > 3000000) return false;` übersprang genau
138
+ diese Datei. Unter 7.8.23 lag der Katalog in einem Bündel von
139
+ 2 843 653 Bytes — fünf Prozent unter der Grenze. Es hat nie sicher
140
+ funktioniert, es ist bloß nie angestoßen.
141
+ * Die Listen stehen nicht mehr als JSON-Text in Rückstrichen, sondern
142
+ als gewöhnliches JavaScript: Schlüssel ohne Anführungszeichen,
143
+ Zeichenketten in Rückstrichen. `JSON.parse` greift da nicht.
144
+
145
+ Darum liest die Werkbank jetzt beide Bauarten. Und weil 7,9 MB bei
146
+ jedem Öffnen des Reiters unzumutbar wären, wird das Ergebnis im
147
+ Dateibereich des Adapters abgelegt und erst wieder geholt, wenn der
148
+ Admin seine Bündel neu schreibt. */
149
+
150
+ /* Eine Liste der Form `[{_id:`x`,name:{…},icon:`y.svg`}]`.
151
+
152
+ Kein `eval` und kein `new Function`: beides hieße, fremden Text
153
+ auszuführen, und der Gewinn wäre keiner. Die Einträge haben eine feste
154
+ Form, und in Namen kommen keine Rückstriche vor. */
155
+ function eintraegeAus(roh) {
156
+ var raus = [];
157
+ var re = /\{_id:`([^`]*)`,name:\{([\s\S]*?)\},icon:`([^`]*)`\}/g, m;
158
+ while ((m = re.exec(roh))) {
159
+ var name = {}, p = /(?:([A-Za-z0-9_$]+)|"([^"]+)"):`([^`]*)`/g, n;
160
+ while ((n = p.exec(m[2]))) { name[n[1] || n[2]] = n[3]; }
161
+ raus.push({ _id: m[1], name: name, icon: m[3].replace(/\.svg$/, '') });
162
+ }
163
+ return raus;
164
+ }
165
+
166
+ /* Von `pos` an die eckige Klammer ausbalancieren. */
167
+ function klammerAb(text, pos) {
168
+ var tiefe = 0;
169
+ for (var j = pos; j < text.length; j += 1) {
170
+ if (text[j] === '[') { tiefe += 1; }
171
+ else if (text[j] === ']') { tiefe -= 1; if (!tiefe) { return text.slice(pos, j + 1); } }
172
+ }
173
+ return null;
174
+ }
175
+
176
+ /* Die Bildkarte zu einer Liste: `{Anteroom:`PHN2…`, "Alarm Systems":`…`}`.
177
+
178
+ Gesucht wird über einen Bildnamen aus der Liste selbst — der
179
+ Variablenname wechselt bei jedem Bau des Admin, der Name „Storeroom"
180
+ nicht. Rückwärts bis zur öffnenden Klammer zu laufen ist hier sicher:
181
+ base64 enthält keine geschweiften Klammern. */
182
+ function ikonKarte(text, probe) {
183
+ var stelle = text.indexOf(probe + ':`');
184
+ if (stelle === -1) { stelle = text.indexOf('"' + probe + '":`'); }
185
+ if (stelle === -1) { return null; }
186
+ var auf = text.lastIndexOf('{', stelle);
187
+ if (auf === -1) { return null; }
188
+ var tiefe = 0, zu = -1;
189
+ for (var j = auf; j < text.length; j += 1) {
190
+ if (text[j] === '{') { tiefe += 1; }
191
+ else if (text[j] === '}') { tiefe -= 1; if (!tiefe) { zu = j; break; } }
192
+ }
193
+ if (zu === -1) { return null; }
194
+ var roh = text.slice(auf, zu + 1), karte = {};
195
+ var re = /(?:([A-Za-z0-9_$]+)|"([^"]+)"):`([A-Za-z0-9+/=]{40,})`/g, m;
196
+ while ((m = re.exec(roh))) { karte[m[1] || m[2]] = m[3]; }
197
+ return Object.keys(karte).length ? karte : null;
198
+ }
199
+
200
+ /* Beide Listen und beide Bildkarten aus dem Riesenmodul. */
201
+ function ausRiesenmodul(text) {
202
+ var gefunden = { rooms: null, functions: null };
203
+ var pos = 0;
204
+ for (;;) {
205
+ var i = text.indexOf('[{_id:`', pos);
206
+ if (i === -1) { break; }
207
+ pos = i + 7;
208
+ var roh = klammerAb(text, i);
209
+ if (!roh) { continue; }
210
+ var liste = eintraegeAus(roh);
211
+ if (liste.length < 20) { continue; }
212
+ if (!gefunden.rooms && istListe(liste, RAUM_MARKE)) { gefunden.rooms = liste; }
213
+ else if (!gefunden.functions && istListe(liste, FUNK_MARKE)) { gefunden.functions = liste; }
214
+ if (gefunden.rooms && gefunden.functions) { break; }
215
+ }
216
+ if (!gefunden.rooms || !gefunden.functions) { return null; }
217
+ return {
218
+ rooms: gefunden.rooms,
219
+ functions: gefunden.functions,
220
+ ikonen: {
221
+ rooms: ikonKarte(text, gefunden.rooms[0].icon) || {},
222
+ functions: ikonKarte(text, gefunden.functions[0].icon) || {}
223
+ }
224
+ };
225
+ }
226
+
227
+ /* ---------------- Der Hinweis, solange geholt wird ----------------
228
+
229
+ 7,9 MB dauern beim ersten Mal ein paar Sekunden. Ohne ein Wort dazu
230
+ wirkt das wie ein Hänger. Danach nie wieder, bis der Admin sich
231
+ ändert — und auch das gehört in den Hinweis, sonst fragt man sich
232
+ beim nächsten Mal, warum es plötzlich schnell geht. */
233
+ function laedtAn() {
234
+ if (document.getElementById('katalog-laedt')) { return; }
235
+ var k = el('div', 'katalog-laedt');
236
+ k.id = 'katalog-laedt';
237
+ k.appendChild(el('div', 'kl-kopf', tr('catalog.loadingTitle')));
238
+ k.appendChild(el('div', 'kl-text', tr('catalog.loadingText')));
239
+ document.body.appendChild(k);
240
+ }
241
+
242
+ function laedtAus() {
243
+ var k = document.getElementById('katalog-laedt');
244
+ if (k && k.parentNode) { k.parentNode.removeChild(k); }
245
+ }
246
+
247
+ /* Was aus der Ablage oder frisch kam, in die Arbeitsvariablen. */
248
+ function uebernehmen(satz) {
249
+ enumVorlagen.rooms = satz.rooms || [];
250
+ enumVorlagen.functions = satz.functions || [];
251
+ if (satz.ikonDateien) {
252
+ enumIkonen.rooms = satz.ikonDateien.rooms || {};
253
+ enumIkonen.functions = satz.ikonDateien.functions || {};
254
+ }
255
+ /* Fertige Bilder gleich in den Vorrat — bei der zweiten Bauart liegen
256
+ sie im selben Modul und müssen nicht einzeln nachgeholt werden. */
257
+ ['rooms', 'functions'].forEach(function (art) {
258
+ var karte = (satz.ikonen && satz.ikonen[art]) || {};
259
+ Object.keys(karte).forEach(function (name) {
260
+ ikonCache[art + ':' + name] = 'data:image/svg+xml;base64,' + karte[name];
261
+ });
262
+ });
263
+ }
264
+
126
265
  export function ladeEnumVorlagen(nachher) {
127
266
  if (vorlagenGeholt || !einst('vorlagenVomAdmin')) { return; }
128
267
  vorlagenGeholt = true;
129
- holeText('/index.html').then(function (html) {
130
- return sucheEnumChunk(html.match(/assets\/[A-Za-z0-9_\-.]+\.js/g) || [], {}, 0);
131
- }).then(function (chunk) {
132
- if (!chunk) { throw new Error('kein Enums-Chunk'); }
133
- return holeText('/assets/' + chunk);
134
- }).then(function (src) {
135
- enumIkonen.functions = ikonMap(src, 'devices');
136
- enumIkonen.rooms = ikonMap(src, 'rooms');
137
- if (ordneListenZu(src)) { return; }
138
-
139
- /* Fehlt eine, liegt sie in einer der Dateien, die der Chunk nennt.
140
- Kurze Namen zuerst: die Listen stecken in kleinen Bausteinen, das
141
- Riesenbuendel des Geraetemanagers waere sonst der erste Griff. */
142
- var dateien = (src.match(/[A-Za-z0-9_.-]+-[A-Za-z0-9_-]{8}\.js/g) || [])
143
- .filter(function (x, i, a) { return a.indexOf(x) === i; })
144
- .sort(function (a, b) { return a.length - b.length; })
145
- .slice(0, 60);
146
-
147
- return dateien.reduce(function (kette, f) {
148
- return kette.then(function (fertig) {
149
- if (fertig) { return true; }
150
- return holeText('/assets/' + f).then(function (t) {
151
- /* Ein Buendel von mehreren Megabyte durchsucht man nicht -
152
- die Listen stehen nie darin, das Durchsuchen kostet nur. */
153
- if (t.length > 3000000) { return false; }
154
- return ordneListenZu(t);
155
- })['catch'](function () { return false; });
268
+
269
+ var stempel = null;
270
+
271
+ function abschluss() {
272
+ laedtAus();
273
+ if (!enumVorlagen.rooms.length || !enumVorlagen.functions.length) {
274
+ katalogFehlt = true;
275
+ }
276
+ /* Der Aufrufer entscheidet, ob und was neu zu zeichnen ist -
277
+ dieses Modul kennt die Oberflaeche nicht. */
278
+ if (typeof nachher === 'function') { nachher(); }
279
+ }
280
+
281
+ /* Erste Bauart: der Enums-Chunk mit JSON.parse in Rueckstrichen. */
282
+ function ersterWeg() {
283
+ return holeText('/index.html').then(function (html) {
284
+ return sucheEnumChunk(html.match(/assets\/[A-Za-z0-9_\-.]+\.js/g) || [], {}, 0);
285
+ }).then(function (chunk) {
286
+ if (!chunk) { return false; }
287
+ return holeText('/assets/' + chunk).then(function (src) {
288
+ enumIkonen.functions = ikonMap(src, 'devices');
289
+ enumIkonen.rooms = ikonMap(src, 'rooms');
290
+ if (ordneListenZu(src)) { return true; }
291
+
292
+ /* Fehlt eine, liegt sie in einer der Dateien, die der Chunk
293
+ nennt. Kurze Namen zuerst: die Listen stecken in kleinen
294
+ Bausteinen. Ohne diese Nachsuche fand Admin 7.8.23 am
295
+ 07.10.2026 nur die 62 Funktionen und keinen einzigen Raum —
296
+ die Raumliste liegt dort in einer eigenen Datei. */
297
+ var dateien = (src.match(/[A-Za-z0-9_.-]+-[A-Za-z0-9_-]{8}\.js/g) || [])
298
+ .filter(function (x, i, a) { return a.indexOf(x) === i; })
299
+ .sort(function (a, b) { return a.length - b.length; })
300
+ .slice(0, 60);
301
+
302
+ return dateien.reduce(function (kette, f) {
303
+ return kette.then(function (fertig) {
304
+ if (fertig) { return true; }
305
+ return holeText('/assets/' + f).then(function (t) {
306
+ return ordneListenZu(t);
307
+ })['catch'](function () { return false; });
308
+ });
309
+ }, Promise.resolve(false));
156
310
  });
157
- }, Promise.resolve(false));
158
- })['catch'](function () { /* still bleiben: der Bestand genuegt */ })
159
- .then(function () {
160
- if (!enumVorlagen.rooms.length || !enumVorlagen.functions.length) {
161
- katalogFehlt = true;
311
+ })['catch'](function () { return false; });
312
+ }
313
+
314
+ /* Zweite Bauart: das Riesenmodul. Groesse ist jetzt kein Ausschluss
315
+ mehr, aber die Reihenfolge bleibt: kleine Dateien zuerst, das
316
+ Riesenmodul zuletzt, und nach dem ersten Treffer ist Schluss. */
317
+ function zweiterWeg() {
318
+ return holeText('/index.html').then(function (html) {
319
+ var dateien = (html.match(/assets\/[A-Za-z0-9_\-.]+\.js/g) || [])
320
+ .filter(function (x, i, a) { return a.indexOf(x) === i; });
321
+ var geholt = 0, treffer = null;
322
+ return dateien.reduce(function (kette, f) {
323
+ return kette.then(function () {
324
+ if (treffer || geholt > 25000000) { return; }
325
+ return holeText('/' + f).then(function (t) {
326
+ geholt += t.length;
327
+ var satz = ausRiesenmodul(t);
328
+ if (satz) { treffer = satz; }
329
+ })['catch'](function () { });
330
+ });
331
+ }, Promise.resolve()).then(function () { return treffer; });
332
+ })['catch'](function () { return null; });
333
+ }
334
+
335
+ holeText('/index.html').then(function (html) {
336
+ stempel = stempelAus(html);
337
+ return leseAblage();
338
+ }).then(function (abgelegt) {
339
+ if (abgelegt && abgelegt.stempel === stempel &&
340
+ (abgelegt.rooms || []).length && (abgelegt.functions || []).length) {
341
+ uebernehmen(abgelegt);
342
+ return null;
343
+ }
344
+ /* Jetzt wird wirklich geholt - und erst jetzt sagen wir es. */
345
+ laedtAn();
346
+ return ersterWeg().then(function (ging) {
347
+ if (ging) {
348
+ return { rooms: enumVorlagen.rooms, functions: enumVorlagen.functions,
349
+ ikonDateien: { rooms: enumIkonen.rooms, functions: enumIkonen.functions } };
162
350
  }
163
- /* Der Aufrufer entscheidet, ob und was neu zu zeichnen ist -
164
- dieses Modul kennt die Oberflaeche nicht. */
165
- if (typeof nachher === 'function') { nachher(); }
351
+ return zweiterWeg().then(function (satz) {
352
+ if (!satz) { return null; }
353
+ uebernehmen(satz);
354
+ return satz;
355
+ });
166
356
  });
357
+ }).then(function (zumAblegen) {
358
+ if (!zumAblegen) { return null; }
359
+ return ergaenzeAblage(stempel, zumAblegen);
360
+ })['catch'](function () { /* still bleiben: der Bestand genuegt */ })
361
+ .then(abschluss);
167
362
  }
168
363
 
169
364
  /* Das Icon einer Vorlage. Es steht als fertige data-URI im Chunk - genau