iobroker.mywebui 1.42.19 → 1.42.20

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.19",
4
+ "version": "1.42.20",
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.19",
3
+ "version": "1.42.20",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413 with 3D Editor",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -1712,6 +1712,46 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1712
1712
  // ── Interaction binding ──
1713
1713
  const nodeKey = (node?.userData?.assetData === asset || !node?.name) ? '__root__' : (node?.name || nodeName);
1714
1714
  const inter = asset?.interactions?.[nodeKey];
1715
+
1716
+ // ── Events ──
1717
+ const nodeEvents = asset?.events?.[nodeKey] ?? {};
1718
+ const nodeEventEntries = Object.entries(nodeEvents);
1719
+ const presetEvents = [
1720
+ { key: 'click', label: '🖱️ click' },
1721
+ { key: 'mouseenter', label: '↗️ mouseenter' },
1722
+ { key: 'mouseleave', label: '↙️ mouseleave' },
1723
+ { key: 'animationEnd', label: '🎬 animationEnd (any clip)' },
1724
+ ...( (asset?.availableClips ?? []).map(c => ({ key: `animationEnd:${c}`, label: `🎬 animationEnd:${c}` })) ),
1725
+ ...( (asset?.drives ?? []).flatMap((_, i) => [
1726
+ { key: `driveAtMax:${i}`, label: `⬆️ driveAtMax:${i}` },
1727
+ { key: `driveAtMin:${i}`, label: `⬇️ driveAtMin:${i}` },
1728
+ ]) ),
1729
+ ].filter(p => !nodeEvents[p.key]);
1730
+ const presetOptsHtml = presetEvents.map(p => `<option value="${p.key}">${p.label}</option>`).join('');
1731
+ const eventsHtml = nodeEventEntries.length > 0
1732
+ ? nodeEventEntries.map(([evtKey, script]) => `
1733
+ <div class="evt-row" style="background:#1a1a2e;border:1px solid #2a2a4a;border-radius:3px;padding:5px;margin-bottom:4px;">
1734
+ <div style="display:flex;align-items:center;gap:4px;margin-bottom:3px;">
1735
+ <span style="color:#dcdcaa;font-size:10px;flex:1;font-family:monospace;">${evtKey}</span>
1736
+ <button class="evt-del-btn tb-btn" data-evtkey="${evtKey}" style="padding:0px 5px;font-size:9px;background:#5a1a1a;color:#f44747;border-color:#8a2a2a;">✕</button>
1737
+ </div>
1738
+ <textarea class="evt-script" data-evtkey="${evtKey}" rows="3"
1739
+ style="width:100%;box-sizing:border-box;background:#0d0d1a;border:1px solid #3c3c5c;color:#d4d4d4;font-family:'Consolas',monospace;font-size:10px;padding:4px;resize:vertical;line-height:1.4;"
1740
+ spellcheck="false"
1741
+ placeholder="// context: node, assetData, THREE, scene, camera&#10;// setState(signal, val), getState(signal), subscribe(signal, cb)&#10;// assets Map, mixers Map, driveEngine"
1742
+ >${this._escHtml(script)}</textarea>
1743
+ </div>`).join('')
1744
+ : `<div style="color:#555;font-size:10px;font-style:italic;padding:4px 0;">No events configured</div>`;
1745
+ const eventsAddHtml = presetEvents.length > 0
1746
+ ? `<div style="display:flex;gap:4px;margin-top:4px;">
1747
+ <select class="evt-preset-sel" style="flex:1;background:#3c3c3c;border:1px solid #555;color:#ccc;padding:2px 4px;border-radius:3px;font-size:10px;">
1748
+ <option value="">— select event type —</option>
1749
+ ${presetOptsHtml}
1750
+ <option value="__custom__">Custom event name...</option>
1751
+ </select>
1752
+ <button class="evt-add-btn tb-btn" style="padding:1px 10px;font-size:10px;">+ Add</button>
1753
+ </div>`
1754
+ : `<div style="color:#555;font-size:9px;margin-top:4px;">All event types configured</div>`;
1715
1755
  const interHtml = inter
1716
1756
  ? `<div style="background:#1a2a1a;border:1px solid #2a4a2a;border-radius:3px;padding:6px;font-size:10px;">
1717
1757
  <div>Signal: <span style="color:#9cdcfe;">${inter.signal}</span></div>
@@ -1771,6 +1811,19 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1771
1811
  <div class="pg-header">🖱️ Interaction (onClick) <button class="inter-add-btn tb-btn" style="padding:1px 8px;font-size:9px;">+ Set</button></div>
1772
1812
  ${interHtml}
1773
1813
  </div>
1814
+ <div class="pg-group">
1815
+ <div class="pg-header">⚡ Events
1816
+ <span style="color:#555;font-size:9px;font-weight:normal;">node: ${nodeKey}</span>
1817
+ </div>
1818
+ ${eventsHtml}
1819
+ ${eventsAddHtml}
1820
+ <div style="color:#555;font-size:9px;margin-top:6px;line-height:1.5;">
1821
+ Script context:<br>
1822
+ <code style="color:#888;">node, assetData, THREE, scene</code><br>
1823
+ <code style="color:#888;">setState(sig,val) · getState(sig)</code><br>
1824
+ <code style="color:#888;">assets(Map) · mixers · driveEngine</code>
1825
+ </div>
1826
+ </div>
1774
1827
  </div>
1775
1828
  `;
1776
1829
 
@@ -1856,92 +1909,8 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1856
1909
  }
1857
1910
  });
1858
1911
 
1859
- // Show events in native Events dock
1860
- this._show3DEventsInDock(node, asset, nodeKey, onChange);
1861
- }
1862
-
1863
- _escHtml(str) {
1864
- return (str || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
1865
- }
1866
-
1867
- _show3DEventsInDock(node, asset, nodeKey, onChange) {
1868
- const dock = this._getDomElement('eventsDock');
1869
- if (!dock) return;
1870
-
1871
- // Get or create the 3D events overlay container
1872
- let d3 = dock.querySelector('#_3dEventsOverlay');
1873
- if (!d3) {
1874
- d3 = document.createElement('div');
1875
- d3.id = '_3dEventsOverlay';
1876
- d3.style.cssText = 'width:100%;height:100%;overflow:auto;box-sizing:border-box;background:#1e1e1e;color:#ccc;font-family:"Segoe UI",sans-serif;font-size:12px;';
1877
- dock.insertBefore(d3, dock.firstChild);
1878
- }
1879
- d3.style.display = 'block';
1880
-
1881
- // Hide native event assignment
1882
- const nativeEvt = this._getDomElement('eventsList');
1883
- if (nativeEvt) nativeEvt.style.display = 'none';
1884
-
1885
- // Build events HTML
1886
- const nodeEvents = asset?.events?.[nodeKey] ?? {};
1887
- const nodeEventEntries = Object.entries(nodeEvents);
1888
- const presetEvents = [
1889
- { key: 'click', label: '🖱️ click' },
1890
- { key: 'mouseenter', label: '↗️ mouseenter' },
1891
- { key: 'mouseleave', label: '↙️ mouseleave' },
1892
- { key: 'animationEnd', label: '🎬 animationEnd' },
1893
- ...((asset?.availableClips ?? []).map(c => ({ key: `animationEnd:${c}`, label: `🎬 animationEnd:${c}` }))),
1894
- ...((asset?.drives ?? []).flatMap((_, i) => [
1895
- { key: `driveAtMax:${i}`, label: `⬆️ driveAtMax:${i}` },
1896
- { key: `driveAtMin:${i}`, label: `⬇️ driveAtMin:${i}` }
1897
- ])),
1898
- ].filter(p => !nodeEvents[p.key]);
1899
-
1900
- const evtRowsHtml = nodeEventEntries.length > 0
1901
- ? nodeEventEntries.map(([evtKey, script]) => `
1902
- <div style="background:#1a1a2e;border:1px solid #2a2a4a;border-radius:3px;padding:5px;margin-bottom:6px;">
1903
- <div style="display:flex;align-items:center;gap:4px;margin-bottom:3px;">
1904
- <span style="color:#dcdcaa;font-size:11px;flex:1;font-family:monospace;">${evtKey}</span>
1905
- <button class="evt-del-btn" data-evtkey="${evtKey}" style="padding:1px 6px;font-size:10px;background:#5a1a1a;color:#f44747;border:1px solid #8a2a2a;border-radius:3px;cursor:pointer;">✕</button>
1906
- </div>
1907
- <textarea class="evt-script" data-evtkey="${evtKey}" rows="4"
1908
- style="width:100%;box-sizing:border-box;background:#0d0d1a;border:1px solid #3c3c5c;color:#d4d4d4;font-family:'Consolas',monospace;font-size:11px;padding:4px;resize:vertical;line-height:1.4;border-radius:2px;"
1909
- spellcheck="false"
1910
- placeholder="// context: node, assetData, THREE, scene&#10;// setState(sig,val) getState(sig)&#10;// assets(Map) mixers driveEngine"
1911
- >${this._escHtml(script)}</textarea>
1912
- </div>`).join('')
1913
- : `<div style="color:#555;font-size:11px;font-style:italic;padding:8px 0;">No events configured</div>`;
1914
-
1915
- const presetOptsHtml = presetEvents.map(p => `<option value="${p.key}">${p.label}</option>`).join('');
1916
- const addRowHtml = presetEvents.length > 0
1917
- ? `<div style="display:flex;gap:4px;margin-top:6px;">
1918
- <select class="evt-preset-sel" style="flex:1;background:#3c3c3c;border:1px solid #555;color:#ccc;padding:3px 4px;border-radius:3px;font-size:11px;">
1919
- <option value="">— select event type —</option>
1920
- ${presetOptsHtml}
1921
- <option value="__custom__">Custom event name...</option>
1922
- </select>
1923
- <button class="evt-add-btn" style="padding:2px 12px;background:#3c3c3c;color:#ccc;border:1px solid #555;border-radius:3px;cursor:pointer;font-size:11px;">+ Add</button>
1924
- </div>`
1925
- : `<div style="color:#555;font-size:10px;margin-top:6px;">All standard events configured</div>`;
1926
-
1927
- d3.innerHTML = `
1928
- <div style="padding:6px 8px;border-bottom:1px solid #3c3c3c;background:#252526;display:flex;align-items:center;gap:6px;">
1929
- <span style="color:#dcdcaa;font-size:11px;font-weight:bold;">⚡ 3D Events</span>
1930
- <span style="color:#555;font-size:10px;">node: ${nodeKey}</span>
1931
- </div>
1932
- <div style="padding:8px;">
1933
- ${evtRowsHtml}
1934
- ${addRowHtml}
1935
- <div style="color:#555;font-size:10px;margin-top:8px;line-height:1.6;">
1936
- Context: <code style="color:#888;">node, assetData, THREE, scene</code><br>
1937
- <code style="color:#888;">setState(sig,val) · getState(sig)</code><br>
1938
- <code style="color:#888;">assets(Map) · mixers · driveEngine</code>
1939
- </div>
1940
- </div>
1941
- `;
1942
-
1943
- // Wire textarea auto-save
1944
- d3.querySelectorAll('.evt-script').forEach(ta => {
1912
+ // ── Events wiring ──
1913
+ p.querySelectorAll('.evt-script').forEach(ta => {
1945
1914
  ta.addEventListener('blur', () => {
1946
1915
  const evtKey = ta.dataset.evtkey;
1947
1916
  if (!asset.events) asset.events = {};
@@ -1950,23 +1919,19 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1950
1919
  if (onChange) onChange(asset);
1951
1920
  });
1952
1921
  });
1953
-
1954
- // Wire delete buttons
1955
- d3.querySelectorAll('.evt-del-btn').forEach(btn => {
1922
+ p.querySelectorAll('.evt-del-btn').forEach(btn => {
1956
1923
  btn.addEventListener('click', () => {
1957
1924
  const evtKey = btn.dataset.evtkey;
1958
1925
  if (asset?.events?.[nodeKey]) {
1959
1926
  delete asset.events[nodeKey][evtKey];
1960
1927
  if (Object.keys(asset.events[nodeKey]).length === 0) delete asset.events[nodeKey];
1961
1928
  if (onChange) onChange(asset);
1962
- this._show3DEventsInDock(node, asset, nodeKey, onChange);
1929
+ this.show3DNodeProperties(node, asset, mixerInfo, onChange);
1963
1930
  }
1964
1931
  });
1965
1932
  });
1966
-
1967
- // Wire add button
1968
- d3.querySelector('.evt-add-btn')?.addEventListener('click', () => {
1969
- const sel = d3.querySelector('.evt-preset-sel');
1933
+ p.querySelector('.evt-add-btn')?.addEventListener('click', () => {
1934
+ const sel = p.querySelector('.evt-preset-sel');
1970
1935
  let evtKey = sel?.value;
1971
1936
  if (!evtKey) return;
1972
1937
  if (evtKey === '__custom__') {
@@ -1977,22 +1942,15 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
1977
1942
  if (!asset.events[nodeKey]) asset.events[nodeKey] = {};
1978
1943
  if (!asset.events[nodeKey][evtKey]) asset.events[nodeKey][evtKey] = '// event: ' + evtKey + '\n';
1979
1944
  if (onChange) onChange(asset);
1980
- this._show3DEventsInDock(node, asset, nodeKey, onChange);
1945
+ this.show3DNodeProperties(node, asset, mixerInfo, onChange);
1981
1946
  });
1982
-
1983
- // Activate the events dock panel
1984
- this.activateDockById('eventsDock');
1985
1947
  }
1986
1948
 
1987
- _restore3DEventsDock() {
1988
- const dock = this._getDomElement('eventsDock');
1989
- if (!dock) return;
1990
- const d3 = dock.querySelector('#_3dEventsOverlay');
1991
- if (d3) d3.style.display = 'none';
1992
- const nativeEvt = this._getDomElement('eventsList');
1993
- if (nativeEvt) nativeEvt.style.display = '';
1949
+ _escHtml(str) {
1950
+ return (str || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
1994
1951
  }
1995
1952
 
1953
+
1996
1954
  _showAddDriveDialog(obj, onChange) {
1997
1955
  // Build a modal dialog for drive configuration
1998
1956
  const overlay = document.createElement('div');