iobroker.mywebui 1.37.96 → 1.37.97

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.96",
4
+ "version": "1.37.97",
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.96",
3
+ "version": "1.37.97",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -32,6 +32,62 @@ function findElementAcrossShadows(fromElement, id) {
32
32
  // AnimationService.js is at dist/frontend/runtime/ → ../../vendor/gsap/ = dist/vendor/gsap/
33
33
  const _gsapBase = new URL('../../vendor/gsap/', import.meta.url).href;
34
34
 
35
+ /**
36
+ * Convert circle/ellipse/rect/polyline/polygon to SVG path data string.
37
+ * GSAP MotionPathPlugin only accepts <path> elements — other SVG shapes must be converted.
38
+ */
39
+ function svgShapeToPathData(el) {
40
+ const tag = el.tagName.toLowerCase();
41
+ if (tag === 'circle') {
42
+ const cx = parseFloat(el.getAttribute('cx') || 0);
43
+ const cy = parseFloat(el.getAttribute('cy') || 0);
44
+ const r = parseFloat(el.getAttribute('r') || 0);
45
+ return `M ${cx-r},${cy} A ${r},${r} 0 1,1 ${cx+r},${cy} A ${r},${r} 0 1,1 ${cx-r},${cy} Z`;
46
+ }
47
+ if (tag === 'ellipse') {
48
+ const cx = parseFloat(el.getAttribute('cx') || 0);
49
+ const cy = parseFloat(el.getAttribute('cy') || 0);
50
+ const rx = parseFloat(el.getAttribute('rx') || 0);
51
+ const ry = parseFloat(el.getAttribute('ry') || 0);
52
+ return `M ${cx-rx},${cy} A ${rx},${ry} 0 1,1 ${cx+rx},${cy} A ${rx},${ry} 0 1,1 ${cx-rx},${cy} Z`;
53
+ }
54
+ if (tag === 'rect') {
55
+ const x = parseFloat(el.getAttribute('x') || 0);
56
+ const y = parseFloat(el.getAttribute('y') || 0);
57
+ const w = parseFloat(el.getAttribute('width') || 0);
58
+ const h = parseFloat(el.getAttribute('height') || 0);
59
+ return `M ${x},${y} H ${x+w} V ${y+h} H ${x} Z`;
60
+ }
61
+ if (tag === 'polyline' || tag === 'polygon') {
62
+ const pts = (el.getAttribute('points') || '').trim().split(/[\s,]+/);
63
+ if (pts.length < 2) return null;
64
+ let d = `M ${pts[0]},${pts[1]}`;
65
+ for (let i = 2; i + 1 < pts.length; i += 2) d += ` L ${pts[i]},${pts[i+1]}`;
66
+ if (tag === 'polygon') d += ' Z';
67
+ return d;
68
+ }
69
+ return null;
70
+ }
71
+
72
+ /**
73
+ * Ensure we have a real SVG <path> element for GSAP MotionPathPlugin.
74
+ * If el is already a <path>, returns it directly.
75
+ * Otherwise converts the shape to path data and creates a temporary hidden <path>
76
+ * inside the same <svg>. Caller must store _tempPathEl and remove it on destroy.
77
+ */
78
+ function ensurePathEl(el) {
79
+ if (el.tagName.toLowerCase() === 'path') return { pathEl: el, tempEl: null };
80
+ const d = svgShapeToPathData(el);
81
+ if (!d) return { pathEl: el, tempEl: null };
82
+ const svgParent = el.closest('svg') ?? el.parentElement;
83
+ const tmp = document.createElementNS('http://www.w3.org/2000/svg', 'path');
84
+ tmp.setAttribute('d', d);
85
+ tmp.setAttribute('fill', 'none');
86
+ tmp.style.cssText = 'visibility:hidden;pointer-events:none;';
87
+ svgParent.appendChild(tmp);
88
+ return { pathEl: tmp, tempEl: tmp };
89
+ }
90
+
35
91
  async function ensureGSAP() {
36
92
  if (window.gsap) return window.gsap;
37
93
  if (_gsapLoadPromise) return _gsapLoadPromise;
@@ -440,12 +496,15 @@ class AnimationInstance {
440
496
  const effect = this.cfg.effect;
441
497
 
442
498
  if (effect === 'motionPath' && this.cfg.pathId) {
443
- let pathEl = findElementAcrossShadows(this.element, this.cfg.pathId);
444
- if (!pathEl) { console.warn('[AnimationService] motionPath: path element not found:', this.cfg.pathId); return; }
445
- // If ID is on <svg> container, use the first SVG shape inside it
446
- // GSAP MotionPathPlugin supports path, circle, ellipse, rect, polyline, polygon
447
- if (pathEl.tagName.toLowerCase() === 'svg')
448
- pathEl = pathEl.querySelector('path, circle, ellipse, rect, polyline, polygon') ?? pathEl;
499
+ let found = findElementAcrossShadows(this.element, this.cfg.pathId);
500
+ if (!found) { console.warn('[AnimationService] motionPath: path element not found:', this.cfg.pathId); return; }
501
+ // If ID is on <svg> container, use the first shape inside it
502
+ if (found.tagName.toLowerCase() === 'svg')
503
+ found = found.querySelector('path, circle, ellipse, rect, polyline, polygon') ?? found;
504
+ // GSAP MotionPathPlugin only accepts <path> convert other shapes to a hidden <path>
505
+ if (this._tempPathEl) { this._tempPathEl.remove(); this._tempPathEl = null; }
506
+ const { pathEl, tempEl } = ensurePathEl(found);
507
+ this._tempPathEl = tempEl;
449
508
  this.tween = gsap.to(this.element, {
450
509
  duration: parseFloat(this.cfg.duration) || 1,
451
510
  ease: this.cfg.ease || 'none',
@@ -480,6 +539,7 @@ class AnimationInstance {
480
539
 
481
540
  destroy() {
482
541
  if (this.tween) { this.tween.kill(); this.tween = null; }
542
+ if (this._tempPathEl) { this._tempPathEl.remove(); this._tempPathEl = null; }
483
543
  _cleanupSubs(this._subs);
484
544
  }
485
545
  }