iobroker.mywebui 1.42.13 → 1.42.14

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/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "mywebui",
4
- "version": "1.42.13",
4
+ "version": "1.42.14",
5
5
  "titleLang": {
6
6
  "en": "mywebui",
7
7
  "de": "mywebui",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.mywebui",
3
- "version": "1.42.13",
3
+ "version": "1.42.14",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413 with 3D Editor",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -1498,19 +1498,22 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1498
1498
  }
1499
1499
  }
1500
1500
  show3DObjectProperties(obj, onChange) {
1501
- const id = '3d_properties';
1502
- // Reuse existing dock or open new one
1503
- const existing = this.isDockOpenAndActivate(id);
1504
- let panel;
1505
- if (!existing) {
1501
+ // Reuse cached panel reference (avoid querySelector with invalid CSS id)
1502
+ let panel = this._tdPropsPanel;
1503
+ if (!panel || !panel.isConnected) {
1506
1504
  panel = document.createElement('div');
1507
- panel.id = id;
1505
+ panel.id = 'tdPropsPanel';
1508
1506
  panel.title = '3D Properties';
1509
1507
  panel.style.cssText = 'width:100%;height:100%;overflow:auto;background:#1e1e1e;color:#ccc;font-size:12px;font-family:"Segoe UI",sans-serif;';
1510
- this.openDock(panel);
1508
+ // Dock to right side (attributeDock area)
1509
+ panel.setAttribute('dock-spawn-dock-to', 'attributeDock');
1510
+ panel.setAttribute('dock-spawn-dock-type', 'fill');
1511
+ panel.setAttribute('dock-spawn-panel-type', 'document');
1512
+ this._dock.appendChild(panel);
1513
+ this._tdPropsPanel = panel;
1511
1514
  } else {
1512
- panel = this.shadowRoot?.querySelector('#' + id) ||
1513
- document.querySelector('#' + id);
1515
+ // Activate existing tab
1516
+ this.isDockOpenAndActivate('tdPropsPanel');
1514
1517
  }
1515
1518
  if (!panel) return;
1516
1519
 
@@ -1520,63 +1523,68 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1520
1523
  const rot = obj.rotation ?? { x: 0, y: 0, z: 0 };
1521
1524
  const scl = obj.scale ?? { x: 1, y: 1, z: 1 };
1522
1525
 
1526
+ const bindingsHtml = obj.bindings && Object.keys(obj.bindings).length > 0
1527
+ ? Object.entries(obj.bindings).map(([k, bv]) =>
1528
+ `<div style="padding:2px 0;border-bottom:1px solid #3c3c3c;display:flex;gap:4px;">
1529
+ <span style="color:#4ec9b0;flex:1;">${k}</span>
1530
+ <span style="color:#888;flex:2;overflow:hidden;text-overflow:ellipsis;">${bv.signal||''}</span>
1531
+ </div>`).join('')
1532
+ : '<span style="font-style:italic;color:#555;">No bindings</span>';
1533
+
1523
1534
  panel.innerHTML = `
1535
+ <style>
1536
+ .pg-group{margin-bottom:10px;}
1537
+ .pg-header{color:#888;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:0.5px;padding:4px 0;border-bottom:1px solid #3c3c3c;margin-bottom:4px;}
1538
+ .pg-row{display:flex;align-items:center;margin-bottom:3px;}
1539
+ .pg-row label{width:16px;color:#888;font-size:10px;margin-right:6px;}
1540
+ .pg-input{flex:1;background:#3c3c3c;border:1px solid #555;color:#ccc;padding:3px 5px;border-radius:2px;font-size:11px;}
1541
+ .pg-input:focus{outline:none;border-color:#9cdcfe;}
1542
+ </style>
1524
1543
  <div style="padding:8px;border-bottom:1px solid #3c3c3c;background:#252526;">
1525
- <div style="color:#9cdcfe;font-weight:bold;font-size:11px;letter-spacing:0.5px;">📦 ${obj.name || 'Object'}</div>
1544
+ <div style="color:#9cdcfe;font-weight:bold;font-size:11px;letter-spacing:0.5px;">&#128230; ${obj.name || 'Object'}</div>
1526
1545
  <div style="color:#666;font-size:10px;">${obj.type || 'model'}</div>
1527
1546
  </div>
1528
1547
  <div style="padding:8px;">
1529
1548
  <div class="pg-group">
1530
1549
  <div class="pg-header">Position</div>
1531
- <div class="pg-row"><label>X</label><input class="pg-input" id="px" type="number" step="0.1" value="${(pos.x||0).toFixed(3)}"></div>
1532
- <div class="pg-row"><label>Y</label><input class="pg-input" id="py" type="number" step="0.1" value="${(pos.y||0).toFixed(3)}"></div>
1533
- <div class="pg-row"><label>Z</label><input class="pg-input" id="pz" type="number" step="0.1" value="${(pos.z||0).toFixed(3)}"></div>
1550
+ <div class="pg-row"><label>X</label><input class="pg-input" data-fid="px" type="number" step="0.1" value="${(pos.x||0).toFixed(3)}"></div>
1551
+ <div class="pg-row"><label>Y</label><input class="pg-input" data-fid="py" type="number" step="0.1" value="${(pos.y||0).toFixed(3)}"></div>
1552
+ <div class="pg-row"><label>Z</label><input class="pg-input" data-fid="pz" type="number" step="0.1" value="${(pos.z||0).toFixed(3)}"></div>
1534
1553
  </div>
1535
1554
  <div class="pg-group">
1536
1555
  <div class="pg-header">Rotation (rad)</div>
1537
- <div class="pg-row"><label>X</label><input class="pg-input" id="rx" type="number" step="0.01" value="${(rot.x||0).toFixed(4)}"></div>
1538
- <div class="pg-row"><label>Y</label><input class="pg-input" id="ry" type="number" step="0.01" value="${(rot.y||0).toFixed(4)}"></div>
1539
- <div class="pg-row"><label>Z</label><input class="pg-input" id="rz" type="number" step="0.01" value="${(rot.z||0).toFixed(4)}"></div>
1556
+ <div class="pg-row"><label>X</label><input class="pg-input" data-fid="rx" type="number" step="0.01" value="${(rot.x||0).toFixed(4)}"></div>
1557
+ <div class="pg-row"><label>Y</label><input class="pg-input" data-fid="ry" type="number" step="0.01" value="${(rot.y||0).toFixed(4)}"></div>
1558
+ <div class="pg-row"><label>Z</label><input class="pg-input" data-fid="rz" type="number" step="0.01" value="${(rot.z||0).toFixed(4)}"></div>
1540
1559
  </div>
1541
1560
  <div class="pg-group">
1542
1561
  <div class="pg-header">Scale</div>
1543
- <div class="pg-row"><label>X</label><input class="pg-input" id="sx" type="number" step="0.1" value="${(scl.x||1).toFixed(3)}"></div>
1544
- <div class="pg-row"><label>Y</label><input class="pg-input" id="sy" type="number" step="0.1" value="${(scl.y||1).toFixed(3)}"></div>
1545
- <div class="pg-row"><label>Z</label><input class="pg-input" id="sz" type="number" step="0.1" value="${(scl.z||1).toFixed(3)}"></div>
1562
+ <div class="pg-row"><label>X</label><input class="pg-input" data-fid="sx" type="number" step="0.1" value="${(scl.x||1).toFixed(3)}"></div>
1563
+ <div class="pg-row"><label>Y</label><input class="pg-input" data-fid="sy" type="number" step="0.1" value="${(scl.y||1).toFixed(3)}"></div>
1564
+ <div class="pg-row"><label>Z</label><input class="pg-input" data-fid="sz" type="number" step="0.1" value="${(scl.z||1).toFixed(3)}"></div>
1546
1565
  </div>
1547
1566
  <div class="pg-group">
1548
1567
  <div class="pg-header">ioBroker Bindings</div>
1549
- <div id="bindList" style="font-size:10px;color:#666;padding:4px 0;">${
1550
- obj.bindings && Object.keys(obj.bindings).length > 0
1551
- ? Object.entries(obj.bindings).map(([k,v]) =>
1552
- `<div style="padding:2px 0;border-bottom:1px solid #3c3c3c;display:flex;gap:4px;">
1553
- <span style="color:#4ec9b0;flex:1;">${k}</span>
1554
- <span style="color:#888;flex:2;overflow:hidden;text-overflow:ellipsis;">${v.signal||''}</span>
1555
- </div>`).join('')
1556
- : '<span style="font-style:italic;">No bindings</span>'
1557
- }</div>
1558
- <button id="addBindBtn" style="width:100%;padding:4px;background:#1a3a1a;color:#4ec9b0;border:1px solid #2a5a2a;border-radius:3px;cursor:pointer;font-size:10px;margin-top:4px;">+ Add Binding</button>
1568
+ <div style="font-size:10px;padding:4px 0;">${bindingsHtml}</div>
1569
+ <button class="bind-add-btn" style="width:100%;padding:4px;background:#1a3a1a;color:#4ec9b0;border:1px solid #2a5a2a;border-radius:3px;cursor:pointer;font-size:10px;margin-top:4px;">+ Add Binding</button>
1559
1570
  </div>
1560
1571
  </div>
1561
- <style>
1562
- .pg-group { margin-bottom:10px; }
1563
- .pg-header { color:#888;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:0.5px;padding:4px 0;border-bottom:1px solid #3c3c3c;margin-bottom:4px; }
1564
- .pg-row { display:flex;align-items:center;margin-bottom:3px; }
1565
- .pg-row label { width:16px;color:#888;font-size:10px;margin-right:6px; }
1566
- .pg-input { flex:1;background:#3c3c3c;border:1px solid #555;color:#ccc;padding:3px 5px;border-radius:2px;font-size:11px; }
1567
- .pg-input:focus { outline:none;border-color:#9cdcfe; }
1568
- </style>
1569
1572
  `;
1570
1573
 
1571
- const applyChange = () => {
1572
- obj.position = { x: parseFloat(panel.querySelector('#px').value)||0, y: parseFloat(panel.querySelector('#py').value)||0, z: parseFloat(panel.querySelector('#pz').value)||0 };
1573
- obj.rotation = { x: parseFloat(panel.querySelector('#rx').value)||0, y: parseFloat(panel.querySelector('#ry').value)||0, z: parseFloat(panel.querySelector('#rz').value)||0 };
1574
- obj.scale = { x: parseFloat(panel.querySelector('#sx').value)||1, y: parseFloat(panel.querySelector('#sy').value)||1, z: parseFloat(panel.querySelector('#sz').value)||1 };
1575
- if (onChange) onChange(obj);
1576
- };
1577
-
1578
- panel.querySelectorAll('.pg-input').forEach(inp => inp.addEventListener('change', applyChange));
1579
- panel.querySelector('#addBindBtn').addEventListener('click', () => {
1574
+ const p = panel;
1575
+ const v = (id) => parseFloat(p.querySelector('[data-fid="'+id+'"]')?.value) || 0;
1576
+ const v1 = (id) => parseFloat(p.querySelector('[data-fid="'+id+'"]')?.value) || 1;
1577
+
1578
+ // Replace #id inputs with data-fid to avoid querySelector ID issues
1579
+ p.querySelectorAll('[data-fid]').forEach(inp => {
1580
+ inp.addEventListener('change', () => {
1581
+ obj.position = { x: v('px'), y: v('py'), z: v('pz') };
1582
+ obj.rotation = { x: v('rx'), y: v('ry'), z: v('rz') };
1583
+ obj.scale = { x: v1('sx'), y: v1('sy'), z: v1('sz') };
1584
+ if (onChange) onChange(obj);
1585
+ });
1586
+ });
1587
+ p.querySelector('.bind-add-btn')?.addEventListener('click', () => {
1580
1588
  const prop = prompt('Property (e.g. position.x, rotation.y, scale.z):', 'position.x');
1581
1589
  if (!prop) return;
1582
1590
  const signal = prompt('ioBroker signal path:', '');