neo.mjs 8.4.1 → 8.5.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.
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/apps/portal/view/learn/ContentComponent.mjs +1 -13
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/grid/bigData/MainContainer.mjs +26 -6
- package/examples/grid/bigData/MainStore.mjs +12 -58
- package/examples/grid/cellEditing/MainContainer.mjs +10 -7
- package/examples/grid/container/MainContainer.mjs +26 -11
- package/package.json +2 -2
- package/resources/data/deck/learnneo/pages/tutorials/TodoList.md +1 -1
- package/resources/data/deck/training/pages/2023-02-05T17-44-53-815Z.md +6 -6
- package/resources/scss/src/apps/portal/examples/TabContainer.scss +5 -1
- package/resources/scss/src/grid/View.scss +4 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/Base.mjs +38 -11
- package/src/grid/Container.mjs +0 -46
- package/src/grid/View.mjs +130 -56
- package/src/grid/header/Toolbar.mjs +4 -2
- package/src/selection/Model.mjs +2 -2
- package/src/selection/grid/RowModel.mjs +16 -47
package/apps/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
@@ -84,18 +84,6 @@ class ContentComponent extends Component {
|
|
84
84
|
|
85
85
|
if (value) {
|
86
86
|
me.timeout(50).then(() => {
|
87
|
-
me.customComponents.forEach(component => {
|
88
|
-
if (!component.mounted && !component.rendering) {
|
89
|
-
component.render(true)
|
90
|
-
}
|
91
|
-
});
|
92
|
-
|
93
|
-
me.livePreviews.forEach(livePreview => {
|
94
|
-
if (!livePreview.mounted && !livePreview.rendering) {
|
95
|
-
livePreview.render(true)
|
96
|
-
}
|
97
|
-
});
|
98
|
-
|
99
87
|
Neo.main.addon.IntersectionObserver.register({
|
100
88
|
callback: 'findTopmostItem',
|
101
89
|
id : me.id,
|
@@ -110,7 +98,7 @@ class ContentComponent extends Component {
|
|
110
98
|
|
111
99
|
me.livePreviews.forEach(livePreview => {
|
112
100
|
livePreview.mounted = false
|
113
|
-
})
|
101
|
+
})
|
114
102
|
}
|
115
103
|
}
|
116
104
|
|
@@ -49,12 +49,19 @@ class MainContainer extends Viewport {
|
|
49
49
|
value : '50',
|
50
50
|
width : 200
|
51
51
|
}, {
|
52
|
-
labelText : 'Buffer
|
53
|
-
labelWidth:
|
52
|
+
labelText : 'Buffer Rows',
|
53
|
+
labelWidth: 95,
|
54
54
|
listeners : {change: 'up.ontBufferRowRangeChange'},
|
55
55
|
store : ['0', '3', '5', '10', '25', '50'],
|
56
56
|
value : '5',
|
57
|
-
width :
|
57
|
+
width : 160
|
58
|
+
}, {
|
59
|
+
labelText : 'Buffer Columns',
|
60
|
+
labelWidth: 120,
|
61
|
+
listeners : {change: 'up.ontBufferColumnRangeChange'},
|
62
|
+
store : ['0', '3', '5', '10', '20'],
|
63
|
+
value : '0',
|
64
|
+
width : 185
|
58
65
|
}]
|
59
66
|
}, {
|
60
67
|
module : GridContainer,
|
@@ -73,12 +80,16 @@ class MainContainer extends Viewport {
|
|
73
80
|
style: {padding: '20px'}
|
74
81
|
}
|
75
82
|
|
83
|
+
get grid() {
|
84
|
+
return this.getItem('grid')
|
85
|
+
}
|
86
|
+
|
76
87
|
/**
|
77
88
|
* @param {Object} data
|
78
89
|
*/
|
79
90
|
onAmountColumnsChange(data) {
|
80
91
|
if (data.oldValue) {
|
81
|
-
this.
|
92
|
+
this.grid.amountColumns = parseInt(data.value.id)
|
82
93
|
}
|
83
94
|
}
|
84
95
|
|
@@ -87,7 +98,16 @@ class MainContainer extends Viewport {
|
|
87
98
|
*/
|
88
99
|
onAmountRowsChange(data) {
|
89
100
|
if (data.oldValue) {
|
90
|
-
this.
|
101
|
+
this.grid.store.amountRows = parseInt(data.value.id)
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
/**
|
106
|
+
* @param {Object} data
|
107
|
+
*/
|
108
|
+
ontBufferColumnRangeChange(data) {
|
109
|
+
if (data.oldValue) {
|
110
|
+
this.grid.view.bufferColumnRange = parseInt(data.value.id)
|
91
111
|
}
|
92
112
|
}
|
93
113
|
|
@@ -96,7 +116,7 @@ class MainContainer extends Viewport {
|
|
96
116
|
*/
|
97
117
|
ontBufferRowRangeChange(data) {
|
98
118
|
if (data.oldValue) {
|
99
|
-
this.
|
119
|
+
this.grid.view.bufferRowRange = parseInt(data.value.id)
|
100
120
|
}
|
101
121
|
}
|
102
122
|
}
|
@@ -27,67 +27,21 @@ class MainStore extends Store {
|
|
27
27
|
}
|
28
28
|
|
29
29
|
firstnames = [
|
30
|
-
'Ashley',
|
31
|
-
'
|
32
|
-
'
|
33
|
-
'
|
34
|
-
'
|
35
|
-
'
|
36
|
-
'Jack',
|
37
|
-
'James',
|
38
|
-
'Jennifer',
|
39
|
-
'Jessica',
|
40
|
-
'Joe',
|
41
|
-
'John',
|
42
|
-
'Karen',
|
43
|
-
'Kelly',
|
44
|
-
'Kim',
|
45
|
-
'Linda',
|
46
|
-
'Lisa',
|
47
|
-
'Mary',
|
48
|
-
'Max',
|
49
|
-
'Michael',
|
50
|
-
'Nancy',
|
51
|
-
'Patricia',
|
52
|
-
'Rich',
|
53
|
-
'Robert',
|
54
|
-
'Sam',
|
55
|
-
'Sandra',
|
56
|
-
'Sarah',
|
57
|
-
'Susan',
|
58
|
-
'Thomas',
|
59
|
-
'Tobias'
|
30
|
+
'Amanda', 'Andrew', 'Anthony', 'Ashley', 'Barbara', 'Betty', 'Brian', 'Carol', 'Charles', 'Christopher',
|
31
|
+
'Daniel', 'David', 'Deborah', 'Donna', 'Elizabeth', 'Emily', 'George', 'Jack', 'James', 'Jennifer',
|
32
|
+
'Jessica', 'Joe', 'John', 'Joseph', 'Joshua', 'Karen', 'Kenneth', 'Kelly', 'Kevin', 'Kimberly',
|
33
|
+
'Linda', 'Lisa', 'Margaret', 'Mark', 'Mary', 'Matthew', 'Max', 'Melissa', 'Michael', 'Michelle',
|
34
|
+
'Nancy', 'Patricia', 'Paul', 'Richard', 'Robert', 'Ronald', 'Sam', 'Sandra', 'Sarah', 'Stephanie',
|
35
|
+
'Steven', 'Susan', 'Thomas', 'Timothy', 'Tobias', 'William'
|
60
36
|
]
|
61
37
|
|
62
38
|
lastnames = [
|
63
|
-
'Anderson',
|
64
|
-
'
|
65
|
-
'
|
66
|
-
'
|
67
|
-
'
|
68
|
-
'
|
69
|
-
'Hernandez',
|
70
|
-
'Jackson',
|
71
|
-
'Johnson',
|
72
|
-
'Jones',
|
73
|
-
'Lee',
|
74
|
-
'Lopez',
|
75
|
-
'Martin',
|
76
|
-
'Martinez',
|
77
|
-
'Miller',
|
78
|
-
'Moore',
|
79
|
-
'Perez',
|
80
|
-
'Rahder',
|
81
|
-
'Rodriguez',
|
82
|
-
'Smith',
|
83
|
-
'Taylor',
|
84
|
-
'Thomas',
|
85
|
-
'Thompson',
|
86
|
-
'Uhlig',
|
87
|
-
'Waters',
|
88
|
-
'White',
|
89
|
-
'Williams',
|
90
|
-
'Wilson'
|
39
|
+
'Adams', 'Allen', 'Anderson', 'Baker', 'Brown', 'Campbell', 'Carter', 'Clark', 'Davis', 'Flores',
|
40
|
+
'Garcia', 'Gonzales', 'Green', 'Hall', 'Harris', 'Hernandez', 'Hill', 'Jackson', 'Johnson', 'Jones',
|
41
|
+
'King', 'Lee', 'Lewis', 'Lopez', 'Martin', 'Martinez', 'Miller', 'Mitchell', 'Moore', 'Nelson',
|
42
|
+
'Nguyen', 'Perez', 'Rahder', 'Ramirez', 'Roberts', 'Rivera', 'Robinson', 'Rodriguez', 'Sanchez', 'Scott',
|
43
|
+
'Smith', 'Taylor', 'Thomas', 'Thompson', 'Torres', 'Uhlig', 'Walker', 'Waters', 'White', 'Williams',
|
44
|
+
'Wilson', 'Wright', 'Young'
|
91
45
|
]
|
92
46
|
|
93
47
|
/**
|
@@ -106,12 +106,11 @@ class MainContainer extends ConfigurationViewport {
|
|
106
106
|
*/
|
107
107
|
createExampleComponent() {
|
108
108
|
return {
|
109
|
-
module
|
110
|
-
bind
|
111
|
-
cellEditing
|
112
|
-
parentId
|
113
|
-
|
114
|
-
store : MainStore,
|
109
|
+
module : GridContainer,
|
110
|
+
bind : {store: 'stores.mainStore'},
|
111
|
+
cellEditing: true,
|
112
|
+
parentId : this.id,
|
113
|
+
store : MainStore,
|
115
114
|
|
116
115
|
columnDefaults: {
|
117
116
|
editable: true,
|
@@ -159,7 +158,11 @@ class MainContainer extends ConfigurationViewport {
|
|
159
158
|
dataField: 'githubId',
|
160
159
|
editable : false,
|
161
160
|
text : 'Github Id (Non-editable)'
|
162
|
-
}]
|
161
|
+
}],
|
162
|
+
|
163
|
+
viewConfig: {
|
164
|
+
selectionModel: CellModel
|
165
|
+
}
|
163
166
|
}
|
164
167
|
}
|
165
168
|
|
@@ -25,7 +25,8 @@ class MainContainer extends ConfigurationViewport {
|
|
25
25
|
}
|
26
26
|
|
27
27
|
createConfigurationComponents() {
|
28
|
-
let me
|
28
|
+
let me = this,
|
29
|
+
{view} = me.exampleComponent;
|
29
30
|
|
30
31
|
const selectionModelRadioDefaults = {
|
31
32
|
module : Radio,
|
@@ -45,34 +46,34 @@ class MainContainer extends ConfigurationViewport {
|
|
45
46
|
value : me.exampleComponent.height
|
46
47
|
}, {
|
47
48
|
...selectionModelRadioDefaults,
|
48
|
-
checked :
|
49
|
+
checked : view.selectionModel.ntype === 'selection-grid-cellmodel',
|
49
50
|
labelText : 'selectionModel',
|
50
51
|
listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellModel)},
|
51
52
|
style : {marginTop: '10px'},
|
52
53
|
valueLabelText: 'Cell'
|
53
54
|
}, {
|
54
55
|
...selectionModelRadioDefaults,
|
55
|
-
checked :
|
56
|
+
checked : view.selectionModel.ntype === 'selection-grid-columnmodel',
|
56
57
|
listeners : {change: me.onRadioChange.bind(me, 'selectionModel', ColumnModel)},
|
57
58
|
valueLabelText: 'Column'
|
58
59
|
}, {
|
59
60
|
...selectionModelRadioDefaults,
|
60
|
-
checked :
|
61
|
+
checked : view.selectionModel.ntype === 'selection-grid-rowmodel',
|
61
62
|
listeners : {change: me.onRadioChange.bind(me, 'selectionModel', RowModel)},
|
62
63
|
valueLabelText: 'Row'
|
63
64
|
}, {
|
64
65
|
...selectionModelRadioDefaults,
|
65
|
-
checked :
|
66
|
+
checked : view.selectionModel.ntype === 'selection-grid-cellcolumnmodel',
|
66
67
|
listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnModel)},
|
67
68
|
valueLabelText: 'Cell & Column'
|
68
69
|
}, {
|
69
70
|
...selectionModelRadioDefaults,
|
70
|
-
checked :
|
71
|
+
checked : view.selectionModel.ntype === 'selection-grid-cellrowmodel',
|
71
72
|
listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellRowModel)},
|
72
73
|
valueLabelText: 'Cell & Row'
|
73
74
|
}, {
|
74
75
|
...selectionModelRadioDefaults,
|
75
|
-
checked :
|
76
|
+
checked : view.selectionModel.ntype === 'selection-grid-cellcolumnrowmodel',
|
76
77
|
listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnRowModel)},
|
77
78
|
valueLabelText: 'Cell & Column & Row'
|
78
79
|
}]
|
@@ -80,9 +81,8 @@ class MainContainer extends ConfigurationViewport {
|
|
80
81
|
|
81
82
|
createExampleComponent() {
|
82
83
|
return {
|
83
|
-
module
|
84
|
-
|
85
|
-
store : MainStore,
|
84
|
+
module: GridContainer,
|
85
|
+
store : MainStore,
|
86
86
|
|
87
87
|
columnDefaults: {
|
88
88
|
width: 200
|
@@ -93,7 +93,22 @@ class MainContainer extends ConfigurationViewport {
|
|
93
93
|
{dataField: 'lastname', text: 'Lastname'},
|
94
94
|
{dataField: 'githubId', text: 'Github Id'},
|
95
95
|
{dataField: 'country', text: 'Country'}
|
96
|
-
]
|
96
|
+
],
|
97
|
+
|
98
|
+
viewConfig: {
|
99
|
+
selectionModel: CellModel
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
/**
|
105
|
+
* @param {String} config
|
106
|
+
* @param {String} value
|
107
|
+
* @param {Object} opts
|
108
|
+
*/
|
109
|
+
onRadioChange(config, value, opts) {
|
110
|
+
if (opts.value === true) { // we only want to listen to check events, not uncheck
|
111
|
+
this.exampleComponent.view[config] = value
|
97
112
|
}
|
98
113
|
}
|
99
114
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.5.0",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -52,7 +52,7 @@
|
|
52
52
|
"commander": "^13.0.0",
|
53
53
|
"cssnano": "^7.0.6",
|
54
54
|
"envinfo": "^7.14.0",
|
55
|
-
"fs-extra": "^11.
|
55
|
+
"fs-extra": "^11.3.0",
|
56
56
|
"highlightjs-line-numbers.js": "^2.9.0",
|
57
57
|
"inquirer": "^12.3.2",
|
58
58
|
"marked": "^15.0.6",
|
@@ -91,7 +91,7 @@ class MainComponent extends Component {
|
|
91
91
|
let me = this,
|
92
92
|
cls = ['far', 'fa-square'],
|
93
93
|
oldCls = ['fa', 'fa-check'],
|
94
|
-
node = VdomUtil.
|
94
|
+
node = VdomUtil.find(me.vdom, data.path[0].id).vdom;
|
95
95
|
|
96
96
|
if (data.path[0].cls.includes('fa-square')) {
|
97
97
|
cls = ['fa', 'fa-check'];
|
@@ -77,7 +77,7 @@ Use the utility method, replacing the statement referencing the vdom hierarchy.
|
|
77
77
|
|
78
78
|
<pre>
|
79
79
|
<s>view.vdom.cn[0].innerHTML = business.title;</s>
|
80
|
-
Neo.util.VDom.
|
80
|
+
Neo.util.VDom.find(view.vdom, 'title').vdom.innerHTML = business.title;
|
81
81
|
</pre>
|
82
82
|
|
83
83
|
|
@@ -86,17 +86,17 @@ calling the function.
|
|
86
86
|
|
87
87
|
Code a new class member.
|
88
88
|
|
89
|
-
|
89
|
+
find = Neo.util.VDom.find
|
90
90
|
|
91
91
|
Then use it in the after set method. Here's how that part of the code will look afterwards.
|
92
92
|
|
93
93
|
<pre style="color:gray; padding: 8px; border: thin solid lightgray;">
|
94
|
-
|
94
|
+
find = Neo.util.VDom.find;
|
95
95
|
|
96
96
|
afterSetBusiness(business){
|
97
97
|
if (!business) return;
|
98
98
|
const view = this.getReference('view');
|
99
|
-
this.
|
99
|
+
this.find(view.vdom, 'title').vdom.innerHTML = business.title;
|
100
100
|
view.update();
|
101
101
|
}
|
102
102
|
</pre>
|
@@ -129,7 +129,7 @@ Then back in the details view, update the vdom as follows.
|
|
129
129
|
|
130
130
|
Then modify the `afterSetBusiness()` method to update the element's `src`.
|
131
131
|
|
132
|
-
this.
|
132
|
+
this.find(view.vdom, 'thumbnail').vdom.src = business.imageUrl;
|
133
133
|
|
134
134
|
??Add the address
|
135
135
|
|
@@ -184,7 +184,7 @@ of thought and try it. If you get stuck, that code is given in the next lab step
|
|
184
184
|
|
185
185
|
Here's one way to code it. How does this compare to your solution?
|
186
186
|
|
187
|
-
this.
|
187
|
+
this.find(view.vdom, 'address').vdom.cn = business
|
188
188
|
.address
|
189
189
|
.map(item => ({tag: 'div', innerHTML: item}));
|
190
190
|
|
package/src/DefaultConfig.mjs
CHANGED
@@ -262,12 +262,12 @@ const DefaultConfig = {
|
|
262
262
|
useVdomWorker: true,
|
263
263
|
/**
|
264
264
|
* buildScripts/injectPackageVersion.mjs will update this value
|
265
|
-
* @default '8.
|
265
|
+
* @default '8.5.0'
|
266
266
|
* @memberOf! module:Neo
|
267
267
|
* @name config.version
|
268
268
|
* @type String
|
269
269
|
*/
|
270
|
-
version: '8.
|
270
|
+
version: '8.5.0'
|
271
271
|
};
|
272
272
|
|
273
273
|
Object.assign(DefaultConfig, {
|
package/src/component/Base.mjs
CHANGED
@@ -402,9 +402,12 @@ class Component extends Base {
|
|
402
402
|
}
|
403
403
|
|
404
404
|
/**
|
405
|
-
*
|
405
|
+
* If an update() gets called while a parent is updating, we store the id & distance of the
|
406
|
+
* requesting component inside the childUpdateCache of the parent, to get resolved once the update is done.
|
407
|
+
* e.g. childUpdateCache = {'neo-grid-view-1': {distance: 1, resolve: fn}}
|
408
|
+
* @member {Object} childUpdateCache={}
|
406
409
|
*/
|
407
|
-
childUpdateCache =
|
410
|
+
childUpdateCache = {}
|
408
411
|
/**
|
409
412
|
* Stores the updateDepth while an update is running to enable checks for parent update collisions
|
410
413
|
* @member {Number|null} currentUpdateDepth=null
|
@@ -1954,7 +1957,7 @@ class Component extends Base {
|
|
1954
1957
|
console.warn('vdom parent update conflict with:', parent, 'for:', me)
|
1955
1958
|
}
|
1956
1959
|
|
1957
|
-
|
1960
|
+
parent.childUpdateCache[me.id] = {distance, resolve};
|
1958
1961
|
|
1959
1962
|
// Adding the resolve fn to its own cache, since the parent will trigger
|
1960
1963
|
// a new update() directly on this cmp
|
@@ -2335,22 +2338,46 @@ class Component extends Base {
|
|
2335
2338
|
* @protected
|
2336
2339
|
*/
|
2337
2340
|
resolveVdomUpdate(resolve) {
|
2338
|
-
let me
|
2341
|
+
let me = this,
|
2342
|
+
hasChildUpdateCache = !Neo.isEmpty(me.childUpdateCache),
|
2343
|
+
component;
|
2339
2344
|
|
2340
2345
|
me.doResolveUpdateCache();
|
2341
2346
|
|
2342
2347
|
resolve?.();
|
2343
2348
|
|
2344
2349
|
if (me.needsVdomUpdate) {
|
2345
|
-
|
2346
|
-
|
2350
|
+
if (hasChildUpdateCache) {
|
2351
|
+
Object.entries(me.childUpdateCache).forEach(([key, value]) => {
|
2352
|
+
component = Neo.getComponent(key);
|
2353
|
+
|
2354
|
+
// The component might already got destroyed
|
2355
|
+
if (component) {
|
2356
|
+
// Pass callbacks to the resolver cache => getting executed once the following update is done
|
2357
|
+
value.resolve && NeoArray.add(me.resolveUpdateCache, value.resolve);
|
2358
|
+
|
2359
|
+
// Adjust the updateDepth to include the depth of all merged child updates
|
2360
|
+
if (me.updateDepth !== -1) {
|
2361
|
+
if (component.updateDepth === -1) {
|
2362
|
+
me.updateDepth = -1
|
2363
|
+
} else {
|
2364
|
+
// Since updateDepth is 1-based, we need to subtract 1 level
|
2365
|
+
me.updateDepth = me.updateDepth + value.distance + component.updateDepth - 1
|
2366
|
+
}
|
2367
|
+
}
|
2368
|
+
}
|
2369
|
+
});
|
2370
|
+
|
2371
|
+
me.childUpdateCache = {}
|
2372
|
+
}
|
2347
2373
|
|
2348
2374
|
me.update()
|
2349
|
-
} else if (
|
2350
|
-
|
2351
|
-
Neo.getComponent(
|
2352
|
-
|
2353
|
-
|
2375
|
+
} else if (hasChildUpdateCache) {
|
2376
|
+
Object.keys(me.childUpdateCache).forEach(key => {
|
2377
|
+
Neo.getComponent(key)?.update()
|
2378
|
+
});
|
2379
|
+
|
2380
|
+
me.childUpdateCache = {}
|
2354
2381
|
}
|
2355
2382
|
}
|
2356
2383
|
|
package/src/grid/Container.mjs
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import BaseContainer from '../container/Base.mjs';
|
2
2
|
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
3
3
|
import GridView from './View.mjs';
|
4
|
-
import RowModel from '../selection/grid/RowModel.mjs';
|
5
4
|
import Store from '../data/Store.mjs';
|
6
5
|
import * as header from './header/_export.mjs';
|
7
6
|
|
@@ -58,11 +57,6 @@ class GridContainer extends BaseContainer {
|
|
58
57
|
* @member {String|null} headerToolbarId_=null
|
59
58
|
*/
|
60
59
|
headerToolbarId_: null,
|
61
|
-
/**
|
62
|
-
* Additional used keys for the selection model
|
63
|
-
* @member {Object} keys
|
64
|
-
*/
|
65
|
-
keys: {},
|
66
60
|
/**
|
67
61
|
* @member {String} layout='base'
|
68
62
|
*/
|
@@ -81,10 +75,6 @@ class GridContainer extends BaseContainer {
|
|
81
75
|
* @protected
|
82
76
|
*/
|
83
77
|
scrollbarId_: null,
|
84
|
-
/**
|
85
|
-
* @member {Neo.selection.Model} selectionModel_=null
|
86
|
-
*/
|
87
|
-
selectionModel_: null,
|
88
78
|
/**
|
89
79
|
* @member {Boolean} showHeaderFilters_=false
|
90
80
|
*/
|
@@ -294,16 +284,6 @@ class GridContainer extends BaseContainer {
|
|
294
284
|
}
|
295
285
|
}
|
296
286
|
|
297
|
-
/**
|
298
|
-
* Triggered after the selectionModel config got changed
|
299
|
-
* @param {Neo.selection.Model} value
|
300
|
-
* @param {Neo.selection.Model} oldValue
|
301
|
-
* @protected
|
302
|
-
*/
|
303
|
-
afterSetSelectionModel(value, oldValue) {
|
304
|
-
this.rendered && value.register(this)
|
305
|
-
}
|
306
|
-
|
307
287
|
/**
|
308
288
|
* Triggered after the showHeaderFilters config got changed
|
309
289
|
* @param {Boolean} value
|
@@ -352,18 +332,6 @@ class GridContainer extends BaseContainer {
|
|
352
332
|
return value || oldValue
|
353
333
|
}
|
354
334
|
|
355
|
-
/**
|
356
|
-
* Triggered before the selectionModel config gets changed.
|
357
|
-
* @param {Neo.selection.Model} value
|
358
|
-
* @param {Neo.selection.Model} oldValue
|
359
|
-
* @protected
|
360
|
-
*/
|
361
|
-
beforeSetSelectionModel(value, oldValue) {
|
362
|
-
oldValue?.destroy();
|
363
|
-
|
364
|
-
return ClassSystemUtil.beforeSetInstance(value, RowModel)
|
365
|
-
}
|
366
|
-
|
367
335
|
/**
|
368
336
|
* Triggered before the store config gets changed.
|
369
337
|
* @param {Neo.data.Store} value
|
@@ -534,14 +502,6 @@ class GridContainer extends BaseContainer {
|
|
534
502
|
return `${this.id}__wrapper`
|
535
503
|
}
|
536
504
|
|
537
|
-
/**
|
538
|
-
*
|
539
|
-
*/
|
540
|
-
onConstructed() {
|
541
|
-
super.onConstructed();
|
542
|
-
this.selectionModel?.register(this)
|
543
|
-
}
|
544
|
-
|
545
505
|
/**
|
546
506
|
* @param {Object} data
|
547
507
|
*/
|
@@ -608,12 +568,6 @@ class GridContainer extends BaseContainer {
|
|
608
568
|
if (me.store.sorters.length < 1) {
|
609
569
|
me.removeSortingCss()
|
610
570
|
}
|
611
|
-
} else {
|
612
|
-
me.on('rendered', () => {
|
613
|
-
me.timeout(50).then(() => {
|
614
|
-
me.createViewData(data)
|
615
|
-
})
|
616
|
-
}, me, {once: true})
|
617
571
|
}
|
618
572
|
}
|
619
573
|
|
package/src/grid/View.mjs
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
import
|
2
|
-
import
|
3
|
-
import
|
1
|
+
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
2
|
+
import Component from '../component/Base.mjs';
|
3
|
+
import NeoArray from '../util/Array.mjs';
|
4
|
+
import RowModel from '../selection/grid/RowModel.mjs';
|
5
|
+
import VDomUtil from '../util/VDom.mjs';
|
4
6
|
|
5
7
|
/**
|
6
8
|
* @class Neo.grid.View
|
@@ -38,6 +40,12 @@ class GridView extends Component {
|
|
38
40
|
* @protected
|
39
41
|
*/
|
40
42
|
baseCls: ['neo-grid-view'],
|
43
|
+
/**
|
44
|
+
* The amount of columns (cells) to paint before the first & after the last visible column,
|
45
|
+
* to enhance the scrolling performance
|
46
|
+
* @member {Number} bufferColumnRange_=0
|
47
|
+
*/
|
48
|
+
bufferColumnRange_: 0,
|
41
49
|
/**
|
42
50
|
* The amount of rows to paint before the first & after the last visible row,
|
43
51
|
* to enhance the scrolling performance
|
@@ -54,6 +62,11 @@ class GridView extends Component {
|
|
54
62
|
* @protected
|
55
63
|
*/
|
56
64
|
containerId: null,
|
65
|
+
/**
|
66
|
+
* Internal flag. Gets calculated after mounting grid.View rows
|
67
|
+
* @member {Number} containerWidth_=0
|
68
|
+
*/
|
69
|
+
containerWidth_: 0,
|
57
70
|
/**
|
58
71
|
* @member {Object[]} columnPositions_=[]
|
59
72
|
* @protected
|
@@ -64,9 +77,10 @@ class GridView extends Component {
|
|
64
77
|
*/
|
65
78
|
isScrolling_: false,
|
66
79
|
/**
|
67
|
-
*
|
80
|
+
* Additional used keys for the selection model
|
81
|
+
* @member {Object} keys
|
68
82
|
*/
|
69
|
-
|
83
|
+
keys: {},
|
70
84
|
/**
|
71
85
|
* @member {String} role='rowgroup'
|
72
86
|
*/
|
@@ -80,6 +94,10 @@ class GridView extends Component {
|
|
80
94
|
* @member {Object} scrollPosition_={x:0,y:0}
|
81
95
|
*/
|
82
96
|
scrollPosition_: {x: 0, y: 0},
|
97
|
+
/**
|
98
|
+
* @member {Neo.selection.Model} selectionModel_=null
|
99
|
+
*/
|
100
|
+
selectionModel_: null,
|
83
101
|
/**
|
84
102
|
* @member {String} selectedRecordField='annotations.selected'
|
85
103
|
*/
|
@@ -92,13 +110,9 @@ class GridView extends Component {
|
|
92
110
|
* @member {Neo.data.Store|null} store_=null
|
93
111
|
*/
|
94
112
|
store_: null,
|
95
|
-
/**
|
96
|
-
* @member {Boolean} useRowRecordIds=true
|
97
|
-
*/
|
98
|
-
useRowRecordIds: true,
|
99
113
|
/**
|
100
114
|
* Stores the indexes of the first & last painted columns
|
101
|
-
* @member {
|
115
|
+
* @member {Number[]} visibleColumns_=[0,0]
|
102
116
|
* @protected
|
103
117
|
*/
|
104
118
|
visibleColumns_: [0, 0],
|
@@ -110,7 +124,7 @@ class GridView extends Component {
|
|
110
124
|
* @member {Object} _vdom
|
111
125
|
*/
|
112
126
|
_vdom:
|
113
|
-
{cn: [
|
127
|
+
{tabIndex: '-1', cn: [
|
114
128
|
{cn: []},
|
115
129
|
{cls: 'neo-grid-scrollbar'}
|
116
130
|
]}
|
@@ -132,10 +146,10 @@ class GridView extends Component {
|
|
132
146
|
* @member {String[]} selectedRows
|
133
147
|
*/
|
134
148
|
get selectedRows() {
|
135
|
-
let {
|
149
|
+
let {selectionModel} = this;
|
136
150
|
|
137
|
-
if (
|
138
|
-
return
|
151
|
+
if (selectionModel.ntype === 'selection-grid-rowmodel') {
|
152
|
+
return selectionModel.items
|
139
153
|
}
|
140
154
|
|
141
155
|
return []
|
@@ -205,6 +219,16 @@ class GridView extends Component {
|
|
205
219
|
}
|
206
220
|
}
|
207
221
|
|
222
|
+
/**
|
223
|
+
* Triggered after the bufferColumnRange config got changed
|
224
|
+
* @param {Number} value
|
225
|
+
* @param {Number} oldValue
|
226
|
+
* @protected
|
227
|
+
*/
|
228
|
+
afterSetBufferColumnRange(value, oldValue) {
|
229
|
+
oldValue !== undefined && this.createViewData()
|
230
|
+
}
|
231
|
+
|
208
232
|
/**
|
209
233
|
* Triggered after the bufferRowRange config got changed
|
210
234
|
* @param {Number} value
|
@@ -215,6 +239,18 @@ class GridView extends Component {
|
|
215
239
|
oldValue !== undefined && this.createViewData()
|
216
240
|
}
|
217
241
|
|
242
|
+
/**
|
243
|
+
* Triggered after the containerWidth config got changed
|
244
|
+
* @param {Number} value
|
245
|
+
* @param {Number} oldValue
|
246
|
+
* @protected
|
247
|
+
*/
|
248
|
+
afterSetContainerWidth(value, oldValue) {
|
249
|
+
if (value > 0 && this.columnPositions.length > 0) {
|
250
|
+
this.updateVisibleColumns()
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
218
254
|
/**
|
219
255
|
* Triggered after the columnPositions config got changed
|
220
256
|
* @param {Object[]} value
|
@@ -222,13 +258,8 @@ class GridView extends Component {
|
|
222
258
|
* @protected
|
223
259
|
*/
|
224
260
|
afterSetColumnPositions(value, oldValue) {
|
225
|
-
|
226
|
-
|
227
|
-
if (value.length > 0) {
|
228
|
-
// for changing an array inline, we need to use the leading underscore
|
229
|
-
me._visibleColumns[1] = value.length - 1;
|
230
|
-
|
231
|
-
me.createViewData()
|
261
|
+
if (value.length > 0 && this.containerWidth > 0) {
|
262
|
+
this.updateVisibleColumns()
|
232
263
|
}
|
233
264
|
}
|
234
265
|
|
@@ -291,6 +322,16 @@ class GridView extends Component {
|
|
291
322
|
}
|
292
323
|
}
|
293
324
|
|
325
|
+
/**
|
326
|
+
* Triggered after the selectionModel config got changed
|
327
|
+
* @param {Neo.selection.Model} value
|
328
|
+
* @param {Neo.selection.Model} oldValue
|
329
|
+
* @protected
|
330
|
+
*/
|
331
|
+
afterSetSelectionModel(value, oldValue) {
|
332
|
+
this.rendered && value.register(this)
|
333
|
+
}
|
334
|
+
|
294
335
|
/**
|
295
336
|
* Triggered after the startIndex config got changed
|
296
337
|
* @param {Number} value
|
@@ -322,8 +363,8 @@ class GridView extends Component {
|
|
322
363
|
|
323
364
|
/**
|
324
365
|
* Triggered after the visibleColumns config got changed
|
325
|
-
* @param {Number} value
|
326
|
-
* @param {Number} oldValue
|
366
|
+
* @param {Number[]} value
|
367
|
+
* @param {Number[]} oldValue
|
327
368
|
* @protected
|
328
369
|
*/
|
329
370
|
afterSetVisibleColumns(value, oldValue) {
|
@@ -400,8 +441,7 @@ class GridView extends Component {
|
|
400
441
|
id : cellId,
|
401
442
|
cls : cellCls,
|
402
443
|
role : 'gridcell',
|
403
|
-
style : rendererOutput.style || {}
|
404
|
-
tabIndex : '-1'
|
444
|
+
style : rendererOutput.style || {}
|
405
445
|
};
|
406
446
|
|
407
447
|
if (column.width) {
|
@@ -421,6 +461,18 @@ class GridView extends Component {
|
|
421
461
|
return cellConfig
|
422
462
|
}
|
423
463
|
|
464
|
+
/**
|
465
|
+
* Triggered before the selectionModel config gets changed.
|
466
|
+
* @param {Neo.selection.Model} value
|
467
|
+
* @param {Neo.selection.Model} oldValue
|
468
|
+
* @protected
|
469
|
+
*/
|
470
|
+
beforeSetSelectionModel(value, oldValue) {
|
471
|
+
oldValue?.destroy();
|
472
|
+
|
473
|
+
return ClassSystemUtil.beforeSetInstance(value, RowModel)
|
474
|
+
}
|
475
|
+
|
424
476
|
/**
|
425
477
|
* @param {Object} opts
|
426
478
|
* @param {Object} opts.record
|
@@ -433,13 +485,11 @@ class GridView extends Component {
|
|
433
485
|
}
|
434
486
|
|
435
487
|
let me = this,
|
436
|
-
{gridContainer, selectedRows, visibleColumns} = me,
|
488
|
+
{bufferColumnRange, gridContainer, selectedRows, visibleColumns} = me,
|
437
489
|
columns = gridContainer.items[0].items,
|
438
490
|
id = me.getRowId(record, rowIndex),
|
439
491
|
trCls = me.getTrClass(record, rowIndex),
|
440
|
-
config, column, gridRow, i;
|
441
|
-
|
442
|
-
me.recordVnodeMap[id] = rowIndex;
|
492
|
+
config, column, endIndex, gridRow, i, startIndex;
|
443
493
|
|
444
494
|
if (rowIndex % 2 !== 0) {
|
445
495
|
trCls.push('neo-even')
|
@@ -463,7 +513,6 @@ class GridView extends Component {
|
|
463
513
|
cls : trCls,
|
464
514
|
cn : [],
|
465
515
|
role : 'row',
|
466
|
-
tabIndex : '-1',
|
467
516
|
|
468
517
|
style: {
|
469
518
|
height : me.rowHeight + 'px',
|
@@ -471,7 +520,10 @@ class GridView extends Component {
|
|
471
520
|
}
|
472
521
|
};
|
473
522
|
|
474
|
-
|
523
|
+
endIndex = Math.min(columns.length - 1, visibleColumns[1] + bufferColumnRange);
|
524
|
+
startIndex = Math.max(0, visibleColumns[0] - bufferColumnRange);
|
525
|
+
|
526
|
+
for (i=startIndex; i <= endIndex; i++) {
|
475
527
|
column = columns[i];
|
476
528
|
config = me.applyRendererOutput({column, gridContainer, index: rowIndex, record});
|
477
529
|
|
@@ -495,16 +547,23 @@ class GridView extends Component {
|
|
495
547
|
*
|
496
548
|
*/
|
497
549
|
createViewData() {
|
498
|
-
let me
|
550
|
+
let me = this,
|
499
551
|
{bufferRowRange, startIndex, store} = me,
|
500
|
-
|
552
|
+
countRecords = store.getCount(),
|
553
|
+
rows = [],
|
501
554
|
endIndex, i;
|
502
555
|
|
503
|
-
if (
|
556
|
+
if (
|
557
|
+
countRecords < 1 ||
|
558
|
+
me.availableRows < 1 ||
|
559
|
+
me._containerWidth < 1 || // we are not checking me.containerWidth, since we want to ignore the config symbol
|
560
|
+
me.columnPositions.length < 1 ||
|
561
|
+
me.visibleColumns[1] < 1
|
562
|
+
) {
|
504
563
|
return
|
505
564
|
}
|
506
565
|
|
507
|
-
endIndex = Math.min(
|
566
|
+
endIndex = Math.min(countRecords, me.availableRows + startIndex + bufferRowRange);
|
508
567
|
startIndex = Math.max(0, startIndex - bufferRowRange);
|
509
568
|
|
510
569
|
for (i=startIndex; i < endIndex; i++) {
|
@@ -619,27 +678,28 @@ class GridView extends Component {
|
|
619
678
|
|
620
679
|
/**
|
621
680
|
* @param {String} rowId
|
622
|
-
* @returns {
|
681
|
+
* @returns {Record}
|
623
682
|
*/
|
624
683
|
getRecordByRowId(rowId) {
|
625
|
-
|
684
|
+
let recordId = rowId.split('__')[2],
|
685
|
+
{store} = this,
|
686
|
+
{model} = store,
|
687
|
+
keyField = model?.getField(store.getKeyProperty()),
|
688
|
+
keyType = keyField?.type?.toLowerCase();
|
689
|
+
|
690
|
+
if (keyType === 'int' || keyType === 'integer') {
|
691
|
+
recordId = parseInt(recordId)
|
692
|
+
}
|
693
|
+
|
694
|
+
return store.get(recordId)
|
626
695
|
}
|
627
696
|
|
628
697
|
/**
|
629
698
|
* @param {Object} record
|
630
|
-
* @param {Number} [index]
|
631
699
|
* @returns {String}
|
632
700
|
*/
|
633
|
-
getRowId(record
|
634
|
-
|
635
|
-
{store} = me;
|
636
|
-
|
637
|
-
if (me.useRowRecordIds) {
|
638
|
-
return `${me.id}__tr__${record[store.keyProperty]}`
|
639
|
-
} else {
|
640
|
-
index = Neo.isNumber(index) ? index : store.indexOf(record);
|
641
|
-
return me.vdom.cn[index]?.id || Neo.getId('tr')
|
642
|
-
}
|
701
|
+
getRowId(record) {
|
702
|
+
return `${this.id}__tr__${record[this.store.getKeyProperty()]}`
|
643
703
|
}
|
644
704
|
|
645
705
|
/**
|
@@ -689,6 +749,14 @@ class GridView extends Component {
|
|
689
749
|
this.fireCellEvent(data, 'cellDoubleClick')
|
690
750
|
}
|
691
751
|
|
752
|
+
/**
|
753
|
+
*
|
754
|
+
*/
|
755
|
+
onConstructed() {
|
756
|
+
super.onConstructed();
|
757
|
+
this.selectionModel?.register(this)
|
758
|
+
}
|
759
|
+
|
692
760
|
/**
|
693
761
|
* @param {Object} data
|
694
762
|
*/
|
@@ -730,7 +798,7 @@ class GridView extends Component {
|
|
730
798
|
* @param {Neo.data.Model} opts.model The model instance of the changed record
|
731
799
|
* @param {Object} opts.record
|
732
800
|
*/
|
733
|
-
onStoreRecordChange({fields,
|
801
|
+
onStoreRecordChange({fields, record}) {
|
734
802
|
let me = this,
|
735
803
|
fieldNames = fields.map(field => field.name),
|
736
804
|
needsUpdate = false,
|
@@ -787,15 +855,16 @@ class GridView extends Component {
|
|
787
855
|
*
|
788
856
|
*/
|
789
857
|
updateVisibleColumns() {
|
790
|
-
let me
|
791
|
-
{
|
792
|
-
|
793
|
-
|
794
|
-
|
858
|
+
let me = this,
|
859
|
+
{columnPositions} = me,
|
860
|
+
{x} = me.scrollPosition,
|
861
|
+
i = 0,
|
862
|
+
len = columnPositions.length,
|
863
|
+
endIndex = len - 1,
|
795
864
|
column, startIndex;
|
796
865
|
|
797
866
|
for (; i < len; i++) {
|
798
|
-
column =
|
867
|
+
column = columnPositions[i];
|
799
868
|
|
800
869
|
if (x >= column.x && x <= column.x + column.width) {
|
801
870
|
startIndex = i
|
@@ -807,7 +876,12 @@ class GridView extends Component {
|
|
807
876
|
}
|
808
877
|
}
|
809
878
|
|
810
|
-
|
879
|
+
if (
|
880
|
+
Math.abs(startIndex - me.visibleColumns[0]) >= me.bufferColumnRange ||
|
881
|
+
me.visibleColumns[1] < 1 // initial call
|
882
|
+
) {
|
883
|
+
me.visibleColumns = [startIndex, endIndex]
|
884
|
+
}
|
811
885
|
}
|
812
886
|
}
|
813
887
|
|
@@ -106,7 +106,8 @@ class Toolbar extends BaseToolbar {
|
|
106
106
|
*
|
107
107
|
*/
|
108
108
|
createItems() {
|
109
|
-
let me
|
109
|
+
let me = this,
|
110
|
+
{mounted} = me;
|
110
111
|
|
111
112
|
me.itemDefaults.showHeaderFilter = me.showHeaderFilters;
|
112
113
|
|
@@ -130,7 +131,8 @@ class Toolbar extends BaseToolbar {
|
|
130
131
|
});
|
131
132
|
|
132
133
|
me.promiseUpdate().then(() => {
|
133
|
-
|
134
|
+
// To prevent duplicate calls, we need to check the mounted state before the update call
|
135
|
+
mounted && me.passSizeToView()
|
134
136
|
})
|
135
137
|
}
|
136
138
|
|
package/src/selection/Model.mjs
CHANGED
@@ -189,11 +189,11 @@ class Model extends Base {
|
|
189
189
|
*/
|
190
190
|
register(component) {
|
191
191
|
let me = this,
|
192
|
-
cls = component.
|
192
|
+
cls = component.wrapperCls || [];
|
193
193
|
|
194
194
|
if (me.cls && !cls.includes(me.cls)) {
|
195
195
|
cls.push(me.cls);
|
196
|
-
component.
|
196
|
+
component.wrapperCls = cls
|
197
197
|
}
|
198
198
|
|
199
199
|
me.view = component;
|
@@ -30,7 +30,7 @@ class RowModel extends BaseModel {
|
|
30
30
|
addDomListener() {
|
31
31
|
let me = this;
|
32
32
|
|
33
|
-
me.view.on('rowClick', me.onRowClick, me)
|
33
|
+
me.view.gridContainer.on('rowClick', me.onRowClick, me)
|
34
34
|
}
|
35
35
|
|
36
36
|
/**
|
@@ -44,76 +44,45 @@ class RowModel extends BaseModel {
|
|
44
44
|
super.destroy(...args)
|
45
45
|
}
|
46
46
|
|
47
|
-
/**
|
48
|
-
* Finds the matching table row for a given row index
|
49
|
-
* @param {Number} index row index
|
50
|
-
* @returns {String|null} The table row node id
|
51
|
-
*/
|
52
|
-
getRowId(index) {
|
53
|
-
if (index < 0 || this.view.store.getCount() < index) {
|
54
|
-
return null
|
55
|
-
}
|
56
|
-
|
57
|
-
return this.view.vdom.cn[0].cn[1].cn[index].id
|
58
|
-
}
|
59
|
-
|
60
|
-
/**
|
61
|
-
* Finds the matching table row for a given event path
|
62
|
-
* @param {Object} path The event path
|
63
|
-
* @returns {Object|null} The node containing the table row class or null
|
64
|
-
* @protected
|
65
|
-
*/
|
66
|
-
static getRowNode(path) {
|
67
|
-
let i = 0,
|
68
|
-
len = path.length,
|
69
|
-
node = null;
|
70
|
-
|
71
|
-
for (; i < len; i++) {
|
72
|
-
if (path[i].cls.includes('neo-grid-row')) {
|
73
|
-
node = path[i]
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
return node
|
78
|
-
}
|
79
|
-
|
80
47
|
/**
|
81
48
|
* @param {Object} data
|
82
49
|
*/
|
83
50
|
onKeyDownDown(data) {
|
84
|
-
this.onNavKeyRow(
|
51
|
+
this.onNavKeyRow(1)
|
85
52
|
}
|
86
53
|
|
87
54
|
/**
|
88
55
|
* @param {Object} data
|
89
56
|
*/
|
90
57
|
onKeyDownUp(data) {
|
91
|
-
this.onNavKeyRow(
|
58
|
+
this.onNavKeyRow(-1)
|
92
59
|
}
|
93
60
|
|
94
61
|
/**
|
95
|
-
* @param {Object} data
|
96
62
|
* @param {Number} step
|
97
63
|
*/
|
98
|
-
onNavKeyRow(
|
64
|
+
onNavKeyRow(step) {
|
99
65
|
let me = this,
|
100
|
-
node = RowModel.getRowNode(data.path),
|
101
66
|
{view} = me,
|
102
67
|
{store} = view,
|
103
|
-
|
104
|
-
newIndex
|
105
|
-
|
106
|
-
|
68
|
+
currentIndex = 0,
|
69
|
+
newIndex, newRecord, rowId;
|
70
|
+
|
71
|
+
if (me.hasSelection()) {
|
72
|
+
currentIndex = store.indexOf(view.getRecordByRowId(me.items[0]))
|
73
|
+
}
|
74
|
+
|
75
|
+
newIndex = (currentIndex + step) % store.getCount();
|
107
76
|
|
108
77
|
while (newIndex < 0) {
|
109
78
|
newIndex += store.getCount()
|
110
79
|
}
|
111
80
|
|
112
|
-
|
81
|
+
newRecord = store.getAt(newIndex);
|
82
|
+
rowId = view.getRowId(newRecord);
|
113
83
|
|
114
|
-
if (
|
115
|
-
me.select(
|
116
|
-
view.focus(id);
|
84
|
+
if (rowId) {
|
85
|
+
me.select(rowId);
|
117
86
|
|
118
87
|
view.fire('select', {
|
119
88
|
record: store.getAt(newIndex)
|