comparison src/implab/text/template-compile.js @ 34:27e8e9e38e07 default tip

Слияние
author nickolay
date Wed, 05 Jun 2019 20:44:15 +0300
parents 8af8e840dd49 1dc2fd263b90
children
comparison
equal deleted inserted replaced
33:8af8e840dd49 34:27e8e9e38e07
1 define(
2 ["dojo/request", "./format", "../log/trace!"],
3 function (request, format, trace) {
4
5 // разбивает строку шаблона на токены, возвращает контекст для
6 // дальнейшей обработки в visitTemplate
7 var parseTemplate = function (str) {
8 var tokens = str.split(/(<%=|\[%=|<%|\[%|%\]|%>)/);
9 var pos = -1;
10 var data = [],
11 code = [];
12
13 return {
14 next: function () {
15 pos++;
16 return pos < tokens.length;
17 },
18 token: function () {
19 return tokens[pos];
20 },
21 pushData: function () {
22 var i = data.length;
23 data.push.apply(data, arguments);
24 return i;
25 },
26 pushCode : function() {
27 var i = code.length;
28 code.push.apply(code, arguments);
29 return i;
30 },
31 compile: function () {
32 var text = "var $p = [];\n" +
33 "var print = function(){\n" +
34 " $p.push(format.apply(null,arguments));\n" +
35 "};\n" +
36 // Introduce the data as local variables using with(){}
37 "with(obj){\n" +
38 code.join("\n") +
39 "}\n" +
40 "return $p.join('');";
41
42 try {
43 var compiled = new Function("obj, format, $data", text);
44 /**
45 * Функция форматирования по шаблону
46 *
47 * @type{Function}
48 * @param{Object} obj объект с параметрами для подстановки
49 */
50 return function (obj) {
51 return compiled(obj || {}, format, data);
52 };
53 } catch (e) {
54 trace.error([e]);
55 trace.log([text, data]);
56 throw e;
57 }
58 }
59 }
60 };
61
62 function visitTemplate(context) {
63 while (context.next()) {
64 switch (context.token()) {
65 case "<%":
66 case "[%":
67 visitCode(context);
68 break;
69 case "<%=":
70 case "[%=":
71 visitInline(context);
72 break;
73 default:
74 visitTextFragment(context);
75 break;
76 }
77 }
78 }
79
80 function visitInline(context) {
81 var code = ["$p.push("];
82 while (context.next()) {
83 if (context.token() == "%>" || context.token() == "%]")
84 break;
85 code.push(context.token());
86 }
87 code.push(");");
88 context.pushCode(code.join(''));
89 }
90
91 function visitCode(context) {
92 var code = [];
93 while (context.next()) {
94 if (context.token() == "%>" || context.token() == "%]")
95 break;
96 code.push(context.token());
97 }
98 context.pushCode(code.join(''));
99 }
100
101 function visitTextFragment(context) {
102 var i = context.pushData(context.token());
103 context.pushCode("$p.push($data["+i+"]);");
104 }
105
106 var compile = function (str) {
107 if (!str)
108 return function() { return "";};
109
110 var ctx = parseTemplate(str);
111 visitTemplate(ctx);
112 return ctx.compile();
113 };
114
115 var cache = {};
116
117 compile.load = function (id, require, callback) {
118 var url = require.toUrl(id);
119 if (url in cache) {
120 callback(cache[url]);
121 } else {
122 request(url).then(compile).then(function (tc) {
123 callback(cache[url] = tc);
124 }, function (err) {
125 require.signal("error", [{
126 error: err,
127 src: 'implab/text/template-compile'
128 }]);
129 });
130 }
131 };
132
133 return compile;
134 });