neo.mjs 9.15.0 → 9.16.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/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/ContentComponent.mjs +5 -5
- package/package.json +1 -1
- package/resources/data/deck/learnneo/pages/UsingTheseTopics.md +65 -0
- package/resources/data/deck/learnneo/pages/benefits/ConfigSystem.md +1 -1
- package/resources/data/deck/learnneo/pages/benefits/FormsEngine.md +7 -7
- package/resources/data/deck/learnneo/pages/benefits/FourEnvironments.md +9 -10
- package/resources/data/deck/learnneo/pages/benefits/Introduction.md +37 -5
- package/resources/data/deck/learnneo/pages/benefits/MultiWindow.md +1 -1
- package/resources/data/deck/learnneo/pages/benefits/Speed.md +1 -1
- package/resources/data/deck/learnneo/pages/gettingstarted/ComponentModels.md +2 -2
- package/resources/data/deck/learnneo/pages/gettingstarted/Config.md +3 -3
- package/resources/data/deck/learnneo/pages/gettingstarted/DescribingTheUI.md +2 -2
- package/resources/data/deck/learnneo/pages/gettingstarted/Events.md +3 -3
- package/resources/data/deck/learnneo/pages/gettingstarted/Extending.md +2 -2
- package/resources/data/deck/learnneo/pages/gettingstarted/References.md +3 -3
- package/resources/data/deck/learnneo/pages/gettingstarted/Workspaces.md +3 -3
- package/resources/data/deck/learnneo/pages/guides/ComponentsAndContainers.md +6 -6
- package/resources/data/deck/learnneo/pages/guides/CustomComponents.md +1 -1
- package/resources/data/deck/learnneo/pages/guides/MainThreadAddonIntro.md +1 -1
- package/resources/data/deck/learnneo/pages/guides/StateProviders.md +6 -6
- package/resources/data/deck/learnneo/pages/guides/events/CustomEvents.md +8 -8
- package/resources/data/deck/learnneo/pages/guides/events/DomEvents.md +6 -6
- package/resources/data/deck/learnneo/pages/javascript/Classes.md +4 -4
- package/resources/data/deck/learnneo/pages/javascript/NewNode.md +2 -2
- package/resources/data/deck/learnneo/pages/javascript/Overrides.md +4 -4
- package/resources/data/deck/learnneo/pages/tutorials/Earthquakes.md +21 -21
- package/resources/data/deck/learnneo/pages/tutorials/TodoList.md +2 -2
- package/resources/data/deck/learnneo/tree.json +1 -1
- package/resources/scss/src/apps/portal/learn/ContentComponent.scss +17 -13
- package/src/DefaultConfig.mjs +2 -2
- package/resources/data/deck/learnneo/pages/Welcome.md +0 -64
package/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
@@ -5,8 +5,8 @@ import {marked} from '../../../../node_modules/marked/lib/marked.esm.js';
|
|
5
5
|
const
|
6
6
|
labCloseRegex = /<!--\s*\/lab\s*-->/g,
|
7
7
|
labOpenRegex = /<!--\s*lab\s*-->/g,
|
8
|
-
|
9
|
-
|
8
|
+
preLivePreviewRegex = /<pre\s+data-code-livepreview\s*>([\s\S]*?)<\/pre>/g,
|
9
|
+
preJsRegex = /<pre\s+data-code-readonly\s*>([\s\S]*?)<\/pre>/g,
|
10
10
|
preNeoComponentRegex = /<pre\s+data-neo-component\s*>([\s\S]*?)<\/pre>/g;
|
11
11
|
|
12
12
|
/**
|
@@ -185,7 +185,7 @@ class ContentComponent extends Component {
|
|
185
185
|
// Replace <pre data-neo></pre> with <div id='neo-preview-1'/>
|
186
186
|
// and create a map keyed by ID, whose value is the javascript
|
187
187
|
// from the <pre>
|
188
|
-
modifiedHtml = me.
|
188
|
+
modifiedHtml = me.extractLivePreviewContent(modifiedHtml, neoDivs);
|
189
189
|
|
190
190
|
html = marked.parse(modifiedHtml);
|
191
191
|
html = me.insertLabDivs(html);
|
@@ -248,11 +248,11 @@ class ContentComponent extends Component {
|
|
248
248
|
* @param {Object} map
|
249
249
|
* @returns {String}
|
250
250
|
*/
|
251
|
-
|
251
|
+
extractLivePreviewContent(htmlString, map) {
|
252
252
|
// 1. Replace <pre data-neo> with <div id='neo-pre-live-preview-x'/>
|
253
253
|
// and update map with key/value pairs, where the key is the ID and the value is the <pre> contents.
|
254
254
|
// Replace the content with tokens, and create a promise to update the corresponding content
|
255
|
-
return htmlString.replace(
|
255
|
+
return htmlString.replace(preLivePreviewRegex, (match, preContent) => {
|
256
256
|
const key = Neo.core.IdGenerator.getId('pre-live-preview');
|
257
257
|
map[key] = preContent;
|
258
258
|
return `<div id="${key}"></div>`
|
package/package.json
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
***Welcome to these Neo.mjs guides and learning resources!*** Neo.mjs is a groundbreaking JavaScript framework designed
|
3
|
+
to help you build lightning-fast, highly scalable, and exceptionally maintainable web applications. This guide will help
|
4
|
+
you understand the structure of these topics and get the most out of our comprehensive content.
|
5
|
+
|
6
|
+
## Documentation Sections
|
7
|
+
|
8
|
+
This documentation is organized into the following main sections, each serving a distinct purpose:
|
9
|
+
|
10
|
+
* ***Benefits***: Describes the technical and business reasons for choosing Neo.mjs, highlighting its unique advantages.
|
11
|
+
* ***Getting Started***: Provides installation instructions, along with fundamental concepts that are good to understand
|
12
|
+
before diving deeper into Neo.mjs.
|
13
|
+
* ***Tutorials***: Offers hands-on tutorials where you'll code a few simple Neo.mjs applications.
|
14
|
+
* ***Guides***: Contains in-depth discussions of various topics related to Neo.mjs concepts and features.
|
15
|
+
|
16
|
+
## Navigating These Topics
|
17
|
+
|
18
|
+
As you can see, the table of contents is on the left. Topic sections and sub-sections are shown on the right, and the
|
19
|
+
content is here in the middle. There are "next" and "previous" buttons at the bottom of each page to make it easier to
|
20
|
+
read several topics in sequence.
|
21
|
+
|
22
|
+
## Special Features
|
23
|
+
|
24
|
+
You'll find a few special features integrated into our content to enhance your learning experience:
|
25
|
+
|
26
|
+
### Disclosure widgets
|
27
|
+
|
28
|
+
Topics sometimes contain "disclosure" widgets, which are just `<details>` tags. These are used in cases
|
29
|
+
where we want to present high-level points and reveal details when the disclosure is expanded.
|
30
|
+
|
31
|
+
<details>
|
32
|
+
<summary>This is a disclosure widget</summary>
|
33
|
+
<p style="background-color:lightgreen;padding:8px">This is a fascinating piece of information which is revealed when the widget is expanded.</p>
|
34
|
+
</details>
|
35
|
+
|
36
|
+
### Runnable examples
|
37
|
+
|
38
|
+
Topics also sometimes contain runnable examples. These are shown as tab panels with Source and Preview tabs.
|
39
|
+
|
40
|
+
You can also launch the preview in a window by going to the Preview tab, then clicking on the little window
|
41
|
+
icon on the right <span class="far fa-xs fa-window-maximize"></span>. This web site is a Neo.mjs application,
|
42
|
+
and the ability to launch browser windows — all integrated within a single app — is a unique feature of Neo.mjs!
|
43
|
+
|
44
|
+
<pre data-code-livepreview>
|
45
|
+
import Button from '../button/Base.mjs';
|
46
|
+
import Container from '../container/Base.mjs';
|
47
|
+
|
48
|
+
class MainView extends Container {
|
49
|
+
static config = {
|
50
|
+
className: 'Example.view.MainView',
|
51
|
+
layout : {ntype:'vbox', align:'start'},
|
52
|
+
items : [{
|
53
|
+
module: Button,
|
54
|
+
text : 'Button'
|
55
|
+
}]
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
MainView = Neo.setupClass(MainView);
|
60
|
+
</pre>
|
61
|
+
|
62
|
+
---
|
63
|
+
|
64
|
+
Your journey into Neo.mjs starts here. The next page will guide you through its core benefits, or if you're ready to get
|
65
|
+
hands-on, jump directly to [Getting Started](#/learn/gettingstarted.Setup) to build your first application.
|
@@ -10,7 +10,7 @@ and nested approach to their configuration, a gap that a class config system aim
|
|
10
10
|
## A bad example
|
11
11
|
I recently found this Angular code snippet (new public API draft) on LinkedIn:
|
12
12
|
|
13
|
-
<pre data-
|
13
|
+
<pre data-code-readonly>
|
14
14
|
// MyComponent with an attribute
|
15
15
|
<MyComponent myAttribute="someValue" />
|
16
16
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
You do not need to define a state tree on your own.
|
4
4
|
It is sufficient to just use namespaces inside the `name` attribute of each field.
|
5
5
|
|
6
|
-
<pre data-
|
6
|
+
<pre data-code-livepreview>
|
7
7
|
import Button from '../button/Base.mjs';
|
8
8
|
import FormContainer from '../form/Container.mjs';
|
9
9
|
import TextField from '../form/field/Text.mjs';
|
@@ -49,7 +49,7 @@ Getting the field values still works like before.
|
|
49
49
|
Use case: In case you have a form split into multiple pages and only one of them is mounted to keep
|
50
50
|
the DOM minimal, you can still get all field values.
|
51
51
|
|
52
|
-
<pre data-
|
52
|
+
<pre data-code-livepreview>
|
53
53
|
import Button from '../button/Base.mjs';
|
54
54
|
import Container from '../container/Base.mjs';
|
55
55
|
import FormContainer from '../form/Container.mjs';
|
@@ -104,7 +104,7 @@ Inside the example preview, clear the user lastname via hitting the x-button.
|
|
104
104
|
Afterwards, click on the 3 buttons at the bottom and inspect the output inside the main window console carefully.
|
105
105
|
|
106
106
|
The main form will log:
|
107
|
-
<pre data-
|
107
|
+
<pre data-code-readonly>
|
108
108
|
{
|
109
109
|
account: 'My Account',
|
110
110
|
product: {brand: 'Tesla', name: 'Car'},
|
@@ -114,18 +114,18 @@ The main form will log:
|
|
114
114
|
</pre>
|
115
115
|
|
116
116
|
The user form will log:
|
117
|
-
<pre data-
|
117
|
+
<pre data-code-readonly>
|
118
118
|
{user: {firstname: 'John', lastname: null}}
|
119
119
|
'isValid: false'
|
120
120
|
</pre>
|
121
121
|
|
122
122
|
The product form will log:
|
123
|
-
<pre data-
|
123
|
+
<pre data-code-readonly>
|
124
124
|
{product: {brand: 'Tesla', name: 'Car'}}
|
125
125
|
'isValid: true'
|
126
126
|
</pre>
|
127
127
|
|
128
|
-
<pre data-
|
128
|
+
<pre data-code-livepreview>
|
129
129
|
import Button from '../button/Base.mjs';
|
130
130
|
import Container from '../container/Base.mjs';
|
131
131
|
import FormContainer from '../form/Container.mjs';
|
@@ -244,7 +244,7 @@ since it does rely on defining child modules inside their own class files
|
|
244
244
|
and dynamically importing them.
|
245
245
|
|
246
246
|
In a nutshell:
|
247
|
-
<pre data-
|
247
|
+
<pre data-code-readonly>
|
248
248
|
{
|
249
249
|
module: TabContainer,
|
250
250
|
items : [
|
@@ -1,7 +1,10 @@
|
|
1
1
|
## Introduction
|
2
2
|
|
3
|
-
Neo.mjs was the very first frontend framework, which enabled full support for a zero builds instant development mode
|
4
|
-
while sticking to the latest ECMAScript features (e.g
|
3
|
+
Neo.mjs was the very first frontend framework, which enabled full support for a ***zero builds instant development mode***,
|
4
|
+
while sticking to the latest ECMAScript features (e.g., the ES6 class system, modules and dynamic imports).
|
5
|
+
This means that your ***primary development workflow*** with Neo.mjs involves creating and debugging your application
|
6
|
+
***entirely within this instant, zero-builds environment***, with builds typically reserved only for ***deployment or
|
7
|
+
specific testing scenarios***.
|
5
8
|
|
6
9
|
Developers can save massive amounts of time when creating and debugging their apps, but at some point apps want to be
|
7
10
|
deployed. To do this right, it is crucial to have an overview of the available environments.
|
@@ -122,12 +125,8 @@ The Webpack build pipeline in `dist/production` applies aggressive optimizations
|
|
122
125
|
* ***Dead Code Elimination*** (Tree Shaking): Removing any code that is not actually used by the application, further
|
123
126
|
reducing bundle size.
|
124
127
|
|
125
|
-
### Broadest Browser Compatibility
|
126
|
-
|
127
|
-
Bundling typically includes polyfills and transpilation for older ECMAScript features, ensuring your application runs
|
128
|
-
smoothly even on browsers that don't fully support the latest web standards (which dist/esm relies upon).
|
129
|
-
|
130
128
|
### Simplified Single-File Deployment
|
129
|
+
|
131
130
|
For environments where serving multiple module files isn't optimal, or for legacy server setups, `dist/production`
|
132
131
|
provides the convenience of deploying just a few highly optimized bundle files.
|
133
132
|
|
@@ -185,14 +184,14 @@ it's running in.
|
|
185
184
|
|
186
185
|
* ***Zero Builds Development Mode***: Dynamically loaded code-based modules will, naturally, load from the dev mode
|
187
186
|
structure itself, leveraging its instant, direct-from-source capabilities.
|
188
|
-
*
|
187
|
+
* ***dist/esm***: When running in the `dist/esm` environment, dynamically loaded code-based modules will be sourced from
|
189
188
|
the dist/esm structure. This means your application consistently utilizes native ES Modules for both its core and any
|
190
189
|
dynamically extended functionalities.
|
191
|
-
*
|
190
|
+
* ***dist/development***: Surprisingly, when running in the `dist/development` environment (the Webpack-bundled, unminified
|
192
191
|
version), dynamically loaded code-based modules will revert to loading from the dev mode structure. This is because
|
193
192
|
dist/development bundles your primary application code, but it doesn't pre-bundle every potential dynamic extension.
|
194
193
|
Relying on the dev mode for these ensures they are unminified and retain debugging fidelity.
|
195
|
-
*
|
194
|
+
* ***dist/production***: Similarly, if your core application is deployed in `dist/production` (the fully optimized Webpack
|
196
195
|
bundle), dynamically loaded code-based modules will be sourced from the `dist/esm` structure. This is the optimal fallback,
|
197
196
|
as `dist/esm` provides highly performant, modular, and standards-compliant loading for individual files, which is critical
|
198
197
|
for code that wasn't part of the initial production bundle.
|
@@ -1,10 +1,42 @@
|
|
1
|
-
Why
|
1
|
+
## Why Organizations Choose Neo.mjs
|
2
2
|
|
3
|
-
|
3
|
+
Are your development teams burdened by slow build times, the debugging complexities introduced by transpilation and
|
4
|
+
unreliable source maps, or battling UI freezes because ***traditional frameworks (like Angular, React, or Vue) often limit
|
5
|
+
your application to a single CPU core?*** Traditional frontend development often comes with these frustrating compromises.
|
4
6
|
|
5
|
-
|
7
|
+
***Neo.mjs fundamentally redefines the web development experience, offering a solution that is both revolutionary for
|
8
|
+
developers and unmatched in performance.***
|
6
9
|
|
7
|
-
|
10
|
+
### Lightning-Fast Development & App-Centric Creation
|
8
11
|
|
12
|
+
Forget the constant interruptions of build processes in your daily workflow. Neo.mjs empowers an instant, zero-builds
|
13
|
+
development mode, allowing you to work directly with 100% web standards-based JavaScript. This dramatically accelerates
|
14
|
+
your team's velocity and simplifies debugging, letting you focus purely on innovation.
|
9
15
|
|
10
|
-
|
16
|
+
Moreover, Neo.mjs shifts the paradigm: instead of just writing UI components that feel like HTML, you'll ***create entire
|
17
|
+
applications***. Thanks to its revolutionary ***Unified Config System***, you define complex application structures—from
|
18
|
+
components and layouts to data models—purely through declarative configurations, gaining unparalleled control and efficiency.
|
19
|
+
|
20
|
+
### Unparalleled Performance & Scalability
|
21
|
+
|
22
|
+
Neo.mjs is engineered from the ground up for extreme performance. Unlike most frameworks that are limited to a single CPU
|
23
|
+
core per browser tab, Neo.mjs leverages a ***truly multi-threaded architecture***. Your application logic runs ***off the
|
24
|
+
main thread*** across dedicated Web Workers, ensuring your UI remains silky smooth, responsive, and free from freezes,
|
25
|
+
even under heavy computation.
|
26
|
+
|
27
|
+
This unique design enables your applications to scale not just in raw performance, but also in ***complexity and scope,
|
28
|
+
growing effortlessly from a tiny proof-of-concept to a massive enterprise application with hundreds of dynamic views.***
|
29
|
+
Features like intelligent lazy loading and runtime-built state trees ensure the framework effortlessly manages large-scale
|
30
|
+
application growth and intricate multi-window experiences.
|
31
|
+
|
32
|
+
### Architectural Brilliance & Future-Proofing
|
33
|
+
|
34
|
+
Built on cutting-edge web standards, Neo.mjs embraces an "Application Worker being the Main Actor" paradigm.
|
35
|
+
This robust architecture inherently prevents common issues like UI blocking and memory leaks. Furthermore, Neo.mjs
|
36
|
+
uniquely handles ***dynamic, run-time module imports*** without the traditional bundler overhead, offering flexibility
|
37
|
+
for advanced scenarios like user-editable code.
|
38
|
+
|
39
|
+
---
|
40
|
+
|
41
|
+
***Read on to learn more about Neo.mjs's key features and benefits, and how it can transform your web application
|
42
|
+
development.***
|
@@ -14,7 +14,7 @@ running the code. Even though it's running in a new window, it's still part of t
|
|
14
14
|
(In this case, the app is the web site you're looking at now.) That means both the code in both windows
|
15
15
|
seamlessly share events, data, etc. — the code doesn't care that some code is running in a
|
16
16
|
separate window.
|
17
|
-
<pre data-
|
17
|
+
<pre data-code-livepreview>
|
18
18
|
import Button from '../button/Base.mjs';
|
19
19
|
import Container from '../container/Base.mjs';
|
20
20
|
|
@@ -20,7 +20,7 @@ Click on Preview, then use your mouse or trackpad to pan and zoom — the he
|
|
20
20
|
If you move quickly, you might reach 20,000 or 30,000 delta updates per second. We've seen some examples that go over 40,000 updates per
|
21
21
|
second — but we've never actually hit the limit.
|
22
22
|
|
23
|
-
<pre data-
|
23
|
+
<pre data-code-livepreview>
|
24
24
|
import Container from '../container/Base.mjs';
|
25
25
|
import Helix from '../component/Helix.mjs';
|
26
26
|
|
@@ -3,7 +3,7 @@ Neo has a feature that allows shared, bindable, data.
|
|
3
3
|
A _state provider_ — `Neo.state.Provider` — instance holds properties that
|
4
4
|
can be bound to component properties.
|
5
5
|
|
6
|
-
<pre data-
|
6
|
+
<pre data-code-livepreview>
|
7
7
|
import Container from '../container/Base.mjs';
|
8
8
|
import Label from '../component/Label.mjs';
|
9
9
|
import TextField from '../form/field/Text.mjs';
|
@@ -55,7 +55,7 @@ usually coded as separate classes.)
|
|
55
55
|
|
56
56
|
Below is another example.
|
57
57
|
|
58
|
-
<pre data-
|
58
|
+
<pre data-code-livepreview>
|
59
59
|
import Container from '../container/Base.mjs';
|
60
60
|
import Label from '../component/Label.mjs';
|
61
61
|
import Panel from '../container/Panel.mjs';
|
@@ -17,7 +17,7 @@ Here's an example of a new component class `Simple` with three config properties
|
|
17
17
|
The `Simple` class introduces syntax. It doesn't have any content, so if you run the code you won't
|
18
18
|
see anything. We'll change that in the next example.
|
19
19
|
|
20
|
-
<pre data-
|
20
|
+
<pre data-code-livepreview>
|
21
21
|
import Component from '../component/Base.mjs';
|
22
22
|
import Container from '../container/Base.mjs';
|
23
23
|
|
@@ -57,7 +57,7 @@ a _lifecyle property_. A lifecycle property provides methods that are run as the
|
|
57
57
|
updated or accessed. You're free to implment these methods to provide business rules, normalize
|
58
58
|
values, or have side-effects, such as updating a view or firing an event.
|
59
59
|
|
60
|
-
<pre data-
|
60
|
+
<pre data-code-livepreview>
|
61
61
|
import Component from '../component/Base.mjs';
|
62
62
|
import Container from '../container/Base.mjs';
|
63
63
|
|
@@ -110,7 +110,7 @@ Typically, the _afterSet_ method is used to update a view or to fire an event.
|
|
110
110
|
|
111
111
|
Look at this code: `afterSetBar()` fires an event, and the config in the `items[]` is listening to it.
|
112
112
|
|
113
|
-
<pre data-
|
113
|
+
<pre data-code-livepreview>
|
114
114
|
import Component from '../component/Base.mjs';
|
115
115
|
import Container from '../container/Base.mjs';
|
116
116
|
|
@@ -10,7 +10,7 @@ use to describe the component you're creating> You can also access or set the pr
|
|
10
10
|
|
11
11
|
## A view with one component
|
12
12
|
|
13
|
-
<pre data-
|
13
|
+
<pre data-code-livepreview>
|
14
14
|
import Button from '../button/Base.mjs';
|
15
15
|
import Container from '../container/Base.mjs';
|
16
16
|
|
@@ -46,7 +46,7 @@ Let's put a second button in the container.
|
|
46
46
|
|
47
47
|
## A view with two components
|
48
48
|
|
49
|
-
<pre data-
|
49
|
+
<pre data-code-livepreview>
|
50
50
|
import Button from '../button/Base.mjs';
|
51
51
|
import Container from '../container/Base.mjs';
|
52
52
|
|
@@ -13,7 +13,7 @@ pairs as you need.
|
|
13
13
|
The code below shows two text fields, with `listeners` for `change` and `focusEnter`.
|
14
14
|
(The events for any component are documented in the API docs.)
|
15
15
|
|
16
|
-
<pre data-
|
16
|
+
<pre data-code-livepreview>
|
17
17
|
import Container from '../container/Base.mjs';
|
18
18
|
import TextField from '../form/field/Text.mjs';
|
19
19
|
|
@@ -52,7 +52,7 @@ that with a _component controller_.
|
|
52
52
|
A `Neo.controller.Component` is a simple class associated with a component class. As a view is created, an
|
53
53
|
instance of its associated controller is automatically created.
|
54
54
|
|
55
|
-
<pre data-
|
55
|
+
<pre data-code-livepreview>
|
56
56
|
import Base from '../controller/Component.mjs';
|
57
57
|
|
58
58
|
class MainViewController extends Base {
|
@@ -116,7 +116,7 @@ automatically get lifecycle methods run before the value is assigned, after the
|
|
116
116
|
before the value is accessed. We're using the _after_ method to fire a `change` event.
|
117
117
|
|
118
118
|
|
119
|
-
<pre data-
|
119
|
+
<pre data-code-livepreview>
|
120
120
|
import Button from '../button/Base.mjs';
|
121
121
|
import Container from '../container/Base.mjs';
|
122
122
|
|
@@ -5,7 +5,7 @@ to test.
|
|
5
5
|
|
6
6
|
Consider this code. It's a panel with a header and a table. The table has a store.
|
7
7
|
|
8
|
-
<pre data-
|
8
|
+
<pre data-code-livepreview>
|
9
9
|
import Button from '../button/Base.mjs';
|
10
10
|
import Panel from '../container/Panel.mjs';
|
11
11
|
import Table from '../table/Container.mjs';
|
@@ -48,7 +48,7 @@ If you wanted, any of the configs can be refactored into their own class. Here,
|
|
48
48
|
have been refactored into their own classes, and the main view is using them. The main view is simpler and
|
49
49
|
more abstract, and each class can be reused, tested, and maintained independently.
|
50
50
|
|
51
|
-
<pre data-
|
51
|
+
<pre data-code-livepreview>
|
52
52
|
import Button from '../button/Base.mjs';
|
53
53
|
import Panel from '../container/Panel.mjs';
|
54
54
|
import Store from '../data/Store.mjs';
|
@@ -10,7 +10,7 @@ There are two common ways of doing that:
|
|
10
10
|
Here's an example with one button. Clicking on the button will disable it.
|
11
11
|
As you can see, the handler uses the component reference pass in via `data.component`.
|
12
12
|
|
13
|
-
<pre data-
|
13
|
+
<pre data-code-livepreview>
|
14
14
|
import Button from '../button/Base.mjs';
|
15
15
|
import Container from '../container/Base.mjs';
|
16
16
|
import Controller from '../controller/Component.mjs';
|
@@ -47,7 +47,7 @@ But what if we need to get a reference to another component in the view? In that
|
|
47
47
|
you tag the component you need with a `reference` config, then use `getReference()` in
|
48
48
|
the controller.
|
49
49
|
|
50
|
-
<pre data-
|
50
|
+
<pre data-code-livepreview>
|
51
51
|
import Button from '../button/Base.mjs';
|
52
52
|
import Container from '../container/Base.mjs';
|
53
53
|
import Controller from '../controller/Component.mjs';
|
@@ -102,7 +102,7 @@ But app logic should never use `Neo.findFirst()` and very rarely use `up()` or `
|
|
102
102
|
The following example gets a reference to the _Learn_ button at the top of this site, and changes its `text`.
|
103
103
|
Again — that use of `Neo.findFirst()` might be handy when debugging, but it should never be used in app logic.
|
104
104
|
|
105
|
-
<pre data-
|
105
|
+
<pre data-code-livepreview>
|
106
106
|
import Button from '../button/Base.mjs';
|
107
107
|
import Container from '../container/Base.mjs';
|
108
108
|
|
@@ -40,7 +40,7 @@ as well as create new views classes, their controllers, and other application lo
|
|
40
40
|
|
41
41
|
Now let's look at a source file. This is the contents of `MainView.mjs`.
|
42
42
|
|
43
|
-
<pre data-
|
43
|
+
<pre data-code-readonly>
|
44
44
|
import Container from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
45
45
|
import Controller from './MainViewController.mjs';
|
46
46
|
import ViewModel from './MainViewModel.mjs';
|
@@ -78,7 +78,7 @@ you see how a component is configured let's put a button in the container.
|
|
78
78
|
First, we need to import the class that defines buttons. Then we'll describe the new button in the
|
79
79
|
`items:[].`
|
80
80
|
|
81
|
-
<pre data-
|
81
|
+
<pre data-code-readonly>
|
82
82
|
import Button from '../../../node_modules/neo.mjs/src/button/Base.mjs';
|
83
83
|
import Container from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
84
84
|
import Controller from './MainViewController.mjs';
|
@@ -120,7 +120,7 @@ Here's a simplified running example. The `model` and `controller` are omitted, b
|
|
120
120
|
actually used in the example, and the import root path is different to reflect the location of the
|
121
121
|
Neo.mjs library relative to the examples.
|
122
122
|
|
123
|
-
<pre data-
|
123
|
+
<pre data-code-livepreview>
|
124
124
|
import Button from '../button/Base.mjs';
|
125
125
|
import Container from '../container/Base.mjs';
|
126
126
|
|
@@ -25,7 +25,7 @@ primitive. Components introduce various properties, such as `width`, `height`, `
|
|
25
25
|
|
26
26
|
Here's a container, with one child item.
|
27
27
|
|
28
|
-
<pre data-
|
28
|
+
<pre data-code-livepreview>
|
29
29
|
import Container from '../container/Base.mjs';
|
30
30
|
|
31
31
|
class MainView extends Container {
|
@@ -47,7 +47,7 @@ MainView = Neo.setupClass(MainView);
|
|
47
47
|
Components also have an `html`. The `html` property is rarely used, and goes against the abstract philosophy of Neo.mjs, but
|
48
48
|
sometimes it's handy as a placeholder as you stub out views.
|
49
49
|
|
50
|
-
<pre data-
|
50
|
+
<pre data-code-livepreview>
|
51
51
|
import Container from '../container/Base.mjs';
|
52
52
|
|
53
53
|
class MainView extends Container {
|
@@ -77,7 +77,7 @@ some commonly-used layouts.
|
|
77
77
|
|
78
78
|
Fix is used when there's a single child. The component is sized to fit the container.
|
79
79
|
|
80
|
-
<pre data-
|
80
|
+
<pre data-code-livepreview>
|
81
81
|
import Container from '../container/Base.mjs';
|
82
82
|
|
83
83
|
class MainView extends Container {
|
@@ -98,7 +98,7 @@ MainView = Neo.setupClass(MainView);
|
|
98
98
|
|
99
99
|
With `vbox` and `hbox`, items are arranged vertically or horizontally.
|
100
100
|
|
101
|
-
<pre data-
|
101
|
+
<pre data-code-livepreview>
|
102
102
|
import Button from '../button/Base.mjs';
|
103
103
|
import Container from '../container/Base.mjs';
|
104
104
|
|
@@ -125,7 +125,7 @@ MainView = Neo.setupClass(MainView);
|
|
125
125
|
|
126
126
|
A card container has multiple child items, one of which is visible.
|
127
127
|
|
128
|
-
<pre data-
|
128
|
+
<pre data-code-livepreview>
|
129
129
|
import Button from '../button/Base.mjs';
|
130
130
|
import Container from '../container/Base.mjs';
|
131
131
|
|
@@ -177,7 +177,7 @@ MainView = Neo.setupClass(MainView);
|
|
177
177
|
Neo.mjs is class-based, and thus, any component or container can be defined as its own class, and reused like any
|
178
178
|
other component in the framework.
|
179
179
|
|
180
|
-
<pre data-
|
180
|
+
<pre data-code-livepreview>
|
181
181
|
import Button from '../button/Base.mjs';
|
182
182
|
// In practice this would be some handy reusable component
|
183
183
|
class MySpecialButton extends Button {
|
@@ -9,7 +9,7 @@ Neo.mjs is class-based, which means you're free to extend any component (or any
|
|
9
9
|
|
10
10
|
## Lifecycle config properties
|
11
11
|
|
12
|
-
<pre data-
|
12
|
+
<pre data-code-livepreview>
|
13
13
|
import Button from '../button/Base.mjs';
|
14
14
|
// In practice this would be some handy reusable component
|
15
15
|
class MySpecialButton extends Button {
|
@@ -18,7 +18,7 @@ please return a specified `window` property." Neo.mjs
|
|
18
18
|
lets you do that via `Neo.Main.getByPath()`. For
|
19
19
|
example, the following statement logs the URL query string.
|
20
20
|
|
21
|
-
<pre data-
|
21
|
+
<pre data-code-readonly>
|
22
22
|
const search = await Neo.Main.getByPath({path: 'window.location.search'});
|
23
23
|
console.log(search); // Logs the search string
|
24
24
|
</pre>
|
@@ -10,7 +10,7 @@ Other libraries or frameworks often call state providers "Stores".
|
|
10
10
|
|
11
11
|
## Inline State Providers
|
12
12
|
### Direct Bindings
|
13
|
-
<pre data-
|
13
|
+
<pre data-code-livepreview>
|
14
14
|
import Button from '../button/Base.mjs';
|
15
15
|
import Container from '../container/Base.mjs';
|
16
16
|
import Label from '../component/Label.mjs';
|
@@ -58,7 +58,7 @@ We can easily bind 1:1 to specific data props using the following syntax:</br>
|
|
58
58
|
`bind: {text: data => data.hello}`
|
59
59
|
|
60
60
|
### Bindings with multiple data props
|
61
|
-
<pre data-
|
61
|
+
<pre data-code-livepreview>
|
62
62
|
import Button from '../button/Base.mjs';
|
63
63
|
import Container from '../container/Base.mjs';
|
64
64
|
import Label from '../component/Label.mjs';
|
@@ -128,7 +128,7 @@ data.component equals to the Button instance itself. Since the Button instance d
|
|
128
128
|
`getStateProvider()` will return the closest stateProvider inside the parent chain.
|
129
129
|
|
130
130
|
### Nested Inline State Providers
|
131
|
-
<pre data-
|
131
|
+
<pre data-code-livepreview>
|
132
132
|
import Button from '../button/Base.mjs';
|
133
133
|
import Container from '../container/Base.mjs';
|
134
134
|
import Label from '../component/Label.mjs';
|
@@ -203,7 +203,7 @@ We can even change data props which live inside different stateProviders at once
|
|
203
203
|
Hint: Modify the example code (Button handler) to try it out right away!
|
204
204
|
|
205
205
|
### Nested Data Properties
|
206
|
-
<pre data-
|
206
|
+
<pre data-code-livepreview>
|
207
207
|
import Button from '../button/Base.mjs';
|
208
208
|
import Container from '../container/Base.mjs';
|
209
209
|
import Label from '../component/Label.mjs';
|
@@ -262,7 +262,7 @@ Or we can directly pass the object containing the change(s):</br>
|
|
262
262
|
Hint: This will not override left out nested data props (lastname in this case).
|
263
263
|
|
264
264
|
### Dialog connecting to a Container
|
265
|
-
<pre data-
|
265
|
+
<pre data-code-livepreview>
|
266
266
|
import Controller from '../controller/Component.mjs';
|
267
267
|
import Dialog from '../dialog/Base.mjs';
|
268
268
|
import Panel from '../container/Panel.mjs';
|
@@ -384,7 +384,7 @@ MainView = Neo.setupClass(MainView);
|
|
384
384
|
When your stateProviders contain many data props or need custom logic, you can easily move them into their own classes.
|
385
385
|
|
386
386
|
### Direct Bindings
|
387
|
-
<pre data-
|
387
|
+
<pre data-code-livepreview>
|
388
388
|
import Button from '../button/Base.mjs';
|
389
389
|
import Container from '../container/Base.mjs';
|
390
390
|
import Label from '../component/Label.mjs';
|
@@ -1,7 +1,7 @@
|
|
1
1
|
As you read in the <a href="#/learn/Events">Getting Started > Events</a> topic, components, stores, and many other objects fire events.
|
2
2
|
|
3
3
|
|
4
|
-
<pre data-
|
4
|
+
<pre data-code-livepreview>
|
5
5
|
import Container from '../container/Base.mjs';
|
6
6
|
import TextField from '../form/field/Text.mjs';
|
7
7
|
|
@@ -35,7 +35,7 @@ MainView = Neo.setupClass(MainView);
|
|
35
35
|
The event listener function can be coded in-line. Normally you want event handlers to be in a view's
|
36
36
|
controller, but for very simple situation it can be convenient to use this syntax.
|
37
37
|
|
38
|
-
<pre data-
|
38
|
+
<pre data-code-livepreview>
|
39
39
|
import Container from '../container/Base.mjs';
|
40
40
|
import TextField from '../form/field/Text.mjs';
|
41
41
|
|
@@ -62,7 +62,7 @@ You can also use the `up.` qualifier to specify a method in the component's pare
|
|
62
62
|
in-line syntax you saw above, using the `up.` syntax might be convenient for simple classees,
|
63
63
|
or when you simply haven't gotten around to defining a view's controller.
|
64
64
|
|
65
|
-
<pre data-
|
65
|
+
<pre data-code-livepreview>
|
66
66
|
import Container from '../container/Base.mjs';
|
67
67
|
import TextField from '../form/field/Text.mjs';
|
68
68
|
|
@@ -92,7 +92,7 @@ Despite the examples above, the most correct way of setting up event handlers is
|
|
92
92
|
Any view class can specify a controller — wWhen the view is created a controller instance is
|
93
93
|
also created.
|
94
94
|
|
95
|
-
<pre data-
|
95
|
+
<pre data-code-livepreview>
|
96
96
|
import Controller from '../controller/Component.mjs';
|
97
97
|
|
98
98
|
class MainViewController extends Controller {
|
@@ -134,7 +134,7 @@ a listener procedurally.
|
|
134
134
|
|
135
135
|
Any observable class has an `addListener` method, along with an easier-to-type version called `on`.
|
136
136
|
|
137
|
-
<pre data-
|
137
|
+
<pre data-code-livepreview>
|
138
138
|
import Controller from '../controller/Component.mjs';
|
139
139
|
|
140
140
|
class MainViewController extends Controller {
|
@@ -171,7 +171,7 @@ MainView = Neo.setupClass(MainView);
|
|
171
171
|
|
172
172
|
The method specified in `on()` doesn't have to be an arrow function; you can use a controller function.
|
173
173
|
|
174
|
-
<pre data-
|
174
|
+
<pre data-code-livepreview>
|
175
175
|
import Controller from '../controller/Component.mjs';
|
176
176
|
|
177
177
|
class MainViewController extends Controller {
|
@@ -241,7 +241,7 @@ will automatically be reflected in the view model.
|
|
241
241
|
To contrast syntax, and to illustrate the simplicity of a binding, let's look at two exmaples of updating a component
|
242
242
|
to reflect the value of a text field. THe first example uses events; the second uses bindings.
|
243
243
|
|
244
|
-
<pre data-
|
244
|
+
<pre data-code-livepreview>
|
245
245
|
import Component from '../component/Base.mjs';
|
246
246
|
import Container from '../container/Base.mjs';
|
247
247
|
import TextField from '../form/field/Text.mjs';
|
@@ -279,7 +279,7 @@ class MainView extends Container {
|
|
279
279
|
MainView = Neo.setupClass(MainView);
|
280
280
|
</pre>
|
281
281
|
|
282
|
-
<pre data-
|
282
|
+
<pre data-code-livepreview>
|
283
283
|
import Component from '../component/Base.mjs';
|
284
284
|
import Container from '../container/Base.mjs';
|
285
285
|
import TextField from '../form/field/Text.mjs';
|
@@ -34,7 +34,7 @@ the class. If you add `console.log(this);`, the output is most likely not want y
|
|
34
34
|
For the second Button we are defining a non-bound function, in which case `this` will point
|
35
35
|
to the Component instance.
|
36
36
|
|
37
|
-
<pre data-
|
37
|
+
<pre data-code-livepreview>
|
38
38
|
import Container from '../container/Base.mjs';
|
39
39
|
|
40
40
|
class MainView extends Container {
|
@@ -72,7 +72,7 @@ A good example would be `tab.header.Toolbar`, where clicking on a Button will ch
|
|
72
72
|
You can use string based listeners. In case the handler method lives within the parent tree (any level),
|
73
73
|
we need to prefix these listeners with `up.`.
|
74
74
|
|
75
|
-
<pre data-
|
75
|
+
<pre data-code-livepreview>
|
76
76
|
import Container from '../container/Base.mjs';
|
77
77
|
|
78
78
|
class MainView extends Container {
|
@@ -107,7 +107,7 @@ to find the closest match.
|
|
107
107
|
|
108
108
|
A good use case would be a form submit Button, where a click will trigger a communication to the backend.
|
109
109
|
|
110
|
-
<pre data-
|
110
|
+
<pre data-code-livepreview>
|
111
111
|
import Container from '../container/Base.mjs';
|
112
112
|
import Controller from '../controller/Component.mjs';
|
113
113
|
|
@@ -146,7 +146,7 @@ MainView = Neo.setupClass(MainView);
|
|
146
146
|
|
147
147
|
We can further delegate listeners to specific DOM nodes within our Component:
|
148
148
|
|
149
|
-
<pre data-
|
149
|
+
<pre data-code-livepreview>
|
150
150
|
import Container from '../container/Base.mjs';
|
151
151
|
|
152
152
|
class MainView extends Container {
|
@@ -184,7 +184,7 @@ we will get logs when clicking on the blue div too.
|
|
184
184
|
|
185
185
|
We can prevent listeners from bubbling upwards:
|
186
186
|
|
187
|
-
<pre data-
|
187
|
+
<pre data-code-livepreview>
|
188
188
|
import Container from '../container/Base.mjs';
|
189
189
|
|
190
190
|
class MainView extends Container {
|
@@ -237,7 +237,7 @@ While we could just manually order the array inside the following example,
|
|
237
237
|
there can be use cases where multiple subscribers get added at run-time and developers
|
238
238
|
can not be sure about the adding order.
|
239
239
|
|
240
|
-
<pre data-
|
240
|
+
<pre data-code-livepreview>
|
241
241
|
import Container from '../container/Base.mjs';
|
242
242
|
|
243
243
|
class MainView extends Container {
|
@@ -2,7 +2,7 @@ Neo.mjs classes are standard JavaScript classes. Every source file
|
|
2
2
|
you write will be a class definition, extending some Neo.mjs
|
3
3
|
class.
|
4
4
|
|
5
|
-
<pre data-
|
5
|
+
<pre data-code-readonly>
|
6
6
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
7
7
|
|
8
8
|
class Mammal extends Base {
|
@@ -29,7 +29,7 @@ and create instances as needed.
|
|
29
29
|
|
30
30
|
Let's add a `name` propery to the class.
|
31
31
|
|
32
|
-
<pre data-
|
32
|
+
<pre data-code-readonly>
|
33
33
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
34
34
|
|
35
35
|
class Mammal extends Base {
|
@@ -61,7 +61,7 @@ anywhere in the class hierarchy.
|
|
61
61
|
Since our class defines a `name` property, we can specify that when creating
|
62
62
|
the instance, using the second argument to the `create` method.
|
63
63
|
|
64
|
-
<pre data-
|
64
|
+
<pre data-code-readonly>
|
65
65
|
const myMammal = Neo.create(Mammal, {
|
66
66
|
name: 'Creature'
|
67
67
|
});
|
@@ -73,7 +73,7 @@ Since _you_ define those properties, you can
|
|
73
73
|
look for them in class methods and use them as needed.
|
74
74
|
Let's add a `speak()` method that uses the `name` property.
|
75
75
|
|
76
|
-
<pre data-
|
76
|
+
<pre data-code-readonly>
|
77
77
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
78
78
|
|
79
79
|
class Mammal extends Base {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<pre data-
|
1
|
+
<pre data-code-readonly>
|
2
2
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
3
3
|
|
4
4
|
class Mammal extends Base {
|
@@ -15,7 +15,7 @@ export default Mammal; // Makes the class available elsewhere.
|
|
15
15
|
|
16
16
|
|
17
17
|
|
18
|
-
<pre data-
|
18
|
+
<pre data-code-livepreview>
|
19
19
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
20
20
|
|
21
21
|
class Mammal extends Base {
|
@@ -3,7 +3,7 @@ In Neo.mjs you sub-class and override methods in the usual way.
|
|
3
3
|
Here, we'll extend `Mammal` and override the `speak()` method.
|
4
4
|
(For brevity, we'll exclude `export` and `import` statements.)
|
5
5
|
|
6
|
-
<pre data-
|
6
|
+
<pre data-code-readonly>
|
7
7
|
class Mammal extends Base {
|
8
8
|
static config = {
|
9
9
|
className: 'Simple.example.Mammal',
|
@@ -17,7 +17,7 @@ class Mammal extends Base {
|
|
17
17
|
Neo.setupClass(Mammal);
|
18
18
|
</pre>
|
19
19
|
|
20
|
-
<pre data-
|
20
|
+
<pre data-code-readonly>
|
21
21
|
class Human extends Mammal {
|
22
22
|
static config = {
|
23
23
|
className: 'Simple.example.Human',
|
@@ -38,7 +38,7 @@ Neo.setupClass(Mammal);
|
|
38
38
|
Any class in the hierarchy is free to add new properties and methods. Let's add
|
39
39
|
a property and behavior (method) to the Human class.
|
40
40
|
|
41
|
-
<pre data-
|
41
|
+
<pre data-code-readonly>
|
42
42
|
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
43
43
|
|
44
44
|
class Mammal extends Base {
|
@@ -53,7 +53,7 @@ class Mammal extends Base {
|
|
53
53
|
}
|
54
54
|
</pre>
|
55
55
|
|
56
|
-
<pre data-
|
56
|
+
<pre data-code-readonly>
|
57
57
|
class Human extends Mammal {
|
58
58
|
static config = {
|
59
59
|
className: 'Simple.example.Human',
|
@@ -187,7 +187,7 @@ later in the lab.
|
|
187
187
|
Use a code editor and look at `workspace/apps/earthquakes/src/view/MainView.mjs`. You'll see the
|
188
188
|
following class definition:
|
189
189
|
|
190
|
-
<pre data-
|
190
|
+
<pre data-code-readonly>
|
191
191
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
192
192
|
import Controller from './MainViewController.mjs';
|
193
193
|
import MainStateProvider from './MainStateProvider.mjs';
|
@@ -223,7 +223,7 @@ that buttons have various configs, such as `text`, which is the button text, `ic
|
|
223
223
|
is typically a FontAwesome CSS class used to show an icon, and `handler`, which specifies
|
224
224
|
which method to run when the button is clicked. We'll use `text`.
|
225
225
|
|
226
|
-
<pre data-
|
226
|
+
<pre data-code-readonly>
|
227
227
|
|
228
228
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
229
229
|
import Button from '../../../node_modules/neo.mjs/src/button/Base.mjs';
|
@@ -271,7 +271,7 @@ for the classes you define.
|
|
271
271
|
|
272
272
|
Let's change the layout to arrange items vertically, with items aligned horizontally at the start.
|
273
273
|
|
274
|
-
<pre data-
|
274
|
+
<pre data-code-readonly>
|
275
275
|
layout: {
|
276
276
|
ntype: 'vbox',
|
277
277
|
align: 'start'
|
@@ -422,7 +422,7 @@ its methods. Let's try that out by adding a method.
|
|
422
422
|
|
423
423
|
Edit `apps/earthquakes/view/MainView.mjs` and add a method.
|
424
424
|
|
425
|
-
<pre data-
|
425
|
+
<pre data-code-readonly>
|
426
426
|
|
427
427
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
428
428
|
import Button from '../../../node_modules/neo.mjs/src/button/Base.mjs';
|
@@ -494,7 +494,7 @@ At this point we have a application with minimal content. You also know how to d
|
|
494
494
|
|
495
495
|
Replace the button with a table by replacing `MainView.mjs` with the following content.
|
496
496
|
|
497
|
-
<pre data-
|
497
|
+
<pre data-code-readonly>
|
498
498
|
|
499
499
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
500
500
|
import Table from '../../../node_modules/neo.mjs/src/table/Container.mjs';
|
@@ -582,7 +582,7 @@ Let's review the code and see what it's doing.
|
|
582
582
|
A store is a collection of records. A record is described in the `model` and the model's `fields`.
|
583
583
|
Here's the config for the store.
|
584
584
|
|
585
|
-
<pre data-
|
585
|
+
<pre data-code-readonly>
|
586
586
|
{
|
587
587
|
module: Store,
|
588
588
|
model: {
|
@@ -602,7 +602,7 @@ Here's the config for the store.
|
|
602
602
|
</pre>
|
603
603
|
|
604
604
|
The feed looks like this.
|
605
|
-
<pre data-
|
605
|
+
<pre data-code-readonly>
|
606
606
|
{
|
607
607
|
"data": [{
|
608
608
|
"timestamp": "2024-09-29T16:45:14.000Z",
|
@@ -632,7 +632,7 @@ of items.
|
|
632
632
|
|
633
633
|
Tables have two key configs: `store` and `columns`. Here's the columns config:
|
634
634
|
|
635
|
-
<pre data-
|
635
|
+
<pre data-code-readonly>
|
636
636
|
columns: [{
|
637
637
|
dataField: "timestamp",
|
638
638
|
text: "Date",
|
@@ -672,7 +672,7 @@ abstract, and it allows those classes to be tested in isolation.
|
|
672
672
|
|
673
673
|
Create a new file named `apps/earthquakes/view/earthquakes/Table.mjs` with this content.
|
674
674
|
|
675
|
-
<pre data-
|
675
|
+
<pre data-code-readonly>
|
676
676
|
import Base from '../../../../node_modules/neo.mjs/src/table/Container.mjs';
|
677
677
|
|
678
678
|
class Table extends Base {
|
@@ -735,7 +735,7 @@ You can confirm that an instance _was created_ by using the DevTools console and
|
|
735
735
|
<details>
|
736
736
|
<summary>Here's the code</summary>
|
737
737
|
|
738
|
-
<pre data-
|
738
|
+
<pre data-code-readonly>
|
739
739
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
740
740
|
import Controller from './MainViewController.mjs';
|
741
741
|
import EarthquakesTable from './earthquakes/Table.mjs';
|
@@ -858,7 +858,7 @@ State Providers have two key configs: `data` and `stores`.
|
|
858
858
|
|
859
859
|
Add a `stores` property to the state provider config that holds a copy of the store.
|
860
860
|
|
861
|
-
<pre data-
|
861
|
+
<pre data-code-readonly>
|
862
862
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
863
863
|
import Controller from './MainViewController.mjs';
|
864
864
|
import EarthquakesTable from './earthquakes/Table.mjs';
|
@@ -972,7 +972,7 @@ value is assigned to the table's `store` property.
|
|
972
972
|
|
973
973
|
Replace each table's `store` config with the binding.
|
974
974
|
|
975
|
-
<pre data-
|
975
|
+
<pre data-code-readonly>
|
976
976
|
|
977
977
|
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
978
978
|
import Controller from './MainViewController.mjs';
|
@@ -1033,7 +1033,7 @@ Save, refresh, and look at network traffic: you'll see a _single_ call to the we
|
|
1033
1033
|
|
1034
1034
|
You can further prove we're using a shared instance by running these statements in the console.
|
1035
1035
|
|
1036
|
-
<pre data-
|
1036
|
+
<pre data-code-readonly>
|
1037
1037
|
a = Neo.findFirst({ntype:'earthquakes-main'}).stateProvider.stores.earthquakes;
|
1038
1038
|
b = Neo.find({ntype:'earthquakes-table'})[0].store;
|
1039
1039
|
c = Neo.find({ntype:'earthquakes-table'})[1].store;
|
@@ -1056,7 +1056,7 @@ Since the starter app already provides `MainStateProvider`, all we need to do is
|
|
1056
1056
|
|
1057
1057
|
Here's the resulting code you should place into `MainStateProvider.mjs`.
|
1058
1058
|
|
1059
|
-
<pre data-
|
1059
|
+
<pre data-code-readonly>
|
1060
1060
|
import StateProvider from '../../../node_modules/neo.mjs/src/state/Provider.mjs';
|
1061
1061
|
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
1062
1062
|
|
@@ -1091,7 +1091,7 @@ export default Neo.setupClass(MainStateProvider);
|
|
1091
1091
|
|
1092
1092
|
And you need to remove the `stores` config from the main view as follows.
|
1093
1093
|
|
1094
|
-
<pre data-
|
1094
|
+
<pre data-code-readonly>
|
1095
1095
|
import Container from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
1096
1096
|
import Controller from './MainViewController.mjs';
|
1097
1097
|
import EarthquakesTable from './earthquakes/Table.mjs';
|
@@ -1188,7 +1188,7 @@ directory, but instead, move the files to their individual locations.
|
|
1188
1188
|
|
1189
1189
|
Edit `apps/earthquakes/neo-config.json` and add entries for the Google Maps add-on and the map key.
|
1190
1190
|
|
1191
|
-
<pre data-
|
1191
|
+
<pre data-code-readonly>
|
1192
1192
|
{
|
1193
1193
|
"appPath": "../../apps/earthquakes/app.mjs",
|
1194
1194
|
"basePath": "../../",
|
@@ -1227,7 +1227,7 @@ lets us implement those via two properties:
|
|
1227
1227
|
|
1228
1228
|
Edit `apps/earthquakes/view/MainStateProvider.mjs` and modify `fields` as follows.
|
1229
1229
|
|
1230
|
-
<pre data-
|
1230
|
+
<pre data-code-readonly>
|
1231
1231
|
fields: [{
|
1232
1232
|
name: "location",
|
1233
1233
|
}, {
|
@@ -1278,7 +1278,7 @@ and show it implace of the top table. The map should be centered on Iceland. To
|
|
1278
1278
|
|
1279
1279
|
If we replace the top table with the map, `view/MainView.mjs` ends up with this content.
|
1280
1280
|
|
1281
|
-
<pre data-
|
1281
|
+
<pre data-code-readonly>
|
1282
1282
|
|
1283
1283
|
import Container from '../container/Base.mjs';
|
1284
1284
|
import Controller from './MainViewController.mjs';
|
@@ -1333,7 +1333,7 @@ export default Neo.setupClass(MainView);
|
|
1333
1333
|
|
1334
1334
|
Add this config to the map.
|
1335
1335
|
|
1336
|
-
<pre data-
|
1336
|
+
<pre data-code-readonly>
|
1337
1337
|
bind: {
|
1338
1338
|
markerStore: 'stores.earthquakes'
|
1339
1339
|
}
|
@@ -1365,7 +1365,7 @@ Table Views fire a select event, passing an object that contains a reference to
|
|
1365
1365
|
|
1366
1366
|
Add this table config:
|
1367
1367
|
|
1368
|
-
<pre data-
|
1368
|
+
<pre data-code-readonly>
|
1369
1369
|
viewConfig: {
|
1370
1370
|
listeners: {
|
1371
1371
|
select: (data) => console.log(data.record)
|
@@ -1391,7 +1391,7 @@ After changing the value you should immediately see it reflected in the table ro
|
|
1391
1391
|
|
1392
1392
|
Now add a `markerClick` listener to the Google Map.
|
1393
1393
|
|
1394
|
-
<pre data-
|
1394
|
+
<pre data-code-readonly>
|
1395
1395
|
listeners: {
|
1396
1396
|
markerClick: data => console.log(data.data.record)
|
1397
1397
|
}
|
@@ -3,7 +3,7 @@
|
|
3
3
|
In case you did not work with neo yet, but come from a more HTML driven ecosystem,
|
4
4
|
you could achieve the task in a similar way.
|
5
5
|
|
6
|
-
<pre data-
|
6
|
+
<pre data-code-livepreview>
|
7
7
|
import Component from '../component/Base.mjs';
|
8
8
|
import NeoArray from '../util/Array.mjs';
|
9
9
|
import VdomUtil from '../util/VDom.mjs';
|
@@ -116,7 +116,7 @@ MainComponent = Neo.setupClass(MainComponent);
|
|
116
116
|
|
117
117
|
content
|
118
118
|
|
119
|
-
<pre data-
|
119
|
+
<pre data-code-livepreview>
|
120
120
|
import Container from '../container/Base.mjs';
|
121
121
|
import List from '../list/Base.mjs';
|
122
122
|
import Model from '../data/Model.mjs';
|
@@ -1,5 +1,5 @@
|
|
1
1
|
{"data": [
|
2
|
-
{"name": "
|
2
|
+
{"name": "Using These Topics", "parentId": null, "id": "UsingTheseTopics" },
|
3
3
|
{"name": "Benefits", "parentId": null, "isLeaf": false, "id": "Benefits"},
|
4
4
|
{"name": "Introduction ", "parentId": "Benefits", "id": "benefits.Introduction"},
|
5
5
|
{"name": "Off the Main Thread", "parentId": "Benefits", "id": "benefits.OffTheMainThread"},
|
@@ -63,8 +63,21 @@
|
|
63
63
|
color: #3E63DD;
|
64
64
|
}
|
65
65
|
|
66
|
-
|
67
|
-
|
66
|
+
.lab {
|
67
|
+
box-shadow : 0 4px 8px 0 rgba(0, 0, 0, 0.2);
|
68
|
+
font-size : 1em;
|
69
|
+
margin-bottom: 1em;
|
70
|
+
padding : 2px 16px;
|
71
|
+
transition : 0.3s;
|
72
|
+
|
73
|
+
&:hover {
|
74
|
+
/* On mouse-over, add a deeper shadow */
|
75
|
+
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
li::marker {
|
80
|
+
color: #3E63DD;
|
68
81
|
}
|
69
82
|
|
70
83
|
p {
|
@@ -78,17 +91,8 @@
|
|
78
91
|
padding : 12px;
|
79
92
|
}
|
80
93
|
|
81
|
-
|
82
|
-
|
83
|
-
font-size : 1em;
|
84
|
-
margin-bottom: 1em;
|
85
|
-
padding : 2px 16px;
|
86
|
-
transition : 0.3s;
|
87
|
-
|
88
|
-
&:hover {
|
89
|
-
/* On mouse-over, add a deeper shadow */
|
90
|
-
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
|
91
|
-
}
|
94
|
+
summary::-webkit-details-marker {
|
95
|
+
display: none;
|
92
96
|
}
|
93
97
|
}
|
94
98
|
|
package/src/DefaultConfig.mjs
CHANGED
@@ -264,12 +264,12 @@ const DefaultConfig = {
|
|
264
264
|
useVdomWorker: true,
|
265
265
|
/**
|
266
266
|
* buildScripts/injectPackageVersion.mjs will update this value
|
267
|
-
* @default '9.
|
267
|
+
* @default '9.16.0'
|
268
268
|
* @memberOf! module:Neo
|
269
269
|
* @name config.version
|
270
270
|
* @type String
|
271
271
|
*/
|
272
|
-
version: '9.
|
272
|
+
version: '9.16.0'
|
273
273
|
};
|
274
274
|
|
275
275
|
Object.assign(DefaultConfig, {
|
@@ -1,64 +0,0 @@
|
|
1
|
-
Welcome to Neo.mjs! This set of topics contains information to help you use Neo.mjs.
|
2
|
-
|
3
|
-
|
4
|
-
## Topics
|
5
|
-
|
6
|
-
### Benefits
|
7
|
-
|
8
|
-
Describes technical and business reasons for using Neo.mjs
|
9
|
-
|
10
|
-
### Getting Started
|
11
|
-
|
12
|
-
Install instructions, along with fundamental concepts that are good to understand before diving into Neo.mjs.
|
13
|
-
|
14
|
-
### Tutorials
|
15
|
-
|
16
|
-
Hands-on tutorials where you'll code a few simple Neo.mjs applications.
|
17
|
-
|
18
|
-
### Guides
|
19
|
-
|
20
|
-
These are in-depth discussions of various topics.
|
21
|
-
|
22
|
-
## Using these topics
|
23
|
-
|
24
|
-
### Layout
|
25
|
-
|
26
|
-
As you can see, the topics table of contents is on the left. Topic sections and sub-sections are shown on the right.
|
27
|
-
And content is here in the middle. There are "next" and "previous" buttons at the bottom of each page, to make it
|
28
|
-
easier to read several topics in sequence.
|
29
|
-
|
30
|
-
### Disclosure widgets
|
31
|
-
|
32
|
-
Topics sometimes contain "disclosure" widgets, which are just <details> tags. These are used in cases
|
33
|
-
where we want to present high-level points and reveal details when the disclosure is expanded.
|
34
|
-
|
35
|
-
<details>
|
36
|
-
<summary>This is a disclosure widget</summary>
|
37
|
-
<p style="background-color:lightgreen;padding:8px">This is a fascinating piece of information which is revealed when the widget is expanded.</p>
|
38
|
-
</details>
|
39
|
-
|
40
|
-
### Runnable examples
|
41
|
-
|
42
|
-
Topics also sometimes contain runnable examples. These are shown as tab panels with Source and Preview tabs.
|
43
|
-
|
44
|
-
You can also launch the preview in a window by going to the Preview tab, then clicking on the little window
|
45
|
-
icon on the right <span class="far fa-xs fa-window-maximize"></span>. This web site is a Neo.mjs application,
|
46
|
-
and the ability to launch browser windows — all integrated within a single app — is a unique feature of Neo.mjs!
|
47
|
-
|
48
|
-
<pre data-neo>
|
49
|
-
import Button from '../button/Base.mjs';
|
50
|
-
import Container from '../container/Base.mjs';
|
51
|
-
|
52
|
-
class MainView extends Container {
|
53
|
-
static config = {
|
54
|
-
className: 'Example.view.MainView',
|
55
|
-
layout : {ntype:'vbox', align:'start'},
|
56
|
-
items : [{
|
57
|
-
module : Button,
|
58
|
-
text : 'Button'
|
59
|
-
}]
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
MainView = Neo.setupClass(MainView);
|
64
|
-
</pre>
|