neo.mjs 8.28.1 → 8.30.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/examples/ServiceWorker.mjs +2 -2
- package/examples/grid/bigData/GridContainer.mjs +12 -3
- package/examples/grid/bigData/MainModel.mjs +5 -2
- package/examples/grid/bigData/MainStore.mjs +4 -2
- package/examples/grid/nestedRecordFields/Viewport.mjs +8 -26
- package/package.json +1 -1
- package/resources/scss/src/component/Progress.scss +1 -1
- package/resources/scss/src/grid/column/AnimatedChange.scss +15 -0
- package/resources/scss/src/grid/column/Progress.scss +34 -0
- package/resources/scss/theme-dark/grid/column/Progress.scss +6 -0
- package/resources/scss/theme-light/grid/column/Progress.scss +6 -0
- package/resources/scss/theme-neo-light/grid/column/Progress.scss +6 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/Base.mjs +1 -1
- package/src/component/Progress.mjs +26 -5
- package/src/core/Observable.mjs +7 -2
- package/src/draggable/grid/header/toolbar/SortZone.mjs +1 -3
- package/src/grid/Container.mjs +52 -26
- package/src/grid/ScrollManager.mjs +1 -1
- package/src/grid/View.mjs +66 -46
- package/src/grid/column/AnimatedChange.mjs +78 -0
- package/src/grid/column/Base.mjs +81 -0
- package/src/grid/column/Component.mjs +122 -0
- package/src/grid/column/Index.mjs +42 -0
- package/src/grid/column/Progress.mjs +42 -0
- package/src/grid/column/_export.mjs +7 -0
- package/src/grid/header/Button.mjs +3 -40
- package/src/selection/grid/BaseModel.mjs +1 -1
- package/src/vdom/Helper.mjs +1 -1
package/apps/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import BaseGridContainer from '../../../src/grid/Container.mjs';
|
2
|
+
import Button from '../../../src/button/Base.mjs';
|
2
3
|
import MainStore from './MainStore.mjs';
|
3
4
|
|
4
5
|
/**
|
@@ -45,11 +46,19 @@ class GridContainer extends BaseGridContainer {
|
|
45
46
|
* @protected
|
46
47
|
*/
|
47
48
|
afterSetAmountColumns(value, oldValue) {
|
48
|
-
let i =
|
49
|
+
let i = 7,
|
49
50
|
columns = [
|
50
|
-
{dataField: 'id', text: '#', width: 60
|
51
|
+
{type: 'index', dataField: 'id', text: '#', width: 60},
|
51
52
|
{cellAlign: 'left', dataField: 'firstname', defaultSortDirection: 'ASC', text: 'Firstname', width: 150},
|
52
|
-
{cellAlign: 'left', dataField: 'lastname', defaultSortDirection: 'ASC', text: 'Lastname', width: 150}
|
53
|
+
{cellAlign: 'left', dataField: 'lastname', defaultSortDirection: 'ASC', text: 'Lastname', width: 150},
|
54
|
+
{cellAlign: 'left', dataField: 'countAction', text: 'Increase Counter', width: 150, component: ({record}) => ({
|
55
|
+
module: Button,
|
56
|
+
handler() {record.counter++},
|
57
|
+
text : record.firstname + ' ++',
|
58
|
+
width : 130
|
59
|
+
})},
|
60
|
+
{type: 'animatedChange', dataField: 'counter', text: 'Counter'},
|
61
|
+
{type: 'progress', dataField: 'progress', text: 'Progress', width: 150}
|
53
62
|
];
|
54
63
|
|
55
64
|
for (; i <= value; i++) {
|
@@ -24,11 +24,14 @@ class MainModel extends Model {
|
|
24
24
|
* @protected
|
25
25
|
*/
|
26
26
|
afterSetAmountColumns(value, oldValue) {
|
27
|
-
let i =
|
27
|
+
let i = 7,
|
28
28
|
fields = [
|
29
29
|
{name: 'id', type: 'Int'},
|
30
|
+
{name: 'countAction'},
|
31
|
+
{name: 'counter', type: 'Int'},
|
30
32
|
{name: 'firstname', type: 'String'},
|
31
|
-
{name: 'lastname', type: 'String'}
|
33
|
+
{name: 'lastname', type: 'String'},
|
34
|
+
{name: 'progress', type: 'Int'}
|
32
35
|
];
|
33
36
|
|
34
37
|
for (; i <= value; i++) {
|
@@ -113,11 +113,13 @@ class MainStore extends Store {
|
|
113
113
|
column, record;
|
114
114
|
|
115
115
|
for (; row < amountRows; row++) {
|
116
|
-
column =
|
116
|
+
column = 7;
|
117
117
|
record = {
|
118
118
|
id : row + 1,
|
119
|
+
counter : Math.round(Math.random() * 100),
|
119
120
|
firstname: me.firstnames[Math.floor(Math.random() * amountFirstnames)],
|
120
|
-
lastname : me.lastnames[ Math.floor(Math.random() * amountLastnames)]
|
121
|
+
lastname : me.lastnames[ Math.floor(Math.random() * amountLastnames)],
|
122
|
+
progress : Math.round(Math.random() * 100)
|
121
123
|
};
|
122
124
|
|
123
125
|
for (; column <= amountColumns; column++) {
|
@@ -43,7 +43,7 @@ class Viewport extends BaseViewport {
|
|
43
43
|
}]
|
44
44
|
}, {
|
45
45
|
module : GridContainer,
|
46
|
-
bind : {store
|
46
|
+
bind : {store: 'stores.mainStore'},
|
47
47
|
reference: 'grid',
|
48
48
|
|
49
49
|
columnDefaults: {
|
@@ -55,7 +55,11 @@ class Viewport extends BaseViewport {
|
|
55
55
|
{dataField: 'user.lastname', text: 'Lastname'},
|
56
56
|
{dataField: 'githubId', text: 'Github Id'},
|
57
57
|
{dataField: 'country', text: 'Country', renderer: 'up.countryRenderer'},
|
58
|
-
{dataField: 'edit', text: 'Edit Action',
|
58
|
+
{dataField: 'edit', text: 'Edit Action', component: {
|
59
|
+
module : Button,
|
60
|
+
handler: 'up.editButtonHandler',
|
61
|
+
text : 'Edit'
|
62
|
+
}}
|
59
63
|
],
|
60
64
|
|
61
65
|
viewConfig: {
|
@@ -72,8 +76,8 @@ class Viewport extends BaseViewport {
|
|
72
76
|
/**
|
73
77
|
* @param {Object} data
|
74
78
|
*/
|
75
|
-
countryRenderer({record}) {
|
76
|
-
let countryStore =
|
79
|
+
countryRenderer({gridContainer, record}) {
|
80
|
+
let countryStore = gridContainer.getStateProvider().getStore('countries');
|
77
81
|
|
78
82
|
if (countryStore.getCount() > 0) {
|
79
83
|
return countryStore.get(record.country).name
|
@@ -111,28 +115,6 @@ class Viewport extends BaseViewport {
|
|
111
115
|
}
|
112
116
|
}
|
113
117
|
|
114
|
-
/**
|
115
|
-
* @param {Object} data
|
116
|
-
*/
|
117
|
-
editRenderer({column, gridContainer, record, rowIndex}) {
|
118
|
-
let me = this,
|
119
|
-
{appName, windowId} = me,
|
120
|
-
widgetId = `${column.id}-widget-${rowIndex}`,
|
121
|
-
button = (column.widgetMap || (column.widgetMap = {}))[widgetId] || (column.widgetMap[widgetId] = Neo.create({
|
122
|
-
module : Button,
|
123
|
-
appName,
|
124
|
-
handler : 'up.editButtonHandler',
|
125
|
-
parentId: gridContainer.id,
|
126
|
-
record,
|
127
|
-
text : 'Edit',
|
128
|
-
windowId
|
129
|
-
}));
|
130
|
-
|
131
|
-
me.view.updateDepth = -1;
|
132
|
-
|
133
|
-
return button.createVdomReference()
|
134
|
-
}
|
135
|
-
|
136
118
|
/**
|
137
119
|
* @param {Object} data
|
138
120
|
*/
|
package/package.json
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
@keyframes grid-animated-cell {
|
2
|
+
50% {background-color:var(--button-ripple-background-color);}
|
3
|
+
}
|
4
|
+
|
5
|
+
.neo-grid-container {
|
6
|
+
.neo-grid-row, .neo-grid-row.neo-even {
|
7
|
+
.neo-grid-cell {
|
8
|
+
&.neo-animated {
|
9
|
+
animation-name : grid-animated-cell;
|
10
|
+
animation-duration : .4s;
|
11
|
+
animation-timing-function: ease-in-out;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
.neo-grid-cell {
|
2
|
+
.neo-progress-wrapper {
|
3
|
+
progress[value] {
|
4
|
+
appearance: none;
|
5
|
+
border : none;
|
6
|
+
display : flex;
|
7
|
+
height : var(--grid-cell-progress-height);
|
8
|
+
|
9
|
+
@-moz-document url-prefix() {
|
10
|
+
background-color: var(--grid-cell-progress-track-color);
|
11
|
+
border-radius : var(--grid-cell-progress-border-radius);
|
12
|
+
box-shadow : 0 2px 5px rgba(0, 0, 0, 0.25) inset;
|
13
|
+
}
|
14
|
+
|
15
|
+
// for webkit the progress-bar is the track
|
16
|
+
&::-webkit-progress-bar {
|
17
|
+
background-color: var(--grid-cell-progress-track-color);
|
18
|
+
border-radius : var(--grid-cell-progress-border-radius);
|
19
|
+
box-shadow : 0 2px 5px rgba(0, 0, 0, 0.25) inset;
|
20
|
+
}
|
21
|
+
|
22
|
+
// for mozilla the progress-bar is the active range
|
23
|
+
&::-moz-progress-bar {
|
24
|
+
background-color: var(--grid-cell-progress-active-color);
|
25
|
+
border-radius : var(--grid-cell-progress-border-radius);
|
26
|
+
}
|
27
|
+
|
28
|
+
&::-webkit-progress-value {
|
29
|
+
background-color: var(--grid-cell-progress-active-color);
|
30
|
+
border-radius : var(--grid-cell-progress-border-radius);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
package/src/DefaultConfig.mjs
CHANGED
@@ -263,12 +263,12 @@ const DefaultConfig = {
|
|
263
263
|
useVdomWorker: true,
|
264
264
|
/**
|
265
265
|
* buildScripts/injectPackageVersion.mjs will update this value
|
266
|
-
* @default '8.
|
266
|
+
* @default '8.30.0'
|
267
267
|
* @memberOf! module:Neo
|
268
268
|
* @name config.version
|
269
269
|
* @type String
|
270
270
|
*/
|
271
|
-
version: '8.
|
271
|
+
version: '8.30.0'
|
272
272
|
};
|
273
273
|
|
274
274
|
Object.assign(DefaultConfig, {
|
package/src/component/Base.mjs
CHANGED
@@ -451,7 +451,7 @@ class Component extends Base {
|
|
451
451
|
get parent() {
|
452
452
|
let me = this;
|
453
453
|
|
454
|
-
return me.parentComponent || me.parentId === 'document.body' ? null : Neo.getComponent(me.parentId)
|
454
|
+
return me.parentComponent || (me.parentId === 'document.body' ? null : Neo.getComponent(me.parentId))
|
455
455
|
}
|
456
456
|
|
457
457
|
/**
|
@@ -37,12 +37,25 @@ class Progress extends Base {
|
|
37
37
|
* @member {Object} _vdom
|
38
38
|
*/
|
39
39
|
_vdom:
|
40
|
-
{tag: 'div', cls: ['neo-progress'], cn: [
|
40
|
+
{tag: 'div', cls: ['neo-progress-wrapper'], cn: [
|
41
41
|
{tag: 'label'},
|
42
42
|
{tag: 'progress'}
|
43
43
|
]}
|
44
44
|
}
|
45
45
|
|
46
|
+
/**
|
47
|
+
* @member {Object} label
|
48
|
+
*/
|
49
|
+
get label() {
|
50
|
+
return this.vdom.cn[0]
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* @member {Object} progress
|
54
|
+
*/
|
55
|
+
get progress() {
|
56
|
+
return this.vdom.cn[1]
|
57
|
+
}
|
58
|
+
|
46
59
|
/**
|
47
60
|
* Triggered after the id config got changed
|
48
61
|
* @param {String} value
|
@@ -52,7 +65,7 @@ class Progress extends Base {
|
|
52
65
|
afterSetId(value, oldValue) {
|
53
66
|
super.afterSetId(value, oldValue);
|
54
67
|
|
55
|
-
this.
|
68
|
+
this.label.for = value;
|
56
69
|
this.update()
|
57
70
|
}
|
58
71
|
|
@@ -63,7 +76,15 @@ class Progress extends Base {
|
|
63
76
|
* @protected
|
64
77
|
*/
|
65
78
|
afterSetLabelText(value, oldValue) {
|
66
|
-
|
79
|
+
let {label} = this;
|
80
|
+
|
81
|
+
if (!value) {
|
82
|
+
label.removeDom = true
|
83
|
+
} else {
|
84
|
+
delete label.removeDom
|
85
|
+
}
|
86
|
+
|
87
|
+
label.html = value;
|
67
88
|
this.update()
|
68
89
|
}
|
69
90
|
|
@@ -74,7 +95,7 @@ class Progress extends Base {
|
|
74
95
|
* @protected
|
75
96
|
*/
|
76
97
|
afterSetMax(value, oldValue) {
|
77
|
-
this.
|
98
|
+
this.progress.max = value;
|
78
99
|
this.update()
|
79
100
|
}
|
80
101
|
|
@@ -85,7 +106,7 @@ class Progress extends Base {
|
|
85
106
|
* @protected
|
86
107
|
*/
|
87
108
|
afterSetValue(value, oldValue) {
|
88
|
-
this.
|
109
|
+
this.progress.value = value;
|
89
110
|
this.update()
|
90
111
|
}
|
91
112
|
|
package/src/core/Observable.mjs
CHANGED
@@ -67,6 +67,11 @@ class Observable extends Base {
|
|
67
67
|
delete name.once
|
68
68
|
}
|
69
69
|
|
70
|
+
if (name.hasOwnProperty('order')) {
|
71
|
+
order = name.order;
|
72
|
+
delete name.order
|
73
|
+
}
|
74
|
+
|
70
75
|
if (name.hasOwnProperty('scope')) {
|
71
76
|
scope = name.scope;
|
72
77
|
delete name.scope
|
@@ -74,9 +79,9 @@ class Observable extends Base {
|
|
74
79
|
|
75
80
|
Object.entries(name).forEach(([key, value]) => {
|
76
81
|
if (Neo.isObject(value)) {
|
77
|
-
me.addListener(key, {delay, once, scope, ...value})
|
82
|
+
me.addListener(key, {delay, once, order, scope, ...value})
|
78
83
|
} else {
|
79
|
-
me.addListener(key, {delay, fn: value, once, scope})
|
84
|
+
me.addListener(key, {delay, fn: value, once, order, scope})
|
80
85
|
}
|
81
86
|
})
|
82
87
|
} else if (optsType === 'object') {
|
@@ -115,9 +115,7 @@ class SortZone extends BaseSortZone {
|
|
115
115
|
*/
|
116
116
|
moveTo(fromIndex, toIndex) {
|
117
117
|
super.moveTo(fromIndex, toIndex);
|
118
|
-
|
119
|
-
// It is crucial to use _columns to not get a shallow copy
|
120
|
-
NeoArray.move(this.owner.parent._columns, fromIndex, toIndex);
|
118
|
+
this.owner.parent.columns.move(fromIndex, toIndex)
|
121
119
|
}
|
122
120
|
|
123
121
|
/**
|
package/src/grid/Container.mjs
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
import BaseContainer from '../container/Base.mjs';
|
2
2
|
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
3
|
+
import Collection from '../collection/Base.mjs';
|
3
4
|
import GridView from './View.mjs';
|
4
5
|
import ScrollManager from './ScrollManager.mjs';
|
5
6
|
import Store from '../data/Store.mjs';
|
6
7
|
import VerticalScrollbar from './VerticalScrollbar.mjs';
|
8
|
+
import * as column from './column/_export.mjs';
|
7
9
|
import * as header from './header/_export.mjs';
|
8
10
|
|
9
11
|
/**
|
@@ -11,6 +13,18 @@ import * as header from './header/_export.mjs';
|
|
11
13
|
* @extends Neo.container.Base
|
12
14
|
*/
|
13
15
|
class GridContainer extends BaseContainer {
|
16
|
+
/**
|
17
|
+
* @member {Object} columnTypes
|
18
|
+
* @protected
|
19
|
+
* @static
|
20
|
+
*/
|
21
|
+
static columnTypes = {
|
22
|
+
animatedChange: column.AnimatedChange,
|
23
|
+
column : column.Base,
|
24
|
+
component : column.Component,
|
25
|
+
index : column.Index,
|
26
|
+
progress : column.Progress
|
27
|
+
}
|
14
28
|
/**
|
15
29
|
* @member {Object} delayable
|
16
30
|
* @protected
|
@@ -182,7 +196,7 @@ class GridContainer extends BaseContainer {
|
|
182
196
|
|
183
197
|
me.vdom.id = me.getWrapperId();
|
184
198
|
|
185
|
-
me.createColumns(me.columns);
|
199
|
+
me._columns = me.createColumns(me.columns);
|
186
200
|
|
187
201
|
me.addDomListeners({
|
188
202
|
resize: me.onResize,
|
@@ -235,19 +249,15 @@ class GridContainer extends BaseContainer {
|
|
235
249
|
|
236
250
|
/**
|
237
251
|
* Triggered after the columns config got changed
|
238
|
-
* @param {
|
239
|
-
* @param {Object[]|null} oldValue
|
252
|
+
* @param {Neo.collection.Base|null} value
|
253
|
+
* @param {Object[]|Neo.collection.Base|null} oldValue
|
240
254
|
* @protected
|
241
255
|
*/
|
242
256
|
async afterSetColumns(value, oldValue) {
|
243
|
-
if (oldValue?.
|
244
|
-
let me
|
245
|
-
{headerToolbar} = me;
|
257
|
+
if (oldValue?.getCount?.() > 0) {
|
258
|
+
let me = this;
|
246
259
|
|
247
|
-
|
248
|
-
headerToolbar.items = value;
|
249
|
-
headerToolbar.createItems()
|
250
|
-
}
|
260
|
+
me.headerToolbar?.createItems()
|
251
261
|
|
252
262
|
await me.timeout(50);
|
253
263
|
|
@@ -413,41 +423,57 @@ class GridContainer extends BaseContainer {
|
|
413
423
|
createColumns(columns) {
|
414
424
|
let me = this,
|
415
425
|
{columnDefaults} = me,
|
426
|
+
headerButtons = [],
|
416
427
|
sorters = me.store?.sorters,
|
417
|
-
renderer;
|
418
|
-
|
419
|
-
if (!columns || !columns.length) {
|
420
|
-
Neo.logError('Attempting to create a grid.Container without defined columns', me.id);
|
421
|
-
}
|
428
|
+
columnClass, renderer;
|
422
429
|
|
423
|
-
columns
|
430
|
+
columns?.forEach((column, index) => {
|
424
431
|
renderer = column.renderer;
|
425
432
|
|
426
433
|
columnDefaults && Neo.assignDefaults(column, columnDefaults);
|
427
434
|
|
428
|
-
if (column.dock && !column.width) {
|
429
|
-
Neo.logError('Attempting to create a docked column without a defined width', column, me.id);
|
430
|
-
}
|
431
|
-
|
432
435
|
if (renderer && Neo.isString(renderer) && me[renderer]) {
|
433
436
|
column.renderer = me[renderer]
|
434
437
|
}
|
435
438
|
|
436
|
-
if (sorters?.[0]) {
|
437
|
-
|
438
|
-
column.isSorted = sorters[0].direction
|
439
|
-
}
|
439
|
+
if (sorters?.[0] && column.dataField === sorters[0].property) {
|
440
|
+
column.isSorted = sorters[0].direction
|
440
441
|
}
|
441
442
|
|
442
443
|
column.listeners = {
|
443
444
|
sort : me.onSortColumn,
|
444
445
|
scope: me
|
446
|
+
};
|
447
|
+
|
448
|
+
headerButtons.push(column);
|
449
|
+
|
450
|
+
if (column.component && !column.type) {
|
451
|
+
column.type = 'component'
|
445
452
|
}
|
453
|
+
|
454
|
+
columnClass = me.constructor.columnTypes[column.type || 'column'];
|
455
|
+
delete column.type;
|
456
|
+
|
457
|
+
columns[index] = Neo.create(columnClass, {
|
458
|
+
parent : me,
|
459
|
+
windowId: me.windowId,
|
460
|
+
...column
|
461
|
+
})
|
446
462
|
});
|
447
463
|
|
448
|
-
me.items[0].items =
|
464
|
+
me.items[0].items = headerButtons;
|
449
465
|
|
450
|
-
|
466
|
+
if (Neo.typeOf(me._columns) === 'NeoInstance') {
|
467
|
+
me._columns.clear();
|
468
|
+
me._columns.add(columns);
|
469
|
+
|
470
|
+
return me._columns
|
471
|
+
}
|
472
|
+
|
473
|
+
return Neo.create(Collection, {
|
474
|
+
keyProperty: 'dataField',
|
475
|
+
items : columns
|
476
|
+
})
|
451
477
|
}
|
452
478
|
|
453
479
|
/**
|
package/src/grid/View.mjs
CHANGED
@@ -388,7 +388,7 @@ class GridView extends Component {
|
|
388
388
|
fieldValue = ''
|
389
389
|
}
|
390
390
|
|
391
|
-
rendererOutput = column.renderer.call(column.rendererScope ||
|
391
|
+
rendererOutput = column.renderer.call(column.rendererScope || column, {
|
392
392
|
column,
|
393
393
|
columnIndex,
|
394
394
|
dataField,
|
@@ -512,7 +512,7 @@ class GridView extends Component {
|
|
512
512
|
let me = this,
|
513
513
|
{mountedColumns, selectedRows} = me,
|
514
514
|
gridContainer = me.parent,
|
515
|
-
columns
|
515
|
+
{columns} = gridContainer,
|
516
516
|
id = me.getRowId(record, rowIndex),
|
517
517
|
rowCls = me.getRowClass(record, rowIndex),
|
518
518
|
config, column, columnPosition, gridRow, i;
|
@@ -544,7 +544,7 @@ class GridView extends Component {
|
|
544
544
|
};
|
545
545
|
|
546
546
|
for (i=mountedColumns[0]; i <= mountedColumns[1]; i++) {
|
547
|
-
column = columns
|
547
|
+
column = columns.getAt(i);
|
548
548
|
config = me.applyRendererOutput({column, columnIndex: i, record, rowIndex});
|
549
549
|
|
550
550
|
if (column.dock) {
|
@@ -661,17 +661,11 @@ class GridView extends Component {
|
|
661
661
|
* @returns {Object|Number|null}
|
662
662
|
*/
|
663
663
|
getColumn(field, returnIndex=false) {
|
664
|
-
let columns = this.parent
|
665
|
-
|
666
|
-
len = columns.length,
|
667
|
-
column;
|
664
|
+
let {columns} = this.parent,
|
665
|
+
column = columns.get(field);
|
668
666
|
|
669
|
-
|
670
|
-
column
|
671
|
-
|
672
|
-
if (column.dataField === field) {
|
673
|
-
return returnIndex ? i : column
|
674
|
-
}
|
667
|
+
if (column) {
|
668
|
+
return returnIndex ? columns.indexOf(column) : column
|
675
669
|
}
|
676
670
|
|
677
671
|
return null
|
@@ -856,51 +850,42 @@ class GridView extends Component {
|
|
856
850
|
}
|
857
851
|
|
858
852
|
/**
|
859
|
-
*
|
860
|
-
*
|
861
|
-
* @param {
|
862
|
-
* @param {Object
|
863
|
-
* @param {Neo.data.Model} opts.model The model instance of the changed record
|
864
|
-
* @param {Object} opts.record
|
853
|
+
* @param {Object} data
|
854
|
+
* @param {Object[]} data.fields Each field object contains the keys: name, oldValue, value
|
855
|
+
* @param {Neo.data.Model} data.model The model instance of the changed record
|
856
|
+
* @param {Object} data.record
|
865
857
|
*/
|
866
858
|
onStoreRecordChange({fields, record}) {
|
867
|
-
let me
|
868
|
-
fieldNames
|
869
|
-
needsUpdate
|
870
|
-
rowIndex
|
871
|
-
{selectionModel
|
872
|
-
|
859
|
+
let me = this,
|
860
|
+
fieldNames = fields.map(field => field.name),
|
861
|
+
needsUpdate = false,
|
862
|
+
rowIndex = me.store.indexOf(record),
|
863
|
+
{selectionModel} = me,
|
864
|
+
column, needsCellUpdate;
|
873
865
|
|
874
866
|
if (fieldNames.includes(me.colspanField)) {
|
875
867
|
me.vdom.cn[rowIndex] = me.createRow({record, rowIndex});
|
876
868
|
me.update()
|
877
869
|
} else {
|
870
|
+
for (column of me.parent.columns.items) {
|
871
|
+
if (
|
872
|
+
column instanceof Neo.grid.column.Component &&
|
873
|
+
Neo.typeOf(column.component === 'Function') &&
|
874
|
+
!fieldNames.includes(column.dataField)
|
875
|
+
) {
|
876
|
+
needsCellUpdate = me.updateCellNode(record, column.dataField);
|
877
|
+
needsUpdate = needsUpdate || needsCellUpdate
|
878
|
+
}
|
879
|
+
}
|
880
|
+
|
878
881
|
fields.forEach(field => {
|
879
882
|
if (field.name === me.selectedRecordField) {
|
880
883
|
if (selectionModel.ntype === 'selection-grid-rowmodel') {
|
881
884
|
selectionModel[field.value ? 'select' : 'deselect'](me.getRowId(record))
|
882
885
|
}
|
883
886
|
} else {
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
// The vdom might not exist yet => nothing to do in this case
|
888
|
-
if (cellNode?.vdom) {
|
889
|
-
cellStyle = cellNode.vdom.style;
|
890
|
-
column = me.getColumn(field.name);
|
891
|
-
columnIndex = cellNode.index;
|
892
|
-
cellVdom = me.applyRendererOutput({cellId, column, columnIndex, record, rowIndex});
|
893
|
-
needsUpdate = true;
|
894
|
-
|
895
|
-
// The cell-positioning logic happens outside applyRendererOutput()
|
896
|
-
// We need to preserve these styles
|
897
|
-
Object.assign(cellVdom.style, {
|
898
|
-
left : cellStyle.left,
|
899
|
-
width: cellStyle.width
|
900
|
-
});
|
901
|
-
|
902
|
-
cellNode.parentNode.cn[columnIndex] = cellVdom
|
903
|
-
}
|
887
|
+
needsCellUpdate = me.updateCellNode(record, field.name);
|
888
|
+
needsUpdate = needsUpdate || needsCellUpdate
|
904
889
|
}
|
905
890
|
})
|
906
891
|
}
|
@@ -957,6 +942,41 @@ class GridView extends Component {
|
|
957
942
|
}
|
958
943
|
}
|
959
944
|
|
945
|
+
/**
|
946
|
+
* Update the cell vdom silently
|
947
|
+
* @param {Record} record
|
948
|
+
* @param {String} dataField
|
949
|
+
* @returns {Boolean} true in case the view needs an update
|
950
|
+
*/
|
951
|
+
updateCellNode(record, dataField) {
|
952
|
+
let me = this,
|
953
|
+
cellId = me.getCellId(record, dataField),
|
954
|
+
cellNode = VDomUtil.find(me.vdom, cellId),
|
955
|
+
needsUpdate = false,
|
956
|
+
rowIndex = me.store.indexOf(record),
|
957
|
+
cellStyle, cellVdom, column, columnIndex;
|
958
|
+
|
959
|
+
// The vdom might not exist yet => nothing to do in this case
|
960
|
+
if (cellNode?.vdom) {
|
961
|
+
cellStyle = cellNode.vdom.style;
|
962
|
+
column = me.getColumn(dataField);
|
963
|
+
columnIndex = cellNode.index;
|
964
|
+
cellVdom = me.applyRendererOutput({cellId, column, columnIndex, record, rowIndex});
|
965
|
+
needsUpdate = true;
|
966
|
+
|
967
|
+
// The cell-positioning logic happens outside applyRendererOutput()
|
968
|
+
// We need to preserve these styles
|
969
|
+
Object.assign(cellVdom.style, {
|
970
|
+
left : cellStyle.left,
|
971
|
+
width: cellStyle.width
|
972
|
+
});
|
973
|
+
|
974
|
+
cellNode.parentNode.cn[columnIndex] = cellVdom
|
975
|
+
}
|
976
|
+
|
977
|
+
return needsUpdate
|
978
|
+
}
|
979
|
+
|
960
980
|
/**
|
961
981
|
*
|
962
982
|
*/
|
@@ -1013,7 +1033,7 @@ class GridView extends Component {
|
|
1013
1033
|
endIndex = Math.min(countRecords, endIndex + bufferRowRange);
|
1014
1034
|
|
1015
1035
|
me.mountedRows[0] = startIndex; // update the array inline
|
1016
|
-
me.mountedRows[1] = endIndex
|
1036
|
+
me.mountedRows[1] = endIndex
|
1017
1037
|
}
|
1018
1038
|
|
1019
1039
|
/**
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import Column from './Base.mjs';
|
2
|
+
import NeoArray from '../../util/Array.mjs';
|
3
|
+
import VdomUtil from '../../util/VDom.mjs';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @class Neo.grid.column.AnimatedChange
|
7
|
+
* @extends Neo.grid.column.Base
|
8
|
+
*/
|
9
|
+
class AnimatedChange extends Column {
|
10
|
+
static config = {
|
11
|
+
/**
|
12
|
+
* @member {String} className='Neo.grid.column.AnimatedChange'
|
13
|
+
* @protected
|
14
|
+
*/
|
15
|
+
className: 'Neo.grid.column.AnimatedChange',
|
16
|
+
/**
|
17
|
+
* @member {String} animationCls='neo-animated'
|
18
|
+
*/
|
19
|
+
animationCls: 'neo-animated',
|
20
|
+
/**
|
21
|
+
* @member {String} type='animatedChange'
|
22
|
+
* @protected
|
23
|
+
*/
|
24
|
+
type: 'animatedChange'
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @param {Object} config
|
29
|
+
*/
|
30
|
+
construct(config) {
|
31
|
+
super.construct(config);
|
32
|
+
|
33
|
+
let me = this;
|
34
|
+
|
35
|
+
me.parent.store.on({
|
36
|
+
recordChange: me.onRecordChange,
|
37
|
+
scope : me
|
38
|
+
})
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* Override as needed for dynamic record-based animation classes
|
43
|
+
* @param {Record} record
|
44
|
+
* @returns {String}
|
45
|
+
*/
|
46
|
+
getAnimationCls(record) {
|
47
|
+
return this.animationCls
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* @param {Object} data
|
52
|
+
* @param {Object[]} data.fields Each field object contains the keys: name, oldValue, value
|
53
|
+
* @param {Neo.data.Model} data.model The model instance of the changed record
|
54
|
+
* @param {Object} data.record
|
55
|
+
*/
|
56
|
+
onRecordChange({fields, record}) {
|
57
|
+
let me = this,
|
58
|
+
{view} = me.parent,
|
59
|
+
cellId, field, node;
|
60
|
+
|
61
|
+
for (field of fields) {
|
62
|
+
if (field.name === me.dataField) {
|
63
|
+
cellId = view.getCellId(record, me.dataField);
|
64
|
+
node = VdomUtil.find(view.vdom, cellId)?.vdom;
|
65
|
+
|
66
|
+
NeoArray.add(node.cls, me.getAnimationCls(record));
|
67
|
+
|
68
|
+
// This will trigger a 2nd view update, after grid.View: onStoreRecordChange()
|
69
|
+
// It is crucial to restart the keyframe based animation
|
70
|
+
// => The previous update call will remove the last animationCls
|
71
|
+
view.update();
|
72
|
+
break
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
export default Neo.setupClass(AnimatedChange);
|
@@ -0,0 +1,81 @@
|
|
1
|
+
import Base from '../../core/Base.mjs';
|
2
|
+
import {resolveCallback} from '../../util/Function.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Neo.grid.column.Base
|
6
|
+
* @extends Neo.core.Base
|
7
|
+
*/
|
8
|
+
class Column extends Base {
|
9
|
+
static config = {
|
10
|
+
/**
|
11
|
+
* @member {String} className='Neo.grid.column.Base'
|
12
|
+
* @protected
|
13
|
+
*/
|
14
|
+
className: 'Neo.grid.column.Base',
|
15
|
+
/**
|
16
|
+
* @member {String|null} dataField=null
|
17
|
+
*/
|
18
|
+
dataField: null,
|
19
|
+
/**
|
20
|
+
* @member {Neo.grid.Container|null} parent=null
|
21
|
+
*/
|
22
|
+
parent: null,
|
23
|
+
/**
|
24
|
+
* @member {Function|String|null} renderer_='cellRenderer'
|
25
|
+
*/
|
26
|
+
renderer_: 'cellRenderer',
|
27
|
+
/**
|
28
|
+
* Scope to execute the column renderer.
|
29
|
+
* Defaults to the column instance
|
30
|
+
* @member {Neo.core.Base|null} rendererScope=null
|
31
|
+
*/
|
32
|
+
rendererScope: null,
|
33
|
+
/**
|
34
|
+
* @member {String} type='column'
|
35
|
+
* @protected
|
36
|
+
*/
|
37
|
+
type: 'column',
|
38
|
+
/**
|
39
|
+
* @member {Number|null} windowId_=null
|
40
|
+
*/
|
41
|
+
windowId_: null
|
42
|
+
}
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Triggered after the windowId config got changed
|
46
|
+
* @param {Number} value
|
47
|
+
* @param {Number|null} oldValue
|
48
|
+
* @protected
|
49
|
+
*/
|
50
|
+
afterSetWindowId(value, oldValue) {
|
51
|
+
value && Neo.currentWorker.insertThemeFiles(value, this.__proto__)
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Triggered before the renderer config gets changed
|
56
|
+
* @param {Function|String|null} value
|
57
|
+
* @param {Function|String|null} oldValue
|
58
|
+
* @protected
|
59
|
+
*/
|
60
|
+
beforeSetRenderer(value, oldValue) {
|
61
|
+
return resolveCallback(value, this).fn
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* @param {Object} data
|
66
|
+
* @param {Neo.button.Base} data.column
|
67
|
+
* @param {Number} data.columnIndex
|
68
|
+
* @param {String} data.dataField
|
69
|
+
* @param {Neo.grid.Container} data.gridContainer
|
70
|
+
* @param {Object} data.record
|
71
|
+
* @param {Number} data.rowIndex
|
72
|
+
* @param {Neo.data.Store} data.store
|
73
|
+
* @param {Number|String} data.value
|
74
|
+
* @returns {*}
|
75
|
+
*/
|
76
|
+
cellRenderer(data) {
|
77
|
+
return data.value
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
export default Neo.setupClass(Column);
|
@@ -0,0 +1,122 @@
|
|
1
|
+
import Column from './Base.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class Neo.grid.column.Component
|
5
|
+
* @extends Neo.grid.column.Base
|
6
|
+
*/
|
7
|
+
class Component extends Column {
|
8
|
+
static config = {
|
9
|
+
/**
|
10
|
+
* @member {String} className='Neo.grid.column.Component'
|
11
|
+
* @protected
|
12
|
+
*/
|
13
|
+
className: 'Neo.grid.column.Component',
|
14
|
+
/**
|
15
|
+
* @member {Function|Object|null} component=null
|
16
|
+
*/
|
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',
|
32
|
+
/**
|
33
|
+
* @member {String} type='component'
|
34
|
+
* @protected
|
35
|
+
*/
|
36
|
+
type: 'component'
|
37
|
+
}
|
38
|
+
|
39
|
+
/**
|
40
|
+
* @member {Map} map=new Map()
|
41
|
+
* @protected
|
42
|
+
*/
|
43
|
+
map = new Map()
|
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
|
+
|
55
|
+
/**
|
56
|
+
* @param {Object} data
|
57
|
+
* @param {Neo.column.Base} data.column
|
58
|
+
* @param {Number} data.columnIndex
|
59
|
+
* @param {String} data.dataField
|
60
|
+
* @param {Neo.grid.Container} data.gridContainer
|
61
|
+
* @param {Object} data.record
|
62
|
+
* @param {Number} data.rowIndex
|
63
|
+
* @param {Neo.data.Store} data.store
|
64
|
+
* @param {Number|String} data.value
|
65
|
+
* @returns {*}
|
66
|
+
*/
|
67
|
+
cellRenderer(data) {
|
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;
|
75
|
+
|
76
|
+
if (Neo.typeOf(componentConfig) === 'Function') {
|
77
|
+
componentConfig = componentConfig(data)
|
78
|
+
}
|
79
|
+
|
80
|
+
componentConfig = me.applyRecordConfigs(componentConfig, record);
|
81
|
+
|
82
|
+
if (component) {
|
83
|
+
delete componentConfig.className;
|
84
|
+
delete componentConfig.module;
|
85
|
+
delete componentConfig.ntype;
|
86
|
+
|
87
|
+
|
88
|
+
componentConfig[recordProperty] = record;
|
89
|
+
|
90
|
+
component.set(componentConfig)
|
91
|
+
} else {
|
92
|
+
component = Neo.create({
|
93
|
+
...me.defaults,
|
94
|
+
...componentConfig,
|
95
|
+
appName,
|
96
|
+
id,
|
97
|
+
parentComponent : view,
|
98
|
+
[recordProperty]: record,
|
99
|
+
windowId
|
100
|
+
});
|
101
|
+
|
102
|
+
me.map.set(id, component)
|
103
|
+
}
|
104
|
+
|
105
|
+
view.updateDepth = -1;
|
106
|
+
|
107
|
+
return component.createVdomReference()
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* @param {Number} rowIndex
|
112
|
+
* @returns {String}
|
113
|
+
*/
|
114
|
+
getComponentId(rowIndex) {
|
115
|
+
let me = this,
|
116
|
+
{view} = me.parent;
|
117
|
+
|
118
|
+
return `${me.id}-component-${rowIndex % (view.availableRows + 2 * view.bufferRowRange)}`
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
export default Neo.setupClass(Component);
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import Column from './Base.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class Neo.grid.column.Index
|
5
|
+
* @extends Neo.grid.column.Base
|
6
|
+
*/
|
7
|
+
class Index extends Column {
|
8
|
+
static config = {
|
9
|
+
/**
|
10
|
+
* @member {String} className='Neo.grid.column.Index'
|
11
|
+
* @protected
|
12
|
+
*/
|
13
|
+
className: 'Neo.grid.column.Index',
|
14
|
+
/**
|
15
|
+
* @member {String} type='index'
|
16
|
+
* @protected
|
17
|
+
*/
|
18
|
+
type: 'index',
|
19
|
+
/**
|
20
|
+
* @member {Boolean} zeroBased=false
|
21
|
+
*/
|
22
|
+
zeroBased: false
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @param {Object} data
|
27
|
+
* @param {Neo.button.Base} data.column
|
28
|
+
* @param {Number} data.columnIndex
|
29
|
+
* @param {String} data.dataField
|
30
|
+
* @param {Neo.grid.Container} data.gridContainer
|
31
|
+
* @param {Object} data.record
|
32
|
+
* @param {Number} data.rowIndex
|
33
|
+
* @param {Neo.data.Store} data.store
|
34
|
+
* @param {Number|String} data.value
|
35
|
+
* @returns {*}
|
36
|
+
*/
|
37
|
+
cellRenderer({rowIndex}) {
|
38
|
+
return rowIndex + (this.zeroBased ? 0 : 1)
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
export default Neo.setupClass(Index);
|
@@ -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);
|
@@ -1,7 +1,6 @@
|
|
1
|
-
import BaseButton
|
2
|
-
import NeoArray
|
3
|
-
import TextField
|
4
|
-
import {resolveCallback} from '../../util/Function.mjs';
|
1
|
+
import BaseButton from '../../button/Base.mjs';
|
2
|
+
import NeoArray from '../../util/Array.mjs';
|
3
|
+
import TextField from '../../form/field/Text.mjs';
|
5
4
|
|
6
5
|
/**
|
7
6
|
* @class Neo.grid.header.Button
|
@@ -72,16 +71,6 @@ class Button extends BaseButton {
|
|
72
71
|
* @protected
|
73
72
|
*/
|
74
73
|
isSorted_: null,
|
75
|
-
/**
|
76
|
-
* @member {Function|String|null} renderer_='cellRenderer'
|
77
|
-
*/
|
78
|
-
renderer_: 'cellRenderer',
|
79
|
-
/**
|
80
|
-
* Scope to execute the column renderer.
|
81
|
-
* Defaults to the matching grid.Container
|
82
|
-
* @member {Neo.core.Base|null} rendererScope=null
|
83
|
-
*/
|
84
|
-
rendererScope: null,
|
85
74
|
/**
|
86
75
|
* @member {String} role='columnheader'
|
87
76
|
*/
|
@@ -217,32 +206,6 @@ class Button extends BaseButton {
|
|
217
206
|
return this.beforeSetEnumValue(value, oldValue, 'cellAlign', 'cellAlignValues')
|
218
207
|
}
|
219
208
|
|
220
|
-
/**
|
221
|
-
* Triggered before the renderer config gets changed
|
222
|
-
* @param {Function|String|null} value
|
223
|
-
* @param {Function|String|null} oldValue
|
224
|
-
* @protected
|
225
|
-
*/
|
226
|
-
beforeSetRenderer(value, oldValue) {
|
227
|
-
return resolveCallback(value, this).fn
|
228
|
-
}
|
229
|
-
|
230
|
-
/**
|
231
|
-
* @param {Object} data
|
232
|
-
* @param {Neo.button.Base} data.column
|
233
|
-
* @param {Number} data.columnIndex
|
234
|
-
* @param {String} data.dataField
|
235
|
-
* @param {Neo.grid.Container} data.gridContainer
|
236
|
-
* @param {Object} data.record
|
237
|
-
* @param {Number} data.rowIndex
|
238
|
-
* @param {Neo.data.Store} data.store
|
239
|
-
* @param {Number|String} data.value
|
240
|
-
* @returns {*}
|
241
|
-
*/
|
242
|
-
cellRenderer(data) {
|
243
|
-
return data.value
|
244
|
-
}
|
245
|
-
|
246
209
|
/**
|
247
210
|
*
|
248
211
|
*/
|
package/src/vdom/Helper.mjs
CHANGED
@@ -250,7 +250,7 @@ class Helper extends Base {
|
|
250
250
|
return deltas
|
251
251
|
}
|
252
252
|
|
253
|
-
if (vnodeId !== oldVnodeId) {
|
253
|
+
if (vnodeId !== oldVnodeId && vnode.componentId !== oldVnode.componentId) {
|
254
254
|
throw new Error(`createDeltas() must get called for the same node. ${vnodeId}, ${oldVnodeId}`);
|
255
255
|
}
|
256
256
|
|