neo.mjs 7.8.0 → 7.9.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/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/dialog/DemoDialog.mjs +2 -1
- package/examples/dialog/MainContainer.mjs +16 -10
- package/examples/table/nestedRecordFields/EditUserDialog.mjs +137 -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 +4 -4
- package/resources/data/deck/learnneo/pages/tutorials/Earthquakes.md +51 -49
- package/resources/scss/src/apps/portal/learn/PageContainer.scss +5 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/Neo.mjs +7 -12
- package/src/core/Base.mjs +0 -8
- package/src/core/IdGenerator.mjs +0 -9
- package/src/data/Model.mjs +0 -7
- package/src/data/RecordFactory.mjs +82 -61
- package/src/data/Store.mjs +7 -0
- package/src/dialog/Base.mjs +26 -2
- 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
|
|
@@ -135,7 +135,8 @@ class DemoDialog extends Dialog {
|
|
135
135
|
trapFocus : true,
|
136
136
|
optionalAnimateTargetId: button.id,
|
137
137
|
style : {left: me.getOffset(), top: me.getOffset()},
|
138
|
-
title : 'Dialog ' + nextIndex
|
138
|
+
title : 'Dialog ' + nextIndex,
|
139
|
+
windowId : me.windowId
|
139
140
|
})
|
140
141
|
}
|
141
142
|
|
@@ -58,7 +58,6 @@ class MainContainer extends Viewport {
|
|
58
58
|
checked : true,
|
59
59
|
hideLabel : true,
|
60
60
|
hideValueLabel: false,
|
61
|
-
listeners : {change: me.onConfigChange.bind(me, 'animated')},
|
62
61
|
style : {marginLeft: '3em'},
|
63
62
|
valueLabelText: 'Animated'
|
64
63
|
}, {
|
@@ -66,7 +65,6 @@ class MainContainer extends Viewport {
|
|
66
65
|
checked : true,
|
67
66
|
hideLabel : true,
|
68
67
|
hideValueLabel: false,
|
69
|
-
listeners : {change: me.onConfigChange.bind(me, 'modal')},
|
70
68
|
style : {marginLeft: '1em'},
|
71
69
|
valueLabelText: 'Modal'
|
72
70
|
}, '->', {
|
@@ -82,19 +80,22 @@ class MainContainer extends Viewport {
|
|
82
80
|
* @param {Object} data
|
83
81
|
*/
|
84
82
|
createDialog(data) {
|
85
|
-
let me
|
83
|
+
let me = this,
|
84
|
+
button = data.component,
|
85
|
+
{appName, boundaryContainerId, windowId} = me;
|
86
86
|
|
87
|
-
|
87
|
+
button.disabled = true;
|
88
88
|
|
89
89
|
me.dialog = Neo.create(DemoDialog, {
|
90
90
|
animated : me.down({valueLabelText: 'Animated'}).checked,
|
91
|
-
appName
|
92
|
-
boundaryContainerId
|
91
|
+
appName,
|
92
|
+
boundaryContainerId,
|
93
93
|
listeners : {close: me.onWindowClose, scope: me},
|
94
94
|
modal : me.down({valueLabelText: 'Modal'}).checked,
|
95
95
|
trapFocus : true,
|
96
|
-
optionalAnimateTargetId:
|
97
|
-
title : 'Dialog 1'
|
96
|
+
optionalAnimateTargetId: button.id,
|
97
|
+
title : 'Dialog 1',
|
98
|
+
windowId
|
98
99
|
})
|
99
100
|
}
|
100
101
|
|
@@ -103,8 +104,13 @@ class MainContainer extends Viewport {
|
|
103
104
|
* @param {Object} opts
|
104
105
|
*/
|
105
106
|
onConfigChange(config, opts) {
|
106
|
-
|
107
|
-
|
107
|
+
let me = this,
|
108
|
+
boundaryContainerId = opts.value ? 'document.body' : null;
|
109
|
+
|
110
|
+
me.boundaryContainerId = boundaryContainerId
|
111
|
+
|
112
|
+
if (me.dialog) {
|
113
|
+
me.dialog[config] = boundaryContainerId
|
108
114
|
}
|
109
115
|
}
|
110
116
|
|
@@ -0,0 +1,137 @@
|
|
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
|
+
let me = this,
|
124
|
+
store = me.getModel().getStore('mainStore');
|
125
|
+
|
126
|
+
if (data.value === false) {
|
127
|
+
me.record.annotations.selected = false
|
128
|
+
} else {
|
129
|
+
// Assuming we want to support a single row selection
|
130
|
+
store.items.forEach(record => {
|
131
|
+
record.annotations.selected = record === me.record ? data.value : false
|
132
|
+
})
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
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.1",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -54,16 +54,16 @@
|
|
54
54
|
"envinfo": "^7.14.0",
|
55
55
|
"fs-extra": "^11.2.0",
|
56
56
|
"highlightjs-line-numbers.js": "^2.8.0",
|
57
|
-
"inquirer": "^11.0
|
57
|
+
"inquirer": "^11.1.0",
|
58
58
|
"marked": "^14.1.2",
|
59
59
|
"monaco-editor": "0.50.0",
|
60
60
|
"neo-jsdoc": "1.0.1",
|
61
61
|
"neo-jsdoc-x": "1.0.5",
|
62
62
|
"postcss": "^8.4.47",
|
63
|
-
"sass": "^1.79.
|
63
|
+
"sass": "^1.79.4",
|
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",
|