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