iobroker.mywebui 1.42.40 → 1.42.41

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.40",
4
+ "version": "1.42.41",
5
5
  "titleLang": {
6
6
  "en": "mywebui",
7
7
  "de": "mywebui",
@@ -29,6 +29,13 @@
29
29
  "zh-cn": "使用万维网传送器的高锰用户接口"
30
30
  },
31
31
  "news": {
32
+ "1.42.41": {
33
+ "en": "improvement: dynamic properties now work on Lit/package widgets at runtime too (accessors + -changed events applied by ScreenViewer); events tab lists -changed events of dynamic properties; added webui-demo-widget sample package",
34
+ "az": "təkmilləşdirmə: dinamik property-lər artıq runtime-da Lit/package widget-lərdə də işləyir (accessor-lar + -changed event-ləri ScreenViewer tərəfindən tətbiq olunur); events tabı dinamik property-lərin -changed event-lərini göstərir; webui-demo-widget nümunə paketi əlavə olundu",
35
+ "tr": "iyileştirme: dinamik property'ler artık runtime'da Lit/package widget'larda da çalışıyor (accessor'lar + -changed event'leri ScreenViewer tarafından uygulanıyor); events sekmesi dinamik property'lerin -changed event'lerini listeliyor; webui-demo-widget örnek paketi eklendi",
36
+ "ru": "улучшение: динамические свойства теперь работают и на Lit/package виджетах во время выполнения (аксессоры + события -changed применяются ScreenViewer); вкладка events показывает события -changed динамических свойств; добавлен пример пакета webui-demo-widget",
37
+ "de": "Verbesserung: dynamische Properties funktionieren zur Laufzeit jetzt auch bei Lit/Package-Widgets (Accessoren + -changed-Events durch ScreenViewer); Events-Tab listet -changed-Events dynamischer Properties; webui-demo-widget Beispielpaket hinzugefügt"
38
+ },
32
39
  "1.42.40": {
33
40
  "en": "feature: per-instance dynamic properties for custom controls (add/edit name, type, default via properties tab) and extended Lit widget property support (Array/Object/converter types, webuiProperties metadata for signal/color/screen/enum editors)",
34
41
  "az": "yenilik: custom control-lar üçün instance-əsaslı dinamik property-lər (properties tabından ad, tip, default əlavə/redaktə) və Lit widget-lər üçün genişləndirilmiş property dəstəyi (Array/Object/converter tipləri, signal/color/screen/enum editorları üçün webuiProperties metadata)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.mywebui",
3
- "version": "1.42.40",
3
+ "version": "1.42.41",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413 with 3D Editor",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -3,6 +3,7 @@ import { iobrokerHandler } from "../common/IobrokerHandler.js";
3
3
  import { PropertiesHelper } from "@gokturk413/web-component-designer/dist/elements/services/propertiesService/services/PropertiesHelper.js";
4
4
  import { visibilityService } from "./VisibilityService.js";
5
5
  import { scanAndApplyAnimations, scanAndApplyEffects, cleanupAnimations, cleanupEffects } from "./AnimationService.js";
6
+ import { applyDynamicProperties, applyDynamicPropertiesToTree } from "./DynamicElementProperties.js";
6
7
  export const webuiCustomControlPrefix = 'webui-';
7
8
  export const webuiCustomControlSymbol = Symbol('webuiCustomControlSymbol');
8
9
  export class BaseCustomControl extends BaseCustomWebComponentConstructorAppend {
@@ -109,51 +110,11 @@ export class BaseCustomControl extends BaseCustomWebComponentConstructorAppend {
109
110
  }
110
111
  // defines accessors for the per-instance dynamic properties declared in the
111
112
  // 'dynamic-property-defs' attribute: [ { "name": "kamran", "type": "string", "default": "x" }, ... ]
112
- // so they behave like normal control properties (bindings refresh + changed events)
113
+ // so they behave like normal control properties (bindings refresh + changed events).
114
+ // also applies dynamic properties to elements inside the control template (e.g. Lit widgets)
113
115
  _setupDynamicProperties() {
114
- let defs;
115
- try {
116
- const v = this.getAttribute('dynamic-property-defs');
117
- if (!v)
118
- return;
119
- defs = JSON.parse(v);
120
- }
121
- catch (e) {
122
- console.warn('invalid dynamic-property-defs attribute', e);
123
- return;
124
- }
125
- if (!Array.isArray(defs))
126
- return;
127
- for (const def of defs) {
128
- const name = def?.name;
129
- if (!name)
130
- continue;
131
- if (!Object.getOwnPropertyDescriptor(this, name)) {
132
- Object.defineProperty(this, name, {
133
- get() {
134
- return this['_' + name];
135
- },
136
- set(newValue) {
137
- if (this['_' + name] !== newValue && (!Number.isNaN(this['_' + name]) || !Number.isNaN(newValue))) {
138
- this['_' + name] = newValue;
139
- this._bindingsRefresh(name);
140
- this.dispatchEvent(new CustomEvent(PropertiesHelper.camelToDashCase(name) + '-changed', { detail: { newValue } }));
141
- }
142
- },
143
- enumerable: true,
144
- configurable: true,
145
- });
146
- }
147
- const attr = this.getAttribute(PropertiesHelper.camelToDashCase(name));
148
- let value = attr ?? def.default;
149
- if (value != null) {
150
- if (def.type === 'number')
151
- value = parseFloat(value);
152
- else if (def.type === 'boolean')
153
- value = value === '' || value === true || value === 'true';
154
- this['_' + name] = value;
155
- }
156
- }
116
+ applyDynamicProperties(this);
117
+ applyDynamicPropertiesToTree(this.shadowRoot);
157
118
  }
158
119
  _assignEvent(event, callback) {
159
120
  const arrayEl = [event, callback];
@@ -0,0 +1,97 @@
1
+ import { PropertiesHelper } from "@gokturk413/web-component-designer/dist/elements/services/propertiesService/services/PropertiesHelper.js";
2
+
3
+ // runtime support for per-instance dynamic properties (any element, incl. Lit/package widgets):
4
+ // reads the 'dynamic-property-defs' attribute and defines accessors on the instance so the
5
+ // properties dispatch '<name>-changed' events and refresh webui bindings on change.
6
+ export const dynamicDefsAttributeName = 'dynamic-property-defs';
7
+
8
+ export function parseDynamicDefs(element) {
9
+ try {
10
+ const v = element.getAttribute(dynamicDefsAttributeName);
11
+ if (v) {
12
+ const parsed = JSON.parse(v);
13
+ if (Array.isArray(parsed))
14
+ return parsed.filter(x => x && x.name);
15
+ }
16
+ }
17
+ catch (e) {
18
+ console.warn('invalid ' + dynamicDefsAttributeName + ' attribute', e, element);
19
+ }
20
+ return [];
21
+ }
22
+
23
+ function findPrototypeAccessor(element, name) {
24
+ let proto = Object.getPrototypeOf(element);
25
+ while (proto && proto !== HTMLElement.prototype) {
26
+ const desc = Object.getOwnPropertyDescriptor(proto, name);
27
+ if (desc)
28
+ return desc;
29
+ proto = Object.getPrototypeOf(proto);
30
+ }
31
+ return null;
32
+ }
33
+
34
+ export function applyDynamicProperties(element) {
35
+ const defs = parseDynamicDefs(element);
36
+ for (const def of defs) {
37
+ const name = def.name;
38
+ if (Object.getOwnPropertyDescriptor(element, name))
39
+ continue;
40
+ // if the element already has an accessor for this name (e.g. a Lit reactive
41
+ // property), route values through it so the widget keeps reacting, but still
42
+ // dispatch the '-changed' event webui bindings listen to
43
+ const protoDesc = findPrototypeAccessor(element, name);
44
+ if (protoDesc && (protoDesc.get || protoDesc.set)) {
45
+ Object.defineProperty(element, name, {
46
+ get() {
47
+ return protoDesc.get ? protoDesc.get.call(this) : undefined;
48
+ },
49
+ set(newValue) {
50
+ const oldValue = protoDesc.get ? protoDesc.get.call(this) : undefined;
51
+ if (oldValue !== newValue) {
52
+ protoDesc.set?.call(this, newValue);
53
+ this._bindingsRefresh?.(name);
54
+ this.dispatchEvent(new CustomEvent(PropertiesHelper.camelToDashCase(name) + '-changed', { detail: { newValue } }));
55
+ }
56
+ },
57
+ enumerable: true,
58
+ configurable: true,
59
+ });
60
+ }
61
+ else {
62
+ Object.defineProperty(element, name, {
63
+ get() {
64
+ return this['_' + name];
65
+ },
66
+ set(newValue) {
67
+ if (this['_' + name] !== newValue && (!Number.isNaN(this['_' + name]) || !Number.isNaN(newValue))) {
68
+ this['_' + name] = newValue;
69
+ this._bindingsRefresh?.(name);
70
+ this.dispatchEvent(new CustomEvent(PropertiesHelper.camelToDashCase(name) + '-changed', { detail: { newValue } }));
71
+ }
72
+ },
73
+ enumerable: true,
74
+ configurable: true,
75
+ });
76
+ }
77
+ const attr = element.getAttribute(PropertiesHelper.camelToDashCase(name));
78
+ let value = attr ?? def.default;
79
+ if (value != null) {
80
+ if (def.type === 'number')
81
+ value = parseFloat(value);
82
+ else if (def.type === 'boolean')
83
+ value = value === '' || value === true || value === 'true';
84
+ if (protoDesc)
85
+ element[name] = value;
86
+ else
87
+ element['_' + name] = value;
88
+ }
89
+ }
90
+ }
91
+
92
+ export function applyDynamicPropertiesToTree(root) {
93
+ if (root instanceof Element && root.hasAttribute(dynamicDefsAttributeName))
94
+ applyDynamicProperties(root);
95
+ for (const el of root.querySelectorAll('[' + dynamicDefsAttributeName + ']'))
96
+ applyDynamicProperties(el);
97
+ }
@@ -7,6 +7,7 @@ import { isFirefox } from "@gokturk413/web-component-designer/dist/elements/help
7
7
  import { PropertiesHelper } from "@gokturk413/web-component-designer/dist/elements/services/propertiesService/services/PropertiesHelper.js";
8
8
  import { visibilityService } from "./VisibilityService.js";
9
9
  import { scanAndApplyAnimations, scanAndApplyEffects, cleanupAnimations, cleanupEffects, ensureGSAP } from "./AnimationService.js";
10
+ import { applyDynamicPropertiesToTree } from "./DynamicElementProperties.js";
10
11
  window.ensureGSAP = ensureGSAP;
11
12
  let ScreenViewer = class ScreenViewer extends BaseCustomWebComponentConstructorAppend {
12
13
  static { ScreenViewer_1 = this; }
@@ -313,6 +314,8 @@ let ScreenViewer = class ScreenViewer extends BaseCustomWebComponentConstructorA
313
314
  get() { return el.style.pointerEvents === 'none'; }
314
315
  });
315
316
  }
317
+ // dynamic per-instance properties (incl. Lit/package widgets) must exist before bindings
318
+ applyDynamicPropertiesToTree(this._rootShadow);
316
319
  const res = window.appShell.bindingsHelper.applyAllBindings(this._rootShadow, this.relativeSignalsPath, this);
317
320
  if (this._iobBindings)
318
321
  this._iobBindings.push(...res);
@@ -1,17 +1,22 @@
1
1
  import { EventsService, PropertiesHelper } from "@gokturk413/web-component-designer";
2
2
  import { BaseCustomControl, webuiCustomControlSymbol } from "../runtime/CustomControls.js";
3
+ import { readDynamicDefs } from "./DynamicPropertiesHelper.js";
3
4
  export class IobrokerWebuiCustomControlEventsService {
4
5
  isHandledElementFromEventsService(designItem) {
5
- return designItem.element instanceof BaseCustomControl;
6
+ return designItem.element instanceof BaseCustomControl || designItem.element.hasAttribute?.('dynamic-property-defs');
6
7
  }
7
8
  getPossibleEvents(designItem) {
8
9
  const evt = [];
9
- let control = designItem.element.constructor[webuiCustomControlSymbol].control;
10
- for (const pname in control.properties) {
10
+ let control = designItem.element.constructor[webuiCustomControlSymbol]?.control;
11
+ for (const pname in control?.properties) {
11
12
  if (control.properties[pname].internal)
12
13
  continue;
13
14
  evt.push({ name: PropertiesHelper.camelToDashCase(pname) + '-changed' });
14
15
  }
16
+ // changed events of the per-instance dynamic properties (dynamic-property-defs attribute)
17
+ for (const def of readDynamicDefs(designItem.element)) {
18
+ evt.push({ name: PropertiesHelper.camelToDashCase(def.name) + '-changed' });
19
+ }
15
20
  return [...evt, ...EventsService._simpleMouseEvents, ...EventsService._pointerEvents, ...EventsService._allElements, ...EventsService._focusableEvents];
16
21
  }
17
22
  getEvent(designItem, name) {