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 | 55 ++++++++++++++++++++++++++++-------------------
test/utility.js | 33 +++++++++++++++++-----------
underscore-min.js | 9 ++++----
underscore.js | 27 ++++++++++++-----------
4 files changed, 72 insertions(+), 52 deletions(-)
diff --git a/index.html b/index.html
index 70490a641..1a03be19f 100644
--- a/index.html
+++ b/index.html
@@ -111,11 +111,11 @@ Downloads (Right-click, and u
@@ -979,8 +979,7 @@ Utility Functions
_.uniqueId('contact_');
-=> 'contact_104'
-
+=> 'contact_104'
_.template(templateString, [context])
@@ -988,17 +987,12 @@
Utility Functions
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 @@ Utility Functions
var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
_.template(list, {people : ['moe', 'curly', 'larry']});
-=> "<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>"
-
+=> "<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 @@ Links & Suggested Reading
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;
};