neo.mjs 8.7.0 → 8.8.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/nestedRecordFields/EditUserDialog.mjs +154 -0
- package/examples/grid/nestedRecordFields/MainModel.mjs +54 -0
- package/examples/grid/nestedRecordFields/MainStore.mjs +54 -0
- package/examples/grid/nestedRecordFields/Viewport.mjs +152 -0
- package/examples/grid/nestedRecordFields/ViewportStateProvider.mjs +62 -0
- package/examples/grid/nestedRecordFields/app.mjs +6 -0
- package/examples/grid/nestedRecordFields/index.html +11 -0
- package/examples/grid/nestedRecordFields/neo-config.json +7 -0
- package/examples/table/nestedRecordFields/{MainContainer.mjs → Viewport.mjs} +50 -21
- package/examples/table/nestedRecordFields/{MainContainerStateProvider.mjs → ViewportStateProvider.mjs} +5 -5
- package/examples/table/nestedRecordFields/app.mjs +3 -3
- package/package.json +1 -1
- package/resources/scss/src/dialog/Base.scss +4 -0
- package/resources/scss/src/grid/View.scss +16 -0
- package/resources/scss/src/grid/header/Button.scss +3 -1
- package/resources/scss/src/table/View.scss +2 -2
- package/resources/scss/src/table/header/Button.scss +1 -2
- package/resources/scss/theme-dark/grid/View.scss +2 -0
- package/resources/scss/theme-dark/table/View.scss +2 -0
- package/resources/scss/theme-light/grid/View.scss +2 -0
- package/resources/scss/theme-light/table/View.scss +2 -0
- package/resources/scss/theme-neo-light/grid/View.scss +2 -0
- package/resources/scss/theme-neo-light/table/View.scss +2 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/Neo.mjs +48 -19
- package/src/data/RecordFactory.mjs +57 -31
- package/src/dialog/Base.mjs +1 -2
- package/src/grid/View.mjs +23 -5
- package/src/table/View.mjs +1 -1
@@ -5,16 +5,16 @@ import Store from '../../../src/data/Store.mjs';
|
|
5
5
|
const dataSymbol = Symbol.for('data');
|
6
6
|
|
7
7
|
/**
|
8
|
-
* @class Neo.examples.table.nestedRecordFields.
|
8
|
+
* @class Neo.examples.table.nestedRecordFields.ViewportStateProvider
|
9
9
|
* @extends Neo.state.Provider
|
10
10
|
*/
|
11
|
-
class
|
11
|
+
class ViewportStateProvider extends StateProvider {
|
12
12
|
static config = {
|
13
13
|
/**
|
14
|
-
* @member {String} className='Neo.examples.table.nestedRecordFields.
|
14
|
+
* @member {String} className='Neo.examples.table.nestedRecordFields.ViewportStateProvider'
|
15
15
|
* @protected
|
16
16
|
*/
|
17
|
-
className: 'Neo.examples.table.nestedRecordFields.
|
17
|
+
className: 'Neo.examples.table.nestedRecordFields.ViewportStateProvider',
|
18
18
|
/**
|
19
19
|
* @member {Object} stores
|
20
20
|
*/
|
@@ -59,4 +59,4 @@ class MainContainerStateProvider extends StateProvider {
|
|
59
59
|
}
|
60
60
|
}
|
61
61
|
|
62
|
-
export default Neo.setupClass(
|
62
|
+
export default Neo.setupClass(ViewportStateProvider);
|
package/package.json
CHANGED
@@ -22,6 +22,22 @@
|
|
22
22
|
height : 100%;
|
23
23
|
overflow-x: visible;
|
24
24
|
|
25
|
+
.neo-grid-cell {
|
26
|
+
&.neo-is-modified {
|
27
|
+
&:after {
|
28
|
+
border-color: transparent var(--grid-cell-ismodified-color) transparent transparent;
|
29
|
+
border-style: solid;
|
30
|
+
border-width: 0 var(--grid-cell-ismodified-size) var(--grid-cell-ismodified-size) 0;
|
31
|
+
content : '';
|
32
|
+
height : 0;
|
33
|
+
position : absolute;
|
34
|
+
right : 0;
|
35
|
+
top : 0;
|
36
|
+
width : 0;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
25
41
|
&.neo-is-scrolling * {
|
26
42
|
pointer-events: none !important;
|
27
43
|
}
|
@@ -2,6 +2,7 @@
|
|
2
2
|
align-items : center;
|
3
3
|
background-color: var(--grid-header-button-background-color);
|
4
4
|
background-image: var(--grid-header-button-background-image);
|
5
|
+
border-radius : 0;
|
5
6
|
border-width : 0;
|
6
7
|
color : var(--grid-header-button-color);
|
7
8
|
cursor : pointer;
|
@@ -13,7 +14,6 @@
|
|
13
14
|
height : 29px; // Webkit => Safari can not handle 100%
|
14
15
|
justify-content : flex-end;
|
15
16
|
margin : 0;
|
16
|
-
padding : 7px 10px 6px;
|
17
17
|
white-space : nowrap;
|
18
18
|
|
19
19
|
&:not(:last-child) {
|
@@ -69,6 +69,8 @@
|
|
69
69
|
}
|
70
70
|
|
71
71
|
.neo-button-text {
|
72
|
+
color : var(--grid-header-button-color);
|
72
73
|
pointer-events: none;
|
74
|
+
text-transform: none;
|
73
75
|
}
|
74
76
|
}
|
@@ -13,9 +13,9 @@
|
|
13
13
|
|
14
14
|
&.neo-is-modified {
|
15
15
|
&:after {
|
16
|
-
border-color: transparent
|
16
|
+
border-color: transparent var(--table-cell-ismodified-color) transparent transparent;
|
17
17
|
border-style: solid;
|
18
|
-
border-width: 0
|
18
|
+
border-width: 0 var(--table-cell-ismodified-size) var(--table-cell-ismodified-size) 0;
|
19
19
|
content : '';
|
20
20
|
height : 0;
|
21
21
|
position : absolute;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
.neo-table-header-button {
|
2
2
|
align-items : center;
|
3
3
|
background-color: var(--table-header-button-background-color);
|
4
|
+
background-image: var(--table-header-button-background-image);
|
4
5
|
border-width : 0;
|
5
6
|
color : var(--table-header-button-color);
|
6
7
|
cursor : pointer;
|
@@ -15,8 +16,6 @@
|
|
15
16
|
white-space : nowrap;
|
16
17
|
width : 100% !important;
|
17
18
|
|
18
|
-
background-image: var(--table-header-button-background-image);
|
19
|
-
|
20
19
|
&.neo-drag-over {
|
21
20
|
background-image: linear-gradient(green, darkgreen);;
|
22
21
|
}
|
@@ -1,5 +1,7 @@
|
|
1
1
|
:root .neo-theme-dark { // .neo-grid-view
|
2
2
|
--grid-cell-background-color-hover : #54595c;
|
3
|
+
--grid-cell-ismodified-color : orange;
|
4
|
+
--grid-cell-ismodified-size : 10px;
|
3
5
|
--grid-cellmodel-selected-cell-background-color : #64B5F6;
|
4
6
|
--grid-cellmodel-selected-cell-color : #2b2b2b;
|
5
7
|
--grid-cellmodel-selected-column-cell-background-color: #4f558a;
|
@@ -1,5 +1,7 @@
|
|
1
1
|
:root .neo-theme-dark { // .neo-table-view
|
2
2
|
--table-cell-background-color-hover : #54595c;
|
3
|
+
--table-cell-ismodified-color : orange;
|
4
|
+
--table-cell-ismodified-size : 10px;
|
3
5
|
--table-cellmodel-selected-cell-background-color : #64B5F6;
|
4
6
|
--table-cellmodel-selected-cell-color : #2b2b2b;
|
5
7
|
--table-cellmodel-selected-column-cell-background-color: #4f558a;
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
:root .neo-theme-light { // .neo-grid-view
|
4
4
|
--grid-cell-background-color-hover : #{color.adjust(#33343d, $lightness: 70%)};
|
5
|
+
--grid-cell-ismodified-color : orange;
|
6
|
+
--grid-cell-ismodified-size : 10px;
|
5
7
|
--grid-cellmodel-selected-cell-background-color : #{color.adjust(#64B5F6, $lightness: 22%)};
|
6
8
|
--grid-cellmodel-selected-cell-color : #2b2b2b;
|
7
9
|
--grid-cellmodel-selected-column-cell-background-color: #{color.adjust(#4f558a, $lightness: 52%)};
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
:root .neo-theme-light { // .neo-table-view
|
4
4
|
--table-cell-background-color-hover : #{color.adjust(#33343d, $lightness: 70%)};
|
5
|
+
--table-cell-ismodified-color : orange;
|
6
|
+
--table-cell-ismodified-size : 10px;
|
5
7
|
--table-cellmodel-selected-cell-background-color : #{color.adjust(#64B5F6, $lightness: 22%)};
|
6
8
|
--table-cellmodel-selected-cell-color : #2b2b2b;
|
7
9
|
--table-cellmodel-selected-column-cell-background-color: #{color.adjust(#4f558a, $lightness: 52%)};
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
:root .neo-theme-neo-light { // .neo-grid-view
|
4
4
|
--grid-cell-background-color-hover : #{color.adjust(#33343d, $lightness: 70%)};
|
5
|
+
--grid-cell-ismodified-color : orange;
|
6
|
+
--grid-cell-ismodified-size : 10px;
|
5
7
|
--grid-cellmodel-selected-cell-background-color : #{color.adjust(#64B5F6, $lightness: 22%)};
|
6
8
|
--grid-cellmodel-selected-cell-color : #2b2b2b;
|
7
9
|
--grid-cellmodel-selected-column-cell-background-color: #{color.adjust(#4f558a, $lightness: 52%)};
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
:root .neo-theme-neo-light { // .neo-table-view
|
4
4
|
--table-cell-background-color-hover : #{color.adjust(#33343d, $lightness: 70%)};
|
5
|
+
--table-cell-ismodified-color : orange;
|
6
|
+
--table-cell-ismodified-size : 10px;
|
5
7
|
--table-cellmodel-selected-cell-background-color : #{color.adjust(#64B5F6, $lightness: 22%)};
|
6
8
|
--table-cellmodel-selected-cell-color : #2b2b2b;
|
7
9
|
--table-cellmodel-selected-column-cell-background-color: #{color.adjust(#4f558a, $lightness: 52%)};
|
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.8.0'
|
266
266
|
* @memberOf! module:Neo
|
267
267
|
* @name config.version
|
268
268
|
* @type String
|
269
269
|
*/
|
270
|
-
version: '8.
|
270
|
+
version: '8.8.0'
|
271
271
|
};
|
272
272
|
|
273
273
|
Object.assign(DefaultConfig, {
|
package/src/Neo.mjs
CHANGED
@@ -66,10 +66,10 @@ Neo = globalThis.Neo = Object.assign({
|
|
66
66
|
*
|
67
67
|
* // e.g. Neo.core.Util.isObject => Neo.isObject
|
68
68
|
* @memberOf module:Neo
|
69
|
-
* @param {Neo|Neo.core.Base} target
|
70
|
-
* @param {Neo.core.Base}
|
71
|
-
* @param {Object}
|
72
|
-
* @param {Boolean}
|
69
|
+
* @param {Neo|Neo.core.Base} target The target class or singleton Instance or Neo
|
70
|
+
* @param {Neo.core.Base} namespace The class containing the methods
|
71
|
+
* @param {Object} config
|
72
|
+
* @param {Boolean} [bind] set this to true in case you want to bind methods to the "from" namespace
|
73
73
|
* @returns {Object} target
|
74
74
|
*/
|
75
75
|
applyFromNs(target, namespace, config, bind) {
|
@@ -104,7 +104,7 @@ Neo = globalThis.Neo = Object.assign({
|
|
104
104
|
/**
|
105
105
|
* Copies all keys of defaults into target, in case they don't already exist
|
106
106
|
* @memberOf module:Neo
|
107
|
-
* @param {Object} target
|
107
|
+
* @param {Object} target The target object
|
108
108
|
* @param {Object} defaults The object containing the keys you want to copy
|
109
109
|
* @returns {Object} target
|
110
110
|
*/
|
@@ -120,6 +120,35 @@ Neo = globalThis.Neo = Object.assign({
|
|
120
120
|
return target
|
121
121
|
},
|
122
122
|
|
123
|
+
/**
|
124
|
+
* Assigns a new value to a given nested objects path.
|
125
|
+
* It will create the path structure or parts of it, in case it does not exist.
|
126
|
+
* @example
|
127
|
+
* Neo.assignToNs('annotations.selected', false, record)
|
128
|
+
*
|
129
|
+
* @memberOf module:Neo
|
130
|
+
* @param {String[]|String} path The path string containing dots or an Array of the string parts
|
131
|
+
* @param {*} value The new value to assign to the leaf node
|
132
|
+
* @param {Object} scope=globalThis Set a different starting point as globalThis
|
133
|
+
* @param {Boolean} force=true false will only assign default values (assign if old value === undefined)
|
134
|
+
*/
|
135
|
+
assignToNs(path, value, scope=globalThis, force=true) {
|
136
|
+
path = Array.isArray(path) ? path : path.split('.');
|
137
|
+
|
138
|
+
let key;
|
139
|
+
|
140
|
+
if (path.length > 1) {
|
141
|
+
key = path.pop();
|
142
|
+
scope = Neo.ns(path, true, scope)
|
143
|
+
} else {
|
144
|
+
key = path
|
145
|
+
}
|
146
|
+
|
147
|
+
if (force || scope[key] === undefined) {
|
148
|
+
scope[key] = value
|
149
|
+
}
|
150
|
+
},
|
151
|
+
|
123
152
|
/**
|
124
153
|
* Converts kebab-case strings into camel-case
|
125
154
|
* @memberOf module:Neo
|
@@ -143,7 +172,7 @@ Neo = globalThis.Neo = Object.assign({
|
|
143
172
|
/**
|
144
173
|
* @memberOf module:Neo
|
145
174
|
* @param {Object|Array|*} obj
|
146
|
-
* @param {Boolean} deep=false
|
175
|
+
* @param {Boolean} deep=false Set this to true in case you want to clone nested objects as well
|
147
176
|
* @param {Boolean} ignoreNeoInstances=false returns existing instances if set to true
|
148
177
|
* @returns {Object|Array|*} the cloned input
|
149
178
|
*/
|
@@ -214,7 +243,7 @@ Neo = globalThis.Neo = Object.assign({
|
|
214
243
|
* });
|
215
244
|
* @memberOf module:Neo
|
216
245
|
* @param {String|Object|Neo.core.Base} className
|
217
|
-
* @param {Object}
|
246
|
+
* @param {Object} [config]
|
218
247
|
* @returns {Neo.core.Base|null} The new class instance
|
219
248
|
* @tutorial 02_ClassSystem
|
220
249
|
*/
|
@@ -263,7 +292,7 @@ Neo = globalThis.Neo = Object.assign({
|
|
263
292
|
* Checks if there is a set method for a given property key inside the prototype chain
|
264
293
|
* @memberOf module:Neo
|
265
294
|
* @param {Neo.core.Base} proto The top level prototype of a class
|
266
|
-
* @param {String}
|
295
|
+
* @param {String} key The property key to test
|
267
296
|
* @returns {Boolean}
|
268
297
|
*/
|
269
298
|
hasPropertySetter(proto, key) {
|
@@ -319,9 +348,9 @@ Neo = globalThis.Neo = Object.assign({
|
|
319
348
|
* // return globalThis.Neo.button.Base;
|
320
349
|
*
|
321
350
|
* @memberOf module:Neo
|
322
|
-
* @param {
|
323
|
-
* @param {Boolean}
|
324
|
-
* @param {Object}
|
351
|
+
* @param {String[]|String} names The class name string containing dots or an Array of the string parts
|
352
|
+
* @param {Boolean} create=false Set create to true to create empty objects for non-existing parts
|
353
|
+
* @param {Object} [scope] Set a different starting point as globalThis
|
325
354
|
* @returns {Object} reference to the toplevel namespace
|
326
355
|
*/
|
327
356
|
ns(names, create=false, scope) {
|
@@ -341,9 +370,9 @@ Neo = globalThis.Neo = Object.assign({
|
|
341
370
|
/**
|
342
371
|
* Extended version of Neo.ns() which supports mapping into arrays.
|
343
372
|
* @memberOf module:Neo
|
344
|
-
* @param {Array|String} names
|
345
|
-
* @param {Boolean}
|
346
|
-
* @param {Object}
|
373
|
+
* @param {Array|String} names The class name string containing dots or an Array of the string parts
|
374
|
+
* @param {Boolean} create=false Set create to true to create empty objects for non-existing parts
|
375
|
+
* @param {Object} [scope] Set a different starting point as globalThis
|
347
376
|
* @returns {Object} reference to the toplevel namespace
|
348
377
|
*/
|
349
378
|
nsWithArrays(names, create=false, scope) {
|
@@ -383,7 +412,7 @@ Neo = globalThis.Neo = Object.assign({
|
|
383
412
|
* });
|
384
413
|
* @memberOf module:Neo
|
385
414
|
* @param {String|Object} ntype
|
386
|
-
* @param {Object}
|
415
|
+
* @param {Object} [config]
|
387
416
|
* @returns {Neo.core.Base}
|
388
417
|
* @see {@link module:Neo.create create}
|
389
418
|
*/
|
@@ -575,7 +604,7 @@ const ignoreMixin = [
|
|
575
604
|
|
576
605
|
/**
|
577
606
|
* @param {Neo.core.Base} cls
|
578
|
-
* @param {Array}
|
607
|
+
* @param {Array} mixins
|
579
608
|
* @private
|
580
609
|
*/
|
581
610
|
function applyMixins(cls, mixins) {
|
@@ -614,7 +643,7 @@ function applyMixins(cls, mixins) {
|
|
614
643
|
/**
|
615
644
|
* Creates get / set methods for class configs ending with an underscore
|
616
645
|
* @param {Neo.core.Base} proto
|
617
|
-
* @param {String}
|
646
|
+
* @param {String} key
|
618
647
|
* @private
|
619
648
|
* @tutorial 02_ClassSystem
|
620
649
|
*/
|
@@ -708,8 +737,8 @@ function autoGenerateGetSet(proto, key) {
|
|
708
737
|
|
709
738
|
/**
|
710
739
|
* @param {Boolean} create
|
711
|
-
* @param {Object}
|
712
|
-
* @param {Object}
|
740
|
+
* @param {Object} current
|
741
|
+
* @param {Object} prev
|
713
742
|
* @returns {Object|undefined}
|
714
743
|
*/
|
715
744
|
function createArrayNs(create, current, prev) {
|
@@ -4,6 +4,7 @@ import Model from './Model.mjs';
|
|
4
4
|
|
5
5
|
const
|
6
6
|
dataSymbol = Symbol.for('data'),
|
7
|
+
isModifiedSymbol = Symbol.for('isModified'),
|
7
8
|
originalDataSymbol = Symbol.for('originalData');
|
8
9
|
|
9
10
|
let instance;
|
@@ -31,21 +32,42 @@ class RecordFactory extends Base {
|
|
31
32
|
singleton: true
|
32
33
|
}
|
33
34
|
|
35
|
+
/**
|
36
|
+
* Assigns model based default values to a data object
|
37
|
+
* @param {Object} data
|
38
|
+
* @param {Neo.data.Model} model
|
39
|
+
* @returns {Object}
|
40
|
+
*/
|
41
|
+
assignDefaultValues(data, model) {
|
42
|
+
model.fieldsMap.forEach((field, fieldName) => {
|
43
|
+
if (Object.hasOwn(field, 'defaultValue')) {
|
44
|
+
// We could always use Neo.assignToNs() => the check is just for improving the performance
|
45
|
+
if (model.hasNestedFields) {
|
46
|
+
Neo.assignToNs(fieldName, field.defaultValue, data, false)
|
47
|
+
} else if (data[fieldName] === undefined) {
|
48
|
+
data[fieldName] = field.defaultValue
|
49
|
+
}
|
50
|
+
}
|
51
|
+
});
|
52
|
+
|
53
|
+
return data
|
54
|
+
}
|
55
|
+
|
34
56
|
/**
|
35
57
|
* @param {Object} data
|
36
58
|
* @param {Object} data.field
|
37
|
-
* @param {Neo.data.RecordFactory} data.me
|
38
59
|
* @param {Neo.data.Model} data.model
|
39
60
|
* @param {String} data.path=''
|
61
|
+
* @param {Object} data.proto
|
40
62
|
*/
|
41
|
-
createField({field,
|
63
|
+
createField({field, model, path='', proto}) {
|
42
64
|
let fieldName = field.name,
|
43
65
|
fieldPath = path === '' ? fieldName : `${path}.${fieldName}`,
|
44
66
|
properties;
|
45
67
|
|
46
68
|
if (field.fields) {
|
47
69
|
field.fields.forEach(childField => {
|
48
|
-
this.createField({field: childField,
|
70
|
+
this.createField({field: childField, model, path: fieldPath, proto})
|
49
71
|
})
|
50
72
|
} else {
|
51
73
|
properties = {
|
@@ -68,7 +90,9 @@ class RecordFactory extends Base {
|
|
68
90
|
if (!Neo.isEqual(value, oldValue)) {
|
69
91
|
instance.setRecordData({fieldName: fieldPath, model, record: me, value});
|
70
92
|
|
71
|
-
|
93
|
+
if (!model.trackModifiedFields) {
|
94
|
+
me[isModifiedSymbol] = true
|
95
|
+
}
|
72
96
|
|
73
97
|
instance.onRecordChange({
|
74
98
|
fields: [{name: fieldPath, oldValue, value}],
|
@@ -80,7 +104,7 @@ class RecordFactory extends Base {
|
|
80
104
|
}
|
81
105
|
};
|
82
106
|
|
83
|
-
Object.defineProperties(
|
107
|
+
Object.defineProperties(proto, properties)
|
84
108
|
}
|
85
109
|
}
|
86
110
|
|
@@ -124,10 +148,10 @@ class RecordFactory extends Base {
|
|
124
148
|
let me = this;
|
125
149
|
|
126
150
|
if (model.trackModifiedFields) {
|
127
|
-
return Neo.isEqual(me[dataSymbol], me[originalDataSymbol])
|
151
|
+
return !Neo.isEqual(me[dataSymbol], me[originalDataSymbol])
|
128
152
|
}
|
129
153
|
|
130
|
-
return me
|
154
|
+
return me[isModifiedSymbol]
|
131
155
|
}
|
132
156
|
|
133
157
|
/**
|
@@ -136,13 +160,15 @@ class RecordFactory extends Base {
|
|
136
160
|
constructor(config) {
|
137
161
|
let me = this;
|
138
162
|
|
163
|
+
config = instance.assignDefaultValues(config, model);
|
164
|
+
|
139
165
|
if (model.trackModifiedFields) {
|
140
166
|
me[originalDataSymbol] = {};
|
141
167
|
me.setOriginal(config)
|
142
168
|
}
|
143
169
|
|
144
170
|
me.setSilent(config); // We do not want to fire change events when constructing
|
145
|
-
me
|
171
|
+
me[isModifiedSymbol] = false
|
146
172
|
}
|
147
173
|
|
148
174
|
/**
|
@@ -153,7 +179,7 @@ class RecordFactory extends Base {
|
|
153
179
|
let me = this;
|
154
180
|
|
155
181
|
// Check if the field getter does exist
|
156
|
-
if (!me.__proto__
|
182
|
+
if (!Object.hasOwn(me.__proto__, fieldName)) {
|
157
183
|
Logger.logError('The record does not contain the field', fieldName, me)
|
158
184
|
}
|
159
185
|
|
@@ -177,6 +203,15 @@ class RecordFactory extends Base {
|
|
177
203
|
return null
|
178
204
|
}
|
179
205
|
|
206
|
+
/**
|
207
|
+
* Bulk-update multiple record fields at once
|
208
|
+
* @param {Object} fields
|
209
|
+
*/
|
210
|
+
reset(fields) {
|
211
|
+
this.setOriginal(fields);
|
212
|
+
this.set(fields)
|
213
|
+
}
|
214
|
+
|
180
215
|
/**
|
181
216
|
* Bulk-update multiple record fields at once
|
182
217
|
* @param {Object} fields
|
@@ -214,7 +249,7 @@ class RecordFactory extends Base {
|
|
214
249
|
|
215
250
|
if (Array.isArray(model.fields)) {
|
216
251
|
model.fields.forEach(field => {
|
217
|
-
instance.createField({field,
|
252
|
+
instance.createField({field, model, proto: cls.prototype})
|
218
253
|
})
|
219
254
|
}
|
220
255
|
|
@@ -228,23 +263,6 @@ class RecordFactory extends Base {
|
|
228
263
|
}
|
229
264
|
}
|
230
265
|
|
231
|
-
/**
|
232
|
-
* @param {Object} record
|
233
|
-
* @returns {Boolean} true in case a change was found
|
234
|
-
*/
|
235
|
-
isModified(record) {
|
236
|
-
return record.isModified
|
237
|
-
}
|
238
|
-
|
239
|
-
/**
|
240
|
-
* @param {Object} record
|
241
|
-
* @param {String} fieldName
|
242
|
-
* @returns {Boolean|null} null in case the model does not use trackModifiedFields, true in case a change was found
|
243
|
-
*/
|
244
|
-
isModifiedField(record, fieldName) {
|
245
|
-
return record.isModifiedField(fieldName)
|
246
|
-
}
|
247
|
-
|
248
266
|
/**
|
249
267
|
* Tests if a given object is an instance of a class created by this factory
|
250
268
|
* @param {Object} record
|
@@ -353,6 +371,10 @@ class RecordFactory extends Base {
|
|
353
371
|
* @protected
|
354
372
|
*/
|
355
373
|
setRecordData({fieldName, model, record, useOriginalData=false, value}) {
|
374
|
+
if (useOriginalData && !model.trackModifiedFields) {
|
375
|
+
return
|
376
|
+
}
|
377
|
+
|
356
378
|
let scope = useOriginalData ? originalDataSymbol : dataSymbol;
|
357
379
|
|
358
380
|
if (model.hasNestedFields && fieldName.includes('.')) {
|
@@ -378,9 +400,13 @@ class RecordFactory extends Base {
|
|
378
400
|
* @param {Boolean} data.useOriginalData=false true will apply changes to the originalData symbol
|
379
401
|
*/
|
380
402
|
setRecordFields({changedFields=[], fields, model, record, silent=false, useOriginalData=false}) {
|
381
|
-
let {fieldsMap} = model,
|
403
|
+
let {fieldsMap, trackModifiedFields} = model,
|
382
404
|
fieldExists, oldValue;
|
383
405
|
|
406
|
+
if (!trackModifiedFields && useOriginalData) {
|
407
|
+
return
|
408
|
+
}
|
409
|
+
|
384
410
|
Object.entries(fields).forEach(([key, value]) => {
|
385
411
|
fieldExists = fieldsMap.has(key);
|
386
412
|
|
@@ -402,8 +428,8 @@ class RecordFactory extends Base {
|
|
402
428
|
if (!Neo.isEqual(oldValue, value)) {
|
403
429
|
instance.setRecordData({fieldName: key, model, record, useOriginalData, value});
|
404
430
|
|
405
|
-
if (!useOriginalData) {
|
406
|
-
record
|
431
|
+
if (!trackModifiedFields && !useOriginalData) {
|
432
|
+
record[isModifiedSymbol] = true
|
407
433
|
}
|
408
434
|
|
409
435
|
changedFields.push({name: key, oldValue, value})
|
@@ -411,7 +437,7 @@ class RecordFactory extends Base {
|
|
411
437
|
}
|
412
438
|
});
|
413
439
|
|
414
|
-
if (!silent && Object.keys(changedFields).length > 0) {
|
440
|
+
if (!silent && !useOriginalData && Object.keys(changedFields).length > 0) {
|
415
441
|
Neo.get(model.storeId)?.onRecordChange({fields: changedFields, model, record})
|
416
442
|
}
|
417
443
|
}
|
package/src/dialog/Base.mjs
CHANGED
package/src/grid/View.mjs
CHANGED
@@ -72,6 +72,10 @@ class GridView extends Component {
|
|
72
72
|
* @protected
|
73
73
|
*/
|
74
74
|
columnPositions_: [],
|
75
|
+
/**
|
76
|
+
* @member {Boolean} highlightModifiedCells_=false
|
77
|
+
*/
|
78
|
+
highlightModifiedCells_: false,
|
75
79
|
/**
|
76
80
|
* @member {Boolean} isScrolling_=false
|
77
81
|
*/
|
@@ -432,6 +436,12 @@ class GridView extends Component {
|
|
432
436
|
cellCls.push('neo-' + column.cellAlign)
|
433
437
|
}
|
434
438
|
|
439
|
+
if (me.highlightModifiedCells) {
|
440
|
+
if (record.isModifiedField(dataField)) {
|
441
|
+
cellCls.push('neo-is-modified')
|
442
|
+
}
|
443
|
+
}
|
444
|
+
|
435
445
|
if (!cellId) {
|
436
446
|
cellId = me.getCellId(record, column.dataField)
|
437
447
|
}
|
@@ -803,9 +813,9 @@ class GridView extends Component {
|
|
803
813
|
fieldNames = fields.map(field => field.name),
|
804
814
|
needsUpdate = false,
|
805
815
|
{gridContainer} = me,
|
806
|
-
{selectionModel} = gridContainer,
|
816
|
+
{selectionModel} = gridContainer.view,
|
807
817
|
{vdom} = me,
|
808
|
-
cellId, cellNode, column, index
|
818
|
+
cellId, cellNode, cellStyle, cellVdom, column, index;
|
809
819
|
|
810
820
|
if (fieldNames.includes(me.colspanField)) {
|
811
821
|
index = me.store.indexOf(record);
|
@@ -821,14 +831,22 @@ class GridView extends Component {
|
|
821
831
|
cellId = me.getCellId(record, field.name);
|
822
832
|
cellNode = VDomUtil.find(vdom, cellId);
|
823
833
|
|
824
|
-
//
|
834
|
+
// The vdom might not exist yet => nothing to do in this case
|
825
835
|
if (cellNode?.vdom) {
|
836
|
+
cellStyle = cellNode.vdom.style;
|
826
837
|
column = me.getColumn(field.name);
|
827
838
|
index = cellNode.index;
|
839
|
+
cellVdom = me.applyRendererOutput({cellId, column, gridContainer, index, record});
|
828
840
|
needsUpdate = true;
|
829
|
-
scope = column.rendererScope || gridContainer;
|
830
841
|
|
831
|
-
|
842
|
+
// The cell-positioning logic happens outside applyRendererOutput()
|
843
|
+
// We need to preserve these styles
|
844
|
+
Object.assign(cellVdom.style, {
|
845
|
+
left : cellStyle.left,
|
846
|
+
width: cellStyle.width
|
847
|
+
});
|
848
|
+
|
849
|
+
cellNode.parentNode.cn[index] = cellVdom
|
832
850
|
}
|
833
851
|
}
|
834
852
|
})
|
package/src/table/View.mjs
CHANGED
@@ -154,7 +154,7 @@ class View extends Component {
|
|
154
154
|
cellCls.push('neo-' + column.cellAlign)
|
155
155
|
}
|
156
156
|
|
157
|
-
if (me.highlightModifiedCells
|
157
|
+
if (me.highlightModifiedCells) {
|
158
158
|
if (record.isModifiedField(dataField)) {
|
159
159
|
cellCls.push('neo-is-modified')
|
160
160
|
}
|