neo.mjs 7.8.0 → 7.9.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/MainContainerController.mjs +1 -1
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/table/nestedRecordFields/EditUserDialog.mjs +127 -0
- package/examples/table/nestedRecordFields/MainContainer.mjs +113 -0
- package/examples/table/nestedRecordFields/MainContainerModel.mjs +61 -0
- package/examples/table/nestedRecordFields/MainModel.mjs +41 -0
- package/examples/table/nestedRecordFields/MainStore.mjs +54 -0
- package/examples/table/nestedRecordFields/app.mjs +6 -0
- package/examples/table/nestedRecordFields/index.html +11 -0
- package/examples/table/nestedRecordFields/neo-config.json +6 -0
- package/package.json +2 -2
- package/resources/scss/src/apps/portal/learn/PageContainer.scss +5 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/data/Model.mjs +0 -7
- package/src/data/RecordFactory.mjs +82 -61
- package/src/data/Store.mjs +7 -0
- package/src/form/field/CheckBox.mjs +12 -7
- package/src/form/field/ComboBox.mjs +8 -7
- package/src/grid/View.mjs +2 -2
- package/src/list/Base.mjs +1 -1
- package/src/model/Component.mjs +10 -1
- package/src/table/View.mjs +31 -15
- package/src/table/header/Button.mjs +33 -18
package/apps/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
@@ -141,7 +141,7 @@ class MainContainerController extends Controller {
|
|
141
141
|
*/
|
142
142
|
onRouteDefault(data) {
|
143
143
|
if (!this.getModel().data.currentPageRecord) {
|
144
|
-
this.onRouteLearnItem({itemId: '
|
144
|
+
this.onRouteLearnItem({itemId: 'benefits.Introduction'})
|
145
145
|
}
|
146
146
|
}
|
147
147
|
|
@@ -0,0 +1,127 @@
|
|
1
|
+
import CheckBox from '../../../src/form/field/CheckBox.mjs';
|
2
|
+
import CountryField from '../../../src/form/field/Country.mjs';
|
3
|
+
import Dialog from '../../../src/dialog/Base.mjs';
|
4
|
+
import TextField from '../../../src/form/field/Text.mjs';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @class Neo.examples.table.nestedRecordFields.EditUserDialog
|
8
|
+
* @extends Neo.dialog.Base
|
9
|
+
*/
|
10
|
+
class EditUserDialog extends Dialog {
|
11
|
+
static config = {
|
12
|
+
/**
|
13
|
+
* @member {String} className='Neo.examples.model.dialog.EditUserDialog'
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
className: 'Neo.examples.model.dialog.EditUserDialog',
|
17
|
+
/**
|
18
|
+
* @member {String} closeAction='hide'
|
19
|
+
*/
|
20
|
+
closeAction: 'hide',
|
21
|
+
/**
|
22
|
+
* @member {Object} containerConfig={style:{padding:'1em'}}
|
23
|
+
*/
|
24
|
+
containerConfig: {
|
25
|
+
style: {
|
26
|
+
padding: '1em'
|
27
|
+
}
|
28
|
+
},
|
29
|
+
/**
|
30
|
+
* @member {Boolean} modal=true
|
31
|
+
*/
|
32
|
+
modal: true,
|
33
|
+
/**
|
34
|
+
* @member {Record|null} record_=null
|
35
|
+
*/
|
36
|
+
record_: null,
|
37
|
+
/**
|
38
|
+
* @member {String} title='Edit User'
|
39
|
+
*/
|
40
|
+
title: 'Edit User',
|
41
|
+
/**
|
42
|
+
* @member {Object} itemDefaults
|
43
|
+
*/
|
44
|
+
itemDefaults: {
|
45
|
+
flex : 'none',
|
46
|
+
labelWidth: 110
|
47
|
+
},
|
48
|
+
/**
|
49
|
+
* @member {Object[]} items
|
50
|
+
*/
|
51
|
+
items: [{
|
52
|
+
module : TextField,
|
53
|
+
labelText: 'Firstname',
|
54
|
+
listeners: {change: 'up.onFirstnameFieldChange'},
|
55
|
+
reference: 'firstname-field'
|
56
|
+
}, {
|
57
|
+
module : TextField,
|
58
|
+
labelText: 'Lastname',
|
59
|
+
listeners: {change: 'up.onLastnameFieldChange'},
|
60
|
+
reference: 'lastname-field'
|
61
|
+
}, {
|
62
|
+
module : CountryField,
|
63
|
+
bind : {store: 'stores.countries'},
|
64
|
+
labelText : 'Country',
|
65
|
+
listeners : {change: 'up.onCountryFieldChange'},
|
66
|
+
reference : 'country-field',
|
67
|
+
valueField: 'code'
|
68
|
+
}, {
|
69
|
+
module : CheckBox,
|
70
|
+
labelText: 'Selected',
|
71
|
+
listeners: {change: 'up.onSelectedFieldChange'},
|
72
|
+
reference: 'selected-field',
|
73
|
+
style : {marginTop: '1em'}
|
74
|
+
}]
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Triggered after the record config got changed
|
79
|
+
* @param {Record|null} value
|
80
|
+
* @param {Record|null} oldValue
|
81
|
+
* @protected
|
82
|
+
*/
|
83
|
+
async afterSetRecord(value, oldValue) {
|
84
|
+
if (value) {
|
85
|
+
let me = this,
|
86
|
+
{record} = me;
|
87
|
+
|
88
|
+
// ensure the store has its data
|
89
|
+
await me.timeout(20);
|
90
|
+
|
91
|
+
me.getItem('country-field') .value = record.country;
|
92
|
+
me.getItem('firstname-field').value = record.user.firstname;
|
93
|
+
me.getItem('lastname-field') .value = record.user.lastname;
|
94
|
+
me.getItem('selected-field') .checked = record.annotations.selected
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* @param {Object} data
|
100
|
+
*/
|
101
|
+
onCountryFieldChange(data) {
|
102
|
+
this.record.country = data.value.code
|
103
|
+
}
|
104
|
+
|
105
|
+
/**
|
106
|
+
* @param {Object} data
|
107
|
+
*/
|
108
|
+
onFirstnameFieldChange(data) {
|
109
|
+
this.record.user.firstname = data.value
|
110
|
+
}
|
111
|
+
|
112
|
+
/**
|
113
|
+
* @param {Object} data
|
114
|
+
*/
|
115
|
+
onLastnameFieldChange(data) {
|
116
|
+
this.record.user.lastname = data.value
|
117
|
+
}
|
118
|
+
|
119
|
+
/**
|
120
|
+
* @param {Object} data
|
121
|
+
*/
|
122
|
+
onSelectedFieldChange(data) {
|
123
|
+
this.record.annotations.selected = data.value
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
export default Neo.setupClass(EditUserDialog);
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import Button from '../../../src/button/Base.mjs';
|
2
|
+
import MainContainerModel from './MainContainerModel.mjs';
|
3
|
+
import TableContainer from '../../../src/table/Container.mjs';
|
4
|
+
import Viewport from '../../../src/container/Viewport.mjs';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @class Neo.examples.table.nestedRecordFields.MainContainer
|
8
|
+
* @extends Neo.container.Viewport
|
9
|
+
*/
|
10
|
+
class MainContainer extends Viewport {
|
11
|
+
static config = {
|
12
|
+
/**
|
13
|
+
* @member {String} className='Neo.examples.table.nestedRecordFields.MainContainer'
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
className: 'Neo.examples.table.nestedRecordFields.MainContainer',
|
17
|
+
/**
|
18
|
+
* @member {Object|String} layout='fit'
|
19
|
+
*/
|
20
|
+
layout: 'fit',
|
21
|
+
/**
|
22
|
+
* @member {Neo.model.Component} model=MainContainerModel
|
23
|
+
*/
|
24
|
+
model: MainContainerModel,
|
25
|
+
/**
|
26
|
+
* @member {Object} style={padding:'20px'}
|
27
|
+
*/
|
28
|
+
style: {padding: '20px'},
|
29
|
+
/**
|
30
|
+
* @member {Object[]} items
|
31
|
+
*/
|
32
|
+
items: [{
|
33
|
+
module: TableContainer,
|
34
|
+
bind : {store : 'stores.mainStore'},
|
35
|
+
|
36
|
+
columns: [
|
37
|
+
{dataField: 'user.firstname', text: 'Firstname'},
|
38
|
+
{dataField: 'user.lastname', text: 'Lastname'},
|
39
|
+
{dataField: 'githubId', text: 'Github Id'},
|
40
|
+
{dataField: 'country', text: 'Country', renderer: 'up.countryRenderer'},
|
41
|
+
{dataField: 'edit', text: 'Edit Action', renderer: 'up.editRenderer'}
|
42
|
+
]
|
43
|
+
}]
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* @member {Neo.dialog.Base|null} dialog=null
|
48
|
+
*/
|
49
|
+
dialog = null
|
50
|
+
|
51
|
+
/**
|
52
|
+
* @param {Object} data
|
53
|
+
*/
|
54
|
+
countryRenderer({record}) {
|
55
|
+
let countryStore = this.getModel().getStore('countries');
|
56
|
+
|
57
|
+
if (countryStore.getCount() > 0) {
|
58
|
+
return countryStore.get(record.country).name
|
59
|
+
}
|
60
|
+
|
61
|
+
return ''
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* @param {Object} data
|
66
|
+
*/
|
67
|
+
editButtonHandler(data) {
|
68
|
+
let me = this,
|
69
|
+
button = data.component,
|
70
|
+
{appName, dialog, windowId} = me,
|
71
|
+
{record} = button;
|
72
|
+
|
73
|
+
if (!dialog) {
|
74
|
+
import('./EditUserDialog.mjs').then(module => {
|
75
|
+
me.dialog = Neo.create({
|
76
|
+
module : module.default,
|
77
|
+
animateTargetId: button.id,
|
78
|
+
appName,
|
79
|
+
model : {parent: me.getModel()},
|
80
|
+
record,
|
81
|
+
windowId
|
82
|
+
})
|
83
|
+
})
|
84
|
+
} else {
|
85
|
+
dialog.animateTargetId = button.id;
|
86
|
+
dialog.record = record;
|
87
|
+
|
88
|
+
dialog.show()
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* @param {Object} data
|
94
|
+
*/
|
95
|
+
editRenderer({column, index, record, tableContainer}) {
|
96
|
+
let me = this,
|
97
|
+
{appName, windowId} = me,
|
98
|
+
widgetId = `${column.id}-widget-${index}`,
|
99
|
+
button = (column.widgetMap || (column.widgetMap = {}))[widgetId] || (column.widgetMap[widgetId] = Neo.create({
|
100
|
+
module : Button,
|
101
|
+
appName,
|
102
|
+
handler : 'up.editButtonHandler',
|
103
|
+
parentId: tableContainer.id,
|
104
|
+
record,
|
105
|
+
text : 'Edit',
|
106
|
+
windowId
|
107
|
+
}));
|
108
|
+
|
109
|
+
return button.vdom
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
export default Neo.setupClass(MainContainer);
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import MainStore from './MainStore.mjs';
|
2
|
+
import Model from '../../../src/model/Component.mjs';
|
3
|
+
import Store from '../../../src/data/Store.mjs';
|
4
|
+
|
5
|
+
const countrySymbol = Symbol.for('country');
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @class Neo.examples.table.nestedRecordFields.MainContainerModel
|
9
|
+
* @extends Neo.model.Component
|
10
|
+
*/
|
11
|
+
class MainContainerModel extends Model {
|
12
|
+
static config = {
|
13
|
+
/**
|
14
|
+
* @member {String} className='Neo.examples.table.nestedRecordFields.MainContainerModel'
|
15
|
+
* @protected
|
16
|
+
*/
|
17
|
+
className: 'Neo.examples.table.nestedRecordFields.MainContainerModel',
|
18
|
+
/**
|
19
|
+
* @member {Object} stores
|
20
|
+
*/
|
21
|
+
stores: {
|
22
|
+
countries: {
|
23
|
+
module : Store,
|
24
|
+
autoLoad : true,
|
25
|
+
keyProperty: 'code',
|
26
|
+
listeners : {load: 'onCountryStoreLoad'},
|
27
|
+
url : '../../../resources/examples/data/countries.json',
|
28
|
+
|
29
|
+
model: {
|
30
|
+
fields: [
|
31
|
+
{name: 'code'},
|
32
|
+
{name: 'name'}
|
33
|
+
]},
|
34
|
+
},
|
35
|
+
mainStore: MainStore
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
/**
|
40
|
+
* @param {Record[]} items
|
41
|
+
*/
|
42
|
+
onCountryStoreLoad(items) {
|
43
|
+
let me = this,
|
44
|
+
mainStore = me.getStore('mainStore'),
|
45
|
+
country;
|
46
|
+
|
47
|
+
// if the main table store is already loaded, the country field renderer had no data
|
48
|
+
if (mainStore.getCount() > 0) {
|
49
|
+
mainStore.items.forEach(record => {
|
50
|
+
country = record.country;
|
51
|
+
|
52
|
+
// hack resetting the current value to get a new record change
|
53
|
+
record[countrySymbol] = null;
|
54
|
+
|
55
|
+
record.country = country
|
56
|
+
})
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
export default Neo.setupClass(MainContainerModel);
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import Model from '../../../src/data/Model.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class Neo.examples.table.nestedRecordFields.MainModel
|
5
|
+
* @extends Neo.data.Model
|
6
|
+
*/
|
7
|
+
class MainModel extends Model {
|
8
|
+
static config = {
|
9
|
+
className: 'Neo.examples.table.container.MainModel',
|
10
|
+
|
11
|
+
fields: [{
|
12
|
+
name: 'annotations',
|
13
|
+
type: 'Object',
|
14
|
+
|
15
|
+
fields: [{
|
16
|
+
name : 'annotations.selected',
|
17
|
+
type : 'Boolean',
|
18
|
+
defaultValue: false
|
19
|
+
}]
|
20
|
+
}, {
|
21
|
+
name: 'country',
|
22
|
+
type: 'String'
|
23
|
+
}, {
|
24
|
+
name: 'githubId',
|
25
|
+
type: 'String'
|
26
|
+
}, {
|
27
|
+
name: 'user',
|
28
|
+
type: 'Object',
|
29
|
+
|
30
|
+
fields: [{
|
31
|
+
name: 'user.firstname',
|
32
|
+
type: 'String'
|
33
|
+
}, {
|
34
|
+
name: 'user.lastname',
|
35
|
+
type: 'String'
|
36
|
+
}]
|
37
|
+
}]
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
export default Neo.setupClass(MainModel);
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import Model from './MainModel.mjs';
|
2
|
+
import Store from '../../../src/data/Store.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Neo.examples.table.nestedRecordFields.MainStore
|
6
|
+
* @extends Neo.data.Store
|
7
|
+
*/
|
8
|
+
class MainStore extends Store {
|
9
|
+
static config = {
|
10
|
+
className : 'Neo.examples.table.container.MainStore',
|
11
|
+
keyProperty: 'githubId',
|
12
|
+
model : Model,
|
13
|
+
|
14
|
+
data: [{
|
15
|
+
country : 'DE',
|
16
|
+
githubId: 'tobiu',
|
17
|
+
|
18
|
+
user: {
|
19
|
+
firstname: 'Tobias',
|
20
|
+
lastname : 'Uhlig'
|
21
|
+
}
|
22
|
+
}, {
|
23
|
+
annotations: {
|
24
|
+
selected: true
|
25
|
+
},
|
26
|
+
|
27
|
+
country : 'US',
|
28
|
+
githubId: 'rwaters',
|
29
|
+
|
30
|
+
user: {
|
31
|
+
firstname: 'Rich',
|
32
|
+
lastname : 'Waters'
|
33
|
+
}
|
34
|
+
}, {
|
35
|
+
country : 'DE',
|
36
|
+
githubId: 'mrsunshine',
|
37
|
+
|
38
|
+
user: {
|
39
|
+
firstname: 'Nils',
|
40
|
+
lastname : 'Dehl'
|
41
|
+
}
|
42
|
+
}, {
|
43
|
+
country : 'US',
|
44
|
+
githubId: 'camtnbikerrwc',
|
45
|
+
|
46
|
+
user: {
|
47
|
+
firstname: 'Gerard',
|
48
|
+
lastname : 'Horan'
|
49
|
+
}
|
50
|
+
}]
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
export default Neo.setupClass(MainStore);
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE HTML>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<title>Neo Table: Nested Record Fields</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<script src="../../../src/MicroLoader.mjs" type="module"></script>
|
10
|
+
</body>
|
11
|
+
</html>
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "7.
|
3
|
+
"version": "7.9.0",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -63,7 +63,7 @@
|
|
63
63
|
"sass": "^1.79.3",
|
64
64
|
"siesta-lite": "5.5.2",
|
65
65
|
"url": "^0.11.4",
|
66
|
-
"webpack": "^5.
|
66
|
+
"webpack": "^5.95.0",
|
67
67
|
"webpack-cli": "^5.1.4",
|
68
68
|
"webpack-dev-server": "^5.1.0",
|
69
69
|
"webpack-hook-plugin": "^1.0.7",
|
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 '7.
|
265
|
+
* @default '7.9.0'
|
266
266
|
* @memberOf! module:Neo
|
267
267
|
* @name config.version
|
268
268
|
* @type String
|
269
269
|
*/
|
270
|
-
version: '7.
|
270
|
+
version: '7.9.0'
|
271
271
|
};
|
272
272
|
|
273
273
|
Object.assign(DefaultConfig, {
|
package/src/data/Model.mjs
CHANGED
@@ -38,13 +38,6 @@ class Model extends Base {
|
|
38
38
|
trackModifiedFields: false
|
39
39
|
}
|
40
40
|
|
41
|
-
/**
|
42
|
-
* A property set in all data records so that they are easily identifiable.
|
43
|
-
* @property {Boolean} isRecord=true
|
44
|
-
* @readonly
|
45
|
-
*/
|
46
|
-
isRecord = true
|
47
|
-
|
48
41
|
/**
|
49
42
|
* Finds a field config by a given field name
|
50
43
|
* @param {String} name
|
@@ -16,11 +16,6 @@ class RecordFactory extends Base {
|
|
16
16
|
* @protected
|
17
17
|
*/
|
18
18
|
className: 'Neo.data.RecordFactory',
|
19
|
-
/**
|
20
|
-
* @member {Boolean} singleton=true
|
21
|
-
* @protected
|
22
|
-
*/
|
23
|
-
singleton: true,
|
24
19
|
/**
|
25
20
|
* The internal record prefix for original field values.
|
26
21
|
* Only used in case the model has trackModifiedFields set to true.
|
@@ -30,7 +25,84 @@ class RecordFactory extends Base {
|
|
30
25
|
/**
|
31
26
|
* @member {String} recordNamespace='Neo.data.record'
|
32
27
|
*/
|
33
|
-
recordNamespace: 'Neo.data.record'
|
28
|
+
recordNamespace: 'Neo.data.record',
|
29
|
+
/**
|
30
|
+
* @member {Boolean} singleton=true
|
31
|
+
* @protected
|
32
|
+
*/
|
33
|
+
singleton: true
|
34
|
+
}
|
35
|
+
|
36
|
+
/**
|
37
|
+
* @param {Object} data
|
38
|
+
* @param {Object} data.config
|
39
|
+
* @param {Object} data.field
|
40
|
+
* @param {Neo.data.RecordFactory} data.me
|
41
|
+
* @param {Neo.data.Model} data.model
|
42
|
+
* @param {String} data.path=''
|
43
|
+
*/
|
44
|
+
createField({config, field, me, model, path=''}) {
|
45
|
+
let value = Neo.ns(field.mapping || field.name, false, config),
|
46
|
+
fieldName = field.name.split('.').pop(),
|
47
|
+
symbol = Symbol.for(fieldName),
|
48
|
+
fieldPath, parsedValue, properties;
|
49
|
+
|
50
|
+
if (field.fields) {
|
51
|
+
field.fields.forEach(childField => {
|
52
|
+
fieldPath = path.split('.');
|
53
|
+
fieldPath = fieldPath.filter(Boolean);
|
54
|
+
fieldPath.push(field.name);
|
55
|
+
|
56
|
+
this.createField({config, field: childField, me, model, path: fieldPath.join('.')})
|
57
|
+
})
|
58
|
+
} else {
|
59
|
+
if (value === undefined && Object.hasOwn(field, 'defaultValue')) {
|
60
|
+
value = field.defaultValue
|
61
|
+
}
|
62
|
+
|
63
|
+
parsedValue = instance.parseRecordValue(me, field, value, config);
|
64
|
+
|
65
|
+
properties = {
|
66
|
+
[symbol]: {
|
67
|
+
value : Neo.clone(parsedValue, true),
|
68
|
+
writable: true
|
69
|
+
},
|
70
|
+
[fieldName]: {
|
71
|
+
configurable: true,
|
72
|
+
enumerable : true,
|
73
|
+
get() {
|
74
|
+
return this[symbol]
|
75
|
+
},
|
76
|
+
set(value) {
|
77
|
+
let oldValue = this[symbol];
|
78
|
+
|
79
|
+
value = instance.parseRecordValue(me, field, value);
|
80
|
+
|
81
|
+
if (!Neo.isEqual(value, oldValue)) {
|
82
|
+
this[symbol] = value;
|
83
|
+
|
84
|
+
me._isModified = true;
|
85
|
+
me._isModified = instance.isModified(me, model.trackModifiedFields);
|
86
|
+
|
87
|
+
instance.onRecordChange({
|
88
|
+
fields: [{name: field.name, oldValue, value}],
|
89
|
+
model,
|
90
|
+
record: me
|
91
|
+
})
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
};
|
96
|
+
|
97
|
+
// adding the original value of each field
|
98
|
+
if (model.trackModifiedFields) {
|
99
|
+
properties[instance.ovPrefix + field.name] = {
|
100
|
+
value: parsedValue
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
Object.defineProperties(path ? Neo.ns(path, true, me) : me, properties)
|
105
|
+
}
|
34
106
|
}
|
35
107
|
|
36
108
|
/**
|
@@ -67,8 +139,7 @@ class RecordFactory extends Base {
|
|
67
139
|
static name = 'Record'
|
68
140
|
|
69
141
|
constructor(config) {
|
70
|
-
let me = this
|
71
|
-
properties;
|
142
|
+
let me = this;
|
72
143
|
|
73
144
|
Object.defineProperties(me, {
|
74
145
|
_isModified: {
|
@@ -79,57 +150,7 @@ class RecordFactory extends Base {
|
|
79
150
|
|
80
151
|
if (Array.isArray(model.fields)) {
|
81
152
|
model.fields.forEach(field => {
|
82
|
-
|
83
|
-
symbol = Symbol.for(field.name),
|
84
|
-
parsedValue;
|
85
|
-
|
86
|
-
if (!Object.hasOwn(config, field.name) && Object.hasOwn(field, 'defaultValue')) {
|
87
|
-
value = field.defaultValue
|
88
|
-
}
|
89
|
-
|
90
|
-
parsedValue = instance.parseRecordValue(me, field, value, config);
|
91
|
-
|
92
|
-
properties = {
|
93
|
-
[symbol]: {
|
94
|
-
value : parsedValue,
|
95
|
-
writable: true
|
96
|
-
},
|
97
|
-
[field.name]: {
|
98
|
-
configurable: true,
|
99
|
-
enumerable : true,
|
100
|
-
get() {
|
101
|
-
return this[symbol]
|
102
|
-
},
|
103
|
-
set(value) {
|
104
|
-
let me = this,
|
105
|
-
oldValue = me[symbol];
|
106
|
-
|
107
|
-
value = instance.parseRecordValue(me, field, value);
|
108
|
-
|
109
|
-
if (!Neo.isEqual(value, oldValue)) {
|
110
|
-
me[symbol] = value;
|
111
|
-
|
112
|
-
me._isModified = true;
|
113
|
-
me._isModified = instance.isModified(me, model.trackModifiedFields);
|
114
|
-
|
115
|
-
instance.onRecordChange({
|
116
|
-
fields: [{name: field.name, oldValue, value}],
|
117
|
-
model,
|
118
|
-
record: me
|
119
|
-
})
|
120
|
-
}
|
121
|
-
}
|
122
|
-
}
|
123
|
-
};
|
124
|
-
|
125
|
-
// adding the original value of each field
|
126
|
-
if (model.trackModifiedFields) {
|
127
|
-
properties[instance.ovPrefix + field.name] = {
|
128
|
-
value: parsedValue
|
129
|
-
}
|
130
|
-
}
|
131
|
-
|
132
|
-
Object.defineProperties(me, properties)
|
153
|
+
instance.createField({config, field, me, model})
|
133
154
|
})
|
134
155
|
}
|
135
156
|
}
|
@@ -151,8 +172,8 @@ class RecordFactory extends Base {
|
|
151
172
|
}
|
152
173
|
};
|
153
174
|
|
154
|
-
Object.defineProperty(cls.prototype, 'isRecord', {
|
155
|
-
Object.defineProperty(cls, 'isClass', {
|
175
|
+
Object.defineProperty(cls.prototype, 'isRecord', {value: true});
|
176
|
+
Object.defineProperty(cls, 'isClass', {value: true});
|
156
177
|
|
157
178
|
return ns[key]
|
158
179
|
}
|
package/src/data/Store.mjs
CHANGED
@@ -309,6 +309,13 @@ class Store extends Base {
|
|
309
309
|
RecordFactory.createRecord(config)
|
310
310
|
}
|
311
311
|
|
312
|
+
/**
|
313
|
+
* @returns {String}
|
314
|
+
*/
|
315
|
+
getKeyProperty() {
|
316
|
+
return this.keyProperty || this.model.keyProperty
|
317
|
+
}
|
318
|
+
|
312
319
|
/**
|
313
320
|
* @param {Object} opts={}
|
314
321
|
* @param {Object} opts.data
|
@@ -456,14 +456,19 @@ class CheckBox extends Base {
|
|
456
456
|
*/
|
457
457
|
getGroupValue() {
|
458
458
|
let form = this.getClosestForm(),
|
459
|
-
|
460
|
-
value = []
|
459
|
+
path = this.getPath(),
|
460
|
+
value = [],
|
461
|
+
fields;
|
461
462
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
463
|
+
if (path) {
|
464
|
+
fields = ComponentManager.find({path});
|
465
|
+
|
466
|
+
fields.forEach(field => {
|
467
|
+
if (field.checked && field.getClosestForm() === form) {
|
468
|
+
NeoArray.add(value, field.value)
|
469
|
+
}
|
470
|
+
})
|
471
|
+
}
|
467
472
|
|
468
473
|
return value
|
469
474
|
}
|
@@ -346,6 +346,7 @@ class ComboBox extends Picker {
|
|
346
346
|
role : 'listbox',
|
347
347
|
selectionModel: {stayInList: false},
|
348
348
|
store : me.store,
|
349
|
+
windowId : me.windowId,
|
349
350
|
...me.listConfig
|
350
351
|
});
|
351
352
|
|
@@ -580,18 +581,18 @@ class ComboBox extends Picker {
|
|
580
581
|
}
|
581
582
|
|
582
583
|
/**
|
583
|
-
* @param {Object}
|
584
|
+
* @param {Object} data
|
584
585
|
* @protected
|
585
586
|
*/
|
586
|
-
onListItemNavigate(
|
587
|
-
let {activeIndex} =
|
587
|
+
onListItemNavigate(data) {
|
588
|
+
let {activeIndex} = data;
|
588
589
|
|
589
590
|
if (activeIndex >= 0) {
|
590
591
|
let me = this,
|
591
592
|
{store} = me;
|
592
593
|
|
593
|
-
me.activeRecord = store.getAt(activeIndex);
|
594
|
-
me.activeRecordId = me.activeRecord[store.
|
594
|
+
me.activeRecord = data.record || store.getAt(activeIndex);
|
595
|
+
me.activeRecordId = me.activeRecord[store.getKeyProperty()];
|
595
596
|
|
596
597
|
// Update typeahead hint (which updates DOM), or update DOM
|
597
598
|
me.typeAhead ? me.updateTypeAheadValue(me.lastManualInput) : me.update()
|
@@ -737,7 +738,7 @@ class ComboBox extends Picker {
|
|
737
738
|
if (match && inputHintEl) {
|
738
739
|
inputHintEl.value = value + match[displayField].substr(value.length);
|
739
740
|
me.activeRecord = match;
|
740
|
-
me.activeRecordId = match[store.
|
741
|
+
me.activeRecordId = match[store.getKeyProperty()]
|
741
742
|
}
|
742
743
|
}
|
743
744
|
|
@@ -771,7 +772,7 @@ class ComboBox extends Picker {
|
|
771
772
|
* The select event fires when a list item gets selected
|
772
773
|
* @event select
|
773
774
|
* @param {Object} record
|
774
|
-
* @param {value} record[store.
|
775
|
+
* @param {value} record[store.getKeyProperty()]
|
775
776
|
* @returns {Object}
|
776
777
|
*/
|
777
778
|
|
package/src/grid/View.mjs
CHANGED
@@ -95,9 +95,9 @@ class View extends Component {
|
|
95
95
|
|
96
96
|
for (; j < colCount; j++) {
|
97
97
|
column = columns[j];
|
98
|
-
rendererValue =
|
98
|
+
rendererValue = Neo.ns(column.field, false, record);
|
99
99
|
|
100
|
-
if (rendererValue === undefined) {
|
100
|
+
if (rendererValue === null || rendererValue === undefined) {
|
101
101
|
rendererValue = ''
|
102
102
|
}
|
103
103
|
|
package/src/list/Base.mjs
CHANGED
@@ -689,7 +689,7 @@ class Base extends Component {
|
|
689
689
|
getItemRecordId(vnodeId) {
|
690
690
|
let itemId = vnodeId.split('__')[1],
|
691
691
|
{model} = this.store,
|
692
|
-
keyField = model?.getField(
|
692
|
+
keyField = model?.getField(this.getKeyProperty()),
|
693
693
|
keyType = keyField?.type?.toLowerCase();
|
694
694
|
|
695
695
|
if (keyType === 'int' || keyType === 'integer') {
|
package/src/model/Component.mjs
CHANGED
@@ -155,10 +155,19 @@ class Component extends Base {
|
|
155
155
|
*/
|
156
156
|
beforeSetStores(value, oldValue) {
|
157
157
|
if (value) {
|
158
|
-
let
|
158
|
+
let me = this,
|
159
|
+
controller = me.getController();
|
159
160
|
|
160
161
|
Object.entries(value).forEach(([key, storeValue]) => {
|
161
162
|
controller?.parseConfig(storeValue);
|
163
|
+
|
164
|
+
// support mapping string based listeners into the model instance
|
165
|
+
Object.entries(storeValue.listeners || {}).forEach(([listenerKey,listener]) => {
|
166
|
+
if (Neo.isString(listener) && Neo.isFunction(me[listener])) {
|
167
|
+
storeValue.listeners[listenerKey] = me[listener].bind(me)
|
168
|
+
}
|
169
|
+
})
|
170
|
+
|
162
171
|
value[key] = ClassSystemUtil.beforeSetInstance(storeValue)
|
163
172
|
})
|
164
173
|
}
|
package/src/table/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
|
/**
|
@@ -35,6 +36,10 @@ class View extends Component {
|
|
35
36
|
* @member {Object} recordVnodeMap={}
|
36
37
|
*/
|
37
38
|
recordVnodeMap: {},
|
39
|
+
/**
|
40
|
+
* @member {String} selectedRecordField='annotations.selected'
|
41
|
+
*/
|
42
|
+
selectedRecordField: 'annotations.selected',
|
38
43
|
/**
|
39
44
|
* @member {Neo.data.Store|null} store=null
|
40
45
|
*/
|
@@ -86,7 +91,7 @@ class View extends Component {
|
|
86
91
|
cellCls = ['neo-table-cell'],
|
87
92
|
colspan = record[me.colspanField],
|
88
93
|
{dataField} = column,
|
89
|
-
fieldValue =
|
94
|
+
fieldValue = Neo.ns(dataField, false, record),
|
90
95
|
hasStore = tableContainer.store?.model, // todo: remove as soon as all tables use stores (examples table)
|
91
96
|
{vdom} = me,
|
92
97
|
cellConfig, rendererOutput;
|
@@ -189,6 +194,10 @@ class View extends Component {
|
|
189
194
|
|
190
195
|
trCls = me.getTrClass(record, i);
|
191
196
|
|
197
|
+
if (selectedRows && Neo.ns(me.selectedRecordField, false, record)) {
|
198
|
+
NeoArray.add(selectedRows, id)
|
199
|
+
}
|
200
|
+
|
192
201
|
if (selectedRows?.includes(id)) {
|
193
202
|
trCls.push('neo-selected');
|
194
203
|
|
@@ -432,11 +441,12 @@ class View extends Component {
|
|
432
441
|
* @param {Object} opts.record
|
433
442
|
*/
|
434
443
|
onStoreRecordChange(opts) {
|
435
|
-
let me
|
436
|
-
fieldNames
|
437
|
-
needsUpdate
|
438
|
-
tableContainer
|
439
|
-
{
|
444
|
+
let me = this,
|
445
|
+
fieldNames = opts.fields.map(field => field.name),
|
446
|
+
needsUpdate = false,
|
447
|
+
tableContainer = me.parent,
|
448
|
+
{selectionModel} = tableContainer,
|
449
|
+
{vdom} = me,
|
440
450
|
cellId, cellNode, column, index, scope;
|
441
451
|
|
442
452
|
if (fieldNames.includes(me.colspanField)) {
|
@@ -444,17 +454,23 @@ class View extends Component {
|
|
444
454
|
me.createViewData(me.store.items)
|
445
455
|
} else {
|
446
456
|
opts.fields.forEach(field => {
|
447
|
-
|
448
|
-
|
457
|
+
if (field.name === me.selectedRecordField) {
|
458
|
+
if (selectionModel.ntype === 'selection-table-rowmodel') {
|
459
|
+
selectionModel[!field.value && selectionModel.singleSelect ? 'deselect' : 'select'](me.getRowId(opts.record))
|
460
|
+
}
|
461
|
+
} else {
|
462
|
+
cellId = me.getCellId(opts.record, field.name);
|
463
|
+
cellNode = VDomUtil.findVdomChild(vdom, cellId);
|
449
464
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
465
|
+
// the vdom might not exist yet => nothing to do in this case
|
466
|
+
if (cellNode?.vdom) {
|
467
|
+
column = me.getColumn(field.name);
|
468
|
+
index = cellNode.index;
|
469
|
+
needsUpdate = true;
|
470
|
+
scope = column.rendererScope || tableContainer;
|
456
471
|
|
457
|
-
|
472
|
+
cellNode.parentNode.cn[index] = me.applyRendererOutput({cellId, column, record: opts.record, index, tableContainer})
|
473
|
+
}
|
458
474
|
}
|
459
475
|
})
|
460
476
|
}
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import BaseButton
|
2
|
-
import NeoArray
|
3
|
-
import TextField
|
1
|
+
import BaseButton from '../../button/Base.mjs';
|
2
|
+
import NeoArray from '../../util/Array.mjs';
|
3
|
+
import TextField from '../../form/field/Text.mjs';
|
4
|
+
import {resolveCallback} from '../../util/Function.mjs';
|
4
5
|
|
5
6
|
/**
|
6
7
|
* @class Neo.table.header.Button
|
@@ -75,6 +76,10 @@ class Button extends BaseButton {
|
|
75
76
|
* @protected
|
76
77
|
*/
|
77
78
|
isSorted_: null,
|
79
|
+
/**
|
80
|
+
* @member {Function|String|null} renderer_='cellRenderer'
|
81
|
+
*/
|
82
|
+
renderer_: 'cellRenderer',
|
78
83
|
/**
|
79
84
|
* Scope to execute the column renderer.
|
80
85
|
* Defaults to the matching table.Container
|
@@ -261,7 +266,31 @@ class Button extends BaseButton {
|
|
261
266
|
* @protected
|
262
267
|
*/
|
263
268
|
beforeSetCellAlign(value, oldValue) {
|
264
|
-
return this.beforeSetEnumValue(value, oldValue, 'cellAlign', 'cellAlignValues')
|
269
|
+
return this.beforeSetEnumValue(value, oldValue, 'cellAlign', 'cellAlignValues')
|
270
|
+
}
|
271
|
+
|
272
|
+
/**
|
273
|
+
* Triggered before the renderer config gets changed
|
274
|
+
* @param {Function|String|null} value
|
275
|
+
* @param {Function|String|null} oldValue
|
276
|
+
* @protected
|
277
|
+
*/
|
278
|
+
beforeSetRenderer(value, oldValue) {
|
279
|
+
return resolveCallback(value, this).fn
|
280
|
+
}
|
281
|
+
|
282
|
+
/**
|
283
|
+
* @param {Object} data
|
284
|
+
* @param {Neo.button.Base} data.column
|
285
|
+
* @param {String} data.dataField
|
286
|
+
* @param {Number} data.index
|
287
|
+
* @param {Object} data.record
|
288
|
+
* @param {Neo.table.Container} data.tableContainer
|
289
|
+
* @param {Number|String} data.value
|
290
|
+
* @returns {*}
|
291
|
+
*/
|
292
|
+
cellRenderer(data) {
|
293
|
+
return data.value
|
265
294
|
}
|
266
295
|
|
267
296
|
/**
|
@@ -461,20 +490,6 @@ class Button extends BaseButton {
|
|
461
490
|
me.cls = cls;
|
462
491
|
me._isSorted = null
|
463
492
|
}
|
464
|
-
|
465
|
-
/**
|
466
|
-
* @param {Object} data
|
467
|
-
* @param {Neo.button.Base} data.column
|
468
|
-
* @param {String} data.dataField
|
469
|
-
* @param {Number} data.index
|
470
|
-
* @param {Object} data.record
|
471
|
-
* @param {Neo.table.Container} data.tableContainer
|
472
|
-
* @param {Number|String} data.value
|
473
|
-
* @returns {*}
|
474
|
-
*/
|
475
|
-
renderer(data) {
|
476
|
-
return data.value
|
477
|
-
}
|
478
493
|
}
|
479
494
|
|
480
495
|
export default Neo.setupClass(Button);
|