mirror of
https://github.com/friendica/friendica
synced 2024-12-23 14:00:15 +00:00
3456 lines
108 KiB
JavaScript
3456 lines
108 KiB
JavaScript
/*!
|
|
* 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; });
|
|
}
|
|
}
|
|
})();
|