iobroker.mywebui 1.42.45 → 1.42.46
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.mywebui",
|
|
3
|
-
"version": "1.42.
|
|
3
|
+
"version": "1.42.46",
|
|
4
4
|
"description": "ioBroker mywebui - Custom edited mywebui by gokturk413 with 3D Editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/backend/main.js",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@iobroker/adapter-core": "^3.3.2",
|
|
70
70
|
"@types/node": "^24.7.2",
|
|
71
|
+
"esbuild": "^0.28.1",
|
|
71
72
|
"three": "^0.184.0"
|
|
72
73
|
},
|
|
73
74
|
"devDependencies": {
|
|
@@ -112,4 +113,4 @@
|
|
|
112
113
|
"typescript-json-schema": "^0.65.1",
|
|
113
114
|
"wunderbaum": "0.13.0"
|
|
114
115
|
}
|
|
115
|
-
}
|
|
116
|
+
}
|
|
@@ -1,34 +1,19 @@
|
|
|
1
1
|
import { BaseCustomWebComponentConstructorAppend, css, html } from "@gokturk413/base-custom-webcomponent";
|
|
2
2
|
|
|
3
|
-
const EDITOR_BASE = new URL('../../../3d-editor/', import.meta.url).href;
|
|
4
|
-
|
|
5
3
|
export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponentConstructorAppend {
|
|
6
4
|
|
|
7
5
|
static template = html`
|
|
8
6
|
<div id="root">
|
|
9
|
-
<!-- Sub-tab bar -->
|
|
10
|
-
<div id="subBar">
|
|
11
|
-
<span class="stab active" data-sub="scene">Scene</span>
|
|
12
|
-
<span class="stab" data-sub="object">Object</span>
|
|
13
|
-
<span class="stab" data-sub="geom">Geom</span>
|
|
14
|
-
<span class="stab" data-sub="mater">Mater</span>
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
|
-
<!-- Scene tab -->
|
|
18
|
-
<div id="subScene" class="spanel active"></div>
|
|
19
7
|
|
|
20
|
-
<!--
|
|
21
|
-
<div id="
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
<div id="bindRows"></div>
|
|
8
|
+
<!-- Selected object header -->
|
|
9
|
+
<div id="objHeader">
|
|
10
|
+
<span id="objType" class="htype"></span>
|
|
11
|
+
<span id="objName" class="hname">No object selected</span>
|
|
25
12
|
</div>
|
|
26
13
|
|
|
27
|
-
<!--
|
|
28
|
-
<div
|
|
29
|
-
|
|
30
|
-
<!-- Mater tab -->
|
|
31
|
-
<div id="subMater" class="spanel" style="display:none;"></div>
|
|
14
|
+
<!-- Section: 3D Bindings -->
|
|
15
|
+
<div class="sechdr">3D BINDINGS (IOBROKER STATES)</div>
|
|
16
|
+
<div id="bindRows"></div>
|
|
32
17
|
|
|
33
18
|
<!-- Context menu -->
|
|
34
19
|
<div id="ctxMenu">
|
|
@@ -40,12 +25,12 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
40
25
|
<!-- Binding dialog -->
|
|
41
26
|
<div id="bdOverlay">
|
|
42
27
|
<div id="bdBox">
|
|
43
|
-
<div id="bdTitle">Edit Binding of '<span id="bdPropLabel"></span>'
|
|
28
|
+
<div id="bdTitle">Edit Binding of '<span id="bdPropLabel"></span>'</div>
|
|
44
29
|
|
|
45
30
|
<div class="bdRow">
|
|
46
31
|
<div class="bdLbl">objects</div>
|
|
47
|
-
<div style="display:flex;gap:3px;
|
|
48
|
-
<input id="bdObj" type="text" class="bdInput" style="flex:1;" placeholder="state
|
|
32
|
+
<div style="display:flex;gap:3px;">
|
|
33
|
+
<input id="bdObj" type="text" class="bdInput" style="flex:1;" placeholder="mywebui.0.state.value" autocomplete="off"/>
|
|
49
34
|
<button class="bdBtn sm" id="bdObjX">X</button>
|
|
50
35
|
<button class="bdBtn sm" id="bdObjBrowse">...</button>
|
|
51
36
|
<button class="bdBtn sm accent" id="bdObjIOB">IOB</button>
|
|
@@ -53,20 +38,20 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
53
38
|
</div>
|
|
54
39
|
|
|
55
40
|
<div class="bdRow" style="display:flex;align-items:center;gap:8px;">
|
|
56
|
-
<span class="bdLbl" style="margin-bottom:0;">type :</span>
|
|
41
|
+
<span class="bdLbl" style="margin-bottom:0;min-width:40px;">type :</span>
|
|
57
42
|
<select id="bdType" class="bdSel">
|
|
58
43
|
<option value="signal">signal</option>
|
|
59
|
-
<option value="ignore"
|
|
44
|
+
<option value="ignore">ignore</option>
|
|
60
45
|
<option value="css">css</option>
|
|
61
46
|
<option value="attribute">attribute</option>
|
|
62
47
|
</select>
|
|
63
48
|
</div>
|
|
64
49
|
|
|
65
|
-
<div class="bdRow
|
|
50
|
+
<div class="bdRow bdChkRow">
|
|
66
51
|
<input id="bdTwoWay" type="checkbox"/>
|
|
67
52
|
<span class="bdChkLbl">two way binding</span>
|
|
68
53
|
</div>
|
|
69
|
-
<div class="bdRow
|
|
54
|
+
<div class="bdRow bdChkRow">
|
|
70
55
|
<input id="bdInvert" type="checkbox"/>
|
|
71
56
|
<span class="bdChkLbl">invert logic</span>
|
|
72
57
|
</div>
|
|
@@ -80,24 +65,24 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
80
65
|
</div>
|
|
81
66
|
|
|
82
67
|
<div class="bdRow">
|
|
83
|
-
<
|
|
84
|
-
<input id="bdWriteBack" type="text" class="bdInput"
|
|
68
|
+
<div class="bdLbl">write back signal :</div>
|
|
69
|
+
<input id="bdWriteBack" type="text" class="bdInput"/>
|
|
85
70
|
</div>
|
|
86
71
|
|
|
87
72
|
<div class="bdRow">
|
|
88
|
-
<
|
|
73
|
+
<div class="bdLbl">formula write back (two way)</div>
|
|
89
74
|
<textarea id="bdFormulaWB" class="bdTa" rows="2" placeholder="val"></textarea>
|
|
90
75
|
</div>
|
|
91
76
|
|
|
92
77
|
<div class="bdRow">
|
|
93
|
-
<
|
|
94
|
-
<table
|
|
78
|
+
<div class="bdLbl">converter:</div>
|
|
79
|
+
<table class="bdTable">
|
|
95
80
|
<thead><tr><th>condition</th><th>value</th></tr></thead>
|
|
96
81
|
<tbody id="bdConvBody"></tbody>
|
|
97
82
|
</table>
|
|
98
83
|
<div style="display:flex;gap:4px;margin-top:4px;justify-content:flex-end;">
|
|
99
|
-
<button class="bdBtn" id="bdConvAdd">add</button>
|
|
100
|
-
<button class="bdBtn" id="bdConvRemove">remove</button>
|
|
84
|
+
<button class="bdBtn sm" id="bdConvAdd">add</button>
|
|
85
|
+
<button class="bdBtn sm" id="bdConvRemove">remove</button>
|
|
101
86
|
</div>
|
|
102
87
|
</div>
|
|
103
88
|
|
|
@@ -112,159 +97,225 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
112
97
|
|
|
113
98
|
static style = css`
|
|
114
99
|
:host { display:block;width:100%;height:100%;overflow:hidden; }
|
|
115
|
-
#root { width:100%;height:100%;display:flex;flex-direction:column;overflow:hidden;background:#1a1a1a;color:#ccc;font-family:Helvetica,Arial,sans-serif;font-size:12px;position:relative; }
|
|
116
100
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
101
|
+
#root {
|
|
102
|
+
width:100%;height:100%;
|
|
103
|
+
display:flex;flex-direction:column;
|
|
104
|
+
overflow:hidden;
|
|
105
|
+
background:#1e1e1e;
|
|
106
|
+
color:#d4d4d4;
|
|
107
|
+
font-family:Segoe UI,Helvetica,Arial,sans-serif;
|
|
108
|
+
font-size:12px;
|
|
109
|
+
position:relative;
|
|
110
|
+
}
|
|
122
111
|
|
|
123
|
-
/*
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
112
|
+
/* Selected object header */
|
|
113
|
+
#objHeader {
|
|
114
|
+
display:flex;align-items:center;gap:6px;
|
|
115
|
+
padding:5px 8px;
|
|
116
|
+
background:#252526;
|
|
117
|
+
border-bottom:1px solid #3c3c3c;
|
|
118
|
+
flex-shrink:0;
|
|
119
|
+
min-height:26px;
|
|
120
|
+
}
|
|
121
|
+
.htype {
|
|
122
|
+
font-size:10px;color:#569cd6;
|
|
123
|
+
background:#1e1e1e;border:1px solid #3c3c3c;
|
|
124
|
+
padding:1px 5px;border-radius:2px;
|
|
125
|
+
white-space:nowrap;
|
|
126
|
+
}
|
|
127
|
+
.hname { font-size:11px;color:#9cdcfe;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
|
|
128
128
|
|
|
129
129
|
/* Section header */
|
|
130
|
-
.sechdr {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
.sechdr {
|
|
131
|
+
background:#252526;
|
|
132
|
+
color:#9cdcfe;
|
|
133
|
+
padding:4px 8px;
|
|
134
|
+
font-size:10px;font-weight:700;
|
|
135
|
+
text-transform:uppercase;
|
|
136
|
+
letter-spacing:.6px;
|
|
137
|
+
border-bottom:1px solid #3c3c3c;
|
|
138
|
+
flex-shrink:0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Binding rows */
|
|
142
|
+
#bindRows { flex:1;overflow-y:auto;overflow-x:hidden; }
|
|
143
|
+
|
|
144
|
+
.brow {
|
|
145
|
+
display:flex;align-items:center;
|
|
146
|
+
padding:0 6px;
|
|
147
|
+
height:22px;
|
|
148
|
+
border-bottom:1px solid #2a2a2a;
|
|
149
|
+
gap:0;
|
|
150
|
+
}
|
|
151
|
+
.brow:hover { background:#2a2d2e; }
|
|
152
|
+
|
|
153
|
+
/* □ square binding button */
|
|
154
|
+
.bsq {
|
|
155
|
+
width:13px;height:13px;min-width:13px;
|
|
156
|
+
border:1px solid #4d4d4d;
|
|
157
|
+
background:transparent;
|
|
158
|
+
cursor:pointer;
|
|
159
|
+
display:flex;align-items:center;justify-content:center;
|
|
160
|
+
font-size:7px;color:transparent;
|
|
161
|
+
flex-shrink:0;
|
|
162
|
+
margin-right:5px;
|
|
163
|
+
padding:0;
|
|
164
|
+
outline:none;
|
|
165
|
+
}
|
|
138
166
|
.bsq:hover { border-color:#4ec9b0; }
|
|
139
|
-
.bsq.bound {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
167
|
+
.bsq.bound {
|
|
168
|
+
background:#0e639c;
|
|
169
|
+
border-color:#1177bb;
|
|
170
|
+
color:#fff;
|
|
171
|
+
font-size:8px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Property label */
|
|
175
|
+
.blbl {
|
|
176
|
+
width:88px;min-width:88px;
|
|
177
|
+
color:#d4d4d4;
|
|
178
|
+
font-size:11px;
|
|
179
|
+
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
180
|
+
flex-shrink:0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Signal value display */
|
|
184
|
+
.bval {
|
|
185
|
+
flex:1;
|
|
186
|
+
font-size:10px;
|
|
187
|
+
font-family:Consolas,monospace;
|
|
188
|
+
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
189
|
+
padding:0 3px;
|
|
190
|
+
color:#4ec9b0;
|
|
191
|
+
}
|
|
144
192
|
.bval.none { color:#555; }
|
|
145
193
|
|
|
146
194
|
/* Context menu */
|
|
147
|
-
#ctxMenu {
|
|
195
|
+
#ctxMenu {
|
|
196
|
+
display:none;position:fixed;z-index:9999;
|
|
197
|
+
background:#252526;border:1px solid #454545;
|
|
198
|
+
min-width:130px;
|
|
199
|
+
box-shadow:2px 4px 12px rgba(0,0,0,.7);
|
|
200
|
+
}
|
|
148
201
|
#ctxMenu.open { display:block; }
|
|
149
|
-
.cmItem { padding:5px
|
|
150
|
-
.cmItem:hover { background:#
|
|
151
|
-
|
|
152
|
-
/* Binding dialog
|
|
153
|
-
#bdOverlay {
|
|
202
|
+
.cmItem { padding:5px 14px;cursor:pointer;font-size:11px;color:#d4d4d4; }
|
|
203
|
+
.cmItem:hover { background:#094771;color:#fff; }
|
|
204
|
+
|
|
205
|
+
/* Binding dialog */
|
|
206
|
+
#bdOverlay {
|
|
207
|
+
display:none;position:absolute;inset:0;
|
|
208
|
+
background:rgba(0,0,0,.72);
|
|
209
|
+
z-index:500;
|
|
210
|
+
align-items:center;justify-content:center;
|
|
211
|
+
}
|
|
154
212
|
#bdOverlay.open { display:flex; }
|
|
155
|
-
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
213
|
+
|
|
214
|
+
#bdBox {
|
|
215
|
+
background:#252526;
|
|
216
|
+
border:1px solid #454545;
|
|
217
|
+
width:320px;max-height:88%;
|
|
218
|
+
overflow-y:auto;
|
|
219
|
+
box-shadow:4px 6px 20px rgba(0,0,0,.8);
|
|
220
|
+
}
|
|
221
|
+
#bdTitle {
|
|
222
|
+
background:#37373d;
|
|
223
|
+
padding:7px 10px;
|
|
224
|
+
font-size:11px;font-weight:600;
|
|
225
|
+
color:#ccc;
|
|
226
|
+
border-bottom:1px solid #454545;
|
|
227
|
+
}
|
|
228
|
+
.bdRow { padding:5px 10px 2px; }
|
|
229
|
+
.bdChkRow { display:flex;align-items:center;gap:8px;padding:3px 10px; }
|
|
230
|
+
.bdLbl { color:#888;font-size:10px;margin-bottom:3px;display:block; }
|
|
231
|
+
.bdChkLbl { font-size:11px;color:#d4d4d4; }
|
|
232
|
+
.bdInput {
|
|
233
|
+
width:100%;
|
|
234
|
+
background:#3c3c3c;border:1px solid #555;
|
|
235
|
+
color:#d4d4d4;padding:3px 5px;
|
|
236
|
+
font-size:11px;box-sizing:border-box;
|
|
237
|
+
outline:none;
|
|
238
|
+
}
|
|
239
|
+
.bdInput:focus { border-color:#4ec9b0; }
|
|
240
|
+
.bdSel {
|
|
241
|
+
background:#3c3c3c;border:1px solid #555;
|
|
242
|
+
color:#d4d4d4;padding:2px 4px;font-size:11px;
|
|
243
|
+
outline:none;
|
|
244
|
+
}
|
|
245
|
+
.bdTa {
|
|
246
|
+
width:100%;background:#3c3c3c;border:1px solid #555;
|
|
247
|
+
color:#d4d4d4;padding:3px 5px;font-size:11px;
|
|
248
|
+
font-family:Consolas,monospace;
|
|
249
|
+
box-sizing:border-box;resize:vertical;
|
|
250
|
+
outline:none;
|
|
251
|
+
}
|
|
252
|
+
.bdTa:focus { border-color:#4ec9b0; }
|
|
253
|
+
.bdTable { width:100%;border-collapse:collapse;font-size:10px;color:#d4d4d4; }
|
|
254
|
+
.bdTable th { background:#1e1e1e;padding:2px 6px;text-align:left;color:#888;border:1px solid #3c3c3c; }
|
|
255
|
+
.bdTable td { padding:1px 3px;border:1px solid #3c3c3c; }
|
|
256
|
+
.bdTable td input { width:100%;background:#3c3c3c;border:none;color:#d4d4d4;padding:2px 3px;font-size:10px;outline:none; }
|
|
257
|
+
.bdBtn {
|
|
258
|
+
padding:3px 10px;
|
|
259
|
+
background:#3c3c3c;border:1px solid #555;
|
|
260
|
+
color:#d4d4d4;cursor:pointer;font-size:11px;
|
|
261
|
+
}
|
|
170
262
|
.bdBtn:hover { border-color:#999; }
|
|
171
263
|
.bdBtn.sm { padding:2px 6px;font-size:10px; }
|
|
172
264
|
.bdBtn.accent { background:#0e639c;border-color:#1177bb;color:#fff; }
|
|
173
265
|
.bdBtn.accent-ok { background:#0e639c;border-color:#1177bb;color:#fff; }
|
|
174
|
-
#bdFoot {
|
|
266
|
+
#bdFoot {
|
|
267
|
+
display:flex;justify-content:flex-end;gap:6px;
|
|
268
|
+
padding:8px 10px;border-top:1px solid #3c3c3c;
|
|
269
|
+
}
|
|
175
270
|
`;
|
|
176
271
|
|
|
177
|
-
_editor
|
|
178
|
-
_editorHost
|
|
179
|
-
_bindings
|
|
272
|
+
_editor = null;
|
|
273
|
+
_editorHost = null;
|
|
274
|
+
_bindings = {};
|
|
180
275
|
_selectedObj = null;
|
|
181
|
-
_ctxTarget
|
|
276
|
+
_ctxTarget = null;
|
|
182
277
|
|
|
183
278
|
// ── Public API ─────────────────────────────────────────────────────────────
|
|
184
279
|
|
|
185
280
|
async connect(editor, editorHost) {
|
|
186
|
-
this._editor
|
|
281
|
+
this._editor = editor;
|
|
187
282
|
this._editorHost = editorHost;
|
|
188
|
-
this._bindings
|
|
283
|
+
this._bindings = editorHost?.sceneData?.bindings ?? {};
|
|
189
284
|
|
|
190
|
-
await this._injectThreeCSS();
|
|
191
|
-
await this._mountThreePanels();
|
|
192
|
-
this._setupSubTabs();
|
|
193
285
|
this._buildBindingRows();
|
|
194
286
|
this._setupContextMenu();
|
|
195
287
|
this._setupBindingDialog();
|
|
196
288
|
|
|
197
289
|
editor.signals.objectSelected.add(obj => {
|
|
198
290
|
this._selectedObj = obj;
|
|
291
|
+
this._refreshHeader();
|
|
199
292
|
this._refreshBindRows();
|
|
200
293
|
});
|
|
201
294
|
editor.signals.objectChanged.add(obj => {
|
|
202
295
|
if (obj && obj === this._selectedObj) this._refreshBindRows();
|
|
203
296
|
});
|
|
204
297
|
|
|
298
|
+
this._refreshHeader();
|
|
205
299
|
this._refreshBindRows();
|
|
206
300
|
}
|
|
207
301
|
|
|
208
302
|
getBindings() { return this._bindings; }
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
// ── Mount Three.js sidebar panels ──────────────────────────────────────────
|
|
227
|
-
|
|
228
|
-
async _mountThreePanels() {
|
|
229
|
-
const base = EDITOR_BASE + 'js/';
|
|
230
|
-
const ed = this._editor;
|
|
231
|
-
const [
|
|
232
|
-
{ SidebarScene },
|
|
233
|
-
{ SidebarObject },
|
|
234
|
-
{ SidebarGeometry },
|
|
235
|
-
{ SidebarMaterial },
|
|
236
|
-
] = await Promise.all([
|
|
237
|
-
import(/* @vite-ignore */ base + 'Sidebar.Scene.js'),
|
|
238
|
-
import(/* @vite-ignore */ base + 'Sidebar.Object.js'),
|
|
239
|
-
import(/* @vite-ignore */ base + 'Sidebar.Geometry.js'),
|
|
240
|
-
import(/* @vite-ignore */ base + 'Sidebar.Material.js'),
|
|
241
|
-
]);
|
|
242
|
-
|
|
243
|
-
this._getDomElement('subScene').appendChild(new SidebarScene(ed).dom);
|
|
244
|
-
this._getDomElement('objThreeWrap').appendChild(new SidebarObject(ed).dom);
|
|
245
|
-
this._getDomElement('subGeom').appendChild(new SidebarGeometry(ed).dom);
|
|
246
|
-
this._getDomElement('subMater').appendChild(new SidebarMaterial(ed).dom);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// ── Sub-tabs ────────────────────────────────────────────────────────────────
|
|
250
|
-
|
|
251
|
-
_setupSubTabs() {
|
|
252
|
-
const bar = this._getDomElement('subBar');
|
|
253
|
-
const panels = {
|
|
254
|
-
scene: this._getDomElement('subScene'),
|
|
255
|
-
object: this._getDomElement('subObject'),
|
|
256
|
-
geom: this._getDomElement('subGeom'),
|
|
257
|
-
mater: this._getDomElement('subMater'),
|
|
258
|
-
};
|
|
259
|
-
bar?.querySelectorAll('.stab').forEach(btn => {
|
|
260
|
-
btn.addEventListener('click', () => {
|
|
261
|
-
bar.querySelectorAll('.stab').forEach(b => b.classList.remove('active'));
|
|
262
|
-
btn.classList.add('active');
|
|
263
|
-
Object.values(panels).forEach(p => { if (p) p.style.display = 'none'; });
|
|
264
|
-
const p = panels[btn.dataset.sub];
|
|
265
|
-
if (p) p.style.display = btn.dataset.sub === 'object' ? 'flex' : 'block';
|
|
266
|
-
});
|
|
267
|
-
});
|
|
303
|
+
setBindings(b) { this._bindings = b || {}; this._refreshBindRows(); }
|
|
304
|
+
|
|
305
|
+
// ── Header ─────────────────────────────────────────────────────────────────
|
|
306
|
+
|
|
307
|
+
_refreshHeader() {
|
|
308
|
+
const obj = this._selectedObj;
|
|
309
|
+
const typeEl = this._getDomElement('objType');
|
|
310
|
+
const nameEl = this._getDomElement('objName');
|
|
311
|
+
if (!typeEl || !nameEl) return;
|
|
312
|
+
if (!obj) {
|
|
313
|
+
typeEl.textContent = '';
|
|
314
|
+
nameEl.textContent = 'No object selected';
|
|
315
|
+
} else {
|
|
316
|
+
typeEl.textContent = obj.type || '';
|
|
317
|
+
nameEl.textContent = obj.name || obj.uuid?.slice(0, 8) || '—';
|
|
318
|
+
}
|
|
268
319
|
}
|
|
269
320
|
|
|
270
321
|
// ── Bindable properties ─────────────────────────────────────────────────────
|
|
@@ -288,60 +339,44 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
288
339
|
const cont = this._getDomElement('bindRows');
|
|
289
340
|
if (!cont) return;
|
|
290
341
|
cont.innerHTML = '';
|
|
291
|
-
|
|
342
|
+
for (const { key, label } of this._BINDABLE) {
|
|
292
343
|
const row = document.createElement('div');
|
|
293
344
|
row.className = 'brow';
|
|
294
345
|
row.dataset.key = key;
|
|
295
346
|
|
|
296
|
-
// □ square button (left of label)
|
|
297
347
|
const sq = document.createElement('button');
|
|
298
348
|
sq.className = 'bsq';
|
|
299
|
-
sq.title =
|
|
300
|
-
|
|
301
|
-
sq.addEventListener('
|
|
302
|
-
|
|
303
|
-
this._showCtxMenu(e, key);
|
|
304
|
-
});
|
|
305
|
-
sq.addEventListener('click', e => {
|
|
306
|
-
e.preventDefault();
|
|
307
|
-
this._showCtxMenu(e, key);
|
|
308
|
-
});
|
|
349
|
+
sq.title = key;
|
|
350
|
+
const onClick = e => { e.preventDefault(); this._showCtxMenu(e, key); };
|
|
351
|
+
sq.addEventListener('click', onClick);
|
|
352
|
+
sq.addEventListener('contextmenu', onClick);
|
|
309
353
|
|
|
310
|
-
// property name
|
|
311
354
|
const lbl = document.createElement('span');
|
|
312
355
|
lbl.className = 'blbl';
|
|
313
356
|
lbl.textContent = label;
|
|
314
357
|
|
|
315
|
-
// current signal display
|
|
316
358
|
const val = document.createElement('span');
|
|
317
359
|
val.className = 'bval none';
|
|
318
|
-
val.textContent = '';
|
|
319
360
|
|
|
320
361
|
row.appendChild(sq);
|
|
321
362
|
row.appendChild(lbl);
|
|
322
363
|
row.appendChild(val);
|
|
323
364
|
cont.appendChild(row);
|
|
324
|
-
}
|
|
365
|
+
}
|
|
325
366
|
}
|
|
326
367
|
|
|
327
368
|
_refreshBindRows() {
|
|
328
369
|
const cont = this._getDomElement('bindRows');
|
|
329
370
|
if (!cont) return;
|
|
330
371
|
const uuid = this._selectedObj?.uuid;
|
|
331
|
-
cont.querySelectorAll('.brow')
|
|
372
|
+
for (const row of cont.querySelectorAll('.brow')) {
|
|
332
373
|
const key = row.dataset.key;
|
|
333
374
|
const sq = row.querySelector('.bsq');
|
|
334
375
|
const val = row.querySelector('.bval');
|
|
335
376
|
const bind = uuid ? this._bindings[uuid]?.[key] : null;
|
|
336
|
-
|
|
337
|
-
if (val) {
|
|
338
|
-
|
|
339
|
-
val.className = 'bval' + (bind?.signal ? '' : ' none');
|
|
340
|
-
}
|
|
341
|
-
if (sq) {
|
|
342
|
-
sq.className = 'bsq' + (bind?.signal ? ' bound' : '');
|
|
343
|
-
}
|
|
344
|
-
});
|
|
377
|
+
if (sq) sq.className = 'bsq' + (bind?.signal ? ' bound' : '');
|
|
378
|
+
if (val) { val.textContent = bind?.signal || ''; val.className = 'bval' + (bind?.signal ? '' : ' none'); }
|
|
379
|
+
}
|
|
345
380
|
}
|
|
346
381
|
|
|
347
382
|
// ── Context menu ────────────────────────────────────────────────────────────
|
|
@@ -349,33 +384,25 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
349
384
|
_setupContextMenu() {
|
|
350
385
|
const menu = this._getDomElement('ctxMenu');
|
|
351
386
|
if (!menu) return;
|
|
352
|
-
|
|
353
387
|
menu.addEventListener('click', e => {
|
|
354
388
|
const item = e.target.closest('.cmItem');
|
|
355
389
|
if (!item) return;
|
|
356
|
-
const action = item.dataset.action;
|
|
357
390
|
menu.classList.remove('open');
|
|
358
|
-
|
|
391
|
+
const action = item.dataset.action;
|
|
359
392
|
if (action === 'clear') this._clearBinding(this._ctxTarget);
|
|
360
393
|
if (action === 'editbind') this._openBindDialog(this._ctxTarget);
|
|
361
394
|
if (action === 'edittext') this._openTextEditor(this._ctxTarget);
|
|
362
395
|
});
|
|
363
|
-
|
|
364
|
-
// close on outside click
|
|
365
396
|
document.addEventListener('click', e => {
|
|
366
397
|
if (!menu.contains(e.target)) menu.classList.remove('open');
|
|
367
398
|
});
|
|
368
399
|
}
|
|
369
400
|
|
|
370
401
|
_showCtxMenu(e, key) {
|
|
371
|
-
if (!this._selectedObj) {
|
|
372
|
-
alert('Select a 3D object first.');
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
402
|
+
if (!this._selectedObj) { alert('Select a 3D object first.'); return; }
|
|
375
403
|
this._ctxTarget = { uuid: this._selectedObj.uuid, key };
|
|
376
404
|
const menu = this._getDomElement('ctxMenu');
|
|
377
405
|
if (!menu) return;
|
|
378
|
-
// position near click
|
|
379
406
|
menu.style.left = e.clientX + 'px';
|
|
380
407
|
menu.style.top = e.clientY + 'px';
|
|
381
408
|
menu.classList.add('open');
|
|
@@ -386,21 +413,18 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
386
413
|
delete this._bindings[uuid]?.[key];
|
|
387
414
|
if (this._bindings[uuid] && !Object.keys(this._bindings[uuid]).length)
|
|
388
415
|
delete this._bindings[uuid];
|
|
389
|
-
this._syncHost();
|
|
390
|
-
this._refreshBindRows();
|
|
416
|
+
this._syncHost(); this._refreshBindRows();
|
|
391
417
|
}
|
|
392
418
|
|
|
393
419
|
_openTextEditor({ uuid, key } = {}) {
|
|
394
420
|
if (!uuid || !key) return;
|
|
395
421
|
const ex = this._bindings[uuid]?.[key];
|
|
396
|
-
const
|
|
397
|
-
const nv = window.prompt(`State ID for "${key}":`, val);
|
|
422
|
+
const nv = window.prompt(`State ID for "${key}":`, ex?.signal || '');
|
|
398
423
|
if (nv === null) return;
|
|
399
424
|
if (!nv.trim()) { this._clearBinding({ uuid, key }); return; }
|
|
400
425
|
if (!this._bindings[uuid]) this._bindings[uuid] = {};
|
|
401
|
-
this._bindings[uuid][key] = { signal: nv.trim(), formula: ex?.formula || 'val'
|
|
402
|
-
this._syncHost();
|
|
403
|
-
this._refreshBindRows();
|
|
426
|
+
this._bindings[uuid][key] = { ...(ex || {}), signal: nv.trim(), formula: ex?.formula || 'val' };
|
|
427
|
+
this._syncHost(); this._refreshBindRows();
|
|
404
428
|
}
|
|
405
429
|
|
|
406
430
|
// ── Binding dialog ──────────────────────────────────────────────────────────
|
|
@@ -408,36 +432,22 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
408
432
|
_setupBindingDialog() {
|
|
409
433
|
const ov = this._getDomElement('bdOverlay');
|
|
410
434
|
|
|
411
|
-
this._getDomElement('bdCancel')?.addEventListener('click', () =>
|
|
412
|
-
ov?.classList.remove('open');
|
|
413
|
-
});
|
|
435
|
+
this._getDomElement('bdCancel')?.addEventListener('click', () => ov?.classList.remove('open'));
|
|
414
436
|
|
|
415
437
|
this._getDomElement('bdObjX')?.addEventListener('click', () => {
|
|
416
|
-
const inp = this._getDomElement('bdObj');
|
|
417
|
-
if (inp) inp.value = '';
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
this._getDomElement('bdObjBrowse')?.addEventListener('click', async () => {
|
|
421
|
-
try {
|
|
422
|
-
const { openSelectIdDialog } = await import('@iobroker/webcomponent-selectid-dialog/dist/selectIdHelper.js');
|
|
423
|
-
const connection = (await import('../common/IobrokerHandler.js')).iobrokerHandler.connection;
|
|
424
|
-
const id = await openSelectIdDialog(connection, null, false);
|
|
425
|
-
if (id) { const inp = this._getDomElement('bdObj'); if (inp) inp.value = id; }
|
|
426
|
-
} catch (_) {}
|
|
438
|
+
const inp = this._getDomElement('bdObj'); if (inp) inp.value = '';
|
|
427
439
|
});
|
|
428
440
|
|
|
429
|
-
|
|
441
|
+
const browse = async () => {
|
|
430
442
|
try {
|
|
431
443
|
const { openSelectIdDialog } = await import('@iobroker/webcomponent-selectid-dialog/dist/selectIdHelper.js');
|
|
432
|
-
const
|
|
433
|
-
const id = await openSelectIdDialog(connection, null, false);
|
|
444
|
+
const { iobrokerHandler } = await import('../common/IobrokerHandler.js');
|
|
445
|
+
const id = await openSelectIdDialog(iobrokerHandler.connection, null, false);
|
|
434
446
|
if (id) { const inp = this._getDomElement('bdObj'); if (inp) inp.value = id; }
|
|
435
447
|
} catch (_) {}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
this._getDomElement('
|
|
439
|
-
// historic signals - show simple list if available
|
|
440
|
-
});
|
|
448
|
+
};
|
|
449
|
+
this._getDomElement('bdObjBrowse')?.addEventListener('click', browse);
|
|
450
|
+
this._getDomElement('bdObjIOB')?.addEventListener('click', browse);
|
|
441
451
|
|
|
442
452
|
this._getDomElement('bdConvAdd')?.addEventListener('click', () => {
|
|
443
453
|
const tbody = this._getDomElement('bdConvBody');
|
|
@@ -449,9 +459,7 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
449
459
|
|
|
450
460
|
this._getDomElement('bdConvRemove')?.addEventListener('click', () => {
|
|
451
461
|
const tbody = this._getDomElement('bdConvBody');
|
|
452
|
-
|
|
453
|
-
const last = tbody.querySelector('tr:last-child');
|
|
454
|
-
if (last) last.remove();
|
|
462
|
+
tbody?.querySelector('tr:last-child')?.remove();
|
|
455
463
|
});
|
|
456
464
|
|
|
457
465
|
this._getDomElement('bdOk')?.addEventListener('click', () => {
|
|
@@ -463,46 +471,42 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
463
471
|
const twoWay = this._getDomElement('bdTwoWay')?.checked ?? false;
|
|
464
472
|
const invert = this._getDomElement('bdInvert')?.checked ?? false;
|
|
465
473
|
const type = this._getDomElement('bdType')?.value || 'signal';
|
|
466
|
-
|
|
467
|
-
// collect converter rows
|
|
468
474
|
const converter = [];
|
|
469
475
|
this._getDomElement('bdConvBody')?.querySelectorAll('tr').forEach(tr => {
|
|
470
|
-
const
|
|
471
|
-
if (
|
|
472
|
-
converter.push({ condition:
|
|
476
|
+
const ins = tr.querySelectorAll('input');
|
|
477
|
+
if (ins[0]?.value || ins[1]?.value)
|
|
478
|
+
converter.push({ condition: ins[0]?.value || '', value: ins[1]?.value || '' });
|
|
473
479
|
});
|
|
474
480
|
|
|
475
|
-
if (uuid && key
|
|
476
|
-
if (
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
481
|
+
if (uuid && key) {
|
|
482
|
+
if (signal) {
|
|
483
|
+
if (!this._bindings[uuid]) this._bindings[uuid] = {};
|
|
484
|
+
this._bindings[uuid][key] = { signal, formula, twoWay, invert, type, writeBack, formulaWB, converter };
|
|
485
|
+
} else {
|
|
486
|
+
this._clearBinding({ uuid, key });
|
|
487
|
+
}
|
|
488
|
+
this._syncHost(); this._refreshBindRows();
|
|
482
489
|
}
|
|
483
|
-
|
|
484
490
|
ov?.classList.remove('open');
|
|
485
491
|
});
|
|
486
492
|
}
|
|
487
493
|
|
|
488
494
|
_openBindDialog({ uuid, key } = {}) {
|
|
489
495
|
if (!uuid || !key) return;
|
|
490
|
-
const ex
|
|
491
|
-
|
|
492
|
-
const getEl = id => this._getDomElement(id);
|
|
496
|
+
const ex = this._bindings[uuid]?.[key];
|
|
493
497
|
const label = this._BINDABLE.find(b => b.key === key)?.label || key;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const tbody =
|
|
498
|
+
const g = id => this._getDomElement(id);
|
|
499
|
+
|
|
500
|
+
g('bdPropLabel').textContent = label;
|
|
501
|
+
g('bdObj').value = ex?.signal || '';
|
|
502
|
+
g('bdFormula').value = ex?.formula || 'val';
|
|
503
|
+
g('bdFormulaWB').value = ex?.formulaWB || '';
|
|
504
|
+
g('bdWriteBack').value = ex?.writeBack || '';
|
|
505
|
+
g('bdTwoWay').checked = ex?.twoWay || false;
|
|
506
|
+
g('bdInvert').checked = ex?.invert || false;
|
|
507
|
+
if (g('bdType')) g('bdType').value = ex?.type || 'signal';
|
|
508
|
+
|
|
509
|
+
const tbody = g('bdConvBody');
|
|
506
510
|
if (tbody) {
|
|
507
511
|
tbody.innerHTML = '';
|
|
508
512
|
(ex?.converter || []).forEach(row => {
|
|
@@ -513,7 +517,7 @@ export class IobrokerWebui3DScreenPropertiesPanel extends BaseCustomWebComponent
|
|
|
513
517
|
}
|
|
514
518
|
|
|
515
519
|
this._ctxTarget = { uuid, key };
|
|
516
|
-
|
|
520
|
+
g('bdOverlay')?.classList.add('open');
|
|
517
521
|
}
|
|
518
522
|
|
|
519
523
|
_syncHost() {
|
|
@@ -19,6 +19,7 @@ import { CommandHandling } from './CommandHandling.js';
|
|
|
19
19
|
import propertiesTypeInfo from "../generated/Properties.json" with { type: 'json' };
|
|
20
20
|
import "../runtime/controls.js";
|
|
21
21
|
import "./IobrokerWebuiSolutionExplorer.js";
|
|
22
|
+
import "./IobrokerWebuiWidgetGallery.js";
|
|
22
23
|
import "./IobrokerWebuiMonacoEditor.js";
|
|
23
24
|
import "./IobrokerWebuiEventAssignment.js";
|
|
24
25
|
import "./IobrokerWebuiPropertyGrid.js";
|
|
@@ -88,10 +89,14 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
88
89
|
<iobroker-webui-solution-explorer id="solutionExplorer"></iobroker-solution-explorer>
|
|
89
90
|
</div>
|
|
90
91
|
|
|
91
|
-
<div title="outline" dock-spawn-dock-type="down" dock-spawn-dock-to="treeUpper" dock-spawn-dock-ratio="0.33"
|
|
92
|
+
<div id="outlineDock" title="outline" dock-spawn-dock-type="down" dock-spawn-dock-to="treeUpper" dock-spawn-dock-ratio="0.33"
|
|
92
93
|
style="overflow: hidden; width: 100%;">
|
|
93
94
|
<node-projects-tree-view-extended name="tree" id="treeViewExtended"></node-projects-tree-view-extended>
|
|
94
95
|
</div>
|
|
96
|
+
|
|
97
|
+
<div id="galleryDock" title="gallery" dock-spawn-dock-to="outlineDock" style="overflow: hidden; width: 100%;">
|
|
98
|
+
<iobroker-webui-widget-gallery id="widgetGallery"></iobroker-webui-widget-gallery>
|
|
99
|
+
</div>
|
|
95
100
|
|
|
96
101
|
<div id="attributeDock" title="Properties" dock-spawn-dock-type="right" dock-spawn-dock-ratio="0.2">
|
|
97
102
|
<node-projects-web-component-designer-property-grid-with-header id="propertyGrid"></node-projects-web-component-designer-property-grid-with-header>
|
|
@@ -108,7 +113,7 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
108
113
|
<div id="visibilityDock" title="Visibility" style="overflow: auto; width: 100%;" dock-spawn-dock-to="attributeDock">
|
|
109
114
|
</div>
|
|
110
115
|
|
|
111
|
-
<div id="effectsDock" title="
|
|
116
|
+
<div id="effectsDock" title="Effects" style="overflow: auto; width: 100%;" dock-spawn-dock-to="attributeDock">
|
|
112
117
|
</div>
|
|
113
118
|
|
|
114
119
|
<div id="animationsDock" title="Animations" style="overflow: auto; width: 100%;" dock-spawn-dock-to="attributeDock">
|
|
@@ -156,6 +161,8 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
156
161
|
this.eventsAssignment = this._getDomElement('eventsList');
|
|
157
162
|
this.refactorView = this._getDomElement('refactorView');
|
|
158
163
|
this.translationEditor = this._getDomElement('translationEditor');
|
|
164
|
+
this.widgetGallery = this._getDomElement('widgetGallery');
|
|
165
|
+
this.widgetGallery.serviceContainer = serviceContainer;
|
|
159
166
|
this.settingsEditor = this._getDomElement('settingsEditor');
|
|
160
167
|
this.settingsEditor.getTypeInfo = (obj, type) => typeInfoFromJsonSchema(propertiesTypeInfo, obj, type);
|
|
161
168
|
this.settingsEditor.propertyChanged.on((prp) => {
|
|
@@ -313,7 +320,7 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
313
320
|
|
|
314
321
|
setTimeout(makeSetup('visibilityDock', () => this._setupVisibilityPanel(), 'Visibility'), 1000);
|
|
315
322
|
setTimeout(makeSetup('animationsDock', () => this._setupAnimationsPanel(), 'Animations'), 1200);
|
|
316
|
-
setTimeout(makeSetup('effectsDock', () => this._setupEffectsPanel(), '
|
|
323
|
+
setTimeout(makeSetup('effectsDock', () => this._setupEffectsPanel(), 'Effects'), 1400);
|
|
317
324
|
}
|
|
318
325
|
|
|
319
326
|
_setupVisibilityPanel() {
|
|
@@ -1430,6 +1437,14 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
1430
1437
|
cfgList.forEach((cfg, i) => content.appendChild(buildEffectBlock(cfg, i)));
|
|
1431
1438
|
}
|
|
1432
1439
|
|
|
1440
|
+
// shows the live rendered widgets of a tree folder in the gallery panel
|
|
1441
|
+
showWidgetGallery(data, title) {
|
|
1442
|
+
this.widgetGallery?.showForSource(data, title);
|
|
1443
|
+
try {
|
|
1444
|
+
this.activateDockById('galleryDock');
|
|
1445
|
+
}
|
|
1446
|
+
catch (e) { }
|
|
1447
|
+
}
|
|
1433
1448
|
/* Move to a Dock Spawn Helper */
|
|
1434
1449
|
activateDockById(name) {
|
|
1435
1450
|
this.activateDock(this._getDomElement(name));
|
|
@@ -2138,44 +2153,35 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
2138
2153
|
|
|
2139
2154
|
_3dPropsActive = false;
|
|
2140
2155
|
_3dPropsPanel = null;
|
|
2141
|
-
_3dSettPanel = null;
|
|
2142
2156
|
_3dProjPanel = null;
|
|
2143
2157
|
|
|
2144
2158
|
_activate3DPropertiesMode(editor3DEl) {
|
|
2145
2159
|
if (this._3dPropsActive) return;
|
|
2146
2160
|
this._3dPropsActive = true;
|
|
2147
2161
|
|
|
2148
|
-
|
|
2149
|
-
const
|
|
2150
|
-
|
|
2162
|
+
const attrDock = this._getDomElement('attributeDock');
|
|
2163
|
+
const projDock = this._getDomElement('effectsDock');
|
|
2164
|
+
|
|
2165
|
+
// Hide existing children of attributeDock only
|
|
2166
|
+
if (attrDock) {
|
|
2167
|
+
for (const c of attrDock.children) {
|
|
2151
2168
|
c.__3d_prev_display = c.style.display;
|
|
2152
2169
|
c.style.display = 'none';
|
|
2153
2170
|
}
|
|
2154
|
-
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
c.style.display = c.__3d_prev_display;
|
|
2160
|
-
delete c.__3d_prev_display;
|
|
2161
|
-
}
|
|
2171
|
+
}
|
|
2172
|
+
if (projDock) {
|
|
2173
|
+
for (const c of projDock.children) {
|
|
2174
|
+
c.__3d_prev_display = c.style.display;
|
|
2175
|
+
c.style.display = 'none';
|
|
2162
2176
|
}
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
const attrDock = this._getDomElement('attributeDock');
|
|
2166
|
-
const settiDock = this._getDomElement('settingsDock');
|
|
2167
|
-
const projDock = this._getDomElement('effectsDock'); // reuse effectsDock for Project
|
|
2168
|
-
|
|
2169
|
-
if (attrDock) hideChildren(attrDock);
|
|
2170
|
-
if (settiDock) hideChildren(settiDock);
|
|
2171
|
-
if (projDock) hideChildren(projDock);
|
|
2177
|
+
}
|
|
2172
2178
|
|
|
2173
2179
|
const tryConnect = () => {
|
|
2174
2180
|
if (!editor3DEl._editor) { setTimeout(tryConnect, 200); return; }
|
|
2175
2181
|
const ed = editor3DEl._editor;
|
|
2176
2182
|
const base = new URL('../../../3d-editor/js/', import.meta.url).href;
|
|
2177
2183
|
|
|
2178
|
-
// ── attributeDock:
|
|
2184
|
+
// ── attributeDock: 3D Bindings panel ──────────────────────────
|
|
2179
2185
|
if (attrDock) {
|
|
2180
2186
|
const propPanel = document.createElement('iobroker-webui-3dscreen-properties');
|
|
2181
2187
|
propPanel.id = '__3d_attr';
|
|
@@ -2185,94 +2191,6 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
2185
2191
|
this._3dPropsPanel = propPanel;
|
|
2186
2192
|
}
|
|
2187
2193
|
|
|
2188
|
-
// ── settingsDock: SidebarSettings + Visibility ─────────────────
|
|
2189
|
-
if (settiDock) {
|
|
2190
|
-
const wrap = document.createElement('div');
|
|
2191
|
-
wrap.id = '__3d_setti';
|
|
2192
|
-
wrap.style.cssText = 'width:100%;height:100%;overflow:auto;background:#1a1a1a;color:#ccc;font-family:Helvetica,Arial,sans-serif;font-size:12px;';
|
|
2193
|
-
|
|
2194
|
-
Promise.all([
|
|
2195
|
-
import(/* @vite-ignore */ base + 'Sidebar.Settings.js'),
|
|
2196
|
-
]).then(([{ SidebarSettings }]) => {
|
|
2197
|
-
const settPanel = new SidebarSettings(ed);
|
|
2198
|
-
settPanel.dom.style.cssText = 'padding:8px;';
|
|
2199
|
-
wrap.appendChild(settPanel.dom);
|
|
2200
|
-
|
|
2201
|
-
// ── Visibility section ─────────────────────────────────
|
|
2202
|
-
const visDiv = document.createElement('div');
|
|
2203
|
-
visDiv.style.cssText = 'border-top:1px solid #3c3c3c;margin-top:8px;padding:10px;';
|
|
2204
|
-
visDiv.innerHTML = `
|
|
2205
|
-
<div style="color:#9cdcfe;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;">
|
|
2206
|
-
Screen Visibility Control
|
|
2207
|
-
</div>
|
|
2208
|
-
<label style="display:flex;align-items:center;gap:8px;margin-bottom:8px;cursor:pointer;font-size:11px;">
|
|
2209
|
-
<input type="checkbox" id="__3d_vis_en" />
|
|
2210
|
-
Enable Visibility Control
|
|
2211
|
-
</label>
|
|
2212
|
-
<div style="font-size:11px;color:#888;margin-bottom:4px;">Only for groups:</div>
|
|
2213
|
-
<div id="__3d_vis_groups" style="border:1px solid #444;padding:6px;max-height:100px;overflow-y:auto;background:#111;font-size:11px;margin-bottom:8px;">
|
|
2214
|
-
<span style="color:#555;">Loading...</span>
|
|
2215
|
-
</div>
|
|
2216
|
-
<div style="font-size:11px;color:#888;margin-bottom:4px;">If not in group:</div>
|
|
2217
|
-
<select id="__3d_vis_act" style="width:100%;background:#3c3c3c;border:1px solid #555;color:#ccc;padding:4px;font-size:11px;margin-bottom:8px;">
|
|
2218
|
-
<option value="hide">Show "Access Denied"</option>
|
|
2219
|
-
<option value="redirect">Redirect to screen</option>
|
|
2220
|
-
</select>
|
|
2221
|
-
<div id="__3d_vis_rdiv" style="display:none;">
|
|
2222
|
-
<div style="font-size:11px;color:#888;margin-bottom:4px;">Redirect screen:</div>
|
|
2223
|
-
<input id="__3d_vis_redir" type="text" style="width:100%;background:#3c3c3c;border:1px solid #555;color:#ccc;padding:4px;font-size:11px;box-sizing:border-box;" />
|
|
2224
|
-
</div>
|
|
2225
|
-
`;
|
|
2226
|
-
|
|
2227
|
-
const settings = editor3DEl.sceneData?.settings ?? {};
|
|
2228
|
-
editor3DEl.sceneData = editor3DEl.sceneData ?? {};
|
|
2229
|
-
editor3DEl.sceneData.settings = settings;
|
|
2230
|
-
if (!settings.visibilityEnabled) settings.visibilityEnabled = false;
|
|
2231
|
-
if (!settings.visibilityGroups) settings.visibilityGroups = [];
|
|
2232
|
-
if (!settings.visibilityAction) settings.visibilityAction = 'hide';
|
|
2233
|
-
if (!settings.visibilityRedirectScreen) settings.visibilityRedirectScreen = '';
|
|
2234
|
-
|
|
2235
|
-
const save = () => {};
|
|
2236
|
-
const enEl = visDiv.querySelector('#__3d_vis_en');
|
|
2237
|
-
const actEl = visDiv.querySelector('#__3d_vis_act');
|
|
2238
|
-
const rdDiv = visDiv.querySelector('#__3d_vis_rdiv');
|
|
2239
|
-
const rdEl = visDiv.querySelector('#__3d_vis_redir');
|
|
2240
|
-
|
|
2241
|
-
if (enEl) { enEl.checked = settings.visibilityEnabled; enEl.addEventListener('change', e => { settings.visibilityEnabled = e.target.checked; }); }
|
|
2242
|
-
if (actEl) { actEl.value = settings.visibilityAction; actEl.addEventListener('change', e => { settings.visibilityAction = e.target.value; if (rdDiv) rdDiv.style.display = e.target.value === 'redirect' ? 'block' : 'none'; }); }
|
|
2243
|
-
if (rdDiv) rdDiv.style.display = settings.visibilityAction === 'redirect' ? 'block' : 'none';
|
|
2244
|
-
if (rdEl) { rdEl.value = settings.visibilityRedirectScreen || ''; rdEl.addEventListener('input', e => { settings.visibilityRedirectScreen = e.target.value; }); }
|
|
2245
|
-
|
|
2246
|
-
// Load groups
|
|
2247
|
-
const grpEl = visDiv.querySelector('#__3d_vis_groups');
|
|
2248
|
-
iobrokerHandler.getUserGroups?.().then(groups => {
|
|
2249
|
-
if (!grpEl) return;
|
|
2250
|
-
if (!groups?.length) { grpEl.innerHTML = '<span style="color:#555;">No groups</span>'; return; }
|
|
2251
|
-
grpEl.innerHTML = '';
|
|
2252
|
-
groups.forEach(g => {
|
|
2253
|
-
const id = typeof g === 'string' ? g : (g.id ?? g._id ?? g.name ?? g);
|
|
2254
|
-
const lbl = typeof g === 'string' ? g : (g.name ?? id);
|
|
2255
|
-
const chk = (settings.visibilityGroups || []).includes(id);
|
|
2256
|
-
const row = document.createElement('label');
|
|
2257
|
-
row.style.cssText = 'display:flex;align-items:center;gap:6px;padding:2px 0;cursor:pointer;';
|
|
2258
|
-
row.innerHTML = `<input type="checkbox" ${chk ? 'checked' : ''} />${lbl}`;
|
|
2259
|
-
row.querySelector('input').addEventListener('change', ev => {
|
|
2260
|
-
const arr = settings.visibilityGroups || [];
|
|
2261
|
-
if (ev.target.checked) { if (!arr.includes(id)) arr.push(id); }
|
|
2262
|
-
else { const i = arr.indexOf(id); if (i >= 0) arr.splice(i, 1); }
|
|
2263
|
-
settings.visibilityGroups = arr;
|
|
2264
|
-
});
|
|
2265
|
-
grpEl.appendChild(row);
|
|
2266
|
-
});
|
|
2267
|
-
}).catch(() => { if (grpEl) grpEl.innerHTML = '<span style="color:#555;">—</span>'; });
|
|
2268
|
-
|
|
2269
|
-
wrap.appendChild(visDiv);
|
|
2270
|
-
});
|
|
2271
|
-
|
|
2272
|
-
settiDock.appendChild(wrap);
|
|
2273
|
-
this._3dSettPanel = wrap;
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
2194
|
// ── effectsDock: SidebarProject (Geometries / Materials / Textures) ──
|
|
2277
2195
|
if (projDock) {
|
|
2278
2196
|
const wrap = document.createElement('div');
|
|
@@ -2307,12 +2225,10 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
2307
2225
|
}
|
|
2308
2226
|
};
|
|
2309
2227
|
|
|
2310
|
-
restore('attributeDock',
|
|
2311
|
-
restore('
|
|
2312
|
-
restore('effectsDock', this._3dProjPanel);
|
|
2228
|
+
restore('attributeDock', this._3dPropsPanel);
|
|
2229
|
+
restore('effectsDock', this._3dProjPanel);
|
|
2313
2230
|
|
|
2314
2231
|
this._3dPropsPanel = null;
|
|
2315
|
-
this._3dSettPanel = null;
|
|
2316
2232
|
this._3dProjPanel = null;
|
|
2317
2233
|
}
|
|
2318
2234
|
}
|