--- /dev/null
+/*!
+ * jSmart Javascript template engine
+ * https://github.com/umakantp/jsmart
+ *
+ * Copyright 2011-2015, Max Miroshnikov <miroshnikov at gmail dot com>
+ * Umakant Patil <me at umakantpatil dot.com>
+ * jSmart is licensed under the GNU Lesser General Public License
+ * http://opensource.org/licenses/LGPL-3.0
+ */
+
+
+(function() {
+
+ /**
+ merges two or more objects into one
+ shallow copy for objects
+ */
+ function obMerge(ob1, ob2 /*, ...*/)
+ {
+ for (var i=1; i<arguments.length; ++i)
+ {
+ for (var nm in arguments[i])
+ {
+ ob1[nm] = arguments[i][nm];
+ }
+ }
+ return ob1;
+ }
+
+ /**
+ @return number of own properties in ob
+ */
+ function countProperties(ob)
+ {
+ var count = 0;
+ for (var nm in ob)
+ {
+ if (ob.hasOwnProperty(nm))
+ {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ IE workaround
+ */
+ function findInArray(a, v)
+ {
+ if (Array.prototype.indexOf) {
+ return a.indexOf(v);
+ }
+ for (var i=0; i < a.length; ++i)
+ {
+ if (a[i] === v)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ function evalString(s)
+ {
+ return s.replace(/\\t/,'\t').replace(/\\n/,'\n').replace(/\\(['"\\])/g,'$1');
+ }
+
+ /**
+ @return s trimmed and without quotes
+ */
+ function trimQuotes(s)
+ {
+ return evalString(s.replace(/^['"](.*)['"]$/,'$1')).replace(/^\s+|\s+$/g,'');
+ }
+
+ /**
+ finds first {tag} in string
+ @param re string with regular expression or an empty string to find any tag
+ @return null or s.match(re) result object where
+ [0] - full tag matched with delimiters (and whitespaces at the begin and the end): { tag }
+ [1] - found part from passed re
+ [index] - position of tag starting { in s
+ */
+ function findTag(re,s)
+ {
+ var openCount = 0;
+ var offset = 0;
+ var ldelim = jSmart.prototype.left_delimiter;
+ var rdelim = jSmart.prototype.right_delimiter;
+ var skipInWS = jSmart.prototype.auto_literal;
+
+ var reAny = /^\s*(.+)\s*$/i;
+ var reTag = re ? new RegExp('^\\s*('+re+')\\s*$','i') : reAny;
+
+ for (var i=0; i<s.length; ++i)
+ {
+ if (s.substr(i,ldelim.length) == ldelim)
+ {
+ if (skipInWS && i+1 < s.length && s.substr(i+1,1).match(/\s/))
+ {
+ continue;
+ }
+ if (!openCount)
+ {
+ s = s.slice(i);
+ offset += parseInt(i);
+ i = 0;
+ }
+ ++openCount;
+ }
+ else if (s.substr(i,rdelim.length) == rdelim)
+ {
+ if (skipInWS && i-1 >= 0 && s.substr(i-1,1).match(/\s/))
+ {
+ continue;
+ }
+ if (!--openCount)
+ {
+ var sTag = s.slice(ldelim.length,i).replace(/[\r\n]/g, ' ');
+ var found = sTag.match(reTag);
+ if (found)
+ {
+ found.index = offset;
+ found[0] = s.slice(0,i+rdelim.length);
+ return found;
+ }
+ }
+ if (openCount < 0) //ignore any number of unmatched right delimiters
+ {
+ openCount = 0;
+ }
+ }
+ }
+ return null;
+ }
+
+ function findCloseTag(reClose,reOpen,s)
+ {
+ var sInner = '';
+ var closeTag = null;
+ var openTag = null;
+ var findIndex = 0;
+
+ do
+ {
+ if (closeTag)
+ {
+ findIndex += closeTag[0].length;
+ }
+ closeTag = findTag(reClose,s);
+ if (!closeTag)
+ {
+ throw new Error('Unclosed {'+reOpen+'}');
+ }
+ sInner += s.slice(0,closeTag.index);
+ findIndex += closeTag.index;
+ s = s.slice(closeTag.index+closeTag[0].length);
+
+ openTag = findTag(reOpen,sInner);
+ if (openTag)
+ {
+ sInner = sInner.slice(openTag.index+openTag[0].length);
+ }
+ }
+ while (openTag);
+
+ closeTag.index = findIndex;
+ return closeTag;
+ }
+
+ function findElseTag(reOpen, reClose, reElse, s)
+ {
+ var offset = 0;
+ for (var elseTag=findTag(reElse,s); elseTag; elseTag=findTag(reElse,s))
+ {
+ var openTag = findTag(reOpen,s);
+ if (!openTag || openTag.index > elseTag.index)
+ {
+ elseTag.index += offset;
+ return elseTag;
+ }
+ else
+ {
+ s = s.slice(openTag.index+openTag[0].length);
+ offset += openTag.index+openTag[0].length;
+ var closeTag = findCloseTag(reClose,reOpen,s);
+ s = s.slice(closeTag.index + closeTag[0].length);
+ offset += closeTag.index + closeTag[0].length;
+ }
+ }
+ return null;
+ }
+
+ function execute(code, data)
+ {
+ if (typeof(code) == 'string')
+ {
+ with ({'__code':code})
+ {
+ with (modifiers)
+ {
+ with (data)
+ {
+ try {
+ return eval(__code);
+ }
+ catch(e)
+ {
+ throw new Error(e.message + ' in \n' + code);
+ }
+ }
+ }
+ }
+ }
+ return code;
+ }
+
+ /**
+ * Execute function when we have a object.
+ *
+ * @param object obj Object of the function to be called.
+ * @param array args Arguments to pass to a function.
+ *
+ * @return
+ * @throws Error If function obj does not exists.
+ */
+ function executeByFuncObject(obj, args) {
+ try {
+ return obj.apply(this, args);
+ } catch (e) {
+ throw new Error(e.message);
+ }
+ }
+
+ function assignVar(nm, val, data)
+ {
+ if (nm.match(/\[\]$/)) //ar[] =
+ {
+ data[ nm.replace(/\[\]$/,'') ].push(val);
+ }
+ else
+ {
+ data[nm] = val;
+ }
+ }
+
+ var buildInFunctions =
+ {
+ expression:
+ {
+ parse: function(s, tree)
+ {
+ var e = parseExpression(s);
+
+ tree.push({
+ type: 'build-in',
+ name: 'expression',
+ expression: e.tree,
+ params: parseParams(s.slice(e.value.length).replace(/^\s+|\s+$/g,''))
+ });
+
+ return e.tree;
+
+ },
+ process: function(node, data)
+ {
+ var params = getActualParamValues(node.params, data);
+ var res = process([node.expression],data);
+
+ if (findInArray(params, 'nofilter') < 0)
+ {
+ for (var i=0; i<default_modifiers.length; ++i)
+ {
+ var m = default_modifiers[i];
+ m.params.__parsed[0] = {type:'text', data:res};
+ res = process([m],data);
+ }
+ if (escape_html)
+ {
+ res = modifiers.escape(res);
+ }
+ res = applyFilters(varFilters,res);
+
+ if (tpl_modifiers.length) {
+ __t = function(){ return res; }
+ res = process(tpl_modifiers,data);
+ }
+ }
+ return res;
+ }
+ },
+
+ operator:
+ {
+ process: function(node, data)
+ {
+ var params = getActualParamValues(node.params, data);
+ var arg1 = params[0];
+
+ if (node.optype == 'binary')
+ {
+ var arg2 = params[1];
+ if (node.op == '=')
+ {
+ getVarValue(node.params.__parsed[0], data, arg2);
+ return '';
+ }
+ else if (node.op.match(/(\+=|-=|\*=|\/=|%=)/))
+ {
+ arg1 = getVarValue(node.params.__parsed[0], data);
+ switch (node.op)
+ {
+ case '+=': arg1+=arg2; break;
+ case '-=': arg1-=arg2; break;
+ case '*=': arg1*=arg2; break;
+ case '/=': arg1/=arg2; break;
+ case '%=': arg1%=arg2; break;
+ }
+ return getVarValue(node.params.__parsed[0], data, arg1);
+ }
+ else if (node.op.match(/div/))
+ {
+ return (node.op!='div')^(arg1%arg2==0);
+ }
+ else if (node.op.match(/even/))
+ {
+ return (node.op!='even')^((arg1/arg2)%2==0);
+ }
+ else if (node.op.match(/xor/))
+ {
+ return (arg1||arg2) && !(arg1&&arg2);
+ }
+
+ switch (node.op)
+ {
+ case '==': return arg1==arg2;
+ case '!=': return arg1!=arg2;
+ case '+': return Number(arg1)+Number(arg2);
+ case '-': return Number(arg1)-Number(arg2);
+ case '*': return Number(arg1)*Number(arg2);
+ case '/': return Number(arg1)/Number(arg2);
+ case '%': return Number(arg1)%Number(arg2);
+ case '&&': return arg1&&arg2;
+ case '||': return arg1||arg2;
+ case '<': return arg1<arg2;
+ case '<=': return arg1<=arg2;
+ case '>': return arg1>arg2;
+ case '>=': return arg1>=arg2;
+ case '===': return arg1===arg2;
+ case '!==': return arg1!==arg2;
+ }
+ }
+ else if (node.op == '!')
+ {
+ return !arg1;
+ }
+ else
+ {
+ var isVar = node.params.__parsed[0].type == 'var';
+ if (isVar)
+ {
+ arg1 = getVarValue(node.params.__parsed[0], data);
+ }
+ var v = arg1;
+ if (node.optype == 'pre-unary')
+ {
+ switch (node.op)
+ {
+ case '-': v=-arg1; break;
+ case '++': v=++arg1; break;
+ case '--': v=--arg1; break;
+ }
+ if (isVar)
+ {
+ getVarValue(node.params.__parsed[0], data, arg1);
+ }
+ }
+ else
+ {
+ switch (node.op)
+ {
+ case '++': arg1++; break;
+ case '--': arg1--; break;
+ }
+ getVarValue(node.params.__parsed[0], data, arg1);
+ }
+ return v;
+ }
+ }
+ },
+
+ section:
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ var subTree = [];
+ var subTreeElse = [];
+ tree.push({
+ type: 'build-in',
+ name: 'section',
+ params: params,
+ subTree: subTree,
+ subTreeElse: subTreeElse
+ });
+
+ var findElse = findElseTag('section [^}]+', '\/section', 'sectionelse', content);
+ if (findElse)
+ {
+ parse(content.slice(0,findElse.index),subTree);
+ parse(content.slice(findElse.index+findElse[0].length).replace(/^[\r\n]/,''), subTreeElse);
+ }
+ else
+ {
+ parse(content, subTree);
+ }
+ },
+
+ process: function(node, data)
+ {
+ var params = getActualParamValues(node.params, data);
+
+ var props = {};
+ data.smarty.section[params.__get('name',null,0)] = props;
+
+ var show = params.__get('show',true);
+ props.show = show;
+ if (!show)
+ {
+ return process(node.subTreeElse, data);
+ }
+
+ var from = parseInt(params.__get('start',0));
+ var to = (params.loop instanceof Object) ? countProperties(params.loop) : isNaN(params.loop) ? 0 : parseInt(params.loop);
+ var step = parseInt(params.__get('step',1));
+ var max = parseInt(params.__get('max'));
+ if (isNaN(max))
+ {
+ max = Number.MAX_VALUE;
+ }
+
+ if (from < 0)
+ {
+ from += to;
+ if (from < 0)
+ {
+ from = 0;
+ }
+ }
+ else if (from >= to)
+ {
+ from = to ? to-1 : 0;
+ }
+
+ var count = 0;
+ var loop = 0;
+ var i = from;
+ for (; i>=0 && i<to && count<max; i+=step,++count)
+ {
+ loop = i;
+ }
+ props.total = count;
+ props.loop = count; //? - because it is so in Smarty
+
+ count = 0;
+ var s = '';
+ for (i=from; i>=0 && i<to && count<max; i+=step,++count)
+ {
+ if (data.smarty['break'])
+ {
+ break;
+ }
+
+ props.first = (i==from);
+ props.last = ((i+step)<0 || (i+step)>=to);
+ props.index = i;
+ props.index_prev = i-step;
+ props.index_next = i+step;
+ props.iteration = props.rownum = count+1;
+
+ s += process(node.subTree, data);
+ data.smarty['continue'] = false;
+ }
+ data.smarty['break'] = false;
+
+ if (count)
+ {
+ return s;
+ }
+ return process(node.subTreeElse, data);
+ }
+ },
+
+ setfilter:
+ {
+ type: 'block',
+ parseParams: function(paramStr)
+ {
+ return [parseExpression('__t()|' + paramStr).tree];
+ },
+
+ parse: function(params, tree, content)
+ {
+ tree.push({
+ type: 'build-in',
+ name: 'setfilter',
+ params: params,
+ subTree: parse(content,[])
+ });
+ },
+
+ process: function(node, data)
+ {
+ tpl_modifiers = node.params;
+ var s = process(node.subTree, data);
+ tpl_modifiers = [];
+ return s;
+ }
+ },
+
+ 'for':
+ {
+ type: 'block',
+ parseParams: function(paramStr)
+ {
+ var res = paramStr.match(/^\s*\$(\w+)\s*=\s*([^\s]+)\s*to\s*([^\s]+)\s*(?:step\s*([^\s]+))?\s*(.*)$/);
+ if (!res)
+ {
+ throw new Error('Invalid {for} parameters: '+paramStr);
+ }
+ return parseParams("varName='"+res[1]+"' from="+res[2]+" to="+res[3]+" step="+(res[4]?res[4]:'1')+" "+res[5]);
+ },
+
+ parse: function(params, tree, content)
+ {
+ var subTree = [];
+ var subTreeElse = [];
+ tree.push({
+ type: 'build-in',
+ name: 'for',
+ params: params,
+ subTree: subTree,
+ subTreeElse: subTreeElse
+ });
+
+ var findElse = findElseTag('for\\s[^}]+', '\/for', 'forelse', content);
+ if (findElse)
+ {
+ parse(content.slice(0,findElse.index),subTree);
+ parse(content.slice(findElse.index+findElse[0].length), subTreeElse);
+ }
+ else
+ {
+ parse(content, subTree);
+ }
+ },
+
+ process: function(node, data)
+ {
+ var params = getActualParamValues(node.params, data);
+ var from = parseInt(params.__get('from'));
+ var to = parseInt(params.__get('to'));
+ var step = parseInt(params.__get('step'));
+ if (isNaN(step))
+ {
+ step = 1;
+ }
+ var max = parseInt(params.__get('max'));
+ if (isNaN(max))
+ {
+ max = Number.MAX_VALUE;
+ }
+
+ var count = 0;
+ var s = '';
+ var total = Math.min( Math.ceil( ((step > 0 ? to-from : from-to)+1) / Math.abs(step) ), max);
+
+ for (var i=parseInt(params.from); count<total; i+=step,++count)
+ {
+ if (data.smarty['break'])
+ {
+ break;
+ }
+ data[params.varName] = i;
+ s += process(node.subTree, data);
+ data.smarty['continue'] = false;
+ }
+ data.smarty['break'] = false;
+
+ if (!count)
+ {
+ s = process(node.subTreeElse, data);
+ }
+ return s;
+ }
+ },
+
+ 'if':
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ var subTreeIf = [];
+ var subTreeElse = [];
+ tree.push({
+ type: 'build-in',
+ name: 'if',
+ params: params,
+ subTreeIf: subTreeIf,
+ subTreeElse: subTreeElse
+ });
+
+ var findElse = findElseTag('if\\s+[^}]+', '\/if', 'else[^}]*', content);
+ if (findElse)
+ {
+ parse(content.slice(0,findElse.index),subTreeIf);
+
+ content = content.slice(findElse.index+findElse[0].length);
+ var findElseIf = findElse[1].match(/^else\s*if(.*)/);
+ if (findElseIf)
+ {
+ buildInFunctions['if'].parse(parseParams(findElseIf[1]), subTreeElse, content.replace(/^\n/,''));
+ }
+ else
+ {
+ parse(content.replace(/^\n/,''), subTreeElse);
+ }
+ }
+ else
+ {
+ parse(content, subTreeIf);
+ }
+ },
+
+ process: function(node, data) {
+ var value = getActualParamValues(node.params,data)[0];
+ // Zero length arrays or empty associative arrays are false in PHP.
+ if (value && !((value instanceof Array && value.length == 0)
+ || (typeof value == 'object' && isEmptyObject(value)))
+ ) {
+ return process(node.subTreeIf, data);
+ } else {
+ return process(node.subTreeElse, data);
+ }
+ }
+ },
+
+ foreach:
+ {
+ type: 'block',
+ parseParams: function(paramStr)
+ {
+ var params = {};
+ var res = paramStr.match(/^\s*([$].+)\s*as\s*[$](\w+)\s*(=>\s*[$](\w+))?\s*$/i);
+ if (res) //Smarty 3.x syntax => Smarty 2.x syntax
+ {
+ paramStr = 'from='+res[1] + ' item='+(res[4]||res[2]);
+ if (res[4])
+ {
+ paramStr += ' key='+res[2];
+ }
+ }
+ return parseParams(paramStr);
+ },
+
+ parse: function(params, tree, content)
+ {
+ var subTree = [];
+ var subTreeElse = [];
+ tree.push({
+ type: 'build-in',
+ name: 'foreach',
+ params: params,
+ subTree: subTree,
+ subTreeElse: subTreeElse
+ });
+
+ var findElse = findElseTag('foreach\\s[^}]+', '\/foreach', 'foreachelse', content);
+ if (findElse)
+ {
+ parse(content.slice(0,findElse.index),subTree);
+ parse(content.slice(findElse.index+findElse[0].length).replace(/^[\r\n]/,''), subTreeElse);
+ }
+ else
+ {
+ parse(content, subTree);
+ }
+ },
+
+ process: function(node, data)
+ {
+ var params = getActualParamValues(node.params, data);
+ var a = params.from;
+ if (typeof a == 'undefined')
+ {
+ a = [];
+ }
+ if (typeof a != 'object')
+ {
+ a = [a];
+ }
+
+ var total = countProperties(a);
+
+ data[params.item+'__total'] = total;
+ if ('name' in params)
+ {
+ data.smarty.foreach[params.name] = {};
+ data.smarty.foreach[params.name].total = total;
+ }
+
+ var s = '';
+ var i=0;
+ for (var key in a)
+ {
+ if (!a.hasOwnProperty(key))
+ {
+ continue;
+ }
+
+ if (data.smarty['break'])
+ {
+ break;
+ }
+
+ data[params.item+'__key'] = isNaN(key) ? key : parseInt(key);
+ if ('key' in params)
+ {
+ data[params.key] = data[params.item+'__key'];
+ }
+ data[params.item] = a[key];
+ data[params.item+'__index'] = parseInt(i);
+ data[params.item+'__iteration'] = parseInt(i+1);
+ data[params.item+'__first'] = (i===0);
+ data[params.item+'__last'] = (i==total-1);
+
+ if ('name' in params)
+ {
+ data.smarty.foreach[params.name].index = parseInt(i);
+ data.smarty.foreach[params.name].iteration = parseInt(i+1);
+ data.smarty.foreach[params.name].first = (i===0) ? 1 : '';
+ data.smarty.foreach[params.name].last = (i==total-1) ? 1 : '';
+ }
+
+ ++i;
+
+ s += process(node.subTree, data);
+ data.smarty['continue'] = false;
+ }
+ data.smarty['break'] = false;
+
+ data[params.item+'__show'] = (i>0);
+ if (params.name)
+ {
+ data.smarty.foreach[params.name].show = (i>0) ? 1 : '';
+ }
+ if (i>0)
+ {
+ return s;
+ }
+ return process(node.subTreeElse, data);
+ }
+ },
+
+ 'function':
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ var subTree = [];
+ plugins[trimQuotes(params.name?params.name:params[0])] =
+ {
+ type: 'function',
+ subTree: subTree,
+ defautParams: params,
+ process: function(params, data)
+ {
+ var defaults = getActualParamValues(this.defautParams,data);
+ delete defaults.name;
+ return process(this.subTree, obMerge({},data,defaults,params));
+ }
+ };
+ parse(content, subTree);
+ }
+ },
+
+ php:
+ {
+ type: 'block',
+ parse: function(params, tree, content) {}
+ },
+
+ 'extends':
+ {
+ type: 'function',
+ parse: function(params, tree)
+ {
+ tree.splice(0,tree.length);
+ getTemplate(trimQuotes(params.file?params.file:params[0]),tree);
+ }
+ },
+
+ block:
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ tree.push({
+ type: 'build-in',
+ name: 'block',
+ params: params
+ });
+ params.append = findInArray(params,'append') >= 0;
+ params.prepend = findInArray(params,'prepend') >= 0;
+ params.hide = findInArray(params,'hide') >= 0;
+ params.hasChild = params.hasParent = false;
+
+ onParseVar = function(nm)
+ {
+ if (nm.match(/^\s*[$]smarty.block.child\s*$/))
+ {
+ params.hasChild = true;
+ }
+ if (nm.match(/^\s*[$]smarty.block.parent\s*$/))
+ {
+ params.hasParent = true;
+ }
+ }
+ var tree = parse(content, []);
+ onParseVar = function(nm) {}
+
+ var blockName = trimQuotes(params.name?params.name:params[0]);
+ if (!(blockName in blocks))
+ {
+ blocks[blockName] = [];
+ }
+ blocks[blockName].push({tree:tree, params:params});
+ },
+
+ process: function(node, data)
+ {
+ data.smarty.block.parent = data.smarty.block.child = '';
+ var blockName = trimQuotes(node.params.name?node.params.name:node.params[0]);
+ this.processBlocks(blocks[blockName], blocks[blockName].length-1, data);
+ return data.smarty.block.child;
+ },
+
+ processBlocks: function(blockAncestry, i, data)
+ {
+ if (!i && blockAncestry[i].params.hide) {
+ data.smarty.block.child = '';
+ return;
+ }
+ var append = true;
+ var prepend = false;
+ for (; i>=0; --i)
+ {
+ if (blockAncestry[i].params.hasParent)
+ {
+ var tmpChild = data.smarty.block.child;
+ data.smarty.block.child = '';
+ this.processBlocks(blockAncestry, i-1, data);
+ data.smarty.block.parent = data.smarty.block.child;
+ data.smarty.block.child = tmpChild;
+ }
+
+ var tmpChild = data.smarty.block.child;
+ var s = process(blockAncestry[i].tree, data);
+ data.smarty.block.child = tmpChild;
+
+ if (blockAncestry[i].params.hasChild)
+ {
+ data.smarty.block.child = s;
+ }
+ else if (append)
+ {
+ data.smarty.block.child = s + data.smarty.block.child;
+ }
+ else if (prepend)
+ {
+ data.smarty.block.child += s;
+ }
+ append = blockAncestry[i].params.append;
+ prepend = blockAncestry[i].params.prepend;
+ }
+ }
+ },
+
+ strip:
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ parse(content.replace(/[ \t]*[\r\n]+[ \t]*/g, ''), tree);
+ }
+ },
+
+ literal:
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ parseText(content, tree);
+ }
+ },
+
+ ldelim:
+ {
+ type: 'function',
+ parse: function(params, tree)
+ {
+ parseText(jSmart.prototype.left_delimiter, tree);
+ }
+ },
+
+ rdelim:
+ {
+ type: 'function',
+ parse: function(params, tree)
+ {
+ parseText(jSmart.prototype.right_delimiter, tree);
+ }
+ },
+
+ 'while':
+ {
+ type: 'block',
+ parse: function(params, tree, content)
+ {
+ tree.push({
+ type: 'build-in',
+ name: 'while',
+ params: params,
+ subTree: parse(content, [])
+ });
+ },
+
+ process: function(node, data)
+ {
+ var s = '';
+ while (getActualParamValues(node.params,data)[0])
+ {
+ if (data.smarty['break'])
+ {
+ break;
+ }
+ s += process(node.subTree, data);
+ data.smarty['continue'] = false;
+ }
+ data.smarty['break'] = false;
+ return s;
+ }
+ }
+ };
+
+ var plugins = {};
+ var modifiers = {};
+ var files = {};
+ var blocks = null;
+ var scripts = null;
+ var tpl_modifiers = [];
+
+ function parse(s, tree)
+ {
+ for (var openTag=findTag('',s); openTag; openTag=findTag('',s))
+ {
+ if (openTag.index)
+ {
+ parseText(s.slice(0,openTag.index),tree);
+ }
+ s = s.slice(openTag.index + openTag[0].length);
+
+ var res = openTag[1].match(/^\s*(\w+)(.*)$/);
+ if (res) //function
+ {
+ var nm = res[1];
+ var paramStr = (res.length>2) ? res[2].replace(/^\s+|\s+$/g,'') : '';
+
+ if (nm in buildInFunctions)
+ {
+ var buildIn = buildInFunctions[nm];
+ var params = ('parseParams' in buildIn ? buildIn.parseParams : parseParams)(paramStr);
+ if (buildIn.type == 'block')
+ {
+ s = s.replace(/^\n/,''); //remove new line after block open tag (like in Smarty)
+ var closeTag = findCloseTag('\/'+nm, nm+' +[^}]*', s);
+ buildIn.parse(params, tree, s.slice(0,closeTag.index));
+ s = s.slice(closeTag.index+closeTag[0].length);
+ }
+ else
+ {
+ buildIn.parse(params, tree);
+ if (nm == 'extends')
+ {
+ tree = []; //throw away further parsing except for {block}
+ }
+ }
+ s = s.replace(/^\n/,'');
+ }
+ else if (nm in plugins)
+ {
+ var plugin = plugins[nm];
+ if (plugin.type == 'block')
+ {
+ var closeTag = findCloseTag('\/'+nm, nm+' +[^}]*', s);
+ parsePluginBlock(nm, parseParams(paramStr), tree, s.slice(0,closeTag.index));
+ s = s.slice(closeTag.index+closeTag[0].length);
+ }
+ else if (plugin.type == 'function')
+ {
+ parsePluginFunc(nm, parseParams(paramStr), tree);
+ }
+ if (nm=='append' || nm=='assign' || nm=='capture' || nm=='eval' || nm=='include')
+ {
+ s = s.replace(/^\n/,'');
+ }
+ }
+ else //variable
+ {
+ buildInFunctions.expression.parse(openTag[1],tree);
+ }
+ }
+ else //variable
+ {
+ var node = buildInFunctions.expression.parse(openTag[1],tree);
+ if (node.type=='build-in' && node.name=='operator' && node.op == '=')
+ {
+ s = s.replace(/^\n/,'');
+ }
+ }
+ }
+ if (s)
+ {
+ parseText(s, tree);
+ }
+ return tree;
+ }
+
+ function parseText(text, tree)
+ {
+ if (parseText.parseEmbeddedVars)
+ {
+ var re = /([$][\w@]+)|`([^`]*)`/;
+ for (var found=re.exec(text); found; found=re.exec(text))
+ {
+ tree.push({type: 'text', data: text.slice(0,found.index)});
+ tree.push( parseExpression(found[1] ? found[1] : found[2]).tree );
+ text = text.slice(found.index + found[0].length);
+ }
+ }
+ tree.push({type: 'text', data: text});
+ return tree;
+ }
+
+ function parseFunc(name, params, tree)
+ {
+ params.__parsed.name = parseText(name,[])[0];
+ tree.push({
+ type: 'plugin',
+ name: '__func',
+ params: params
+ });
+ return tree;
+ }
+
+ function parseOperator(op, type, precedence, tree)
+ {
+ tree.push({
+ type: 'build-in',
+ name: 'operator',
+ op: op,
+ optype: type,
+ precedence: precedence,
+ params: {}
+ });
+ }
+
+ function parseVar(s, e, nm)
+ {
+ var rootName = e.token;
+ var parts = [{type:'text', data:nm.replace(/^(\w+)@(key|index|iteration|first|last|show|total)/gi, "$1__$2")}];
+
+ var re = /^(?:\.|\s*->\s*|\[\s*)/;
+ for (var op=s.match(re); op; op=s.match(re))
+ {
+ e.token += op[0];
+ s = s.slice(op[0].length);
+
+ var eProp = {value:'', tree:[]};
+ if (op[0].match(/\[/))
+ {
+ eProp = parseExpression(s);
+ if (eProp)
+ {
+ e.token += eProp.value;
+ parts.push( eProp.tree );
+ s = s.slice(eProp.value.length);
+ }
+
+ var closeOp = s.match(/\s*\]/);
+ if (closeOp)
+ {
+ e.token += closeOp[0];
+ s = s.slice(closeOp[0].length);
+ }
+ }
+ else
+ {
+ var parseMod = parseModifiers.stop;
+ parseModifiers.stop = true;
+ if (lookUp(s,eProp))
+ {
+ e.token += eProp.value;
+ var part = eProp.tree[0];
+ if (part.type == 'plugin' && part.name == '__func')
+ {
+ part.hasOwner = true;
+ }
+ parts.push( part );
+ s = s.slice(eProp.value.length);
+ }
+ else
+ {
+ eProp = false;
+ }
+ parseModifiers.stop = parseMod;
+ }
+
+ if (!eProp)
+ {
+ parts.push({type:'text', data:''});
+ }
+ }
+
+ e.tree.push({type: 'var', parts: parts});
+
+ e.value += e.token.substr(rootName.length);
+
+ onParseVar(e.token);
+
+ return s;
+ }
+
+ function onParseVar(nm) {}
+
+
+ var tokens =
+ [
+ {
+ re: /^\$([\w@]+)/, //var
+ parse: function(e, s)
+ {
+ parseModifiers(parseVar(s, e, RegExp.$1), e);
+ }
+ },
+ {
+ re: /^(true|false)/i, //bool
+ parse: function(e, s)
+ {
+ parseText(e.token.match(/true/i) ? '1' : '', e.tree);
+ }
+ },
+ {
+ re: /^'([^'\\]*(?:\\.[^'\\]*)*)'/, //single quotes
+ parse: function(e, s)
+ {
+ parseText(evalString(RegExp.$1), e.tree);
+ parseModifiers(s, e);
+ }
+ },
+ {
+ re: /^"([^"\\]*(?:\\.[^"\\]*)*)"/, //double quotes
+ parse: function(e, s)
+ {
+ var v = evalString(RegExp.$1);
+ var isVar = v.match(tokens[0].re);
+ if (isVar)
+ {
+ var eVar = {token:isVar[0], tree:[]};
+ parseVar(v, eVar, isVar[1]);
+ if (eVar.token.length == v.length)
+ {
+ e.tree.push( eVar.tree[0] );
+ return;
+ }
+ }
+ parseText.parseEmbeddedVars = true;
+ e.tree.push({
+ type: 'plugin',
+ name: '__quoted',
+ params: {__parsed: parse(v,[])}
+ });
+ parseText.parseEmbeddedVars = false;
+ parseModifiers(s, e);
+ }
+ },
+ {
+ re: /^(\w+)\s*[(]([)]?)/, //func()
+ parse: function(e, s)
+ {
+ var fnm = RegExp.$1;
+ var noArgs = RegExp.$2;
+ var params = parseParams(noArgs?'':s,/^\s*,\s*/);
+ parseFunc(fnm, params, e.tree);
+ e.value += params.toString();
+ parseModifiers(s.slice(params.toString().length), e);
+ }
+ },
+ {
+ re: /^\s*\(\s*/, //expression in parentheses
+ parse: function(e, s)
+ {
+ var parens = [];
+ e.tree.push(parens);
+ parens.parent = e.tree;
+ e.tree = parens;
+ }
+ },
+ {
+ re: /^\s*\)\s*/,
+ parse: function(e, s)
+ {
+ if (e.tree.parent) //it may be the end of func() or (expr)
+ {
+ e.tree = e.tree.parent;
+ }
+ }
+ },
+ {
+ re: /^\s*(\+\+|--)\s*/,
+ parse: function(e, s)
+ {
+ if (e.tree.length && e.tree[e.tree.length-1].type == 'var')
+ {
+ parseOperator(RegExp.$1, 'post-unary', 1, e.tree);
+ }
+ else
+ {
+ parseOperator(RegExp.$1, 'pre-unary', 1, e.tree);
+ }
+ }
+ },
+ {
+ re: /^\s*(===|!==|==|!=)\s*/,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$1, 'binary', 6, e.tree);
+ }
+ },
+ {
+ re: /^\s+(eq|ne|neq)\s+/i,
+ parse: function(e, s)
+ {
+ var op = RegExp.$1.replace(/ne(q)?/,'!=').replace(/eq/,'==');
+ parseOperator(op, 'binary', 6, e.tree);
+ }
+ },
+ {
+ re: /^\s*!\s*/,
+ parse: function(e, s)
+ {
+ parseOperator('!', 'pre-unary', 2, e.tree);
+ }
+ },
+ {
+ re: /^\s+not\s+/i,
+ parse: function(e, s)
+ {
+ parseOperator('!', 'pre-unary', 2, e.tree);
+ }
+ },
+ {
+ re: /^\s*(=|\+=|-=|\*=|\/=|%=)\s*/,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$1, 'binary', 10, e.tree);
+ }
+ },
+ {
+ re: /^\s*(\*|\/|%)\s*/,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$1, 'binary', 3, e.tree);
+ }
+ },
+ {
+ re: /^\s+mod\s+/i,
+ parse: function(e, s)
+ {
+ parseOperator('%', 'binary', 3, e.tree);
+ }
+ },
+ {
+ re: /^\s*(\+|-)\s*/,
+ parse: function(e, s)
+ {
+ if (!e.tree.length || e.tree[e.tree.length-1].name == 'operator')
+ {
+ parseOperator(RegExp.$1, 'pre-unary', 4, e.tree);
+ }
+ else
+ {
+ parseOperator(RegExp.$1, 'binary', 4, e.tree);
+ }
+ }
+ },
+ {
+ re: /^\s*(<=|>=|<>|<|>)\s*/,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$1.replace(/<>/,'!='), 'binary', 5, e.tree);
+ }
+ },
+ {
+ re: /^\s+(lt|lte|le|gt|gte|ge)\s+/i,
+ parse: function(e, s)
+ {
+ var op = RegExp.$1.replace(/lt/,'<').replace(/l(t)?e/,'<=').replace(/gt/,'>').replace(/g(t)?e/,'>=');
+ parseOperator(op, 'binary', 5, e.tree);
+ }
+ },
+ {
+ re: /^\s+(is\s+(not\s+)?div\s+by)\s+/i,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$2?'div_not':'div', 'binary', 7, e.tree);
+ }
+ },
+ {
+ re: /^\s+is\s+(not\s+)?(even|odd)(\s+by\s+)?\s*/i,
+ parse: function(e, s)
+ {
+ var op = RegExp.$1 ? ((RegExp.$2=='odd')?'even':'even_not') : ((RegExp.$2=='odd')?'even_not':'even');
+ parseOperator(op, 'binary', 7, e.tree);
+ if (!RegExp.$3)
+ {
+ parseText('1', e.tree);
+ }
+ }
+ },
+ {
+ re: /^\s*(&&)\s*/,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$1, 'binary', 8, e.tree);
+ }
+ },
+ {
+ re: /^\s*(\|\|)\s*/,
+ parse: function(e, s)
+ {
+ parseOperator(RegExp.$1, 'binary', 9, e.tree);
+ }
+ },
+ {
+ re: /^\s+and\s+/i,
+ parse: function(e, s)
+ {
+ parseOperator('&&', 'binary', 11, e.tree);
+ }
+ },
+ {
+ re: /^\s+xor\s+/i,
+ parse: function(e, s)
+ {
+ parseOperator('xor', 'binary', 12, e.tree);
+ }
+ },
+ {
+ re: /^\s+or\s+/i,
+ parse: function(e, s)
+ {
+ parseOperator('||', 'binary', 13, e.tree);
+ }
+ },
+ {
+ re: /^#(\w+)#/, //config variable
+ parse: function(e, s)
+ {
+ var eVar = {token:'$smarty',tree:[]};
+ parseVar('.config.'+RegExp.$1, eVar, 'smarty');
+ e.tree.push( eVar.tree[0] );
+ parseModifiers(s, e);
+ }
+ },
+ {
+ re: /^\s*\[\s*/, //array
+ parse: function(e, s)
+ {
+ var params = parseParams(s, /^\s*,\s*/, /^('[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"|\w+)\s*=>\s*/);
+ parsePluginFunc('__array',params,e.tree);
+ e.value += params.toString();
+ var paren = s.slice(params.toString().length).match(/\s*\]/);
+ if (paren)
+ {
+ e.value += paren[0];
+ }
+ }
+ },
+ {
+ re: /^[\d.]+/, //number
+ parse: function(e, s)
+ {
+ if (e.token.indexOf('.') > -1) {
+ e.token = parseFloat(e.token);
+ } else {
+ e.token = parseInt(e.token, 10);
+ }
+ parseText(e.token, e.tree);
+ parseModifiers(s, e);
+ }
+ },
+ {
+ re: /^\w+/, //static
+ parse: function(e, s)
+ {
+ parseText(e.token, e.tree);
+ parseModifiers(s, e);
+ }
+ }
+ ];
+
+ function parseModifiers(s, e)
+ {
+ if (parseModifiers.stop)
+ {
+ return;
+ }
+
+ var modifier = s.match(/^\|(\w+)/);
+ if (!modifier)
+ {
+ return;
+ }
+
+ e.value += modifier[0];
+
+ var fnm = modifier[1]=='default' ? 'defaultValue' : modifier[1];
+ s = s.slice(modifier[0].length).replace(/^\s+/,'');
+
+ parseModifiers.stop = true;
+ var params = [];
+ for (var colon=s.match(/^\s*:\s*/); colon; colon=s.match(/^\s*:\s*/))
+ {
+ e.value += s.slice(0,colon[0].length);
+ s = s.slice(colon[0].length);
+
+ var param = {value:'', tree:[]};
+ if (lookUp(s, param))
+ {
+ e.value += param.value;
+ params.push(param.tree[0]);
+ s = s.slice(param.value.length);
+ }
+ else
+ {
+ parseText('',params);
+ }
+ }
+ parseModifiers.stop = false;
+
+ params.unshift(e.tree.pop()); //modifiers have the highest priority
+ e.tree.push(parseFunc(fnm,{__parsed:params},[])[0]);
+
+ parseModifiers(s, e); //modifiers can be combined
+ }
+
+ function lookUp(s,e)
+ {
+ if (!s)
+ {
+ return false;
+ }
+
+ if (s.substr(0,jSmart.prototype.left_delimiter.length)==jSmart.prototype.left_delimiter)
+ {
+ var tag = findTag('',s);
+ if (tag)
+ {
+ e.token = tag[0];
+ e.value += tag[0];
+ parse(tag[0], e.tree);
+ parseModifiers(s.slice(e.value.length), e);
+ return true;
+ }
+ }
+
+ for (var i=0; i<tokens.length; ++i)
+ {
+ if (s.match(tokens[i].re))
+ {
+ e.token = RegExp.lastMatch;
+ e.value += RegExp.lastMatch;
+ tokens[i].parse(e, s.slice(e.token.length));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function bundleOp(i, tree, precedence)
+ {
+ var op = tree[i];
+ if (op.name == 'operator' && op.precedence == precedence && !op.params.__parsed)
+ {
+ if (op.optype == 'binary')
+ {
+ op.params.__parsed = [tree[i-1],tree[i+1]];
+ tree.splice(i-1,3,op);
+ return true;
+ }
+ else if (op.optype == 'post-unary')
+ {
+ op.params.__parsed = [tree[i-1]];
+ tree.splice(i-1,2,op);
+ return true;
+ }
+
+ op.params.__parsed = [tree[i+1]];
+ tree.splice(i,2,op);
+ }
+ return false;
+ }
+
+ function composeExpression(tree)
+ {
+ var i = 0;
+ for (i=0; i<tree.length; ++i)
+ {
+ if (tree[i] instanceof Array)
+ {
+ tree[i] = composeExpression(tree[i])
+ }
+ }
+
+ for (var precedence=1; precedence<14; ++precedence)
+ {
+ if (precedence==2 || precedence==10)
+ {
+ for (i=tree.length; i>0; --i)
+ {
+ i -= bundleOp(i-1, tree, precedence);
+ }
+ }
+ else
+ {
+ for (i=0; i<tree.length; ++i)
+ {
+ i -= bundleOp(i, tree, precedence);
+ }
+ }
+ }
+ return tree[0]; //only one node must be left
+ }
+
+ function parseExpression(s)
+ {
+ var e = { value:'', tree:[] };
+ while (lookUp(s.slice(e.value.length), e)){}
+ if (!e.tree.length)
+ {
+ return false;
+ }
+ e.tree = composeExpression(e.tree);
+ return e;
+ }
+
+ function parseParams(paramsStr, reDelim, reName)
+ {
+ var s = paramsStr.replace(/\n/g,' ').replace(/^\s+|\s+$/g,'');
+ var params = [];
+ params.__parsed = [];
+ var paramsStr = '';
+
+ if (!s)
+ {
+ return params;
+ }
+
+ if (!reDelim)
+ {
+ reDelim = /^\s+/;
+ reName = /^(\w+)\s*=\s*/;
+ }
+
+ while (s)
+ {
+ var nm = null;
+ if (reName)
+ {
+ var foundName = s.match(reName);
+ if (foundName)
+ {
+ nm = trimQuotes(foundName[1]);
+ paramsStr += s.slice(0,foundName[0].length);
+ s = s.slice(foundName[0].length);
+ }
+ }
+
+ var param = parseExpression(s);
+ if (!param)
+ {
+ break;
+ }
+
+ if (nm)
+ {
+ params[nm] = param.value;
+ params.__parsed[nm] = param.tree;
+ }
+ else
+ {
+ params.push(param.value);
+ params.__parsed.push(param.tree);
+ }
+
+ paramsStr += s.slice(0,param.value.length);
+ s = s.slice(param.value.length);
+
+ var foundDelim = s.match(reDelim);
+ if (foundDelim)
+ {
+ paramsStr += s.slice(0,foundDelim[0].length);
+ s = s.slice(foundDelim[0].length);
+ }
+ else
+ {
+ break;
+ }
+ }
+ params.toString = function() { return paramsStr; }
+ return params;
+ }
+
+ function parsePluginBlock(name, params, tree, content)
+ {
+ tree.push({
+ type: 'plugin',
+ name: name,
+ params: params,
+ subTree: parse(content,[])
+ });
+ }
+
+ function parsePluginFunc(name, params, tree)
+ {
+ tree.push({
+ type: 'plugin',
+ name: name,
+ params: params
+ });
+ }
+
+ function getActualParamValues(params,data)
+ {
+ var actualParams = [];
+ for (var nm in params.__parsed)
+ {
+ if (params.__parsed.hasOwnProperty(nm))
+ {
+ var v = process([params.__parsed[nm]], data);
+ actualParams[nm] = v;
+ }
+ }
+
+ actualParams.__get = function(nm,defVal,id)
+ {
+ if (nm in actualParams && typeof(actualParams[nm]) != 'undefined')
+ {
+ return actualParams[nm];
+ }
+ if (typeof(id)!='undefined' && typeof(actualParams[id]) != 'undefined')
+ {
+ return actualParams[id];
+ }
+ if (defVal === null)
+ {
+ throw new Error("The required attribute '"+nm+"' is missing");
+ }
+ return defVal;
+ };
+ return actualParams;
+ }
+
+ /**
+ * Returns boolean true if object is empty otherwise false.
+ *
+ * @param object hash Object you are testing against.
+ *
+ * @return boolean
+ */
+ function isEmptyObject(hash) {
+ for (var i in hash) {
+ if (hash.hasOwnProperty(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function getVarValue(node, data, val)
+ {
+ var v = data;
+ var nm = '';
+ for (var i=0; i<node.parts.length; ++i)
+ {
+ var part = node.parts[i];
+ if (part.type == 'plugin' && part.name == '__func' && part.hasOwner)
+ {
+ data.__owner = v;
+ v = process([node.parts[i]],data);
+ delete data.__owner;
+ }
+ else
+ {
+ nm = process([part],data);
+
+ //section name
+ if (nm in data.smarty.section && part.type=='text' && process([node.parts[0]],data)!='smarty')
+ {
+ nm = data.smarty.section[nm].index;
+ }
+
+ //add to array
+ if (!nm && typeof val != 'undefined' && v instanceof Array)
+ {
+ nm = v.length;
+ }
+
+ //set new value
+ if (typeof val != 'undefined' && i==node.parts.length-1)
+ {
+ v[nm] = val;
+ }
+
+ if (typeof v == 'object' && v !== null && nm in v)
+ {
+ v = v[nm];
+ }
+ else
+ {
+ if (typeof val == 'undefined')
+ {
+ return val;
+ }
+ v[nm] = {};
+ v = v[nm];
+ }
+ }
+ }
+ return v;
+ }
+
+ function process(tree, data)
+ {
+ var res = '';
+ for (var i=0; i<tree.length; ++i)
+ {
+ var s = '';
+ var node = tree[i];
+ if (node.type == 'text')
+ {
+ s = node.data;
+ }
+ else if (node.type == 'var')
+ {
+ s = getVarValue(node,data);
+ }
+ else if (node.type == 'build-in')
+ {
+ s = buildInFunctions[node.name].process(node,data);
+ }
+ else if (node.type == 'plugin')
+ {
+ var plugin = plugins[node.name];
+ if (plugin.type == 'block')
+ {
+ var repeat = {value:true};
+ plugin.process(getActualParamValues(node.params,data), '', data, repeat);
+ while (repeat.value)
+ {
+ repeat.value = false;
+ s += plugin.process(
+ getActualParamValues(node.params,data),
+ process(node.subTree, data),
+ data,
+ repeat
+ );
+ }
+ }
+ else if (plugin.type == 'function')
+ {
+ s = plugin.process(getActualParamValues(node.params,data), data);
+ }
+ }
+ if (typeof s == 'boolean')
+ {
+ s = s ? '1' : '';
+ }
+ if (s == null) {
+ s = '';
+ }
+ if (tree.length == 1)
+ {
+ return s;
+ }
+ res += s!==null ? s : '';
+
+ if (data.smarty['continue'] || data.smarty['break'])
+ {
+ return res;
+ }
+ }
+ return res;
+ }
+
+ function getTemplate(name, tree, nocache)
+ {
+ if (nocache || !(name in files))
+ {
+ var tpl = jSmart.prototype.getTemplate(name);
+ if (typeof(tpl) != 'string')
+ {
+ throw new Error('No template for '+ name);
+ }
+ parse(applyFilters(jSmart.prototype.filters_global.pre, stripComments(tpl.replace(/\r\n/g,'\n'))), tree);
+ files[name] = tree;
+ }
+ else
+ {
+ tree = files[name];
+ }
+ return tree;
+ }
+
+ function stripComments(s)
+ {
+ var sRes = '';
+ for (var openTag=s.match(/{{\*/); openTag; openTag=s.match(/{{\*/))
+ {
+ sRes += s.slice(0,openTag.index);
+ s = s.slice(openTag.index+openTag[0].length);
+ var closeTag = s.match(/\*}}/);
+ if (!closeTag)
+ {
+ throw new Error('Unclosed {*');
+ }
+ s = s.slice(closeTag.index+closeTag[0].length);
+ }
+ return sRes + s;
+ }
+
+ function applyFilters(filters, s)
+ {
+ for (var i=0; i<filters.length; ++i)
+ {
+ s = filters[i](s);
+ }
+ return s;
+ }
+
+
+ jSmart = function(tpl)
+ {
+ this.tree = [];
+ this.tree.blocks = {};
+ this.scripts = {};
+ this.default_modifiers = [];
+ this.filters = {'variable':[], 'post':[]};
+ this.smarty = {
+ 'smarty': {
+ block: {},
+ 'break': false,
+ capture: {},
+ 'continue': false,
+ counter: {},
+ cycle: {},
+ foreach: {},
+ section: {},
+ now: Math.floor( (new Date()).getTime()/1000 ),
+ 'const': {},
+ config: {},
+ current_dir: '/',
+ template: '',
+ ldelim: jSmart.prototype.left_delimiter,
+ rdelim: jSmart.prototype.right_delimiter,
+ version: '2.15.0'
+ }
+ };
+ blocks = this.tree.blocks;
+ parse(
+ applyFilters(jSmart.prototype.filters_global.pre, stripComments((new String(tpl?tpl:'')).replace(/\r\n/g,'\n'))),
+ this.tree
+ );
+ };
+
+ jSmart.prototype.fetch = function(data)
+ {
+ blocks = this.tree.blocks;
+ scripts = this.scripts;
+ escape_html = this.escape_html;
+ default_modifiers = jSmart.prototype.default_modifiers_global.concat(this.default_modifiers);
+ this.data = obMerge((typeof data == 'object') ? data : {}, this.smarty);
+ varFilters = jSmart.prototype.filters_global.variable.concat(this.filters.variable);
+ var res = process(this.tree, this.data);
+ if (jSmart.prototype.debugging)
+ {
+ plugins.debug.process([],this.data);
+ }
+ return applyFilters(jSmart.prototype.filters_global.post.concat(this.filters.post), res);
+ };
+
+ jSmart.prototype.escape_html = false;
+
+ /**
+ @param type valid values are 'function', 'block', 'modifier'
+ @param callback func(params,data) or block(params,content,data,repeat)
+ */
+ jSmart.prototype.registerPlugin = function(type, name, callback)
+ {
+ if (type == 'modifier')
+ {
+ modifiers[name] = callback;
+ }
+ else
+ {
+ plugins[name] = {'type': type, 'process': callback};
+ }
+ };
+
+ /**
+ @param type valid values are 'pre', 'variable', 'post'
+ @param callback function(textValue) { ... }
+ */
+ jSmart.prototype.registerFilter = function(type, callback)
+ {
+ (this.tree ? this.filters : jSmart.prototype.filters_global)[type=='output'?'post':type].push(callback);
+ }
+
+ jSmart.prototype.filters_global = {'pre':[],'variable':[],'post':[]};
+
+ jSmart.prototype.configLoad = function(confValues, section, data)
+ {
+ data = data ? data : this.data;
+ var s = confValues.replace(/\r\n/g,'\n').replace(/^\s+|\s+$/g,'');
+ var re = /^\s*(?:\[([^\]]+)\]|(?:(\w+)[ \t]*=[ \t]*("""|'[^'\\\n]*(?:\\.[^'\\\n]*)*'|"[^"\\\n]*(?:\\.[^"\\\n]*)*"|[^\n]*)))/m;
+ var currSect = '';
+ for (var f=s.match(re); f; f=s.match(re))
+ {
+ s = s.slice(f.index+f[0].length);
+ if (f[1])
+ {
+ currSect = f[1];
+ }
+ else if ((!currSect || currSect == section) && currSect.substr(0,1) != '.')
+ {
+ if (f[3] == '"""')
+ {
+ var triple = s.match(/"""/);
+ if (triple)
+ {
+ data.smarty.config[f[2]] = s.slice(0,triple.index);
+ s = s.slice(triple.index + triple[0].length);
+ }
+ }
+ else
+ {
+ data.smarty.config[f[2]] = trimQuotes(f[3]);
+ }
+ }
+ var newln = s.match(/\n+/);
+ if (newln)
+ {
+ s = s.slice(newln.index + newln[0].length);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ jSmart.prototype.clearConfig = function(varName)
+ {
+ if (varName)
+ {
+ delete this.data.smarty.config[varName];
+ }
+ else
+ {
+ this.data.smarty.config = {};
+ }
+ }
+
+ /**
+ add modifier to implicitly apply to every variable in a template
+ @param modifiers single string (e.g. "replace:'from':'to'")
+ or array of strings (e.g. ['escape:"htmlall"', "replace:'from':'to'"])
+ */
+ jSmart.prototype.addDefaultModifier = function(modifiers)
+ {
+ if (!(modifiers instanceof Array))
+ {
+ modifiers = [modifiers];
+ }
+
+ for (var i=0; i<modifiers.length; ++i)
+ {
+ var e = { value:'', tree:[0] };
+ parseModifiers('|'+modifiers[i], e);
+ (this.tree ? this.default_modifiers : this.default_modifiers_global).push( e.tree[0] );
+ }
+ }
+
+ jSmart.prototype.default_modifiers_global = [];
+
+ /**
+ override this function
+ @param name value of 'file' parameter in {include} and {extends}
+ @return template text
+ */
+ jSmart.prototype.getTemplate = function(name)
+ {
+ throw new Error('No template for ' + name);
+ }
+
+ /**
+ override this function
+ @param name value of 'file' parameter in {fetch}
+ @return file content
+ */
+ jSmart.prototype.getFile = function(name)
+ {
+ throw new Error('No file for ' + name);
+ }
+
+ /**
+ override this function
+ @param name value of 'file' parameter in {include_php} and {include_javascript}
+ or value of 'script' parameter in {insert}
+ @return Javascript script
+ */
+ jSmart.prototype.getJavascript = function(name)
+ {
+ throw new Error('No Javascript for ' + name);
+ }
+
+ /**
+ override this function
+ @param name value of 'file' parameter in {config_load}
+ @return config file content
+ */
+ jSmart.prototype.getConfig = function(name)
+ {
+ throw new Error('No config for ' + name);
+ }
+
+
+
+ /**
+ whether to skip tags in open brace { followed by white space(s) and close brace } with white space(s) before
+ */
+ jSmart.prototype.auto_literal = true;
+
+ jSmart.prototype.left_delimiter = '{';
+ jSmart.prototype.right_delimiter = '}';
+
+ /** enables the debugging console */
+ jSmart.prototype.debugging = false;
+
+
+ jSmart.prototype.PHPJS = function(fnm, modifier)
+ {
+ if (eval('typeof '+fnm) == 'function')
+ {
+ return (typeof window == 'object') ? window : global;
+ }
+ else if (typeof(PHP_JS) == 'function')
+ {
+ return new PHP_JS();
+ }
+ throw new Error("Modifier '" + modifier + "' uses JavaScript port of PHP function '" + fnm + "'. You can find one at http://phpjs.org");
+ }
+
+ jSmart.prototype.makeTimeStamp = function(s)
+ {
+ if (!s)
+ {
+ return Math.floor( (new Date()).getTime()/1000 );
+ }
+ if (isNaN(s))
+ {
+ var tm = jSmart.prototype.PHPJS('strtotime','date_format').strtotime(s);
+ if (tm == -1 || tm === false) {
+ return Math.floor( (new Date()).getTime()/1000 );
+ }
+ return tm;
+ }
+ s = new String(s);
+ if (s.length == 14) //mysql timestamp format of YYYYMMDDHHMMSS
+ {
+ return Math.floor( (new Date(s.substr(0,4),s.substr(4,2)-1,s.substr(6,2),s.substr(8,2),s.substr(10,2)).getTime()/1000 ) );
+ }
+ return parseInt(s);
+ }
+
+
+
+ /**
+ register custom functions
+ */
+ jSmart.prototype.registerPlugin(
+ 'function',
+ '__array',
+ function(params, data)
+ {
+ var a = [];
+ for (var nm in params)
+ {
+ if (params.hasOwnProperty(nm) && params[nm] && typeof params[nm] != 'function')
+ {
+ a[nm] = params[nm];
+ }
+ }
+ return a;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ '__func',
+ function(params, data) {
+ var paramNames = [], paramValues = {}, paramData = [];
+ for (var i=0; i<params.length; ++i) {
+ paramNames.push(params.name+'__p'+i);
+ paramData.push(params[i]);
+ paramValues[params.name+'__p'+i] = params[i];
+ }
+ var fname, mergedParams = obMerge({}, data, paramValues);
+ if (('__owner' in data && params.name in data.__owner)) {
+ fname = '__owner.'+params.name;
+ return execute(fname + '(' + paramNames.join(',') + ')', mergedParams);
+ } else if (modifiers.hasOwnProperty(params.name)) {
+ fname = modifiers[params.name]
+ return executeByFuncObject(fname, paramData, mergedParams);
+ } else {
+ fname = params.name;
+ return execute(fname + '(' + paramNames.join(',') + ')', mergedParams);
+ }
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ '__quoted',
+ function(params, data)
+ {
+ return params.join('');
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'append',
+ function(params, data)
+ {
+ var varName = params.__get('var',null,0);
+ if (!(varName in data) || !(data[varName] instanceof Array))
+ {
+ data[varName] = [];
+ }
+ var index = params.__get('index',false);
+ var val = params.__get('value',null,1);
+ if (index === false)
+ {
+ data[varName].push(val);
+ }
+ else
+ {
+ data[varName][index] = val;
+ }
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'assign',
+ function(params, data)
+ {
+ assignVar(params.__get('var',null,0), params.__get('value',null,1), data);
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'break',
+ function(params, data)
+ {
+ data.smarty['break'] = true;
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'call',
+ function(params, data)
+ {
+ var fname = params.__get('name',null,0);
+ delete params.name;
+ var assignTo = params.__get('assign',false);
+ delete params.assign;
+ var s = plugins[fname].process(params, data);
+ if (assignTo)
+ {
+ assignVar(assignTo, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'block',
+ 'capture',
+ function(params, content, data, repeat)
+ {
+ if (content)
+ {
+ content = content.replace(/^\n/,'');
+ data.smarty.capture[params.__get('name','default',0)] = content;
+
+ if ('assign' in params)
+ {
+ assignVar(params.assign, content, data);
+ }
+
+ var append = params.__get('append',false);
+ if (append)
+ {
+ if (append in data)
+ {
+ if (data[append] instanceof Array)
+ {
+ data[append].push(content);
+ }
+ }
+ else
+ {
+ data[append] = [content];
+ }
+ }
+ }
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'continue',
+ function(params, data)
+ {
+ data.smarty['continue'] = true;
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'counter',
+ function(params, data)
+ {
+ var name = params.__get('name','default');
+ if (name in data.smarty.counter)
+ {
+ var counter = data.smarty.counter[name];
+ if ('start' in params)
+ {
+ counter.value = parseInt(params['start']);
+ }
+ else
+ {
+ counter.value = parseInt(counter.value);
+ counter.skip = parseInt(counter.skip);
+ if ('down' == counter.direction)
+ {
+ counter.value -= counter.skip;
+ }
+ else
+ {
+ counter.value += counter.skip;
+ }
+ }
+ counter.skip = params.__get('skip',counter.skip);
+ counter.direction = params.__get('direction',counter.direction);
+ counter.assign = params.__get('assign',counter.assign);
+ }
+ else
+ {
+ data.smarty.counter[name] = {
+ value: parseInt(params.__get('start',1)),
+ skip: parseInt(params.__get('skip',1)),
+ direction: params.__get('direction','up'),
+ assign: params.__get('assign',false)
+ };
+ }
+
+ if (data.smarty.counter[name].assign)
+ {
+ data[data.smarty.counter[name].assign] = data.smarty.counter[name].value;
+ return '';
+ }
+
+ if (params.__get('print',true))
+ {
+ return data.smarty.counter[name].value;
+ }
+
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'cycle',
+ function(params, data)
+ {
+ var name = params.__get('name','default');
+ var reset = params.__get('reset',false);
+ if (!(name in data.smarty.cycle))
+ {
+ data.smarty.cycle[name] = {arr: [''], delimiter: params.__get('delimiter',','), index: 0};
+ reset = true;
+ }
+
+ if (params.__get('delimiter',false))
+ {
+ data.smarty.cycle[name].delimiter = params.delimiter;
+ }
+ var values = params.__get('values',false);
+ if (values)
+ {
+ var arr = [];
+ if (values instanceof Object)
+ {
+ for (nm in values)
+ {
+ arr.push(values[nm]);
+ }
+ }
+ else
+ {
+ arr = values.split(data.smarty.cycle[name].delimiter);
+ }
+
+ if (arr.length != data.smarty.cycle[name].arr.length || arr[0] != data.smarty.cycle[name].arr[0])
+ {
+ data.smarty.cycle[name].arr = arr;
+ data.smarty.cycle[name].index = 0;
+ reset = true;
+ }
+ }
+
+ if (params.__get('advance','true'))
+ {
+ data.smarty.cycle[name].index += 1;
+ }
+ if (data.smarty.cycle[name].index >= data.smarty.cycle[name].arr.length || reset)
+ {
+ data.smarty.cycle[name].index = 0;
+ }
+
+ if (params.__get('assign',false))
+ {
+ assignVar(params.assign, data.smarty.cycle[name].arr[ data.smarty.cycle[name].index ], data);
+ return '';
+ }
+
+ if (params.__get('print',true))
+ {
+ return data.smarty.cycle[name].arr[ data.smarty.cycle[name].index ];
+ }
+
+ return '';
+ }
+ );
+
+ jSmart.prototype.print_r = function(v,indent)
+ {
+ if (v instanceof Object)
+ {
+ var s = ((v instanceof Array) ? 'Array['+v.length+']' : 'Object') + '<br>';
+ for (var nm in v)
+ {
+ if (v.hasOwnProperty(nm))
+ {
+ s += indent + ' <strong>' + nm + '</strong> : ' + jSmart.prototype.print_r(v[nm],indent+' ') + '<br>';
+ }
+ }
+ return s;
+ }
+ return v;
+ }
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'debug',
+ function(params, data)
+ {
+ if (typeof dbgWnd != 'undefined')
+ {
+ dbgWnd.close();
+ }
+ dbgWnd = window.open('','','width=680,height=600,resizable,scrollbars=yes');
+ var sVars = '';
+ var i=0;
+ for (var nm in data)
+ {
+ sVars += '<tr class=' + (++i%2?'odd':'even') + '><td><strong>' + nm + '</strong></td><td>' + jSmart.prototype.print_r(data[nm],'') + '</td></tr>';
+ }
+ dbgWnd.document.write(" \
+ <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'> \
+ <head> \
+ <title>jSmart Debug Console</title> \
+ <style type='text/css'> \
+ table {width: 100%;} \
+ td {vertical-align:top;width: 50%;} \
+ .even td {background-color: #fafafa;} \
+ </style> \
+ </head> \
+ <body> \
+ <h1>jSmart Debug Console</h1> \
+ <h2>assigned template variables</h2> \
+ <table>" + sVars + "</table> \
+ </body> \
+ </html> \
+ ");
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'eval',
+ function(params, data)
+ {
+ var tree = [];
+ parse(params.__get('var','',0), tree);
+ var s = process(tree, data);
+ if ('assign' in params)
+ {
+ assignVar(params.assign, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'fetch',
+ function(params, data)
+ {
+ var s = jSmart.prototype.getFile(params.__get('file',null,0));
+ if ('assign' in params)
+ {
+ assignVar(params.assign, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'html_checkboxes',
+ function (params, data) {
+ var type = params.__get('type','checkbox'),
+ name = params.__get('name',type),
+ realName = params.__get('name',type),
+ values = params.__get('values',params.options),
+ output = params.__get('options',[]),
+ useName = ('options' in params),
+ selected = params.__get('selected',false),
+ separator = params.__get('separator',''),
+ labels = Boolean(params.__get('labels',true)),
+ label_ids = Boolean(params.__get('label_ids',false)),
+ p,
+ res = [],
+ i = 0,
+ s = '',
+ value,
+ id;
+
+ if (type == 'checkbox') {
+ name += '[]';
+ }
+ if (!useName) {
+ for (p in params.output) {
+ output.push(params.output[p]);
+ }
+ }
+
+ for (p in values) {
+ if (values.hasOwnProperty(p)) {
+ value = (useName ? p : values[p]);
+ id = realName + '_' + value;
+ s = (labels ? ( label_ids ? '<label for="'+id+'">' : '<label>') : '');
+
+ s += '<input type="' + type + '" name="' + name + '" value="' + value + '" ';
+ if (label_ids) {
+ s += 'id="'+id+'" ';
+ }
+ if (selected == (useName ? p : values[p])) {
+ s += 'checked="checked" ';
+ }
+ s += '/>' + output[useName?p:i++];
+ s += (labels ? '</label>' : '');
+ s += separator;
+ res.push(s);
+ }
+ }
+ if ('assign' in params) {
+ assignVar(params.assign, res, data);
+ return '';
+ }
+ return res.join('\n');
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'html_image',
+ function (params, data) {
+ var url = params.__get('file', null),
+ width = params.__get('width', false),
+ height = params.__get('height', false),
+ alt = params.__get('alt', ''),
+ href = params.__get('href', params.__get('link', false)),
+ path_prefix = params.__get('path_prefix', ''),
+ paramNames = {file:1, width:1, height:1, alt:1, href:1, basedir:1, path_prefix:1, link:1},
+ s = '<img src="' + path_prefix + url + '"' + ' alt="'+alt+'"' + (width ? ' width="'+width+'"':'') + (height ? ' height="'+height+'"':''),
+ p;
+
+ for (p in params) {
+ if (params.hasOwnProperty(p) && typeof(params[p]) == 'string') {
+ if (!(p in paramNames)) {
+ s += ' ' + p + '="' + params[p] + '"';
+ }
+ }
+ }
+ s += ' />';
+ return href ? '<a href="'+href+'">'+s+'</a>' : s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'html_options',
+ function(params, data)
+ {
+ var values = params.__get('values',params.options);
+ var output = params.__get('options',[]);
+ var useName = ('options' in params);
+ var p;
+ if (!useName)
+ {
+ for (p in params.output)
+ {
+ output.push(params.output[p]);
+ }
+ }
+ var selected = params.__get('selected',false);
+
+ var res = [];
+ var s = '';
+ var i = 0;
+ for (p in values)
+ {
+ if (values.hasOwnProperty(p))
+ {
+ s = '<option value="' + (useName ? p : values[p]) + '"';
+ if (selected == (useName ? p : values[p]))
+ {
+ s += ' selected="selected"';
+ }
+ s += '>' + output[useName ? p : i++] + '</option>';
+ res.push(s);
+ }
+ }
+ var name = params.__get('name',false);
+ return (name ? ('<select name="' + name + '">\n' + res.join('\n') + '\n</select>') : res.join('\n')) + '\n';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'html_radios',
+ function(params, data)
+ {
+ params.type = 'radio';
+ return plugins.html_checkboxes.process(params,data);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'html_select_date',
+ function(params, data)
+ {
+ var prefix = params.__get('prefix','Date_');
+ var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
+
+ var s = '';
+ s += '<select name="'+prefix+'Month">\n';
+ var i=0;
+ for (i=0; i<months.length; ++i)
+ {
+ s += '<option value="' + i + '">' + months[i] + '</option>\n';
+ }
+ s += '</select>\n'
+
+ s += '<select name="'+prefix+'Day">\n';
+ for (i=0; i<31; ++i)
+ {
+ s += '<option value="' + i + '">' + i + '</option>\n';
+ }
+ s += '</select>\n'
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'html_table',
+ function(params, data)
+ {
+ var loop = [];
+ var p;
+ if (params.loop instanceof Array)
+ {
+ loop = params.loop
+ }
+ else
+ {
+ for (p in params.loop)
+ {
+ if (params.loop.hasOwnProperty(p))
+ {
+ loop.push( params.loop[p] );
+ }
+ }
+ }
+ var rows = params.__get('rows',false);
+ var cols = params.__get('cols',false);
+ if (!cols)
+ {
+ cols = rows ? Math.ceil(loop.length/rows) : 3;
+ }
+ var colNames = [];
+ if (isNaN(cols))
+ {
+ if (typeof cols == 'object')
+ {
+ for (p in cols)
+ {
+ if (cols.hasOwnProperty(p))
+ {
+ colNames.push(cols[p]);
+ }
+ }
+ }
+ else
+ {
+ colNames = cols.split(/\s*,\s*/);
+ }
+ cols = colNames.length;
+ }
+ rows = rows ? rows : Math.ceil(loop.length/cols);
+
+ var inner = params.__get('inner','cols');
+ var caption = params.__get('caption','');
+ var table_attr = params.__get('table_attr','border="1"');
+ var th_attr = params.__get('th_attr',false);
+ if (th_attr && typeof th_attr != 'object')
+ {
+ th_attr = [th_attr];
+ }
+ var tr_attr = params.__get('tr_attr',false);
+ if (tr_attr && typeof tr_attr != 'object')
+ {
+ tr_attr = [tr_attr];
+ }
+ var td_attr = params.__get('td_attr',false);
+ if (td_attr && typeof td_attr != 'object')
+ {
+ td_attr = [td_attr];
+ }
+ var trailpad = params.__get('trailpad',' ');
+ var hdir = params.__get('hdir','right');
+ var vdir = params.__get('vdir','down');
+
+ var s = '';
+ for (var row=0; row<rows; ++row)
+ {
+ s += '<tr' + (tr_attr ? ' '+tr_attr[row%tr_attr.length] : '') + '>\n';
+ for (var col=0; col<cols; ++col)
+ {
+ var idx = (inner=='cols') ? ((vdir=='down'?row:rows-1-row) * cols + (hdir=='right'?col:cols-1-col)) : ((hdir=='right'?col:cols-1-col) * rows + (vdir=='down'?row:rows-1-row));
+
+ s += '<td' + (td_attr ? ' '+td_attr[col%td_attr.length] : '') + '>' + (idx < loop.length ? loop[idx] : trailpad) + '</td>\n';
+ }
+ s += '</tr>\n';
+ }
+
+ var sHead = '';
+ if (colNames.length)
+ {
+ sHead = '\n<thead><tr>';
+ for (var i=0; i<colNames.length; ++i)
+ {
+ sHead += '\n<th' + (th_attr ? ' '+th_attr[i%th_attr.length] : '') + '>' + colNames[hdir=='right'?i:colNames.length-1-i] + '</th>';
+ }
+ sHead += '\n</tr></thead>';
+ }
+
+ return '<table ' + table_attr + '>' + (caption?'\n<caption>'+caption+'</caption>':'') + sHead + '\n<tbody>\n' + s + '</tbody>\n</table>\n';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'include',
+ function(params, data)
+ {
+ var file = params.__get('file',null,0);
+ var incData = obMerge({},data,params);
+ incData.smarty.template = file;
+ var s = process(getTemplate(file,[],findInArray(params,'nocache')>=0), incData);
+ if ('assign' in params)
+ {
+ assignVar(params.assign, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'include_javascript',
+ function(params, data)
+ {
+ var file = params.__get('file',null,0);
+ if (params.__get('once',true) && file in scripts)
+ {
+ return '';
+ }
+ scripts[file] = true;
+ var s = execute(jSmart.prototype.getJavascript(file), {'$this':data});
+ if ('assign' in params)
+ {
+ assignVar(params.assign, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'include_php',
+ function(params, data)
+ {
+ return plugins['include_javascript'].process(params,data);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'insert',
+ function(params, data)
+ {
+ var fparams = {};
+ for (var nm in params)
+ {
+ if (params.hasOwnProperty(nm) && isNaN(nm) && params[nm] && typeof params[nm] == 'string' && nm != 'name' && nm != 'assign' && nm != 'script')
+ {
+ fparams[nm] = params[nm];
+ }
+ }
+ var prefix = 'insert_';
+ if ('script' in params)
+ {
+ eval(jSmart.prototype.getJavascript(params.script));
+ prefix = 'smarty_insert_';
+ }
+ var func = eval(prefix+params.__get('name',null,0));
+ var s = func(fparams, data);
+ if ('assign' in params)
+ {
+ assignVar(params.assign, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'block',
+ 'javascript',
+ function(params, content, data, repeat)
+ {
+ data['$this'] = data;
+ execute(content,data);
+ delete data['$this'];
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'config_load',
+ function(params, data)
+ {
+ jSmart.prototype.configLoad(jSmart.prototype.getConfig(params.__get('file',null,0)), params.__get('section','',1), data);
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'mailto',
+ function(params, data)
+ {
+ var address = params.__get('address',null);
+ var encode = params.__get('encode','none');
+ var text = params.__get('text',address);
+ var cc = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('cc','')).replace('%40','@');
+ var bcc = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('bcc','')).replace('%40','@');
+ var followupto = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('followupto','')).replace('%40','@');
+ var subject = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode( params.__get('subject','') );
+ var newsgroups = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('newsgroups',''));
+ var extra = params.__get('extra','');
+
+ address += (cc?'?cc='+cc:'');
+ address += (bcc?(cc?'&':'?')+'bcc='+bcc:'');
+ address += (subject ? ((cc||bcc)?'&':'?') + 'subject='+subject : '');
+ address += (newsgroups ? ((cc||bcc||subject)?'&':'?') + 'newsgroups='+newsgroups : '');
+ address += (followupto ? ((cc||bcc||subject||newsgroups)?'&':'?') + 'followupto='+followupto : '');
+
+ s = '<a href="mailto:' + address + '" ' + extra + '>' + text + '</a>';
+
+ if (encode == 'javascript')
+ {
+ s = "document.write('" + s + "');";
+ var sEncoded = '';
+ for (var i=0; i<s.length; ++i)
+ {
+ sEncoded += '%' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(s.substr(i,1));
+ }
+ return '<script type="text/javascript">eval(unescape(\'' + sEncoded + "'))</script>";
+ }
+ else if (encode == 'javascript_charcode')
+ {
+ var codes = [];
+ for (var i=0; i<s.length; ++i)
+ {
+ codes.push(jSmart.prototype.PHPJS('ord','mailto').ord(s.substr(i,1)));
+ }
+ return '<script type="text/javascript" language="javascript">\n<!--\n{document.write(String.fromCharCode('
+ + codes.join(',') + '))}\n//-->\n</script>\n';
+ }
+ else if (encode == 'hex')
+ {
+ if (address.match(/^.+\?.+$/))
+ {
+ throw new Error('mailto: hex encoding does not work with extra attributes. Try javascript.');
+ }
+ var aEncoded = '';
+ for (var i=0; i<address.length; ++i)
+ {
+ if (address.substr(i,1).match(/\w/))
+ {
+ aEncoded += '%' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(address.substr(i,1));
+ }
+ else
+ {
+ aEncoded += address.substr(i,1);
+ }
+ }
+ aEncoded = aEncoded.toLowerCase();
+ var tEncoded = '';
+ for (var i=0; i<text.length; ++i)
+ {
+ tEncoded += '&#x' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(text.substr(i,1)) + ';';
+ }
+ tEncoded = tEncoded.toLowerCase();
+ return '<a href="mailto:' + aEncoded + '" ' + extra + '>' + tEncoded + '</a>';
+ }
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'function',
+ 'math',
+ function(params, data)
+ {
+ with (Math)
+ {
+ with (params)
+ {
+ var res = eval(params.__get('equation',null).replace(/pi\(\s*\)/g,'PI'));
+ }
+ }
+
+ if ('format' in params)
+ {
+ res = jSmart.prototype.PHPJS('sprintf','math').sprintf(params.format,res);
+ }
+
+ if ('assign' in params)
+ {
+ assignVar(params.assign, res, data);
+ return '';
+ }
+ return res;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'block',
+ 'nocache',
+ function(params, content, data, repeat)
+ {
+ return content;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'block',
+ 'textformat',
+ function(params, content, data, repeat)
+ {
+ if (!content) {
+ return '';
+ }
+
+ content = new String(content);
+
+ var wrap = params.__get('wrap',80);
+ var wrap_char = params.__get('wrap_char','\n');
+ var wrap_cut = params.__get('wrap_cut',false);
+ var indent_char = params.__get('indent_char',' ');
+ var indent = params.__get('indent',0);
+ var indentStr = (new Array(indent+1)).join(indent_char);
+ var indent_first = params.__get('indent_first',0);
+ var indentFirstStr = (new Array(indent_first+1)).join(indent_char);
+
+ var style = params.__get('style','');
+
+ if (style == 'email') {
+ wrap = 72;
+ }
+
+ var paragraphs = content.split(/[\r\n]{2}/);
+ for (var i=0; i<paragraphs.length; ++i) {
+ var p = paragraphs[i];
+ if (!p) {
+ continue;
+ }
+ p = p.replace(/^\s+|\s+$/,'').replace(/\s+/g,' ');
+ if (indent_first> 0 ) {
+ p = indentFirstStr + p;
+ }
+ p = modifiers.wordwrap(p, wrap-indent, wrap_char, wrap_cut);
+ if (indent > 0) {
+ p = p.replace(/^/mg, indentStr);
+ }
+ paragraphs[i] = p;
+ }
+ var s = paragraphs.join(wrap_char+wrap_char);
+ if ('assign' in params)
+ {
+ assignVar(params.assign, s, data);
+ return '';
+ }
+ return s;
+ }
+ );
+
+
+ /**
+ register modifiers
+ */
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'capitalize',
+ function(s, upDigits, lcRest) {
+ if (typeof s != 'string') {
+ return s;
+ }
+ var re = new RegExp(upDigits ? '[^a-zA-Z_\u00E0-\u00FC]+' : '[^a-zA-Z0-9_\u00E0-\u00FC]');
+ var found = null;
+ var res = '';
+ if (lcRest) {
+ s = s.toLowerCase();
+ }
+ for (found=s.match(re); found; found=s.match(re))
+ {
+ var word = s.slice(0,found.index);
+ if (word.match(/\d/))
+ {
+ res += word;
+ }
+ else
+ {
+ res += word.charAt(0).toUpperCase() + word.slice(1);
+ }
+ res += s.slice(found.index, found.index+found[0].length);
+ s = s.slice(found.index+found[0].length);
+ }
+ if (s.match(/\d/))
+ {
+ return res + s;
+ }
+ return res + s.charAt(0).toUpperCase() + s.slice(1);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'cat',
+ function(s, value)
+ {
+ value = value ? value : '';
+ return new String(s) + value;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'count',
+ function(v, recursive)
+ {
+ if (v === null || typeof v === 'undefined') {
+ return 0;
+ } else if (v.constructor !== Array && v.constructor !== Object) {
+ return 1;
+ }
+
+ recursive = Boolean(recursive);
+ var k, cnt = 0;
+ for (k in v)
+ {
+ if (v.hasOwnProperty(k))
+ {
+ cnt++;
+ if (recursive && v[k] && (v[k].constructor === Array || v[k].constructor === Object)) {
+ cnt += modifiers.count(v[k], true);
+ }
+ }
+ }
+ return cnt;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'count_characters',
+ function(s, includeWhitespaces)
+ {
+ s = new String(s);
+ return includeWhitespaces ? s.length : s.replace(/\s/g,'').length;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'count_paragraphs',
+ function(s)
+ {
+ var found = (new String(s)).match(/\n+/g);
+ if (found)
+ {
+ return found.length+1;
+ }
+ return 1;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'count_sentences',
+ function(s)
+ {
+ if (typeof s == 'string')
+ {
+ var found = s.match(/[^\s]\.(?!\w)/g);
+ if (found)
+ {
+ return found.length;
+ }
+ }
+ return 0;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'count_words',
+ function(s)
+ {
+ if (typeof s == 'string')
+ {
+ var found = s.match(/\w+/g);
+ if (found)
+ {
+ return found.length;
+ }
+ }
+ return 0;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'date_format',
+ function(s, fmt, defaultDate)
+ {
+ return jSmart.prototype.PHPJS('strftime','date_format').strftime(fmt?fmt:'%b %e, %Y', jSmart.prototype.makeTimeStamp(s?s:defaultDate));
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'defaultValue',
+ function(s, value)
+ {
+ return (s && s!='null' && s!='undefined') ? s : (value ? value : '');
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'unescape',
+ function(s, esc_type, char_set)
+ {
+ s = new String(s);
+ esc_type = esc_type || 'html';
+ char_set = char_set || 'UTF-8';
+
+ switch (esc_type)
+ {
+ case 'html':
+ return s.replace(/</g, '<').replace(/>/g,'>').replace(/'/g,"'").replace(/"/g,'"');
+ case 'entity':
+ case 'htmlall':
+ return jSmart.prototype.PHPJS('html_entity_decode','unescape').html_entity_decode(s, 1);
+ case 'url':
+ return jSmart.prototype.PHPJS('rawurldecode','unescape').rawurldecode(s);
+ };
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'escape',
+ function(s, esc_type, char_set, double_encode)
+ {
+ s = new String(s);
+ esc_type = esc_type || 'html';
+ char_set = char_set || 'UTF-8';
+ double_encode = (typeof double_encode != 'undefined') ? Boolean(double_encode) : true;
+
+ switch (esc_type)
+ {
+ case 'html':
+ if (double_encode) {
+ s = s.replace(/&/g, '&');
+ }
+ return s.replace(/</g,'<').replace(/>/g,'>').replace(/'/g,''').replace(/"/g,'"');
+ case 'htmlall':
+ return jSmart.prototype.PHPJS('htmlentities','escape').htmlentities(s, 3, char_set);
+ case 'url':
+ return jSmart.prototype.PHPJS('rawurlencode','escape').rawurlencode(s);
+ case 'urlpathinfo':
+ return jSmart.prototype.PHPJS('rawurlencode','escape').rawurlencode(s).replace(/%2F/g, '/');
+ case 'quotes':
+ return s.replace(/(^|[^\\])'/g, "$1\\'");
+ case 'hex':
+ var res = '';
+ for (var i=0; i<s.length; ++i)
+ {
+ res += '%' + jSmart.prototype.PHPJS('bin2hex','escape').bin2hex(s.substr(i,1)).toLowerCase();
+ }
+ return res;
+ case 'hexentity':
+ var res = '';
+ for (var i=0; i<s.length; ++i) {
+ res += '&#x' + jSmart.prototype.PHPJS('bin2hex','escape').bin2hex(s.substr(i,1)) + ';';
+ }
+ return res;
+ case 'decentity':
+ var res = '';
+ for (var i=0; i<s.length; ++i) {
+ res += '&#' + jSmart.prototype.PHPJS('ord','escape').ord(s.substr(i,1)) + ';';
+ }
+ return res;
+ case 'mail':
+ return s.replace(/@/g,' [AT] ').replace(/[.]/g,' [DOT] ');
+ case 'nonstd':
+ var res = '';
+ for (var i=0; i<s.length; ++i)
+ {
+ var _ord = jSmart.prototype.PHPJS('ord','escape').ord(s.substr(i,1));
+ if (_ord >= 126) {
+ res += '&#' + _ord + ';';
+ } else {
+ res += s.substr(i, 1);
+ }
+
+ }
+ return res;
+ case 'javascript':
+ return s.replace(/\\/g,'\\\\').replace(/'/g,"\\'").replace(/"/g,'\\"').replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/<\//g,'<\/');
+ };
+ return s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'indent',
+ function(s, repeat, indentWith)
+ {
+ s = new String(s);
+ repeat = repeat ? repeat : 4;
+ indentWith = indentWith ? indentWith : ' ';
+
+ var indentStr = '';
+ while (repeat--)
+ {
+ indentStr += indentWith;
+ }
+
+ var tail = s.match(/\n+$/);
+ return indentStr + s.replace(/\n+$/,'').replace(/\n/g,'\n'+indentStr) + (tail ? tail[0] : '');
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'lower',
+ function(s)
+ {
+ return new String(s).toLowerCase();
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'nl2br',
+ function(s)
+ {
+ return new String(s).replace(/\n/g,'<br />\n');
+ }
+ );
+
+ /**
+ only modifiers (flags) 'i' and 'm' are supported
+ backslashes should be escaped e.g. \\s
+ */
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'regex_replace',
+ function(s, re, replaceWith)
+ {
+ var pattern = re.match(/^ *\/(.*)\/(.*) *$/);
+ return (new String(s)).replace(new RegExp(pattern[1],'g'+(pattern.length>1?pattern[2]:'')), replaceWith);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'replace',
+ function(s, search, replaceWith)
+ {
+ if (!search)
+ {
+ return s;
+ }
+ s = new String(s);
+ search = new String(search);
+ replaceWith = new String(replaceWith);
+ var res = '';
+ var pos = -1;
+ for (pos=s.indexOf(search); pos>=0; pos=s.indexOf(search))
+ {
+ res += s.slice(0,pos) + replaceWith;
+ pos += search.length;
+ s = s.slice(pos);
+ }
+ return res + s;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'spacify',
+ function(s, space)
+ {
+ if (!space)
+ {
+ space = ' ';
+ }
+ return (new String(s)).replace(/(\n|.)(?!$)/g,'$1'+space);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'noprint',
+ function(s)
+ {
+ return '';
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'string_format',
+ function(s, fmt)
+ {
+ return jSmart.prototype.PHPJS('sprintf','string_format').sprintf(fmt,s);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'strip',
+ function(s, replaceWith)
+ {
+ replaceWith = replaceWith ? replaceWith : ' ';
+ return (new String(s)).replace(/[\s]+/g, replaceWith);
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'strip_tags',
+ function(s, addSpace)
+ {
+ addSpace = (addSpace==null) ? true : addSpace;
+ return (new String(s)).replace(/<[^>]*?>/g, addSpace ? ' ' : '');
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'truncate',
+ function(s, length, etc, breakWords, middle)
+ {
+ s = new String(s);
+ length = length ? length : 80;
+ etc = (etc!=null) ? etc : '...';
+
+ if (s.length <= length)
+ {
+ return s;
+ }
+
+ length -= Math.min(length,etc.length);
+ if (middle)
+ {
+ //one of floor()'s should be replaced with ceil() but it so in Smarty
+ return s.slice(0,Math.floor(length/2)) + etc + s.slice(s.length-Math.floor(length/2));
+ }
+
+ if (!breakWords)
+ {
+ s = s.slice(0,length+1).replace(/\s+?(\S+)?$/,'');
+ }
+
+ return s.slice(0,length) + etc;
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'upper',
+ function(s)
+ {
+ return (new String(s)).toUpperCase();
+ }
+ );
+
+ jSmart.prototype.registerPlugin(
+ 'modifier',
+ 'wordwrap',
+ function(s, width, wrapWith, breakWords)
+ {
+ width = width || 80;
+ wrapWith = wrapWith || '\n';
+
+ var lines = (new String(s)).split('\n');
+ for (var i=0; i<lines.length; ++i)
+ {
+ var line = lines[i];
+ var parts = ''
+ while (line.length > width)
+ {
+ var pos = 0;
+ var found = line.slice(pos).match(/\s+/);
+ for (;found && (pos+found.index)<=width; found=line.slice(pos).match(/\s+/))
+ {
+ pos += found.index + found[0].length;
+ }
+ pos = pos || (breakWords ? width : (found ? found.index+found[0].length : line.length));
+ parts += line.slice(0,pos).replace(/\s+$/,'');// + wrapWith;
+ if (pos < line.length)
+ {
+ parts += wrapWith;
+ }
+ line = line.slice(pos);
+ }
+ lines[i] = parts + line;
+ }
+ return lines.join('\n');
+ }
+ );
+
+
+ String.prototype.fetch = function(data)
+ {
+ var tpl = new jSmart(this);
+ return tpl.fetch(data);
+ };
+
+ if (typeof module === "object" && module && typeof module.exports === "object") {
+ module.exports = jSmart;
+ } else {
+ if (typeof global !== "undefined") {
+ global.jSmart = jSmart;
+ }
+
+ if (typeof define === "function" && define.amd) {
+ define("jSmart", [], function () { return jSmart; });
+ }
+ }
+})();