neo.mjs 8.35.1 → 8.36.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/email/app.mjs +6 -0
- package/apps/email/index.html +11 -0
- package/apps/email/model/Email.mjs +39 -0
- package/apps/email/neo-config.json +9 -0
- package/apps/email/resources/data/emails.json +15 -0
- package/apps/email/store/Emails.mjs +22 -0
- package/apps/email/view/Viewport.mjs +57 -0
- package/apps/email/view/ViewportStateProvider.mjs +26 -0
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/buildScripts/createApp.mjs +0 -4
- package/buildScripts/createAppMinimal.mjs +23 -28
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +2 -2
- package/resources/data/deck/learnneo/pages/tutorials/Earthquakes.md +98 -120
- package/src/DefaultConfig.mjs +2 -2
package/apps/ServiceWorker.mjs
CHANGED
@@ -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>Email</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<script src="../../src/MicroLoader.mjs" type="module"></script>
|
10
|
+
</body>
|
11
|
+
</html>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import Model from '../../../src/data/Model.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class Email.model.Email
|
5
|
+
* @extends Neo.data.Model
|
6
|
+
*/
|
7
|
+
class Email extends Model {
|
8
|
+
static config = {
|
9
|
+
/**
|
10
|
+
* @member {String} className='Email.model.Email'
|
11
|
+
* @protected
|
12
|
+
*/
|
13
|
+
className: 'Email.model.Email',
|
14
|
+
/**
|
15
|
+
* @member {Object[]} fields
|
16
|
+
*/
|
17
|
+
fields: [{
|
18
|
+
name: 'id',
|
19
|
+
type: 'Int'
|
20
|
+
}, {
|
21
|
+
name: 'content',
|
22
|
+
type: 'String'
|
23
|
+
}, {
|
24
|
+
name: 'dateSent',
|
25
|
+
type: 'String'
|
26
|
+
}, {
|
27
|
+
name: 'recipients',
|
28
|
+
type: 'Array'
|
29
|
+
}, {
|
30
|
+
name: 'sender',
|
31
|
+
type: 'String'
|
32
|
+
}, {
|
33
|
+
name: 'title',
|
34
|
+
type: 'String'
|
35
|
+
}]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
export default Neo.setupClass(Email);
|
@@ -0,0 +1,15 @@
|
|
1
|
+
[{
|
2
|
+
"id" : 2,
|
3
|
+
"content" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
4
|
+
"dateSent" : "Mon Mar 31 2025 19:03:50 GMT+0200",
|
5
|
+
"recipients": ["Alice@neomjs.com"],
|
6
|
+
"sender" : "John@neomjs.com",
|
7
|
+
"title" : "Hello World"
|
8
|
+
}, {
|
9
|
+
"id" : 1,
|
10
|
+
"content" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vestibulum purus consectetur ex convallis, vitae ullamcorper sapien lobortis. Etiam elementum.",
|
11
|
+
"dateSent" : "Mon Mar 31 2025 18:03:50 GMT+0200",
|
12
|
+
"recipients": ["Alice@neomjs.com"],
|
13
|
+
"sender" : "David@neomjs.com",
|
14
|
+
"title" : "Hello World"
|
15
|
+
}]
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import EmailModel from '../model/Email.mjs';
|
2
|
+
import Store from '../../../src/data/Store.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Email.store.Emails
|
6
|
+
* @extends Neo.data.Store
|
7
|
+
*/
|
8
|
+
class Emails extends Store {
|
9
|
+
static config = {
|
10
|
+
/**
|
11
|
+
* @member {String} className='Email.store.Emails'
|
12
|
+
* @protected
|
13
|
+
*/
|
14
|
+
className: 'Email.store.Emails',
|
15
|
+
/**
|
16
|
+
* @member {Neo.data.Model} model=Email
|
17
|
+
*/
|
18
|
+
model: EmailModel
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
export default Neo.setupClass(Emails);
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import BaseViewport from '../../../src/container/Viewport.mjs';
|
2
|
+
import Component from '../../../src/component/Base.mjs';
|
3
|
+
import TabContainer from '../../../src/tab/Container.mjs';
|
4
|
+
import ViewportStateProvider from './ViewportStateProvider.mjs';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @class Email.view.Viewport
|
8
|
+
* @extends Neo.container.Viewport
|
9
|
+
*/
|
10
|
+
class Viewport extends BaseViewport {
|
11
|
+
static config = {
|
12
|
+
/**
|
13
|
+
* @member {String} className='Email.view.Viewport'
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
className: 'Email.view.Viewport',
|
17
|
+
/*
|
18
|
+
* @member {Object} layout={ntype:'fit'}
|
19
|
+
*/
|
20
|
+
layout: {ntype: 'fit'},
|
21
|
+
/**
|
22
|
+
* @member {Neo.state.Provider} stateProvider=ViewportStateProvider
|
23
|
+
*/
|
24
|
+
stateProvider: ViewportStateProvider,
|
25
|
+
/**
|
26
|
+
* @member {Object[]} items
|
27
|
+
*/
|
28
|
+
items: [{
|
29
|
+
module: TabContainer,
|
30
|
+
height: 300,
|
31
|
+
width : 500,
|
32
|
+
style : {flex: 'none', margin: '20px'},
|
33
|
+
|
34
|
+
itemDefaults: {
|
35
|
+
module: Component,
|
36
|
+
cls : ['neo-examples-tab-component'],
|
37
|
+
style : {padding: '20px'},
|
38
|
+
},
|
39
|
+
|
40
|
+
items: [{
|
41
|
+
header: {
|
42
|
+
iconCls: 'fa fa-home',
|
43
|
+
text : 'Tab 1'
|
44
|
+
},
|
45
|
+
vdom: {innerHTML: 'Welcome to your new Neo App.'}
|
46
|
+
}, {
|
47
|
+
header: {
|
48
|
+
iconCls: 'fa fa-play-circle',
|
49
|
+
text : 'Tab 2'
|
50
|
+
},
|
51
|
+
vdom: {innerHTML: 'Have fun creating something awesome!'}
|
52
|
+
}]
|
53
|
+
}]
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
export default Neo.setupClass(Viewport);
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import EmailStore from '../store/Emails.mjs';
|
2
|
+
import Provider from '../../../src/state/Provider.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Email.view.ViewportStateProvider
|
6
|
+
* @extends Neo.state.Provider
|
7
|
+
*/
|
8
|
+
class ViewportStateProvider extends Provider {
|
9
|
+
static config = {
|
10
|
+
/**
|
11
|
+
* @member {String} className='Email.view.ViewportStateProvider'
|
12
|
+
* @protected
|
13
|
+
*/
|
14
|
+
className: 'Email.view.ViewportStateProvider',
|
15
|
+
/**
|
16
|
+
* @member {Object} stores
|
17
|
+
*/
|
18
|
+
stores: {
|
19
|
+
emails: {
|
20
|
+
module: EmailStore
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
export default Neo.setupClass(ViewportStateProvider);
|
package/apps/portal/index.html
CHANGED
@@ -213,10 +213,6 @@ if (programOpts.info) {
|
|
213
213
|
" */",
|
214
214
|
" className: '" + appName + ".view.MainContainer',",
|
215
215
|
" /**",
|
216
|
-
" * @member {Boolean} autoMount=true",
|
217
|
-
" */",
|
218
|
-
" autoMount: true,",
|
219
|
-
" /**",
|
220
216
|
" * @member {Object[]} items",
|
221
217
|
" */",
|
222
218
|
" items: [{",
|
@@ -86,16 +86,6 @@ if (programOpts.info) {
|
|
86
86
|
});
|
87
87
|
}
|
88
88
|
|
89
|
-
if (!programOpts.mainThreadAddons) {
|
90
|
-
questions.push({
|
91
|
-
type: 'checkbox',
|
92
|
-
name: 'mainThreadAddons',
|
93
|
-
message: 'Please choose your main thread addons:',
|
94
|
-
choices: addonChoices,
|
95
|
-
default: ['DragDrop', 'Stylesheet']
|
96
|
-
});
|
97
|
-
}
|
98
|
-
|
99
89
|
if (!programOpts.useSharedWorkers) {
|
100
90
|
questions.push({
|
101
91
|
type: 'list',
|
@@ -117,16 +107,16 @@ if (programOpts.info) {
|
|
117
107
|
}
|
118
108
|
|
119
109
|
inquirer.prompt(questions).then(answers => {
|
120
|
-
let appName
|
121
|
-
mainThreadAddons
|
122
|
-
themes
|
123
|
-
useSharedWorkers
|
124
|
-
useServiceWorker
|
125
|
-
lAppName
|
126
|
-
appPath
|
127
|
-
dir
|
128
|
-
folder
|
129
|
-
startDate
|
110
|
+
let appName = programOpts.appName || answers.appName,
|
111
|
+
mainThreadAddons = programOpts.mainThreadAddons || ['DragDrop', 'Navigator', 'Stylesheet'],
|
112
|
+
themes = programOpts.themes || answers.themes,
|
113
|
+
useSharedWorkers = programOpts.useSharedWorkers || answers.useSharedWorkers,
|
114
|
+
useServiceWorker = programOpts.useServiceWorker || answers.useServiceWorker,
|
115
|
+
lAppName = appName.toLowerCase(),
|
116
|
+
appPath = 'apps/' + lAppName + '/',
|
117
|
+
dir = 'apps/' + lAppName,
|
118
|
+
folder = path.resolve(cwd, dir),
|
119
|
+
startDate = new Date();
|
130
120
|
|
131
121
|
if (!Array.isArray(themes)) {
|
132
122
|
themes = [themes];
|
@@ -179,7 +169,12 @@ if (programOpts.info) {
|
|
179
169
|
mainPath: `${insideNeo ? './' : '../node_modules/neo.mjs/src/'}Main.mjs`
|
180
170
|
};
|
181
171
|
|
182
|
-
if (!(
|
172
|
+
if (!(
|
173
|
+
mainThreadAddons.includes('DragDrop') &&
|
174
|
+
mainThreadAddons.includes('Navigator') &&
|
175
|
+
mainThreadAddons.includes('Stylesheet') &&
|
176
|
+
mainThreadAddons.length === 3)
|
177
|
+
) {
|
183
178
|
neoConfig.mainThreadAddons = mainThreadAddons;
|
184
179
|
}
|
185
180
|
|
@@ -244,16 +239,16 @@ export default Neo.setupClass(${className});
|
|
244
239
|
|
245
240
|
className = 'MainView';
|
246
241
|
content = `
|
247
|
-
import Base
|
248
|
-
import Controller
|
249
|
-
import
|
242
|
+
import Base from '${neoSrcPath}/container/Base.mjs';
|
243
|
+
import Controller from './${className}Controller.mjs';
|
244
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
250
245
|
|
251
246
|
class ${className} extends Base {
|
252
247
|
static config = {
|
253
248
|
className: '${appName}.view.${className}',
|
254
249
|
|
255
250
|
controller: {module: Controller},
|
256
|
-
|
251
|
+
stateProvider: {module: MainStateProvider},
|
257
252
|
|
258
253
|
layout: {ntype: 'fit'},
|
259
254
|
items: [],
|
@@ -283,11 +278,11 @@ export default Neo.setupClass(${className});
|
|
283
278
|
|
284
279
|
// -------------------------------------------------------------------------
|
285
280
|
|
286
|
-
className = '
|
281
|
+
className = 'MainStateProvider';
|
287
282
|
content = `
|
288
|
-
import
|
283
|
+
import StateProvider from '${neoSrcPath}/state/Provider.mjs';
|
289
284
|
|
290
|
-
class ${className} extends
|
285
|
+
class ${className} extends StateProvider {
|
291
286
|
static config = {
|
292
287
|
className: '${appName}.view.${className}',
|
293
288
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.36.0",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -62,7 +62,7 @@
|
|
62
62
|
"neo-jsdoc": "1.0.1",
|
63
63
|
"neo-jsdoc-x": "1.0.5",
|
64
64
|
"postcss": "^8.5.3",
|
65
|
-
"sass": "^1.86.
|
65
|
+
"sass": "^1.86.1",
|
66
66
|
"siesta-lite": "5.5.2",
|
67
67
|
"url": "^0.11.4",
|
68
68
|
"webpack": "^5.98.0",
|
@@ -23,7 +23,7 @@ A few key concepts we'll be discussing:
|
|
23
23
|
- Configuring components
|
24
24
|
- Debugging
|
25
25
|
- Class-based coding
|
26
|
-
-
|
26
|
+
- State providers
|
27
27
|
- Events
|
28
28
|
- Controllers
|
29
29
|
|
@@ -188,9 +188,9 @@ Use a code editor and look at `workspace/apps/earthquakes/src/view/MainView.mjs`
|
|
188
188
|
following class definition:
|
189
189
|
|
190
190
|
<pre data-javascript>
|
191
|
-
import Base
|
192
|
-
import Controller
|
193
|
-
import
|
191
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
192
|
+
import Controller from './MainViewController.mjs';
|
193
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
194
194
|
|
195
195
|
class MainView extends Base {
|
196
196
|
static config = {
|
@@ -198,16 +198,14 @@ class MainView extends Base {
|
|
198
198
|
ntype: 'earthquakes-main',
|
199
199
|
|
200
200
|
controller: {module: Controller},
|
201
|
-
|
201
|
+
stateProvider: {module: MainStateProvider},
|
202
202
|
|
203
203
|
layout: {ntype: 'fit'},
|
204
204
|
items: [],
|
205
205
|
}
|
206
206
|
}
|
207
207
|
|
208
|
-
Neo.setupClass(MainView);
|
209
|
-
|
210
|
-
export default MainView;
|
208
|
+
export default Neo.setupClass(MainView);
|
211
209
|
</pre>
|
212
210
|
|
213
211
|
As you can see, `MainView extends Base`, and `Base` is a _container_ (`Neo.container.Base`).
|
@@ -227,10 +225,10 @@ which method to run when the button is clicked. We'll use `text`.
|
|
227
225
|
|
228
226
|
<pre data-javascript>
|
229
227
|
|
230
|
-
import Base
|
231
|
-
import Button
|
232
|
-
import Controller
|
233
|
-
import
|
228
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
229
|
+
import Button from '../../../node_modules/neo.mjs/src/button/Base.mjs';
|
230
|
+
import Controller from './MainViewController.mjs';
|
231
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
234
232
|
|
235
233
|
class MainView extends Base {
|
236
234
|
static config = {
|
@@ -238,7 +236,7 @@ class MainView extends Base {
|
|
238
236
|
ntype: 'earthquakes-main',
|
239
237
|
|
240
238
|
controller: {module: Controller},
|
241
|
-
|
239
|
+
stateProvider: {module: MainStateProvider},
|
242
240
|
|
243
241
|
layout: {ntype: 'fit'},
|
244
242
|
items: [{
|
@@ -248,9 +246,7 @@ class MainView extends Base {
|
|
248
246
|
}
|
249
247
|
}
|
250
248
|
|
251
|
-
Neo.setupClass(MainView);
|
252
|
-
|
253
|
-
export default MainView;
|
249
|
+
export default Neo.setupClass(MainView);
|
254
250
|
</pre>
|
255
251
|
|
256
252
|
|
@@ -428,10 +424,10 @@ Edit `apps/earthquakes/view/MainView.mjs` and add a method.
|
|
428
424
|
|
429
425
|
<pre data-javascript>
|
430
426
|
|
431
|
-
import Base
|
432
|
-
import Button
|
433
|
-
import Controller
|
434
|
-
import
|
427
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
428
|
+
import Button from '../../../node_modules/neo.mjs/src/button/Base.mjs';
|
429
|
+
import Controller from './MainViewController.mjs';
|
430
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
435
431
|
|
436
432
|
class MainView extends Base {
|
437
433
|
static config = {
|
@@ -439,7 +435,7 @@ class MainView extends Base {
|
|
439
435
|
ntype: 'earthquakes-main',
|
440
436
|
|
441
437
|
controller: {module: Controller},
|
442
|
-
|
438
|
+
stateProvider: {module: MainStateProvider},
|
443
439
|
|
444
440
|
layout: {
|
445
441
|
ntype: 'vbox',
|
@@ -456,9 +452,7 @@ class MainView extends Base {
|
|
456
452
|
}
|
457
453
|
}
|
458
454
|
|
459
|
-
Neo.setupClass(MainView);
|
460
|
-
|
461
|
-
export default MainView;
|
455
|
+
export default Neo.setupClass(MainView);
|
462
456
|
</pre>
|
463
457
|
|
464
458
|
Save your changes.
|
@@ -502,11 +496,11 @@ Replace the button with a table by replacing `MainView.mjs` with the following c
|
|
502
496
|
|
503
497
|
<pre data-javascript>
|
504
498
|
|
505
|
-
import Base
|
506
|
-
import Table
|
507
|
-
import Store
|
508
|
-
import Controller
|
509
|
-
import
|
499
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
500
|
+
import Table from '../../../node_modules/neo.mjs/src/table/Container.mjs';
|
501
|
+
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
502
|
+
import Controller from './MainViewController.mjs';
|
503
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
510
504
|
|
511
505
|
class MainView extends Base {
|
512
506
|
static config = {
|
@@ -514,7 +508,7 @@ class MainView extends Base {
|
|
514
508
|
ntype: 'earthquakes-main',
|
515
509
|
|
516
510
|
controller: {module: Controller},
|
517
|
-
|
511
|
+
stateProvider: {module: MainStateProvider},
|
518
512
|
|
519
513
|
layout: {ntype: 'vbox', align: 'stretch'},
|
520
514
|
items: [{
|
@@ -555,9 +549,7 @@ class MainView extends Base {
|
|
555
549
|
}
|
556
550
|
}
|
557
551
|
|
558
|
-
Neo.setupClass(MainView);
|
559
|
-
|
560
|
-
export default MainView;
|
552
|
+
export default Neo.setupClass(MainView);
|
561
553
|
</pre>
|
562
554
|
|
563
555
|
Save and refresh.
|
@@ -705,9 +697,7 @@ class Table extends Base {
|
|
705
697
|
}
|
706
698
|
}
|
707
699
|
|
708
|
-
Neo.setupClass(Table);
|
709
|
-
|
710
|
-
export default Table;
|
700
|
+
export default Neo.setupClass(Table);
|
711
701
|
</pre>
|
712
702
|
|
713
703
|
</details>
|
@@ -733,7 +723,7 @@ Edit `apps/earthquakes/view/MainView` and make these changes.
|
|
733
723
|
|
734
724
|
Save and refresh the browser, and your app should run as before.
|
735
725
|
|
736
|
-
You can
|
726
|
+
You can confirm that the new class _is being loaded_ by using DevTools to try to open `earthquakes/Table` — if it
|
737
727
|
was imported, it'll be listed.
|
738
728
|
|
739
729
|
You can confirm that an instance _was created_ by using the DevTools console and searching for it via
|
@@ -746,11 +736,11 @@ You can confirm that an instance _was created_ by using the DevTools console and
|
|
746
736
|
<summary>Here's the code</summary>
|
747
737
|
|
748
738
|
<pre data-javascript>
|
749
|
-
import Base
|
750
|
-
import Controller
|
751
|
-
import EarthquakesTable
|
752
|
-
import
|
753
|
-
import
|
739
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
740
|
+
import Controller from './MainViewController.mjs';
|
741
|
+
import EarthquakesTable from './earthquakes/Table.mjs';
|
742
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
743
|
+
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
754
744
|
|
755
745
|
class MainView extends Base {
|
756
746
|
static config = {
|
@@ -758,7 +748,7 @@ static config = {
|
|
758
748
|
ntype: 'earthquakes-main',
|
759
749
|
|
760
750
|
controller: {module: Controller},
|
761
|
-
|
751
|
+
stateProvider: {module: MainStateProvider},
|
762
752
|
|
763
753
|
layout: {ntype: 'vbox', align: 'stretch'},
|
764
754
|
items: [{
|
@@ -784,9 +774,7 @@ static config = {
|
|
784
774
|
}
|
785
775
|
}
|
786
776
|
|
787
|
-
Neo.setupClass(MainView);
|
788
|
-
|
789
|
-
export default MainView;
|
777
|
+
export default Neo.setupClass(MainView);
|
790
778
|
</pre>
|
791
779
|
|
792
780
|
</details>
|
@@ -832,12 +820,12 @@ twice.
|
|
832
820
|
If we simply wanted to re-use the store's description we could refactor the store config into a new
|
833
821
|
store class, just like we did for the table. But in _earthquakes_ we want to share the store _instance_.
|
834
822
|
|
835
|
-
Neo has a feature that allows shared, bindable, data. A `Neo.
|
836
|
-
can be values like strings, numbers, or even references, like component or store references. `Neo.
|
837
|
-
is commonly called a
|
823
|
+
Neo has a feature that allows shared, bindable, data. A `Neo.state.Provider` instance holds properties that
|
824
|
+
can be values like strings, numbers, or even references, like component or store references. `Neo.state.Provider`
|
825
|
+
is commonly called a _state provider_.<small><sup>*</sup></small>
|
838
826
|
|
839
|
-
The `create-app-minimal` script includes a
|
840
|
-
will hold the store.
|
827
|
+
The `create-app-minimal` script includes a state provider and view controller config.
|
828
|
+
The state provider will hold the store.
|
841
829
|
|
842
830
|
<br>
|
843
831
|
<br>
|
@@ -846,36 +834,36 @@ will hold the store.
|
|
846
834
|
|
847
835
|
|
848
836
|
|
849
|
-
## Lab. Use a
|
837
|
+
## Lab. Use a State Provider
|
850
838
|
|
851
839
|
<!-- lab -->
|
852
840
|
|
853
841
|
<details>
|
854
842
|
<summary>Look at network traffic</summary>
|
855
843
|
|
856
|
-
Before making any changes, open devtools in the Network tab and refresh _earthquakes_.
|
857
|
-
calls to the web service.
|
844
|
+
Before making any changes, open devtools in the Network tab and refresh _earthquakes_.
|
845
|
+
You'll see two calls to the web service.
|
858
846
|
|
859
847
|
<img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/EarthquakesTwoTablesTwoCalls.png"></img>
|
860
848
|
|
861
849
|
</details>
|
862
850
|
|
863
851
|
<details>
|
864
|
-
<summary>Copy the store config to the
|
852
|
+
<summary>Copy the store config to the state provider</summary>
|
865
853
|
|
866
|
-
|
854
|
+
State Providers have two key configs: `data` and `stores`.
|
867
855
|
|
868
856
|
- `data` holds name/value pairs where the value can be a simple value, or object references
|
869
857
|
- `stores` holds configs of stores
|
870
858
|
|
871
|
-
Add a `stores` property to the
|
859
|
+
Add a `stores` property to the state provider config that holds a copy of the store.
|
872
860
|
|
873
861
|
<pre data-javascript>
|
874
|
-
import Base
|
875
|
-
import Controller
|
876
|
-
import EarthquakesTable
|
877
|
-
import
|
878
|
-
import
|
862
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
863
|
+
import Controller from './MainViewController.mjs';
|
864
|
+
import EarthquakesTable from './earthquakes/Table.mjs';
|
865
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
866
|
+
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
879
867
|
|
880
868
|
class MainView extends Base {
|
881
869
|
static config = {
|
@@ -883,8 +871,8 @@ class MainView extends Base {
|
|
883
871
|
ntype: 'earthquakes-main',
|
884
872
|
|
885
873
|
controller: {module: Controller},
|
886
|
-
|
887
|
-
module:
|
874
|
+
stateProvider: {
|
875
|
+
module: MainStateProvider,
|
888
876
|
stores: {
|
889
877
|
earthquakes: {
|
890
878
|
module: Store,
|
@@ -950,9 +938,7 @@ class MainView extends Base {
|
|
950
938
|
}
|
951
939
|
}
|
952
940
|
|
953
|
-
Neo.setupClass(MainView);
|
954
|
-
|
955
|
-
export default MainView;
|
941
|
+
export default Neo.setupClass(MainView);
|
956
942
|
|
957
943
|
</pre>
|
958
944
|
|
@@ -963,16 +949,16 @@ of the data the store holds.
|
|
963
949
|
At this point we have _three_ identical store configs! Save and refresh, and look at network traffic — you
|
964
950
|
should see three calls.
|
965
951
|
|
966
|
-
Having an instance in the
|
952
|
+
Having an instance in the state provider means we can share it. It can be shared anywhere in the containment
|
967
953
|
hierarchy. The app doesn't have much of a hierarchy: it's just the main view and two child components (the two
|
968
|
-
tables). But now that the store is in the parent's
|
954
|
+
tables). But now that the store is in the parent's state provider we can share it.
|
969
955
|
|
970
956
|
</details>
|
971
957
|
|
972
958
|
<details>
|
973
959
|
<summary>Use the shared store</summary>
|
974
960
|
|
975
|
-
The way to bind an instance to a
|
961
|
+
The way to bind an instance to a state provider property is with the `bind` config. For example
|
976
962
|
|
977
963
|
bind: {
|
978
964
|
store: 'stores.earthquakes'
|
@@ -980,7 +966,7 @@ The way to bind an instance to a view model property is with the `bind` config.
|
|
980
966
|
|
981
967
|
binds a `store` property to a store called `foo`. The code is saying _in the future, when the value
|
982
968
|
of "stores.earthquakes" changes, assign it to this object's "store" property_. In this case, `stores.earthquakes`
|
983
|
-
starts out undefined, then at runtime within a few milliseconds as the
|
969
|
+
starts out undefined, then at runtime within a few milliseconds as the state provider is processed, the configured
|
984
970
|
store is created and a reference is assigned to `stores.earthquakes`. That wakes the binding up, and the
|
985
971
|
value is assigned to the table's `store` property.
|
986
972
|
|
@@ -988,19 +974,19 @@ Replace each table's `store` config with the binding.
|
|
988
974
|
|
989
975
|
<pre data-javascript>
|
990
976
|
|
991
|
-
import Base
|
992
|
-
import Controller
|
993
|
-
import EarthquakesTable
|
994
|
-
import
|
995
|
-
import
|
977
|
+
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
978
|
+
import Controller from './MainViewController.mjs';
|
979
|
+
import EarthquakesTable from './earthquakes/Table.mjs';
|
980
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
981
|
+
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
996
982
|
|
997
983
|
class MainView extends Base {
|
998
984
|
static config = {
|
999
985
|
className: 'Earthquakes.view.MainView',
|
1000
986
|
ntype: 'earthquakes-main',
|
1001
987
|
controller: {module: Controller},
|
1002
|
-
|
1003
|
-
module:
|
988
|
+
stateProvider: {
|
989
|
+
module: MainStateProvider,
|
1004
990
|
stores: {
|
1005
991
|
earthquakes: {
|
1006
992
|
module: Store,
|
@@ -1017,7 +1003,7 @@ class MainView extends Base {
|
|
1017
1003
|
url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
|
1018
1004
|
responseRoot: "data",
|
1019
1005
|
autoLoad: true
|
1020
|
-
}
|
1006
|
+
}
|
1021
1007
|
}
|
1022
1008
|
},
|
1023
1009
|
|
@@ -1034,13 +1020,11 @@ class MainView extends Base {
|
|
1034
1020
|
store: 'stores.earthquakes'
|
1035
1021
|
},
|
1036
1022
|
style: {width: '100%'}
|
1037
|
-
}]
|
1023
|
+
}]
|
1038
1024
|
}
|
1039
1025
|
}
|
1040
1026
|
|
1041
|
-
Neo.setupClass(MainView);
|
1042
|
-
|
1043
|
-
export default MainView;
|
1027
|
+
export default Neo.setupClass(MainView);
|
1044
1028
|
</pre>
|
1045
1029
|
|
1046
1030
|
Save, refresh, and look at network traffic: you'll see a _single_ call to the web service.
|
@@ -1050,7 +1034,7 @@ Save, refresh, and look at network traffic: you'll see a _single_ call to the we
|
|
1050
1034
|
You can further prove we're using a shared instance by running these statements in the console.
|
1051
1035
|
|
1052
1036
|
<pre data-javascript>
|
1053
|
-
a = Neo.findFirst({ntype:'earthquakes-main'}).
|
1037
|
+
a = Neo.findFirst({ntype:'earthquakes-main'}).stateProvider.stores.earthquakes;
|
1054
1038
|
b = Neo.find({ntype:'earthquakes-table'})[0].store;
|
1055
1039
|
c = Neo.find({ntype:'earthquakes-table'})[1].store;
|
1056
1040
|
|
@@ -1060,25 +1044,25 @@ c = Neo.find({ntype:'earthquakes-table'})[1].store;
|
|
1060
1044
|
</details>
|
1061
1045
|
|
1062
1046
|
<details>
|
1063
|
-
<summary>Use the
|
1047
|
+
<summary>Use the state provider class</summary>
|
1064
1048
|
|
1065
|
-
We configured the
|
1066
|
-
has a `
|
1049
|
+
We configured the state provider in-line, in the `stateProvider` config at the top of `MainView`. But the starter app
|
1050
|
+
has a `MainStateProvider` class. In theory, if you have a trivial state provider you could configure it in-line. But
|
1067
1051
|
in general you want to keep that code separate by coding it in a separate class. This is what we did for the
|
1068
1052
|
table config — we started by coding it in-line in the main view, then we refactored it into its own
|
1069
|
-
class. The result was a simpler and more abstract main view. We want to do the same for the
|
1053
|
+
class. The result was a simpler and more abstract main view. We want to do the same for the state provider.
|
1070
1054
|
|
1071
|
-
Since the starter app already provides `
|
1055
|
+
Since the starter app already provides `MainStateProvider`, all we need to do is copy the `stores` property.
|
1072
1056
|
|
1073
|
-
Here's the resulting code you should place into `
|
1057
|
+
Here's the resulting code you should place into `MainStateProvider.mjs`.
|
1074
1058
|
|
1075
1059
|
<pre data-javascript>
|
1076
|
-
import
|
1077
|
-
import Store
|
1060
|
+
import StateProvider from '../../../node_modules/neo.mjs/src/state/Provider.mjs';
|
1061
|
+
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
1078
1062
|
|
1079
|
-
class
|
1063
|
+
class MainStateProvider extends StateProvider {
|
1080
1064
|
static config = {
|
1081
|
-
className: 'Earthquakes.view.
|
1065
|
+
className: 'Earthquakes.view.MainStateProvider',
|
1082
1066
|
|
1083
1067
|
data: {},
|
1084
1068
|
stores: {
|
@@ -1102,26 +1086,24 @@ class MainViewModel extends Model {
|
|
1102
1086
|
}
|
1103
1087
|
}
|
1104
1088
|
|
1105
|
-
Neo.setupClass(
|
1106
|
-
|
1107
|
-
export default MainViewModel;
|
1089
|
+
export default Neo.setupClass(MainStateProvider);
|
1108
1090
|
</pre>
|
1109
1091
|
|
1110
1092
|
And you need to remove the `stores` config from the main view as follows.
|
1111
1093
|
|
1112
1094
|
<pre data-javascript>
|
1113
|
-
import Container
|
1114
|
-
import Controller
|
1115
|
-
import EarthquakesTable
|
1116
|
-
import
|
1095
|
+
import Container from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
1096
|
+
import Controller from './MainViewController.mjs';
|
1097
|
+
import EarthquakesTable from './earthquakes/Table.mjs';
|
1098
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
1117
1099
|
|
1118
1100
|
class MainView extends Container {
|
1119
1101
|
static config = {
|
1120
1102
|
className: 'Earthquakes.view.MainView',
|
1121
1103
|
ntype: 'earthquakes-main',
|
1122
1104
|
controller: {module: Controller},
|
1123
|
-
|
1124
|
-
module:
|
1105
|
+
stateProvider: {
|
1106
|
+
module: MainStateProvider
|
1125
1107
|
},
|
1126
1108
|
|
1127
1109
|
layout: { ntype: 'vbox', align: 'stretch' },
|
@@ -1141,12 +1123,10 @@ class MainView extends Container {
|
|
1141
1123
|
}
|
1142
1124
|
}
|
1143
1125
|
|
1144
|
-
Neo.setupClass(MainView);
|
1145
|
-
|
1146
|
-
export default MainView;
|
1126
|
+
export default Neo.setupClass(MainView);
|
1147
1127
|
</pre>
|
1148
1128
|
|
1149
|
-
The refactorings to have separate table and
|
1129
|
+
The refactorings to have separate table and state provider classes means the code is more modular, more reusable,
|
1150
1130
|
and each class is simpler than using complex source files that try to configure every detail.
|
1151
1131
|
|
1152
1132
|
</details>
|
@@ -1155,8 +1135,8 @@ and each class is simpler than using complex source files that try to configure
|
|
1155
1135
|
|
1156
1136
|
## Google Maps Add-on
|
1157
1137
|
|
1158
|
-
Neo.mjs has a Google Map component. This component is a little different
|
1159
|
-
|
1138
|
+
Neo.mjs has a Google Map component. This component is a little different from a button or table,
|
1139
|
+
because it's implemented as a _main thread add-on_.
|
1160
1140
|
|
1161
1141
|
When you use Google Maps you use the Google Map API to ask it to draw the map and markers.
|
1162
1142
|
In a normal app, Google Maps &mdahs; and everything else — runs in the main browser thread.
|
@@ -1192,7 +1172,7 @@ Marker store records are required to have these properties:
|
|
1192
1172
|
<details>
|
1193
1173
|
<summary>Get the code for the custom add-on</summary>
|
1194
1174
|
At the time this tutorial was written, the Neo.mjs Google Maps addon was about to be updated to
|
1195
|
-
|
1175
|
+
accommodate Google's "AdvancedMarker" class. Until that's ready, we're going to use a modified version of the add-on.
|
1196
1176
|
|
1197
1177
|
Download and unzip this file, and copy the two source files to the corresponding subdirectories in
|
1198
1178
|
your workspace's `src` directory. Note that `src` already contains some files, so don't replace the whole
|
@@ -1245,7 +1225,7 @@ lets us implement those via two properties:
|
|
1245
1225
|
- `mapping` — the path to a feed property holding the value
|
1246
1226
|
- `calculate` — a function that returns a value
|
1247
1227
|
|
1248
|
-
Edit `apps/earthquakes/view/
|
1228
|
+
Edit `apps/earthquakes/view/MainStateProvider.mjs` and modify `fields` as follows.
|
1249
1229
|
|
1250
1230
|
<pre data-javascript>
|
1251
1231
|
fields: [{
|
@@ -1270,9 +1250,9 @@ calculated by returning an object with _lat_ and _lng_ set to the corresponding
|
|
1270
1250
|
Save and refresh _earthquakes_. You can use the debugger to inspect the store via _Shift-Ctrl-right-click_ and
|
1271
1251
|
putting the main view into a global variable. Then run
|
1272
1252
|
|
1273
|
-
temp1.
|
1253
|
+
temp1.getStateProvider().stores.earthquakes.items
|
1274
1254
|
|
1275
|
-
Look at one of the items and you should see that _title_ and _location_ are in each record.
|
1255
|
+
Look at one of the items, and you should see that _title_ and _location_ are in each record.
|
1276
1256
|
|
1277
1257
|
<img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/StoreHasTitleAndLocation.png"></img>
|
1278
1258
|
|
@@ -1304,15 +1284,15 @@ import Container from '../container/Base.mjs';
|
|
1304
1284
|
import Controller from './MainViewController.mjs';
|
1305
1285
|
import EarthquakesTable from './earthquakes/Table.mjs';
|
1306
1286
|
import GoogleMapsComponent from '../component/wrapper/GoogleMaps.mjs';
|
1307
|
-
import
|
1287
|
+
import MainStateProvider from './MainStateProvider.mjs';
|
1308
1288
|
|
1309
1289
|
class MainView extends Container {
|
1310
1290
|
static config = {
|
1311
1291
|
className: 'Earthquakes.view.MainView',
|
1312
1292
|
ntype: 'earthquakes-main',
|
1313
1293
|
controller: {module: Controller},
|
1314
|
-
|
1315
|
-
module:
|
1294
|
+
stateProvider: {
|
1295
|
+
module: MainStateProvider
|
1316
1296
|
},
|
1317
1297
|
|
1318
1298
|
layout: { ntype: 'vbox', align: 'stretch' },
|
@@ -1337,9 +1317,7 @@ class MainView extends Container {
|
|
1337
1317
|
}
|
1338
1318
|
}
|
1339
1319
|
|
1340
|
-
Neo.setupClass(MainView);
|
1341
|
-
|
1342
|
-
export default MainView;
|
1320
|
+
export default Neo.setupClass(MainView);
|
1343
1321
|
</pre>
|
1344
1322
|
|
1345
1323
|
<img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/CenteredMap.png"></img>
|
@@ -1430,6 +1408,6 @@ and to introduce some basic Neo.mjs concepts
|
|
1430
1408
|
|
1431
1409
|
- Declarative, abstract code
|
1432
1410
|
- Class-based coding, and the ability to extend any class, such as `view/earthquakes/Table.mjs`
|
1433
|
-
-
|
1411
|
+
- State providers, to share properties and objects, such as the store shared by the table and map
|
1434
1412
|
- Events, specified via `listeners:{}`
|
1435
1413
|
- Controllers, to hold event listeners and other procedural logic
|
package/src/DefaultConfig.mjs
CHANGED
@@ -263,12 +263,12 @@ const DefaultConfig = {
|
|
263
263
|
useVdomWorker: true,
|
264
264
|
/**
|
265
265
|
* buildScripts/injectPackageVersion.mjs will update this value
|
266
|
-
* @default '8.
|
266
|
+
* @default '8.36.0'
|
267
267
|
* @memberOf! module:Neo
|
268
268
|
* @name config.version
|
269
269
|
* @type String
|
270
270
|
*/
|
271
|
-
version: '8.
|
271
|
+
version: '8.36.0'
|
272
272
|
};
|
273
273
|
|
274
274
|
Object.assign(DefaultConfig, {
|