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.
Files changed (33) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/portal/index.html +1 -1
  3. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  4. package/apps/portal/view/learn/MainContainerController.mjs +1 -1
  5. package/examples/ServiceWorker.mjs +2 -2
  6. package/examples/dialog/DemoDialog.mjs +2 -1
  7. package/examples/dialog/MainContainer.mjs +16 -10
  8. package/examples/table/nestedRecordFields/EditUserDialog.mjs +137 -0
  9. package/examples/table/nestedRecordFields/MainContainer.mjs +113 -0
  10. package/examples/table/nestedRecordFields/MainContainerModel.mjs +61 -0
  11. package/examples/table/nestedRecordFields/MainModel.mjs +41 -0
  12. package/examples/table/nestedRecordFields/MainStore.mjs +54 -0
  13. package/examples/table/nestedRecordFields/app.mjs +6 -0
  14. package/examples/table/nestedRecordFields/index.html +11 -0
  15. package/examples/table/nestedRecordFields/neo-config.json +6 -0
  16. package/package.json +4 -4
  17. package/resources/data/deck/learnneo/pages/tutorials/Earthquakes.md +51 -49
  18. package/resources/scss/src/apps/portal/learn/PageContainer.scss +5 -0
  19. package/src/DefaultConfig.mjs +2 -2
  20. package/src/Neo.mjs +7 -12
  21. package/src/core/Base.mjs +0 -8
  22. package/src/core/IdGenerator.mjs +0 -9
  23. package/src/data/Model.mjs +0 -7
  24. package/src/data/RecordFactory.mjs +82 -61
  25. package/src/data/Store.mjs +7 -0
  26. package/src/dialog/Base.mjs +26 -2
  27. package/src/form/field/CheckBox.mjs +12 -7
  28. package/src/form/field/ComboBox.mjs +8 -7
  29. package/src/grid/View.mjs +2 -2
  30. package/src/list/Base.mjs +1 -1
  31. package/src/model/Component.mjs +10 -1
  32. package/src/table/View.mjs +31 -15
  33. package/src/table/header/Button.mjs +33 -18
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='7.8.0'
23
+ * @member {String} version='7.9.1'
24
24
  */
25
- version: '7.8.0'
25
+ version: '7.9.1'
26
26
  }
27
27
 
28
28
  /**
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2024-09-21",
19
+ "datePublished": "2024-09-30",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -111,7 +111,7 @@ class FooterContainer extends Container {
111
111
  }, {
112
112
  module: Component,
113
113
  cls : ['neo-version'],
114
- html : 'v7.8.0'
114
+ html : 'v7.9.1'
115
115
  }]
116
116
  }],
117
117
  /**
@@ -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: 'WhyNeo-Intro'})
144
+ this.onRouteLearnItem({itemId: 'benefits.Introduction'})
145
145
  }
146
146
  }
147
147
 
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='7.8.0'
23
+ * @member {String} version='7.9.1'
24
24
  */
25
- version: '7.8.0'
25
+ version: '7.9.1'
26
26
  }
27
27
 
28
28
  /**
@@ -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 = this;
83
+ let me = this,
84
+ button = data.component,
85
+ {appName, boundaryContainerId, windowId} = me;
86
86
 
87
- data.component.disabled = true;
87
+ button.disabled = true;
88
88
 
89
89
  me.dialog = Neo.create(DemoDialog, {
90
90
  animated : me.down({valueLabelText: 'Animated'}).checked,
91
- appName : me.appName,
92
- boundaryContainerId : me.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: data.component.id,
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
- if (this.dialog) {
107
- this.dialog[config] = opts.value ? 'document.body' : null
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,6 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.table.nestedRecordFields'
6
+ });
@@ -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>
@@ -0,0 +1,6 @@
1
+ {
2
+ "appPath" : "examples/table/nestedRecordFields/app.mjs",
3
+ "basePath" : "../../../",
4
+ "environment": "development",
5
+ "mainPath" : "./Main.mjs"
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "7.8.0",
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.2",
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.3",
63
+ "sass": "^1.79.4",
64
64
  "siesta-lite": "5.5.2",
65
65
  "url": "^0.11.4",
66
- "webpack": "^5.94.0",
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",