diff --git a/Changelog b/Changelog index bf1f7ad..a09bf16 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,11 @@ +1.3.3-alpha / 2016-09-15 +================== + +* Tags `increment`, `decrement` +* Money filters `money`, `money_with_currency`, `money_without_trailing_zeros`, `money_without_currency` +* Math filters `ceil`, `floor`, `round` +* Fix range to support variable, eg. (start..end) + 1.3.2 / 2015-04-27 ================== diff --git a/Gemfile b/Gemfile index d2a05fd..c310fc5 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,4 @@ source 'http://rubygems.org' gem 'sprockets', '~>1.0.2' gem 'rake', '~> 10.4.2' +gem 'listen', '~> 3.1.5' diff --git a/dist/liquid.js b/dist/liquid.js index 5aff343..1356344 100644 --- a/dist/liquid.js +++ b/dist/liquid.js @@ -406,16 +406,22 @@ Liquid.Context = Liquid.Class.extend({ left = parseInt(range[1]), right = parseInt(range[2]), arr = []; - if (isNaN(left) || isNaN(right)) { - left = range[1].charCodeAt(0); - right = range[2].charCodeAt(0); - - var limit = right-left+1; - for (var i=0; i 0 ? '.' + dp : ''); + } catch(e){} + return ret; + } +}; + Liquid.Template.registerFilter({ _HTML_ESCAPE_MAP: { @@ -1444,6 +1479,19 @@ Liquid.Template.registerFilter({ return (Number(input) || 0) % (Number(number) || 0); }, + ceil: function(input) { + return Math.ceil(Number(input) || 0); + }, + + floor: function(input) { + return Math.floor(Number(input) || 0); + }, + + round: function(input, dp) { + let pow = Math.pow(10, dp || 0); + return Math.round((Number(input) || 0) * pow) / pow; + }, + map: function(input, property) { input = input || []; var results = []; @@ -1473,10 +1521,28 @@ Liquid.Template.registerFilter({ append: function(input, string) { return '' + (input || '').toString() + (string || '').toString(); - } + }, + + money: function(input){ + return Money.format(input, Money.getCurrencySign(), false); + }, + + money_with_currency: function(input){ + return Money.format(input, Money.getCurrencySign(), false) + Money.getCurrencyCode(); + }, + + money_without_trailing_zeros: function(input){ + return Money.format(input, Money.getCurrencySign(), true); + }, + + money_without_currency: function(input){ + return Money.format(input, '', false); + }, }); +})(Liquid); + if(!(new Date()).strftime) {(function(){ Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(x,pad,r){if(typeof (r)=="undefined"){r=10}for(;parseInt(x,10)1;r/=10){x=pad.toString()+x}return x.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"}; diff --git a/dist/liquid.min.js b/dist/liquid.min.js index 1df3f39..163101d 100644 --- a/dist/liquid.min.js +++ b/dist/liquid.min.js @@ -30,8 +30,9 @@ else if((/^(\d+)$/).test(key)) {return parseInt(key.replace(/^(\d+)$/,'$1'));} else if((/^(\d[\d\.]+)$/).test(key)) {return parseFloat(key.replace(/^(\d[\d\.]+)$/,'$1'));} -else if((/^\((\S+)\.\.(\S+)\)$/).test(key)){var range=key.match(/^\((\S+)\.\.(\S+)\)$/),left=parseInt(range[1]),right=parseInt(range[2]),arr=[];if(isNaN(left)||isNaN(right)){left=range[1].charCodeAt(0);right=range[2].charCodeAt(0);var limit=right-left+1;for(var i=0;i':'>','<':'<','"':'"',"'":'''},size:function(iterable){return(iterable['length'])?iterable.length:0;},downcase:function(input){return input.toString().toLowerCase();},upcase:function(input){return input.toString().toUpperCase();},capitalize:function(input){return Liquid.extensions.stringTools.capitalize(input.toString());},escape:function(input){var self=this;return input.replace(/[&<>"']/g,function(chr){return self._HTML_ESCAPE_MAP[chr];});},h:function(input){var self=this;return input.replace(/[&<>"']/g,function(chr){return self._HTML_ESCAPE_MAP[chr];});},default:function(input,default_value){return Liquid.extensions.object.isEmpty(input)?default_value:input;},truncate:function(input,length,string){if(!input||input==''){return'';} +output=String(context.registers['decrement'][key]);context.registers['decrement'][key]--;return output;}}));(function(Liquid){var Money={getCurrencySign:function(){var currencySign='$';return currencySign;},getCurrencyCode:function(){var currencyCode='';return currencyCode?' '+currencyCode:'';},format:function(num,currencySign,trimZero){var ret='0.00';try{num=parseFloat((''+num)||ret);if(trimZero!==true){num=Math.round(num*100)/100;} +var tokens=(''+num).match(/^(-?)(\d+)(.(\d+))?$/)||[];var sign=tokens[1]||'';var digit=tokens[2]||'0';var dp=((tokens[4]||'')+'00');if(trimZero){dp=dp.replace(/0+$/,'');}else{dp=dp.substr(0,2);} +ret=sign+currencySign+digit+(dp.length>0?'.'+dp:'');}catch(e){} +return ret;}};Liquid.Template.registerFilter({_HTML_ESCAPE_MAP:{'&':'&','>':'>','<':'<','"':'"',"'":'''},size:function(iterable){return(iterable['length'])?iterable.length:0;},downcase:function(input){return input.toString().toLowerCase();},upcase:function(input){return input.toString().toUpperCase();},capitalize:function(input){return Liquid.extensions.stringTools.capitalize(input.toString());},escape:function(input){var self=this;return input.replace(/[&<>"']/g,function(chr){return self._HTML_ESCAPE_MAP[chr];});},h:function(input){var self=this;return input.replace(/[&<>"']/g,function(chr){return self._HTML_ESCAPE_MAP[chr];});},default:function(input,default_value){return Liquid.extensions.object.isEmpty(input)?default_value:input;},truncate:function(input,length,string){if(!input||input==''){return'';} length=length||50;string=string||"...";var seg=input.slice(0,length);return(input.length>length?input.slice(0,length)+string:input);},truncatewords:function(input,words,string){if(!input||input==''){return'';} words=parseInt(words||15);string=string||'...';var wordlist=input.toString().split(" "),l=Math.max((words),0);return(wordlist.length>l)?wordlist.slice(0,l).join(' ')+string:input;},truncate_words:function(input,words,string){if(!input||input==''){return'';} words=parseInt(words||15);string=string||'...';var wordlist=input.toString().split(" "),l=Math.max((words),0);return(wordlist.length>l)?wordlist.slice(0,l).join(' ')+string:input;},strip_html:function(input){return input.toString().replace(/<.*?>/g,'');},strip_newlines:function(input){return input.toString().replace(/\n/g,'')},join:function(input,separator){separator=separator||' ';return input.join(separator);},split:function(input,separator){separator=separator||' ';return input.split(separator);},sort:function(input){return input.sort();},reverse:function(input){return input.reverse();},replace:function(input,string,replacement){replacement=replacement||'';return input.toString().replace(new RegExp(string,'g'),replacement);},replace_first:function(input,string,replacement){replacement=replacement||'';return input.toString().replace(new RegExp(string,""),replacement);},newline_to_br:function(input){return input.toString().replace(/\n/g,"
\n");},date:function(input,format){var date;if(input instanceof Date){date=input;} @@ -118,8 +122,8 @@ if(!(date instanceof Date)&&input=='now'){date=new Date();} if(!(date instanceof Date)&&typeof(input)=='number'){date=new Date(input*1000);} if(!(date instanceof Date)&&typeof(input)=='string'){date=new Date(Date.parse(input));} if(!(date instanceof Date)){return input;} -return date.strftime(format);},first:function(input){return input[0];},last:function(input){input=input;return input[input.length-1];},minus:function(input,number){return(Number(input)||0)-(Number(number)||0);},plus:function(input,number){return(Number(input)||0)+(Number(number)||0);},times:function(input,number){return(Number(input)||0)*(Number(number)||0);},divided_by:function(input,number){return(Number(input)||0)/(Number(number)||0);},modulo:function(input,number){return(Number(input)||0)%(Number(number)||0);},map:function(input,property){input=input||[];var results=[];for(var i=0;i<']|&(?!([a-zA-Z]+|(#\d+));)/g,function(chr){return self._HTML_ESCAPE_MAP[chr];});},remove:function(input,string){return input.toString().replace(new RegExp(string,'g'),'');},remove_first:function(input,string){return input.toString().replace(string,'');},prepend:function(input,string){return''+(string||'').toString()+(input||'').toString();},append:function(input,string){return''+(input||'').toString()+(string||'').toString();}});if(!(new Date()).strftime){(function(){Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(x,pad,r){if(typeof(r)=="undefined"){r=10}for(;parseInt(x,10)1;r/=10){x=pad.toString()+x}return x.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};if(typeof JSON!='undefined'){Date.ext.locales['en-US']=JSON.parse(JSON.stringify(Date.ext.locales.en));}else{Date.ext.locales["en-US"]=Date.ext.locales.en;};Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(d){return Date.ext.locales[d.locale].a[d.getDay()]},A:function(d){return Date.ext.locales[d.locale].A[d.getDay()]},b:function(d){return Date.ext.locales[d.locale].b[d.getMonth()]},B:function(d){return Date.ext.locales[d.locale].B[d.getMonth()]},c:"toLocaleString",C:function(d){return Date.ext.util.xPad(parseInt(d.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(d){return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100,10),0)},G:function(d){var y=d.getFullYear();var V=parseInt(Date.ext.formats.V(d),10);var W=parseInt(Date.ext.formats.W(d),10);if(W>V){y++}else{if(W===0&&V>=52){y--}}return y},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return Date.ext.util.xPad(I===0?12:I,0)},j:function(d){var ms=d-new Date(""+d.getFullYear()+"/1/1 GMT");ms+=d.getTimezoneOffset()*60000;var doy=parseInt(ms/60000/60/24,10)+1;return Date.ext.util.xPad(doy,0,100)},m:function(d){return Date.ext.util.xPad(d.getMonth()+1,0)},M:["getMinutes","0"],p:function(d){return Date.ext.locales[d.locale].p[d.getHours()>=12?1:0]},P:function(d){return Date.ext.locales[d.locale].P[d.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow},U:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0)},V:function(d){var woy=parseInt(Date.ext.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow==53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4){idow=1}else{if(idow===0){idow=Date.ext.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(idow,0)},w:"getDay",W:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=7-Date.ext.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0,10)},y:function(d){return Date.ext.util.xPad(d.getFullYear()%100,0)},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=Date.ext.util.xPad(parseInt(Math.abs(o/60),10),0);var M=Date.ext.util.xPad(o%60,0);return(o>0?"-":"+")+H+M},Z:function(d){return d.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(d){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(fmt){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"")in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var d=this;while(fmt.match(/%[cDhnrRtTxXzZ]/)){fmt=fmt.replace(/%([cDhnrRtTxXzZ])/g,function(m0,m1){var f=Date.ext.aggregates[m1];return(f=="locale"?Date.ext.locales[d.locale][m1]:f)})}var str=fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(m0,m1){var f=Date.ext.formats[m1];if(typeof(f)=="string"){return d[f]()}else{if(typeof(f)=="function"){return f.call(d,d)}else{if(typeof(f)=="object"&&typeof(f[0])=="string"){return Date.ext.util.xPad(d[f[0]](),f[1])}else{return m1}}}});d=null;return str};})();} +return date.strftime(format);},first:function(input){return input[0];},last:function(input){input=input;return input[input.length-1];},minus:function(input,number){return(Number(input)||0)-(Number(number)||0);},plus:function(input,number){return(Number(input)||0)+(Number(number)||0);},times:function(input,number){return(Number(input)||0)*(Number(number)||0);},divided_by:function(input,number){return(Number(input)||0)/(Number(number)||0);},modulo:function(input,number){return(Number(input)||0)%(Number(number)||0);},ceil:function(input){return Math.ceil(Number(input)||0);},floor:function(input){return Math.floor(Number(input)||0);},round:function(input,dp){let pow=Math.pow(10,dp||0);return Math.round((Number(input)||0)*pow)/pow;},map:function(input,property){input=input||[];var results=[];for(var i=0;i<']|&(?!([a-zA-Z]+|(#\d+));)/g,function(chr){return self._HTML_ESCAPE_MAP[chr];});},remove:function(input,string){return input.toString().replace(new RegExp(string,'g'),'');},remove_first:function(input,string){return input.toString().replace(string,'');},prepend:function(input,string){return''+(string||'').toString()+(input||'').toString();},append:function(input,string){return''+(input||'').toString()+(string||'').toString();},money:function(input){return Money.format(input,Money.getCurrencySign(),false);},money_with_currency:function(input){return Money.format(input,Money.getCurrencySign(),false)+Money.getCurrencyCode();},money_without_trailing_zeros:function(input){return Money.format(input,Money.getCurrencySign(),true);},money_without_currency:function(input){return Money.format(input,'',false);},});})(Liquid);if(!(new Date()).strftime){(function(){Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(x,pad,r){if(typeof(r)=="undefined"){r=10}for(;parseInt(x,10)1;r/=10){x=pad.toString()+x}return x.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};if(typeof JSON!='undefined'){Date.ext.locales['en-US']=JSON.parse(JSON.stringify(Date.ext.locales.en));}else{Date.ext.locales["en-US"]=Date.ext.locales.en;};Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(d){return Date.ext.locales[d.locale].a[d.getDay()]},A:function(d){return Date.ext.locales[d.locale].A[d.getDay()]},b:function(d){return Date.ext.locales[d.locale].b[d.getMonth()]},B:function(d){return Date.ext.locales[d.locale].B[d.getMonth()]},c:"toLocaleString",C:function(d){return Date.ext.util.xPad(parseInt(d.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(d){return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100,10),0)},G:function(d){var y=d.getFullYear();var V=parseInt(Date.ext.formats.V(d),10);var W=parseInt(Date.ext.formats.W(d),10);if(W>V){y++}else{if(W===0&&V>=52){y--}}return y},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return Date.ext.util.xPad(I===0?12:I,0)},j:function(d){var ms=d-new Date(""+d.getFullYear()+"/1/1 GMT");ms+=d.getTimezoneOffset()*60000;var doy=parseInt(ms/60000/60/24,10)+1;return Date.ext.util.xPad(doy,0,100)},m:function(d){return Date.ext.util.xPad(d.getMonth()+1,0)},M:["getMinutes","0"],p:function(d){return Date.ext.locales[d.locale].p[d.getHours()>=12?1:0]},P:function(d){return Date.ext.locales[d.locale].P[d.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow},U:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0)},V:function(d){var woy=parseInt(Date.ext.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow==53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4){idow=1}else{if(idow===0){idow=Date.ext.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(idow,0)},w:"getDay",W:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=7-Date.ext.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0,10)},y:function(d){return Date.ext.util.xPad(d.getFullYear()%100,0)},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=Date.ext.util.xPad(parseInt(Math.abs(o/60),10),0);var M=Date.ext.util.xPad(o%60,0);return(o>0?"-":"+")+H+M},Z:function(d){return d.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(d){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(fmt){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"")in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var d=this;while(fmt.match(/%[cDhnrRtTxXzZ]/)){fmt=fmt.replace(/%([cDhnrRtTxXzZ])/g,function(m0,m1){var f=Date.ext.aggregates[m1];return(f=="locale"?Date.ext.locales[d.locale][m1]:f)})}var str=fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(m0,m1){var f=Date.ext.formats[m1];if(typeof(f)=="string"){return d[f]()}else{if(typeof(f)=="function"){return f.call(d,d)}else{if(typeof(f)=="object"&&typeof(f[0])=="string"){return Date.ext.util.xPad(d[f[0]](),f[1])}else{return m1}}}});d=null;return str};})();} var split;split=split||function(undef){var nativeSplit=String.prototype.split,compliantExecNpcg=/()??/.exec("")[1]===undef,self;self=function(str,separator,limit){if(Object.prototype.toString.call(separator)!=="[object RegExp]"){return nativeSplit.call(str,separator,limit);} var output=[],flags=(separator.ignoreCase?"i":"")+ (separator.multiline?"m":"")+ diff --git a/source/context.js b/source/context.js index aaf8a2a..22898f6 100644 --- a/source/context.js +++ b/source/context.js @@ -7,36 +7,36 @@ Liquid.Context = Liquid.Class.extend({ this.rethrowErrors = rethrowErrors; this.strainer = Liquid.Strainer.create(this); }, - + get: function(varname) { return this.resolve(varname); }, - + set: function(varname, value) { this.scopes[0][varname] = value; }, - + hasKey: function(key) { return (this.resolve(key)) ? true : false; }, - + push: function() { var scpObj = {}; this.scopes.unshift(scpObj); return scpObj // Is this right? }, - + merge: function(newScope) { - // HACK Apply from Liquid.extensions.object; extending Object sad. + // HACK Apply from Liquid.extensions.object; extending Object sad. //return this.scopes[0].update(newScope); return Liquid.extensions.object.update.call(this.scopes[0], newScope); }, - + pop: function() { if(this.scopes.length == 1){ throw "Context stack error"; } return this.scopes.shift(); }, - + stack: function(lambda, bind) { var result = null; this.push(); @@ -47,7 +47,7 @@ Liquid.Context = Liquid.Class.extend({ } return result; }, - + invoke: function(method, args) { if( this.strainer.respondTo(method) ) { // console.log('found method '+ method); @@ -60,7 +60,7 @@ Liquid.Context = Liquid.Class.extend({ return (args.length == 0) ? null : args[0]; // was: $pick } }, - + resolve: function(key) { switch(key) { case null: @@ -68,72 +68,77 @@ Liquid.Context = Liquid.Class.extend({ case 'null': case '': return null; - + case 'true': return true; - + case 'false': return false; - + // Not sure what to do with (what would be) Symbols case 'blank': case 'empty': return ''; - + default: if((/^'(.*)'$/).test(key)) // Single quoted strings { return key.replace(/^'(.*)'$/, '$1'); } - + else if((/^"(.*)"$/).test(key)) // Double quoted strings { return key.replace(/^"(.*)"$/, '$1'); } - + else if((/^(\d+)$/).test(key)) // Integer... { return parseInt( key.replace(/^(\d+)$/ , '$1') ); } - + else if((/^(\d[\d\.]+)$/).test(key)) // Float... { return parseFloat( key.replace(/^(\d[\d\.]+)$/, '$1') ); } - - else if((/^\((\S+)\.\.(\S+)\)$/).test(key)) {// Ranges - // JavaScript doesn't have native support for those, so I turn 'em + + else if((/^\((\S+)\.\.(\S+)\)$/).test(key)) {// Ranges + // JavaScript doesn't have native support for those, so I turn 'em // into an array of integers... var range = key.match(/^\((\S+)\.\.(\S+)\)$/), left = parseInt(range[1]), right = parseInt(range[2]), arr = []; // Check if left and right are NaN, if so try as characters - if (isNaN(left) || isNaN(right)) { - // TODO Add in error checking to make sure ranges are single - // character, A-Z or a-z, etc. - left = range[1].charCodeAt(0); - right = range[2].charCodeAt(0); - - var limit = right-left+1; - for (var i=0; i 0 ? '.' + dp : ''); + } catch(e){} + return ret; + } +}; + // Standard Filters Liquid.Template.registerFilter({ - + _HTML_ESCAPE_MAP: { '&': '&', '>': '>', @@ -12,19 +45,19 @@ Liquid.Template.registerFilter({ size: function(iterable) { return (iterable['length']) ? iterable.length : 0; }, - + downcase: function(input) { return input.toString().toLowerCase(); }, - + upcase: function(input) { return input.toString().toUpperCase(); }, - + capitalize: function(input) { return Liquid.extensions.stringTools.capitalize(input.toString()); }, - + escape: function(input) { var self = this; return input.replace(/[&<>"']/g, function(chr) { @@ -50,10 +83,10 @@ Liquid.Template.registerFilter({ var seg = input.slice(0, length); return (input.length > length ? - input.slice(0, length) + string : + input.slice(0, length) + string : input); }, - + truncatewords: function(input, words, string) { if(!input || input == ''){ return ''; } words = parseInt(words || 15); @@ -71,15 +104,15 @@ Liquid.Template.registerFilter({ l = Math.max((words), 0); return (wordlist.length > l) ? wordlist.slice(0,l).join(' ') + string : input; }, - + strip_html: function(input) { return input.toString().replace(/<.*?>/g, ''); }, - + strip_newlines: function(input) { return input.toString().replace(/\n/g, '') }, - + join: function(input, separator) { separator = separator || ' '; return input.join(separator); @@ -89,29 +122,29 @@ Liquid.Template.registerFilter({ separator = separator || ' '; return input.split(separator); }, - + sort: function(input) { return input.sort(); }, - + reverse: function(input) { return input.reverse(); }, - + replace: function(input, string, replacement) { replacement = replacement || ''; return input.toString().replace(new RegExp(string, 'g'), replacement); }, - + replace_first: function(input, string, replacement) { replacement = replacement || ''; return input.toString().replace(new RegExp(string, ""), replacement); }, - + newline_to_br: function(input) { return input.toString().replace(/\n/g, "
\n"); }, - + date: function(input, format) { var date; if( input instanceof Date ){ date = input; } @@ -121,11 +154,11 @@ Liquid.Template.registerFilter({ if(!(date instanceof Date)){ return input; } // Punt return date.strftime(format); }, - + first: function(input) { return input[0]; }, - + last: function(input) { input = input; return input[input.length -1]; @@ -151,6 +184,19 @@ Liquid.Template.registerFilter({ return (Number(input) || 0) % (Number(number) || 0); }, + ceil: function(input) { + return Math.ceil(Number(input) || 0); + }, + + floor: function(input) { + return Math.floor(Number(input) || 0); + }, + + round: function(input, dp) { + let pow = Math.pow(10, dp || 0); + return Math.round((Number(input) || 0) * pow) / pow; + }, + map: function(input, property) { input = input || []; var results = []; @@ -180,6 +226,24 @@ Liquid.Template.registerFilter({ append: function(input, string) { return '' + (input || '').toString() + (string || '').toString(); - } + }, + + money: function(input){ + return Money.format(input, Money.getCurrencySign(), false); + }, + + money_with_currency: function(input){ + return Money.format(input, Money.getCurrencySign(), false) + Money.getCurrencyCode(); + }, + + money_without_trailing_zeros: function(input){ + return Money.format(input, Money.getCurrencySign(), true); + }, + + money_without_currency: function(input){ + return Money.format(input, '', false); + }, }); + +})(Liquid); \ No newline at end of file diff --git a/source/default_tags.js b/source/default_tags.js index cb99316..1172438 100644 --- a/source/default_tags.js +++ b/source/default_tags.js @@ -497,8 +497,6 @@ Liquid.Template.registerTag( 'increment', Liquid.Tag.extend({ init: function(tagName, markup, tokens) { var parts = markup.match(this.tagSyntax); - console.log(tagName, markup, tokens); - console.log(parts[1]); if( parts ) { this.name = parts[1]; } else { @@ -531,8 +529,6 @@ Liquid.Template.registerTag( 'decrement', Liquid.Tag.extend({ init: function(tagName, markup, tokens) { var parts = markup.match(this.tagSyntax); - console.log(tagName, markup, tokens); - console.log(parts[1]); if( parts ) { this.name = parts[1]; } else { diff --git a/test/liquid-console.html b/test/liquid-console.html index f53d265..cdbb874 100644 --- a/test/liquid-console.html +++ b/test/liquid-console.html @@ -1,4 +1,23 @@ + - + +
+ +
- -
-
- Rendered: -
-
- Template: - +The end. +
+
+ + +
+ +
+
+ +
+
+
+ +
+
diff --git a/test/tests.js b/test/tests.js index 200bbcf..bbf86fe 100755 --- a/test/tests.js +++ b/test/tests.js @@ -48,7 +48,7 @@ var Tests = (function() { assertEqual( '1,2,3,4,5', render('{{ (1..5) }}') ) }, "{{ (a..e) }}": function() { - assertEqual( 'a,b,c,d,e', render('{{(a..e)}}') ) + assertEqual('1,2,3,4,5', render('{{(a..e)}}', { a: 1, e: 5 })) }, '{{ varname }}': function() { @@ -306,6 +306,26 @@ var Tests = (function() { assertEqual( '2', render("{{ x | modulo:y }}", {x:'8',y:'3'}) ) }, + '{{ number | ceil }}': function() { + assertEqual('2', render("{{x|ceil}}", { x: 1.2 })) + assertEqual('2', render("{{x|ceil}}", { x: 2.0 })) + assertEqual('184', render("{{x|ceil}}", { x: 183.357 })) + assertEqual('4', render("{{'3.5'|ceil}}")) + }, + + '{{ number | floor }}': function() { + assertEqual('1', render("{{x|floor}}", { x: 1.2 })) + assertEqual('2', render("{{x|floor}}", { x: 2.0 })) + assertEqual('183', render("{{x|floor}}", { x: 183.357 })) + assertEqual('3', render("{{'3.5'|floor}}")) + }, + + '{{ number | round }}': function() { + assertEqual('1', render("{{x|round}}", { x: 1.2 })) + assertEqual('3', render("{{x|round}}", { x: 2.7 })) + assertEqual('183.36', render("{{x|round:2}}", { x: 183.357 })) + }, + '{{ collection | map:y }}': function() { assertEqual( 'Tony,Pepper', render("{{people|map:'firstName'}}", {people:[{firstName:"Tony",lastName:"Stark"},{firstName:"Pepper",lastName:"Potts"}]}) ) assertEqual( 'Tony,Pepper', render("{{ people | map:'firstName' }}", {people:[{firstName:"Tony",lastName:"Stark"},{firstName:"Pepper",lastName:"Potts"}]}) ) @@ -348,6 +368,104 @@ var Tests = (function() { assertEqual( 'foobar', render("{{ 'foo' | append:more}}", {more:'bar'}) ) }, + '{{ number | money }}': function() { + assertEqual( '$10.00', render("{{ num | money }}", { num: 10 }) ); + assertEqual( '$1.00', render("{{ num | money }}", { num: 1 }) ); + assertEqual( '$0.10', render("{{ num | money }}", { num: 0.1 }) ); + assertEqual( '$0.01', render("{{ num | money }}", { num: 0.01 }) ); + assertEqual( '$0.00', render("{{ num | money }}", { num: 0.001 }) ); + assertEqual( '$12.00', render("{{ num | money }}", { num: 12 }) ); + assertEqual( '$12.30', render("{{ num | money }}", { num: 12.3 }) ); + assertEqual( '$12.34', render("{{ num | money }}", { num: 12.34 }) ); + assertEqual( '$12.34', render("{{ num | money }}", { num: 12.343 }) ); + assertEqual( '$12.35', render("{{ num | money }}", { num: 12.345 }) ); + assertEqual( '$12.35', render("{{ num | money }}", { num: 12.346 }) ); + assertEqual( '-$12.00', render("{{ num | money }}", { num: -12 }) ); + assertEqual( '-$12.30', render("{{ num | money }}", { num: -12.3 }) ); + assertEqual( '-$12.34', render("{{ num | money }}", { num: -12.34 }) ); + assertEqual( '-$12.34', render("{{ num | money }}", { num: -12.344 }) ); + assertEqual( '-$12.34', render("{{ num | money }}", { num: -12.345 }) ); + assertEqual( '-$12.35', render("{{ num | money }}", { num: -12.346 }) ); + }, + + '{{ number | money_with_currency }}': function() { + assertEqual( '$10.00', render("{{ num | money_with_currency }}", { num: 10 }) ); + assertEqual( '$1.00', render("{{ num | money_with_currency }}", { num: 1 }) ); + assertEqual( '$0.10', render("{{ num | money_with_currency }}", { num: 0.1 }) ); + assertEqual( '$0.01', render("{{ num | money_with_currency }}", { num: 0.01 }) ); + assertEqual( '$0.00', render("{{ num | money_with_currency }}", { num: 0.001 }) ); + assertEqual( '$12.00', render("{{ num | money_with_currency }}", { num: 12 }) ); + assertEqual( '$12.30', render("{{ num | money_with_currency }}", { num: 12.3 }) ); + assertEqual( '$12.34', render("{{ num | money_with_currency }}", { num: 12.34 }) ); + assertEqual( '$12.34', render("{{ num | money_with_currency }}", { num: 12.344 }) ); + assertEqual( '$12.35', render("{{ num | money_with_currency }}", { num: 12.345 }) ); + assertEqual( '$12.35', render("{{ num | money_with_currency }}", { num: 12.346 }) ); + assertEqual( '-$12.00', render("{{ num | money_with_currency }}", { num: -12 }) ); + assertEqual( '-$12.30', render("{{ num | money_with_currency }}", { num: -12.3 }) ); + assertEqual( '-$12.34', render("{{ num | money_with_currency }}", { num: -12.34 }) ); + assertEqual( '-$12.34', render("{{ num | money_with_currency }}", { num: -12.344 }) ); + assertEqual( '-$12.34', render("{{ num | money_with_currency }}", { num: -12.345 }) ); + assertEqual( '-$12.35', render("{{ num | money_with_currency }}", { num: -12.346 }) ); + }, + + '{{ number | money_without_trailing_zeros }}': function() { + assertEqual( '$10', render("{{ num | money_without_trailing_zeros }}", { num: 10 }) ); + assertEqual( '$1', render("{{ num | money_without_trailing_zeros }}", { num: 1 }) ); + assertEqual( '$0.1', render("{{ num | money_without_trailing_zeros }}", { num: 0.1 }) ); + assertEqual( '$0.01', render("{{ num | money_without_trailing_zeros }}", { num: 0.01 }) ); + assertEqual( '$0.001', render("{{ num | money_without_trailing_zeros }}", { num: 0.001 }) ); + assertEqual( '$12', render("{{ num | money_without_trailing_zeros }}", { num: 12 }) ); + assertEqual( '$12.3', render("{{ num | money_without_trailing_zeros }}", { num: 12.3 }) ); + assertEqual( '$12.34', render("{{ num | money_without_trailing_zeros }}", { num: 12.34 }) ); + assertEqual( '$12.344', render("{{ num | money_without_trailing_zeros }}", { num: 12.344 }) ); + assertEqual( '$12.345', render("{{ num | money_without_trailing_zeros }}", { num: 12.345 }) ); + assertEqual( '$12.346', render("{{ num | money_without_trailing_zeros }}", { num: 12.346 }) ); + assertEqual( '$100', render("{{ num | money_without_trailing_zeros }}", { num: '100' }) ); + assertEqual( '$10', render("{{ num | money_without_trailing_zeros }}", { num: '10' }) ); + assertEqual( '$1', render("{{ num | money_without_trailing_zeros }}", { num: '1' }) ); + assertEqual( '$100', render("{{ num | money_without_trailing_zeros }}", { num: '100.00' }) ); + assertEqual( '$10', render("{{ num | money_without_trailing_zeros }}", { num: '10.00' }) ); + assertEqual( '$1', render("{{ num | money_without_trailing_zeros }}", { num: '1.00' }) ); + assertEqual( '$12', render("{{ num | money_without_trailing_zeros }}", { num: '12.00' }) ); + assertEqual( '$12.3', render("{{ num | money_without_trailing_zeros }}", { num: '12.30' }) ); + assertEqual( '$12.34', render("{{ num | money_without_trailing_zeros }}", { num: '12.340' }) ); + assertEqual( '$12.344', render("{{ num | money_without_trailing_zeros }}", { num: '12.3440' }) ); + assertEqual( '$12.345', render("{{ num | money_without_trailing_zeros }}", { num: '12.3450' }) ); + assertEqual( '$12.346', render("{{ num | money_without_trailing_zeros }}", { num: '12.3460' }) ); + assertEqual( '-$12', render("{{ num | money_without_trailing_zeros }}", { num: -12 }) ); + assertEqual( '-$12.3', render("{{ num | money_without_trailing_zeros }}", { num: -12.3 }) ); + assertEqual( '-$12.34', render("{{ num | money_without_trailing_zeros }}", { num: -12.34 }) ); + assertEqual( '-$12.344', render("{{ num | money_without_trailing_zeros }}", { num: -12.344 }) ); + assertEqual( '-$12.345', render("{{ num | money_without_trailing_zeros }}", { num: -12.345 }) ); + assertEqual( '-$12.346', render("{{ num | money_without_trailing_zeros }}", { num: -12.346 }) ); + assertEqual( '-$12', render("{{ num | money_without_trailing_zeros }}", { num: '-12.00' }) ); + assertEqual( '-$12.3', render("{{ num | money_without_trailing_zeros }}", { num: '-12.30' }) ); + assertEqual( '-$12.34', render("{{ num | money_without_trailing_zeros }}", { num: '-12.340' }) ); + assertEqual( '-$12.344', render("{{ num | money_without_trailing_zeros }}", { num: '-12.3440' }) ); + assertEqual( '-$12.345', render("{{ num | money_without_trailing_zeros }}", { num: '-12.3450' }) ); + assertEqual( '-$12.346', render("{{ num | money_without_trailing_zeros }}", { num: '-12.3460' }) ); + }, + + '{{ number | money_without_currency }}': function() { + assertEqual( '10.00', render("{{ num | money_without_currency }}", { num: 10 }) ); + assertEqual( '1.00', render("{{ num | money_without_currency }}", { num: 1 }) ); + assertEqual( '0.10', render("{{ num | money_without_currency }}", { num: 0.1 }) ); + assertEqual( '0.01', render("{{ num | money_without_currency }}", { num: 0.01 }) ); + assertEqual( '0.00', render("{{ num | money_without_currency }}", { num: 0.001 }) ); + assertEqual( '12.00', render("{{ num | money_without_currency }}", { num: 12 }) ); + assertEqual( '12.30', render("{{ num | money_without_currency }}", { num: 12.3 }) ); + assertEqual( '12.34', render("{{ num | money_without_currency }}", { num: 12.34 }) ); + assertEqual( '12.34', render("{{ num | money_without_currency }}", { num: 12.344 }) ); + assertEqual( '12.35', render("{{ num | money_without_currency }}", { num: 12.345 }) ); + assertEqual( '12.35', render("{{ num | money_without_currency }}", { num: 12.346 }) ); + assertEqual( '-12.00', render("{{ num | money_without_currency }}", { num: -12 }) ); + assertEqual( '-12.30', render("{{ num | money_without_currency }}", { num: -12.3 }) ); + assertEqual( '-12.34', render("{{ num | money_without_currency }}", { num: -12.34 }) ); + assertEqual( '-12.34', render("{{ num | money_without_currency }}", { num: -12.344 }) ); + assertEqual( '-12.34', render("{{ num | money_without_currency }}", { num: -12.345 }) ); + assertEqual( '-12.35', render("{{ num | money_without_currency }}", { num: -12.346 }) ); + }, + note3: "Testing tags...", "{% assign varname = value %}": function() { @@ -425,6 +543,10 @@ var Tests = (function() { assertEqual(" 0 1 2 ", render("{% for item in (1..3) %} {{ forloop.index0 }} {% endfor %}")); assertEqual(" true false false ", render("{% for item in (1..3) %} {{ forloop.first }} {% endfor %}")); assertEqual(" false false true ", render("{% for item in (1..3) %} {{ forloop.last }} {% endfor %}")); + assertEqual(" 0 1 2 ", render("{% for item in data %} {{ item }} {% endfor %}", { data: [0, 1, 2] })); + assertEqual(" 0 1 2 ", render("{% for item in (0..n) %} {{ item }} {% endfor %}", { n: 2 })); + assertEqual(" 1 2 3 ", render("{% assign n = 3 %}{% for item in (1..n) %} {{ item }} {% endfor %}")); + assertEqual(" 2 3 4 ", render("{% for item in (x..y) %} {{ item }} {% endfor %}", { x: 2, y: 4 })); // TODO: Add test for the rest of the forloop variables too... }, diff --git a/watcher.rb b/watcher.rb new file mode 100644 index 0000000..98c9e1a --- /dev/null +++ b/watcher.rb @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +require 'listen' + +listener = Listen.to( 'source' ) do |modified, added, removed| + puts 'Running builder...' + system( 'bundle exec rake' ) +end +listener.start +sleep