/
hugs.min.js
9 lines (9 loc) · 4.15 KB
/
hugs.min.js
1
2
3
4
5
6
7
8
9
/*
* Simple JavaScript templating system.
* (c) 2010, Borgar Þorsteinsson
*
* Licenced under the terms of the MIT software licence.
* http://www.opensource.org/licenses/mit-license.php
*
*/
(function(n){function m(a,c){for(var b=[],d=0,g=a.length;d<g;d++)b.push(c(a[d],d));return b}function o(a,c){for(var b in c)a[b]=c[b];return a}function l(a){a=Object.prototype.toString.call(a);return a.substring(8,a.length-1).toLowerCase()}function h(a){if(a in h.tmpl)return h.tmpl[a];if(this instanceof h)this.nodes=this.parse(a);else return new h(a)}var e=n.Template=h;e.prototype={render:function(a){if(l(a)==="array"){var c=this;return m(a,function(b){return c.nodes.toString(b)})}return this.nodes.toString(a||{})},parse:function(a,c){if(l(a)==="string"){var b=a.replace(/\{#("(\"|[^"])*?"|'(\'|[^'])*?'|[\S\s])*?#\}/g,"");for(a=[];b.length;){var d=b.match(/^([\S\s]*?)(\{\{("(\"|[^"])*?"|'(\'|[^'])*?'|.)*?\}\})/m);if(d){d[1]&&a.push(d[1]);a.push(d[2]);b=b.substr(d[0].length)}else{a.push(b);b=""}}}for(b=[];a.length;){var g=a.shift();if((d=g.match(/^(\{[\{#])\s*(\=|\w+)((?:(?:\"|[^"])*?"|'(?:\'|[^'])*?'|[\s\S])*?)\s*[\}#]\}$/))&&d[1]==="{{"){var f=d[2],i=d[3];if(c&&f in c){a.unshift(f);return new e.Nodelist(b)}if(e.tags[f]){d=new e.Node(f,i);d.resolve=this.compile_variable(i,g);if(!e.tags[f].single){g=this.parse(a,{"else":1,end:1});f=a.shift();if(f==="else"){d.$TRUE=g;g=this.parse(a,{end:1});f=a.shift()}if(f==="end")if(d.$TRUE!=="")d.$FALSE=g;else d.$TRUE=g;else throw new e.Error("Unexpected termination by "+f);}b.push(d)}else throw new e.Error("Unknown template tag "+f);}else b.push(g)}if(c){a=[];for(var j in c)a.push(j);throw new e.Error("Unmatched block tag, expected: "+a.join(" or "));}return new e.Nodelist(b)},compile_variable:function(a,c){var b=a.replace(/"(?:\\"|[^"])*?"|'(?:\\'|[^'])*?'|[!=]=+|([^<>])[><]=|\b\[/g,"$1");if(/((<<|>?>>|[&\*\+-\/\^\|])?=|\+\+|--|\{|\}|\[)/.test(b))throw new e.Error('Illegal template operator "'+RegExp.lastMatch+'" in '+a);else if(/\b(break|(cas|els|continu|delet|whil)e|(ca|swi)tch|with|default|do|finally|try|for|var|function|return|if|new|throw|void)\b/.test(b))throw new e.Error('Illegal reserved word "'+RegExp.lastMatch+'" in '+a);a=a.replace(/(")((?:\\"|[^"])*?)"|(')((?:\\'|[^'])*?)'/g,function(g,f,i,j,p){return(f||j)+(i||p||"").replace(/(\\(?!["'])|[\n\r\b\t])/g,function(k){k=k.charCodeAt(0).toString(16);return"\\u0000".substring(0,6-k.length)+k})+(f||j)});try{return new Function("","try{with(this){with(Template.vars){with(Template.fn){return ["+a+"];}}}}catch(e){if(Template.SILENT && (e instanceof ReferenceError || e instanceof TypeError)){return [Template.INVALID];}throw e;}")}catch(d){throw new e.Error('Evaluation error in tag "'+c+'"');}}};o(e,{SILENT:true,INVALID:"",render:function(a,c){return(new e(a)).render(c||{})},tags:{"=":{handler:function(a){return a},single:true},"if":{handler:function(a){return(a?this.$TRUE:this.$FALSE)+""}},each:{handler:function(a){var c=this.$TRUE,b=e.vars;if(!a||!a.length||l(a)==="string")return this.$FALSE+"";var d=m(a,function(g,f){b.each={counter:f,first:f===0,last:f===a.length};return c.toString(g)});delete b.each;return d}},include:{handler:function(a){return a in e.tmpl?e.render(a,this):this.$FALSE+""},single:true}},fn:{upper:function(a){return(a+"").toUpperCase()},lower:function(a){return(a+"").toLowerCase()},escape:function(a){return(a+"").replace(/&/g,"&").replace(/"/g,"&quo;").replace(/</g,"<").replace(/>/g,">")}},tmpl:{},vars:{},Error:function(a){this.message=a;this.name="TemplateError";this.toString=function(){return this.name+': "'+this.message+'"'}},Node:function(a,c){this.tag=a;this.args=c;this.$TRUE=this.$FALSE=""},Nodelist:function(a){this.length=0;Array.prototype.push.apply(this,a||[])}});e.Node.prototype={toString:function(a){if(!arguments.length)return"<Template Node>";a=a||{};var c=this.resolve.call(a);a.$TRUE=this.$TRUE;a.$FALSE=this.$FALSE;var b=e.tags[this.tag].handler;if(!b)throw new e.Error('The "'+this.tag+'" tag is missing a handler.');return c.length===1?b.call(a,c[0]):b.apply(a,c)}};e.Nodelist.prototype.toString=function(a){for(var c=[],b=0,d;b<this.length;b++)if((d=this[b].toString(a))&&d.join)c=c.concat(d);else c[c.length]=d;return c.join("")}})(window);