diff core/src/js/text/template-compile.js @ 34:27e8e9e38e07 default tip

Слияние
author nickolay
date Wed, 05 Jun 2019 20:44:15 +0300
parents acdcdf1a8d21
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/text/template-compile.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,134 @@
+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;
+    });
\ No newline at end of file