diff --git a/css/style.css b/css/style.css index adc4d61f0..53b551fb9 100644 --- a/css/style.css +++ b/css/style.css @@ -1596,6 +1596,7 @@ ul.viewcontact_wrapper > li { .contact-wrapper.media { overflow: visible; word-wrap: break-word; + margin-top: 0; } /* bootstrap hack for .media */ .contact-wrapper.media .media-body { @@ -1710,3 +1711,35 @@ main .nav-tabs>li.active>a:hover { .theme-frio .back-bar .pointer-label { color: #999; } + +/* textcomplete for contact filtering*/ +#contact-list ul.dropdown-menu.textcomplete-dropdown.media-list { + position: relative !important; + top: inherit !important; + bottom: inherit !important; + left: inherit !important; + padding: 0; + margin-left: -15px; + margin-right: -15px; + background-color: transparent; + box-shadow: none; + border: none; +} +#contact-list ul.dropdown-menu.textcomplete-dropdown.media-list > li { + padding-left: 15px; + border-bottom: 1px solid rgba(238, 238, 238, $contentbg_transp); +} +#contact-list ul.dropdown-menu.textcomplete-dropdown.media-list > li:first-child { + display: none; +} +#contact-list ul.dropdown-menu.textcomplete-dropdown.media-list +.textcomplete-item > a { + padding: 0 !important; + border-left: none; + background-color: transparent !important; +} +/* this is a little hack for texcomplete contact filter +There are for some reasons empty tags. I don't know why */ +.textcomplete-item .contact-wrapper a { + padding: 0; +} diff --git a/frameworks/jsmart/jsmart.js b/frameworks/jsmart/jsmart.js new file mode 100644 index 000000000..5c3264154 --- /dev/null +++ b/frameworks/jsmart/jsmart.js @@ -0,0 +1,3433 @@ +/*! + * jSmart Javascript template engine + * https://github.com/umakantp/jsmart + * + * Copyright 2011-2015, Max Miroshnikov + * Umakant Patil + * 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= 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': 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=0 && i=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\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 (!(a instanceof 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; i0; --i) + { + i -= bundleOp(i-1, tree, precedence); + } + } + else + { + for (i=0; i= 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') + '
'; + for (var nm in v) + { + if (v.hasOwnProperty(nm)) + { + s += indent + '  ' + nm + ' : ' + jSmart.prototype.print_r(v[nm],indent+'   ') + '
'; + } + } + 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 += '' + nm + '' + jSmart.prototype.print_r(data[nm],'') + ''; + } + dbgWnd.document.write(" \ + \ + \ + jSmart Debug Console \ + \ + \ + \ +

jSmart Debug Console

\ +

assigned template variables

\ + " + sVars + "
\ + \ + \ + "); + 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 ? '
' : 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 = '