From 2055d745db5ee91e99476e837754d9bc052c3ab7 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Fri, 23 Mar 2012 12:52:50 -0400 Subject: [PATCH 1/2] Attach template source to returned function. --- underscore.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/underscore.js b/underscore.js index aeaa8b1b0..1649df208 100644 --- a/underscore.js +++ b/underscore.js @@ -938,28 +938,30 @@ // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. _.template = function(str, data) { - var c = _.templateSettings; - var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + var settings = _.templateSettings; + var source = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + 'with(obj||{}){__p.push(\'' + str .replace(escaper, function(match) { return '\\' + escapes[match]; }) - .replace(c.escape || noMatch, function(match, code) { - return "',_.escape(" + unescape(code) + "),\n'"; + .replace(settings.escape || noMatch, function(match, code) { + return "',\n_.escape(" + unescape(code) + "),\n'"; }) - .replace(c.interpolate || noMatch, function(match, code) { - return "'," + unescape(code) + ",\n'"; + .replace(settings.interpolate || noMatch, function(match, code) { + return "',\n" + unescape(code) + ",\n'"; }) - .replace(c.evaluate || noMatch, function(match, code) { - return "');" + unescape(code) + ";\n__p.push('"; + .replace(settings.evaluate || noMatch, function(match, code) { + return "');\n" + unescape(code) + "\n;__p.push('"; }) - + "');}return __p.join('');"; - var func = new Function('obj', '_', tmpl); - if (data) return func(data, _); - return function(data) { - return func.call(this, data, _); + + "');\n}\nreturn __p.join('');"; + var render = new Function('obj', '_', source); + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); }; + template.source = 'function(obj, _){\n' + source + '\n}'; + return template; }; // Add a "chain" function, which will delegate to the wrapper. From 2c0ccf03ef1b5d0d54b267341f57fd7f8161b75c Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Mon, 26 Mar 2012 13:37:06 -0400 Subject: [PATCH 2/2] Documentation for `_.template(...).source`. --- index.html | 14 +++++++++++++- underscore.js | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 9b163c16b..99453e2ce 100644 --- a/index.html +++ b/index.html @@ -1327,7 +1327,7 @@ _.result(object, 'stuff');
Compiles JavaScript templates into functions that can be evaluated for rendering. Useful for rendering complicated bits of HTML from JSON - data sources. Template functions can both interpolate variables, using
+ data sources. Template functions can both interpolate variables, using <%= … %>, as well as execute arbitrary JavaScript code, with <% … %>. If you wish to interpolate a value, and have it be HTML-escaped, use <%- … %> When you evaluate a template function, pass in a @@ -1381,6 +1381,18 @@ var template = _.template("Hello {{ name }}!"); template({name : "Mustache"}); => "Hello Mustache!" +

+ Precompiling your templates can be a big help when debugging errors you can't + reproduce. This is because precompiled templates can provide line numbers and + a stack trace, something that is not possible when compiling templates on the client. + template provides the source property on the compiled template + function for easy precompilation. +

+ +
<script>
+  JST.project = <%= _.template(jstText).source %>;
+</script>
+

Chaining

diff --git a/underscore.js b/underscore.js index 1649df208..44226a07c 100644 --- a/underscore.js +++ b/underscore.js @@ -960,7 +960,7 @@ var template = function(data) { return render.call(this, data, _); }; - template.source = 'function(obj, _){\n' + source + '\n}'; + template.source = 'function(obj){\n' + source + '\n}'; return template; };