From 7d9e603be862a66a093c0062a580d5fc8c95ce1b Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Mon, 18 Jan 2010 12:45:04 -0500
Subject: [PATCH] Underscore 0.5.6, with custom template delimiters
---
index.html | 53 ++++++++++++++++++++++++++++-------------------
test/utility.js | 33 +++++++++++++++++------------
underscore-min.js | 9 ++++----
underscore.js | 27 ++++++++++++------------
4 files changed, 71 insertions(+), 51 deletions(-)
diff --git a/index.html b/index.html
index 70490a641..1a03be19f 100644
--- a/index.html
+++ b/index.html
@@ -111,11 +111,11 @@
@@ -979,8 +979,7 @@ result;
_.uniqueId('contact_');
-=> 'contact_104'
-
+=> 'contact_104'
_.template(templateString, [context])
@@ -988,17 +987,12 @@ _.uniqueId('contact_');
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
- <%= … %>, as well as execute arbitrary JavaScript code, with
- <% … %>. When you evaluate a template function, pass in a
+ <%= … %>, as well as execute arbitrary JavaScript code, with
+ <% … %>. When you evaluate a template function, pass in a
context object that has properties corresponding to the template's free
variables. If you're writing a one-off, you can pass the context
object as the second parameter to template in order to render
immediately instead of returning a template function.
-
- If the <% … %> syntax is not convenient because
- your templating languages assigns special meaning to it, the delimeters
- can be customized by passing an object as the first argument. See the
- code sample below for options.
var compiled = _.template("hello: <%= name %>");
@@ -1007,17 +1001,28 @@ compiled({name : 'moe'});
var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
_.template(list, {people : ['moe', 'curly', 'larry']});
-=> "<li>moe</li><li>curly</li><li>larry</li>"
+=> "<li>moe</li><li>curly</li><li>larry</li>"
-var custom = "{{ _.each(people, function(name) { }} <li>{{= name }}</li> {{ }); }}";
-_.template({
- template: custom,
- start: '{{', // the code start delimeter
- end: '}}', // the code end delimeter
- interpolate: /\{\{=(.+?)\}\}/g // a regex with 1 capture group for the var name
-}, {people : ['moe', 'curly', 'larry']});
-=> "<li>moe</li><li>curly</li><li>larry</li>"
-
+
+ If ERB-style delimiters aren't your cup of tea, you can change Underscore's
+ template settings to use different symbols to set off interpolated code.
+ Define start and end tokens, and an interpolate regex
+ to match expressions that should be evaluated and inserted. For example,
+ to perform
+ Mustache.js
+ style templating:
+
+
+
+_.templateSettings = {
+ start : '{{',
+ end : '}}',
+ interpolate : /\{\{(.+?)\}\}/g
+};
+
+var template = _.template("Hello {{ name }}!");
+template({name : "Mustache"});
+=> "Hello Mustache!"
Chaining
@@ -1079,6 +1084,12 @@ _([1, 2, 3]).value();
Change Log
+
+
+ Customizable delimiters for _.template, contributed by
+ Noah Sloan.
+
+
Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object.
diff --git a/test/utility.js b/test/utility.js
index 93263c9c6..763a48036 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -39,23 +39,30 @@ $(document).ready(function() {
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equals(result, "
", 'can run arbitrary javascript in templates');
- var custom = _.template({
- template: "{{ for (key in people) { }}- {{= people[key] }}
{{ } }}
",
- start: "{{", end: "}}",
- interpolate: /\{\{=(.+?)\}\}/g
- });
- result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equals(result, "", 'can run arbitrary javascript in templates');
-
var quoteTemplate = _.template("It's its, not it's");
equals(quoteTemplate({}), "It's its, not it's");
- var customQuote = _.template({
- template: "It's its, not it's",
- start: "{{", end: "}}",
- interpolate: /\{\{=(.+?)\}\}/g
- });
+ _.templateSettings = {
+ start : '{{',
+ end : '}}',
+ interpolate : /\{\{=(.+?)\}\}/g
+ };
+
+ var custom = _.template("{{ for (key in people) { }}- {{= people[key] }}
{{ } }}
");
+ result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
+ equals(result, "", 'can run arbitrary javascript in templates');
+
+ var customQuote = _.template("It's its, not it's");
equals(customQuote({}), "It's its, not it's");
+
+ _.templateSettings = {
+ start : '{{',
+ end : '}}',
+ interpolate : /\{\{(.+?)\}\}/g
+ };
+
+ var mustache = _.template("Hello {{planet}}!");
+ equals(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
});
});
diff --git a/underscore-min.js b/underscore-min.js
index 9146e0860..2c8b49988 100644
--- a/underscore-min.js
+++ b/underscore-min.js
@@ -1,4 +1,4 @@
-(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
-o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
+a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.templateSettings={start:"<%",end:"%>",interpolate:/<%=(.+?)%>/g};b.template=function(a,c){var d=b.templateSettings;a=new Function("obj",
+"var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").replace(new RegExp("'(?=[^"+d.end[0]+"]*"+d.end+")","g"),"\t").split("'").join("\\'").split("\t").join("'").replace(d.interpolate,"',$1,'").split(d.start).join("');").split(d.end).join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;
+var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,
+arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
diff --git a/underscore.js b/underscore.js
index c0f901651..cb620b4fd 100644
--- a/underscore.js
+++ b/underscore.js
@@ -38,7 +38,7 @@
propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
// Current version.
- _.VERSION = '0.5.5';
+ _.VERSION = '0.5.6';
// ------------------------ Collection Functions: ---------------------------
@@ -559,28 +559,29 @@
return prefix ? prefix + id : id;
};
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ start : '<%',
+ end : '%>',
+ interpolate : /<%=(.+?)%>/g
+ };
+
// JavaScript templating a-la ERB, pilfered from John Resig's
// "Secrets of the JavaScript Ninja", page 83.
// Single-quote fix from Rick Strahl's version.
_.template = function(str, data) {
- var start = '<%', end = '%>',
- interpolate = /<%=(.+?)%>/g;
- if(str && !_.isString(str)) {
- start = str.start || start;
- end = str.end || end;
- interpolate = str.interpolate || interpolate;
- str = str.template;
- }
+ var c = _.templateSettings;
var fn = new Function('obj',
'var p=[],print=function(){p.push.apply(p,arguments);};' +
'with(obj){p.push(\'' +
str.replace(/[\r\t\n]/g, " ")
- .replace(new RegExp("'(?=[^"+end[0]+"]*"+end+")","g"),"\t")
+ .replace(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
.split("'").join("\\'")
.split("\t").join("'")
- .replace(interpolate, "',$1,'")
- .split(start).join("');")
- .split(end).join("p.push('")
+ .replace(c.interpolate, "',$1,'")
+ .split(c.start).join("');")
+ .split(c.end).join("p.push('")
+ "');}return p.join('');");
return data ? fn(data) : fn;
};