template-compile.js
133 lines
| 4.5 KiB
| application/javascript
|
JavascriptErbLexer
|
|
r49 | define( | |
| ["dojo/request", "./format", "../log/trace!"], | |||
| function (request, format, trace) { | |||
| // разбивает строку шаблона на токены, возвращает контекст для | |||
| // дальнейшей обработки в visitTemplate | |||
| var parseTemplate = function (str) { | |||
| var tokens = str.split(/(<%=|\[%=|<%|\[%|%\]|%>)/); | |||
| var pos = -1; | |||
| var data = [], | |||
| code = []; | |||
| return { | |||
| next: function () { | |||
| pos++; | |||
| return pos < tokens.length; | |||
| }, | |||
| token: function () { | |||
| return tokens[pos]; | |||
| }, | |||
| pushData: function () { | |||
| var i = data.length; | |||
| data.push.apply(data, arguments); | |||
| return i; | |||
| }, | |||
| pushCode : function() { | |||
| var i = code.length; | |||
| code.push.apply(code, arguments); | |||
| return i; | |||
| }, | |||
| compile: function () { | |||
| var text = "var $p = [];\n" + | |||
| "var print = function(){\n" + | |||
| " $p.push(format.apply(null,arguments));\n" + | |||
| "};\n" + | |||
| // Introduce the data as local variables using with(){} | |||
| "with(obj){\n" + | |||
| code.join("\n") + | |||
| "}\n" + | |||
| "return $p.join('');"; | |||
| try { | |||
| var compiled = new Function("obj, format, $data", text); | |||
| /** | |||
| * Функция форматирования по шаблону | |||
| * | |||
| * @type{Function} | |||
| * @param{Object} obj объект с параметрами для подстановки | |||
| */ | |||
| return function (obj) { | |||
| return compiled(obj || {}, format, data); | |||
| }; | |||
| } catch (e) { | |||
| trace.error([e]); | |||
| trace.log([text, data]); | |||
| throw e; | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| function visitTemplate(context) { | |||
| while (context.next()) { | |||
| switch (context.token()) { | |||
| case "<%": | |||
| case "[%": | |||
| visitCode(context); | |||
| break; | |||
| case "<%=": | |||
| case "[%=": | |||
| visitInline(context); | |||
| break; | |||
| default: | |||
| visitTextFragment(context); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| function visitInline(context) { | |||
| var code = ["$p.push("]; | |||
| while (context.next()) { | |||
| if (context.token() == "%>" || context.token() == "%]") | |||
| break; | |||
| code.push(context.token()); | |||
| } | |||
| code.push(");"); | |||
| context.pushCode(code.join('')); | |||
| } | |||
| function visitCode(context) { | |||
| var code = []; | |||
| while (context.next()) { | |||
| if (context.token() == "%>" || context.token() == "%]") | |||
| break; | |||
| code.push(context.token()); | |||
| } | |||
| context.pushCode(code.join('')); | |||
| } | |||
| function visitTextFragment(context) { | |||
| var i = context.pushData(context.token()); | |||
| context.pushCode("$p.push($data["+i+"]);"); | |||
| } | |||
| var compile = function (str) { | |||
| if (!str) | |||
| return function() { return "";}; | |||
| var ctx = parseTemplate(str); | |||
| visitTemplate(ctx); | |||
| return ctx.compile(); | |||
| }; | |||
| var cache = {}; | |||
| compile.load = function (id, require, callback) { | |||
| var url = require.toUrl(id); | |||
| if (url in cache) { | |||
| callback(cache[url]); | |||
| } else { | |||
| request(url).then(compile).then(function (tc) { | |||
| callback(cache[url] = tc); | |||
| }, function (err) { | |||
| require.signal("error", [{ | |||
| error: err, | |||
| src: 'implab/text/template-compile' | |||
| }]); | |||
| }); | |||
| } | |||
| }; | |||
| return compile; | |||
| }); |
