@lightningjs/blits 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/docs/_sidebar.md +3 -0
- package/docs/router/basics.md +98 -0
- package/docs/router/hooks.md +70 -0
- package/docs/router/transitions.md +146 -0
- package/docs/sidebar.json +13 -0
- package/package.json +2 -2
- package/src/lib/codegenerator/generator.js +9 -1
- package/src/lib/codegenerator/generator.test.js +176 -0
package/CHANGELOG.md
CHANGED
package/docs/_sidebar.md
CHANGED
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
- [Directives](/built-in/directives.md)
|
|
25
25
|
- [For loop](/built-in/for-loop.md)
|
|
26
26
|
- [Layout](/built-in/layout.md)
|
|
27
|
+
- Router
|
|
28
|
+
- [Basics](/router/basics.md)
|
|
29
|
+
- [Hooks](/router/hooks.md)
|
|
27
30
|
- Plugins
|
|
28
31
|
- [Text-to-Speech / Announcer](/plugins/text-to-speech-announcer.md)
|
|
29
32
|
- [Language](/plugins/language.md)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Router Basics
|
|
2
|
+
|
|
3
|
+
The Blits framework comes with a built-in, performant router that eliminates the need to pull in any additional dependencies into your App.
|
|
4
|
+
|
|
5
|
+
Before we dive into the details, let's first touch base on some key concepts.
|
|
6
|
+
|
|
7
|
+
## Key concepts
|
|
8
|
+
|
|
9
|
+
### Pages are regular Blits Components
|
|
10
|
+
|
|
11
|
+
The router in Blits is primarily used to navigate between Pages in your App. In the context of a Blits App, a Page is just a regular Blits Component. Usually it will be a Component that fills the entire screen. But it is also possible to have only a smaller portion of the screen contain dynamic routed content.
|
|
12
|
+
|
|
13
|
+
### URL hash
|
|
14
|
+
|
|
15
|
+
When navigating to a page, the hash in the URL of the browser will automatically be updated (i.e. `http://localhost:8080/#my/page`) to match the current page. The hash can also be used to _deep-link_ directly into your application. Upon first load, the router functionality will evaluate the URL hash and try to match that to a defined route. If a matching route is found, it will load that page as deep linked content.
|
|
16
|
+
|
|
17
|
+
## Defining Routes
|
|
18
|
+
|
|
19
|
+
Routes are defined in the main Application component, as an Array under the `routes` key of the configuration object.
|
|
20
|
+
|
|
21
|
+
Each route in this array, is an Object literal that includes the following key properties:
|
|
22
|
+
|
|
23
|
+
- `path` - the url hash to the route (i.e. `/my/page`)
|
|
24
|
+
- `component` - the Blits component to render for the route. This can be a direct reference, but also a promise or a dynamic import that resolves to a Blits component
|
|
25
|
+
- `hooks` (optional) - hooks such as `before` can be defined to execute code before navigating to the route
|
|
26
|
+
- `options` (optional) - additional options defining route behaviour, such as `keepAlive` and `inHistory`
|
|
27
|
+
- `transitions` (optional) - used to define custom transitions between pages
|
|
28
|
+
|
|
29
|
+
### Dynamic routes with params
|
|
30
|
+
|
|
31
|
+
Besides static routes such as `/account` and `/settings/wifi/advanced`, the Blits router also supports dynamic routes where URI parts can contain params.
|
|
32
|
+
|
|
33
|
+
To define a param in a route path prefix a string with a colon (`:`), followed by the name of the param, e.g. `/movies/:genre/:id`. This route path will match a URI hash such as `#/movies/sci-fi/65281918`. The router will take the params and inject them as a `prop` into the Page that's being navigated to.
|
|
34
|
+
|
|
35
|
+
To access these props in the Page component, they must first be defined in the Component first (i.e. `props: ['genre', 'id']`). Once defined, the values (`sci-fi` and `65281918`) in this case, will be available on the `this` scope, as with any regular Component.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Router view
|
|
39
|
+
|
|
40
|
+
The routes are loaded into a `<RouterView />` component, which acts as a placeholder for the routed Page components.
|
|
41
|
+
|
|
42
|
+
The `<RouterView />` component can be positioned and sized as you would expect from a normal Blits Component.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
export default Blits.Application({
|
|
47
|
+
template: `
|
|
48
|
+
<Element>
|
|
49
|
+
<RouterView x="300" y="200" w="1520" h="680" />
|
|
50
|
+
</Element>
|
|
51
|
+
`,
|
|
52
|
+
routes: [
|
|
53
|
+
{ path: '/', component: Home },
|
|
54
|
+
{ path: '/details', component: () => import('./pages/Details.js'), },
|
|
55
|
+
{ path: '/account',
|
|
56
|
+
component: () => {
|
|
57
|
+
// imagine this is an API call or some other async action
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
resolve(Account)
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
// ...
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Navigation
|
|
69
|
+
|
|
70
|
+
Each component in a routed Blits app has a `this.$router` object that provides access to the Router instance. It can be used to programmatically navigate to pages, by calling the `to()` method on it.
|
|
71
|
+
|
|
72
|
+
The `this.$router.to()`-methods accepts 3 arguments:
|
|
73
|
+
|
|
74
|
+
- `path` - the path of the route to navigate to
|
|
75
|
+
- `data` (optional) - an object with data to pass into the page as `props`
|
|
76
|
+
- `options` (optional) - additional options defining route behaviour, such as `keepAlive` and `inHistory` (these will overwrite any options specified for a route in the routes array)
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
export default Blits.Component('Poster', {
|
|
80
|
+
input: {
|
|
81
|
+
enter() {
|
|
82
|
+
this.$router.to('/movie/details', {id: '1', img: 'details.png'}, {inHistory: false})
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Whenever you navigate to a new page, the URL hash will automatically be updated. Unless specified otherwise, navigating to a new page, will add that route to the history stack. The `back` input action is automatically wired up to navigate back down the history stack.
|
|
89
|
+
|
|
90
|
+
## Router API
|
|
91
|
+
|
|
92
|
+
The Router API provides several useful methods and properties for managing routes and navigation:
|
|
93
|
+
|
|
94
|
+
- `this.$router.to()` - navigating to a different location (as discussed above)
|
|
95
|
+
- `this.$router.back()` - programmatically navigate back down the history stack
|
|
96
|
+
- `this.$router.currentRoute` - retrieve the current route
|
|
97
|
+
- `this.$router.routes` - retrieve the list of all routes
|
|
98
|
+
- `this.$router.navigating` - retrieve the current navigating state
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Router Hooks
|
|
2
|
+
|
|
3
|
+
The Blits router supports hooks that allow you to execute code at specific points during the navigation process.
|
|
4
|
+
|
|
5
|
+
Hooks are defined per route in the optional `hooks` key within the Route configuration object.
|
|
6
|
+
|
|
7
|
+
> Currently, the Blits router only supports the before hook, with additional hooks planned for future releases.
|
|
8
|
+
|
|
9
|
+
## Before hook
|
|
10
|
+
|
|
11
|
+
The before hook is executed before the navigation occurs. It can be used for checks, such as verifying user authentication for a specific route, for pre-fetching data, or for executing logic like sending stats beacons.
|
|
12
|
+
|
|
13
|
+
The before hook is defined as a function that receives 2 arguments: the Route object that is being navigated `to`. And the Route object that is being navigated away `from`.
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
export default Blits.Application({
|
|
17
|
+
// ...
|
|
18
|
+
routes: [
|
|
19
|
+
{
|
|
20
|
+
path: '/',
|
|
21
|
+
component: Home,
|
|
22
|
+
hooks: {
|
|
23
|
+
before(to, from) {
|
|
24
|
+
// custom logic
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
// ...
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The before hook can optionally return a value, which will influence the behaviour of the route change:
|
|
34
|
+
|
|
35
|
+
- when `false` is returned, the router will fail to finish the routing, and act as if _no matching route was found_
|
|
36
|
+
- when a `string` is returned, the router will interpret this a _new route path to redirect to_
|
|
37
|
+
- when an `object` is returned, the router will interpret this as a route object, allowing to _modify (or completely replace) the route object_ being navigated to
|
|
38
|
+
|
|
39
|
+
Returning an `object` is a simple, yet powerful, mechanism to add advanced runtime configuration to your routes. A common scenario is to overwrite certain parts of the route object provided in the `to`-argument, such as the route options (such as `inHistory` or `stayAlive`) or define conditional page transitions.
|
|
40
|
+
|
|
41
|
+
It's also possible to add custom data to the route object in the `key` object. Custom data should be an object literal. When the new page loads, the keys in the `data` object are injected into the Component as `props`.
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
export default Blits.Application({
|
|
45
|
+
// ...
|
|
46
|
+
routes: [
|
|
47
|
+
{
|
|
48
|
+
path: '/video/details/:id',
|
|
49
|
+
component: Details,
|
|
50
|
+
hooks: {
|
|
51
|
+
before(to, from) {
|
|
52
|
+
// redirect to an error page when id is not a number
|
|
53
|
+
if(isNaN(to.params.id)) {
|
|
54
|
+
return '/not-valid'
|
|
55
|
+
}
|
|
56
|
+
// set a different transition when navigating from home page
|
|
57
|
+
if(from && from.path === '/home') {
|
|
58
|
+
to.transition = slideInTransition
|
|
59
|
+
}
|
|
60
|
+
// add custom data
|
|
61
|
+
to.data.title = 'Hello World'
|
|
62
|
+
// finally return the modified route object
|
|
63
|
+
return to
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
// ...
|
|
69
|
+
})
|
|
70
|
+
```
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Router Transitions
|
|
2
|
+
|
|
3
|
+
Page transitions add a layer of visual polish to your application by animating the change between routes.
|
|
4
|
+
|
|
5
|
+
When the router in Blits navigates to a new page, it automatically applies a subtle _fade-in / fade-out_ transition. Blits also allows to specify custom transitions on a per-route basis.
|
|
6
|
+
|
|
7
|
+
## Defining Route Transitions
|
|
8
|
+
|
|
9
|
+
In the Route object, the `transition` key can be used to specify which transition should be applied when navigating _to_ that route.
|
|
10
|
+
|
|
11
|
+
It accepts a _Transition_ object, with 3 optional keys: `before`, `in`, `out`.
|
|
12
|
+
|
|
13
|
+
### Before
|
|
14
|
+
|
|
15
|
+
The `before` key is used to set a property to a certain value _before_ the page transition starts. The properties are set on the page that is being navigated _to_. For example, it can be used to position the page out of screen by setting the `x` value to a negative value, in order to create a _slide in from the right_ effect. Or the `alpha` property can be set to `0` if you want to create a _fade-in_ effect.
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
const pageTransition = {
|
|
19
|
+
// position the new page outside the screen on the left side
|
|
20
|
+
before: {
|
|
21
|
+
prop: 'x',
|
|
22
|
+
value: -1920
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
In order to set multiple properties to an initial state, an Array of objects can be assigned to the `before` key.
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
const pageTransition = {
|
|
31
|
+
// position the new page outside the screen on the left side
|
|
32
|
+
// and set the alpha to 0
|
|
33
|
+
before: [{
|
|
34
|
+
prop: 'x',
|
|
35
|
+
value: -1920
|
|
36
|
+
},{
|
|
37
|
+
prop: 'alpha',
|
|
38
|
+
value: 0
|
|
39
|
+
}]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### In
|
|
44
|
+
|
|
45
|
+
The `in`-key is used to define how the new page should transition _into_ the screen, given the initial defaults, in combination with any properties set in the optional `before` key.
|
|
46
|
+
|
|
47
|
+
The transition is defined by a _Transition_ object, consisting of:
|
|
48
|
+
|
|
49
|
+
- `prop` - the property to apply the transition on
|
|
50
|
+
- `value` - the value to transition to
|
|
51
|
+
- `duration` (optional) - the duration of the transition in milliseconds (defaults to `300ms`)
|
|
52
|
+
- `easing` (optional) - the easing function applied to the transition (defaults to `ease-in`)
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
const pageTransition = {
|
|
56
|
+
// position the new page outside the screen on the left side
|
|
57
|
+
before: {
|
|
58
|
+
prop: 'x',
|
|
59
|
+
value: -1920
|
|
60
|
+
},
|
|
61
|
+
// transition the new page from outside, into the screen
|
|
62
|
+
in: {
|
|
63
|
+
prop: 'x',
|
|
64
|
+
value: 0,
|
|
65
|
+
duration: 800,
|
|
66
|
+
easing: 'cubic-bezier(0.20, 1.00, 0.80, 1.00)'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
In order to transition multiple properties, an Array of objects can be assigned to the `in` key.
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
const pageTransition = {
|
|
75
|
+
// position the new page outside the screen on the left side
|
|
76
|
+
// and set the alpha to 0
|
|
77
|
+
before: [{
|
|
78
|
+
prop: 'x',
|
|
79
|
+
value: -1920
|
|
80
|
+
},{
|
|
81
|
+
prop: 'alpha',
|
|
82
|
+
value: 0
|
|
83
|
+
}],
|
|
84
|
+
// transition the new page from outside, into the screen
|
|
85
|
+
// and transition the alpha from 0 to 1
|
|
86
|
+
in: [{
|
|
87
|
+
prop: 'x',
|
|
88
|
+
value: 0,
|
|
89
|
+
duration: 800,
|
|
90
|
+
easing: 'cubic-bezier(0.20, 1.00, 0.80, 1.00)'
|
|
91
|
+
},{
|
|
92
|
+
prop: 'alpha',
|
|
93
|
+
value: 1,
|
|
94
|
+
duration: 500,
|
|
95
|
+
}]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Out
|
|
100
|
+
|
|
101
|
+
Finally the `out`-key is used to define how the old page should transition _out of_ the screen.
|
|
102
|
+
|
|
103
|
+
Similar to the `in`-transition, the `out`-transition is defined by a _Transition object_, consisting of:
|
|
104
|
+
|
|
105
|
+
- `prop` - the property to apply the transition on
|
|
106
|
+
- `value` - the value to transition to
|
|
107
|
+
- `duration` (optional) - the duration of the transition in milliseconds (defaults to `300ms`)
|
|
108
|
+
- `easing` (optional) - the easing function applied to the transition (defaults to `ease-in`)
|
|
109
|
+
|
|
110
|
+
And in order to transition multiple properties at the same time during the _out_ transition, an Array of transition objects can be supplied.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
const pageTransition = {
|
|
115
|
+
// position the new page outside the screen on the left side
|
|
116
|
+
// and set the alpha to 0
|
|
117
|
+
before: [{
|
|
118
|
+
prop: 'x',
|
|
119
|
+
value: -1920
|
|
120
|
+
},{
|
|
121
|
+
prop: 'alpha',
|
|
122
|
+
value: 0
|
|
123
|
+
}],
|
|
124
|
+
// transition the new page from outside, into the screen
|
|
125
|
+
// and transition the alpha from 0 to 1
|
|
126
|
+
in: [{
|
|
127
|
+
prop: 'x',
|
|
128
|
+
value: 0,
|
|
129
|
+
duration: 800,
|
|
130
|
+
easing: 'cubic-bezier(0.20, 1.00, 0.80, 1.00)'
|
|
131
|
+
},{
|
|
132
|
+
prop: 'alpha',
|
|
133
|
+
value: 1,
|
|
134
|
+
duration: 500,
|
|
135
|
+
}],
|
|
136
|
+
// slide up the old page
|
|
137
|
+
// while rotating
|
|
138
|
+
out: [{
|
|
139
|
+
prop: 'y',
|
|
140
|
+
value: -1080
|
|
141
|
+
},{
|
|
142
|
+
prop: 'rotate',
|
|
143
|
+
value: 720
|
|
144
|
+
}]
|
|
145
|
+
}
|
|
146
|
+
```
|
package/docs/sidebar.json
CHANGED
|
@@ -108,6 +108,19 @@
|
|
|
108
108
|
}
|
|
109
109
|
]
|
|
110
110
|
},
|
|
111
|
+
{
|
|
112
|
+
"text": "Router",
|
|
113
|
+
"items": [
|
|
114
|
+
{
|
|
115
|
+
"text": "Basics",
|
|
116
|
+
"link": "/router/basics"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"text": "Hooks",
|
|
120
|
+
"link": "/router/hooks"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
},
|
|
111
124
|
{
|
|
112
125
|
"text": "Plugins",
|
|
113
126
|
"items": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightningjs/blits",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@lightningjs/msdf-generator": "^1.1.0",
|
|
53
|
-
"@lightningjs/renderer": "^2.
|
|
53
|
+
"@lightningjs/renderer": "^2.7.1"
|
|
54
54
|
},
|
|
55
55
|
"repository": {
|
|
56
56
|
"type": "git",
|
|
@@ -442,10 +442,18 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
442
442
|
|
|
443
443
|
// inject the destroy code in the correct spot
|
|
444
444
|
ctx.renderCode.splice(indexToInjectDestroyCode, 0, ...destroyCode)
|
|
445
|
+
|
|
446
|
+
let effectKey = `${interpolate(result[2], '')}`
|
|
447
|
+
|
|
448
|
+
// Get the last property from nested path
|
|
449
|
+
if (effectKey && effectKey.includes('.')) {
|
|
450
|
+
effectKey = effectKey.match(/[^.]+$/)[0]
|
|
451
|
+
}
|
|
452
|
+
|
|
445
453
|
ctx.renderCode.push(`
|
|
446
454
|
effect(() => {
|
|
447
455
|
forloop${forStartCounter}(${cast(result[2], ':for')}, elms, created${forStartCounter})
|
|
448
|
-
}, '${
|
|
456
|
+
}, '${effectKey}' )
|
|
449
457
|
`)
|
|
450
458
|
|
|
451
459
|
outerScopeEffects.forEach((effect) => {
|
|
@@ -2055,6 +2055,182 @@ test('Generate code for a template with a simple for-loop on an Element', (asser
|
|
|
2055
2055
|
assert.end()
|
|
2056
2056
|
})
|
|
2057
2057
|
|
|
2058
|
+
test('Generate code for a template with a simple for-loop on an Element, Using data from appState plugin', (assert) => {
|
|
2059
|
+
const templateObject = {
|
|
2060
|
+
children: [
|
|
2061
|
+
{
|
|
2062
|
+
[Symbol.for('componentType')]: 'Element',
|
|
2063
|
+
children: [
|
|
2064
|
+
{
|
|
2065
|
+
[Symbol.for('componentType')]: 'Element',
|
|
2066
|
+
':for': 'item in $$appState.list',
|
|
2067
|
+
},
|
|
2068
|
+
],
|
|
2069
|
+
},
|
|
2070
|
+
],
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
const expectedRender = `
|
|
2074
|
+
function anonymous(parent, component, context, components, effect, getRaw) {
|
|
2075
|
+
const elms = []
|
|
2076
|
+
let componentType
|
|
2077
|
+
const rootComponent = component
|
|
2078
|
+
let propData
|
|
2079
|
+
const elementConfig0 = {}
|
|
2080
|
+
elms[0] = this.element({ parent: parent || 'root' }, component)
|
|
2081
|
+
elms[0].populate(elementConfig0)
|
|
2082
|
+
parent = elms[0]
|
|
2083
|
+
const created1 = []
|
|
2084
|
+
const forloop1 = (collection = [], elms, created) => {
|
|
2085
|
+
const rawCollection = getRaw(collection)
|
|
2086
|
+
const keys = new Set()
|
|
2087
|
+
let l = rawCollection.length
|
|
2088
|
+
while (l--) {
|
|
2089
|
+
const item = rawCollection[l]
|
|
2090
|
+
const index = l
|
|
2091
|
+
keys.add('' + l)
|
|
2092
|
+
}
|
|
2093
|
+
let i = created.length
|
|
2094
|
+
while (i--) {
|
|
2095
|
+
if (keys.has(created[i]) === false) {
|
|
2096
|
+
const key = created[i]
|
|
2097
|
+
elms[1][key] && elms[1][key].destroy()
|
|
2098
|
+
delete elms[1][key]
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
created.length = 0
|
|
2102
|
+
const length = rawCollection.length
|
|
2103
|
+
for (let __index = 0; __index < length; __index++) {
|
|
2104
|
+
const scope = Object.create(component)
|
|
2105
|
+
parent = elms[0]
|
|
2106
|
+
scope['index'] = __index
|
|
2107
|
+
scope['item'] = rawCollection[__index]
|
|
2108
|
+
scope['key'] = '' + __index
|
|
2109
|
+
created.push(scope.key)
|
|
2110
|
+
parent = elms[0]
|
|
2111
|
+
if (elms[1] === undefined) {
|
|
2112
|
+
elms[1] = {}
|
|
2113
|
+
}
|
|
2114
|
+
const elementConfig1 = {}
|
|
2115
|
+
if (elms[1][scope.key] === undefined) {
|
|
2116
|
+
elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
|
|
2117
|
+
}
|
|
2118
|
+
if (elms[1][scope.key].nodeId === undefined) {
|
|
2119
|
+
elms[1][scope.key].populate(elementConfig1)
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
effect(() => {
|
|
2124
|
+
forloop1(component.$appState.list, elms, created1)
|
|
2125
|
+
}, 'list')
|
|
2126
|
+
return elms
|
|
2127
|
+
}
|
|
2128
|
+
`
|
|
2129
|
+
|
|
2130
|
+
const actual = generator.call(scope, templateObject)
|
|
2131
|
+
|
|
2132
|
+
assert.equal(
|
|
2133
|
+
normalize(actual.render.toString()),
|
|
2134
|
+
normalize(expectedRender),
|
|
2135
|
+
'Generator should return a render function with the correct code using data from appState plugin'
|
|
2136
|
+
)
|
|
2137
|
+
|
|
2138
|
+
assert.ok(
|
|
2139
|
+
Array.isArray(actual.effects) && actual.effects.length === 0,
|
|
2140
|
+
'Generator should return an empty effect array'
|
|
2141
|
+
)
|
|
2142
|
+
|
|
2143
|
+
assert.end()
|
|
2144
|
+
})
|
|
2145
|
+
|
|
2146
|
+
test('Generate code for a template with a simple for-loop on an Element, Using data from nested state property', (assert) => {
|
|
2147
|
+
const templateObject = {
|
|
2148
|
+
children: [
|
|
2149
|
+
{
|
|
2150
|
+
[Symbol.for('componentType')]: 'Element',
|
|
2151
|
+
children: [
|
|
2152
|
+
{
|
|
2153
|
+
[Symbol.for('componentType')]: 'Element',
|
|
2154
|
+
':for': 'item in $content.data',
|
|
2155
|
+
},
|
|
2156
|
+
],
|
|
2157
|
+
},
|
|
2158
|
+
],
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
const expectedRender = `
|
|
2162
|
+
function anonymous(parent, component, context, components, effect, getRaw) {
|
|
2163
|
+
const elms = []
|
|
2164
|
+
let componentType
|
|
2165
|
+
const rootComponent = component
|
|
2166
|
+
let propData
|
|
2167
|
+
const elementConfig0 = {}
|
|
2168
|
+
elms[0] = this.element({ parent: parent || 'root' }, component)
|
|
2169
|
+
elms[0].populate(elementConfig0)
|
|
2170
|
+
parent = elms[0]
|
|
2171
|
+
const created1 = []
|
|
2172
|
+
const forloop1 = (collection = [], elms, created) => {
|
|
2173
|
+
const rawCollection = getRaw(collection)
|
|
2174
|
+
const keys = new Set()
|
|
2175
|
+
let l = rawCollection.length
|
|
2176
|
+
while (l--) {
|
|
2177
|
+
const item = rawCollection[l]
|
|
2178
|
+
const index = l
|
|
2179
|
+
keys.add('' + l)
|
|
2180
|
+
}
|
|
2181
|
+
let i = created.length
|
|
2182
|
+
while (i--) {
|
|
2183
|
+
if (keys.has(created[i]) === false) {
|
|
2184
|
+
const key = created[i]
|
|
2185
|
+
elms[1][key] && elms[1][key].destroy()
|
|
2186
|
+
delete elms[1][key]
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
created.length = 0
|
|
2190
|
+
const length = rawCollection.length
|
|
2191
|
+
for (let __index = 0; __index < length; __index++) {
|
|
2192
|
+
const scope = Object.create(component)
|
|
2193
|
+
parent = elms[0]
|
|
2194
|
+
scope['index'] = __index
|
|
2195
|
+
scope['item'] = rawCollection[__index]
|
|
2196
|
+
scope['key'] = '' + __index
|
|
2197
|
+
created.push(scope.key)
|
|
2198
|
+
parent = elms[0]
|
|
2199
|
+
if (elms[1] === undefined) {
|
|
2200
|
+
elms[1] = {}
|
|
2201
|
+
}
|
|
2202
|
+
const elementConfig1 = {}
|
|
2203
|
+
if (elms[1][scope.key] === undefined) {
|
|
2204
|
+
elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
|
|
2205
|
+
}
|
|
2206
|
+
if (elms[1][scope.key].nodeId === undefined) {
|
|
2207
|
+
elms[1][scope.key].populate(elementConfig1)
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
effect(() => {
|
|
2212
|
+
forloop1(component.content.data, elms, created1)
|
|
2213
|
+
}, 'data')
|
|
2214
|
+
return elms
|
|
2215
|
+
}
|
|
2216
|
+
`
|
|
2217
|
+
|
|
2218
|
+
const actual = generator.call(scope, templateObject)
|
|
2219
|
+
|
|
2220
|
+
assert.equal(
|
|
2221
|
+
normalize(actual.render.toString()),
|
|
2222
|
+
normalize(expectedRender),
|
|
2223
|
+
'Generator should return a render function with the correct code using data from nested state property'
|
|
2224
|
+
)
|
|
2225
|
+
|
|
2226
|
+
assert.ok(
|
|
2227
|
+
Array.isArray(actual.effects) && actual.effects.length === 0,
|
|
2228
|
+
'Generator should return an empty effect array'
|
|
2229
|
+
)
|
|
2230
|
+
|
|
2231
|
+
assert.end()
|
|
2232
|
+
})
|
|
2233
|
+
|
|
2058
2234
|
test('Generate code for a template with a simple for-loop on an Element with a custom index key', (assert) => {
|
|
2059
2235
|
const templateObject = {
|
|
2060
2236
|
children: [
|