diff --git a/README.md b/README.md index 7f171ee..b4b00ac 100644 --- a/README.md +++ b/README.md @@ -70,3 +70,9 @@ Laura Doktorova @olado ## License doT is licensed under the MIT License. (See LICENSE-DOT) + +

+ logo by Kevin Kirchner +

+ + diff --git a/benchmarks/templating/doT.js b/benchmarks/templating/doT.js index 3b82453..191b60d 100644 --- a/benchmarks/templating/doT.js +++ b/benchmarks/templating/doT.js @@ -6,7 +6,7 @@ "use strict"; var doT = { - version: '1.0.1', + version: '1.0.2', templateSettings: { evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g, interpolate: /\{\{=([\s\S]+?)\}\}/g, @@ -20,32 +20,34 @@ varname: 'it', strip: true, append: true, - selfcontained: false + selfcontained: false, + doNotSkipEncoded: false }, template: undefined, //fn, compile template compile: undefined //fn, for express + }, _globals; + + doT.encodeHTMLSource = function(doNotSkipEncoded) { + var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }, + matchHTML = doNotSkipEncoded ? /&|<|>|"|'|\//g : /&(?!#?\w+;)|<|>|"|'|\//g; + return function(code) { + return code ? code.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : ""; + }; }; + _globals = (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 { - (function(){ return this || (0,eval)('this'); }()).doT = doT; - } - - function encodeHTMLSource() { - var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }, - matchHTML = /&(?!#?\w+;)|<|>|"|'|\//g; - return function() { - return this ? this.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : this; - }; + _globals.doT = doT; } - String.prototype.encodeHTML = encodeHTMLSource(); var startend = { - append: { start: "'+(", end: ")+'", endencode: "||'').toString().encodeHTML()+'" }, - split: { start: "';out+=(", end: ");out+='", endencode: "||'').toString().encodeHTML();out+='"} + append: { start: "'+(''+", end: ")+'", startencode: "'+encodeHTML(" }, + split: { start: "';out+=(''+", end: ");out+='", startencode: "';out+=encodeHTML(" } }, skip = /$^/; function resolveDefs(c, block, def) { @@ -97,7 +99,7 @@ }) .replace(c.encode || skip, function(m, code) { needhtmlencode = true; - return cse.start + unescape(code) + cse.endencode; + return cse.startencode + unescape(code) + cse.end; }) .replace(c.conditional || skip, function(m, elsecase, code) { return elsecase ? @@ -118,8 +120,11 @@ .replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, '') .replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+='); - if (needhtmlencode && c.selfcontained) { - str = "String.prototype.encodeHTML=(" + encodeHTMLSource.toString() + "());" + str; + if (needhtmlencode) { + if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = doT.encodeHTMLSource(c.doNotSkipEncoded); + str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : (" + + doT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));" + + str; } try { return new Function(c.varname, str); diff --git a/doT.js b/doT.js index 7963629..191b60d 100644 --- a/doT.js +++ b/doT.js @@ -6,7 +6,7 @@ "use strict"; var doT = { - version: '1.0.1', + version: '1.0.2', templateSettings: { evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g, interpolate: /\{\{=([\s\S]+?)\}\}/g, @@ -20,33 +20,34 @@ varname: 'it', strip: true, append: true, - selfcontained: false + selfcontained: false, + doNotSkipEncoded: false }, template: undefined, //fn, compile template compile: undefined //fn, for express - }, global; + }, _globals; + + doT.encodeHTMLSource = function(doNotSkipEncoded) { + var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }, + matchHTML = doNotSkipEncoded ? /&|<|>|"|'|\//g : /&(?!#?\w+;)|<|>|"|'|\//g; + return function(code) { + return code ? code.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : ""; + }; + }; + + _globals = (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 { - global = (function(){ return this || (0,eval)('this'); }()); - global.doT = doT; - } - - function encodeHTMLSource() { - var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }, - matchHTML = /&(?!#?\w+;)|<|>|"|'|\//g; - return function() { - return this ? this.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : this; - }; + _globals.doT = doT; } - String.prototype.encodeHTML = encodeHTMLSource(); var startend = { - append: { start: "'+(", end: ")+'", endencode: "||'').toString().encodeHTML()+'" }, - split: { start: "';out+=(", end: ");out+='", endencode: "||'').toString().encodeHTML();out+='"} + append: { start: "'+(''+", end: ")+'", startencode: "'+encodeHTML(" }, + split: { start: "';out+=(''+", end: ");out+='", startencode: "';out+=encodeHTML(" } }, skip = /$^/; function resolveDefs(c, block, def) { @@ -98,7 +99,7 @@ }) .replace(c.encode || skip, function(m, code) { needhtmlencode = true; - return cse.start + unescape(code) + cse.endencode; + return cse.startencode + unescape(code) + cse.end; }) .replace(c.conditional || skip, function(m, elsecase, code) { return elsecase ? @@ -119,8 +120,11 @@ .replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, '') .replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+='); - if (needhtmlencode && c.selfcontained) { - str = "String.prototype.encodeHTML=(" + encodeHTMLSource.toString() + "());" + str; + if (needhtmlencode) { + if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = doT.encodeHTMLSource(c.doNotSkipEncoded); + str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : (" + + doT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));" + + str; } try { return new Function(c.varname, str); diff --git a/doT.min.js b/doT.min.js index 823cabc..afaf9ba 100644 --- a/doT.min.js +++ b/doT.min.js @@ -1,8 +1,8 @@ /* Laura Doktorova https://github.com/olado/doT */ -(function(){function o(){var a={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},b=/&(?!#?\w+;)|<|>|"|'|\//g;return function(){return this?this.replace(b,function(c){return a[c]||c}):this}}function p(a,b,c){return(typeof b==="string"?b:b.toString()).replace(a.define||i,function(l,e,f,g){if(e.indexOf("def.")===0)e=e.substring(4);if(!(e in c))if(f===":"){a.defineParams&&g.replace(a.defineParams,function(n,h,d){c[e]={arg:h,text:d}});e in c||(c[e]=g)}else(new Function("def","def['"+ -e+"']="+g))(c);return""}).replace(a.use||i,function(l,e){if(a.useParams)e=e.replace(a.useParams,function(g,n,h,d){if(c[h]&&c[h].arg&&d){g=(h+":"+d).replace(/'|\\/g,"_");c.__exp=c.__exp||{};c.__exp[g]=c[h].text.replace(RegExp("(^|[^\\w$])"+c[h].arg+"([^\\w$])","g"),"$1"+d+"$2");return n+"def.__exp['"+g+"']"}});var f=(new Function("def","return "+e))(c);return f?p(a,f,c):f})}function m(a){return a.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var j={version:"1.0.1",templateSettings:{evaluate:/\{\{([\s\S]+?(\}?)+)\}\}/g, -interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,useParams:/(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,defineParams:/^\s*([\w$]+):([\s\S]+)/,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:true,append:true,selfcontained:false},template:undefined, -compile:undefined},q;if(typeof module!=="undefined"&&module.exports)module.exports=j;else if(typeof define==="function"&&define.amd)define(function(){return j});else{q=function(){return this||(0,eval)("this")}();q.doT=j}String.prototype.encodeHTML=o();var r={append:{start:"'+(",end:")+'",endencode:"||'').toString().encodeHTML()+'"},split:{start:"';out+=(",end:");out+='",endencode:"||'').toString().encodeHTML();out+='"}},i=/$^/;j.template=function(a,b,c){b=b||j.templateSettings;var l=b.append?r.append: -r.split,e,f=0,g;a=b.use||b.define?p(b,a,c||{}):a;a=("var out='"+(b.strip?a.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):a).replace(/'|\\/g,"\\$&").replace(b.interpolate||i,function(h,d){return l.start+m(d)+l.end}).replace(b.encode||i,function(h,d){e=true;return l.start+m(d)+l.endencode}).replace(b.conditional||i,function(h,d,k){return d?k?"';}else if("+m(k)+"){out+='":"';}else{out+='":k?"';if("+m(k)+"){out+='":"';}out+='"}).replace(b.iterate||i,function(h, -d,k,s){if(!d)return"';} } out+='";f+=1;g=s||"i"+f;d=m(d);return"';var arr"+f+"="+d+";if(arr"+f+"){var "+k+","+g+"=-1,l"+f+"=arr"+f+".length-1;while("+g+"":">",'"':""","'":"'","/":"/"},d=b?/&|<|>|"|'|\//g:/&(?!#?\w+;)|<|>|"|'|\//g;return function(b){return b? +b.replace(d,function(b){return a[b]||b}):""}};m=function(){return this||(0,eval)("this")}();"undefined"!==typeof module&&module.exports?module.exports=f:"function"===typeof define&&define.amd?define(function(){return f}):m.doT=f;var r={start:"'+(''+",end:")+'",startencode:"'+encodeHTML("},s={start:"';out+=(''+",end:");out+='",startencode:"';out+=encodeHTML("},h=/$^/;f.template=function(b,a,d){a=a||f.templateSettings;var n=a.append?r:s,c,e=0,g;b=a.use||a.define?p(a,b,d||{}):b;b=("var out='"+(a.strip? +b.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):b).replace(/'|\\/g,"\\$&").replace(a.interpolate||h,function(b,a){return n.start+k(a)+n.end}).replace(a.encode||h,function(b,a){c=!0;return n.startencode+k(a)+n.end}).replace(a.conditional||h,function(b,a,c){return a?c?"';}else if("+k(c)+"){out+='":"';}else{out+='":c?"';if("+k(c)+"){out+='":"';}out+='"}).replace(a.iterate||h,function(b,a,c,d){if(!a)return"';} } out+='";e+=1;g=d||"i"+e;a=k(a);return"';var arr"+ +e+"="+a+";if(arr"+e+"){var "+c+","+g+"=-1,l"+e+"=arr"+e+".length-1;while("+g+" + +
Signin
+
+
+ + +
+
+
+ + +
+
+ +
+
+
Signup
+
+
+ + +
+
+
+ + +
+
+ +
+
+ + diff --git a/index.js b/index.js index ac624ae..5f65317 100644 --- a/index.js +++ b/index.js @@ -76,7 +76,7 @@ InstallDots.prototype.compileToFile = function(path, template, def) { } compiled += defaultcompiled.toString().replace('anonymous', modulename); fs.writeFileSync(path, "(function(){" + compiled - + "var itself=" + modulename + ";" + + "var itself=" + modulename + ", _encodeHTML=(" + doT.encodeHTMLSource.toSource() + "(" + (settings.doNotSkipEncoded || '') + "));" + addexports(exports) + "if(typeof module!=='undefined' && module.exports) module.exports=itself;else if(typeof define==='function')define(function(){return itself;});else {" + this.__global + "=" + this.__global + "||{};" + this.__global + "['" + modulename + "']=itself;}}());"); diff --git a/package.json b/package.json index 7eb416c..7ac15fe 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "simple", "templating" ], - "version": "1.0.1", + "version": "1.0.2", "main": "index", "bin": { "dottojs": "./bin/dot-packer" diff --git a/test/testdoT.js b/test/testdoT.js index 2a4ad28..fc9ef7d 100644 --- a/test/testdoT.js +++ b/test/testdoT.js @@ -8,23 +8,54 @@ describe('doT', function(){ describe('#template()', function(){ it('should return a function', function(){ - assert.equal("function", typeof basiccompiled); + assert.equal(typeof basiccompiled, "function"); }); }); describe('#()', function(){ it('should render the template', function(){ - assert.equal("
http
", basiccompiled({foo:"http"})); - assert.equal("
http://abc.com
", basiccompiled({foo:"http://abc.com"})); - assert.equal("
", basiccompiled({})); + assert.equal(basiccompiled({foo:"http"}), "
http
"); + assert.equal(basiccompiled({foo:"http://abc.com"}), "
http://abc.com
"); + assert.equal(basiccompiled({}), "
"); }); }); describe('defines', function(){ it('should render define', function(){ - assert.equal("
http
", definescompiled({foo:"http"})); - assert.equal("
http://abc.com
", definescompiled({foo:"http://abc.com"})); - assert.equal("
", definescompiled({})); + assert.equal(definescompiled({foo:"http"}), "
http
"); + assert.equal(definescompiled({foo:"http://abc.com"}), "
http://abc.com
"); + assert.equal(definescompiled({}), "
"); }); }); + + describe('encoding with doNotSkipEncoded=false', function() { + it('should not replace &', function() { + global._encodeHTML = undefined; + doT.templateSettings.doNotSkipEncoded = false; + assert.equal(doT.template(definestemplate)({foo:"&"}), "
&
"); + }); + }); + + describe('evaluate 2 numbers', function() { + it('should print numbers next to each other', function() { + var fn = doT.template("{{=it.one}}{{=it.two}}"); + assert.equal(fn({one:1, two: 2}), "12"); + }); + }); + + describe('evaluate 2 numbers in the middle', function() { + it('should print numbers next to each other', function() { + var fn = doT.template("{{?it.one}}{{=it.one}}{{?}}{{=it.one}}{{=it.two}}"); + assert.equal(fn({one:1, two: 2}), "112"); + }); + }); + + describe('encoding with doNotSkipEncoded=true', function() { + it('should replace &', function() { + global._encodeHTML = undefined; + doT.templateSettings.doNotSkipEncoded = true; + assert.equal(doT.template(definestemplate)({foo:"&"}), "
&amp;
"); + }); + }); + });