diff --git a/README.md b/README.md index 80c2895..9cc74ae 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ * Simple interpolation: `{{=value}}` * Scrubbed interpolation: `{{%unsafe_value}}` * Name-spaced variables: `{{=User.address.city}}` + * Formatted output (see below): `{{=value | formatter1[, formatter2]...}}` * If/else blocks: `{{value}} <> {{:value}} <> {{/value}}` * If not blocks: `{{!value}} <> {{/!value}}` * Object/Array iteration: `{{@object_value}} {{=_key}}:{{=_val}} {{/@object_value}}` @@ -19,6 +20,35 @@ var template = new t("
Hello {{=name}}
"); document.body.innerHtml = template.render({name: "World!"}); +### Formatted output + +Either value tag, i.e.:`{{=` or `{{%` can have the variable name followed by a vertical bar and one or more formatters separated by commas. + + var template = new t( + '
Name: {{=user.name}}, age: {{=user.dob | dob2age}}
', + { + dob2age: (dob) => Math.floor((Date.now() - dob.getTime()) / 1000 / 60 / 60 / 24 / 365.25) + } + ); + document.body.innerHTML = template({name:'Joe', dob: new Date(2000,0,1)}); + +The formatter functions should be provided along the template as an object containing functions that will receive the value to be formatted and return the formatted value. The property name for that function, `dob2age`, is the one used in the template. + +Several formatters can be chained, the value of the first served to the next in the chain. + +Values need not be limited to simple values but they can be objects as well, a pointless use would be: + + var template = new t( + '
Full Name: {{=user | getFullName}}
', + { + getFullName: (user) => `${user.firstName} ${user.lastName}` + } + ) + +The test suite contains both simple and complex uses of formatters. + +--- + For more advanced usage check the [`t_test.html`](https://github.com/jasonmoo/t.js/blob/master/t_test.html). This software is released under the MIT license. diff --git a/t.js b/t.js index add6913..6fde8d2 100644 --- a/t.js +++ b/t.js @@ -19,10 +19,11 @@ (function() { var blockregex = /\{\{(([@!]?)(.+?))\}\}(([\s\S]+?)(\{\{:\1\}\}([\s\S]+?))?)\{\{\/\1\}\}/g, - valregex = /\{\{([=%])(.+?)\}\}/g; + valregex = /\{\{([=%])([\.\w]+?)\s*(\|\s*([\w,]+))?\s*\}\}/g; - function t(template) { + function t(template, formatters) { this.t = template; + this.f = formatters || {}; } function scrub(val) { @@ -40,7 +41,7 @@ return vars; } - function render(fragment, vars) { + function render(fragment, vars, formatters) { return fragment .replace(blockregex, function(_, __, meta, key, inner, if_true, has_else, if_false) { @@ -50,11 +51,11 @@ // handle if not if (meta == '!') { - return render(inner, vars); + return render(inner, vars, formatters); } // check for else if (has_else) { - return render(if_false, vars); + return render(if_false, vars, formatters); } return ""; @@ -62,7 +63,7 @@ // regular if if (!meta) { - return render(if_true, vars); + return render(if_true, vars, formatters); } // process array/obj iteration @@ -75,7 +76,7 @@ if (val.hasOwnProperty(i)) { vars._key = i; vars._val = val[i]; - temp += render(inner, vars); + temp += render(inner, vars, formatters); } } vars._key = _; @@ -84,8 +85,15 @@ } }) - .replace(valregex, function(_, meta, key) { - var val = get_value(vars,key); + .replace(valregex, function (_, meta, key, __, fns = '') { + const val = fns + .split(',') + .reduce( + function (val, fn) { + return typeof formatters[fn] == 'function' ? formatters[fn](val) : val + }, + get_value(vars, key) + ); if (val || val === 0) { return meta == '%' ? scrub(val) : val; @@ -95,7 +103,7 @@ } t.prototype.render = function (vars) { - return render(this.t, vars); + return render(this.t, vars, this.f); }; window.t = t; diff --git a/t.min.js b/t.min.js index 4152667..e434c6a 100644 --- a/t.min.js +++ b/t.min.js @@ -1,2 +1 @@ -(function(){function c(a){this.t=a}function l(a,b){for(var e=b.split(".");e.length;){if(!(e[0]in a))return!1;a=a[e.shift()]}return a}function d(a,b){return a.replace(h,function(e,a,i,f,c,h,k,m){var f=l(b,f),j="",g;if(!f)return"!"==i?d(c,b):k?d(m,b):"";if(!i)return d(h,b);if("@"==i){e=b._key;a=b._val;for(g in f)f.hasOwnProperty(g)&&(b._key=g,b._val=f[g],j+=d(c,b));b._key=e;b._val=a;return j}}).replace(k,function(a,c,d){return(a=l(b,d))||0===a?"%"==c?(new Option(a)).innerHTML.replace(/"/g,"""): -a:""})}var h=/\{\{(([@!]?)(.+?))\}\}(([\s\S]+?)(\{\{:\1\}\}([\s\S]+?))?)\{\{\/\1\}\}/g,k=/\{\{([=%])(.+?)\}\}/g;c.prototype.render=function(a){return d(this.t,a)};window.t=c})(); \ No newline at end of file +!function(){var n=/\{\{(([@!]?)(.+?))\}\}(([\s\S]+?)(\{\{:\1\}\}([\s\S]+?))?)\{\{\/\1\}\}/g,t=/\{\{([=%])([\.\w]+?)\s*(\|\s*([\w,]+))?\s*\}\}/g;function r(n,t){this.t=n,this.f=t||{}}function e(n,t){for(var r=t.split(".");r.length;){if(!(r[0]in n))return!1;n=n[r.shift()]}return n}function i(r,u,f){return r.replace(n,(function(n,t,r,o,c,s,a,p){var l,h=e(u,o),v="";if(!h)return"!"==r?i(c,u,f):a?i(p,u,f):"";if(!r)return i(s,u,f);if("@"==r){for(l in n=u._key,t=u._val,h)h.hasOwnProperty(l)&&(u._key=l,u._val=h[l],v+=i(c,u,f));return u._key=n,u._val=t,v}})).replace(t,(function(n,t,r,i,o=""){const c=o.split(",").reduce((function(n,t){return"function"==typeof f[t]?f[t](n):n}),e(u,r));return c||0===c?"%"==t?function(n){return new Option(n).innerHTML.replace(/"/g,""")}(c):c:""}))}r.prototype.render=function(n){return i(this.t,n,this.f)},window.t=r}(); \ No newline at end of file diff --git a/t_test.html b/t_test.html index f410c54..02156d8 100644 --- a/t_test.html +++ b/t_test.html @@ -15,7 +15,7 @@ - +