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
|
@@ -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,
|
|
12
|
+
import { musterVon, platzFuerRolle, typenFuerRolle } from './erkennung.js';
|
|
13
13
|
import { musterZeile, musterName } from './musternamen.js';
|
|
14
14
|
import { ladeVorlagen, aendereVorlagen, setzeMeta, pruefeVorlage, hinweisTaugt, INSTANZ_ID } from './vorlagen.js';
|
|
15
15
|
import { kindZustaende, hatPunkt, feldAusFormel } from './werte.js';
|
|
@@ -283,9 +283,12 @@ export function zeichneVorlagenBlatt(host) {
|
|
|
283
283
|
var st = el('select', 'tx');
|
|
284
284
|
st.disabled = !eigen;
|
|
285
285
|
st.appendChild(opt('', tr('tpls.noType')));
|
|
286
|
+
/* Wie im Speichern-Dialog: der Wert ist der Typ, nicht der
|
|
287
|
+
Musterschluessel. musterwahl.js loest es seit laengerem so. */
|
|
286
288
|
(D ? Object.keys(D.patterns).sort() : []).forEach(function (m) {
|
|
287
|
-
var
|
|
288
|
-
|
|
289
|
+
var typ = D.patterns[m].type || m;
|
|
290
|
+
var o = opt(typ, musterZeile(m));
|
|
291
|
+
if (typ === v.geraetetyp) { o.selected = true; }
|
|
289
292
|
st.appendChild(o);
|
|
290
293
|
});
|
|
291
294
|
st.addEventListener('change', function () {
|
|
@@ -543,7 +546,7 @@ function dtFeld(beschriftung, element) {
|
|
|
543
546
|
|
|
544
547
|
/* Rollenauswahl samt Begruendung. geraetetyp darf leer sein — dann
|
|
545
548
|
entfaellt nur der Hinweis, welchen Platz die Rolle traefe. */
|
|
546
|
-
function rollenBlock(rolle, geraetetyp, setzen) {
|
|
549
|
+
function rollenBlock(rolle, geraetetyp, setzen, typJetzt, setzeTyp) {
|
|
547
550
|
var rb = el('div');
|
|
548
551
|
/* Dasselbe durchsuchbare Feld wie am Geraet - ein Aussehen fuer alle
|
|
549
552
|
Rollenwahlen. Ohne Belegt-Vermerk: in der Vorlage gibt es keinen
|
|
@@ -553,24 +556,38 @@ function rollenBlock(rolle, geraetetyp, setzen) {
|
|
|
553
556
|
muster: geraetetyp,
|
|
554
557
|
leerErlaubt: true,
|
|
555
558
|
breite: '300px',
|
|
556
|
-
|
|
559
|
+
/* Wie am Geraet: der Platz bringt seinen Datentyp mit, also wird er
|
|
560
|
+
beim Waehlen der Rolle gleich gesetzt. Eine Vorlage, deren Rolle
|
|
561
|
+
stimmt und deren Typ nicht, faellt sonst lautlos aus dem Muster. */
|
|
562
|
+
beiWahl: function (r) {
|
|
563
|
+
/* Wie am Geraet: nur ein eindeutiger Typ wird gesetzt. */
|
|
564
|
+
var moegliche = typenFuerRolle(geraetetyp, r);
|
|
565
|
+
if (moegliche.length === 1 && setzeTyp && typJetzt !== moegliche[0]) { setzeTyp(moegliche[0]); }
|
|
566
|
+
setzen(r);
|
|
567
|
+
}
|
|
557
568
|
}));
|
|
558
569
|
|
|
559
570
|
var must = geraetetyp && musterVon(geraetetyp);
|
|
560
571
|
if (must) {
|
|
561
|
-
var treffer =
|
|
562
|
-
|
|
563
|
-
if (!treffer && pp.role && rolleTrifft(pp.role, rolle)) { treffer = pp; }
|
|
564
|
-
});
|
|
572
|
+
var treffer = platzFuerRolle(geraetetyp, rolle, typJetzt);
|
|
573
|
+
var erlaubt = typenFuerRolle(geraetetyp, rolle);
|
|
565
574
|
var hin = el('div', 'sugg');
|
|
566
575
|
if (treffer) {
|
|
567
576
|
hin.appendChild(document.createTextNode(tr('pattern.fitsOn')));
|
|
568
577
|
hin.appendChild(el('b', null, String(treffer.role)));
|
|
569
578
|
hin.appendChild(document.createTextNode(tr('pattern.toSlot', treffer.name, musterName(geraetetyp) || geraetetyp)));
|
|
579
|
+
if (erlaubt.length) {
|
|
580
|
+
hin.appendChild(document.createTextNode(
|
|
581
|
+
tr('pattern.expectsType', erlaubt.join(tr('pattern.typeOr')))));
|
|
582
|
+
}
|
|
570
583
|
} else {
|
|
571
584
|
hin.textContent = tr('pattern.noPlaceLong', musterName(geraetetyp) || geraetetyp);
|
|
572
585
|
}
|
|
573
586
|
rb.appendChild(hin);
|
|
587
|
+
if (treffer && typJetzt && erlaubt.length && erlaubt.indexOf(typJetzt) === -1) {
|
|
588
|
+
rb.appendChild(el('div', 'aside w',
|
|
589
|
+
tr('pattern.typeMismatch', treffer.name, erlaubt.join(tr('pattern.typeOr')), typJetzt)));
|
|
590
|
+
}
|
|
574
591
|
}
|
|
575
592
|
return rb;
|
|
576
593
|
}
|
|
@@ -782,7 +799,7 @@ function vZeilenDetail(z, nr) {
|
|
|
782
799
|
|
|
783
800
|
dtZeile(d, tr('detail.role'), rollenBlock(z.rolle, v.geraetetyp, function (neu) {
|
|
784
801
|
setzeFeld('rolle', neu);
|
|
785
|
-
}));
|
|
802
|
+
}, z.typ, function (t) { setzeFeld('typ', t); }));
|
|
786
803
|
|
|
787
804
|
dtZeile(d, tr('detail.display'), anzeigeBlock(
|
|
788
805
|
function (was) {
|
|
@@ -1222,9 +1239,24 @@ export function vorlagenVorbereiten(e) {
|
|
|
1222
1239
|
|
|
1223
1240
|
var zeilen = [];
|
|
1224
1241
|
e.states.forEach(function (s) {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1242
|
+
/* Eine Zeile braucht wenigstens ein Ziel - lesend oder schreibend.
|
|
1243
|
+
`STOP` am Rollladen hat nur ein Schreibziel: ein Tastendruck hat
|
|
1244
|
+
keinen Zustand zum Lesen. Bis 11.09.2026 stand hier `!s.srcR`,
|
|
1245
|
+
und solche Zeilen fielen beim Speichern lautlos weg. Dass das
|
|
1246
|
+
Anwenden diesen Fall kennt, steht seit dem 09.09.2026 in
|
|
1247
|
+
vorlagen.js - die Gegenrichtung war vergessen worden. */
|
|
1248
|
+
if (!s.n || (!s.srcR && !s.srcW)) { return; }
|
|
1249
|
+
var r = s.srcR ? relZu(s.srcR, e.kanal) : { p: '', abs: false };
|
|
1250
|
+
/* Das Schreibziel gehoert in die Vorlage, auch wenn es derselbe
|
|
1251
|
+
Punkt ist wie der gelesene. Bis 11.09.2026 stand hier zusaetzlich
|
|
1252
|
+
`s.srcW !== s.srcR`, und genau das trifft auf jeden Aktor zu, der
|
|
1253
|
+
seinen eigenen Zustand fuehrt: Rollladen, Dimmer, Thermostat
|
|
1254
|
+
schreiben auf denselben Punkt, den sie lesen (1.LEVEL). Beim
|
|
1255
|
+
Speichern verschwand ihr Schreibweg - der Alias zeigte die
|
|
1256
|
+
Position an und liess sich nicht mehr verstellen. Aufgefallen
|
|
1257
|
+
bei Tasmota nie, weil dort tele.STATE gelesen und cmnd.POWER
|
|
1258
|
+
geschrieben wird. */
|
|
1259
|
+
var w = s.srcW ? relZu(s.srcW, e.kanal) : null;
|
|
1228
1260
|
var zv = null;
|
|
1229
1261
|
if (quelle && s.ausVorlage) {
|
|
1230
1262
|
(quelle.zustaende || []).forEach(function (z) { if (z.name === s.ausVorlage) { zv = z; } });
|
|
@@ -1348,9 +1380,11 @@ export function baueVorlage(z) {
|
|
|
1348
1380
|
name: r.name,
|
|
1349
1381
|
rolle: s.role || undefined,
|
|
1350
1382
|
typ: s.typ || undefined,
|
|
1351
|
-
einheit: s.unit || undefined
|
|
1352
|
-
lesen: zPfad(r, k, false, z.zeilen)
|
|
1383
|
+
einheit: s.unit || undefined
|
|
1353
1384
|
};
|
|
1385
|
+
/* Ohne Lesequelle kein `lesen` - sonst stuende dort ein leerer
|
|
1386
|
+
Pfad, und `wendeAn` suchte einen Punkt namens "". */
|
|
1387
|
+
if (r.lesenRoh) { zu.lesen = zPfad(r, k, false, z.zeilen); }
|
|
1354
1388
|
if (r.lesenAbs) { zu.absolut = true; }
|
|
1355
1389
|
if (r.schreibenRoh) { zu.schreiben = zPfad(r, k, true, z.zeilen); }
|
|
1356
1390
|
if (f) { zu.feld = f; } else if (s.f) { zu.leseformel = s.f; }
|
|
@@ -1696,9 +1730,16 @@ export function zeichneVorlagenDialog() {
|
|
|
1696
1730
|
lt.appendChild(el('span', 'feldlabel', tr('tpls.deviceType')));
|
|
1697
1731
|
var st = el('select', 'tx');
|
|
1698
1732
|
st.appendChild(opt('', tr('tpls.noType')));
|
|
1733
|
+
/* Der Wert ist der Geraetetyp, nicht der Musterschluessel - drei
|
|
1734
|
+
Muster tragen einen anderen Namen als ihr Typ: blinds meldet
|
|
1735
|
+
"blind", mediaPlayer meldet "media", levelSlider meldet "slider".
|
|
1736
|
+
Die Vorlagen fuehren den Typ. Bis 11.09.2026 stand hier der
|
|
1737
|
+
Schluessel, und an jedem Rollladen zeigte der Dialog
|
|
1738
|
+
"- keiner -", obwohl "blind" gesetzt war. */
|
|
1699
1739
|
(D ? Object.keys(D.patterns).sort() : []).forEach(function (m) {
|
|
1700
|
-
var
|
|
1701
|
-
|
|
1740
|
+
var typ = D.patterns[m].type || m;
|
|
1741
|
+
var o = opt(typ, musterZeile(m));
|
|
1742
|
+
if (typ === k.geraetetyp) { o.selected = true; }
|
|
1702
1743
|
st.appendChild(o);
|
|
1703
1744
|
});
|
|
1704
1745
|
st.addEventListener('change', function () { k.geraetetyp = st.value; zeichneVorlagenDialog(); });
|
|
@@ -2017,19 +2058,81 @@ export function zeichneVorlagenDialog() {
|
|
|
2017
2058
|
|
|
2018
2059
|
var b = $('#btn-tpl-save');
|
|
2019
2060
|
if (b) {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2061
|
+
/* Fuenf Gruende sperren den Knopf - und jeder von ihnen gehoert
|
|
2062
|
+
hingeschrieben.
|
|
2063
|
+
|
|
2064
|
+
Bisher wurde nur `disabled` gesetzt, `title` blieb leer. Bei
|
|
2065
|
+
fehlenden Pflichtpunkten stand die Erklaerung weiter unten in der
|
|
2066
|
+
Probelauf-Karte, fuer die man scrollen musste; bei den anderen
|
|
2067
|
+
vier stand sie nirgends. Ricardo stiess darauf, als er fuer den
|
|
2068
|
+
Objektdump eine eigene Vorlage anlegen wollte - grauer Knopf,
|
|
2069
|
+
kein Wort dazu (I32, 11.09.2026). Ein Knopf, der nicht sagt warum,
|
|
2070
|
+
ist derselbe Fehler wie eine Sperre ohne Begruendung (U28). */
|
|
2071
|
+
var gruende = sperrgruende(z);
|
|
2072
|
+
b.disabled = gruende.length > 0;
|
|
2073
|
+
b.title = gruende.join(' · ');
|
|
2023
2074
|
b.textContent = k.modus === 'update' ? tr('tpls.saveUpdate') : tr('tpls.saveNew');
|
|
2075
|
+
if (gruende.length) {
|
|
2076
|
+
var sk = el('div', 'aside w');
|
|
2077
|
+
sk.style.borderLeftColor = 'var(--bad)';
|
|
2078
|
+
sk.appendChild(el('b', null, tr('tpls.lockedWhy')));
|
|
2079
|
+
var sul = el('ul');
|
|
2080
|
+
gruende.forEach(function (x) { sul.appendChild(el('li', null, x)); });
|
|
2081
|
+
sk.appendChild(sul);
|
|
2082
|
+
body.appendChild(sk);
|
|
2083
|
+
}
|
|
2024
2084
|
}
|
|
2025
2085
|
var tt = $('#tpl-titel');
|
|
2026
2086
|
if (tt) { tt.textContent = tr('tpls.title', z.e.kanal.split('.').pop()); }
|
|
2027
2087
|
}
|
|
2028
2088
|
|
|
2089
|
+
/* Die fuenf Gruende, die das Speichern sperren - an einer Stelle.
|
|
2090
|
+
|
|
2091
|
+
Gebraucht werden sie zweimal: beim Zeichnen, um Knopf und Kasten zu
|
|
2092
|
+
beschriften, und beim Speichern selbst. Das zweite ist keine
|
|
2093
|
+
Doppelung, sondern die eigentliche Sicherung: Der Knopf wird beim
|
|
2094
|
+
VERLASSEN eines Feldes neu bewertet, nicht beim Tippen. Wer eine
|
|
2095
|
+
offene Klammer in den Namenshinweis schreibt und ohne Umweg auf
|
|
2096
|
+
„Vorlage speichern" klickt, hat einen blauen Knopf vor sich - und die
|
|
2097
|
+
Vorlage wurde mit `namenshinweis: "("` gespeichert (Ricardo,
|
|
2098
|
+
12.09.2026, am Testsystem nachgestellt; `hinweisTrifft` faengt den
|
|
2099
|
+
kaputten Ausdruck zwar ab, aber gespeichert gehoert er trotzdem
|
|
2100
|
+
nicht). */
|
|
2101
|
+
export function sperrgruende(z) {
|
|
2102
|
+
if (!z) { return []; }
|
|
2103
|
+
var k = z.kopf;
|
|
2104
|
+
var neu = baueVorlage(z);
|
|
2105
|
+
var gruende = [];
|
|
2106
|
+
if (!neu.erkennung.erforderlich.length) { gruende.push(tr('tpls.lockNoRequired')); }
|
|
2107
|
+
if (!k.id) { gruende.push(tr('tpls.lockNoId')); }
|
|
2108
|
+
var fremd = fremdeMitId(k);
|
|
2109
|
+
if (fremd) { gruende.push(tr('tpls.lockIdTaken', fremd.id)); }
|
|
2110
|
+
if (!hinweisTaugt(k.namenshinweis)) { gruende.push(tr('tpls.lockBadHint')); }
|
|
2111
|
+
if (!z.zeilen.filter(function (r) { return !r.weg; }).length) { gruende.push(tr('tpls.lockNoRows')); }
|
|
2112
|
+
return gruende;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2029
2115
|
export function speichereVorlageAusDialog() {
|
|
2030
2116
|
if (!S.tplZ) { return; }
|
|
2031
2117
|
var neu = baueVorlage(S.tplZ);
|
|
2032
2118
|
|
|
2119
|
+
/* Letzte Instanz, unabhaengig vom Zustand des Knopfes. */
|
|
2120
|
+
var gesperrt = sperrgruende(S.tplZ);
|
|
2121
|
+
if (gesperrt.length) {
|
|
2122
|
+
var bodyS = $('#tpl-body');
|
|
2123
|
+
var altS = bodyS.querySelector('.sperrgrund-kasten');
|
|
2124
|
+
if (altS) { altS.remove(); }
|
|
2125
|
+
var wS = el('div', 'aside w sperrgrund-kasten');
|
|
2126
|
+
wS.style.borderLeftColor = 'var(--bad)';
|
|
2127
|
+
wS.appendChild(el('b', null, tr('tpls.lockedWhy')));
|
|
2128
|
+
var ulS = el('ul');
|
|
2129
|
+
gesperrt.forEach(function (x) { ulS.appendChild(el('li', null, x)); });
|
|
2130
|
+
wS.appendChild(ulS);
|
|
2131
|
+
bodyS.insertBefore(wS, bodyS.firstChild);
|
|
2132
|
+
bodyS.scrollTop = 0;
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2033
2136
|
/* Widerspricht sie sich, wird nicht gespeichert — eine Vorlage, die
|
|
2034
2137
|
auf nichts passen kann, hilft niemandem und ist spaeter schwer zu
|
|
2035
2138
|
durchschauen. */
|
package/admin/js/werte.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { S } from './zustand.js';
|
|
8
8
|
import { socket } from './verbindung.js';
|
|
9
|
-
import { tr } from './sprache.js';
|
|
9
|
+
import { tr, txt } from './sprache.js';
|
|
10
10
|
import './entwurf.js';
|
|
11
11
|
|
|
12
12
|
/* Direkt nachschlagen — die Vorlagen nennen den Pfad ja vollstaendig
|
|
@@ -76,10 +76,23 @@ export function mitVorspann(pre) {
|
|
|
76
76
|
return raus;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/* Wie der Baum: POWER2 vor POWER10.
|
|
80
|
+
|
|
81
|
+
`keysSorted` MUSS byteweise sortiert bleiben - die Binaersuche in
|
|
82
|
+
`mitVorspann` haengt daran. Fuer die Anzeige ist das die falsche
|
|
83
|
+
Ordnung: an einer Mehrfachsteckdose stand `POWER10` vor `POWER2`,
|
|
84
|
+
waehrend der Baum daneben richtig zaehlte (er nimmt `Intl.Collator`
|
|
85
|
+
mit `numeric: true`). Also wird hier nachsortiert, wo die Liste
|
|
86
|
+
entsteht - je Kanal ein paar Dutzend Eintraege, nicht der
|
|
87
|
+
Gesamtindex (gemessen 12.09.2026). */
|
|
88
|
+
var ZEILEN_VERGLEICH = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
|
|
89
|
+
|
|
79
90
|
export function kindZustaende(kanal) {
|
|
80
91
|
var pre = kanal + '.';
|
|
81
92
|
return mitVorspann(pre).filter(function (k) {
|
|
82
93
|
return S.objects[k] && S.objects[k].type === 'state';
|
|
94
|
+
}).sort(function (a, b) {
|
|
95
|
+
return ZEILEN_VERGLEICH.compare(a.slice(pre.length), b.slice(pre.length));
|
|
83
96
|
});
|
|
84
97
|
}
|
|
85
98
|
|
|
@@ -112,6 +125,55 @@ export function schreibQuelle(o) {
|
|
|
112
125
|
return (c.write === true || typeof a.write === 'string') ? (q.write || '') : '';
|
|
113
126
|
}
|
|
114
127
|
|
|
128
|
+
/* Aus einem Alias-Objekt die Felder einer Entwurfszeile.
|
|
129
|
+
|
|
130
|
+
Dieselbe Umrechnung stand fuenfmal ausprogrammiert - dreimal in
|
|
131
|
+
`entwurf.js`, zweimal in `zuordnung.js` -, jedes Mal mit derselben
|
|
132
|
+
Schreibquellenregel und leicht anderem Drumherum. Die Kommentare an
|
|
133
|
+
jenen Stellen dokumentieren vier Fehler, die genau daraus entstanden
|
|
134
|
+
sind: eine verlorene Schreibquelle am Rollladen, ein schaltender Punkt
|
|
135
|
+
der zum lesenden wurde, eine fehlende Beschriftung an Solar.Netz und
|
|
136
|
+
eine Abweichung, die die Werkbank selbst erzeugt hatte (Y5).
|
|
137
|
+
|
|
138
|
+
Was hier steht, ist die ABLEITUNG - nicht, was damit geschieht. Die
|
|
139
|
+
eine Stelle vergleicht nur, die zweite legt eine Zeile an, die beiden
|
|
140
|
+
anderen ueberschreiben eine bestehende; das bleibt bei den Aufrufern.
|
|
141
|
+
|
|
142
|
+
`baueEntwurf` ruft sie bewusst NICHT: die Funktion baut Zeilen fuer
|
|
143
|
+
zwei Faelle, Alias und rohe Quelle, und drei der Felder haengen dort
|
|
144
|
+
an dieser Unterscheidung. Sie mit Schaltern hereinzuholen waere
|
|
145
|
+
schlechter als zwei ehrliche Stellen.
|
|
146
|
+
|
|
147
|
+
Die Beschriftung folgt der Regel „leer, wenn sie dem Zeilennamen
|
|
148
|
+
gleicht" - so halten es `vomAliasUebernehmen` und der Zweig, der neue
|
|
149
|
+
Zeilen anlegt. `bestandVorrang` will sie anders (uebernehmen, sobald
|
|
150
|
+
`common.name` gesetzt ist) und behaelt dafuer eine eigene Zeile.
|
|
151
|
+
|
|
152
|
+
Und `role`/`typ` bleiben bei den beiden Stellen, die eine BESTEHENDE
|
|
153
|
+
Zeile ueberschreiben (`bestandVorrang`, `vomAliasUebernehmen`), an
|
|
154
|
+
ihrer `!== undefined`-Frage: dort steht schon der Vorlagenwert, und
|
|
155
|
+
ein Alias, der gar keine Rolle nennt, soll ihn behalten statt ihn
|
|
156
|
+
gegen den Leerstring zu tauschen, den diese Funktion liefert. Wer das
|
|
157
|
+
wegraeumt, nimmt jedem vorlagenbasierten Alias seine Rollen. */
|
|
158
|
+
export function zeileAusAlias(o, zeilenname) {
|
|
159
|
+
var c = (o && o.common) || {};
|
|
160
|
+
var a = c.alias || {};
|
|
161
|
+
var q = aliasQuellen(o);
|
|
162
|
+
var nm = txt(c.name);
|
|
163
|
+
return {
|
|
164
|
+
role: c.role || '',
|
|
165
|
+
typ: c.type || '',
|
|
166
|
+
unit: c.unit || '',
|
|
167
|
+
states: c.states || undefined,
|
|
168
|
+
wr: !!c.write,
|
|
169
|
+
srcR: q.read || '',
|
|
170
|
+
srcW: schreibQuelle(o),
|
|
171
|
+
f: (typeof a.read === 'string') ? a.read : '',
|
|
172
|
+
fw: (typeof a.write === 'string') ? a.write : '',
|
|
173
|
+
caption: (nm && nm !== zeilenname) ? nm : ''
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
115
177
|
export function aliasQuellen(obj) {
|
|
116
178
|
var a = obj && obj.common && obj.common.alias;
|
|
117
179
|
if (!a) { return {}; }
|
package/admin/js/zuordnung.js
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
} from './aufzaehlungen.js';
|
|
15
15
|
import { enumVorlagen, katalogFehlt, ikonCache, ikonErlaubt, ikonNachtrag,
|
|
16
16
|
ikonTaugt, vorlageZu, holeIkon } from './katalog.js';
|
|
17
|
-
import { kindZustaende, aliasQuellen, holeEinzelne,
|
|
17
|
+
import { kindZustaende, aliasQuellen, holeEinzelne,
|
|
18
|
+
zeileAusAlias } from './werte.js';
|
|
18
19
|
import { aliasFuer, zielId, knotenDa } from './entwurf.js';
|
|
19
20
|
import { zeichneErgebnis, entwurfAngefasst, angebotFrisch } from './ergebnis.js';
|
|
20
21
|
|
|
@@ -580,7 +581,8 @@ export function uebernehmeBestand(e) {
|
|
|
580
581
|
hiesse, dem Vorlagenknopf den Wert zu nehmen, den er zurueckholen
|
|
581
582
|
soll. */
|
|
582
583
|
function vomAliasUebernehmen(z, o) {
|
|
583
|
-
var c = o.common || {},
|
|
584
|
+
var c = o.common || {}, q2 = aliasQuellen(o);
|
|
585
|
+
var ist = zeileAusAlias(o, z.n);
|
|
584
586
|
if (!z.vorlagenWert) {
|
|
585
587
|
z.vorlagenWert = {
|
|
586
588
|
on: z.on, role: z.role, typ: z.typ, unit: z.unit, caption: z.caption,
|
|
@@ -593,10 +595,10 @@ export function uebernehmeBestand(e) {
|
|
|
593
595
|
stellen, kann der Stand nicht wieder auseinanderlaufen. */
|
|
594
596
|
if (c.role !== undefined) { z.role = c.role; }
|
|
595
597
|
if (c.type !== undefined) { z.typ = c.type; }
|
|
596
|
-
z.unit =
|
|
597
|
-
z.states =
|
|
598
|
-
z.f =
|
|
599
|
-
z.fw =
|
|
598
|
+
z.unit = ist.unit;
|
|
599
|
+
z.states = ist.states;
|
|
600
|
+
z.f = ist.f;
|
|
601
|
+
z.fw = ist.fw;
|
|
600
602
|
/* Die Beschriftung steht im Alias und gehoert dem Nutzer.
|
|
601
603
|
|
|
602
604
|
Sie fehlte hier als einzige - `bestandVorrang` holt sie laengst
|
|
@@ -607,8 +609,7 @@ export function uebernehmeBestand(e) {
|
|
|
607
609
|
„Bezug" geworden (Ricardo, 07.09.2026, an alias.0.Solar.Netz).
|
|
608
610
|
Gleicht die Beschriftung dem Zeilennamen, bleibt sie leer - so
|
|
609
611
|
haelt es der Zweig darunter, der neue Zeilen anlegt, auch. */
|
|
610
|
-
|
|
611
|
-
z.caption = (nm2 && nm2 !== z.n) ? nm2 : '';
|
|
612
|
+
z.caption = ist.caption;
|
|
612
613
|
if (q2.read) { z.srcR = q2.read; }
|
|
613
614
|
/* Und dieselbe Schreibregel wie im Bestandsvorrang.
|
|
614
615
|
|
|
@@ -622,7 +623,7 @@ export function uebernehmeBestand(e) {
|
|
|
622
623
|
Belegt ist das Schreiben durch `common.write` oder durch eine
|
|
623
624
|
hinterlegte Schreibformel; bei getrennten Quellen zaehlt, was in
|
|
624
625
|
`alias.id.write` steht. */
|
|
625
|
-
z.srcW =
|
|
626
|
+
z.srcW = ist.srcW;
|
|
626
627
|
if (q2.write && !q2.einfach && q2.write !== q2.read) {
|
|
627
628
|
/* Die Gegenzeile eines Paars ist keine eigene mehr - ihre Quelle
|
|
628
629
|
steckt jetzt als Schreibquelle in dieser Zeile. */
|
|
@@ -663,7 +664,7 @@ export function uebernehmeBestand(e) {
|
|
|
663
664
|
kindZustaende(e.ziel).forEach(function (id) {
|
|
664
665
|
var n = id.slice(e.ziel.length + 1);
|
|
665
666
|
if (n.indexOf('.') !== -1 || kennt[n]) { return; }
|
|
666
|
-
var o = S.objects[id],
|
|
667
|
+
var o = S.objects[id], q = aliasQuellen(o);
|
|
667
668
|
|
|
668
669
|
/* Derselbe Punkt unter anderem Namen? Dann ist es kein zweiter,
|
|
669
670
|
sondern derselbe — und der Name, der schon im Alias steht, gilt.
|
|
@@ -699,31 +700,24 @@ export function uebernehmeBestand(e) {
|
|
|
699
700
|
kennt[n] = vorhanden;
|
|
700
701
|
return;
|
|
701
702
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
gemacht (Ricardo, 08.09.2026). */
|
|
721
|
-
srcW: schreibQuelle(o),
|
|
722
|
-
f: (typeof a.read === 'string') ? a.read : '',
|
|
723
|
-
fw: (typeof a.write === 'string') ? a.write : '',
|
|
724
|
-
caption: (nm && nm !== n) ? nm : '',
|
|
725
|
-
manuell: false
|
|
726
|
-
});
|
|
703
|
+
/* Rolle, Typ, Einheit, Zustaende, Formeln, Quellen und Beschriftung
|
|
704
|
+
kommen geschlossen aus `zeileAusAlias` - dieselbe Ablesung wie in
|
|
705
|
+
`bestandVorrang`, `bestandsAbweichung` und `vomAliasUebernehmen`.
|
|
706
|
+
|
|
707
|
+
Dazu gehoert die Schreibregel: Hier stand `q.einfach ? '' :
|
|
708
|
+
(q.write || '')` - bei schlichtem `alias.id` also immer leer, ohne
|
|
709
|
+
`common.write` ueberhaupt anzusehen. Es trifft jeden Alias, bei dem
|
|
710
|
+
MEHRERE Punkte auf denselben Quellpunkt zeigen: die eine
|
|
711
|
+
Vorschlagszeile bekommt der erste von ihnen, alle weiteren landen
|
|
712
|
+
hier. Am `alias.0.Badezimmer.Rollladen` zeigen OPEN, CLOSE, SET und
|
|
713
|
+
pct alle auf `…Bad.level`; CLOSE lief oben durch und behielt seine
|
|
714
|
+
Schreibquelle, OPEN, SET und pct verloren sie - ein Aktualisieren
|
|
715
|
+
haette den Rollladen ueber den Alias unfahrbar gemacht (Ricardo,
|
|
716
|
+
08.09.2026). Seit dem Zusammenlegen der vier Stellen (Y5) gilt die
|
|
717
|
+
Regel fuer alle zugleich. */
|
|
718
|
+
e.states.push(Object.assign(zeileAusAlias(o, n), {
|
|
719
|
+
n: n, on: true, ausBestand: true, nurImAlias: true, manuell: false
|
|
720
|
+
}));
|
|
727
721
|
});
|
|
728
722
|
|
|
729
723
|
/* Einmal nachzeichnen.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { S } from './zustand.js';
|
|
10
10
|
import { el, $ } from './basis.js';
|
|
11
11
|
import { tr } from './sprache.js';
|
|
12
|
-
import { erkenneEntwurf, musterVon, rolleVonPlatz } from './erkennung.js';
|
|
12
|
+
import { erkenneEntwurf, musterVon, rolleVonPlatz, typKonflikte } from './erkennung.js';
|
|
13
13
|
import { kindZustaende, wertVon, fmt } from './werte.js';
|
|
14
14
|
import { steuerKanaele, vorlagenAbweichung, bestandsAbweichung, waehle, quelleHier, quellenVerteilung } from './entwurf.js';
|
|
15
15
|
import { musterName } from './musternamen.js';
|
|
@@ -367,6 +367,11 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
367
367
|
var legendenPlatz = el('div');
|
|
368
368
|
card.appendChild(legendenPlatz);
|
|
369
369
|
|
|
370
|
+
/* Kippt das ganze Muster an einem einzelnen Typkonflikt? Einmal
|
|
371
|
+
gerechnet: die Zeilenschleife braucht es, die Legende darunter
|
|
372
|
+
ebenso, und beide sollen dieselbe Antwort geben. */
|
|
373
|
+
var kipptAnTyp = typKonflikte(e.states, e.want).filter(function (x) { return x.pflicht; })[0] || null;
|
|
374
|
+
|
|
370
375
|
/* --- Zustandsliste --- */
|
|
371
376
|
e.states.forEach(function (s, i) {
|
|
372
377
|
var pl = platzVon[s.n];
|
|
@@ -378,12 +383,27 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
378
383
|
06.09.2026). Jetzt traegt die Zeile eine Marke, der Satz steht
|
|
379
384
|
einmal als Legende ueber der Liste, und der lange Text haengt als
|
|
380
385
|
Hinweis an der Zeile. */
|
|
381
|
-
|
|
386
|
+
/* Kippt das Muster an einem Typkonflikt, wird nur der Verursacher
|
|
387
|
+
getoent - nicht die ganze Liste.
|
|
388
|
+
|
|
389
|
+
Dass danach keine Zeile einen Platz hat, stimmt zwar, taugt aber
|
|
390
|
+
nicht als Auskunft: Die Toenung liest sich als „mit dieser Zeile
|
|
391
|
+
stimmt etwas nicht", und das trifft auf sieben von acht nicht zu.
|
|
392
|
+
Sie zeigte die Folge und nicht die Ursache (Ricardo, 12.09.2026).
|
|
393
|
+
Die Legende darueber nennt den Grund; markiert wird die Zeile, an
|
|
394
|
+
der er haengt. */
|
|
395
|
+
var ohnePlatz = (s.on && !unfertig && !pl &&
|
|
396
|
+
(!kipptAnTyp || kipptAnTyp.n === s.n));
|
|
382
397
|
if (ohnePlatz) { ohnePlatzZahl++; ohnePlatzNamen.push(s.n); }
|
|
383
398
|
var row = el('div', 'erow' + (s.on ? '' : ' skip') + (S.openRow === i ? ' open' : '') +
|
|
384
399
|
(ohnePlatz ? ' ohneplatz' : ''));
|
|
385
400
|
row.tabIndex = 0;
|
|
386
|
-
if (ohnePlatz) {
|
|
401
|
+
if (ohnePlatz) {
|
|
402
|
+
row.title = kipptAnTyp
|
|
403
|
+
? tr('pattern.noPlaceBecauseType', musterName(e.want) || e.want || '?',
|
|
404
|
+
kipptAnTyp.platz, kipptAnTyp.erwartet.join(tr('pattern.typeOr')), kipptAnTyp.typ)
|
|
405
|
+
: tr('pattern.noPlaceLong', musterName(e.want) || e.want || '?');
|
|
406
|
+
}
|
|
387
407
|
|
|
388
408
|
var cbw = el('span');
|
|
389
409
|
var cb = document.createElement('input');
|
|
@@ -670,7 +690,20 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
670
690
|
if (ohnePlatzZahl) {
|
|
671
691
|
var mn = musterName(e.want) || e.want || '?';
|
|
672
692
|
var lg = el('div', 'legendenzeile');
|
|
673
|
-
|
|
693
|
+
/* Steht die ganze Liste ohne Platz da, weil EINE Zeile im falschen
|
|
694
|
+
Datentyp ist, sagt die Legende das - statt acht Zeilen pauschal zu
|
|
695
|
+
beschuldigen.
|
|
696
|
+
|
|
697
|
+
Der Ablauf: der Punkt faellt wegen des Typs aus dem Muster, damit
|
|
698
|
+
ist ein Pflichtplatz leer, damit greift das Muster nicht mehr, und
|
|
699
|
+
damit hat KEINE Zeile mehr einen Platz. Am Bastelzimmer_Licht
|
|
700
|
+
reichte ein Wechsel an SET von `boolean` auf `mixed`: acht von acht
|
|
701
|
+
Zeilen getoent, Musterfeld „✕ SET fehlt", und die Ursache stand
|
|
702
|
+
nur in der aufgeklappten SET-Zeile (Ricardo, 12.09.2026). */
|
|
703
|
+
lg.appendChild(document.createTextNode(kipptAnTyp
|
|
704
|
+
? tr('pattern.noPlaceBecauseType', mn, kipptAnTyp.platz,
|
|
705
|
+
kipptAnTyp.erwartet.join(tr('pattern.typeOr')), kipptAnTyp.typ)
|
|
706
|
+
: tr('pattern.noPlaceLegend', mn)));
|
|
674
707
|
|
|
675
708
|
var ib = el('button', 'infoknopf', 'i');
|
|
676
709
|
ib.type = 'button';
|