neo.mjs 8.11.0 → 8.13.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 (44) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/colors/view/TableContainer.mjs +1 -1
  3. package/apps/covid/Util.mjs +9 -9
  4. package/apps/portal/index.html +1 -1
  5. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  6. package/apps/sharedcovid/Util.mjs +2 -2
  7. package/examples/ConfigurationViewport.mjs +1 -7
  8. package/examples/ServiceWorker.mjs +2 -2
  9. package/examples/grid/covid/Util.mjs +3 -3
  10. package/examples/table/covid/Util.mjs +2 -2
  11. package/package.json +2 -2
  12. package/resources/scss/src/draggable/DragProxyComponent.scss +9 -0
  13. package/resources/scss/src/draggable/grid/header/toolbar/SortZone.scss +16 -0
  14. package/resources/scss/src/draggable/table/header/toolbar/SortZone.scss +32 -0
  15. package/resources/scss/src/grid/header/Toolbar.scss +0 -1
  16. package/resources/scss/src/table/header/Button.scss +0 -4
  17. package/resources/scss/theme-dark/draggable/grid/header/toolbar/SortZone.scss +3 -0
  18. package/resources/scss/theme-dark/draggable/table/header/toolbar/SortZone.scss +3 -0
  19. package/resources/scss/theme-light/draggable/grid/header/toolbar/SortZone.scss +3 -0
  20. package/resources/scss/theme-light/draggable/table/header/toolbar/SortZone.scss +3 -0
  21. package/resources/scss/theme-neo-light/draggable/grid/header/toolbar/SortZone.scss +3 -0
  22. package/resources/scss/theme-neo-light/draggable/table/header/toolbar/SortZone.scss +3 -0
  23. package/src/DefaultConfig.mjs +2 -2
  24. package/src/component/Base.mjs +2 -6
  25. package/src/draggable/grid/header/toolbar/SortZone.mjs +74 -0
  26. package/src/draggable/table/header/toolbar/SortZone.mjs +70 -0
  27. package/src/draggable/toolbar/SortZone.mjs +23 -14
  28. package/src/grid/View.mjs +19 -21
  29. package/src/grid/header/Button.mjs +7 -115
  30. package/src/grid/header/Toolbar.mjs +32 -0
  31. package/src/main/DomAccess.mjs +1 -1
  32. package/src/main/DomEvents.mjs +10 -50
  33. package/src/main/addon/AmCharts.mjs +28 -9
  34. package/src/main/addon/DragDrop.mjs +9 -20
  35. package/src/main/mixin/DeltaUpdates.mjs +13 -7
  36. package/src/selection/grid/BaseModel.mjs +1 -1
  37. package/src/selection/grid/RowModel.mjs +57 -18
  38. package/src/selection/table/BaseModel.mjs +1 -1
  39. package/src/selection/table/RowModel.mjs +57 -17
  40. package/src/table/Container.mjs +6 -6
  41. package/src/table/View.mjs +28 -26
  42. package/src/table/header/Button.mjs +7 -111
  43. package/src/table/header/Toolbar.mjs +34 -2
  44. package/src/util/Rectangle.mjs +1 -1
@@ -1,5 +1,4 @@
1
1
  import BaseModel from './BaseModel.mjs';
2
- import VDomUtil from '../../util/VDom.mjs';
3
2
 
4
3
  /**
5
4
  * @class Neo.selection.grid.RowModel
@@ -44,6 +43,14 @@ class RowModel extends BaseModel {
44
43
  super.destroy(...args)
45
44
  }
46
45
 
46
+ /**
47
+ * @param {Record} record
48
+ * @returns {Boolean}
49
+ */
50
+ hasAnnotations(record) {
51
+ return !!Object.getOwnPropertyDescriptor(record.__proto__, this.view.selectedRecordField)
52
+ }
53
+
47
54
  /**
48
55
  * @param {Object} data
49
56
  */
@@ -65,28 +72,31 @@ class RowModel extends BaseModel {
65
72
  let me = this,
66
73
  {view} = me,
67
74
  {store} = view,
75
+ countRecords = store.getCount(),
68
76
  currentIndex = 0,
69
- newIndex, newRecord, rowId;
77
+ newIndex, record, rowId;
70
78
 
71
79
  if (me.hasSelection()) {
72
80
  currentIndex = store.indexOf(view.getRecordByRowId(me.items[0]))
73
81
  }
74
82
 
75
- newIndex = (currentIndex + step) % store.getCount();
83
+ newIndex = (currentIndex + step) % countRecords;
76
84
 
77
85
  while (newIndex < 0) {
78
- newIndex += store.getCount()
86
+ newIndex += countRecords
79
87
  }
80
88
 
81
- newRecord = store.getAt(newIndex);
82
- rowId = view.getRowId(newRecord);
89
+ record = store.getAt(newIndex);
83
90
 
84
- if (rowId) {
85
- me.select(rowId);
91
+ if (me.hasAnnotations(record)) {
92
+ me.updateAnnotations(record)
93
+ } else {
94
+ rowId = view.getRowId(record);
86
95
 
87
- view.fire('select', {
88
- record: store.getAt(newIndex)
89
- })
96
+ if (rowId) {
97
+ me.select(rowId);
98
+ view.fire('select', {record})
99
+ }
90
100
  }
91
101
  }
92
102
 
@@ -100,16 +110,19 @@ class RowModel extends BaseModel {
100
110
  isSelected, record;
101
111
 
102
112
  if (id) {
103
- me.toggleSelection(id);
113
+ record = view.getRecord(id);
114
+
115
+ if (me.hasAnnotations(record)) {
116
+ me.updateAnnotations(record)
117
+ } else {
118
+ me.toggleSelection(id);
104
119
 
105
- isSelected = me.isSelected(id);
106
- record = view.getRecord(id);
120
+ isSelected = me.isSelected(id);
107
121
 
108
- !isSelected && view.onDeselect?.(record);
122
+ !isSelected && view.onDeselect?.(record);
109
123
 
110
- view.fire(isSelected ? 'select' : 'deselect', {
111
- record
112
- })
124
+ view.fire(isSelected ? 'select' : 'deselect', {record})
125
+ }
113
126
  }
114
127
  }
115
128
 
@@ -140,6 +153,32 @@ class RowModel extends BaseModel {
140
153
 
141
154
  super.unregister()
142
155
  }
156
+
157
+ /**
158
+ * @param {Record} record
159
+ */
160
+ updateAnnotations(record) {
161
+ let me = this,
162
+ {view} = me,
163
+ rowId = view.getRowId(record),
164
+ isSelected = me.isSelected(rowId),
165
+ annotationsField = view.selectedRecordField;
166
+
167
+ if (me.singleSelect) {
168
+ if (isSelected) {
169
+ record[annotationsField] = false
170
+ } else {
171
+ me.items.forEach(rowId => {
172
+ // We can use setSilent(), since the last change will trigger a view update
173
+ view.getRecordByRowId(rowId).setSilent({[annotationsField]: false})
174
+ });
175
+
176
+ record[annotationsField] = true
177
+ }
178
+ } else {
179
+ record[annotationsField] = !record[annotationsField]
180
+ }
181
+ }
143
182
  }
144
183
 
145
184
  export default Neo.setupClass(RowModel);
@@ -20,7 +20,7 @@ class BaseModel extends Model {
20
20
  * @member {String[]} dataFields
21
21
  */
22
22
  get dataFields() {
23
- return this.view.parent.columns.map(c => c.dataField)
23
+ return this.view.parent.columns.map(column => column.dataField)
24
24
  }
25
25
  }
26
26
 
@@ -23,6 +23,14 @@ class RowModel extends BaseModel {
23
23
  cls: 'neo-selection-rowmodel'
24
24
  }
25
25
 
26
+ /**
27
+ * @param {Record} record
28
+ * @returns {Boolean}
29
+ */
30
+ hasAnnotations(record) {
31
+ return !!Object.getOwnPropertyDescriptor(record.__proto__, this.view.selectedRecordField)
32
+ }
33
+
26
34
  /**
27
35
  *
28
36
  */
@@ -64,28 +72,31 @@ class RowModel extends BaseModel {
64
72
  let me = this,
65
73
  {view} = me,
66
74
  {store} = view,
75
+ countRecords = store.getCount(),
67
76
  currentIndex = 0,
68
- newIndex, newRecord, rowId;
77
+ newIndex, record, rowId;
69
78
 
70
79
  if (me.hasSelection()) {
71
80
  currentIndex = store.indexOf(view.getRecordByRowId(me.items[0]))
72
81
  }
73
82
 
74
- newIndex = (currentIndex + step) % store.getCount();
83
+ newIndex = (currentIndex + step) % countRecords;
75
84
 
76
85
  while (newIndex < 0) {
77
- newIndex += store.getCount()
86
+ newIndex += countRecords
78
87
  }
79
88
 
80
- newRecord = store.getAt(newIndex);
81
- rowId = view.getRowId(newRecord);
89
+ record = store.getAt(newIndex);
82
90
 
83
- if (rowId) {
84
- me.select(rowId);
91
+ if (me.hasAnnotations(record)) {
92
+ me.updateAnnotations(record)
93
+ } else {
94
+ rowId = view.getRowId(record);
85
95
 
86
- view.fire('select', {
87
- record: store.getAt(newIndex)
88
- })
96
+ if (rowId) {
97
+ me.select(rowId);
98
+ view.fire('select', {record})
99
+ }
89
100
  }
90
101
  }
91
102
 
@@ -99,16 +110,19 @@ class RowModel extends BaseModel {
99
110
  isSelected, record;
100
111
 
101
112
  if (id) {
102
- me.toggleSelection(id);
113
+ record = view.getRecord(id);
114
+
115
+ if (me.hasAnnotations(record)) {
116
+ me.updateAnnotations(record)
117
+ } else {
118
+ me.toggleSelection(id);
103
119
 
104
- isSelected = me.isSelected(id);
105
- record = view.getRecord(id);
120
+ isSelected = me.isSelected(id);
106
121
 
107
- !isSelected && view.onDeselect?.(record);
122
+ !isSelected && view.onDeselect?.(record);
108
123
 
109
- view.fire(isSelected ? 'select' : 'deselect', {
110
- record
111
- })
124
+ view.fire(isSelected ? 'select' : 'deselect', {record})
125
+ }
112
126
  }
113
127
  }
114
128
 
@@ -139,6 +153,32 @@ class RowModel extends BaseModel {
139
153
 
140
154
  super.unregister()
141
155
  }
156
+
157
+ /**
158
+ * @param {Record} record
159
+ */
160
+ updateAnnotations(record) {
161
+ let me = this,
162
+ {view} = me,
163
+ rowId = view.getRowId(record),
164
+ isSelected = me.isSelected(rowId),
165
+ annotationsField = view.selectedRecordField;
166
+
167
+ if (me.singleSelect) {
168
+ if (isSelected) {
169
+ record[annotationsField] = false
170
+ } else {
171
+ me.items.forEach(rowId => {
172
+ // We can use setSilent(), since the last change will trigger a view update
173
+ view.getRecordByRowId(rowId).setSilent({[annotationsField]: false})
174
+ });
175
+
176
+ record[annotationsField] = true
177
+ }
178
+ } else {
179
+ record[annotationsField] = !record[annotationsField]
180
+ }
181
+ }
142
182
  }
143
183
 
144
184
  export default Neo.setupClass(RowModel);
@@ -192,7 +192,7 @@ class Container extends BaseContainer {
192
192
  headerToolbar.createItems()
193
193
  }
194
194
 
195
- me.view?.createViewData(me.store.items)
195
+ me.view?.createViewData()
196
196
  }
197
197
  }
198
198
 
@@ -407,12 +407,12 @@ class Container extends BaseContainer {
407
407
  }
408
408
 
409
409
  /**
410
- * @param {Array} inputData
410
+ *
411
411
  */
412
- createViewData(inputData) {
412
+ createViewData() {
413
413
  let me = this;
414
414
 
415
- me.view.createViewData(inputData);
415
+ me.view.createViewData();
416
416
 
417
417
  if (me.useCustomScrollbars && me.scrollbarsCssApplied === false) {
418
418
  me.applyCustomScrollbarsCss()
@@ -478,7 +478,7 @@ class Container extends BaseContainer {
478
478
  let me = this;
479
479
 
480
480
  if (me.rendered) {
481
- me.createViewData(data);
481
+ me.createViewData();
482
482
 
483
483
  if (me.store.sorters.length < 1) {
484
484
  me.removeSortingCss()
@@ -486,7 +486,7 @@ class Container extends BaseContainer {
486
486
  } else {
487
487
  me.on('rendered', () => {
488
488
  me.timeout(50).then(() => {
489
- me.createViewData(data)
489
+ me.createViewData()
490
490
  })
491
491
  }, me, {once: true})
492
492
  }
@@ -116,13 +116,14 @@ class View extends Component {
116
116
  * @param {Object} data
117
117
  * @param {String} [data.cellId]
118
118
  * @param {Object} data.column
119
+ * @param {Number} data.columnIndex
119
120
  * @param {Object} data.record
120
- * @param {Number} data.index
121
+ * @param {Number} data.rowIndex
121
122
  * @param {Neo.table.Container} data.tableContainer
122
123
  * @returns {Object}
123
124
  */
124
125
  applyRendererOutput(data) {
125
- let {cellId, column, record, index, tableContainer} = data,
126
+ let {cellId, column, columnIndex, record, rowIndex, tableContainer} = data,
126
127
  me = this,
127
128
  cellCls = ['neo-table-cell'],
128
129
  colspan = record[me.colspanField],
@@ -138,9 +139,10 @@ class View extends Component {
138
139
 
139
140
  rendererOutput = column.renderer.call(column.rendererScope || tableContainer, {
140
141
  column,
142
+ columnIndex,
141
143
  dataField,
142
- index,
143
144
  record,
145
+ rowIndex,
144
146
  tableContainer,
145
147
  value: fieldValue
146
148
  });
@@ -184,7 +186,7 @@ class View extends Component {
184
186
  if (hasStore) {
185
187
  cellId = me.getCellId(record, column.dataField)
186
188
  } else {
187
- cellId = vdom.cn[index]?.cn[me.getColumn(column.dataField, true)]?.id || Neo.getId('td')
189
+ cellId = vdom.cn[rowIndex]?.cn[me.getColumn(column.dataField, true)]?.id || Neo.getId('td')
188
190
  }
189
191
  }
190
192
 
@@ -267,7 +269,7 @@ class View extends Component {
267
269
 
268
270
  for (i=0; i < colCount; i++) {
269
271
  column = columns[i];
270
- config = me.applyRendererOutput({column, record, index: rowIndex, tableContainer});
272
+ config = me.applyRendererOutput({column, columnIndex: i, record, rowIndex, tableContainer});
271
273
 
272
274
  if (column.dock) {
273
275
  config.cls = ['neo-locked', ...config.cls || []];
@@ -310,17 +312,17 @@ class View extends Component {
310
312
  }
311
313
 
312
314
  /**
313
- * @param {Object[]} inputData
315
+ *
314
316
  */
315
- createViewData(inputData) {
316
- let me = this,
317
- amountRows = inputData.length,
318
- i = 0,
319
- rows = [],
320
- {selectedRows} = me;
321
-
322
- for (; i < amountRows; i++) {
323
- rows.push(me.createRow({record: inputData[i], rowIndex: i}))
317
+ createViewData() {
318
+ let me = this,
319
+ {selectedRows, store} = me,
320
+ countRecords = store.getCount(),
321
+ i = 0,
322
+ rows = [];
323
+
324
+ for (; i < countRecords; i++) {
325
+ rows.push(me.createRow({record: store.items[i], rowIndex: i}))
324
326
  }
325
327
 
326
328
  me.vdom.cn = rows;
@@ -522,17 +524,16 @@ class View extends Component {
522
524
  * @param {Object} opts.record
523
525
  */
524
526
  onStoreRecordChange({fields, model, record}) {
525
- let me = this,
526
- fieldNames = fields.map(field => field.name),
527
- needsUpdate = false,
528
- tableContainer = me.parent,
529
- {selectionModel} = tableContainer,
530
- {vdom} = me,
531
- cellId, cellNode, column, index, scope;
527
+ let me = this,
528
+ fieldNames = fields.map(field => field.name),
529
+ needsUpdate = false,
530
+ tableContainer = me.parent,
531
+ rowIndex = me.store.indexOf(record),
532
+ {selectionModel, vdom} = me,
533
+ cellId, cellNode, cellVdom, column, columnIndex, scope;
532
534
 
533
535
  if (fieldNames.includes(me.colspanField)) {
534
- index = me.store.indexOf(record);
535
- me.vdom.cn[index] = me.createRow({record, rowIndex: index});
536
+ me.vdom.cn[rowIndex] = me.createRow({record, rowIndex});
536
537
  me.update()
537
538
  } else {
538
539
  fields.forEach(field => {
@@ -547,11 +548,12 @@ class View extends Component {
547
548
  // the vdom might not exist yet => nothing to do in this case
548
549
  if (cellNode?.vdom) {
549
550
  column = me.getColumn(field.name);
550
- index = cellNode.index;
551
+ columnIndex = cellNode.index;
551
552
  needsUpdate = true;
552
553
  scope = column.rendererScope || tableContainer;
554
+ cellVdom = me.applyRendererOutput({cellId, column, columnIndex, record, rowIndex, tableContainer});
553
555
 
554
- cellNode.parentNode.cn[index] = me.applyRendererOutput({cellId, column, record, index, tableContainer})
556
+ cellNode.parentNode.cn[columnIndex] = cellVdom
555
557
  }
556
558
  }
557
559
  })
@@ -110,43 +110,6 @@ class Button extends BaseButton {
110
110
  ]}
111
111
  }
112
112
 
113
- /**
114
- * @param {Object} config
115
- */
116
- construct(config) {
117
- super.construct(config);
118
-
119
- let me = this;
120
-
121
- me.draggable && me.addDomListeners({
122
- dragend : me.onDragEnd,
123
- dragenter: me.onDragEnter,
124
- dragleave: me.onDragLeave,
125
- dragover : me.onDragOver,
126
- dragstart: me.onDragStart,
127
- drop : me.onDrop,
128
- scope : me
129
- })
130
- }
131
-
132
- /**
133
- * Triggered after the draggable config got changed
134
- * @param {Boolean} value
135
- * @param {Boolean} oldValue
136
- * @protected
137
- */
138
- afterSetDraggable(value, oldValue) {
139
- let me = this;
140
-
141
- if (value === true) {
142
- me.getVdomRoot().draggable = true
143
- } else {
144
- delete me.getVdomRoot().draggable
145
- }
146
-
147
- me.update()
148
- }
149
-
150
113
  /**
151
114
  * Triggered after the isSorted config got changed
152
115
  * @param {String|null} value
@@ -279,13 +242,14 @@ class Button extends BaseButton {
279
242
  }
280
243
 
281
244
  /**
282
- * @param {Object} data
283
- * @param {Neo.button.Base} data.column
284
- * @param {String} data.dataField
285
- * @param {Number} data.index
286
- * @param {Object} data.record
245
+ * @param {Object} data
246
+ * @param {Neo.button.Base} data.column
247
+ * @param {Number} data.columnIndex
248
+ * @param {String} data.dataField
249
+ * @param {Object} data.record
250
+ * @param {Number} data.rowIndex
287
251
  * @param {Neo.table.Container} data.tableContainer
288
- * @param {Number|String} data.value
252
+ * @param {Number|String} data.value
289
253
  * @returns {*}
290
254
  */
291
255
  cellRenderer(data) {
@@ -413,74 +377,6 @@ class Button extends BaseButton {
413
377
  me.isSorted = map[me.isSorted + '']
414
378
  }
415
379
 
416
- /**
417
- * @protected
418
- */
419
- onDragEnd() {
420
- let me = this,
421
- {style} = me;
422
-
423
- delete style.opacity;
424
- me.style = style
425
- }
426
-
427
- /**
428
- * @protected
429
- */
430
- onDragEnter() {
431
- let me = this,
432
- {cls} = me;
433
-
434
- NeoArray.add(cls, 'neo-drag-over');
435
- me.cls = cls
436
- }
437
-
438
- /**
439
- * @protected
440
- */
441
- onDragLeave() {
442
- let me = this,
443
- {cls} = me;
444
-
445
- NeoArray.remove(cls, 'neo-drag-over');
446
- me.cls = cls
447
- }
448
-
449
- /**
450
- * @param {Object} event
451
- */
452
- onDragOver(event) {
453
- //console.log('onDragOver', event);
454
- }
455
-
456
- /**
457
- * @protected
458
- */
459
- onDragStart() {
460
- let me = this,
461
- {style} = me;
462
-
463
- style.opacity = 0.4;
464
- me.style = style
465
- }
466
-
467
- /**
468
- * @param {Object} data
469
- */
470
- onDrop(data) {
471
- let me = this,
472
- headerToolbar = me.parent,
473
- {style} = me,
474
- tableContainer = headerToolbar.parent;
475
-
476
- me.onDragLeave();
477
- headerToolbar.switchItems(me.id, data.srcId);
478
- tableContainer.createViewData(tableContainer.store.data);
479
-
480
- style.opacity = 1;
481
- me.style = style
482
- }
483
-
484
380
  /**
485
381
  * @protected
486
382
  */
@@ -17,9 +17,13 @@ class Toolbar extends BaseToolbar {
17
17
  */
18
18
  ntype: 'table-header-toolbar',
19
19
  /**
20
- * @member {String[]} baseCls=['table-header-toolbar']
20
+ * @member {String[]} baseCls=['neo-table-header-toolbar']
21
21
  */
22
- baseCls: ['table-header-toolbar'],
22
+ baseCls: ['neo-table-header-toolbar'],
23
+ /**
24
+ * @member {Boolean} draggable_=true
25
+ */
26
+ draggable_: true,
23
27
  /**
24
28
  * @member {String} layout='base'
25
29
  */
@@ -35,6 +39,8 @@ class Toolbar extends BaseToolbar {
35
39
  */
36
40
  showHeaderFilters_: false,
37
41
  /**
42
+ * Convenience shortcut to pass sortable to all toolbar items.
43
+ * If set to true, header clicks will sort the matching column (ASC, DESC, null)
38
44
  * @member {Boolean} sortable=true
39
45
  */
40
46
  sortable: true,
@@ -47,6 +53,31 @@ class Toolbar extends BaseToolbar {
47
53
  ]}
48
54
  }
49
55
 
56
+ /**
57
+ * Triggered after the draggable config got changed
58
+ * @param {Boolean} value
59
+ * @param {Boolean} oldValue
60
+ * @protected
61
+ */
62
+ afterSetDraggable(value, oldValue) {
63
+ let me = this;
64
+
65
+ if (value && !me.sortZone) {
66
+ import('../../draggable/table/header/toolbar/SortZone.mjs').then(module => {
67
+ let {appName, id, windowId} = me;
68
+
69
+ me.sortZone = Neo.create({
70
+ module : module.default,
71
+ appName,
72
+ boundaryContainerId: id,
73
+ owner : me,
74
+ windowId,
75
+ ...me.sortZoneConfig
76
+ })
77
+ })
78
+ }
79
+ }
80
+
50
81
  /**
51
82
  * Triggered after the showHeaderFilters config got changed
52
83
  * @param {Boolean} value
@@ -84,6 +115,7 @@ class Toolbar extends BaseToolbar {
84
115
  })
85
116
  });
86
117
 
118
+ me.updateDepth = 2;
87
119
  me.update()
88
120
  }
89
121
  }
@@ -309,7 +309,7 @@ export default class Rectangle extends DOMRect {
309
309
 
310
310
  /**
311
311
  * Returns a clone of this Rectangle expanded according to the edges array.
312
- * @param {Number}Number[]} edges
312
+ * @param {Number[]} edges
313
313
  * @returns {Rectangle}
314
314
  */
315
315
  expand(edges) {