iobroker.mywebui 1.37.37 → 1.37.39

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.37.37",
4
+ "version": "1.37.39",
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.37.37",
3
+ "version": "1.37.39",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -404,9 +404,31 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
404
404
  const designItem = selectedItems[0];
405
405
  const element = designItem.element;
406
406
 
407
- // Read existing signal from data-visibility-signal (NOT bind-prop:hidden)
408
- const existingSignal = element.getAttribute('data-visibility-signal') || null;
409
- const existingBinding = existingSignal ? { signal: existingSignal, target: 'property' } : null;
407
+ // Read existing signal from data-visibility-signal (may be plain signal string or JSON with signal+expression+historic+converter)
408
+ const existingSignalAttr = element.getAttribute('data-visibility-signal') || null;
409
+ let existingSignal = existingSignalAttr;
410
+ let existingBinding = null;
411
+ if (existingSignalAttr) {
412
+ if (existingSignalAttr.startsWith('{')) {
413
+ try {
414
+ const parsed = JSON.parse(existingSignalAttr);
415
+ existingSignal = parsed.signal || existingSignalAttr;
416
+ // BindingsEditor expects bindableObjectNames array, not signal string
417
+ existingBinding = {
418
+ bindableObjectNames: parsed.signal ? [parsed.signal] : [],
419
+ expression: parsed.expression || '',
420
+ historic: parsed.historic || null,
421
+ converter: parsed.converter || null,
422
+ invert: parsed.invert || false,
423
+ target: 'property'
424
+ };
425
+ } catch (e) {
426
+ existingBinding = { bindableObjectNames: [existingSignalAttr], target: 'property' };
427
+ }
428
+ } else {
429
+ existingBinding = { bindableObjectNames: [existingSignalAttr], target: 'property' };
430
+ }
431
+ }
410
432
 
411
433
  // Read group access control config from data attributes
412
434
  const dataConfig = {
@@ -436,11 +458,23 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
436
458
  dlg.close();
437
459
  const signal = dynEdt.objectNames;
438
460
  if (signal) {
439
- designItem.setAttribute('data-visibility-signal', signal);
461
+ const bnd = { signal };
462
+ if (dynEdt.expression) bnd.expression = dynEdt.expression;
463
+ if (dynEdt.historic) bnd.historic = dynEdt.historic;
464
+ if (dynEdt.invert) bnd.invert = true;
465
+ // converters: array of {key,value} objects → plain object, or named converter string
466
+ if (dynEdt.converters && dynEdt.converters.length > 0) {
467
+ bnd.converter = {};
468
+ for (const c of dynEdt.converters) bnd.converter[c.key] = c.value;
469
+ } else if (dynEdt.convertersString) {
470
+ bnd.converter = dynEdt.convertersString;
471
+ }
472
+ const needsJson = bnd.expression || bnd.historic || bnd.converter || bnd.invert;
473
+ designItem.setAttribute('data-visibility-signal', needsJson ? JSON.stringify(bnd) : signal);
440
474
  } else {
441
475
  designItem.removeAttribute('data-visibility-signal');
442
476
  }
443
- designItem.removeAttribute('bind-prop:hidden'); // clean up old approach
477
+ designItem.removeAttribute('bind-prop:hidden');
444
478
  this._updateVisibilityPanel();
445
479
  });
446
480
  };
@@ -449,13 +483,11 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
449
483
  const bindRow = document.createElement('div');
450
484
  bindRow.style.cssText = 'display:flex;align-items:center;gap:6px;padding:4px 0;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #ddd;';
451
485
 
452
- // button on the LEFT (like Properties panel style)
453
- const bindBtn = document.createElement('button');
454
- bindBtn.textContent = '';
455
- bindBtn.title = 'Right-click for binding options';
456
- bindBtn.style.cssText = existingSignal
457
- ? 'width:16px;height:16px;padding:0;font-size:11px;line-height:1;border:1px solid #888;background:#ffd700;cursor:pointer;flex-shrink:0;'
458
- : 'width:16px;height:16px;padding:0;font-size:11px;line-height:1;border:1px solid #888;background:#f0f0f0;cursor:pointer;flex-shrink:0;';
486
+ // Bind indicator styled exactly like PropertyGridPropertyList's isSetElement
487
+ const bindBtn = document.createElement('div');
488
+ bindBtn.title = existingSignal ? 'Visibility: ' + existingSignal + ' (click / right-click)' : 'Click to bind visibility signal';
489
+ bindBtn.style.cssText = 'width:11px;height:11px;border:1px solid #596c7a;cursor:pointer;flex-shrink:0;box-sizing:border-box;'
490
+ + (existingSignal ? 'background:orange;' : 'background:transparent;');
459
491
 
460
492
  bindBtn.onclick = openVisibilityBindingEditor;
461
493
 
@@ -44,11 +44,36 @@ class VisibilityService {
44
44
 
45
45
  // Step 2: Signal/state check (if objectId configured)
46
46
  if (visibilityConfig.objectId) {
47
+ // objectId may be a plain signal string or JSON like {"signal":"...","expression":"...","converter":{...},"historic":{...}}
48
+ let signalId = visibilityConfig.objectId;
49
+ let expression = null;
50
+ let converter = null;
51
+ if (typeof signalId === 'string' && signalId.startsWith('{')) {
52
+ try {
53
+ const parsed = JSON.parse(signalId);
54
+ signalId = parsed.signal || signalId;
55
+ expression = parsed.expression || null;
56
+ converter = parsed.converter || null;
57
+ } catch (e) { /* keep raw */ }
58
+ }
59
+
47
60
  let stateVal = currentStateVal;
48
61
  if (stateVal === undefined) {
49
- const state = await iobrokerHandler.connection.getState(visibilityConfig.objectId);
62
+ const state = await iobrokerHandler.connection.getState(signalId);
50
63
  stateVal = state?.val;
51
64
  }
65
+
66
+ // Evaluate expression if present
67
+ if (expression) {
68
+ try { stateVal = new Function('__0', expression)(stateVal); } catch (e) { console.warn('[Visibility] Expression error:', e); }
69
+ }
70
+
71
+ // Apply converter if present (object map like {"true":"1","false":"0"} or inverse)
72
+ if (converter && typeof converter === 'object') {
73
+ const key = String(stateVal);
74
+ if (key in converter) stateVal = converter[key];
75
+ }
76
+
52
77
  // Truthy state value → apply action
53
78
  const isActive = stateVal !== null && stateVal !== undefined && stateVal !== false && stateVal !== 0 && stateVal !== '';
54
79
  this.#applyResult(element, isActive
@@ -75,7 +100,11 @@ class VisibilityService {
75
100
  await this.#checkAndApply(element, visibilityConfig, undefined);
76
101
 
77
102
  if (visibilityConfig.objectId) {
78
- await iobrokerHandler.subscribeState(visibilityConfig.objectId, (_id, state) => {
103
+ let signalId = visibilityConfig.objectId;
104
+ if (typeof signalId === 'string' && signalId.startsWith('{')) {
105
+ try { signalId = JSON.parse(signalId).signal || signalId; } catch (e) { /* keep raw */ }
106
+ }
107
+ await iobrokerHandler.subscribeState(signalId, (_id, state) => {
79
108
  this.#checkAndApply(element, visibilityConfig, state?.val);
80
109
  });
81
110
  }