From 17958da20110876c454585920f90123392e96172 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Thu, 28 Apr 2016 21:35:33 +0200 Subject: [PATCH] introduce a filter function at the contact page. This is done with the help of textcomplete and jsmart.js. There is annoying bug inside. If the screensize is to small, the browser freezes. It is traced back to the "media-body" class (and its css attributes) which we use in the template. --- css/style.css | 33 + frameworks/jsmart/jsmart.js | 3433 +++++++++++++++++++++++++++++++ frameworks/jsmart/jsmart.min.js | 10 + js/theme.js | 62 +- php/modes/default.php | 1 + templates/contact_template.tpl | 82 +- templates/contacts-head.tpl | 23 + templates/contacts-template.tpl | 17 +- theme.php | 63 + 9 files changed, 3712 insertions(+), 12 deletions(-) create mode 100644 frameworks/jsmart/jsmart.js create mode 100644 frameworks/jsmart/jsmart.min.js create mode 100644 templates/contacts-head.tpl diff --git a/css/style.css b/css/style.css index adc4d61f06..53b551fb9f 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 0000000000..5c3264154c --- /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 = '