neo.mjs 8.29.0 → 8.31.0

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.
Files changed (37) hide show
  1. package/BACKERS.md +15 -15
  2. package/CONTRIBUTING.md +9 -9
  3. package/apps/ServiceWorker.mjs +2 -2
  4. package/apps/portal/index.html +1 -1
  5. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  6. package/examples/ServiceWorker.mjs +2 -2
  7. package/examples/grid/animatedRowSorting/MainModel.mjs +40 -0
  8. package/examples/grid/animatedRowSorting/MainStore.mjs +36 -0
  9. package/examples/grid/animatedRowSorting/Viewport.mjs +87 -0
  10. package/examples/grid/animatedRowSorting/app.mjs +6 -0
  11. package/examples/grid/animatedRowSorting/index.html +11 -0
  12. package/examples/grid/animatedRowSorting/neo-config.json +8 -0
  13. package/examples/grid/bigData/GridContainer.mjs +3 -2
  14. package/examples/grid/bigData/MainModel.mjs +3 -2
  15. package/examples/grid/bigData/MainStore.mjs +3 -2
  16. package/package.json +3 -3
  17. package/resources/scss/src/component/Progress.scss +1 -1
  18. package/resources/scss/src/grid/column/Progress.scss +34 -0
  19. package/resources/scss/theme-dark/grid/column/Progress.scss +6 -0
  20. package/resources/scss/theme-light/grid/column/Progress.scss +6 -0
  21. package/resources/scss/theme-neo-light/grid/column/Progress.scss +6 -0
  22. package/src/DefaultConfig.mjs +2 -2
  23. package/src/collection/Base.mjs +2 -1
  24. package/src/component/Base.mjs +1 -1
  25. package/src/component/Progress.mjs +26 -5
  26. package/src/data/Store.mjs +12 -9
  27. package/src/grid/Container.mjs +45 -68
  28. package/src/grid/ScrollManager.mjs +1 -1
  29. package/src/grid/View.mjs +81 -1
  30. package/src/grid/column/Component.mjs +50 -8
  31. package/src/grid/column/Progress.mjs +42 -0
  32. package/src/grid/column/_export.mjs +2 -1
  33. package/src/grid/header/Button.mjs +1 -2
  34. package/src/grid/plugin/AnimateRows.mjs +234 -0
  35. package/src/list/plugin/Animate.mjs +16 -7
  36. package/src/vdom/Helper.mjs +1 -1
  37. package/src/worker/Manager.mjs +6 -8
@@ -400,7 +400,7 @@ class Store extends Base {
400
400
  onCollectionMutate(opts) {
401
401
  let me = this;
402
402
 
403
- if (me.configsApplied && !me.isLoading) {
403
+ if (me.isConstructed && !me.isLoading) {
404
404
  me.fire('load', me.items)
405
405
  }
406
406
  }
@@ -411,9 +411,8 @@ class Store extends Base {
411
411
  onCollectionSort() {
412
412
  let me = this;
413
413
 
414
- if (me.configsApplied) {
415
- // console.log('onCollectionSort', me.collection.items);
416
- // me.fire('load', me.items);
414
+ if (me.isConstructed) {
415
+ //me.fire('load', me.items)
417
416
  }
418
417
  }
419
418
 
@@ -426,14 +425,18 @@ class Store extends Base {
426
425
  let me = this;
427
426
 
428
427
  if (me.data) {
429
- me.afterSetData(me.data);
428
+ me.afterSetData(me.data)
430
429
  }
431
430
 
432
- if (me.autoLoad) {
433
- me.timeout(100).then(() => { // todo
431
+ // Being constructed does not mean that related afterSetStore() methods got executed
432
+ // => break the sync flow to ensure potential listeners got applied
433
+ Promise.resolve().then(() => {
434
+ if (me.getCount() > 0) {
435
+ me.fire('load', me.items)
436
+ } else if (me.autoLoad) {
434
437
  me.load()
435
- })
436
- }
438
+ }
439
+ })
437
440
  }
438
441
 
439
442
  /**
@@ -22,7 +22,8 @@ class GridContainer extends BaseContainer {
22
22
  animatedChange: column.AnimatedChange,
23
23
  column : column.Base,
24
24
  component : column.Component,
25
- index : column.Index
25
+ index : column.Index,
26
+ progress : column.Progress
26
27
  }
27
28
  /**
28
29
  * @member {Object} delayable
@@ -321,6 +322,29 @@ class GridContainer extends BaseContainer {
321
322
  }
322
323
  }
323
324
 
325
+ /**
326
+ * Triggered after the store config got changed
327
+ * @param {Number} value
328
+ * @param {Number} oldValue
329
+ * @protected
330
+ */
331
+ afterSetStore(value, oldValue) {
332
+ let me = this,
333
+ listeners = {
334
+ filter: me.onStoreFilter,
335
+ load : me.onStoreLoad,
336
+ scope : me
337
+ };
338
+
339
+ value ?.on(listeners);
340
+ oldValue?.un(listeners);
341
+
342
+ // in case we dynamically change the store, the view needs to get the new reference
343
+ if (me.view) {
344
+ me.view.store = value
345
+ }
346
+ }
347
+
324
348
  /**
325
349
  * Triggered before the columns config gets changed.
326
350
  * @param {Object[]} value
@@ -347,36 +371,13 @@ class GridContainer extends BaseContainer {
347
371
 
348
372
  /**
349
373
  * Triggered before the store config gets changed.
350
- * @param {Neo.data.Store} value
351
- * @param {Neo.data.Store} oldValue
374
+ * @param {Object|Neo.data.Store|null} value
375
+ * @param {Neo.data.Store} oldValue
352
376
  * @protected
353
377
  */
354
378
  beforeSetStore(value, oldValue) {
355
- oldValue?.destroy();
356
-
357
379
  if (value) {
358
- let me = this,
359
-
360
- listeners = {
361
- filter : me.onStoreFilter,
362
- load : me.onStoreLoad,
363
- recordChange: me.onStoreRecordChange,
364
- scope : me
365
- };
366
-
367
- if (value instanceof Store) {
368
- value.on(listeners);
369
- value.getCount() > 0 && me.onStoreLoad(value.items)
370
- } else {
371
- value = ClassSystemUtil.beforeSetInstance(value, Store, {
372
- listeners
373
- })
374
- }
375
-
376
- // in case we dynamically change the store, the view needs to get the new reference
377
- if (me.view) {
378
- me.view.store = value
379
- }
380
+ value = ClassSystemUtil.beforeSetInstance(value, Store)
380
381
  }
381
382
 
382
383
  return value
@@ -475,24 +476,14 @@ class GridContainer extends BaseContainer {
475
476
  })
476
477
  }
477
478
 
478
- /**
479
- * @param {Array} inputData
480
- */
481
- createViewData(inputData) {
482
- let me = this;
483
-
484
- me.getVdomRoot()['aria-rowcount'] = inputData.length + 2; // 1 based & the header row counts as well
485
- me.update();
486
-
487
- me.view.createViewData()
488
- }
489
-
490
479
  /**
491
480
  * @param args
492
481
  */
493
482
  destroy(...args) {
494
483
  let me = this;
495
484
 
485
+ me.store = null; // remove the listeners
486
+
496
487
  me.scrollManager.destroy();
497
488
 
498
489
  me.mounted && Neo.main.addon.ResizeObserver.unregister({
@@ -569,14 +560,14 @@ class GridContainer extends BaseContainer {
569
560
 
570
561
  me.store.sort(opts);
571
562
  me.removeSortingCss(opts.property);
572
- me.onStoreLoad(me.store.items)
563
+ me.view.onStoreLoad()
573
564
  }
574
565
 
575
566
  /**
576
567
  *
577
568
  */
578
569
  onStoreFilter() {
579
- this.onStoreLoad(this.store.items)
570
+ this.updateRowCount()
580
571
  }
581
572
 
582
573
  /**
@@ -586,37 +577,13 @@ class GridContainer extends BaseContainer {
586
577
  onStoreLoad(data) {
587
578
  let me = this;
588
579
 
589
- if (me.rendered) {
590
- me.createViewData(data);
591
-
592
- me.timeout(50).then(() => {
593
- Neo.main.DomAccess.scrollTo({
594
- direction: 'top',
595
- id : me.view.vdom.id,
596
- value : 0
597
- })
598
- })
580
+ me.updateRowCount();
599
581
 
600
- if (me.store.sorters.length < 1) {
601
- me.removeSortingCss()
602
- }
582
+ if (me.store.sorters?.length < 1) {
583
+ me.removeSortingCss()
603
584
  }
604
585
  }
605
586
 
606
- /**
607
- * Gets triggered after changing the value of a record field.
608
- * E.g. myRecord.foo = 'bar';
609
- * @param {Object} opts
610
- * @param {String} opts.field The name of the field which got changed
611
- * @param {Neo.data.Model} opts.model The model instance of the changed record
612
- * @param {*} opts.oldValue
613
- * @param {Object} opts.record
614
- * @param {*} opts.value
615
- */
616
- onStoreRecordChange(opts) {
617
- this.view.onStoreRecordChange(opts)
618
- }
619
-
620
587
  /**
621
588
  * @param {Boolean} silent=false
622
589
  * @returns {Promise<void>}
@@ -700,6 +667,16 @@ class GridContainer extends BaseContainer {
700
667
  })
701
668
  }
702
669
  }
670
+
671
+ /**
672
+ * @param {Boolean} silent=false
673
+ */
674
+ updateRowCount(silent=false) {
675
+ let me = this;
676
+
677
+ this.getVdomRoot()['aria-rowcount'] = me.store.getCount() + 2; // 1 based & the header row counts as well
678
+ !silent && this.update()
679
+ }
703
680
  }
704
681
 
705
682
  export default Neo.setupClass(GridContainer);
@@ -151,7 +151,7 @@ class ScrollManager extends Base {
151
151
 
152
152
  me.scrollTimeoutId = setTimeout(() => {
153
153
  view.isScrolling = false
154
- }, 30);
154
+ }, 100);
155
155
 
156
156
  view.set({isScrolling: true, scrollTop});
157
157
 
package/src/grid/View.mjs CHANGED
@@ -21,6 +21,10 @@ class GridView extends Component {
21
21
  * @protected
22
22
  */
23
23
  ntype: 'grid-view',
24
+ /**
25
+ * @member {Boolean} animatedRowSorting_=false
26
+ */
27
+ animatedRowSorting_: false,
24
28
  /**
25
29
  * Internal flag. Gets calculated when mounting the grid.Container
26
30
  * @member {Number} availableHeight_=0
@@ -93,6 +97,11 @@ class GridView extends Component {
93
97
  * @protected
94
98
  */
95
99
  mountedRows: [0, 0],
100
+ /**
101
+ * Optional config values for Neo.grid.plugin.AnimateRows
102
+ * @member {Object} pluginAnimateRowsConfig=null
103
+ */
104
+ pluginAnimateRowsConfig: null,
96
105
  /**
97
106
  * @member {String} role='rowgroup'
98
107
  */
@@ -204,6 +213,30 @@ class GridView extends Component {
204
213
  }])
205
214
  }
206
215
 
216
+ /**
217
+ * Triggered after the animatedRowSorting config got changed
218
+ * @param {Boolean} value
219
+ * @param {Boolean} oldValue
220
+ * @protected
221
+ */
222
+ afterSetAnimatedRowSorting(value, oldValue) {
223
+ if (value && !this.getPlugin('grid-animate-rows')) {
224
+ import('./plugin/AnimateRows.mjs').then(module => {
225
+ let me = this,
226
+ plugins = me.plugins || [];
227
+
228
+ plugins.push({
229
+ module : module.default,
230
+ appName : me.appName,
231
+ windowId: me.windowId,
232
+ ...me.pluginAnimateRowsConfig
233
+ });
234
+
235
+ me.plugins = plugins
236
+ })
237
+ }
238
+ }
239
+
207
240
  /**
208
241
  * Triggered after the availableHeight config got changed
209
242
  * @param {Number} value
@@ -364,6 +397,25 @@ class GridView extends Component {
364
397
  oldValue !== undefined && this.createViewData()
365
398
  }
366
399
 
400
+ /**
401
+ * Triggered after the store config got changed
402
+ * @param {Number} value
403
+ * @param {Number} oldValue
404
+ * @protected
405
+ */
406
+ afterSetStore(value, oldValue) {
407
+ let me = this,
408
+ listeners = {
409
+ filter : me.onStoreFilter,
410
+ load : me.onStoreLoad,
411
+ recordChange: me.onStoreRecordChange,
412
+ scope : me
413
+ };
414
+
415
+ oldValue?.un(listeners);
416
+ value ?.on(listeners);
417
+ }
418
+
367
419
  /**
368
420
  * @param {Object} data
369
421
  * @param {String} [data.cellId]
@@ -608,7 +660,8 @@ class GridView extends Component {
608
660
  * @param args
609
661
  */
610
662
  destroy(...args) {
611
- this.store = null;
663
+ this.store = null; // remove the listeners
664
+
612
665
  super.destroy(...args)
613
666
  }
614
667
 
@@ -849,6 +902,33 @@ class GridView extends Component {
849
902
  this.fireRowEvent(data, 'rowDoubleClick')
850
903
  }
851
904
 
905
+ /**
906
+ *
907
+ */
908
+ onStoreFilter() {
909
+ this.onStoreLoad()
910
+ }
911
+
912
+ /**
913
+ * @param {Object[]} data
914
+ * @protected
915
+ */
916
+ onStoreLoad(data) {
917
+ let me = this;
918
+
919
+ me.createViewData();
920
+
921
+ if (me.mounted) {
922
+ me.timeout(50).then(() => {
923
+ Neo.main.DomAccess.scrollTo({
924
+ direction: 'top',
925
+ id : me.vdom.id,
926
+ value : 0
927
+ })
928
+ })
929
+ }
930
+ }
931
+
852
932
  /**
853
933
  * @param {Object} data
854
934
  * @param {Object[]} data.fields Each field object contains the keys: name, oldValue, value
@@ -1,4 +1,3 @@
1
- import Button from '../../button/Base.mjs';
2
1
  import Column from './Base.mjs';
3
2
 
4
3
  /**
@@ -16,6 +15,20 @@ class Component extends Column {
16
15
  * @member {Function|Object|null} component=null
17
16
  */
18
17
  component: null,
18
+ /**
19
+ * @member {Object} defaults
20
+ * @protected
21
+ */
22
+ defaults: null,
23
+ /**
24
+ * Components can delegate event listeners (or button handlers) into methods somewhere inside
25
+ * the view controller or component tree hierarchy.
26
+ *
27
+ * In this case, it is helpful to know what the related record is, so we are adding the record
28
+ * to the component as a property. By default, as 'record', but this config can change the property name.
29
+ * @member {String} recordProperty='record'
30
+ */
31
+ recordProperty: 'record',
19
32
  /**
20
33
  * @member {String} type='component'
21
34
  * @protected
@@ -29,9 +42,19 @@ class Component extends Column {
29
42
  */
30
43
  map = new Map()
31
44
 
45
+ /**
46
+ * Override as needed inside class extensions
47
+ * @param {Object} config
48
+ * @param {Record} record
49
+ * @returns {Object}
50
+ */
51
+ applyRecordConfigs(config, record) {
52
+ return config
53
+ }
54
+
32
55
  /**
33
56
  * @param {Object} data
34
- * @param {Neo.button.Base} data.column
57
+ * @param {Neo.column.Base} data.column
35
58
  * @param {Number} data.columnIndex
36
59
  * @param {String} data.dataField
37
60
  * @param {Neo.grid.Container} data.gridContainer
@@ -42,28 +65,36 @@ class Component extends Column {
42
65
  * @returns {*}
43
66
  */
44
67
  cellRenderer(data) {
45
- let {gridContainer, rowIndex} = data,
46
- {appName, view, windowId} = gridContainer,
47
- me = this,
48
- id = `${me.id}-component-${rowIndex % (view.availableRows + 2 * view.bufferRowRange)}`,
49
- component = me.map.get(id),
50
- componentConfig = me.component;
68
+ let {gridContainer, record, rowIndex} = data,
69
+ {appName, view, windowId} = gridContainer,
70
+ me = this,
71
+ {recordProperty} = me,
72
+ id = me.getComponentId(rowIndex),
73
+ component = me.map.get(id),
74
+ componentConfig = me.component;
51
75
 
52
76
  if (Neo.typeOf(componentConfig) === 'Function') {
53
77
  componentConfig = componentConfig(data)
54
78
  }
55
79
 
80
+ componentConfig = me.applyRecordConfigs(componentConfig, record);
81
+
56
82
  if (component) {
57
83
  delete componentConfig.className;
58
84
  delete componentConfig.module;
59
85
  delete componentConfig.ntype;
60
86
 
87
+ componentConfig[recordProperty] = record;
88
+
61
89
  component.set(componentConfig)
62
90
  } else {
63
91
  component = Neo.create({
92
+ ...me.defaults,
64
93
  ...componentConfig,
65
94
  appName,
66
95
  id,
96
+ parentComponent : view,
97
+ [recordProperty]: record,
67
98
  windowId
68
99
  });
69
100
 
@@ -74,6 +105,17 @@ class Component extends Column {
74
105
 
75
106
  return component.createVdomReference()
76
107
  }
108
+
109
+ /**
110
+ * @param {Number} rowIndex
111
+ * @returns {String}
112
+ */
113
+ getComponentId(rowIndex) {
114
+ let me = this,
115
+ {view} = me.parent;
116
+
117
+ return `${me.id}-component-${rowIndex % (view.availableRows + 2 * view.bufferRowRange)}`
118
+ }
77
119
  }
78
120
 
79
121
  export default Neo.setupClass(Component);
@@ -0,0 +1,42 @@
1
+ import ComponentColumn from './Component.mjs';
2
+ import ProgressComponent from '../../component/Progress.mjs';
3
+
4
+ /**
5
+ * @class Neo.grid.column.Progress
6
+ * @extends Neo.grid.column.Component
7
+ */
8
+ class Progress extends ComponentColumn {
9
+ static config = {
10
+ /**
11
+ * @member {String} className='Neo.grid.column.Progress'
12
+ * @protected
13
+ */
14
+ className: 'Neo.grid.column.Progress',
15
+ /**
16
+ * @member {Object} defaults
17
+ * @protected
18
+ */
19
+ defaults: {
20
+ module: ProgressComponent
21
+ },
22
+ /**
23
+ * @member {String} type='progress'
24
+ * @protected
25
+ */
26
+ type: 'progress'
27
+ }
28
+
29
+ /**
30
+ * @param {Object} config
31
+ * @param {Record} record
32
+ * @returns {Object}
33
+ */
34
+ applyRecordConfigs(config, record) {
35
+ return {
36
+ value: record[this.dataField],
37
+ ...config
38
+ }
39
+ }
40
+ }
41
+
42
+ export default Neo.setupClass(Progress);
@@ -2,5 +2,6 @@ import AnimatedChange from './AnimatedChange.mjs';
2
2
  import Base from './Base.mjs';
3
3
  import Component from './Component.mjs';
4
4
  import Index from './Index.mjs';
5
+ import Progress from './Progress.mjs';
5
6
 
6
- export {AnimatedChange, Base, Component, Index};
7
+ export {AnimatedChange, Base, Component, Index, Progress};
@@ -176,7 +176,7 @@ class Button extends BaseButton {
176
176
  let me = this,
177
177
  {cls} = me;
178
178
 
179
- if (value === true) {
179
+ if (value) {
180
180
  NeoArray.remove(cls, 'neo-sort-hidden');
181
181
 
182
182
  me.addDomListeners({
@@ -211,7 +211,6 @@ class Button extends BaseButton {
211
211
  */
212
212
  destroy(...args) {
213
213
  this.filterField?.destroy();
214
-
215
214
  super.destroy(...args)
216
215
  }
217
216