Skip to content
Browse files

mangles

  • Loading branch information...
1 parent a71b250 commit ab3e541367742a1a6ad52dec7b30bfe9ae9dea91 Max Melentiev committed Mar 27, 2013
Showing with 214 additions and 118 deletions.
  1. +24 −1 README.md
  2. +102 −53 doT.js
  3. +1 −1 doT.min.js
  4. +87 −63 src/doT.coffee
View
25 README.md
@@ -60,7 +60,30 @@ All described features did NOT make doT slower. There is `benchmark` folder, try
Instead of this set `doT.templateSettings.startend` directly to one of
`doT.startend.append` (default), `doT.startend.split` or define your one.
-####Add, modify and remove tags
+#### Extend it!
+Template compilation consist of serial mangles: resolving defines, processing tags,
+wrapping it into function's body and, finally, making it js function.
+
+And you have easy access to all of this steps! `doT.mangles` is an object that
+contains functions to be called while mangling template from string to function.
+Every function executes in `doT.templateSettings` context, accepts 2 args: current
+template value and object with compile time variables. Here is an mangle definition
+that wraps function into `with` construction if `doT.templateSettings.with` is set to smth.
+
+```coffee
+mangles['80_with'] = (str, compileParams) ->
+ return str unless @with
+ "with(#{if true == @with then @varname else @with}) {#{str}}"
+```
+
+This functions are called in alphabetical order of their keys. So this function
+will be executed first(it stores original template on input):
+
+```coffee
+doT.mangles["00_test"] = (str, params) -> params.origTmpl = str
+```
+
+##### Add, modify and remove tags
Now it's much easier to modify or add new tags in your templates.
I moved all tag's definitions into `doT.tags` object:
View
155 doT.js
@@ -12,7 +12,7 @@
(function() {
"use strict";
- var cache, doT, resolveDefs, sid, skip, startend, tags, unescape;
+ var cache, doT, mangles, resolveDefs, sid, skip, startend, tags, unescape;
startend = {
append: {
@@ -39,6 +39,7 @@
startend: startend.append
},
startend: startend,
+ mangles: {},
tags: {}
};
@@ -153,44 +154,16 @@
}
};
- if (typeof module !== "undefined" && module !== null ? module.exports : void 0) {
- module.exports = doT;
- } else if (typeof define !== "undefined" && define !== null ? define.amd : void 0) {
- define(function() {
- return doT;
- });
- } else {
- this.doT = doT;
- }
+ mangles = doT.mangles;
- if (!String.prototype.encodeHTML) {
- (function() {
- var match, rules;
- rules = {
- "&": "&",
- "<": "&#60;",
- ">": "&#62;",
- '"': '&#34;',
- "'": '&#39;',
- "/": '&#47;'
- };
- match = /&(?!#?\w+;)|<|>|"|'|\//g;
- return String.prototype.encodeHTML = function() {
- return this.replace(match, function(m) {
- return rules[m] || m;
- });
- };
- })();
- }
-
- unescape = function(code) {
- return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
- };
-
- doT.unescape = unescape;
-
- resolveDefs = function(c, block, def) {
- return (typeof block === "string" ? block : block.toString()).replace(c.define || skip, function(m, code, assign, value) {
+ mangles['05_define'] = resolveDefs = function(block, compileParams) {
+ var c, def;
+ if (!(this.use || this.define)) {
+ return str;
+ }
+ c = this;
+ def = compileParams.def || {};
+ return block.toString().replace(c.define || skip, function(m, code, assign, value) {
if (code.indexOf("def.") === 0) {
code = code.substring(4);
}
@@ -208,7 +181,7 @@
def[code] = value;
}
} else {
- new Function("def", "def['" + code + "']=" + value)(def);
+ new Function("def", "def['" + code + "'] = " + value)(def);
}
}
return "";
@@ -227,40 +200,116 @@
}
v = new Function("def", "return " + code)(def);
if (v) {
- return resolveDefs(c, v, def);
+ return resolveDefs.call(c, v, compileParams);
} else {
return v;
}
});
};
- doT.compile = function(tmpl, def) {
- var c, compile_params, str, t_id, t_name, taglist;
- c = doT.templateSettings;
- str = c.use || c.define ? resolveDefs(c, tmpl, def || {}) : tmpl;
- compile_params = {};
- if (c.strip) {
- str = str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g, ' ').replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g, '');
+ mangles['10_strip'] = function(str, compileParams) {
+ if (!this.strip) {
+ return str;
}
- str = str.replace(/'|\\/g, '\\$&');
+ return str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g, ' ').replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g, '');
+ };
+
+ mangles['20_escape_quotes'] = function(str, compileParams) {
+ return str.replace(/'|\\/g, '\\$&');
+ };
+
+ mangles['50_tags'] = function(str, compileParams) {
+ var t_id, t_name, taglist;
taglist = Object.keys(doT.tags).sort();
for (t_id in taglist) {
t_name = taglist[t_id];
str = str.replace(doT.tags[t_name].regex, function() {
- return doT.tags[t_name].func.apply(compile_params, arguments);
+ return doT.tags[t_name].func.apply(compileParams, arguments);
});
}
- str = (compile_params.multiple_contents ? str = " var out_stack = [], contents = {}, current_out = '_content'; var out = '" + str + "'; contents[current_out] = out; return contents; " : " var out = '" + str + "'; return out; ").replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r').replace(/(\s|;|}|^|{)out\+='';/g, '$1').replace(/\+''/g, '').replace(/(\s|;|}|^|{)out\+=''\+/g, '$1out+=');
- if (c["with"]) {
- str = "with(" + (true === c["with"] ? c.varname : c["with"]) + ") {" + str + "}";
+ return str;
+ };
+
+ mangles['70_escape_spaces'] = function(str, compileParams) {
+ return str.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r');
+ };
+
+ mangles['80_cleanup'] = function(str, compileParams) {
+ return str.replace(/(\s|;|}|^|{)out\+='';/g, '$1').replace(/\s*\+\s*''/g, '').replace(/(\s|;|}|^|{)out\+=''\+/g, '$1out+=');
+ };
+
+ mangles['80_function_basics'] = function(str, compileParams) {
+ if (compileParams.multiple_contents) {
+ return " var out_stack = [], contents = {}, current_out = '_content'; var out = '" + str + "'; contents[current_out] = out; return contents; ";
+ } else {
+ return " var out = '" + str + "'; return out; ";
}
+ };
+
+ mangles['80_with'] = function(str, compileParams) {
+ if (!this["with"]) {
+ return str;
+ }
+ return "with(" + (true === this["with"] ? this.varname : this["with"]) + ") {" + str + "}";
+ };
+
+ mangles['95_functionize'] = function(str, compileParams) {
try {
- return new Function(c.varname, str);
+ return new Function(this.varname, str);
} catch (e) {
throw new Error("" + e + " in \"" + str + "\"");
}
};
+ if (typeof module !== "undefined" && module !== null ? module.exports : void 0) {
+ module.exports = doT;
+ } else if (typeof define !== "undefined" && define !== null ? define.amd : void 0) {
+ define(function() {
+ return doT;
+ });
+ } else {
+ this.doT = doT;
+ }
+
+ if (!String.prototype.encodeHTML) {
+ (function() {
+ var match, rules;
+ rules = {
+ "&": "&#38;",
+ "<": "&#60;",
+ ">": "&#62;",
+ '"': '&#34;',
+ "'": '&#39;',
+ "/": '&#47;'
+ };
+ match = /&(?!#?\w+;)|<|>|"|'|\//g;
+ return String.prototype.encodeHTML = function() {
+ return this.replace(match, function(m) {
+ return rules[m] || m;
+ });
+ };
+ })();
+ }
+
+ unescape = function(code) {
+ return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
+ };
+
+ doT.unescape = unescape;
+
+ doT.compile = function(tmpl, def) {
+ var compile_params, m_id, m_name, mangles_list;
+ compile_params = {
+ def: def
+ };
+ mangles_list = Object.keys(doT.mangles).sort();
+ for (m_id in mangles_list) {
+ m_name = mangles_list[m_id];
+ tmpl = doT.mangles[m_name].call(doT.templateSettings, tmpl, compile_params);
+ }
+ return tmpl;
+ };
+
doT.template = doT.compile;
doT.getCached = function(tmpl) {
View
2 doT.min.js
@@ -1 +1 @@
-(function(){"use strict";var cache,doT,resolveDefs,sid,skip,startend,tags,unescape;startend={append:{start:"' + (",end:") + '",endEncode:").encodeHTML() + '"},split:{start:"'; out += (",end:"); out += '",endEncode:").encodeHTML(); out += '"}};doT={version:"0.2.0",templateSettings:{use:/\{\{#([\s\S]+?)\}\}/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,varname:"it",strip:true,"with":true,dynamicList:"it._dynamic",startend:startend.append},startend:startend,tags:{}};cache={};sid=0;skip=/$^/;tags=doT.tags;tags.interpolate={regex:/\{\{\s*=([\s\S]*?)\}\}/g,func:function(m,code){var cse;cse=doT.templateSettings.startend;return cse.start+unescape(code)+cse.end}};tags.encode={regex:/\{\{\s*!([\s\S]*?)\}\}/g,func:function(m,code){var cse;cse=doT.templateSettings.startend;return cse.start+unescape(code)+cse.endEncode}};tags.conditional={regex:/\{\{\s*\?(\?)?\s*([\s\S]*?)\}\}/g,func:function(m,elsecase,code){if(elsecase){if(code){return"' ; } else if ( "+unescape(code)+" ) { out += '"}else{return"'; } else { out += '"}}else{if(code){return"'; if ( "+unescape(code)+" ) { out += '"}else{return"'; } out += '"}}}};tags.iterate={regex:/\{\{\s*~\s*(?:(\S+?)\s*\:\s*([\w$]+)\s*(?:=>\s*([\w$]+))?\s*)?\}\}/g,func:function(m,iterate,iname,vname){var _ref;if(!iterate){return"'; } } out += '"}if(!vname){_ref=[iname,"i"+ ++sid],vname=_ref[0],iname=_ref[1]}iterate=unescape(iterate);return"'; var arr"+sid+" = "+iterate+"; if( arr"+sid+" ) { var "+vname+", "+iname+" = -1, l"+sid+" = arr"+sid+".length-1; while( "+iname+" < l"+sid+" ){ "+vname+" = arr"+sid+"["+iname+" += 1]; out += '"}};tags.iterateFor={regex:/\{\{\s*:\s*(?:(\S+?)\s*\:\s*([\w$]+)\s*(?:=>\s*([\w$]+))?\s*)?\}\}/g,func:function(m,iterate,iname,vname){var inpname,_ref;if(!iterate){return"'; } } out += '"}inpname="i"+ ++sid;if(!vname){_ref=[iname,"i"+ ++sid],vname=_ref[0],iname=_ref[1]}return"'; var "+inpname+" = "+iterate+"; if ( "+inpname+" ) { var "+vname+", "+iname+"; for ("+iname+" in "+inpname+" ) { "+vname+" = "+inpname+"[ "+iname+" ]; out += '"}};tags.content_for={regex:/\{\{\s*>([\s\S]*?)\}\}/g,func:function(m,id){this.multiple_contents=true;if(id){return"'; contents[current_out] = out; out_stack.push(current_out); current_out='"+unescape(id).trim()+"'; out = contents[current_out] = '"}else{return"'; contents[current_out] = out; out = contents[current_out = out_stack.pop()] += '"}}};tags.xx_includeDynamic={regex:/\{\{\s*@@\s*(\S+?)\(([\s\S]*?)\)\s*\}\}/g,func:function(m,tmpl,args){var vname;sid+=1;vname="tmpl"+sid;return"'; var "+vname+" = "+doT.templateSettings.dynamicList+"[ '"+unescape(tmpl)+"' ]; if ('string' === typeof "+vname+") "+vname+" = {name: "+vname+"}; out += doT.render({name: "+vname+".name, args: "+vname+".args || arguments}) + '"}};tags.xy_render={regex:/\{\{\s*@\s*(\S+?)\(([\s\S]*?)\)\s*\}\}/g,func:function(m,tmpl,args){return"' + doT.render( '"+tmpl+"' "+(args?","+unescape(args):"")+" ) + '"}};tags.zz_evaluate={regex:/\{\{([\s\S]*?)\}\}/g,func:function(m,code){return"'; "+unescape(code)+"; out += '"}};if(typeof module!=="undefined"&&module!==null?module.exports:void 0){module.exports=doT}else if(typeof define!=="undefined"&&define!==null?define.amd:void 0){define(function(){return doT})}else{this.doT=doT}if(!String.prototype.encodeHTML){(function(){var match,rules;rules={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"};match=/&(?!#?\w+;)|<|>|"|'|\//g;return String.prototype.encodeHTML=function(){return this.replace(match,function(m){return rules[m]||m})}})()}unescape=function(code){return code.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")};doT.unescape=unescape;resolveDefs=function(c,block,def){return(typeof block==="string"?block:block.toString()).replace(c.define||skip,function(m,code,assign,value){if(code.indexOf("def.")===0){code=code.substring(4)}if(!(code in def)){if(assign===":"){if(c.defineParams){value.replace(c.defineParams,function(m,param,v){return def[code]={arg:param,text:v}})}if(!(code in def)){def[code]=value}}else{new Function("def","def['"+code+"']="+value)(def)}}return""}).replace(c.use||skip,function(m,code){var v;if(c.useParams){code=code.replace(c.useParams,function(m,s,d,param){var rw;if(def[d]&&def[d].arg&&param){rw=(d+":"+param).replace(/'|\\/g,"_");def.__exp=def.__exp||{};def.__exp[rw]=def[d].text.replace(new RegExp("(^|[^\\w$])"+def[d].arg+"([^\\w$])","g"),"$1"+param+"$2");return s+("def.__exp['"+rw+"']")}})}v=new Function("def","return "+code)(def);if(v){return resolveDefs(c,v,def)}else{return v}})};doT.compile=function(tmpl,def){var c,compile_params,str,t_id,t_name,taglist;c=doT.templateSettings;str=c.use||c.define?resolveDefs(c,tmpl,def||{}):tmpl;compile_params={};if(c.strip){str=str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,"")}str=str.replace(/'|\\/g,"\\$&");taglist=Object.keys(doT.tags).sort();for(t_id in taglist){t_name=taglist[t_id];str=str.replace(doT.tags[t_name].regex,function(){return doT.tags[t_name].func.apply(compile_params,arguments)})}str=(compile_params.multiple_contents?str=" var out_stack = [], contents = {}, current_out = '_content'; var out = '"+str+"'; contents[current_out] = out; return contents; ":" var out = '"+str+"'; return out; ").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|}|^|{)out\+='';/g,"$1").replace(/\+''/g,"").replace(/(\s|;|}|^|{)out\+=''\+/g,"$1out+=");if(c["with"]){str="with("+(true===c["with"]?c.varname:c["with"])+") {"+str+"}"}try{return new Function(c.varname,str)}catch(e){throw new Error(""+e+' in "'+str+'"')}};doT.template=doT.compile;doT.getCached=function(tmpl){if(!tmpl){return cache}if(!cache[tmpl]){throw new Error("Template not found: "+tmpl)}return cache[tmpl]};doT.setCached=function(fns){return cache=fns};doT.exportCached=function(){var f,id,str;str="";for(id in cache){f=cache[id];str+=',"'+id+'": '+f.toString()}return"{"+str.substring(1)+"}"};doT.addCached=function(id,fn){var f,i;if("object"===typeof id){for(i in id){f=id[i];doT.addCached(i,f)}return}return cache[id]=fn};doT.render=function(tmpl){var src;"object"!==typeof tmpl&&(tmpl={name:tmpl});if(!cache[tmpl.name]){src=doT.autoload(tmpl.name);if(false===src){throw new Error("Template not found: "+tmpl.name)}doT.addCached(tmpl.name,doT.compile(src))}return cache[tmpl.name].apply(this,tmpl.args||Array.prototype.slice.call(arguments,1))};doT.autoloadDOM=function(opts){return function(name){var src;src=document.getElementById(name);if(!src||!src.type||"text/x-dot-tmpl"!==src.type){return false}else{return src.innerHTML}}};doT.autoloadFS=function(opts){return function(name){try{return opts.fs.readFileSync(""+opts.root+"/"+name.replace(".","/")+".tmpl")}catch(e){return false}}};doT.autoloadFail=function(){return false};doT.autoload=doT.autoloadDOM()}).call(this);
+(function(){"use strict";var cache,doT,mangles,resolveDefs,sid,skip,startend,tags,unescape;startend={append:{start:"' + (",end:") + '",endEncode:").encodeHTML() + '"},split:{start:"'; out += (",end:"); out += '",endEncode:").encodeHTML(); out += '"}};doT={version:"0.2.0",templateSettings:{use:/\{\{#([\s\S]+?)\}\}/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,varname:"it",strip:true,"with":true,dynamicList:"it._dynamic",startend:startend.append},startend:startend,mangles:{},tags:{}};cache={};sid=0;skip=/$^/;tags=doT.tags;tags.interpolate={regex:/\{\{\s*=([\s\S]*?)\}\}/g,func:function(m,code){var cse;cse=doT.templateSettings.startend;return cse.start+unescape(code)+cse.end}};tags.encode={regex:/\{\{\s*!([\s\S]*?)\}\}/g,func:function(m,code){var cse;cse=doT.templateSettings.startend;return cse.start+unescape(code)+cse.endEncode}};tags.conditional={regex:/\{\{\s*\?(\?)?\s*([\s\S]*?)\}\}/g,func:function(m,elsecase,code){if(elsecase){if(code){return"' ; } else if ( "+unescape(code)+" ) { out += '"}else{return"'; } else { out += '"}}else{if(code){return"'; if ( "+unescape(code)+" ) { out += '"}else{return"'; } out += '"}}}};tags.iterate={regex:/\{\{\s*~\s*(?:(\S+?)\s*\:\s*([\w$]+)\s*(?:=>\s*([\w$]+))?\s*)?\}\}/g,func:function(m,iterate,iname,vname){var _ref;if(!iterate){return"'; } } out += '"}if(!vname){_ref=[iname,"i"+ ++sid],vname=_ref[0],iname=_ref[1]}iterate=unescape(iterate);return"'; var arr"+sid+" = "+iterate+"; if( arr"+sid+" ) { var "+vname+", "+iname+" = -1, l"+sid+" = arr"+sid+".length-1; while( "+iname+" < l"+sid+" ){ "+vname+" = arr"+sid+"["+iname+" += 1]; out += '"}};tags.iterateFor={regex:/\{\{\s*:\s*(?:(\S+?)\s*\:\s*([\w$]+)\s*(?:=>\s*([\w$]+))?\s*)?\}\}/g,func:function(m,iterate,iname,vname){var inpname,_ref;if(!iterate){return"'; } } out += '"}inpname="i"+ ++sid;if(!vname){_ref=[iname,"i"+ ++sid],vname=_ref[0],iname=_ref[1]}return"'; var "+inpname+" = "+iterate+"; if ( "+inpname+" ) { var "+vname+", "+iname+"; for ("+iname+" in "+inpname+" ) { "+vname+" = "+inpname+"[ "+iname+" ]; out += '"}};tags.content_for={regex:/\{\{\s*>([\s\S]*?)\}\}/g,func:function(m,id){this.multiple_contents=true;if(id){return"'; contents[current_out] = out; out_stack.push(current_out); current_out='"+unescape(id).trim()+"'; out = contents[current_out] = '"}else{return"'; contents[current_out] = out; out = contents[current_out = out_stack.pop()] += '"}}};tags.xx_includeDynamic={regex:/\{\{\s*@@\s*(\S+?)\(([\s\S]*?)\)\s*\}\}/g,func:function(m,tmpl,args){var vname;sid+=1;vname="tmpl"+sid;return"'; var "+vname+" = "+doT.templateSettings.dynamicList+"[ '"+unescape(tmpl)+"' ]; if ('string' === typeof "+vname+") "+vname+" = {name: "+vname+"}; out += doT.render({name: "+vname+".name, args: "+vname+".args || arguments}) + '"}};tags.xy_render={regex:/\{\{\s*@\s*(\S+?)\(([\s\S]*?)\)\s*\}\}/g,func:function(m,tmpl,args){return"' + doT.render( '"+tmpl+"' "+(args?","+unescape(args):"")+" ) + '"}};tags.zz_evaluate={regex:/\{\{([\s\S]*?)\}\}/g,func:function(m,code){return"'; "+unescape(code)+"; out += '"}};mangles=doT.mangles;mangles["05_define"]=resolveDefs=function(block,compileParams){var c,def;if(!(this.use||this.define)){return str}c=this;def=compileParams.def||{};return block.toString().replace(c.define||skip,function(m,code,assign,value){if(code.indexOf("def.")===0){code=code.substring(4)}if(!(code in def)){if(assign===":"){if(c.defineParams){value.replace(c.defineParams,function(m,param,v){return def[code]={arg:param,text:v}})}if(!(code in def)){def[code]=value}}else{new Function("def","def['"+code+"'] = "+value)(def)}}return""}).replace(c.use||skip,function(m,code){var v;if(c.useParams){code=code.replace(c.useParams,function(m,s,d,param){var rw;if(def[d]&&def[d].arg&&param){rw=(d+":"+param).replace(/'|\\/g,"_");def.__exp=def.__exp||{};def.__exp[rw]=def[d].text.replace(new RegExp("(^|[^\\w$])"+def[d].arg+"([^\\w$])","g"),"$1"+param+"$2");return s+("def.__exp['"+rw+"']")}})}v=new Function("def","return "+code)(def);if(v){return resolveDefs.call(c,v,compileParams)}else{return v}})};mangles["10_strip"]=function(str,compileParams){if(!this.strip){return str}return str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,"")};mangles["20_escape_quotes"]=function(str,compileParams){return str.replace(/'|\\/g,"\\$&")};mangles["50_tags"]=function(str,compileParams){var t_id,t_name,taglist;taglist=Object.keys(doT.tags).sort();for(t_id in taglist){t_name=taglist[t_id];str=str.replace(doT.tags[t_name].regex,function(){return doT.tags[t_name].func.apply(compileParams,arguments)})}return str};mangles["70_escape_spaces"]=function(str,compileParams){return str.replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r")};mangles["80_cleanup"]=function(str,compileParams){return str.replace(/(\s|;|}|^|{)out\+='';/g,"$1").replace(/\s*\+\s*''/g,"").replace(/(\s|;|}|^|{)out\+=''\+/g,"$1out+=")};mangles["80_function_basics"]=function(str,compileParams){if(compileParams.multiple_contents){return" var out_stack = [], contents = {}, current_out = '_content'; var out = '"+str+"'; contents[current_out] = out; return contents; "}else{return" var out = '"+str+"'; return out; "}};mangles["80_with"]=function(str,compileParams){if(!this["with"]){return str}return"with("+(true===this["with"]?this.varname:this["with"])+") {"+str+"}"};mangles["95_functionize"]=function(str,compileParams){try{return new Function(this.varname,str)}catch(e){throw new Error(""+e+' in "'+str+'"')}};if(typeof module!=="undefined"&&module!==null?module.exports:void 0){module.exports=doT}else if(typeof define!=="undefined"&&define!==null?define.amd:void 0){define(function(){return doT})}else{this.doT=doT}if(!String.prototype.encodeHTML){(function(){var match,rules;rules={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"};match=/&(?!#?\w+;)|<|>|"|'|\//g;return String.prototype.encodeHTML=function(){return this.replace(match,function(m){return rules[m]||m})}})()}unescape=function(code){return code.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")};doT.unescape=unescape;doT.compile=function(tmpl,def){var compile_params,m_id,m_name,mangles_list;compile_params={def:def};mangles_list=Object.keys(doT.mangles).sort();for(m_id in mangles_list){m_name=mangles_list[m_id];tmpl=doT.mangles[m_name].call(doT.templateSettings,tmpl,compile_params)}return tmpl};doT.template=doT.compile;doT.getCached=function(tmpl){if(!tmpl){return cache}if(!cache[tmpl]){throw new Error("Template not found: "+tmpl)}return cache[tmpl]};doT.setCached=function(fns){return cache=fns};doT.exportCached=function(){var f,id,str;str="";for(id in cache){f=cache[id];str+=',"'+id+'": '+f.toString()}return"{"+str.substring(1)+"}"};doT.addCached=function(id,fn){var f,i;if("object"===typeof id){for(i in id){f=id[i];doT.addCached(i,f)}return}return cache[id]=fn};doT.render=function(tmpl){var src;"object"!==typeof tmpl&&(tmpl={name:tmpl});if(!cache[tmpl.name]){src=doT.autoload(tmpl.name);if(false===src){throw new Error("Template not found: "+tmpl.name)}doT.addCached(tmpl.name,doT.compile(src))}return cache[tmpl.name].apply(this,tmpl.args||Array.prototype.slice.call(arguments,1))};doT.autoloadDOM=function(opts){return function(name){var src;src=document.getElementById(name);if(!src||!src.type||"text/x-dot-tmpl"!==src.type){return false}else{return src.innerHTML}}};doT.autoloadFS=function(opts){return function(name){try{return opts.fs.readFileSync(""+opts.root+"/"+name.replace(".","/")+".tmpl")}catch(e){return false}}};doT.autoloadFail=function(){return false};doT.autoload=doT.autoloadDOM()}).call(this);
View
150 src/doT.coffee
@@ -28,6 +28,7 @@ doT =
dynamicList: 'it._dynamic'
startend: startend.append
startend: startend
+ mangles: {}
tags: {}
cache = {}
@@ -127,30 +128,14 @@ tags.zz_evaluate =
func: (m, code) ->
"'; #{unescape(code)}; out += '"
-# register in global scope
-if module?.exports
- module.exports = doT
-else if define?.amd
- define -> doT
-else
- @doT = doT
-
-unless String::encodeHTML
- (->
- rules = "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': '&#34;', "'": '&#39;', "/": '&#47;'
- match = /&(?!#?\w+;)|<|>|"|'|\//g
- String::encodeHTML = -> @replace( match, (m) -> rules[m] || m )
- )()
-
-unescape = (code) ->
- code.replace( /\\('|\\)/g, "$1" ).replace( /[\r\t\n]/g, ' ' )
-doT.unescape = unescape
-
-# template compilation
-resolveDefs = (c, block, def) ->
- (
- (if (typeof block is "string") then block else block.toString())
- ).replace(c.define or skip, (m, code, assign, value) ->
+# mangles definition
+mangles = doT.mangles
+mangles['05_define'] = resolveDefs = (block, compileParams) ->
+ return str unless @use || @define
+ c = @
+ def = compileParams.def || {}
+ block.toString()
+ .replace c.define or skip, (m, code, assign, value) ->
code = code.substring(4) if code.indexOf("def.") is 0
unless code of def
if assign is ":"
@@ -159,65 +144,105 @@ resolveDefs = (c, block, def) ->
def[code] =
arg: param
text: v
-
def[code] = value unless code of def
else
- new Function("def", "def['" + code + "']=" + value) def
+ new Function("def", "def['#{code}'] = #{value}") def
""
- ).replace c.use or skip, (m, code) ->
+ .replace c.use or skip, (m, code) ->
if c.useParams
code = code.replace(c.useParams, (m, s, d, param) ->
if def[d] and def[d].arg and param
rw = (d + ":" + param).replace(/'|\\/g, "_")
# gtksourceview '
def.__exp = def.__exp or {}
- def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])#{def[d].arg}([^\\w$])", "g"), "$1#{param}$2")
+ def.__exp[rw] = def[d].text.replace(
+ new RegExp "(^|[^\\w$])#{def[d].arg}([^\\w$])", "g"
+ "$1#{param}$2"
+ )
s + "def.__exp['#{rw}']"
)
v = new Function("def", "return " + code)(def)
- (if v then resolveDefs(c, v, def) else v)
+ if v then resolveDefs.call c, v, compileParams else v
-doT.compile = (tmpl, def) ->
- c = doT.templateSettings
- str = if (c.use || c.define) then resolveDefs(c, tmpl, def || {}) else tmpl
- compile_params = {}
-
- if c.strip
- str = str.replace( /(^|\r|\n)\t* +| +\t*(\r|\n|$)/g , ' ' )
- .replace( /\r|\n|\t|\/\*[\s\S]*?\*\//g, '' )
- str = str.replace /'|\\/g, '\\$&'
+mangles['10_strip'] = (str, compileParams) ->
+ return str unless @strip
+ str
+ .replace( /(^|\r|\n)\t* +| +\t*(\r|\n|$)/g , ' ' )
+ .replace( /\r|\n|\t|\/\*[\s\S]*?\*\//g, '' )
+
+mangles['20_escape_quotes'] = (str, compileParams) ->
+ str.replace /'|\\/g, '\\$&'
# gtksourceview '
+
+mangles['50_tags'] = (str, compileParams) ->
taglist = Object.keys(doT.tags).sort()
for t_id, t_name of taglist
str = str.replace doT.tags[ t_name ].regex, ->
- doT.tags[ t_name ].func.apply compile_params, arguments
-
- str = (
- if compile_params.multiple_contents
- str = "
- var out_stack = [], contents = {}, current_out = '_content';
- var out = '#{str}';
- contents[current_out] = out;
- return contents;
- "
- else
- " var out = '#{str}';
- return out;
- "
- )
- .replace( /\n/g, '\\n' )
- .replace( /\t/g, '\\t' )
- .replace( /\r/g, '\\r' )
- .replace( /(\s|;|}|^|{)out\+='';/g, '$1' )
- .replace( /\+''/g, '' )
- .replace( /(\s|;|}|^|{)out\+=''\+/g, '$1out+=' )
- if c.with
- str = "with(#{if true == c.with then c.varname else c.with}) {#{str}}"
+ doT.tags[ t_name ].func.apply compileParams, arguments
+ str
+
+mangles['70_escape_spaces'] = (str, compileParams) ->
+ str
+ .replace( /\n/g, '\\n' )
+ .replace( /\t/g, '\\t' )
+ .replace( /\r/g, '\\r' )
+
+mangles['80_cleanup'] = (str, compileParams) ->
+ str
+ .replace( /(\s|;|}|^|{)out\+='';/g, '$1' )
+ .replace( /\s*\+\s*''/g, '' )
+ .replace( /(\s|;|}|^|{)out\+=''\+/g, '$1out+=' )
+
+mangles['80_function_basics'] = (str, compileParams) ->
+ if compileParams.multiple_contents
+ "
+ var out_stack = [], contents = {}, current_out = '_content';
+ var out = '#{str}';
+ contents[current_out] = out;
+ return contents;
+ "
+ else
+ " var out = '#{str}';
+ return out;
+ "
+
+mangles['80_with'] = (str, compileParams) ->
+ return str unless @with
+ "with(#{if true == @with then @varname else @with}) {#{str}}"
+
+mangles['95_functionize'] = (str, compileParams) ->
try
- new Function c.varname, str
+ new Function @varname, str
catch e
throw new Error "#{e} in \"#{str}\""
+# register in global scope
+if module?.exports
+ module.exports = doT
+else if define?.amd
+ define -> doT
+else
+ @doT = doT
+
+unless String::encodeHTML
+ (->
+ rules = "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': '&#34;', "'": '&#39;', "/": '&#47;'
+ match = /&(?!#?\w+;)|<|>|"|'|\//g
+ String::encodeHTML = -> @replace( match, (m) -> rules[m] || m )
+ )()
+
+unescape = (code) ->
+ code.replace( /\\('|\\)/g, "$1" ).replace( /[\r\t\n]/g, ' ' )
+doT.unescape = unescape
+
+# template compilation
+doT.compile = (tmpl, def) ->
+ compile_params = def: def
+ mangles_list = Object.keys(doT.mangles).sort()
+ for m_id, m_name of mangles_list
+ tmpl = doT.mangles[ m_name ].call doT.templateSettings, tmpl, compile_params
+ tmpl
+
# backward compability
doT.template = doT.compile
@@ -267,4 +292,3 @@ doT.autoloadFS = ( opts ) ->
doT.autoloadFail = () -> false
doT.autoload = doT.autoloadDOM();
-

0 comments on commit ab3e541

Please sign in to comment.
Something went wrong with that request. Please try again.