neo.mjs 8.0.0-beta.2 → 8.0.1
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/covid/view/MainContainerController.mjs +7 -4
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/about/Container.mjs +0 -2
- package/apps/portal/view/about/MemberContainer.mjs +1 -20
- package/apps/portal/view/home/FooterContainer.mjs +1 -5
- package/apps/sharedcovid/view/MainContainerController.mjs +7 -4
- package/examples/ConfigurationViewport.mjs +37 -32
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/calendar/weekview/MainContainer.mjs +6 -6
- package/examples/grid/cellEditing/MainContainer.mjs +175 -0
- package/examples/grid/cellEditing/MainContainerStateProvider.mjs +62 -0
- package/examples/grid/cellEditing/MainModel.mjs +30 -0
- package/examples/grid/cellEditing/MainStore.mjs +54 -0
- package/examples/grid/cellEditing/app.mjs +6 -0
- package/examples/grid/cellEditing/index.html +11 -0
- package/examples/grid/cellEditing/neo-config.json +6 -0
- package/examples/grid/container/MainContainer.mjs +7 -6
- package/examples/grid/covid/GridContainer.mjs +36 -36
- package/examples/grid/covid/Util.mjs +1 -1
- package/examples/table/cellEditing/MainContainer.mjs +174 -0
- package/examples/table/cellEditing/MainContainerStateProvider.mjs +62 -0
- package/examples/table/cellEditing/MainModel.mjs +30 -0
- package/examples/table/cellEditing/MainStore.mjs +54 -0
- package/examples/table/cellEditing/app.mjs +6 -0
- package/examples/table/cellEditing/index.html +11 -0
- package/examples/table/cellEditing/neo-config.json +6 -0
- package/examples/table/nestedRecordFields/MainContainerStateProvider.mjs +2 -1
- package/package.json +8 -8
- package/resources/scss/src/apps/portal/home/FooterContainer.scss +11 -2
- package/resources/scss/src/grid/Container.scss +0 -13
- package/resources/scss/src/grid/plugin/CellEditing.scss +11 -0
- package/resources/scss/src/table/plugin/CellEditing.scss +11 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/Neo.mjs +2 -2
- package/src/code/LivePreview.mjs +2 -2
- package/src/component/DateSelector.mjs +15 -0
- package/src/core/Base.mjs +1 -1
- package/src/form/field/Base.mjs +1 -4
- package/src/form/field/ComboBox.mjs +18 -2
- package/src/form/field/Date.mjs +10 -4
- package/src/grid/Container.mjs +242 -39
- package/src/grid/README.md +1 -1
- package/src/grid/View.mjs +282 -129
- package/src/grid/header/Button.mjs +327 -36
- package/src/grid/header/Toolbar.mjs +68 -4
- package/src/grid/plugin/CellEditing.mjs +30 -0
- package/src/main/DomEvents.mjs +12 -3
- package/src/manager/Focus.mjs +2 -2
- package/src/plugin/Base.mjs +15 -1
- package/src/plugin/Resizable.mjs +1 -5
- package/src/selection/Model.mjs +5 -1
- package/src/selection/grid/CellColumnModel.mjs +1 -1
- package/src/selection/grid/CellColumnRowModel.mjs +1 -1
- package/src/selection/grid/CellModel.mjs +1 -1
- package/src/selection/grid/ColumnModel.mjs +2 -2
- package/src/table/Container.mjs +32 -3
- package/src/table/View.mjs +9 -4
- package/src/table/header/Toolbar.mjs +15 -1
- package/src/table/plugin/CellEditing.mjs +330 -0
- package/src/tooltip/Base.mjs +17 -17
- package/src/util/KeyNavigation.mjs +14 -8
- package/src/vdom/Helper.mjs +1 -3
package/src/grid/View.mjs
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import Component from '../component/Base.mjs';
|
2
|
+
import NeoArray from '../util/Array.mjs';
|
2
3
|
import VDomUtil from '../util/VDom.mjs';
|
3
4
|
|
4
5
|
/**
|
@@ -20,7 +21,46 @@ class View extends Component {
|
|
20
21
|
/**
|
21
22
|
* @member {String[]} baseCls=['neo-grid-view']
|
22
23
|
*/
|
23
|
-
baseCls: ['neo-grid-view']
|
24
|
+
baseCls: ['neo-grid-view'],
|
25
|
+
/**
|
26
|
+
* Define which model field contains the value of colspan definitions
|
27
|
+
* @member {String} colspanField='colspan'
|
28
|
+
*/
|
29
|
+
colspanField: 'colspan',
|
30
|
+
/**
|
31
|
+
* @member {String|null} containerId=null
|
32
|
+
* @protected
|
33
|
+
*/
|
34
|
+
containerId: null,
|
35
|
+
/**
|
36
|
+
* @member {Object} recordVnodeMap={}
|
37
|
+
*/
|
38
|
+
recordVnodeMap: {},
|
39
|
+
/**
|
40
|
+
* @member {String} selectedRecordField='annotations.selected'
|
41
|
+
*/
|
42
|
+
selectedRecordField: 'annotations.selected',
|
43
|
+
/**
|
44
|
+
* @member {Neo.data.Store|null} store=null
|
45
|
+
*/
|
46
|
+
store: null,
|
47
|
+
/**
|
48
|
+
* @member {Boolean} useRowRecordIds=true
|
49
|
+
*/
|
50
|
+
useRowRecordIds: true
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* @member {String[]} selectedRows
|
55
|
+
*/
|
56
|
+
get selectedRows() {
|
57
|
+
let gridContainer = this.parent;
|
58
|
+
|
59
|
+
if (gridContainer.selectionModel.ntype === 'selection-grid-rowmodel') {
|
60
|
+
return gridContainer.selectionModel.items
|
61
|
+
}
|
62
|
+
|
63
|
+
return []
|
24
64
|
}
|
25
65
|
|
26
66
|
/**
|
@@ -45,149 +85,211 @@ class View extends Component {
|
|
45
85
|
}
|
46
86
|
|
47
87
|
/**
|
48
|
-
* @param {
|
88
|
+
* @param {Object} data
|
89
|
+
* @param {String} [data.cellId]
|
90
|
+
* @param {Object} data.column
|
91
|
+
* @param {Neo.grid.Container} data.gridContainer
|
92
|
+
* @param {Number} data.index
|
93
|
+
* @param {Object} data.record
|
94
|
+
* @returns {Object}
|
49
95
|
*/
|
50
|
-
|
51
|
-
let
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
me.recordVnodeMap = {}; // remove old data
|
63
|
-
|
64
|
-
if (container.selectionModel?.ntype === 'selection-grid-rowmodel') {
|
65
|
-
selectedRows = container.selectionModel.items || []
|
96
|
+
applyRendererOutput(data) {
|
97
|
+
let {cellId, column, gridContainer, index, record} = data,
|
98
|
+
me = this,
|
99
|
+
cellCls = ['neo-grid-cell'],
|
100
|
+
colspan = record[me.colspanField],
|
101
|
+
{dataField} = column,
|
102
|
+
fieldValue = Neo.ns(dataField, false, record),
|
103
|
+
cellConfig, rendererOutput;
|
104
|
+
|
105
|
+
if (fieldValue === null || fieldValue === undefined) {
|
106
|
+
fieldValue = ''
|
66
107
|
}
|
67
108
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
109
|
+
rendererOutput = column.renderer.call(column.rendererScope || gridContainer, {
|
110
|
+
column,
|
111
|
+
dataField,
|
112
|
+
gridContainer,
|
113
|
+
index,
|
114
|
+
record,
|
115
|
+
value: fieldValue
|
116
|
+
});
|
73
117
|
|
74
|
-
|
118
|
+
switch (Neo.typeOf(rendererOutput)) {
|
119
|
+
case 'Object': {
|
120
|
+
if (rendererOutput.html) {
|
121
|
+
rendererOutput.cls && cellCls.push(...rendererOutput.cls);
|
122
|
+
} else {
|
123
|
+
rendererOutput = [rendererOutput];
|
124
|
+
}
|
125
|
+
break
|
126
|
+
}
|
127
|
+
case 'Date':
|
128
|
+
case 'Number':
|
129
|
+
case 'String': {
|
130
|
+
rendererOutput = {
|
131
|
+
cls : cellCls,
|
132
|
+
html: rendererOutput?.toString()
|
133
|
+
};
|
134
|
+
break
|
135
|
+
}
|
136
|
+
}
|
75
137
|
|
76
|
-
|
77
|
-
|
138
|
+
if (rendererOutput === null || rendererOutput === undefined) {
|
139
|
+
rendererOutput = ''
|
140
|
+
}
|
78
141
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
}
|
142
|
+
if (column.cellAlign !== 'left') {
|
143
|
+
cellCls.push('neo-' + column.cellAlign)
|
144
|
+
}
|
83
145
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
cn : [],
|
88
|
-
tabIndex: '-1'
|
89
|
-
});
|
146
|
+
if (!cellId) {
|
147
|
+
cellId = me.getCellId(record, column.dataField)
|
148
|
+
}
|
90
149
|
|
91
|
-
|
92
|
-
|
150
|
+
cellConfig = {
|
151
|
+
id : cellId,
|
152
|
+
cls : cellCls,
|
153
|
+
style : rendererOutput.style || {},
|
154
|
+
tabIndex: '-1'
|
155
|
+
};
|
93
156
|
|
94
|
-
|
157
|
+
if (column.width) {
|
158
|
+
cellConfig.style.minWidth = `${column.width}px`
|
159
|
+
}
|
95
160
|
|
96
|
-
|
97
|
-
|
98
|
-
|
161
|
+
if (colspan && Object.keys(colspan).includes(dataField)) {
|
162
|
+
cellConfig.colspan = colspan[dataField]
|
163
|
+
}
|
99
164
|
|
100
|
-
|
101
|
-
|
102
|
-
|
165
|
+
if (Neo.typeOf(rendererOutput) === 'Object') {
|
166
|
+
cellConfig.innerHTML = rendererOutput.html || ''
|
167
|
+
} else {
|
168
|
+
cellConfig.cn = rendererOutput
|
169
|
+
}
|
103
170
|
|
104
|
-
|
105
|
-
|
106
|
-
field: column.field,
|
107
|
-
index: i,
|
108
|
-
record,
|
109
|
-
value: rendererValue
|
110
|
-
});
|
171
|
+
return cellConfig
|
172
|
+
}
|
111
173
|
|
112
|
-
|
174
|
+
/**
|
175
|
+
* @param {Object} opts
|
176
|
+
* @param {Object} opts.record
|
177
|
+
* @param {Number} [opts.rowIndex]
|
178
|
+
* @returns {Object}
|
179
|
+
*/
|
180
|
+
createRow({record, rowIndex}) {
|
181
|
+
if (!Neo.isNumber(rowIndex)) {
|
182
|
+
rowIndex = this.store.indexOf(record)
|
183
|
+
}
|
113
184
|
|
114
|
-
|
115
|
-
|
116
|
-
|
185
|
+
let me = this,
|
186
|
+
gridContainer = me.parent,
|
187
|
+
colspan = record[me.colspanField],
|
188
|
+
colspanKeys = colspan && Object.keys(colspan),
|
189
|
+
columns = gridContainer.items[0].items,
|
190
|
+
colCount = columns.length,
|
191
|
+
dockLeftMargin = 0,
|
192
|
+
dockRightMargin = 0,
|
193
|
+
id = me.getRowId(record, rowIndex),
|
194
|
+
{selectedRows} = me,
|
195
|
+
trCls = me.getTrClass(record, rowIndex),
|
196
|
+
config, column, columnIndex, gridRow, i;
|
197
|
+
|
198
|
+
me.recordVnodeMap[id] = rowIndex;
|
199
|
+
|
200
|
+
if (selectedRows && Neo.ns(me.selectedRecordField, false, record)) {
|
201
|
+
NeoArray.add(selectedRows, id)
|
202
|
+
}
|
117
203
|
|
118
|
-
|
119
|
-
|
120
|
-
cls : cellCls,
|
121
|
-
html: rendererOutput?.toString()
|
122
|
-
}
|
123
|
-
}
|
204
|
+
if (selectedRows?.includes(id)) {
|
205
|
+
trCls.push('neo-selected');
|
124
206
|
|
125
|
-
|
207
|
+
me.parent.fire('select', {
|
208
|
+
record
|
209
|
+
})
|
210
|
+
}
|
126
211
|
|
127
|
-
|
128
|
-
|
129
|
-
|
212
|
+
gridRow = {
|
213
|
+
id,
|
214
|
+
cls : trCls,
|
215
|
+
cn : [],
|
216
|
+
tabIndex: '-1'
|
217
|
+
};
|
130
218
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
innerHTML: rendererOutput.html || '',
|
135
|
-
style : cellStyle,
|
136
|
-
tabIndex : '-1'
|
137
|
-
};
|
219
|
+
for (i=0; i < colCount; i++) {
|
220
|
+
column = columns[i];
|
221
|
+
config = me.applyRendererOutput({column, gridContainer, index: rowIndex, record});
|
138
222
|
|
139
|
-
|
140
|
-
|
223
|
+
if (column.dock) {
|
224
|
+
config.cls = ['neo-locked', ...config.cls || []];
|
141
225
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
}
|
226
|
+
if (column.dock === 'left') {
|
227
|
+
config.style.left = dockLeftMargin + 'px';
|
228
|
+
dockLeftMargin += (column.width + 1) // todo: borders fix
|
146
229
|
}
|
230
|
+
}
|
147
231
|
|
148
|
-
|
149
|
-
|
150
|
-
|
232
|
+
if (column.flex) {
|
233
|
+
config.style.width = '100%'
|
234
|
+
}
|
151
235
|
|
152
|
-
|
236
|
+
gridRow.cn.push(config);
|
237
|
+
|
238
|
+
if (colspanKeys?.includes(column.dataField)) {
|
239
|
+
i += (colspan[column.dataField] - 1)
|
153
240
|
}
|
241
|
+
}
|
154
242
|
|
155
|
-
|
243
|
+
for (i=0; i < colCount; i++) {
|
244
|
+
columnIndex = colCount - i -1;
|
245
|
+
column = columns[columnIndex];
|
156
246
|
|
157
|
-
|
158
|
-
|
159
|
-
column
|
247
|
+
if (column.dock === 'right') {
|
248
|
+
gridRow.cn[columnIndex].style.right = dockRightMargin + 'px';
|
249
|
+
dockRightMargin += (column.width + 1) // todo: borders fix
|
250
|
+
}
|
160
251
|
|
161
|
-
|
162
|
-
|
163
|
-
dockRightMargin += (column.width + 1) // todo: borders fix
|
164
|
-
}
|
252
|
+
if (colspanKeys?.includes(column.dataField)) {
|
253
|
+
i += (colspan[column.dataField] - 1)
|
165
254
|
}
|
166
255
|
}
|
167
256
|
|
168
|
-
|
257
|
+
// the dock margins are the same for each row
|
258
|
+
rowIndex === 0 && Object.assign(gridContainer, {dockLeftMargin, dockRightMargin});
|
169
259
|
|
170
|
-
|
171
|
-
|
260
|
+
return gridRow
|
261
|
+
}
|
262
|
+
|
263
|
+
/**
|
264
|
+
* @param {Object[]} inputData
|
265
|
+
*/
|
266
|
+
createViewData(inputData) {
|
267
|
+
let me = this,
|
268
|
+
amountRows = inputData.length,
|
269
|
+
i = 0,
|
270
|
+
rows = [],
|
271
|
+
{selectedRows} = me;
|
272
|
+
|
273
|
+
for (; i < amountRows; i++) {
|
274
|
+
rows.push(me.createRow({record: inputData[i], rowIndex: i}))
|
275
|
+
}
|
276
|
+
|
277
|
+
me.vdom.cn = rows;
|
172
278
|
|
173
279
|
me.promiseUpdate().then(() => {
|
174
280
|
if (selectedRows?.length > 0) {
|
175
|
-
// this logic only works for selection.
|
176
|
-
Neo.main.DomAccess.scrollToTableRow({
|
177
|
-
appName: me.appName,
|
178
|
-
id : selectedRows[0]
|
179
|
-
})
|
281
|
+
// this logic only works for selection.grid.RowModel
|
282
|
+
Neo.main.DomAccess.scrollToTableRow({appName: me.appName, id: selectedRows[0]})
|
180
283
|
}
|
181
284
|
})
|
182
285
|
}
|
183
286
|
|
184
287
|
/**
|
185
|
-
* @param
|
186
|
-
* @param {Boolean} silent
|
288
|
+
* @param args
|
187
289
|
*/
|
188
|
-
destroy(
|
290
|
+
destroy(...args) {
|
189
291
|
this.store = null;
|
190
|
-
super.destroy(
|
292
|
+
super.destroy(...args)
|
191
293
|
}
|
192
294
|
|
193
295
|
/**
|
@@ -196,11 +298,11 @@ class View extends Component {
|
|
196
298
|
*/
|
197
299
|
fireCellEvent(data, eventName) {
|
198
300
|
let me = this,
|
199
|
-
|
301
|
+
id = data.currentTarget,
|
200
302
|
dataField = me.getCellDataField(id),
|
201
303
|
record = me.getRecord(id);
|
202
304
|
|
203
|
-
me.parent.fire(eventName, {
|
305
|
+
me.parent.fire(eventName, {data, dataField, record, view: me})
|
204
306
|
}
|
205
307
|
|
206
308
|
/**
|
@@ -209,10 +311,10 @@ class View extends Component {
|
|
209
311
|
*/
|
210
312
|
fireRowEvent(data, eventName) {
|
211
313
|
let me = this,
|
212
|
-
|
314
|
+
id = data.currentTarget,
|
213
315
|
record = me.getRecord(id);
|
214
316
|
|
215
|
-
me.parent.fire(eventName, {
|
317
|
+
me.parent.fire(eventName, {data, record, view: me})
|
216
318
|
}
|
217
319
|
|
218
320
|
/**
|
@@ -225,15 +327,39 @@ class View extends Component {
|
|
225
327
|
|
226
328
|
/**
|
227
329
|
* @param {Object} record
|
228
|
-
* @param {String}
|
330
|
+
* @param {String} dataField
|
229
331
|
* @returns {String}
|
230
332
|
*/
|
231
|
-
getCellId(record,
|
232
|
-
return this.id + '__' + record[this.store.keyProperty] + '__' +
|
333
|
+
getCellId(record, dataField) {
|
334
|
+
return this.id + '__' + record[this.store.keyProperty] + '__' + dataField
|
335
|
+
}
|
336
|
+
|
337
|
+
/**
|
338
|
+
* Get a grid column or column index by a given field name
|
339
|
+
* @param {String} field
|
340
|
+
* @param {Boolean} returnIndex=false
|
341
|
+
* @returns {Object|Number|null}
|
342
|
+
*/
|
343
|
+
getColumn(field, returnIndex=false) {
|
344
|
+
let container = this.parent,
|
345
|
+
columns = container.headerToolbar.items,
|
346
|
+
i = 0,
|
347
|
+
len = columns.length,
|
348
|
+
column;
|
349
|
+
|
350
|
+
for (; i < len; i++) {
|
351
|
+
column = columns[i];
|
352
|
+
|
353
|
+
if (column.dataField === field) {
|
354
|
+
return returnIndex ? i : column
|
355
|
+
}
|
356
|
+
}
|
357
|
+
|
358
|
+
return null
|
233
359
|
}
|
234
360
|
|
235
361
|
/**
|
236
|
-
* Get the matching record by passing a row id, a cell id or an id inside a
|
362
|
+
* Get the matching record by passing a row id, a cell id or an id inside a grid cell.
|
237
363
|
* @param {String} nodeId
|
238
364
|
* @returns {Object|null}
|
239
365
|
*/
|
@@ -243,7 +369,7 @@ class View extends Component {
|
|
243
369
|
node, parentNodes;
|
244
370
|
|
245
371
|
if (record) {
|
246
|
-
return record
|
372
|
+
return record;
|
247
373
|
}
|
248
374
|
|
249
375
|
parentNodes = VDomUtil.getParentNodes(me.vdom, nodeId);
|
@@ -273,7 +399,15 @@ class View extends Component {
|
|
273
399
|
* @returns {String}
|
274
400
|
*/
|
275
401
|
getRowId(record, index) {
|
276
|
-
|
402
|
+
let me = this,
|
403
|
+
{store} = me;
|
404
|
+
|
405
|
+
if (me.useRowRecordIds) {
|
406
|
+
return `${me.id}__tr__${record[store.keyProperty]}`
|
407
|
+
} else {
|
408
|
+
index = Neo.isNumber(index) ? index : store.indexOf(record);
|
409
|
+
return me.vdom.cn[index]?.id || Neo.getId('tr')
|
410
|
+
}
|
277
411
|
}
|
278
412
|
|
279
413
|
/**
|
@@ -322,24 +456,43 @@ class View extends Component {
|
|
322
456
|
* @param {Neo.data.Model} opts.model The model instance of the changed record
|
323
457
|
* @param {Object} opts.record
|
324
458
|
*/
|
325
|
-
onStoreRecordChange(
|
326
|
-
let me
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
cellNode
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
459
|
+
onStoreRecordChange({fields, model, record}) {
|
460
|
+
let me = this,
|
461
|
+
fieldNames = fields.map(field => field.name),
|
462
|
+
needsUpdate = false,
|
463
|
+
gridContainer = me.parent,
|
464
|
+
{selectionModel} = gridContainer,
|
465
|
+
{vdom} = me,
|
466
|
+
cellId, cellNode, column, index, scope;
|
467
|
+
|
468
|
+
if (fieldNames.includes(me.colspanField)) {
|
469
|
+
index = me.store.indexOf(record);
|
470
|
+
me.vdom.cn[index] = me.createRow({record, rowIndex: index});
|
471
|
+
me.update()
|
472
|
+
} else {
|
473
|
+
fields.forEach(field => {
|
474
|
+
if (field.name === me.selectedRecordField) {
|
475
|
+
if (selectionModel.ntype === 'selection-grid-rowmodel') {
|
476
|
+
selectionModel[field.value ? 'select' : 'deselect'](me.getRowId(record))
|
477
|
+
}
|
478
|
+
} else {
|
479
|
+
cellId = me.getCellId(record, field.name);
|
480
|
+
cellNode = VDomUtil.find(vdom, cellId);
|
481
|
+
|
482
|
+
// the vdom might not exist yet => nothing to do in this case
|
483
|
+
if (cellNode?.vdom) {
|
484
|
+
column = me.getColumn(field.name);
|
485
|
+
index = cellNode.index;
|
486
|
+
needsUpdate = true;
|
487
|
+
scope = column.rendererScope || gridContainer;
|
488
|
+
|
489
|
+
cellNode.parentNode.cn[index] = me.applyRendererOutput({cellId, column, gridContainer, index, record})
|
490
|
+
}
|
491
|
+
}
|
339
492
|
})
|
340
|
-
}
|
493
|
+
}
|
341
494
|
|
342
|
-
|
495
|
+
needsUpdate && me.update()
|
343
496
|
}
|
344
497
|
}
|
345
498
|
|