29 |
30 | [#if it.isTrue]
31 | It is true.
32 | [#elseif it.isElseIf]
33 | It is else if.
34 | [#else]
35 | It is else.
36 | [/#if]
37 |
38 |
39 | [#for item, index in it.list]
40 | It is for loop {{index}}.
41 | [/#for]
42 |
43 | ```
44 |
45 | 插入值的标记是装大括号包裹住的部分,中间部分会解释称为运行的取值代码。
46 |
47 | if条件判读和for遍历都使用了比较特殊的节点方式,[#]这样的节点进行设计的。
48 |
49 | 这样设计的原因是把html语法判断使用节点的方式进行包裹,让作用域清晰,易于自定义语法拓展。
50 |
51 |
52 | ### 事件绑定
53 | ```html
54 |
(click)
55 |
on-click
56 | ```
57 | 这里有两种绑定事件的方式,一种是on-前缀,另一种是把事件名用()包裹起来。
58 |
59 | 事件绑定对应的值可以是一个函数对象,也可以是一个函数执行表达式。函数执行的时候,可以使用'$event'这个关键值传递Dom Event。
60 |
61 | 注意:
62 |
63 | 函数执行表达式是通过‘()’来判断的,所以这里不建议使用动态函数,而是使用上下文中的函数。
64 |
65 | ### 反向输出
66 | ```html
67 |
68 |
69 | ```
70 | 反向绑定将会在change和input事件的时候触发,读取当前Dom节点的属性,并且赋值给绑定的对象属性。就比如上面的例子,实际的运行代码会是这样的:
71 | ```javascript
72 | it.name = this.value
73 | it.file = this.file
74 | ```
75 |
76 | ### 双向绑定
77 | ```html
78 |
79 |
80 | ```
81 | 双向绑定其实是一种便捷解释,目前只能使用[(value)]这样的关键值,并且会在编译过程中被解释称为相对应的插值和反向绑定。
82 |
83 |
84 | ### child语法
85 | ```html
86 |
87 | [#child ./models/user, it.userContext]
88 |
89 | ```
90 | child 是引用子模板的语法,后面跟着的第一个参数是子模板的引用路径。
91 | 从第二个参数是初始化这个模板需要的上下文对象,这里可以是一个求值表达式;也可以不传递指定对象,这时会使用当前对象的上下文进行初始化。
92 |
93 | 通常情况下来说,child使用的模板的上下文应该在当前模板中始终取到一个固定的对象,而不应该是动态的。
94 |
95 |
96 | ### html语法
97 | ```html
98 |
99 | [#html]
100 | Hello {{it.name}}
101 | [/#html]
102 |
103 |
104 | [#html]
105 | Hello world.
106 | [/#html]
107 |
108 | ```
109 | html 使用时会将内容字符或者变量作为innerHTML赋值给对应的父节点,所以这个语法使用有很多限制:
110 | * 必须拥有父节点。
111 | * 父节点的nodeType必须是1,是一个element对象。
112 | * 没有兄弟节点,意味着父节点只有这一个子节点。
113 | * html 子内容会被当作字符串处理,只能做字符串判断,而不能进行复杂的逻辑处理。
114 |
115 |
116 | ## et.compile(source: string, options: Object)
117 | ### options.modules
118 |
119 | 编译结果的运行格式
120 |
121 | 可选参数: 'common', 'cmd', 'amd', 'global', 'angular'
122 |
123 | 默认值: 'common'
124 |
125 |
126 | ### options.depPath
127 |
128 | 编译结果的依赖对象的引用地址
129 |
130 | 默认值: 'et-dependency'
131 |
132 |
133 | ### options.moduleId
134 |
135 | 在 amd, global, angular 的模式下需要显示指定每个结果函数的地址命名
136 |
137 | 默认值: 'Tempalte'
138 |
139 |
140 |
141 | ## License
142 | MIT
143 |
--------------------------------------------------------------------------------
/design/attributes-with-expression/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 | var _dep_concatMatrix = _dep.concatMatrix;
8 | var _dep_concatMatrixOthers = _dep.concatMatrixOthers;
9 | var _dep_setAttributesCondition = _dep.setAttributesCondition;
10 | var _dep_updateAttr = _dep.updateAttr;
11 |
12 | var Template_0 = _dep_template(function(_template) {
13 | _dep_element(_template, 0, 1, 'DIV', [
14 | ['disabled', ''],
15 | ['class', 'class-true']
16 | ]);
17 | }, function (it, _args) {
18 | var _patches = [];
19 |
20 | var _conditions = [];
21 | if (it.isTrue) _conditions[0] = 0;
22 | _patches[0] = _conditions;
23 |
24 | _patches[1] = [it.id, it.getSrc()];
25 | _patches[2] = (function(){return it.a + it.b})();
26 |
27 | return _patches;
28 | }, function (_template, it, _args, _patches, _cache) {
29 | var _tmp = _patches[0];
30 | if (_cache(0, _tmp)) {
31 | var _includes = [];
32 | var _excludes = [];
33 |
34 | var _matrix0 = [['class']];
35 | _dep_concatMatrix(_includes, _matrix0, _tmp[0]);
36 | _dep_concatMatrixOthers(_excludes, _matrix0, _tmp[0]);
37 |
38 | _dep_setAttributesCondition(_template, 1, _includes, _excludes);
39 | }
40 |
41 | var _tmp = _patches[1];
42 | if (_cache(1, _tmp)) {
43 | var _value0 = _tmp[0];
44 | _value0 = util.format(_value0);
45 | var _value1 = _tmp[1];
46 | _dep_updateAttr(_template, 1, 'id', 'aaa' + _value0 + 'bbb' + _value1);
47 | }
48 |
49 | var _tmp = _patches[2];
50 | if (_cache(2, _tmp)) {
51 | _dep_updateAttr(_template, 1, 'data-type', _tmp);
52 | }
53 | });
54 |
55 | module.exports = Template_0;
56 |
--------------------------------------------------------------------------------
/design/attributes-with-expression/source.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/design/attributes/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 |
8 | var Template_0 = _dep_template(function (_template) {
9 | _dep_element(_template, 0, 1, 'DIV', [
10 | ['id', 'test'],
11 | ['data-title', 'Sorry, you can\'t do it.']
12 | ]);
13 | _dep_element(_template, 0, 2, 'BR');
14 | });
15 |
16 | module.exports = Template_0;
17 |
--------------------------------------------------------------------------------
/design/attributes/source.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/design/child/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var Template_2 = require('./models/user');
4 | var _dep = require('et-dependency');
5 |
6 | var _dep_template = _dep.template;
7 | var _dep_element = _dep.element;
8 | var _dep_child = _dep.child;
9 | var _dep_text = _dep.text;
10 |
11 | var Template_0 = _dep_template(function(_template) {
12 | _dep_element(_template, 0, 1, 'DIV');
13 | _dep_child(_template, 1, 2, Template_2, function (it, _args) {
14 | return it.userContext;
15 | });
16 | _dep_text(_template, 1, 3, '1234567890');
17 | });
18 |
19 | module.exports = Template_0;
20 |
--------------------------------------------------------------------------------
/design/child/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#child ./models/user, it.userContext]
3 | 1234567890
4 |
5 |
--------------------------------------------------------------------------------
/design/compile/amd/expect.js:
--------------------------------------------------------------------------------
1 | ;define('Template', ['et-dependency'], function(_dep) {
2 |
3 | var _dep_template = _dep.template;
4 | var _dep_element = _dep.element;
5 | var _dep_text = _dep.text;
6 |
7 | var Template_0 = _dep_template(function(_template) {
8 | _dep_element(_template, 0, 1, 'DIV');
9 | _dep_text(_template, 1, 2, 'test');
10 | });
11 |
12 | return Template_0;
13 | });
14 |
--------------------------------------------------------------------------------
/design/compile/amd/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "modules": "amd"
3 | }
4 |
--------------------------------------------------------------------------------
/design/compile/amd/source.html:
--------------------------------------------------------------------------------
1 |
test
2 |
--------------------------------------------------------------------------------
/design/compile/angular/expect.js:
--------------------------------------------------------------------------------
1 | angular.module('et.template').factory('Template', ['et-dependency', function(_dep) {
2 |
3 | var _dep_template = _dep.template;
4 | var _dep_element = _dep.element;
5 | var _dep_text = _dep.text;
6 |
7 | var Template_0 = _dep_template(function(_template) {
8 | _dep_element(_template, 0, 1, 'DIV');
9 | _dep_text(_template, 1, 2, 'test');
10 | });
11 |
12 | return function(option) {
13 | return new Template_0(option);
14 | }
15 | }]);
16 |
--------------------------------------------------------------------------------
/design/compile/angular/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "modules": "angular"
3 | }
4 |
--------------------------------------------------------------------------------
/design/compile/angular/source.html:
--------------------------------------------------------------------------------
1 |
test
2 |
--------------------------------------------------------------------------------
/design/compile/cmd/expect.js:
--------------------------------------------------------------------------------
1 | ;define(function(require, exports, module) {
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 | var _dep_text = _dep.text;
8 |
9 | var Template_0 = _dep_template(function(_template) {
10 | _dep_element(_template, 0, 1, 'DIV');
11 | _dep_text(_template, 1, 2, 'test');
12 | });
13 |
14 | module.exports = Template_0;
15 | });
16 |
--------------------------------------------------------------------------------
/design/compile/cmd/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "modules": "cmd"
3 | }
4 |
--------------------------------------------------------------------------------
/design/compile/cmd/source.html:
--------------------------------------------------------------------------------
1 |
test
2 |
--------------------------------------------------------------------------------
/design/compile/global/expect.js:
--------------------------------------------------------------------------------
1 | ;(function(global) {
2 | var _dep = global['et-dependency'];
3 |
4 | var _dep_template = _dep.template;
5 | var _dep_element = _dep.element;
6 | var _dep_text = _dep.text;
7 |
8 | var Template_0 = _dep_template(function(_template) {
9 | _dep_element(_template, 0, 1, 'DIV');
10 | _dep_text(_template, 1, 2, 'test');
11 | });
12 |
13 | global['Template'] = Template_0;
14 | })(window);
15 |
--------------------------------------------------------------------------------
/design/compile/global/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "modules": "global"
3 | }
4 |
--------------------------------------------------------------------------------
/design/compile/global/source.html:
--------------------------------------------------------------------------------
1 |
test
2 |
--------------------------------------------------------------------------------
/design/complex/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 | var _dep_eif = _dep.eif;
8 | var _dep_text = _dep.text;
9 | var _dep_efor = _dep.efor;
10 | var _dep_updateText = _dep.updateText;
11 |
12 | var Template_0 = _dep_template(function (_template) {
13 | _dep_element(_template, 0, 1, 'DIV', [
14 | ['id', 'content']
15 | ]);
16 | _dep_eif(_template, 1, 2, function (it, _args) {
17 | if (it.isTrue) return [0, Template_2];
18 | else return [1, Template_4];
19 | });
20 | _dep_element(_template, 1, 6, 'P');
21 | _dep_text(_template, 6, 7, 'It is P label.');
22 |
23 | _dep_efor(_template, 1, 8, Template_8, function (it, _args) {
24 | return it.matrix[it.members[1]];
25 | });
26 | });
27 |
28 | var Template_2 = _dep_template(function (_template) {
29 | _dep_text(_template, 2, 3, 'It is true.');
30 | });
31 |
32 | var Template_4 = _dep_template(function (_template) {
33 | _dep_text(_template, 4, 5, 'It is else.');
34 | });
35 |
36 | var Template_8 = _dep_template(function (_template) {
37 | _dep_text(_template, 8, 9);
38 | }, function (it, _args) {
39 | var item = _args[0];
40 | var index = _args[1];
41 |
42 | var _patches = [];
43 | _patches[0] = index;
44 | return _patches;
45 | }, function (_template, it, _args, _patches, _cache) {
46 | var item = _args[0];
47 | var index = _args[1];
48 |
49 | var _tmp = _patches[0];
50 | if (_cache(0, _tmp)) {
51 | _dep_updateText(_template, 9, 'it is for loop ' + _tmp);
52 | }
53 | });
54 |
55 | module.exports = Template_0;
56 |
--------------------------------------------------------------------------------
/design/complex/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#if it.isTrue]
3 | It is true.
4 | [#else]
5 | It is else.
6 | [/#if]
7 |
8 | It is P label.
9 |
10 | [#for item, index in it.matrix[it.members[1]]]
11 | it is for loop {{index}}
12 | [/#for]
13 |
14 |
--------------------------------------------------------------------------------
/design/event-bind/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 | var _dep_text = _dep.text;
8 |
9 | var Template_0 = _dep_template(function (_template) {
10 |
11 | _dep_element(_template, 0, 1, 'DIV');
12 |
13 | _dep_element(_template, 1, 2, 'A', 0, [
14 | ['click', function ($event, it, _args) {
15 | return it.onClick(it.getName(), item, $event, index);
16 | }]
17 | ]);
18 | _dep_text(_template, 2, 3, 'on-click');
19 |
20 | _dep_element(_template, 1, 4, 'A', 0, [
21 | ['click', function ($event, it, _args) {
22 | return it.onClick();
23 | }]
24 | ]);
25 | _dep_text(_template, 4, 5, '(click)');
26 | });
27 |
28 | module.exports = Template_0;
29 |
--------------------------------------------------------------------------------
/design/event-bind/source.html:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/design/for-and-if/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 | var _dep_efor = _dep.efor;
8 | var _dep_eif = _dep.eif;
9 | var _dep_text = _dep.text;
10 | var _dep_updateText = _dep.updateText;
11 |
12 | var Template_0 = _dep_template(function (_template) {
13 | _dep_element(_template, 0, 1, 'UL', [
14 | ['class', 'list']
15 | ]);
16 | _dep_efor(_template, 1, 2, Template_2, function (it, _args) {
17 | return it.list;
18 | });
19 | });
20 |
21 | var Template_2 = _dep_template(function (_template) {
22 | _dep_element(_template, 2, 3, 'LI', [
23 | ['class', 'item']
24 | ]);
25 | _dep_eif(_template, 3, 4, function (it, _args) {
26 | var item = _args[0];
27 | var index = _args[1];
28 | if (index === 0) return [0, Template_4];
29 | });
30 | _dep_text(_template, 3, 6);
31 | }, function (it, _args) {
32 | var item = _args[0];
33 | var index = _args[1];
34 |
35 | var _patches = [];
36 | _patches[0] = item;
37 | return _patches;
38 |
39 | }, function (_template, it, _args, _patches, _cache) {
40 | var item = _args[0];
41 | var index = _args[1];
42 |
43 | var _tmp = _patches[0];
44 | if (_cache(0, _tmp)) {
45 | _dep_updateText(_template, 6, _tmp);
46 | }
47 | });
48 |
49 | var Template_4 = _dep_template(function (_template) {
50 | _dep_text(_template, 4, 5, 'It is 0.');
51 | });
52 |
53 | module.exports = Template_0;
54 |
--------------------------------------------------------------------------------
/design/for-and-if/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#for item, index in it.list]
3 | -
4 | [#if index === 0]It is 0.[/#if]
5 | {{item}}
6 |
7 | [/#for]
8 |
9 |
--------------------------------------------------------------------------------
/design/for-for/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 | var _dep_template = _dep.template;
5 | var _dep_efor = _dep.efor;
6 | var _dep_text = _dep.text;
7 | var _dep_updateText = _dep.updateText;
8 |
9 | var Template_0 = _dep_template(function(_template) {
10 | _dep_efor(_template, 0, 1, Template_1, function(it, _args) {
11 | return it.matrix;
12 | });
13 | });
14 | var Template_1 = _dep_template(function(_template) {
15 | _dep_efor(_template, 1, 2, Template_2, function(it, _args) {
16 | var list = _args[0];
17 | var index1 = _args[1];
18 | return list;
19 | });
20 | });
21 | var Template_2 = _dep_template(function(_template) {
22 | _dep_text(_template, 2, 3);
23 | }, function (it, _args) {
24 | var list = _args[0];
25 | var index1 = _args[1];
26 | var item = _args[2];
27 | var index2 = _args[3];
28 |
29 | var _patches = [];
30 | _patches[0] = [index2, item];
31 | return _patches;
32 |
33 | }, function (_template, it, _args, _patches, _cache) {
34 | var list = _args[0];
35 | var index1 = _args[1];
36 | var item = _args[2];
37 | var index2 = _args[3];
38 |
39 | var _tmp = _patches[0];
40 | if (_cache(0, _tmp)) {
41 | var _value0 = _tmp[0];
42 | var _value1 = _tmp[1];
43 | _dep_updateText(_template, 3, 'It is for loop ' + _value0 + ':' + _value1 + '.');
44 | }
45 | });
46 | module.exports = Template_0;
--------------------------------------------------------------------------------
/design/for-for/source.html:
--------------------------------------------------------------------------------
1 | [#for list, index1 in it.matrix]
2 | [#for item, index2 in list]
3 | It is for loop {{index2}}:{{item}}.
4 | [/#for]
5 | [/#for]
6 |
--------------------------------------------------------------------------------
/design/for-track-by/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_efor = _dep.efor;
7 | var _dep_element = _dep.element;
8 | var _dep_text = _dep.text;
9 | var _dep_updateText = _dep.updateText;
10 |
11 | var Template_0 = _dep_template(function (_template) {
12 | _dep_efor(_template, 0, 1, Template_1, function (it, _args) {
13 | return it.users;
14 | }, function (it, _args) {
15 | var user = _args[0];
16 | var index = _args[1];
17 | return user.id;
18 | });
19 | });
20 |
21 | var Template_1 = _dep_template(function (_template) {
22 | _dep_element(_template, 1, 2, 'H1');
23 | _dep_text(_template, 2, 3);
24 | _dep_element(_template, 1, 4, 'P');
25 | _dep_text(_template, 4, 5);
26 |
27 | }, function (it, _args) {
28 | var user = _args[0];
29 | var index = _args[1];
30 |
31 | var _patches = [];
32 | _patches[0] = [user.id, user.name];
33 | _patches[1] = user.description;
34 | return _patches;
35 |
36 | }, function (_template, it, _args, _patches, _cache) {
37 | var user = _args[0];
38 | var index = _args[1];
39 |
40 | var _tmp = _patches[0];
41 | if (_cache(0, _tmp)) {
42 | var _value0 = _tmp[0];
43 | var _value1 = _tmp[1];
44 | _dep_updateText(_template, 3, _value0 + ': ' + _value1);
45 | }
46 |
47 | var _tmp = _patches[1];
48 | if (_cache(1, _tmp)) {
49 | _dep_updateText(_template, 5, _tmp);
50 | }
51 | });
52 |
53 | module.exports = Template_0;
54 |
--------------------------------------------------------------------------------
/design/for-track-by/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#for user, index in it.users track by user.id]
3 |
{{user.id}}: {{user.name}}
4 |
{{user.description}}
5 | [/#for]
6 |
--------------------------------------------------------------------------------
/design/for/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_efor = _dep.efor;
7 | var _dep_text = _dep.text;
8 | var _dep_updateText = _dep.updateText;
9 |
10 | var Template_0 = _dep_template(function (_template) {
11 | _dep_efor(_template, 0, 1, Template_1, function (it, _args) {
12 | return it.matrix[it.members[1]];
13 | }, function (it, _args) {
14 | var item = _args[0];
15 | var index = _args[1];
16 | return item.id;
17 | });
18 | });
19 |
20 | var Template_1 = _dep_template(function (_template) {
21 | _dep_text(_template, 1, 2);
22 |
23 | }, function (it, _args) {
24 | var item = _args[0];
25 | var index = _args[1];
26 |
27 | var _patches = [];
28 | _patches[0] = index;
29 | return _patches;
30 |
31 | }, function (_template, it, _args, _patches, _cache) {
32 | var item = _args[0];
33 | var index = _args[1];
34 |
35 | var _tmp = _patches[0];
36 | if (_cache(0, _tmp)) {
37 | _tmp = it.format(_tmp);
38 | _dep_updateText(_template, 2, 'it is for loop ' + _tmp);
39 | }
40 | });
41 |
42 | module.exports = Template_0;
43 |
--------------------------------------------------------------------------------
/design/for/source.html:
--------------------------------------------------------------------------------
1 | [#for item, index in it.matrix[it.members[1]] track by item.id]
2 | it is for loop {{index | it.format}}
3 | [/#for]
4 |
--------------------------------------------------------------------------------
/design/if-else/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 | var _dep_template = _dep.template;
5 | var _dep_element = _dep.element;
6 | var _dep_eif = _dep.eif;
7 | var _dep_text = _dep.text;
8 |
9 | var Template_0 = _dep_template(function (_template) {
10 | _dep_element(_template, 0, 1, 'DIV');
11 | _dep_eif(_template, 1, 2, function (it, _args) {
12 | if (it.isTrue) return [0, Template_2];
13 | else if (it.elseTrue) return [1, Template_4];
14 | else return [2, Template_6];
15 | });
16 | });
17 |
18 | var Template_2 = _dep_template(function (_template) {
19 | _dep_text(_template, 2, 3, 'It is true.');
20 | });
21 |
22 | var Template_4 = _dep_template(function (_template) {
23 | _dep_text(_template, 4, 5, 'It is elseTrue.');
24 | });
25 |
26 | var Template_6 = _dep_template(function (_template) {
27 | _dep_text(_template, 6, 7, 'It is else.');
28 | });
29 |
30 | module.exports = Template_0;
31 |
--------------------------------------------------------------------------------
/design/if-else/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#if it.isTrue]
3 | It is true.
4 | [#elseif it.elseTrue]
5 | It is elseTrue.
6 | [#else]
7 | It is else.
8 | [/#if]
9 |
10 |
--------------------------------------------------------------------------------
/design/if-with-siblings/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_text = _dep.text;
7 | var _dep_eif = _dep.eif;
8 |
9 | var Template_0 = _dep_template(function (_template) {
10 | _dep_text(_template, 0, 1, 'It is before.');
11 | _dep_eif(_template, 0, 2, function (it, _args) {
12 | if (it.isNumber && it.isEven) return [0, Template_2];
13 | });
14 | });
15 |
16 | var Template_2 = _dep_template(function (_template) {
17 | _dep_text(_template, 2, 3, 'It is number and is even');
18 | });
19 |
20 | module.exports = Template_0;
21 |
--------------------------------------------------------------------------------
/design/if-with-siblings/source.html:
--------------------------------------------------------------------------------
1 | It is before.
2 | [#if it.isNumber && it.isEven]
3 | It is number and is even
4 | [/#if]
5 |
--------------------------------------------------------------------------------
/design/import/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var util = require('./util');
4 | var util1 = require('./util1');
5 | var util2 = require('./util2');
6 | var _dep = require('et-dependency');
7 |
8 | var _dep_template = _dep.template;
9 | var _dep_element = _dep.element;
10 | var _dep_text = _dep.text;
11 | var _dep_updateText = _dep.updateText;
12 |
13 | var Template_0 = _dep_template(function (_template) {
14 | _dep_element(_template, 0, 4, 'A');
15 | _dep_text(_template, 4, 5);
16 |
17 | }, function (it, _args) {
18 | var _patches = [];
19 | _patches[0] = util.add(it.a, it.b);
20 | return _patches;
21 |
22 | }, function (_template, it, _args, _patches, _cache) {
23 | var _tmp = _patches[0];
24 | if (_cache(0, _tmp)) {
25 | _dep_updateText(_template, 5, _tmp);
26 | }
27 | });
28 |
29 | module.exports = Template_0;
30 |
--------------------------------------------------------------------------------
/design/import/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#import util from './util']
3 | [#import util1 from ./util1]
4 | [#import util2 from "./util2"]
5 |
6 |
{{util.add(it.a, it.b)}}
7 |
--------------------------------------------------------------------------------
/design/innerHTML/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 | var _dep_template = _dep.template;
5 | var _dep_element = _dep.element;
6 | var _dep_html = _dep.html;
7 |
8 | var Template_0 = _dep_template(function (_template) {
9 | _dep_element(_template, 0, 1, 'DIV');
10 |
11 | }, function (it, _args) {
12 | var _patches = [];
13 | _patches[0] = it.html;
14 | return _patches;
15 |
16 | }, function (_template, it, _args, _patches, _cache) {
17 | var _tmp = _patches[0];
18 | if (_cache(0, _tmp)) {
19 | _dep_html(_template, 1, '
aaa' + _tmp + 'bbb');
20 | }
21 | });
22 |
23 | module.exports = Template_0;
24 |
--------------------------------------------------------------------------------
/design/innerHTML/source.html:
--------------------------------------------------------------------------------
1 |
2 | [#html]
3 |
4 | aaa{{it.html}}bbb
5 | [/#html]
6 |
7 |
--------------------------------------------------------------------------------
/design/output/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 | var _dep_template = _dep.template;
5 | var _dep_element = _dep.element;
6 |
7 | var Template_0 = _dep_template(function (_template) {
8 | _dep_element(_template, 0, 1, 'DIV');
9 | _dep_element(_template, 1, 2, 'INPUT', [
10 | ['type', 'file']
11 | ], [
12 | ['change input', function ($event, it, _args) {
13 | it.file = this.file;
14 | it.value = this.value;
15 | }]
16 | ]);
17 | });
18 |
19 | module.exports = Template_0;
20 |
--------------------------------------------------------------------------------
/design/output/source.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/design/text-pipe/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var util = require('./util');
4 | var _dep = require('et-dependency');
5 |
6 | var _dep_template = _dep.template;
7 | var _dep_element = _dep.element;
8 | var _dep_text = _dep.text;
9 | var _dep_updateText = _dep.updateText;
10 |
11 | var Template_0 = _dep_template(function (_template) {
12 | _dep_element(_template, 0, 2, 'A');
13 | _dep_text(_template, 2, 3);
14 | }, function (it, _args) {
15 | var _patches = [];
16 | _patches[0] = it.isMe ? 'ME' : 'YOU | HE';
17 | return _patches;
18 |
19 | }, function (_template, it, _args, _patches, _cache) {
20 | var _tmp = _patches[0];
21 | if (_cache(0, _tmp)) {
22 | _tmp = util.format(_tmp);
23 | _tmp = util.trim(_tmp, ' | ', ' , ');
24 | _dep_updateText(_template, 3, _tmp);
25 | }
26 | });
27 |
28 | module.exports = Template_0;
29 |
--------------------------------------------------------------------------------
/design/text-pipe/source.html:
--------------------------------------------------------------------------------
1 | [#import util from './util']
2 |
3 |
{{it.isMe?'ME':'YOU | HE' | util.format | util.trim, ' | ', ' , '}}
4 |
--------------------------------------------------------------------------------
/design/text/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 |
5 | var _dep_template = _dep.template;
6 | var _dep_element = _dep.element;
7 | var _dep_text = _dep.text;
8 | var _dep_updateText = _dep.updateText;
9 |
10 | var Template_0 = _dep_template(function (_template) {
11 | _dep_element(_template, 0, 1, 'DIV');
12 | _dep_text(_template, 1, 2);
13 | _dep_element(_template, 0, 3, 'P');
14 | _dep_text(_template, 3, 4, 'Sorry, you can\'t do it.\n\n\n bbbbbbbbb');
15 | _dep_element(_template, 0, 5, 'P');
16 | _dep_text(_template, 5, 6);
17 |
18 | }, function (it, _args) {
19 | var _patches = [];
20 | _patches[0] = it.src;
21 | _patches[1] = it.unreadCount > 99 ? '99+' : it.unreadCount;
22 | return _patches;
23 |
24 | }, function (_template, it, _args, _patches, _cache) {
25 | var _tmp = _patches[0];
26 | if (_cache(0, _tmp)) {
27 | _dep_updateText(_template, 2, 'aaaa[' + _tmp + ']');
28 | }
29 |
30 | var _tmp = _patches[1];
31 | if (_cache(1, _tmp)) {
32 | _dep_updateText(_template, 6, _tmp);
33 | }
34 | });
35 |
36 | module.exports = Template_0;
37 |
--------------------------------------------------------------------------------
/design/text/source.html:
--------------------------------------------------------------------------------
1 |
2 | aaaa[{{it.src}}]
3 |
4 |
5 | Sorry, you can't do it.
6 |
7 |
8 | bbbbbbbbb
9 |
10 |
11 | {{it.unreadCount > 99 ? '99+' : it.unreadCount}}
12 |
13 |
--------------------------------------------------------------------------------
/design/two-way-bind/expect.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var _dep = require('et-dependency');
4 | var _dep_template = _dep.template;
5 | var _dep_element = _dep.element;
6 | var _dep_updateAttr = _dep.updateAttr;
7 |
8 | var Template_0 = _dep_template(function (_template) {
9 | _dep_element(_template, 0, 1, 'DIV');
10 | _dep_element(_template, 1, 2, 'INPUT', 0, [
11 | ['change input', function ($event, it, _args) {
12 | it.name = this.value;
13 | }]
14 | ]);
15 | }, function (it, _args) {
16 | var _patches = [];
17 | _patches[0] = it.name;
18 | return _patches;
19 |
20 | }, function (_template, it, _args, _patches, _cache) {
21 | var _tmp = _patches[0];
22 | if (_cache(0, _tmp)) {
23 | _dep_updateAttr(_template, 2, 'value', _tmp);
24 | }
25 | });
26 |
27 | module.exports = Template_0;
28 |
--------------------------------------------------------------------------------
/design/two-way-bind/source.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "et-template",
3 | "version": "0.4.0",
4 | "description": "A template for web.",
5 | "author": "suyu34",
6 | "repository": {
7 | "type": "git",
8 | "url": "git@github.com:et-studio/et-template.git"
9 | },
10 | "main": "./es5/et.js",
11 | "typings": "./typings/et-tempalte.d.ts",
12 | "scripts": {
13 | "setup": "typings install",
14 | "clean": "rm -rf es5",
15 | "lint": "standard && tslint src/**/*.ts",
16 | "start": "webpack-dev-server --content-base test/server/views --hot --progress",
17 | "prebuild": "npm run clean && npm run lint",
18 | "build": "tsc",
19 | "postbuild": "npm run test",
20 | "test": "mocha test/**/*_spec.js",
21 | "deploy": "npm run build && npm publish"
22 | },
23 | "engines": {
24 | "node": "4.0.x"
25 | },
26 | "dependencies": {
27 | "et-parser": "^0.1.8",
28 | "lodash": "^4.11.1"
29 | },
30 | "devDependencies": {
31 | "js-beautify": "^1.6.2",
32 | "mocha": "^2.4.5",
33 | "should": "^8.3.1",
34 | "standard": "^6.0.8",
35 | "ts-loader": "^0.8.2",
36 | "tslint": "^3.7.4",
37 | "typescript": "^1.8.10",
38 | "typings": "^0.7.12",
39 | "webpack": "^1.12.14",
40 | "webpack-dev-server": "^1.14.1"
41 | },
42 | "standard": {
43 | "ignore": [
44 | "design",
45 | "src-old"
46 | ]
47 | },
48 | "keywords": [
49 | "template",
50 | "et",
51 | "ET"
52 | ],
53 | "files": [
54 | "es5",
55 | "src",
56 | "typings/et-template.d.ts",
57 | "README.md"
58 | ],
59 | "license": "MIT"
60 | }
61 |
--------------------------------------------------------------------------------
/src/et.ts:
--------------------------------------------------------------------------------
1 |
2 | import {pick, extend} from 'lodash';
3 | import {parseOrigin} from './parsers'
4 | import {create as createNode} from './middlewares/node-creator'
5 | import {translate as translateAttributes} from './middlewares/attributes-translator'
6 | import {rebuild as rebuildNode} from './middlewares/node-rebuilder'
7 | import {check as checkNode} from './middlewares/node-checker'
8 | import {compile as compileNode} from './middlewares/node-compiler'
9 | import {format as formatResult} from './middlewares/node-formatter'
10 | import {eachNode} from './util'
11 |
12 | const PROP_LIST = ['modules', 'depName', 'depPath']
13 | const PROP_DEFAULT = {
14 | modules: 'common', // ['common', 'cmd', 'amd', 'global', 'angular']
15 | depName: '_dep',
16 | depPath: 'et-dependency',
17 | moduleId: 'Template'
18 | }
19 |
20 | export function compile (source: string, options: IOptions) {
21 | options = extend({}, PROP_DEFAULT, options)
22 |
23 | // parse string to origin node tree
24 | let origin = parseOrigin(source)
25 |
26 | // handle node tree
27 | let root = createNode(origin, options)
28 | eachNode(root, node => node.parse())
29 | root.addDependency(options.depName, options.depPath)
30 | root = translateAttributes(root)
31 | root = rebuildNode(root)
32 | root = checkNode(root)
33 |
34 | // handle string
35 | let result = compileNode(root, options)
36 | result = formatResult(result)
37 |
38 | return result
39 | }
40 |
--------------------------------------------------------------------------------
/src/middlewares/attributes-translator.ts:
--------------------------------------------------------------------------------
1 |
2 | import {eachNode} from '../util'
3 | import {ElementNode} from '../nodes/element'
4 |
5 | const TWO_WAY_KEY = '[(value)]'
6 | const EVENT_REG = /^\(([\s\S]*)\)$|^on-([\s\S]*)/
7 | const OUTPUT_REG = /^\[([\s\S]*)\]$/
8 | const METHOD_LEFT = '('
9 | const METHOD_RIGHT = ')'
10 | const EVENT_SPLIT = ','
11 |
12 | export function translate (last: INode) {
13 | eachNode(last, (node) => {
14 | if (node.nodeType === 1 && node instanceof ElementNode) {
15 | translateTwoWayBind(node)
16 | translateElementAttributes(node)
17 | }
18 | })
19 | return last
20 | }
21 |
22 | function translateTwoWayBind (element: ElementNode) {
23 | let attrs = element.attributes
24 | attrs.forEach((value, key) => {
25 | if (key === TWO_WAY_KEY) {
26 | attrs.delete(key)
27 | attrs.set('value', `{{${value}}}`)
28 | attrs.set('[value]', value)
29 | }
30 | })
31 | }
32 | function translateElementAttributes (element: ElementNode) {
33 | let attrs = element.attributes
34 | attrs.forEach((value, key) => {
35 | let eventName = getEventFromKey(key)
36 | let outputName = getOutputFromKey(key)
37 |
38 | if (eventName) {
39 | let event = parseEventFromExpression(value)
40 | element.addEvent(eventName, event.expression, event.args)
41 | attrs.delete(key)
42 | } else if (outputName) {
43 | element.addOutput(outputName, value)
44 | attrs.delete(key)
45 | }
46 | })
47 | }
48 |
49 | function getEventFromKey (key: string) {
50 | let matches = EVENT_REG.exec(key)
51 | // parse event like: on-click or (click)
52 | if (matches) {
53 | return matches[1] || matches[2] || null
54 | } else {
55 | return null
56 | }
57 | }
58 | function parseEventFromExpression (value: string) {
59 | let startIndex = value.indexOf(METHOD_LEFT)
60 | let endIndex = value.lastIndexOf(METHOD_RIGHT)
61 |
62 | if (!(startIndex < endIndex)) {
63 | return {expression: value, args: []}
64 | }
65 |
66 | let methodExprssion = value.substring(0, startIndex)
67 | let argsExpression = value.substring(startIndex + 1, endIndex)
68 | let args = []
69 | argsExpression.split(EVENT_SPLIT).map((item) => {
70 | let tmp = item.trim()
71 | if (tmp) args.push(tmp)
72 | })
73 | return {expression: methodExprssion, args}
74 | }
75 | function getOutputFromKey (key: string) {
76 | let matches = OUTPUT_REG.exec(key)
77 |
78 | if (matches) {
79 | return matches[1] || null
80 | } else {
81 | return null
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/middlewares/node-checker.ts:
--------------------------------------------------------------------------------
1 |
2 | import {eachNode} from '../util'
3 | import {HtmlNode} from '../nodes/html'
4 |
5 | export function check (node: INode) {
6 | eachNode(node, (item) => {
7 | if (item instanceof HtmlNode) {
8 | checkHtmlNode(item)
9 | }
10 | })
11 | return node
12 | }
13 |
14 | function checkHtmlNode (node: HtmlNode) {
15 | let message = ''
16 | if (!node.parent) {
17 | message = 'html node need a parent'
18 | }
19 | if (node.parent.nodeType !== 1) {
20 | message = 'the parent of html node should be element node'
21 | }
22 | if (node.parent.children.length > 1) {
23 | message = 'html node should not has siblings'
24 | }
25 | if (message) {
26 | throw new Error(message)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/middlewares/node-compiler.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as compiler from '../templates/compile'
3 |
4 | export function compile (root: INode, options: IOptions) {
5 | switch (options.modules) {
6 | case 'angular':
7 | return compiler.angular(root, options)
8 | case 'cmd':
9 | return compiler.cmd(root, options)
10 | case 'amd':
11 | return compiler.amd(root, options)
12 | case 'global':
13 | return compiler.global(root, options)
14 | default:
15 | return compiler.common(root, options)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/middlewares/node-creator.ts:
--------------------------------------------------------------------------------
1 |
2 | import {each} from 'lodash'
3 | import {BasicNode} from '../nodes/basic'
4 | import {createNode as createFromOrigin} from '../nodes/factory'
5 |
6 | export function create (last: IOriginNode, options: IOptions) {
7 | let index = 0
8 | function createNode (origin?: IOriginNode, isExpression?: boolean) {
9 | let result: BasicNode
10 | if (origin) {
11 | result = createFromOrigin(origin, options)
12 | if (!isExpression) result.setIndex(index++)
13 | } else {
14 | result = createFromOrigin(null, options)
15 | if (!isExpression) index++
16 | }
17 | return result
18 | }
19 | function createChildren (parent: INode, origin: IOriginNode) {
20 | each(origin.children, (child) => {
21 | let node = createNode(child)
22 | parent.append(node)
23 | createChildren(node, child)
24 | })
25 | each(origin.expressions, (item) => {
26 | let expNode = createNode(item, true)
27 | parent.expressions.push(expNode)
28 | createChildren(expNode, item)
29 | })
30 | return parent
31 | }
32 |
33 | let root = createNode()
34 | return createChildren(root, last)
35 | }
36 |
--------------------------------------------------------------------------------
/src/middlewares/node-formatter.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | const LINE_SPLIT = '\n'
4 |
5 | export function format (last: string) {
6 | removeComments('')
7 | return last
8 | }
9 | function removeComments (content: string) {
10 | let list = content.split(LINE_SPLIT)
11 | let results = []
12 | for (let i = 0, len = list.length; i < len; i++) {
13 | let item = list[i].trim()
14 | if (item.indexOf('//') !== 0) results.push(item)
15 | }
16 | return results.join(LINE_SPLIT)
17 | }
18 |
--------------------------------------------------------------------------------
/src/middlewares/node-rebuilder.ts:
--------------------------------------------------------------------------------
1 |
2 | import {clone, each} from 'lodash'
3 | import {eachNode} from '../util'
4 | import {IfNode} from '../nodes/if'
5 | import {ElseIfNode} from '../nodes/elseif'
6 | import {ElseNode} from '../nodes/else'
7 |
8 | export function rebuild (node: INode) {
9 | eachNode(node, (item) => {
10 | if (item instanceof IfNode) {
11 | rebuildIf(item)
12 | }
13 | })
14 | return node
15 | }
16 |
17 | function rebuildIf (node: IfNode) {
18 | let isChange = false
19 | let duplicate = clone(node.children)
20 | let currentNode: INode = node
21 |
22 | each(duplicate, (child) => {
23 | if (child instanceof ElseIfNode || child instanceof ElseNode) {
24 | currentNode.after(child)
25 | currentNode = child
26 | isChange = true
27 | } else {
28 | currentNode.append(child)
29 | }
30 | })
31 | return isChange
32 | }
33 |
--------------------------------------------------------------------------------
/src/nodes/basic.ts:
--------------------------------------------------------------------------------
1 |
2 | import {extend, each, pick, uniq} from 'lodash'
3 | import {OriginNode} from './origin'
4 | import {wrap} from '../parsers'
5 |
6 | export class BasicNode extends OriginNode implements INode {
7 | id = 0
8 | name = 'Template_0'
9 | isTemplate = false
10 |
11 | previous: BasicNode
12 | next: BasicNode
13 | parent: BasicNode
14 | origin: IOriginNode
15 |
16 | attributes = new Map
()
17 | arguments = new Array()
18 | dependencies = new Map()
19 | expressions = new Array();
20 | children = new Array()
21 |
22 | private valueId = 0
23 |
24 | constructor (origin?: IOriginNode) {
25 | super()
26 | this.origin = origin
27 | if (!origin) return this
28 |
29 | let props = [
30 | 'nodeType',
31 | 'nodeName',
32 | 'source',
33 | 'html',
34 | 'tail'
35 | ]
36 | extend(this, pick(origin, props))
37 | }
38 |
39 | parse () {
40 | // to be override
41 | }
42 | setIndex (index: number) {
43 | this.id = index
44 | this.name = 'Template_' + this.id
45 | }
46 | addDependency (variable: string, path: string) {
47 | let root = this.getRoot()
48 | root.dependencies.set(variable, path)
49 | }
50 | getArguments () {
51 | let args = this.arguments
52 | let last = this.getLastTemplate()
53 | if (last) {
54 | args = last.getArguments().concat(args)
55 | }
56 | return uniq(args)
57 | }
58 | getCreateList () {
59 | let results: (string | ICreate)[] = []
60 | each(this.children, (child) => {
61 | let tmp = child.create()
62 | if (tmp) results.push(tmp)
63 |
64 | if (!child.isTemplate) {
65 | results = results.concat(child.getCreateList())
66 | }
67 | })
68 | return results.filter(item => {
69 | if (typeof item === 'string') {
70 | return !!item.trim()
71 | }
72 | return true
73 | })
74 | }
75 |
76 | protected checkRoot () {
77 | let parent = this.parent
78 | if (!parent) return true
79 | if (parent.id === 0) return true
80 | if (parent.isTemplate) return true
81 | return false
82 | }
83 |
84 | protected addArguments (...list: string[]) {
85 | let args = this.arguments
86 | each(list, (item) => {
87 | if (args.indexOf(item) < 0) {
88 | args.push(item)
89 | }
90 | })
91 | }
92 |
93 | protected getLastTemplate () {
94 | if (!this.parent) return null
95 |
96 | let root = this.parent
97 | while (root.parent && !root.isTemplate) {
98 | root = root.parent
99 | }
100 | return root
101 | }
102 | protected getRoot () {
103 | let root: BasicNode = this
104 | while (root.parent) {
105 | root = root.parent
106 | }
107 | return root
108 | }
109 | protected createFunction (expression: string, isIncludeSelf?: boolean) {
110 | let argExps: string[]
111 | if (isIncludeSelf === false) {
112 | argExps = this.parent.getArguments().map((arg, index) => {
113 | return `var ${arg} = _args[${index}];`
114 | })
115 | } else {
116 | argExps = this.getArguments().map((arg, index) => {
117 | return `var ${arg} = _args[${index}];`
118 | })
119 | }
120 |
121 | return `function (it, _args) {
122 | ${argExps.join('\n')}
123 |
124 | ${expression}
125 | }`
126 | }
127 | protected getValueSet (valueResult: IValueResult, updateExp: string, updateArgs: string[]) {
128 | const patches: string[] = []
129 | const updates: string[] = []
130 | if (!valueResult.isDynamic) return {patches, updates}
131 |
132 | const valueId = this.getValueId()
133 | const dynamicValues: {expression: string, pipes: string[][]}[] = []
134 | each(valueResult.values, value => {
135 | if (typeof value !== 'string') dynamicValues.push(value)
136 | })
137 |
138 | if (dynamicValues.length === 1) {
139 | const value = dynamicValues[0]
140 | patches.push(`_patches[${valueId}] = ${value.expression};`)
141 |
142 | const pipes: string[] = []
143 | each(value.pipes, pipe => {
144 | const args = pipe.slice(0)
145 | const method = args.shift()
146 | args.unshift('_tmp')
147 | pipes.push(`_tmp = ${method}(${args.join(', ')});`)
148 | })
149 | updates.push(`
150 | var _tmp = _patches[${valueId}];
151 | if (_cache(${valueId}, _tmp)) {
152 | ${pipes.join('\n')}
153 | ${updateExp}(${updateArgs.join(', ')}, ${this.translateValue(valueResult, dynamicValues)});
154 | }
155 | `)
156 | } else if (dynamicValues.length > 1) {
157 | const exps = dynamicValues.map(item => item.expression)
158 | patches.push(`_patches[${valueId}] = [${exps.join(', ')}];`)
159 |
160 | const pipes: string[] = []
161 | each(dynamicValues, (value, valueIndex) => {
162 | pipes.push(`var _value${valueIndex} = _tmp[${valueIndex}];`)
163 | each(value.pipes, pipe => {
164 | const args = pipe.slice(0)
165 | const method = args.shift()
166 | args.unshift(`_value${valueIndex}`)
167 | pipes.push(`_value${valueIndex} = ${method}(${args.join(', ')});`)
168 | })
169 | })
170 | updates.push(`
171 | var _tmp = _patches[${valueId}];
172 | if (_cache(${valueId}, _tmp)) {
173 | ${pipes.join('\n')}
174 | ${updateExp}(${updateArgs.join(', ')}, ${this.translateValue(valueResult, dynamicValues)});
175 | }
176 | `)
177 | }
178 | return {patches, updates}
179 | }
180 | protected createEventFunction (expression: string) {
181 | let argExps = this.getArguments().map((arg, index) => {
182 | return `var ${arg} = _args[${index}];`
183 | })
184 |
185 | return `function ($event, it, _args) {
186 | ${argExps.join('\n')}
187 |
188 | ${expression}
189 | }`
190 | }
191 | protected create (): string | ICreate {
192 | // to be override
193 | return ''
194 | }
195 |
196 | protected getValueId () {
197 | let last = this.getLastTemplate()
198 | if (last) {
199 | return last.valueId++
200 | } else {
201 | return this.valueId++
202 | }
203 | }
204 | protected translateValue (valueResult: IValueResult, dynamicValues: {expression: string, pipes: string[][]}[]) {
205 | let results: string[] = []
206 | each(valueResult.values, item => {
207 | if (typeof item === 'string') {
208 | results.push(wrap(item))
209 | } else {
210 | if (dynamicValues.length === 1) {
211 | results.push(`_tmp`)
212 | } else {
213 | results.push(`_value${dynamicValues.indexOf(item)}`)
214 | }
215 | }
216 | })
217 | return results.join(' + ')
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/src/nodes/child.ts:
--------------------------------------------------------------------------------
1 |
2 | import {BasicNode} from './basic';
3 | const PARAMETER_SPLIT = ',';
4 |
5 | export class ChildNode extends BasicNode {
6 |
7 | childContext = ''
8 |
9 | parse () {
10 | let list = this.source.split(PARAMETER_SPLIT)
11 |
12 | let path = (list[0] || '').trim()
13 | let c1 = path[0]
14 | let c2 = path[path.length - 1]
15 | let isSingleQuotation = (c1 === '\'' && c2 === '\'')
16 | let isDoubleQuotation = (c1 === '"' && c2 === '"')
17 | if (isSingleQuotation || isDoubleQuotation) {
18 | path = path.slice(1, path.length - 1)
19 | }
20 |
21 | this.childContext = (list[1] || '').trim()
22 | this.addDependency(this.name, path)
23 | }
24 | create () {
25 | let context = this.childContext
26 | let args = [this.parent.id, this.id, this.name]
27 | if (this.childContext) {
28 | args.push(this.createFunction(`return ${context};`))
29 | }
30 | return `_dep.child(_template, ${args.join(', ')});`
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/nodes/element.ts:
--------------------------------------------------------------------------------
1 |
2 | import {each} from 'lodash'
3 | import {BasicNode} from './basic'
4 | import {fillTo, addMapToMap} from '../util'
5 | import {IfNode} from './if'
6 | import {wrap, parseAttributes, parseValue} from '../parsers'
7 |
8 | export class ElementNode extends BasicNode {
9 | nodeType = 1
10 | namespace = 'element'
11 | outputs = new Map()
12 | events = new Map()
13 | attributes = new Map()
14 |
15 | parse () {
16 | this.attributes = parseAttributes(this.source)
17 | each(this.expressions, (node) => {
18 | if (node instanceof IfNode) {
19 | addMapToMap(this.attributes, parseAttributes(node.getExpressionSource()))
20 | }
21 | })
22 | }
23 | addOutput (prop: string, expression: string) {
24 | this.outputs.set(prop, expression)
25 | }
26 | addEvent (name: string, expression: string, args: string[]) {
27 | this.events.set(name, {expression, args})
28 | }
29 |
30 | protected create (): string | ICreate {
31 | const args: (string | number)[] = [this.parent.id, this.id, wrap(this.nodeName.toUpperCase())]
32 |
33 | const attrs = this.createAttributes()
34 | if (attrs) args.push(attrs)
35 |
36 | if (this.events.size || this.outputs.size) {
37 | fillTo(args, 4, 0)
38 | args.push(this.createEvent())
39 | }
40 |
41 | const create = `_dep.element(_template, ${args.join(', ')});`
42 | const set = this.calculateDynamic()
43 | if (set.patch) {
44 | return {create, patch: set.patch, update: set.update}
45 | } else {
46 | return create
47 | }
48 | }
49 |
50 | private createAttributes () {
51 | const attrs: string[] = []
52 | this.attributes.forEach((value, name) => {
53 | const valueResult = parseValue(value)
54 | if (!valueResult.isDynamic) {
55 | attrs.push(`[${wrap(name)}, ${wrap(value)}]`)
56 | }
57 | })
58 |
59 | if (attrs.length) {
60 | return `[${attrs.join(',\n')}]`
61 | } else {
62 | return ''
63 | }
64 | }
65 | private calculateDynamic () {
66 | const patches: string[] = []
67 | const updates: string[] = []
68 |
69 | const conditionSet = this.calculateConditions()
70 | if (conditionSet.patch) patches.push(conditionSet.patch)
71 | if (conditionSet.update) updates.push(conditionSet.update)
72 |
73 | this.attributes.forEach((value, key) => {
74 | const valueResult = parseValue(value)
75 | if (valueResult.isDynamic) {
76 | const args = ['_template', this.id.toString(), wrap(key)]
77 | const set = this.getValueSet(valueResult, '_dep.updateAttr', args)
78 | if (set.patches.length) patches.push(set.patches.join('\n'))
79 | if (set.updates.length) updates.push(set.updates.join('\n'))
80 | }
81 | })
82 | return {patch: patches.join('\n'), update: updates.join('\n')}
83 | }
84 | private calculateConditions () {
85 | if (this.expressions.length <= 0) {
86 | return {patch: '', update: ''}
87 | }
88 |
89 | const patches: string[] = []
90 | const updates: string[] = []
91 | const valueId = this.getValueId()
92 | each(this.expressions, (node, index) => {
93 | if (node instanceof IfNode) {
94 | const matrix: string[] = []
95 | patches.push('var _conditions = [];')
96 | each(node.getExpressions(), (item, itemIndex) => {
97 | if (item.tag) {
98 | patches.push(`${item.tag} (${item.condition}) _conditions[${index}] = ${itemIndex};`)
99 | } else {
100 | patches.push(`else _conditions[${index}] = ${itemIndex};`)
101 | }
102 | matrix.push(`[${item.attrs.map(attr => wrap(attr)).join(', ')}]`)
103 | })
104 | patches.push(`_patches[${valueId}] = _conditions;`)
105 |
106 | updates.push(`
107 | var _matrix${index} = [${matrix.join(', ')}];
108 | _dep.concatMatrix(_includes, _matrix${index}, _tmp[${index}]);
109 | _dep.concatMatrixOthers(_excludes, _matrix${index}, _tmp[${index}]);
110 | `)
111 | }
112 | })
113 |
114 | const update = `
115 | var _tmp = _patches[${valueId}];
116 | if (_cache(${valueId}, _tmp)) {
117 | var _includes = [];
118 | var _excludes = [];
119 | ${updates.join('\n')}
120 | _dep.setAttributesCondition(_template, ${this.id}, _includes, _excludes);
121 | }
122 | `
123 | return {patch: patches.join('\n'), update}
124 | }
125 | private createEvent () {
126 | let events: string[] = []
127 | this.events.forEach((event, type) => {
128 | let typeStr = wrap(type)
129 | let fnStr = this.createEventFunction(`return ${event.expression}(${event.args.join(', ')});`)
130 | events.push(`[${typeStr}, ${fnStr}]`)
131 | })
132 | if (this.outputs.size) {
133 | let outputs: string[] = []
134 | this.outputs.forEach((output, key) => {
135 | outputs.push(`${output} = this.${key};`)
136 | })
137 | events.push(`['change input', ${this.createEventFunction(outputs.join('\n'))}]`)
138 | }
139 | return `[${events.join(',\n')}]`
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/nodes/else.ts:
--------------------------------------------------------------------------------
1 |
2 | import {BasicNode} from './basic'
3 |
4 | export class ElseNode extends BasicNode {
5 | tag = 'else'
6 | isTemplate = true
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/nodes/elseif.ts:
--------------------------------------------------------------------------------
1 |
2 | import {BasicNode} from './basic'
3 |
4 | export class ElseIfNode extends BasicNode {
5 | tag = 'else if'
6 | isTemplate = true
7 |
8 | get condition () {
9 | return this.source.trim()
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/nodes/factory.ts:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import {ElementNode} from './element'
4 | import {TextNode} from './text'
5 | import {BasicNode} from './basic'
6 | import {IfNode} from './if'
7 | import {ElseIfNode} from './elseif'
8 | import {ElseNode} from './else'
9 | import {ForNode} from './for'
10 | import {HtmlNode} from './html'
11 | import {ChildNode} from './child'
12 | import {ImportNode} from './import'
13 |
14 | export function createNode (origin: IOriginNode, options: IOptions) {
15 | let result: BasicNode
16 | if (!origin) {
17 | result = new BasicNode()
18 | } else if (origin.nodeType === 'ET') {
19 | switch (origin.nodeName) {
20 | case '#if':
21 | result = new IfNode(origin)
22 | break
23 | case '#elseif':
24 | result = new ElseIfNode(origin)
25 | break
26 | case '#else':
27 | result = new ElseNode(origin)
28 | break
29 | case '#for':
30 | result = new ForNode(origin)
31 | break
32 | case '#html':
33 | result = new HtmlNode(origin)
34 | break
35 | case '#child':
36 | result = new ChildNode(origin)
37 | break
38 | case '#import':
39 | result = new ImportNode(origin)
40 | break
41 | }
42 | } else {
43 | switch (origin.nodeType) {
44 | case 1:
45 | result = new ElementNode(origin)
46 | break
47 | case 3:
48 | result = new TextNode(origin)
49 | break
50 | }
51 | }
52 | return result
53 | }
54 |
--------------------------------------------------------------------------------
/src/nodes/for.ts:
--------------------------------------------------------------------------------
1 |
2 | import {BasicNode} from './basic'
3 | import {parseFor} from '../parsers'
4 |
5 | export class ForNode extends BasicNode {
6 |
7 | isTemplate = true
8 |
9 | forExpression = ''
10 | forItem = 'item'
11 | forIndex = '_i'
12 | forTrackBy = ''
13 |
14 | parse () {
15 | let result = parseFor(this.source)
16 | this.forExpression = result.expression
17 |
18 | if (result.item) {
19 | this.forItem = result.item
20 | }
21 | if (result.index) {
22 | this.forIndex = result.index
23 | }
24 | if (result.trackBy) {
25 | this.forTrackBy = result.trackBy
26 | }
27 |
28 | this.addArguments(result.item)
29 | this.addArguments(result.index)
30 | }
31 |
32 | create () {
33 | let args = [this.parent.id, this.id, this.name]
34 |
35 | args.push(this.createFunction(`return ${this.forExpression};`, false))
36 | if (this.forTrackBy) {
37 | args.push(this.createFunction(`return ${this.forTrackBy};`))
38 | }
39 | return `_dep.efor(_template, ${args.join(', ')});`
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/nodes/html.ts:
--------------------------------------------------------------------------------
1 |
2 | import {BasicNode} from './basic'
3 | import {parseValue, wrap} from '../parsers'
4 |
5 | export class HtmlNode extends BasicNode {
6 | nodeName = '#html'
7 |
8 | create (): string | ICreate {
9 | const result = parseValue(this.html)
10 | if (!result.isDynamic) {
11 | const args = [this.parent.id.toString()]
12 | args.push(wrap(this.html))
13 | return `_dep.html(_template, ${args.join(', ')});`
14 | } else {
15 | const args = ['_template', this.parent.id.toString()]
16 | const create = ''
17 | const set = this.getValueSet(result, '_dep.html', args)
18 | const patch = set.patches.join('\n')
19 | const update = set.updates.join('\n')
20 | return {create, patch, update}
21 | }
22 | }
23 |
24 | getCreateList () {
25 | return []
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/nodes/if.ts:
--------------------------------------------------------------------------------
1 |
2 | import {each} from 'lodash'
3 | import {BasicNode} from './basic'
4 | import {ElseIfNode} from './elseif'
5 | import {ElseNode} from './else'
6 | import {parseAttributes} from '../parsers'
7 |
8 | export class IfNode extends BasicNode {
9 | tag = 'if';
10 | isTemplate = true;
11 |
12 | get condition () {
13 | return this.source.trim()
14 | }
15 |
16 | getExpressionSource () {
17 | let re = ''
18 | each(this.children, (child) => {
19 | if (child.nodeType === 3) re += (' ' + child.source)
20 | })
21 | return re
22 | }
23 |
24 | getExpressions () {
25 | let expressions: {tag: string, condition: string, attrs: string[]}[] = []
26 |
27 | let current = {tag: 'if', condition: this.condition, attrs: new Array()}
28 | each(this.children, (child) => {
29 | if (child instanceof ElseIfNode) {
30 | expressions.push(current)
31 | current = {tag: 'else if', condition: child.condition, attrs: new Array()}
32 | } else if (child instanceof ElseNode) {
33 | expressions.push(current)
34 | current = {tag: 'else', condition: '', attrs: new Array()}
35 | } else {
36 | parseAttributes(child.source).forEach((value, key) => current.attrs.push(key))
37 | }
38 | })
39 | expressions.push(current)
40 | return expressions
41 | }
42 |
43 | protected create () {
44 | let args: (string | number)[] = [this.parent.id, this.id]
45 | let exps: string[] = []
46 | this.getConditions().forEach((node, index) => {
47 | if (node instanceof IfNode || node instanceof ElseIfNode) {
48 | exps.push(`${node.tag} (${node.condition}) return [${index}, ${node.name}];`)
49 | } else {
50 | exps.push(`else return [${index}, ${node.name}];`)
51 | }
52 | })
53 | args.push(this.createFunction(exps.join('\n')))
54 | return `_dep.eif(_template, ${args.join(', ')});`
55 | }
56 | private getConditions () {
57 | let results: INode[] = [this]
58 | let current: INode = this
59 |
60 | while (true) {
61 | current = current.next
62 | if (current instanceof ElseIfNode || current instanceof ElseNode) {
63 | results.push(current)
64 | } else {
65 | break
66 | }
67 | }
68 | return results
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/nodes/import.ts:
--------------------------------------------------------------------------------
1 |
2 | import {BasicNode} from './basic'
3 | const PARAMETER_SPLIT = ' from '
4 |
5 | export class ImportNode extends BasicNode {
6 | namespace = 'import';
7 | nodeName = '#import';
8 |
9 | parse () {
10 | let list = this.source.split(PARAMETER_SPLIT)
11 |
12 | let name = (list[0] || '').trim()
13 | let path = (list[1] || '').trim()
14 |
15 | let c1 = path[0]
16 | let c2 = path[path.length - 1]
17 | let isSingle = (c1 === '\'' && c2 === '\'')
18 | let isDouble = (c1 === '"' && c2 === '"')
19 | if (isSingle || isDouble) {
20 | path = path.slice(1, path.length - 1)
21 | }
22 | this.addDependency(name, path)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/nodes/origin.ts:
--------------------------------------------------------------------------------
1 |
2 | import {removeAt, insertAfter, insertBefore} from '../util'
3 |
4 | export class OriginNode implements IOriginNode {
5 | nodeType: string | number = 'ET';
6 | nodeName = '';
7 | source = '';
8 | header = '';
9 | html = '';
10 | tail = '';
11 |
12 | parent: OriginNode = null;
13 | previous: OriginNode = null;
14 | next: OriginNode = null;
15 | expressions = new Array();
16 | children = new Array();
17 |
18 | append (childNode: OriginNode) {
19 | childNode.remove()
20 |
21 | let children = this.children
22 | if (children.length > 0) {
23 | let last = children[children.length - 1]
24 | last.next = childNode
25 | childNode.previous = last
26 | }
27 |
28 | children.push(childNode)
29 | childNode.next = null
30 | childNode.parent = this
31 | }
32 | prepend (childNode: OriginNode) {
33 | childNode.remove()
34 |
35 | let children = this.children
36 | if (children.length > 0) {
37 | let first = children[0]
38 | first.previous = childNode
39 | childNode.next = first
40 | }
41 |
42 | children.unshift(childNode)
43 | childNode.previous = null
44 | childNode.parent = this
45 | }
46 | after (nextNode: OriginNode) {
47 | if (!this.parent) return
48 |
49 | if (!this.next) {
50 | return this.parent.append(nextNode)
51 | }
52 |
53 | nextNode.remove()
54 | nextNode.parent = this.parent
55 | nextNode.previous = this
56 | nextNode.next = this.next
57 |
58 | let currentNext = this.next
59 | if (currentNext) currentNext.previous = nextNode
60 | this.next = nextNode
61 |
62 | insertAfter(this.parent.children, this, nextNode)
63 | }
64 | before (previousNode: OriginNode) {
65 | if (!this.parent) return
66 |
67 | if (!this.previous) {
68 | return this.parent.prepend(previousNode)
69 | }
70 |
71 | previousNode.remove()
72 | previousNode.parent = this.parent
73 | previousNode.next = this
74 | previousNode.previous = this.previous
75 |
76 | let currentPrevious = this.previous
77 | if (currentPrevious) currentPrevious.next = previousNode
78 | this.previous = previousNode
79 |
80 | insertBefore(this.parent.children, this, previousNode)
81 | }
82 | remove () {
83 | let previous = this.previous
84 | let next = this.next
85 | if (previous) previous.next = next
86 | if (next) next.previous = previous
87 |
88 | if (this.parent) {
89 | removeAt(this.parent.children, this)
90 | }
91 | }
92 | getOuterHTML () {
93 | switch (this.nodeType) {
94 | case 1:
95 | let results: string[] = [];
96 | results.push(this.header)
97 | results.push(this.html)
98 | results.push(this.tail)
99 | return results.join('')
100 | case 3:
101 | return this.getInnerHTML()
102 | }
103 | }
104 | getInnerHTML () {
105 | return this.html
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/nodes/text.ts:
--------------------------------------------------------------------------------
1 |
2 | import {parseValue, wrap} from '../parsers'
3 | import {BasicNode} from './basic'
4 |
5 | export class TextNode extends BasicNode {
6 | nodeType = 3
7 |
8 | create (): string | ICreate {
9 | const text = this.source
10 | const result = parseValue(text)
11 |
12 | const args = [this.parent.id.toString(), this.id.toString()]
13 | if (!result.isDynamic) {
14 | args.push(wrap(text))
15 | return `_dep.text(_template, ${args.join(', ')});`
16 | } else {
17 | const updateArgs = ['_template', this.id.toString()]
18 | const create = `_dep.text(_template, ${args.join(', ')});`
19 | const set = this.getValueSet(result, '_dep.updateText', updateArgs)
20 | const patch = set.patches.join('\n')
21 | const update = set.updates.join('\n')
22 | return {create, patch, update}
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/parsers/attributes/attributes-result.ts:
--------------------------------------------------------------------------------
1 |
2 | import {each} from 'lodash'
3 | import {ATTRIBUTES_STATE} from './attributes-state'
4 |
5 | export class AttributesResult {
6 | list = new Array<{key: string, value: string}>()
7 | state = ATTRIBUTES_STATE.Scan
8 |
9 | addToken (token: string) {
10 | switch (this.state) {
11 | case ATTRIBUTES_STATE.Key:
12 | this.addKey(token)
13 | break
14 | case ATTRIBUTES_STATE.Value:
15 | this.addValue(token)
16 | break
17 | }
18 | }
19 | createOne () {
20 | this.list.push({key: '', value: ''})
21 | }
22 | getAttributes () {
23 | let attrs = new Map()
24 | each(this.list, (item) => {
25 | attrs.set(item.key, item.value)
26 | })
27 | return attrs
28 | }
29 |
30 | private addKey (token: string) {
31 | let last = this.getLastOne()
32 | last.key += token
33 | }
34 | private addValue (token: string) {
35 | let last = this.getLastOne()
36 | last.value += token
37 | }
38 | private getLastOne () {
39 | let len = this.list.length
40 | if (len) {
41 | return this.list[len - 1]
42 | } else {
43 | this.createOne()
44 | return this.list[0]
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/parsers/attributes/attributes-state.ts:
--------------------------------------------------------------------------------
1 |
2 | export const ATTRIBUTES_STATE = {
3 | Scan: 0,
4 | Key: 1,
5 | Value: 2
6 | }
7 |
--------------------------------------------------------------------------------
/src/parsers/attributes/index.ts:
--------------------------------------------------------------------------------
1 |
2 | import {Parser} from 'et-parser'
3 | import {ATTRIBUTES_STATE} from './attributes-state'
4 | import {AttributesResult} from './attributes-result'
5 |
6 | const parser = new Parser(`
7 | | scan | key | keyEnd | valueStart | value{{ | value | value' | value" | _str
8 | ------ | ------ | --- | ------ | ---------- | ------- | ----- | ------ | ------ | ----
9 | :[\\s] | scan | keyEnd | keyEnd | valueStart | value{{ | valueEnd:scan | value' | value" |
10 | ' | keyStart:key | key | keyStart:key | ignore:value' | value{{ | value | value'End:scan | value" |
11 | " | keyStart:key | key | keyStart:key | ignore:value" | value{{ | value | value' | value"End:scan |
12 | = | keyStart:key | valueStart | valueStart | value | value{{ | value | value' | value" |
13 | \\' | keyStart:key | key | keyStart:key | value | value{{ | value | value' | value" |
14 | \\" | keyStart:key | key | keyStart:key | value | value{{ | value | value' | value" |
15 | {{ | keyStart:key | key | keyStart:key | value{{ | value{{ | _str | _str | _str |
16 | }} | keyStart:key | key | keyStart:key | value | value | value | value' | value" | _
17 | | keyStart:key | key | keyStart:key | value | value{{ | value | value' | value" |
18 | `)
19 |
20 | export function parseAttributes (source: string) {
21 | let result = new AttributesResult()
22 | parser.parse(source, (state, token) => {
23 | switch (state) {
24 | case 'scan':
25 | case 'keyEnd':
26 | case 'ignore':
27 | break
28 | case '_str':
29 | case 'key':
30 | case 'value{{':
31 | case 'value':
32 | case 'value\'':
33 | case 'value"':
34 | result.addToken(token)
35 | break
36 | case 'keyStart':
37 | result.createOne()
38 | result.state = ATTRIBUTES_STATE.Key
39 | result.addToken(token)
40 | break
41 | case 'valueStart':
42 | result.state = ATTRIBUTES_STATE.Value
43 | break
44 | case 'valueEnd':
45 | case 'value\'End':
46 | case 'value"End':
47 | result.state = ATTRIBUTES_STATE.Scan
48 | break
49 | default:
50 | throw new Error(`The state: '${state}' is not defined.`)
51 | }
52 | })
53 | return result.getAttributes()
54 | }
55 |
--------------------------------------------------------------------------------
/src/parsers/dep.ts:
--------------------------------------------------------------------------------
1 |
2 | import {forEachRight, uniq} from 'lodash'
3 | import {Parser} from 'et-parser'
4 |
5 | const SYMBOL = '_dep.'
6 |
7 | const parser = new Parser(`
8 | | text | method | _str1 | _str2
9 | ------- | ------ | ------ | ----- | -----
10 | ${SYMBOL} | start:method | start | |
11 | ( | text | end:text | |
12 | ' | _str1 | method | _ |
13 | " | _str2 | method | | _
14 | \\\' | text | method | |
15 | \\\" | text | method | |
16 | :[\\s] | text | cancel:text | |
17 | | text | method | |
18 | `)
19 |
20 | export function parseDep (source: string) {
21 | let result = ''
22 | let methods: string[] = []
23 | let method = '';
24 | parser.parse(source, function (state, token) {
25 | switch (state) {
26 | case '_str1':
27 | case '_str2':
28 | case 'text':
29 | result += token
30 | break;
31 | case 'start':
32 | case 'cancel':
33 | result += (method + token)
34 | method = '';
35 | break;
36 | case 'method':
37 | method += token;
38 | break;
39 | case 'end':
40 | result = result.substr(0, result.length - SYMBOL.length)
41 | result += `_dep_${method}${token}`
42 | methods.push(method.trim());
43 | method = '';
44 | break;
45 | default:
46 | throw new Error(`The state: '${state}' is not defined.`)
47 | }
48 | })
49 |
50 | forEachRight(uniq(methods), (item) => {
51 | if (item) {
52 | result = `var _dep_${item} = _dep.${item};\n` + result
53 | }
54 | })
55 | return result
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/parsers/for.ts:
--------------------------------------------------------------------------------
1 | import {Parser} from 'et-parser'
2 |
3 | const parser = new Parser(`
4 | | ignore | item | indexPre | index | indexEnd | expression | trackBy | _str1 | _str2
5 | -------------------- | ------ | -------- | -------- | -------- | -------- | ---------- | ------- | ----- | -----
6 | :[\\s] | ignore | indexPre | indexPre | indexEnd | indexEnd | expression | trackBy | |
7 | :[,;] | error1 | indexPre | indexPre | index | error2 | expression | trackBy | |
8 | in | ::: | ignore:expression | ignore:expression | ignore:expression | ignore:expression | expression | trackBy | |
9 | track by | ::: | ::: | ::: | ::: | error2 | ignore:trackBy | trackBy | |
10 | ' | item | item | index | index | error2 | _str1 | trackBy | _ |
11 | " | item | item | index | index | error2 | _str2 | trackBy | | _
12 | \\' | item | item | index | index | error2 | expression | trackBy | |
13 | \\" | item | item | index | index | error2 | expression | trackBy | |
14 | | item | item | index | index | error2 | expression | trackBy | |
15 | `)
16 |
17 | export function parseFor (source: string) {
18 | let item = '';
19 | let index = '';
20 | let expression = '';
21 | let trackBy = '';
22 |
23 | parser.parse(source, (state, token) => {
24 | switch (state) {
25 | case 'ignore':
26 | case 'indexPre':
27 | case 'indexEnd':
28 | break;
29 | case 'item':
30 | item += token;
31 | break;
32 | case 'index':
33 | index += token;
34 | break;
35 | case '_str1':
36 | case '_str2':
37 | case 'expression':
38 | expression += token;
39 | break;
40 | case 'trackBy':
41 | trackBy += token;
42 | break;
43 | default:
44 | throw new Error(`parse_for_${state}`)
45 | }
46 | })
47 |
48 | if (!index) index = '_index';
49 | return {item, index, expression, trackBy}
50 | }
51 |
--------------------------------------------------------------------------------
/src/parsers/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export * from './dep'
3 | export * from './for'
4 | export * from './wrap'
5 |
6 | export * from './attributes'
7 | export * from './origin'
8 | export * from './value'
9 |
10 |
--------------------------------------------------------------------------------
/src/parsers/origin/index.ts:
--------------------------------------------------------------------------------
1 |
2 | import {Parser} from 'et-parser'
3 | import {NODE_STATE} from './origin-state'
4 | import {Node} from './origin-node'
5 | import {translateNode} from './origin-helper'
6 |
7 | const parser = new Parser(`
8 | | text | start | name | source | tail | etStart | etName | etSource | etTail | _str[ | _str{{ | _str1 | _str2 | _ignore
9 | ------ | ---- | ----- | ---- | ------ | ---- | ------- | ------ | -------- | ------ | ----- | ------ | ----- | ----- | --------
10 | < | start | | | source | | | | etSource | | | | | |
11 | | tail | | | source | | | | etSource | | | | | |
12 | > | text | | nodeEnd:text | nodeEnd:text | tailEnd:text | | | etSource | | | | | |
13 | /> | text | | nodeEnd:text | nodeEnd:text | tailEnd:text | | | etSource | | | | | |
14 | [# | etStart | | | etStart | | | | etSource | | | | | |
15 | [/# | etTail | | | source | | | | etSource | | | | | |
16 | ] | text | | | source | | | etEnd:text | etEnd:text | etTailEnd:text | _ | | | |
17 | [ | text | | | source | | | | _str[ | | _str[ | | | |
18 | ' | text | | | _str1 | | | | _str1 | | | | _ | |
19 | " | text | | | _str2 | | | | _str2 | | | | | _ |
20 | {{ | _str{{ | | | _str{{ | | | | etSource | | | | | |
21 | \\' | text | | | source | | | | etSource | | | | | |
22 | \\" | text | | | source | | | | etSource | | | | | |
23 | }} | text | | | source | | | | etSource | | | _ | | |
24 | :[\\s] | text | | nameEnd:source | source | | | etNameEnd:etSource | etSource | | | | | |
25 | :[\\S] | text | name | name | source | tail | etName | etName | etSource | etTail | | | | |
26 | | text | | | source | | | | etSource | | | | | | _
28 | | text | | | source | | | | etSource | | | | | |
29 | `)
30 |
31 | // 1. token归属到 nodeName header tail 中去
32 | // 2. 当前节点几个状态 [header, body, closed]
33 | // 3. html = header + 子辈html + tail
34 | export function parseOrigin (source: string) {
35 | let root = new Node()
36 | let current = root
37 | let tail = ''
38 |
39 | parser.parse(source, (state: string, token: string, index: number) => {
40 | switch (state) {
41 | case '_ignore':
42 | break
43 | case 'text':
44 | case '_str[':
45 | case '_str{{':
46 | case '_str1':
47 | case '_str2':
48 | case 'name':
49 | case 'source':
50 | case 'etName':
51 | case 'etSource':
52 | current.addSource(token)
53 | break
54 | case 'start':
55 | current = current.createChild()
56 | current.addSource(token)
57 | current.state = 1
58 | break
59 | case 'etStart':
60 | current = current.createChild()
61 | current.addSource(token)
62 | current.nodeName = '#'
63 | current.state = NODE_STATE.NodeName
64 | break
65 | case 'nameEnd':
66 | case 'etNameEnd':
67 | current.state = NODE_STATE.Source
68 | current.addSource(token)
69 | break
70 | case 'nodeEnd':
71 | case 'etEnd':
72 | current.state = NODE_STATE.Header
73 | current.addSource(token)
74 | current.state = NODE_STATE.Body
75 | break
76 | case 'tail':
77 | case 'etTail':
78 | tail += token
79 | break
80 | case 'tailEnd':
81 | current = current.closeNode(tail + token)
82 | tail = ''
83 | break
84 | case 'etTailEnd':
85 | current = current.closeNode(tail + token)
86 | tail = ''
87 | if (current.state === NODE_STATE.Source) {
88 | // 如果关闭之后的父节点头还没有读完
89 | // 证明这是一个从中间分离出去的
90 | current.saveExpressions()
91 | return 'source'
92 | }
93 | break
94 | default:
95 | throw new Error(`The state: '${state}' is not defined.`)
96 | }
97 | })
98 | root.closeNode('')
99 | return translateNode(root, true)
100 | }
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/src/parsers/origin/origin-helper.ts:
--------------------------------------------------------------------------------
1 |
2 | import {each} from 'lodash'
3 | import {OriginNode} from '../../nodes/origin'
4 | import {Node} from './origin-node'
5 |
6 | // help methods to translate node
7 | export function getHtml (node: Node) {
8 | let html = ''
9 | each(node.children, (child) => {
10 | if (child.isTextNode) {
11 | html += child.source.trim()
12 | } else {
13 | html += child.header
14 | html += getHtml(child)
15 | html += child.tail
16 | }
17 | })
18 | return html
19 | }
20 |
21 | export function translateChildren (parent: OriginNode, children: Node[]) {
22 | let resuts = new Array()
23 | let last = null
24 |
25 | each(children, (child) => {
26 | if (!child.nodeName && !child.source.trim()) {
27 | return
28 | }
29 | let current = translateNode(child)
30 | current.parent = parent
31 | current.previous = last
32 | if (last) last.next = current
33 |
34 | resuts.push(current)
35 | last = current
36 | })
37 | return resuts
38 | }
39 |
40 | export function translateNode (node: Node, isRoot?: boolean) {
41 | let result = new OriginNode()
42 | result.nodeName = node.nodeName
43 | result.source = node.source.trim()
44 | result.header = node.header
45 | result.html = getHtml(node)
46 | result.tail = node.tail
47 | result.children = translateChildren(result, node.children)
48 | result.expressions = translateChildren(result, node.expressions)
49 |
50 | if (!isRoot) {
51 | let nodeName = result.nodeName
52 | if (!nodeName) {
53 | result.nodeType = 3 // text
54 | } else if (nodeName.indexOf('#') === 0) {
55 | result.nodeType = 'ET'
56 | } else if (nodeName === '