neo.mjs 5.15.1 → 5.15.3

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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.15.1'
23
+ * @member {String} version='5.15.3'
24
24
  */
25
- version: '5.15.1'
25
+ version: '5.15.3'
26
26
  }
27
27
 
28
28
  /**
@@ -45,7 +45,7 @@ class PreviewList extends List {
45
45
  });
46
46
 
47
47
  if (!silent) {
48
- me.promiseVdomUpdate().then(() => {
48
+ me.promiseUpdate().then(() => {
49
49
  me.fire('createItems');
50
50
  });
51
51
  }
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.15.1'
23
+ * @member {String} version='5.15.3'
24
24
  */
25
- version: '5.15.1'
25
+ version: '5.15.3'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "5.15.1",
3
+ "version": "5.15.3",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -245,12 +245,12 @@ const DefaultConfig = {
245
245
  useVdomWorker: true,
246
246
  /**
247
247
  * buildScripts/injectPackageVersion.mjs will update this value
248
- * @default '5.15.1'
248
+ * @default '5.15.3'
249
249
  * @memberOf! module:Neo
250
250
  * @name config.version
251
251
  * @type String
252
252
  */
253
- version: '5.15.1'
253
+ version: '5.15.3'
254
254
  };
255
255
 
256
256
  Object.assign(DefaultConfig, {
package/src/Neo.mjs CHANGED
@@ -645,7 +645,10 @@ function autoGenerateGetSet(proto, key) {
645
645
  me[_key] = value;
646
646
  }
647
647
 
648
- if (!Neo.isEqual(value, oldValue)) {
648
+ if (
649
+ (key === 'vnode' && value !== oldValue) || // vnode trees can be huge, avoid a deep comparison
650
+ !Neo.isEqual(value, oldValue)
651
+ ) {
649
652
  me[afterSet]?.(value, oldValue);
650
653
  me.afterSetConfig?.(key, value, oldValue);
651
654
  }
@@ -261,7 +261,7 @@ class MainContainer extends Container {
261
261
  if (value) {
262
262
  delete sideBar.vdom.removeDom;
263
263
 
264
- me.promiseVdomUpdate().then(() => {
264
+ me.promiseUpdate().then(() => {
265
265
  sideBar.mounted = true;
266
266
 
267
267
  setTimeout(() => {
@@ -274,7 +274,7 @@ class MainContainer extends Container {
274
274
  sideBar._style = style; // silent update
275
275
  sideBar._vdom.style = style; // silent update
276
276
 
277
- me.promiseVdomUpdate().then(() => {
277
+ me.promiseUpdate().then(() => {
278
278
  setTimeout(() => {
279
279
  sideBar.vdom.removeDom = true;
280
280
  sideBar.update();
@@ -57,7 +57,7 @@ class SettingsContainer extends Container {
57
57
  me._style = style; // silent update
58
58
  me._vdom.style = style; // silent update
59
59
 
60
- Neo.getComponent(me.parentId).promiseVdomUpdate().then(() => {
60
+ Neo.getComponent(me.parentId).promiseUpdate().then(() => {
61
61
  setTimeout(() => {
62
62
  me.collapsed = true;
63
63
 
@@ -145,7 +145,7 @@ class SettingsContainer extends Container {
145
145
 
146
146
  delete me.vdom.removeDom;
147
147
 
148
- Neo.getComponent(me.parentId).promiseVdomUpdate().then(() => {
148
+ Neo.getComponent(me.parentId).promiseUpdate().then(() => {
149
149
  me.collapsed = false;
150
150
  me.mounted = true;
151
151
 
@@ -512,7 +512,7 @@ class YearComponent extends Component {
512
512
  vdom.cn[1].cn[0].cn[scrollFromTop ? 'unshift' : 'push'](vdom.cn[0]);
513
513
  vdom.cn.splice(0, 1);
514
514
 
515
- me.promiseVdomUpdate(vdom).then(() => {
515
+ me.promiseUpdate(vdom).then(() => {
516
516
  y = scrollFromTop ? -data.height : 0;
517
517
  vdom.cn[0].cn[0].style.transform = `translateY(${y}px)`;
518
518
  me.update();
@@ -783,7 +783,7 @@ class YearComponent extends Component {
783
783
 
784
784
  me.isUpdating = true;
785
785
 
786
- me.promiseVdomUpdate(me.vdom).then(() => {
786
+ me.promiseUpdate(me.vdom).then(() => {
787
787
  me.isUpdating = false;
788
788
  });
789
789
  }
@@ -689,7 +689,7 @@ class Component extends BaseComponent {
689
689
  week.header && container.cn.unshift(week.header);
690
690
  }
691
691
 
692
- me.promiseVdomUpdate(me.vdom).then(() => {
692
+ me.promiseUpdate(me.vdom).then(() => {
693
693
  Neo.main.DomAccess.scrollTo({
694
694
  direction: 'top',
695
695
  id : me.vdom.cn[1].id,
@@ -805,7 +805,7 @@ class Component extends BaseComponent {
805
805
  if (scrollValue) {
806
806
  me.isUpdating = true;
807
807
 
808
- me.promiseVdomUpdate().then(() => {
808
+ me.promiseUpdate().then(() => {
809
809
  Neo.main.DomAccess.scrollBy({
810
810
  direction: 'left',
811
811
  id : me.getScrollContainer().id,
@@ -313,6 +313,11 @@ class Base extends CoreBase {
313
313
  */
314
314
  childUpdateCache = []
315
315
 
316
+ /**
317
+ * @member {Function[]} resolveUpdateCache=[]
318
+ */
319
+ resolveUpdateCache = []
320
+
316
321
  /**
317
322
  * Apply component based listeners
318
323
  * @member {Object} listeners={}
@@ -635,6 +640,8 @@ class Base extends CoreBase {
635
640
  }, 100)
636
641
  }
637
642
 
643
+ me.doResolveUpdateCache();
644
+
638
645
  me.fire('mounted', me.id)
639
646
  }
640
647
  }
@@ -709,45 +716,7 @@ class Base extends CoreBase {
709
716
  * @protected
710
717
  */
711
718
  afterSetVdom(value, oldValue) {
712
- let me = this,
713
- app = Neo.apps[me.appName],
714
- vdom = value,
715
- listenerId;
716
-
717
- // It is important to keep the vdom tree stable to ensure that containers do not lose the references to their
718
- // child vdom trees. The if case should not happen, but in case it does, keeping the reference and merging
719
- // the content over seems to be the best strategy
720
- if (me._vdom !== vdom) {
721
- Logger.warn('vdom got replaced for: ' + me.id + '. Copying the content into the reference holder object');
722
-
723
- Object.keys(me._vdom).forEach(key => {
724
- delete me._vdom[key]
725
- });
726
-
727
- vdom = Object.assign(me._vdom, vdom)
728
- }
729
-
730
- if (!me.needsParentUpdate()) {
731
- if (me.silentVdomUpdate) {
732
- me.needsVdomUpdate = true
733
- } else {
734
- if (!me.mounted && me.isConstructed && !me.hasRenderingListener && app?.rendering === true) {
735
- me.hasRenderingListener = true;
736
-
737
- listenerId = app.on('mounted', () => {
738
- app.un('mounted', listenerId);
739
-
740
- setTimeout(() => {
741
- me.vnode && me.updateVdom(me.vdom, me.vnode)
742
- }, 50)
743
- });
744
- } else if (me.mounted && me.vnode && !me.isParentVdomUpdating()) {
745
- me.updateVdom(vdom, me.vnode)
746
- }
747
- }
748
- }
749
-
750
- me.hasUnmountedVdomChanges = !me.mounted && me.hasBeenMounted
719
+ this.updateVdom(value)
751
720
  }
752
721
 
753
722
  /**
@@ -1097,6 +1066,14 @@ class Base extends CoreBase {
1097
1066
  super.destroy()
1098
1067
  }
1099
1068
 
1069
+ /**
1070
+ * Triggers all stored resolve() callbacks
1071
+ */
1072
+ doResolveUpdateCache() {
1073
+ this.resolveUpdateCache.forEach(item => item());
1074
+ this.resolveUpdateCache = [];
1075
+ }
1076
+
1100
1077
  /**
1101
1078
  * Convenience shortcut for Neo.manager.Component.down
1102
1079
  * @param {Object|String} config
@@ -1107,6 +1084,55 @@ class Base extends CoreBase {
1107
1084
  return ComponentManager.down(this, config, returnFirstMatch)
1108
1085
  }
1109
1086
 
1087
+ /**
1088
+ * Internal method to send update requests to the vdom worker
1089
+ * @param {Object} vdom
1090
+ * @param {Neo.vdom.VNode} vnode
1091
+ * @param {function} [resolve] used by promiseUpdate()
1092
+ * @param {function} [reject] used by promiseUpdate()
1093
+ * @private
1094
+ */
1095
+ #executeVdomUpdate(vdom, vnode, resolve, reject) {
1096
+ let me = this,
1097
+ opts = {vdom, vnode},
1098
+ deltas;
1099
+
1100
+ me.isVdomUpdating = true;
1101
+
1102
+ // we can not set the config directly => it could already be false,
1103
+ // and we still want to pass it further into subtrees
1104
+ me._needsVdomUpdate = false;
1105
+ me.afterSetNeedsVdomUpdate?.(false, true)
1106
+
1107
+ if (Neo.currentWorker.isSharedWorker) {
1108
+ opts.appName = me.appName
1109
+ }
1110
+
1111
+ Neo.vdom.Helper.update(opts).catch(err => {
1112
+ console.log('Error attempting to update component dom', err, me);
1113
+ me.isVdomUpdating = false;
1114
+
1115
+ reject?.()
1116
+ }).then(data => {
1117
+ // checking if the component got destroyed before the update cycle is done
1118
+ if (me.id) {
1119
+ // console.log('Component vnode updated', data);
1120
+ me.vnode = data.vnode;
1121
+ me.isVdomUpdating = false;
1122
+
1123
+ deltas = data.deltas;
1124
+
1125
+ if (!Neo.config.useVdomWorker && deltas.length > 0) {
1126
+ Neo.applyDeltas(me.appName, deltas).then(() => {
1127
+ me.resolveVdomUpdate(resolve)
1128
+ })
1129
+ } else {
1130
+ me.resolveVdomUpdate(resolve)
1131
+ }
1132
+ }
1133
+ })
1134
+ }
1135
+
1110
1136
  /**
1111
1137
  * Calls focus() on the top level DOM node of this component or on a given node via id
1112
1138
  * @param {String} id=this.id
@@ -1382,11 +1408,13 @@ class Base extends CoreBase {
1382
1408
  }
1383
1409
 
1384
1410
  /**
1385
- * Checks for vdom updates inside the parent chain and if found, registers the component for a vdom update once done
1411
+ * Checks for vdom updates inside the parent chain and if found.
1412
+ * Registers the component for a vdom update once done.
1386
1413
  * @param {String} parentId=this.parentId
1414
+ * @param {Function} [resolve] gets passed by updateVdom()
1387
1415
  * @returns {Boolean}
1388
1416
  */
1389
- isParentVdomUpdating(parentId=this.parentId) {
1417
+ isParentVdomUpdating(parentId=this.parentId, resolve) {
1390
1418
  if (parentId !== 'document.body') {
1391
1419
  let me = this,
1392
1420
  parent = Neo.getComponent(parentId);
@@ -1398,6 +1426,10 @@ class Base extends CoreBase {
1398
1426
  }
1399
1427
 
1400
1428
  NeoArray.add(parent.childUpdateCache, me.id);
1429
+
1430
+ // Adding the resolve fn to its own cache, since the parent will trigger
1431
+ // a new update() directly on this cmp
1432
+ resolve && me.resolveUpdateCache.push(resolve)
1401
1433
  return true
1402
1434
  } else {
1403
1435
  return me.isParentVdomUpdating(parent.parentId)
@@ -1489,15 +1521,19 @@ class Base extends CoreBase {
1489
1521
  /**
1490
1522
  * Checks the needsVdomUpdate config inside the parent tree
1491
1523
  * @param {String} parentId=this.parentId
1524
+ * @param {Function} [resolve] gets passed by updateVdom()
1492
1525
  * @returns {Boolean}
1493
1526
  */
1494
- needsParentUpdate(parentId=this.parentId) {
1527
+ needsParentUpdate(parentId=this.parentId, resolve) {
1495
1528
  if (parentId !== 'document.body') {
1496
1529
  let me = this,
1497
1530
  parent = Neo.getComponent(parentId);
1498
1531
 
1499
1532
  if (parent) {
1500
1533
  if (parent.needsVdomUpdate) {
1534
+ parent.resolveUpdateCache.push(...me.resolveUpdateCache);
1535
+ resolve && parent.resolveUpdateCache.push(resolve);
1536
+ me.resolveUpdateCache = [];
1501
1537
  return true
1502
1538
  } else {
1503
1539
  return me.needsParentUpdate(parent.parentId)
@@ -1596,35 +1632,9 @@ class Base extends CoreBase {
1596
1632
  * @param {Neo.vdom.VNode} [vnode= this.vnode]
1597
1633
  * @returns {Promise<any>}
1598
1634
  */
1599
- promiseVdomUpdate(vdom=this.vdom, vnode=this.vnode) {
1600
- let me = this,
1601
- _vdom = me.vdom;
1602
-
1603
- // todo: updateVdom() should handle this
1604
- // It is important to keep the vdom tree stable to ensure that containers do not lose the references to their
1605
- // child vdom trees. The if case should not happen, but in case it does, keeping the reference and merging
1606
- // the content over seems to be the best strategy
1607
- if (_vdom !== vdom) {
1608
- Logger.warn('vdom got replaced for: ' + me.id + '. Copying the content into the reference holder object');
1609
-
1610
- Object.keys(_vdom).forEach(key => {
1611
- delete _vdom[key];
1612
- });
1613
-
1614
- vdom = Object.assign(me._vdom, vdom)
1615
- }
1616
-
1617
- if (me.silentVdomUpdate) {
1618
- return Promise.resolve()
1619
- }
1620
-
1635
+ promiseUpdate(vdom=this.vdom, vnode=this.vnode) {
1621
1636
  return new Promise((resolve, reject) => {
1622
- if (me.mounted && me.vnode) {
1623
- me.updateVdom(vdom, vnode, resolve, reject)
1624
- } else {
1625
- me.update();
1626
- resolve()
1627
- }
1637
+ this.updateVdom(vdom, vnode, resolve, reject)
1628
1638
  })
1629
1639
  }
1630
1640
 
@@ -1716,6 +1726,9 @@ class Base extends CoreBase {
1716
1726
 
1717
1727
  delete me.vdom.removeDom;
1718
1728
 
1729
+ me._needsVdomUpdate = false;
1730
+ me.afterSetNeedsVdomUpdate?.(false, true)
1731
+
1719
1732
  Neo.vdom.Helper.create({
1720
1733
  appName : me.appName,
1721
1734
  autoMount,
@@ -1739,11 +1752,14 @@ class Base extends CoreBase {
1739
1752
  resolveVdomUpdate(resolve) {
1740
1753
  let me = this;
1741
1754
 
1755
+ me.doResolveUpdateCache();
1756
+
1742
1757
  resolve?.();
1743
1758
 
1744
1759
  if (me.needsVdomUpdate) {
1745
1760
  me.childUpdateCache = []; // if a new update is scheduled, we can clear the cache => these updates are included
1746
- me.vdom = me.vdom // trigger the next update cycle
1761
+
1762
+ me.update()
1747
1763
  } else {
1748
1764
  [...me.childUpdateCache].forEach(id => {
1749
1765
  Neo.getComponent(id)?.update();
@@ -1776,7 +1792,7 @@ class Base extends CoreBase {
1776
1792
  return Promise.resolve()
1777
1793
  }
1778
1794
 
1779
- return me.promiseVdomUpdate()
1795
+ return me.promiseUpdate()
1780
1796
  }
1781
1797
  }
1782
1798
 
@@ -1975,11 +1991,12 @@ class Base extends CoreBase {
1975
1991
  updateStyle(value, oldValue, id=this.id) {
1976
1992
  let me = this,
1977
1993
  delta = Style.compareStyles(value, oldValue),
1978
- vdom = VDomUtil.findVdomChild(me.vdom, id),
1979
- vnode = me.vnode && VNodeUtil.findChildVnode(me.vnode, id),
1980
- opts, vnodeStyle;
1994
+ opts, vdom, vnode, vnodeStyle;
1981
1995
 
1982
1996
  if (delta) {
1997
+ vdom = VDomUtil.findVdomChild(me.vdom, id);
1998
+ vnode = me.vnode && VNodeUtil.findChildVnode(me.vnode, id);
1999
+
1983
2000
  if (!me.hasUnmountedVdomChanges) {
1984
2001
  me.hasUnmountedVdomChanges = !me.mounted && me.hasBeenMounted
1985
2002
  }
@@ -2018,55 +2035,65 @@ class Base extends CoreBase {
2018
2035
 
2019
2036
  /**
2020
2037
  * Gets called after the vdom config gets changed in case the component is already mounted (delta updates).
2021
- * @param {Object} vdom
2022
- * @param {Neo.vdom.VNode} vnode
2023
- * @param {function} [resolve] used by promiseVdomUpdate()
2024
- * @param {function} [reject] used by promiseVdomUpdate()
2038
+ * @param {Object} vdom=this.vdom
2039
+ * @param {Neo.vdom.VNode} vnode=this.vnode
2040
+ * @param {function} [resolve] used by promiseUpdate()
2041
+ * @param {function} [reject] used by promiseUpdate()
2025
2042
  * @protected
2026
2043
  */
2027
- updateVdom(vdom, vnode, resolve, reject) {
2028
- let me = this,
2029
- deltas, opts;
2044
+ updateVdom(vdom=this.vdom, vnode=this.vnode, resolve, reject) {
2045
+ let me = this,
2046
+ app = Neo.apps[me.appName],
2047
+ mounted = me.mounted,
2048
+ listenerId;
2030
2049
 
2031
- // console.log('updateVdom', me.id, Neo.clone(vdom, true), Neo.clone(vnode, true));
2032
- // console.log('updateVdom', me.id, me.isVdomUpdating);
2050
+ // It is important to keep the vdom tree stable to ensure that containers do not lose the references to their
2051
+ // child vdom trees. The if case should not happen, but in case it does, keeping the reference and merging
2052
+ // the content over seems to be the best strategy
2053
+ if (me._vdom !== vdom) {
2054
+ Logger.warn('vdom got replaced for: ' + me.id + '. Copying the content into the reference holder object');
2055
+
2056
+ Object.keys(me._vdom).forEach(key => {
2057
+ delete me._vdom[key]
2058
+ });
2033
2059
 
2034
- if (me.isVdomUpdating) {
2060
+ vdom = Object.assign(me._vdom, vdom)
2061
+ }
2062
+
2063
+ if (resolve && me.isVdomUpdating) {
2064
+ me.resolveUpdateCache.push(resolve)
2065
+ }
2066
+
2067
+ if (me.isVdomUpdating || me.silentVdomUpdate) {
2035
2068
  me.needsVdomUpdate = true
2036
2069
  } else {
2037
- me.isVdomUpdating = true;
2038
- me.needsVdomUpdate = false;
2070
+ if (!mounted && me.isConstructed && !me.hasRenderingListener && app?.rendering === true) {
2071
+ me.hasRenderingListener = true;
2039
2072
 
2040
- opts = { vdom, vnode };
2073
+ listenerId = app.on('mounted', () => {
2074
+ app.un('mounted', listenerId);
2041
2075
 
2042
- if (Neo.currentWorker.isSharedWorker) {
2043
- opts.appName = me.appName
2044
- }
2045
-
2046
- Neo.vdom.Helper.update(opts).catch(err => {
2047
- console.log('Error attempting to update component dom', err, me);
2048
- me.isVdomUpdating = false;
2076
+ me.timeout(50).then(() => {
2077
+ me.vnode && me.updateVdom(me.vdom, me.vnode, resolve, reject)
2078
+ })
2079
+ })
2080
+ } else {
2081
+ if (resolve && (!mounted || !vnode)) {
2082
+ me.resolveUpdateCache.push(resolve)
2083
+ }
2049
2084
 
2050
- reject?.()
2051
- }).then(data => {
2052
- // checking if the component got destroyed before the update cycle is done
2053
- if (me.id) {
2054
- // console.log('Component vnode updated', data);
2055
- me.vnode = data.vnode;
2056
- me.isVdomUpdating = false;
2057
-
2058
- deltas = data.deltas;
2059
-
2060
- if (!Neo.config.useVdomWorker && deltas.length > 0) {
2061
- Neo.applyDeltas(me.appName, deltas).then(() => {
2062
- me.resolveVdomUpdate(resolve)
2063
- })
2064
- } else {
2065
- me.resolveVdomUpdate(resolve)
2066
- }
2085
+ if (
2086
+ mounted
2087
+ && vnode
2088
+ && !me.needsParentUpdate(me.parentId, resolve)
2089
+ && !me.isParentVdomUpdating(me.parentId, resolve)
2090
+ ) {
2091
+ me.#executeVdomUpdate(vdom, vnode, resolve, reject)
2067
2092
  }
2068
- })
2093
+ }
2069
2094
  }
2095
+
2096
+ me.hasUnmountedVdomChanges = !mounted && me.hasBeenMounted
2070
2097
  }
2071
2098
  }
2072
2099
 
@@ -255,7 +255,7 @@ class Circle extends Component {
255
255
  me.createItems(oldValue, true);
256
256
  me.updateItemPositions(true);
257
257
 
258
- me.promiseVdomUpdate().then(() => {
258
+ me.promiseUpdate().then(() => {
259
259
  if (!me.collapsed) {
260
260
  me.updateItemOpacity(1, true, oldValue);
261
261
  me.update();
@@ -720,7 +720,7 @@ class Circle extends Component {
720
720
 
721
721
  me.circleCenterHasTransitionCls = false;
722
722
 
723
- me.promiseVdomUpdate().then(() => {
723
+ me.promiseUpdate().then(() => {
724
724
  me.updateItemAngle(true);
725
725
  circleCenterEl.style.transform = transform;
726
726
  me.update();
@@ -447,7 +447,7 @@ class DateSelector extends Component {
447
447
  vdom.cn[2].cn[0].cn[slideDirection === 'right'? 'unshift' : 'push'](vdom.cn[1]);
448
448
  vdom.cn.splice(1, 1);
449
449
 
450
- me.promiseVdomUpdate().then(() => {
450
+ me.promiseUpdate().then(() => {
451
451
  me.changeMonthTransitionCallback({data: data[0], slideDirection: slideDirection});
452
452
  me.updateHeaderMonthTransitionCallback(headerMonthOpts);
453
453
  me.update();
@@ -533,7 +533,7 @@ class DateSelector extends Component {
533
533
  vdom.cn[2].cn[0].cn[scrollFromTop ? 'unshift' : 'push'](vdom.cn[1]);
534
534
  vdom.cn.splice(1, 1);
535
535
 
536
- me.promiseVdomUpdate(vdom).then(() => {
536
+ me.promiseUpdate(vdom).then(() => {
537
537
  y = scrollFromTop ? -data.height : 0;
538
538
  vdom.cn[1].cn[0].style.transform = `translateY(${y}px)`;
539
539
  me.update();
@@ -844,7 +844,7 @@ class DateSelector extends Component {
844
844
 
845
845
  me.isUpdating = true;
846
846
 
847
- me.promiseVdomUpdate(me.vdom).then(() => {
847
+ me.promiseUpdate(me.vdom).then(() => {
848
848
  me.isUpdating = false;
849
849
  });
850
850
  }
@@ -440,7 +440,7 @@ class Gallery extends Component {
440
440
  itemsRoot.cn.push(vdomItem);
441
441
  }
442
442
 
443
- me.promiseVdomUpdate(vdom).then(() => {
443
+ me.promiseUpdate(vdom).then(() => {
444
444
  me[itemsMounted] = true;
445
445
  });
446
446
  }
@@ -581,7 +581,7 @@ class Helix extends Component {
581
581
 
582
582
  me[lockWheel] = false;
583
583
 
584
- me.promiseVdomUpdate(vdom).then(() => {
584
+ me.promiseUpdate(vdom).then(() => {
585
585
  me[itemsMounted] = true;
586
586
  me.fire('itemsMounted');
587
587
 
@@ -422,7 +422,7 @@ class Base extends Component {
422
422
  }
423
423
 
424
424
  if (!silent) {
425
- me.promiseVdomUpdate().then(() => {
425
+ me.promiseUpdate().then(() => {
426
426
  me.fire('insert', { index, item });
427
427
  });
428
428
  }
@@ -1,6 +1,5 @@
1
1
  import Container from './Base.mjs';
2
2
  import Panel from './Panel.mjs';
3
- import Toolbar from './Toolbar.mjs';
4
3
  import Viewport from './Viewport.mjs';
5
4
 
6
- export {Container, Panel, Toolbar, Viewport};
5
+ export {Container, Panel, Viewport};
@@ -1,4 +1,4 @@
1
- import Socket from './Socket.mjs';
2
- import Xhr from './Xhr.mjs';
1
+ import WebSocket from './WebSocket.mjs';
2
+ import Xhr from './Xhr.mjs';
3
3
 
4
- export {Socket, Xhr};
4
+ export {WebSocket, Xhr};
@@ -197,7 +197,7 @@ class DateField extends Picker {
197
197
  if (me.hidePickerOnSelect) {
198
198
  VDomUtil.removeVdomChild(vdom, me.getPickerId());
199
199
 
200
- me.promiseVdomUpdate().then(data => {
200
+ me.promiseUpdate().then(data => {
201
201
  me.value = opts.value;
202
202
  });
203
203
  } else {
@@ -23,7 +23,7 @@ class Text extends Base {
23
23
  * @protected
24
24
  * @static
25
25
  */
26
- static labelPositions = ['bottom', 'inline', 'left', 'right', 'top']
26
+ static labelPositions = ['bottom', 'inline', 'left', 'right', 'top']
27
27
 
28
28
  static config = {
29
29
  /**
@@ -220,14 +220,18 @@ class Text extends Base {
220
220
  * @member {Object} _vdom
221
221
  */
222
222
  _vdom:
223
- {cn: [
224
- {tag: 'label', cls: [], style: {}},
225
- {tag: 'label', cls: []},
226
- {tag: 'input', cls: ['neo-textfield-input'], flag: 'neo-real-input', style: {}},
227
- {cls: ['neo-textfield-error-wrapper'], removeDom: true, cn: [
228
- {cls: ['neo-textfield-error']}
229
- ]}
230
- ]}
223
+ {
224
+ cn: [
225
+ {tag: 'label', cls: [], style: {}},
226
+ {tag: 'label', cls: []},
227
+ {tag: 'input', cls: ['neo-textfield-input'], flag: 'neo-real-input', style: {}},
228
+ {
229
+ cls: ['neo-textfield-error-wrapper'], removeDom: true, cn: [
230
+ {cls: ['neo-textfield-error']}
231
+ ]
232
+ }
233
+ ]
234
+ }
231
235
  }
232
236
 
233
237
  /**
@@ -246,9 +250,9 @@ class Text extends Base {
246
250
  let me = this;
247
251
 
248
252
  me.addDomListeners([
249
- {input : me.onInputValueChange, scope: me},
250
- {mouseenter: me.onMouseEnter, scope: me},
251
- {mouseleave: me.onMouseLeave, scope: me}
253
+ {input: me.onInputValueChange, scope: me},
254
+ {mouseenter: me.onMouseEnter, scope: me},
255
+ {mouseleave: me.onMouseLeave, scope: me}
252
256
  ]);
253
257
  }
254
258
 
@@ -530,7 +534,7 @@ class Text extends Base {
530
534
  delete me.getCenterBorderEl()?.width;
531
535
  }
532
536
 
533
- me.promiseVdomUpdate().then(() => {
537
+ me.promiseUpdate().then(() => {
534
538
  me.updateCenterBorderElWidth(isEmpty)
535
539
  })
536
540
  } else {
@@ -637,7 +641,7 @@ class Text extends Base {
637
641
  * @protected
638
642
  */
639
643
  afterSetReadOnly(value, oldValue) {
640
- let me = this,
644
+ let me = this,
641
645
  cls = me.cls;
642
646
 
643
647
  NeoArray[value ? 'add' : 'remove'](cls, 'neo-readonly');
@@ -663,7 +667,7 @@ class Text extends Base {
663
667
 
664
668
  me.validate(false);
665
669
  me.changeInputElKey('required', value ? value : null);
666
- me.labelText = me.labelText; // apply the optional text if needed
670
+ me.labelText = me.labelText; // apply the optional text if needed
667
671
 
668
672
  me.silentVdomUpdate = false;
669
673
 
@@ -753,10 +757,10 @@ class Text extends Base {
753
757
  });
754
758
 
755
759
  postTriggers.sort((a, b) => b.weight - a.weight); // DESC
756
- preTriggers .sort((a, b) => a.weight - b.weight); // ASC
760
+ preTriggers.sort((a, b) => a.weight - b.weight); // ASC
757
761
 
758
762
  postTriggers = postTriggers.map(a => a.vdom);
759
- preTriggers = preTriggers .map(a => a.vdom);
763
+ preTriggers = preTriggers.map(a => a.vdom);
760
764
 
761
765
  if (inputEl.tag === 'input') {
762
766
  // wrap the input tag
@@ -774,13 +778,13 @@ class Text extends Base {
774
778
  } else {
775
779
  if (inputEl.tag !== 'input') {
776
780
  // replacing the input wrapper div with the input tag
777
- width = inputEl.width;
778
- vdom.cn[2] = me.getInputEl();
781
+ width = inputEl.width;
782
+ vdom.cn[2] = me.getInputEl();
779
783
  vdom.cn[2].width = width;
780
784
  }
781
785
  }
782
786
 
783
- me.promiseVdomUpdate().then(() => {
787
+ me.promiseUpdate().then(() => {
784
788
  me.updateTriggerVnodes()
785
789
  })
786
790
  }
@@ -807,7 +811,7 @@ class Text extends Base {
807
811
  cls = me.cls;
808
812
 
809
813
  NeoArray[me.hasContent() ? 'add' : 'remove'](cls, 'neo-has-content');
810
- NeoArray[isDirty ? 'add' : 'remove'](cls, 'neo-is-dirty');
814
+ NeoArray[isDirty ? 'add' : 'remove'](cls, 'neo-is-dirty');
811
815
  me.cls = cls;
812
816
 
813
817
  me.silentVdomUpdate = false;
@@ -1242,7 +1246,7 @@ class Text extends Base {
1242
1246
  vnode.vnode.attributes.value = value;
1243
1247
  }
1244
1248
 
1245
- me.value = me.inputValueAdjustor(value)
1249
+ me.value = me.inputValueAdjustor(value)
1246
1250
  }
1247
1251
 
1248
1252
  /**
@@ -1278,7 +1282,7 @@ class Text extends Base {
1278
1282
  * @param {Array} [triggerSource] pass a shallow copy of this.triggers
1279
1283
  * @returns {Boolean} true in case a trigger was found & removed
1280
1284
  */
1281
- removeTrigger(type, silent=false, triggerSource) {
1285
+ removeTrigger(type, silent = false, triggerSource) {
1282
1286
  let me = this,
1283
1287
  hasMatch = false,
1284
1288
  triggers = triggerSource || me.triggers || [],
@@ -1308,7 +1312,7 @@ class Text extends Base {
1308
1312
  * You can optionally pass a new value, which will adjust the originalConfig.value if needed.
1309
1313
  * @param {String|null} [value=null]
1310
1314
  */
1311
- reset(value=null) {
1315
+ reset(value = null) {
1312
1316
  let me = this;
1313
1317
 
1314
1318
  if (me.clearToOriginalValue) {
@@ -1331,7 +1335,7 @@ class Text extends Base {
1331
1335
  * @param {Boolean} [silent=false] true to get the value, but not apply it to the DOM
1332
1336
  * @protected
1333
1337
  */
1334
- updateCenterBorderElWidth(silent=false) {
1338
+ updateCenterBorderElWidth(silent = false) {
1335
1339
  let me = this;
1336
1340
 
1337
1341
  me.mounted && me.getDomRect(me.getCenterBorderEl().id).then(data => {
@@ -1348,7 +1352,7 @@ class Text extends Base {
1348
1352
  @param {String|null} value
1349
1353
  @param {Boolean} silent=false
1350
1354
  */
1351
- updateError(value, silent=false) {
1355
+ updateError(value, silent = false) {
1352
1356
  let me = this,
1353
1357
  cls = me.cls,
1354
1358
  errorNode, errorWrapper;
@@ -1394,9 +1398,9 @@ class Text extends Base {
1394
1398
  * todo: this could be handled by component.Base
1395
1399
  */
1396
1400
  updateTriggerVnodes() {
1397
- let me = this,
1398
- triggerRoot = me.vnode?.childNodes[1],
1399
- childNodes = triggerRoot?.childNodes || [],
1401
+ let me = this,
1402
+ triggerRoot = me.vnode?.childNodes[1],
1403
+ childNodes = triggerRoot?.childNodes || [],
1400
1404
  trigger;
1401
1405
 
1402
1406
  childNodes.forEach(vnode => {
@@ -1415,7 +1419,7 @@ class Text extends Base {
1415
1419
  * @param {Boolean} silent=true
1416
1420
  * @returns {Boolean} Returns true in case there are no client-side errors
1417
1421
  */
1418
- validate(silent=true) {
1422
+ validate(silent = true) {
1419
1423
  let me = this,
1420
1424
  maxLength = me.maxLength,
1421
1425
  minLength = me.minLength,
@@ -1433,30 +1437,28 @@ class Text extends Base {
1433
1437
  me.clean = false;
1434
1438
  }
1435
1439
 
1436
- if (Neo.isFunction(me.validator)) {
1437
- errorText = me.validator(me);
1438
-
1439
- if (errorText !== true) {
1440
- me._error = errorText;
1441
- returnValue = false;
1442
- }
1443
- }
1444
-
1445
1440
  if (isEmpty) {
1446
1441
  if (required) {
1447
- me._error = me.errorTextRequired;
1442
+ me._error = me.errorTextRequired;
1448
1443
  returnValue = false;
1449
1444
  }
1450
1445
  } else {
1451
1446
  if (Neo.isNumber(maxLength) && valueLength > maxLength) {
1452
- me._error = me.errorTextMaxLength(errorParam);
1447
+ me._error = me.errorTextMaxLength(errorParam);
1453
1448
  returnValue = false;
1454
1449
  } else if (Neo.isNumber(minLength) && valueLength < minLength) {
1455
- me._error = me.errorTextMinLength(errorParam);
1450
+ me._error = me.errorTextMinLength(errorParam);
1456
1451
  returnValue = false;
1457
1452
  } else if (inputPattern && !inputPattern.test(value)) {
1458
- me._error = me.errorTextInputPattern(errorParam);
1453
+ me._error = me.errorTextInputPattern(errorParam);
1459
1454
  returnValue = false;
1455
+ } else if (Neo.isFunction(me.validator)) {
1456
+ errorText = me.validator(me);
1457
+
1458
+ if (errorText !== true) {
1459
+ me._error = errorText;
1460
+ returnValue = false;
1461
+ }
1460
1462
  }
1461
1463
  }
1462
1464
 
@@ -13,6 +13,8 @@ class ZipCode extends Text {
13
13
  * @static
14
14
  */
15
15
  static countryCodes = {
16
+ AT: /^\d{4}$/,
17
+ CH: /^\d{4}$/,
16
18
  DE: /^(?!01000|99999)(0[1-9]\d{3}|[1-9]\d{4})$/
17
19
  }
18
20
 
@@ -40,12 +42,12 @@ class ZipCode extends Text {
40
42
  * The data.Model field inside the related country field which provides the country code (e.g. 'DE')
41
43
  * @member {String} countryKeyProperty='id'
42
44
  */
43
- countryKeyProperty: 'id',
45
+ countryKeyProperty: "id",
44
46
  /**
45
47
  * data passes inputPattern, maxLength, minLength & valueLength properties
46
- * @member {Function} errorTextInputPattern=data=>`Not a valid zip code`
48
+ * @member {Function} errorTextInputPattern=data=>'Not a valid zip code'
47
49
  */
48
- errorTextInputPattern: data => `Not a valid zip code`
50
+ errorTextInputPattern: (data) => 'Not a valid zip code'
49
51
  }
50
52
 
51
53
  /**
@@ -59,7 +61,7 @@ class ZipCode extends Text {
59
61
 
60
62
  me.inputPattern = ZipCode.countryCodes[value] || null;
61
63
 
62
- oldValue !== undefined && me.value && !me.clean && me.validate(false);
64
+ oldValue !== undefined && me.value && !me.clean && me.validate(false)
63
65
  }
64
66
 
65
67
  /**
@@ -99,14 +101,14 @@ class ZipCode extends Text {
99
101
  return me.up().getReference(value)
100
102
  }
101
103
 
102
- return value;
104
+ return value
103
105
  }
104
106
 
105
107
  /**
106
108
  * @param {Object} data
107
109
  */
108
110
  onCountryFieldChange(data) {
109
- this.countryCode = data.record?.[this.countryKeyProperty] || null;
111
+ this.countryCode = data.record?.[this.countryKeyProperty] || null
110
112
  }
111
113
  }
112
114
 
package/src/grid/View.mjs CHANGED
@@ -150,7 +150,7 @@ class View extends Component {
150
150
  container.dockLeftMargin = dockLeftMargin;
151
151
  container.dockRightMargin = dockRightMargin;
152
152
 
153
- me.promiseVdomUpdate().then(() => {
153
+ me.promiseUpdate().then(() => {
154
154
  if (selectedRows?.length > 0) {
155
155
  // this logic only works for selection.table.RowModel
156
156
  Neo.main.DomAccess.scrollToTableRow({id: selectedRows[0]});
package/src/list/Base.mjs CHANGED
@@ -485,7 +485,7 @@ class Base extends Component {
485
485
  listItem && vdom.cn.push(listItem);
486
486
  });
487
487
 
488
- !silent && me.promiseVdomUpdate().then(() => {
488
+ !silent && me.promiseUpdate().then(() => {
489
489
  me.fire('createItems');
490
490
  });
491
491
  }
@@ -215,12 +215,14 @@ class DeltaUpdates extends Base {
215
215
  case 'style':
216
216
  if (Neo.isObject(value)) {
217
217
  Object.entries(value).forEach(([key, val]) => {
218
+ let important;
219
+
218
220
  if (Neo.isString(val) && val.includes('!important')) {
219
221
  val = val.replace('!important', '').trim();
220
- node.style.setProperty(Neo.decamel(key), val, 'important');
221
- } else {
222
- node.style[Neo.decamel(key)] = val;
222
+ important = 'important';
223
223
  }
224
+
225
+ node.style.setProperty(Neo.decamel(key), val, important);
224
226
  });
225
227
  }
226
228
  break;
@@ -214,7 +214,7 @@ class View extends Component {
214
214
  container.dockLeftMargin = dockLeftMargin;
215
215
  container.dockRightMargin = dockRightMargin;
216
216
 
217
- me.promiseVdomUpdate().then(() => {
217
+ me.promiseUpdate().then(() => {
218
218
  if (selectedRows?.length > 0) {
219
219
  // this logic only works for selection.table.RowModel
220
220
  Neo.main.DomAccess.scrollToTableRow({id: selectedRows[0]});