Permalink
Browse files

new in 0.1.8: 1. faster compilation and HTML encoding 2. fixed minifi…

…ers compatibility 3. pulled conditional else from @lgalfaso 4. pulled AMD support from @satazor 5. encoding of null|undefined strings now does not throw exceptions
  • Loading branch information...
1 parent bcb0238 commit 6078c662353a9838232746fd394d4260d09cc89b @olado committed Apr 21, 2012
Showing with 118 additions and 74 deletions.
  1. +2 −1 benchmarks/compileBench.js
  2. +3 −2 benchmarks/templatesBench.js
  3. +55 −35 benchmarks/templating/doT.js
  4. +55 −35 doT.js
  5. +3 −1 examples/advancedsnippet.txt
@@ -1,10 +1,11 @@
(function() {
var jslitmus, _, doU, doT,
- data = { f1: 1, f2: 2, f3: 3},
+ data = { f1: 1, f2: 2, f3: 3, f4: "http://bebedo.com/laura"},
snippet = "<h1>Just static text</h1>\
<p>Here is a simple {{=it.f1}} </p>\
<div>test {{=it.f2}}\
<div>{{=it.f3}}</div>\
+ <div>{{!it.f4}}</div>\
</div>";
if (typeof module !== 'undefined' && module.exports) {
@@ -1,10 +1,11 @@
(function() {
var jslitmus, _, doU, doT,
- data = { f1: 1, f2: 2, f3: 3},
+ data = { f1: 1, f2: 2, f3: 3, f4: "http://bebedo.com/laura"},
snippet = "<h1>Just static text</h1>\
<p>Here is a simple {{=it.f1}} </p>\
<div>test {{=it.f2}}\
<div>{{=it.f3}}</div>\
+ <div>{{!it.f4}}</div>\
</div>";
if (typeof module !== 'undefined' && module.exports) {
@@ -19,7 +20,7 @@
// doT with 'it'
var doTCompiledParam = doT.template(snippet);
// doT with 'this'
- var doTCompiled = doT.template(snippet.replace(/=it\./g, '=this.'));
+ var doTCompiled = doT.template(snippet.replace(/=it\./g, '=this.').replace(/{{!it\./g, '{{!this.'));
// doT with 'it' and append = false
doT.templateSettings.append = false;
var doTCompiledNoAppend = doT.template(snippet);
@@ -1,84 +1,104 @@
// doT.js
-// 2011, Laura Doktorova
-// https://github.com/olado/doT
+// 2011, Laura Doktorova, https://github.com/olado/doT
//
// doT.js is an open source component of http://bebedo.com
-//
-// doT is a custom blend of templating functions from jQote2.js
-// (jQuery plugin) by aefxx (http://aefxx.com/jquery-plugins/jqote2/)
-// and underscore.js (http://documentcloud.github.com/underscore/)
-// plus extensions.
-//
// Licensed under the MIT license.
//
(function() {
- var doT = { version : '0.1.7' };
+ "use strict";
+
+ var doT = { version : '0.1.8' };
+
+ var global = (function () { return this || (0 || eval)('this'); }());
if (typeof module !== 'undefined' && module.exports) {
module.exports = doT;
+ } else if (typeof define === 'function' && define.amd) {
+ define(function() { return doT; });
} else {
- this.doT = doT;
+ global.doT = doT;
}
doT.templateSettings = {
- evaluate: /\{\{([\s\S]+?)\}\}/g,
- interpolate: /\{\{=([\s\S]+?)\}\}/g,
- encode: /\{\{!([\s\S]+?)\}\}/g,
- use: /\{\{#([\s\S]+?)\}\}/g, //compile time evaluation
- define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g, //compile time defs
+ evaluate: /\{\{([\s\S]+?)\}\}/g,
+ interpolate: /\{\{=([\s\S]+?)\}\}/g,
+ encode: /\{\{!([\s\S]+?)\}\}/g,
+ use: /\{\{#([\s\S]+?)\}\}/g,
+ define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
conditionalStart: /\{\{\?([\s\S]+?)\}\}/g,
- conditionalEnd: /\{\{\?\}\}/g,
+ conditionalElse: /\{\{\?\?\s*([\s\S]*?)\s*\}\}/g,
+ conditionalEnd: /\{\{\?\}\}/g,
varname: 'it',
strip : true,
append: true
};
function resolveDefs(c, block, def) {
return ((typeof block === 'string') ? block : block.toString())
- .replace(c.define, function (match, code, assign, value) {
+ .replace(c.define, function (m, code, assign, value) {
if (code.indexOf('def.') === 0) {
code = code.substring(4);
}
if (!(code in def)) {
if (assign === ':') {
def[code]= value;
} else {
- eval("def[code]=" + value);
+ eval("def['"+code+"']=" + value);
}
}
return '';
})
- .replace(c.use, function(match, code) {
+ .replace(c.use, function(m, code) {
var v = eval(code);
return v ? resolveDefs(c, v, def) : v;
});
}
+ function unescape(code) {
+ return code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ');
+ }
+
+ if (!global.encodeHTML) { // encodeHTML is in global scope for performance :(
+ var encodeHTMLRules = { "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': '&#34;', "'": '&#39;', "/": '&#47;' },
+ matchHTML = /&(?!\\w+;)|<|>|\"|'|\//g;
+ global.encodeHTML = function(code) {
+ return code ? code.toString().replace(matchHTML, function(m) { return encodeHTMLRules[m] || m; }) : code;
+ };
+ }
+
+ var startend = { // optimal choice depends on platform/size of templates
+ append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" },
+ split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML("}
+ };
+
doT.template = function(tmpl, c, def) {
c = c || doT.templateSettings;
- var cstart = c.append ? "'+(" : "';out+=(", // optimal choice depends on platform/size of templates
- cend = c.append ? ")+'" : ");out+='";
- var str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
+ var cse = c.append ? startend.append : startend.split, str;
+
+ if (c.use || c.define) {
+ var olddef = global.def; global.def = def || {}; // workaround minifiers
+ str = resolveDefs(c, tmpl, global.def);
+ if (olddef) global.def = olddef; else delete global.def;
+ } else str = tmpl;
- str = ("var out='" +
- ((c.strip) ? str.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, ''): str)
+ str = ("var out='" + ((c.strip) ? str.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, ''): str)
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
- .replace(c.interpolate, function(match, code) {
- return cstart + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + cend;
+ .replace(c.interpolate, function(m, code) {
+ return cse.start + unescape(code) + cse.end;
})
- .replace(c.encode, function(match, code) {
- return cstart + code.replace(/\\'/g, "'").replace(/\\\\/g, "\\").replace(/[\r\t\n]/g, ' ') + ").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('" + '"' + "').join('&#34;').split(" + '"' + "'" + '"' + ").join('&#39;').split('/').join('&#47;'" + cend;
+ .replace(c.encode, function(m, code) {
+ return cse.startencode + unescape(code) + cse.end;
})
- .replace(c.conditionalEnd, function(match, expression) {
- return "';}out+='";
+ .replace(c.conditionalEnd, "';}out+='")
+ .replace(c.conditionalElse, function(m, code) {
+ return (code) ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='";
})
- .replace(c.conditionalStart, function(match, expression) {
- var code = "if(" + expression + "){";
- return "';" + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + "out+='";
+ .replace(c.conditionalStart, function(m, code) {
+ return "';if(" + unescape(code) + "){out+='";
})
- .replace(c.evaluate, function(match, code) {
- return "';" + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + "out+='";
+ .replace(c.evaluate, function(m, code) {
+ return "';" + unescape(code) + "out+='";
})
+ "';return out;")
.replace(/\n/g, '\\n')
View
90 doT.js
@@ -1,84 +1,104 @@
// doT.js
-// 2011, Laura Doktorova
-// https://github.com/olado/doT
+// 2011, Laura Doktorova, https://github.com/olado/doT
//
// doT.js is an open source component of http://bebedo.com
-//
-// doT is a custom blend of templating functions from jQote2.js
-// (jQuery plugin) by aefxx (http://aefxx.com/jquery-plugins/jqote2/)
-// and underscore.js (http://documentcloud.github.com/underscore/)
-// plus extensions.
-//
// Licensed under the MIT license.
//
(function() {
- var doT = { version : '0.1.7' };
+ "use strict";
+
+ var doT = { version : '0.1.8' };
+
+ var global = (function () { return this || (0 || eval)('this'); }());
if (typeof module !== 'undefined' && module.exports) {
module.exports = doT;
+ } else if (typeof define === 'function' && define.amd) {
+ define(function() { return doT; });
} else {
- this.doT = doT;
+ global.doT = doT;
}
doT.templateSettings = {
- evaluate: /\{\{([\s\S]+?)\}\}/g,
- interpolate: /\{\{=([\s\S]+?)\}\}/g,
- encode: /\{\{!([\s\S]+?)\}\}/g,
- use: /\{\{#([\s\S]+?)\}\}/g, //compile time evaluation
- define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g, //compile time defs
+ evaluate: /\{\{([\s\S]+?)\}\}/g,
+ interpolate: /\{\{=([\s\S]+?)\}\}/g,
+ encode: /\{\{!([\s\S]+?)\}\}/g,
+ use: /\{\{#([\s\S]+?)\}\}/g,
+ define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
conditionalStart: /\{\{\?([\s\S]+?)\}\}/g,
- conditionalEnd: /\{\{\?\}\}/g,
+ conditionalElse: /\{\{\?\?\s*([\s\S]*?)\s*\}\}/g,
+ conditionalEnd: /\{\{\?\}\}/g,
varname: 'it',
strip : true,
append: true
};
function resolveDefs(c, block, def) {
return ((typeof block === 'string') ? block : block.toString())
- .replace(c.define, function (match, code, assign, value) {
+ .replace(c.define, function (m, code, assign, value) {
if (code.indexOf('def.') === 0) {
code = code.substring(4);
}
if (!(code in def)) {
if (assign === ':') {
def[code]= value;
} else {
- eval("def[code]=" + value);
+ eval("def['"+code+"']=" + value);
}
}
return '';
})
- .replace(c.use, function(match, code) {
+ .replace(c.use, function(m, code) {
var v = eval(code);
return v ? resolveDefs(c, v, def) : v;
});
}
+ function unescape(code) {
+ return code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ');
+ }
+
+ if (!global.encodeHTML) { // encodeHTML is in global scope for performance :(
+ var encodeHTMLRules = { "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': '&#34;', "'": '&#39;', "/": '&#47;' },
+ matchHTML = /&(?!\\w+;)|<|>|\"|'|\//g;
+ global.encodeHTML = function(code) {
+ return code ? code.toString().replace(matchHTML, function(m) { return encodeHTMLRules[m] || m; }) : code;
+ };
+ }
+
+ var startend = { // optimal choice depends on platform/size of templates
+ append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" },
+ split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML("}
+ };
+
doT.template = function(tmpl, c, def) {
c = c || doT.templateSettings;
- var cstart = c.append ? "'+(" : "';out+=(", // optimal choice depends on platform/size of templates
- cend = c.append ? ")+'" : ");out+='";
- var str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
+ var cse = c.append ? startend.append : startend.split, str;
+
+ if (c.use || c.define) {
+ var olddef = global.def; global.def = def || {}; // workaround minifiers
+ str = resolveDefs(c, tmpl, global.def);
+ if (olddef) global.def = olddef; else delete global.def;
+ } else str = tmpl;
- str = ("var out='" +
- ((c.strip) ? str.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, ''): str)
+ str = ("var out='" + ((c.strip) ? str.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, ''): str)
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
- .replace(c.interpolate, function(match, code) {
- return cstart + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + cend;
+ .replace(c.interpolate, function(m, code) {
+ return cse.start + unescape(code) + cse.end;
})
- .replace(c.encode, function(match, code) {
- return cstart + code.replace(/\\'/g, "'").replace(/\\\\/g, "\\").replace(/[\r\t\n]/g, ' ') + ").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('" + '"' + "').join('&#34;').split(" + '"' + "'" + '"' + ").join('&#39;').split('/').join('&#47;'" + cend;
+ .replace(c.encode, function(m, code) {
+ return cse.startencode + unescape(code) + cse.end;
})
- .replace(c.conditionalEnd, function(match, expression) {
- return "';}out+='";
+ .replace(c.conditionalEnd, "';}out+='")
+ .replace(c.conditionalElse, function(m, code) {
+ return (code) ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='";
})
- .replace(c.conditionalStart, function(match, expression) {
- var code = "if(" + expression + "){";
- return "';" + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + "out+='";
+ .replace(c.conditionalStart, function(m, code) {
+ return "';if(" + unescape(code) + "){out+='";
})
- .replace(c.evaluate, function(match, code) {
- return "';" + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + "out+='";
+ .replace(c.evaluate, function(m, code) {
+ return "';" + unescape(code) + "out+='";
})
+ "';return out;")
.replace(/\n/g, '\\n')
@@ -54,10 +54,12 @@ Compare xyz to 1, show 'xyz is not 1' if false:
{{#def.fntest()}}
Conditionals:
-{{? it.altEmail }}
+{{? !it.altEmail }}
<p>
second email: {{= it.altEmail }}
</p>
+{{?? true }}
+else case worked
{{?}}

0 comments on commit 6078c66

Please sign in to comment.