mol_view_tree2_lib 1.0.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/.nojekyll +0 -0
- package/README.md +608 -0
- package/node.audit.js +2 -0
- package/node.d.ts +1093 -0
- package/node.d.ts.map +1 -0
- package/node.deps.json +1 -0
- package/node.js +5346 -0
- package/node.js.map +1 -0
- package/node.meta.tree +44 -0
- package/node.mjs +5347 -0
- package/node.test.js +13456 -0
- package/node.test.js.map +1 -0
- package/package.json +152 -0
- package/test.html +11 -0
- package/web.audit.js +2 -0
- package/web.css +1 -0
- package/web.css.map +1 -0
- package/web.d.ts +1055 -0
- package/web.d.ts.map +1 -0
- package/web.deps.json +1 -0
- package/web.js +5181 -0
- package/web.js.map +1 -0
- package/web.meta.tree +44 -0
- package/web.mjs +5182 -0
- package/web.test.js +8193 -0
- package/web.test.js.map +1 -0
package/.nojekyll
ADDED
|
File without changes
|
package/README.md
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# $mol_view
|
|
2
|
+
|
|
3
|
+
The base class for all visual components. It provides the infrastructure for reactive lazy rendering, handling exceptions. By default it finds or creates a `div` without child node changing and additional attributes, fields and event handler creation. You can customize it by inheritance or properties overriding at instantiating.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
**`dom_name()' : string`**
|
|
8
|
+
|
|
9
|
+
Returns name of the DOM-element creating for component, if the element with appropriate id is not presented at DOM yet.
|
|
10
|
+
|
|
11
|
+
**`dom_name_space() = 'http://www.w3.org/1999/xhtml'`**
|
|
12
|
+
|
|
13
|
+
Returns namespaceURI for the DOM element.
|
|
14
|
+
|
|
15
|
+
**`sub() : Array< $mol_view | Node | string | number | boolean > = null `**
|
|
16
|
+
|
|
17
|
+
Returns list of child components/elements/primitives. If the list have not been set (by default), then the content of the DOM-element would not be changed in way, it's helpful for manual operating with DOM.
|
|
18
|
+
|
|
19
|
+
**`context( next? : $ ) : $`**
|
|
20
|
+
Some rendering context. Parent node injects context to all rendered child components.
|
|
21
|
+
|
|
22
|
+
**`minimal_height()` = 0**
|
|
23
|
+
|
|
24
|
+
Returns minimum possible height of the component. It's set by hand with constant or some expression.This property is used for lazy rendering.
|
|
25
|
+
|
|
26
|
+
**`dom_node() : Element`**
|
|
27
|
+
|
|
28
|
+
Returns DOM-element, to which the component is bounded to. At first the method tries to find the element by its id at DOM and only if it would have not been found - the method would create and remember a new one.
|
|
29
|
+
|
|
30
|
+
**`dom_tree() : Element`**
|
|
31
|
+
|
|
32
|
+
Same as `dom_node`, but its guarantee, that the content, attributes and properties of the DOM-element should be in actual state.
|
|
33
|
+
|
|
34
|
+
**`attr() : { [ key : string ] : string | number | boolean }`**
|
|
35
|
+
|
|
36
|
+
Returns the dictionary of the DOM-attributes, which values would be set while rendering. Passing `null` or `false` as the value to the attribute would lead to removing the attribute.
|
|
37
|
+
Passing `true` is an equivalent to passing its name as value. `undefined` is just ignored.
|
|
38
|
+
|
|
39
|
+
**`field() : { [ key : string ] : any }`**
|
|
40
|
+
|
|
41
|
+
Returns dictionary of fields, which is necessary to set to the DOM-element after rendering.
|
|
42
|
+
|
|
43
|
+
**`style() : { [ key : string ] : string | number }`**
|
|
44
|
+
|
|
45
|
+
Returns dictionary of styles. Numbers will be converted to string with "px" suffix.
|
|
46
|
+
|
|
47
|
+
**`event() : { [ key : string ] : ( event : Event )=> void }`**
|
|
48
|
+
|
|
49
|
+
Returns dictionary of event handlers. The event handlers are bind to the DOM-element one time, when the value is set to `dom_node` property. This handlers are synchronous and can be cancelled by ```preventDefault()```.
|
|
50
|
+
|
|
51
|
+
**`focused( next? : boolean ) : boolean`**
|
|
52
|
+
|
|
53
|
+
Determines, whether the component is focused or not at this time. If any inserted component would be focused, then its parent component would be focused also.
|
|
54
|
+
|
|
55
|
+
**`plugins() : Array< $mol_view > = null`**
|
|
56
|
+
|
|
57
|
+
Array of plugins. Plugin is a component which can be supplemented with the logic of the current components.
|
|
58
|
+
|
|
59
|
+
For example, list component with keyboard navigation (used `$mol_nav` plugin):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
<= Options $mol_list
|
|
63
|
+
plugins /
|
|
64
|
+
<= Nav $mol_nav
|
|
65
|
+
keys_y <= options /
|
|
66
|
+
rows <= options /
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## *.view.tree
|
|
70
|
+
|
|
71
|
+
*view.tree* - is a declarative language of describing components, based on [tree format](https://github.com/nin-jin/tree.d). One file can have multiple component definitions, but better to put every component in a separate file, except in very trivial cases.
|
|
72
|
+
To create a new component in `view.tree` file you must inherit it from any existing one or `$mol_view`.
|
|
73
|
+
Name of the component should begin with `$` and be unique globally accordance with principles presented on [MAM](https://github.com/eigenmethod/mam). For example, let's declare the component `$my_button` extended from `$mol_view`:
|
|
74
|
+
|
|
75
|
+
```tree
|
|
76
|
+
$my_button $mol_view
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
It translates to (every *.view.tree code would be translated to *.view.tree.ts):
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
namespace $ { export class $my_button extends $mol_view {} }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
When inheriting, it is possible to declare additional properties or overload existing ones (but the property type must match). For example, lets overload a `uri` property with `"https://example.org"` string, and `sub` - with array of one string `"Click me!"`, besides, lets declare a new property `target` with `"_top"` value by default (default value is necessary when declaring a new property):
|
|
86
|
+
|
|
87
|
+
```tree
|
|
88
|
+
$my_example $mol_link
|
|
89
|
+
uri \https://example.org
|
|
90
|
+
sub /
|
|
91
|
+
\Click me!
|
|
92
|
+
target \_top
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
namespace $ { export class $my_example extends $mol_link {
|
|
97
|
+
|
|
98
|
+
uri() { return "https://example.org" }
|
|
99
|
+
|
|
100
|
+
sub() { return [ "Click me!" ] }
|
|
101
|
+
|
|
102
|
+
target() { return "_top" }
|
|
103
|
+
} }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Note: For better readability, a single child node in a tree file is often written on a single line. You can expand all nodes in the previous example:
|
|
107
|
+
|
|
108
|
+
```tree
|
|
109
|
+
$my_example
|
|
110
|
+
$mol_link
|
|
111
|
+
uri
|
|
112
|
+
\https://example.org
|
|
113
|
+
sub
|
|
114
|
+
/
|
|
115
|
+
\Click me!
|
|
116
|
+
target
|
|
117
|
+
\_top
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Node where name starts with `$` - name of component.
|
|
121
|
+
Child nodes beginning with node `/` - list. You can set type of list, e.g `/number`, `/$mol_view` for better type checking.
|
|
122
|
+
Text after `\` - raw data which can contain entirely any data until the end of the line.
|
|
123
|
+
Node `@` marks string for extraction to separate `*.locale=en.json` file and used for i18n translation, e.g `@ \Values example`.
|
|
124
|
+
Numbers, booleans values and `null` is being wrote as it is, without any prefixes:
|
|
125
|
+
Nodes after `-` are ignored, you can use them for commenting and temporary disable subtree.
|
|
126
|
+
|
|
127
|
+
```tree
|
|
128
|
+
$my_values $mol_view
|
|
129
|
+
title @ \Values example
|
|
130
|
+
sub /
|
|
131
|
+
0
|
|
132
|
+
1.1
|
|
133
|
+
true
|
|
134
|
+
false
|
|
135
|
+
null
|
|
136
|
+
\I can contain any character! \("o")/
|
|
137
|
+
- I
|
|
138
|
+
am
|
|
139
|
+
remark...
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
namespace $ { export class $my_values extends $mol_view {
|
|
144
|
+
|
|
145
|
+
title() {
|
|
146
|
+
return this.$.$mol_locale.text( '$my_values_title' )
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
sub() {
|
|
150
|
+
return [ 0 , 1.1 , true , false , <any> null , "I can contain any character! \\(\"o\")/" ]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
} }
|
|
154
|
+
````
|
|
155
|
+
|
|
156
|
+
Dictionary (correspondence keys to their values) could be declared through a node `*` (you can use `^` to inherit pairs from superclass). For example, set DOM-element's attribute values:
|
|
157
|
+
|
|
158
|
+
```tree
|
|
159
|
+
$my_number $mol_view
|
|
160
|
+
dom_name \input
|
|
161
|
+
attr *
|
|
162
|
+
^
|
|
163
|
+
type \number
|
|
164
|
+
- attribute values must be a strings
|
|
165
|
+
min \0
|
|
166
|
+
max \20
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
namespace $ { export class $my_number extends $mol_view {
|
|
171
|
+
|
|
172
|
+
dom_name() { return "input" }
|
|
173
|
+
|
|
174
|
+
attr() {
|
|
175
|
+
return { ...super.attr() ,
|
|
176
|
+
"type" : "number" ,
|
|
177
|
+
"min" : "0" ,
|
|
178
|
+
"max" : "20" ,
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
To set a value for a DOM element's fields:
|
|
185
|
+
|
|
186
|
+
```tree
|
|
187
|
+
$my_scroll $mol_view
|
|
188
|
+
field *
|
|
189
|
+
^
|
|
190
|
+
scrollTop 0
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
namespace $ { export class $my_scroll extends $mol_view {
|
|
195
|
+
|
|
196
|
+
field() {
|
|
197
|
+
return { ...super.field() ,
|
|
198
|
+
"scrollTop" : 0 ,
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} }
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
To set styles:
|
|
205
|
+
|
|
206
|
+
```tree
|
|
207
|
+
$my_rotate $mol_view
|
|
208
|
+
style *
|
|
209
|
+
^
|
|
210
|
+
transform \rotate( 180deg )
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
namespace $ { export class $my_rotate extends $mol_view {
|
|
215
|
+
|
|
216
|
+
style() {
|
|
217
|
+
return { ...super.style() ,
|
|
218
|
+
"transform" : "rotate( 180deg )" ,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
As a value, we could cast not only constants, but also the contents of other properties through `<=` one-way binding. For example, let's declare two text properties `hint` and `text` and then use them for the `field` dictionary and `sub` list:
|
|
225
|
+
|
|
226
|
+
```tree
|
|
227
|
+
$my_hint $mol_view
|
|
228
|
+
hint \Default hint
|
|
229
|
+
text \Default text
|
|
230
|
+
field *
|
|
231
|
+
^
|
|
232
|
+
title <= hint -
|
|
233
|
+
sub /
|
|
234
|
+
<= text -
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
namespace $ { export class $my_hint extends $mol_view {
|
|
239
|
+
|
|
240
|
+
hint() { return "Default hint" }
|
|
241
|
+
|
|
242
|
+
text() { return "Default text" }
|
|
243
|
+
|
|
244
|
+
field() {
|
|
245
|
+
return { ...super.field() ,
|
|
246
|
+
"title" : this.hint() ,
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
sub() {
|
|
251
|
+
return [ this.text() ]
|
|
252
|
+
}
|
|
253
|
+
} }
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
It's often convenient to combine declaring a property and using it. The following example is exactly the same as the previous one:
|
|
257
|
+
|
|
258
|
+
```tree
|
|
259
|
+
$my_hint $mol_view
|
|
260
|
+
field *
|
|
261
|
+
^
|
|
262
|
+
title <= hint \Default hint
|
|
263
|
+
sub /
|
|
264
|
+
<= text \Default text
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Reactions on DOM-events are required for two-way binding. For example, lets point out, that objects of `click` event is necessary to put in `remove` property, which we declare right here and set it a default value `null`:
|
|
268
|
+
|
|
269
|
+
```tree
|
|
270
|
+
$my_remover $mol_view
|
|
271
|
+
event *
|
|
272
|
+
^
|
|
273
|
+
click? <=> remove? null
|
|
274
|
+
sub /
|
|
275
|
+
\Remove
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
namespace $ { export class $my_remover extends $mol_view {
|
|
280
|
+
|
|
281
|
+
@ $mol_mem
|
|
282
|
+
remove( next? : any ) {
|
|
283
|
+
return ( next !== undefinded ) ? next : null as any
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
event() {
|
|
287
|
+
return { ...super.event() ,
|
|
288
|
+
"click" : ( next? : any )=> this.remove( next ) ,
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
sub() {
|
|
293
|
+
return [ "Remove" ]
|
|
294
|
+
}
|
|
295
|
+
} }
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
You can declare an instance of another class as a value directly. The following example declares a `List` property with the value of instance `$mol_list_demo_tree` and then places it in a list of `sub` child components:
|
|
299
|
+
|
|
300
|
+
```tree
|
|
301
|
+
$my_app $mol_view
|
|
302
|
+
List $mol_list_demo_tree
|
|
303
|
+
sub /
|
|
304
|
+
<= List -
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
namespace $ { export class $my_app extends $mol_view {
|
|
309
|
+
|
|
310
|
+
@ $mol_mem
|
|
311
|
+
List() {
|
|
312
|
+
const obj = new $mol_list_demo_tree
|
|
313
|
+
return obj
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
sub() {
|
|
317
|
+
return [ this.List() ]
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
} }
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Properties of a nested component can be overloaded, below overloaded `title` and `content` properties of `$mol_label` component:
|
|
324
|
+
|
|
325
|
+
```tree
|
|
326
|
+
$my_name $mol_view
|
|
327
|
+
sub /
|
|
328
|
+
<= Info $mol_label
|
|
329
|
+
title \Name
|
|
330
|
+
content \Jin
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
namespace $ { export class $my_name extends $mol_view {
|
|
335
|
+
|
|
336
|
+
@ $mol_mem
|
|
337
|
+
Info() {
|
|
338
|
+
const obj = new $mol_label
|
|
339
|
+
obj.title = () => "Name"
|
|
340
|
+
obj.content = () => "Jin"
|
|
341
|
+
return obj
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
sub() {
|
|
345
|
+
return [ this.Info() ]
|
|
346
|
+
}
|
|
347
|
+
} }
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Properties of parent and child components can be linked. In the following example, we declare a reactive `name` property and tell the `Input` child component to use the `name` property as its own `value` property, we also tell the `Output` child component that we want the `name` property to output inside that.
|
|
351
|
+
The `Input` and `Output` components are linked through the `name` parent property, and changing the value in the `Input` will also update the `Output`:
|
|
352
|
+
|
|
353
|
+
```tree
|
|
354
|
+
$my_greeter $mol_view
|
|
355
|
+
sub /
|
|
356
|
+
<= Input $mol_string
|
|
357
|
+
hint \Name
|
|
358
|
+
value? <=> name? \
|
|
359
|
+
<= Output $mol_view
|
|
360
|
+
sub /
|
|
361
|
+
<= name? \
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
namespace $ { export class $my_greeter extends $mol_view {
|
|
366
|
+
|
|
367
|
+
@ $mol_mem
|
|
368
|
+
name( next? : any ) {
|
|
369
|
+
return ( next !== undefined ) ? next : ""
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
@ $mol_mem
|
|
373
|
+
Input() {
|
|
374
|
+
const obj = new $mol_string
|
|
375
|
+
obj.hint = () => "Name"
|
|
376
|
+
obj.value = ( next? : any ) => this.name( next )
|
|
377
|
+
return obj
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@ $mol_mem
|
|
381
|
+
Output() {
|
|
382
|
+
const obj = new $mol_view
|
|
383
|
+
obj.sub = () => [ this.name() ]
|
|
384
|
+
return obj
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
sub() {
|
|
388
|
+
return [ this.Input() , this.Output() ]
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
} }
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
`=>` - Right-side binding. It declares alias for property of subcomponent in declared component.
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
$my_app $mol_scroll
|
|
398
|
+
sub /
|
|
399
|
+
<= Page $mol_page
|
|
400
|
+
Title => Page_title -
|
|
401
|
+
head /
|
|
402
|
+
<= Back $mol_button_minor
|
|
403
|
+
title \Back
|
|
404
|
+
<= Page_title -
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
namespace $ {
|
|
409
|
+
export class $my_app extends $mol_scroll {
|
|
410
|
+
|
|
411
|
+
// sub / <= Page
|
|
412
|
+
sub() {
|
|
413
|
+
return [
|
|
414
|
+
this.Page()
|
|
415
|
+
] as readonly any[]
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Back $mol_button_minor title \Back
|
|
419
|
+
@ $mol_mem
|
|
420
|
+
Back() {
|
|
421
|
+
const obj = new this.$.$mol_button_minor()
|
|
422
|
+
|
|
423
|
+
obj.title = () => "Back"
|
|
424
|
+
|
|
425
|
+
return obj
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Page_title
|
|
429
|
+
Page_title() {
|
|
430
|
+
return this.Page().Title()
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Page $mol_page
|
|
434
|
+
// Title => Page_title
|
|
435
|
+
// head /
|
|
436
|
+
// <= Back
|
|
437
|
+
// <= Page_title
|
|
438
|
+
@ $mol_mem
|
|
439
|
+
Page() {
|
|
440
|
+
const obj = new this.$.$mol_page()
|
|
441
|
+
|
|
442
|
+
obj.head = () => [
|
|
443
|
+
this.Back(),
|
|
444
|
+
this.Page_title()
|
|
445
|
+
] as readonly any[]
|
|
446
|
+
|
|
447
|
+
return obj
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
There are certain properties that return different values depending on the key. A typical example of is a list of strings. Each row is a separate component, accessed by a unique key. The list of such properties has a `*` after the name:
|
|
454
|
+
|
|
455
|
+
```tree
|
|
456
|
+
$my_tasks $mol_list
|
|
457
|
+
sub <= task_rows /
|
|
458
|
+
Task_row* $mol_view
|
|
459
|
+
sub /
|
|
460
|
+
<= task_title* <= task_title_default \
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
namespace $ {
|
|
465
|
+
export class $my_tasks extends $mol_list {
|
|
466
|
+
|
|
467
|
+
// sub <= task_rows
|
|
468
|
+
sub() { return this.task_rows() }
|
|
469
|
+
|
|
470
|
+
// Task_row* $mol_view sub / <= task_title*
|
|
471
|
+
@ $mol_mem_key
|
|
472
|
+
Task_row(id: any) {
|
|
473
|
+
const obj = new this.$.$mol_view()
|
|
474
|
+
|
|
475
|
+
obj.sub = () => [
|
|
476
|
+
this.task_title(id)
|
|
477
|
+
] as readonly any[]
|
|
478
|
+
|
|
479
|
+
return obj
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// task_rows /
|
|
483
|
+
task_rows() { return [] as readonly any[] }
|
|
484
|
+
|
|
485
|
+
// task_title_default \
|
|
486
|
+
task_title_default() { return "" }
|
|
487
|
+
|
|
488
|
+
// task_title* <= task_title_default
|
|
489
|
+
task_title(id: any) { return this.task_title_default() }
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
In above example we declared the property `Task_row`, which takes on input some ID-key and returns an unique instance of `$mol_view` for every key.
|
|
495
|
+
`Task_row` has overloaded property `sub` that outputs appropriate `task_title` for every `Task_row` (`task_title` returns content of property `task_title_default`), which is equal to empty string initially.
|
|
496
|
+
Further, by overloading any of these properties, we can change any aspect of the component's behavior. You can override `task_rows` in a subclass to generate rows of your choice. For example":
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
task_rows() {
|
|
500
|
+
const rows = [] as $mol_view[]
|
|
501
|
+
for( let i = 0 ; i < 10 ; ++ i ) rows.push( this.Task_row( i ) )
|
|
502
|
+
return rows
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
task_title(id: any) {
|
|
506
|
+
return `Title - ${id}`
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Note: There is old way howto to use property with id. Instead of `*` you can write `!id`. E.g. instead of `task_title*` you can use `task_title!key`. You might find such usage in old examples, tutorials or old projects.
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
### All special chars
|
|
514
|
+
|
|
515
|
+
- `-` - remarks, ignored by code generation
|
|
516
|
+
- `$` - component name prefix, e.g `$mol_button`
|
|
517
|
+
- `/` - array, optionally you can set type of array, e.g `sub /number`
|
|
518
|
+
- `*` - dictionary (string keys, any values)
|
|
519
|
+
- `^` - return value of the same property from super class
|
|
520
|
+
- `\` - raw string, e.g. `message \Hello`
|
|
521
|
+
- `@` - localized string, e.g. `message @ \Hello world`
|
|
522
|
+
- `<=` - provides read-only property from owner to sub-componen
|
|
523
|
+
- `=>` - provides read-only property from sub-componen to owner
|
|
524
|
+
- `<=>` - fully replace sub component property by owner's one
|
|
525
|
+
- property + `*` or `!` - property takes ID as first argument, e.g. `Task_row* $mol_view`
|
|
526
|
+
- property + `?` - property can be changed by providing an additional optional argument, e.g. `value <=> name? \`
|
|
527
|
+
|
|
528
|
+
## view.ts
|
|
529
|
+
|
|
530
|
+
In addition to declarative description of component, next to it could be created a file of the same name with `view.ts` extension, where a behavior could be described. Using a special construction, it could be inherited from realization obtained of `view.tree` and it would be overloaded automatically by heir:
|
|
531
|
+
|
|
532
|
+
For example we have following description into `./my/hello/hello.view.tree`:
|
|
533
|
+
|
|
534
|
+
```tree
|
|
535
|
+
$my_hello $mol_view
|
|
536
|
+
sub /
|
|
537
|
+
<= Input $mol_string
|
|
538
|
+
hint \Name
|
|
539
|
+
value? <=> name? \
|
|
540
|
+
<= message \
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Here we have declared 2 properties: `name` to get the value from `Input` and `message` to output the value (we will override this property below).
|
|
544
|
+
It will be translated into following file `./my/hello/-view.tree/hello.view.tree.ts`:
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
namespace $ {
|
|
548
|
+
export class $my_hello extends $mol_view {
|
|
549
|
+
|
|
550
|
+
// sub /
|
|
551
|
+
// <= Input
|
|
552
|
+
// <= message
|
|
553
|
+
sub() {
|
|
554
|
+
return [
|
|
555
|
+
this.Input(),
|
|
556
|
+
this.message()
|
|
557
|
+
] as readonly any[]
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// name? \
|
|
561
|
+
@ $mol_mem
|
|
562
|
+
name(val?: any) {
|
|
563
|
+
if ( val !== undefined ) return val as never
|
|
564
|
+
return ""
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Input $mol_string
|
|
568
|
+
// hint \Name
|
|
569
|
+
// value? <=> name?
|
|
570
|
+
@ $mol_mem
|
|
571
|
+
Input() {
|
|
572
|
+
const obj = new this.$.$mol_string()
|
|
573
|
+
|
|
574
|
+
obj.hint = () => "Name"
|
|
575
|
+
obj.value = (val?: any) => this.name(val)
|
|
576
|
+
|
|
577
|
+
return obj
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// message \
|
|
581
|
+
message() { return "" }
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Now let's override the `message` method, which will use the `name` property in `./my/hello/hello.view.ts` behaivour file. `message` will depend on the `name` property entered by the user:
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
namespace $.$$ {
|
|
590
|
+
export class $my_hello extends $.$my_hello {
|
|
591
|
+
|
|
592
|
+
message() {
|
|
593
|
+
const name = this.name()
|
|
594
|
+
return name && `Hello, ${name}!`
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## IDE Support
|
|
602
|
+
|
|
603
|
+
* [Language Service for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=valikov.tree-language-service)
|
|
604
|
+
|
|
605
|
+
## Articles
|
|
606
|
+
|
|
607
|
+
* [View formats](https://github.com/eigenmethod/mol/wiki/View-formats) - Comparison of component description formats (tree, xml, json)
|
|
608
|
+
* [React'ивные Panel'и](https://habrahabr.ru/post/314752/) - JSX vs view.tree
|
package/node.audit.js
ADDED