/** * Contemplate * Light-weight Object-Oriented Template Engine for PHP, Python, JavaScript * * @version: 1.6.0 * https://github.com/foo123/Contemplate * * @inspired by : Simple JavaScript Templating, John Resig - http://ejohn.org/ - MIT Licensed * http://ejohn.org/blog/javascript-micro-templating/ * **/ !function(root, name, factory) { "use strict"; if (('undefined'!==typeof Components)&&('object'===typeof Components.classes)&&('object'===typeof Components.classesByID)&&Components.utils&&('function'===typeof Components.utils['import'])) /* XPCOM */ (root.$deps = root.$deps||{}) && (root.EXPORTED_SYMBOLS = [name]) && (root[name] = root.$deps[name] = factory.call(root)); else if (('object'===typeof module)&&module.exports) /* CommonJS */ (module.$deps = module.$deps||{}) && (module.exports = module.$deps[name] = factory.call(root)); else if (('function'===typeof define)&&define.amd&&('function'===typeof require)&&('function'===typeof require.specified)&&require.specified(name) /*&& !require.defined(name)*/) /* AMD */ define(name,['module'],function(module){factory.moduleUri = module.uri; return factory.call(root);}); else if (!(name in root)) /* Browser/WebWorker/.. */ (root[name] = factory.call(root)||1)&&('function'===typeof(define))&&define.amd&&define(function(){return root[name];} ); }( /* current root */ 'undefined' !== typeof self ? self : this, /* module name */ "Contemplate", /* module factory */ function ModuleFactory__Contemplate(undef) { "use strict"; ///////////////////////////////////////////////////////////////////////////////////// // // Contemplate Engine Main Class // ////////////////////////////////////////////////////////////////////////////////////// // private vars var __version__ = "1.6.0", Contemplate, PROTO = 'prototype', Obj = Object, Arr = Array, HAS = Obj[PROTO].hasOwnProperty, toString = Obj[PROTO].toString, NOP = function( ){ }, isXPCOM = ("undefined" !== typeof Components) && ("object" === typeof Components.classes) && ("object" === typeof Components.classesByID) && Components.utils && ("function" === typeof Components.utils['import']), isNode = "undefined" !== typeof(global) && '[object global]' === toString.call(global), $Scope = this, Cu = isXPCOM ? Components.utils : null, Cc = isXPCOM ? Components.classes : null, Ci = isXPCOM ? Components.interfaces : null, import_ = isXPCOM ? Cu['import'] : (isNode ? require : NOP), fs = isNode ? import_('fs') : null, import_module = isXPCOM ? function import_module(name, path) {import_(path, $Scope); return $Scope[name];} : (isNode ? function import_module(name, path) {return import_(path);} : NOP), XHR = function() { return window.XMLHttpRequest // code for IE7+, Firefox, Chrome, Opera, Safari ? new XMLHttpRequest() // code for IE6, IE5 : new ActiveXObject("Microsoft.XMLHTTP") // or ActiveXObject("Msxml2.XMLHTTP"); ?? ; }, $__isInited = false, $__leftTplSep = "<%", $__rightTplSep = "%>", $__tplStart = "", $__tplEnd = "", // https://nodejs.org/api/os.html#os_os_eol // $__EOL = "\n", $__TEOL = /*isNode ? import_('os').EOL :*/ "\n", $__escape = true, $__preserveLinesDefault = "' + \"\\n\" + '", $__preserveLines = '', $__level = 0, $__pad = " ", $__idcnt = 0, $__locals, $__variables, $__loops = 0, $__ifs = 0, $__loopifs = 0, $__forType = 2, $__allblocks = null, $__allblockscnt = null, $__openblocks = null, $__currentblock, $__startblock = null, $__endblock = null, $__blockptr = -1, $__extends = null, $__uses = null, $__strings = null, $__ctx, $__global, $__context, $__uuid = 0, UNDERLN = /[\W]+/g, NEWLINE = /\n\r|\r\n|\n|\r/g, SQUOTE = /'/g, DS_RE = /[\/\\]/, BASENAME_RE = /[\/\\]?[^\/\\]+$/, TAG_RE = /<\/?[a-zA-Z0-9:_\-]+[^<>]*>/gm, AMP_RE = /&+/g, ALPHA = /^[a-zA-Z_]/, NUM = /^[0-9]/, ALPHANUM = /^[a-zA-Z0-9_]/i, SPACE = /^\s/, ALL_SPACE = /^\s+$/, INDENT = /^(postdent|predent)\((-?\d+)\):/, re_controls = /(\t|\s?)\s*((#ID_(continue|endblock|elsefor|endfor|endif|break|else|fi)#(\s*\(\s*\))?)|(#ID_([^#]+)#\s*(\()))(.*)$/g, $__reserved_var_names = [ 'Contemplate', 'self', 'this', 'data', '__p__', '__i__', '__ctx' ], $__directives = [ 'set', 'unset', 'isset', 'if', 'elseif', 'else', 'endif', 'for', 'elsefor', 'endfor', 'extends', 'block', 'endblock', 'include', 'super', 'getblock', 'iif', 'empty', 'continue', 'break', 'local_set', 'get', 'local' ], $__directive_aliases = { 'elif' : 'elseif' ,'fi' : 'endif' }, $__aliases = { 'cc' : 'concat' ,'j' : 'join' ,'dq' : 'qq' ,'now' : 'time' ,'template' : 'tpl' }, // generated cached tpl class code as a "heredoc" template (for Node cached templates) TT_ClassCode, // generated cached tpl block method code as a "heredoc" template (for Node cached templates) TT_BlockCode, TT_BLOCK, TT_FUNC, TT_RCODE ; if (isXPCOM) { // do some necessary imports import_("resource://gre/modules/NetUtil.jsm"); import_("resource://gre/modules/FileUtils.jsm"); } /*function HAS(o, x) { return !!(o && Object.prototype.hasOwnProperty.call(o, x)); }*/ function reset_state() { $__loops = 0; $__ifs = 0; $__loopifs = 0; $__forType = 2; $__level = 0; $__allblocks = []; $__allblockscnt = {}; $__openblocks = [[null, -1]]; $__extends = null; $__uses = []; $__locals = {}; $__variables = {}; $__currentblock = '_'; $__locals[$__currentblock] = $__locals[$__currentblock] || {}; $__variables[$__currentblock] = $__variables[$__currentblock] || {}; } function clear_state() { $__loops = 0; $__ifs = 0; $__loopifs = 0; $__forType = 2; $__level = 0; $__allblocks = null; $__allblockscnt = null; $__openblocks = null; $__locals = null; $__variables = null; $__currentblock = null; $__idcnt = 0; $__strings = null; /*$__extends = null; $__uses = [];*/ } function push_state() { return [$__loops, $__ifs, $__loopifs, $__forType, $__level, $__allblocks, $__allblockscnt, $__openblocks, $__extends, $__locals, $__variables, $__currentblock, $__uses]; } function pop_state(state) { $__loops = state[0]; $__ifs = state[1]; $__loopifs = state[2]; $__forType = state[3]; $__level = state[4]; $__allblocks = state[5]; $__allblockscnt = state[6]; $__openblocks = state[7]; $__extends = state[8]; $__locals = state[9]; $__variables = state[10]; $__currentblock = state[11]; $__uses = state[12]; } function remove_initial_space(s) { var l = s.length, sl, i, initial_space, c, pos; if (l) { initial_space = ''; for (i=0; i=start; --i) { l = lines[i]; if (l.length && !ALL_SPACE.test(l)) { end = i; break; } } return lines.slice(start, end+1).join("\n"); } function align(s, level) { // pad lines to generate formatted code if (2 > arguments.length) level = $__level; s = remove_initial_space(s); var aligned = '', alignment, c, i, l = s.length, is_line_start; if (l && (0 < level)) { alignment = new Arr(level+1).join($__pad); aligned = alignment; is_line_start = true; for (i=0; i1 ? "false"===trim(block[1]) : false); block = trim(block[0]); if ($__strings && HAS.call($__strings, block)) block = $__strings[block]; var ch = block.charAt(0); if (('"' === ch || "'" === ch) && (ch === block.charAt(block.length-1))) block = block.slice(1, -1); // quoted block $__allblocks.push([block, -1, -1, 0, $__openblocks[0][1], echoed]); $__allblockscnt[block] = $__allblockscnt[block] ? ($__allblockscnt[block]+1) : 1; $__blockptr = $__allblocks.length; $__openblocks.unshift([block, $__blockptr-1]); $__startblock = block; $__endblock = null; $__currentblock = block; $__locals[$__currentblock] = $__locals[$__currentblock] || {}; $__variables[$__currentblock] = $__variables[$__currentblock] || {}; return "' + #BLOCK_" + block + "#"; } function t_endblock() { if (1 < $__openblocks.length) { var block = $__openblocks.shift(); $__endblock = block[0]; $__blockptr = block[1]+1; $__startblock = null; $__currentblock = $__openblocks.length ? $__openblocks[0][0] : '_'; return "#/BLOCK_" + block[0] + "#"; } else { $__currentblock = '_'; } return ''; } // // auxilliary parsing methods function parse_constructs_async(s, cb) { // reset lastIndex of regex, else it may fail where it should succeed re_controls.lastIndex = 0; var match = re_controls.exec(s), s2; if (!match) { cb(null, s); return; } parse_constructs(match, function(err, replace) { if (err) { cb(err, null); return; } s2 = s.slice(0, match.index) + replace; // continue until end parse_constructs_async(s.slice(match.index+match[0].length), function(err, replace2) { if (err) { cb(err, null); return; } cb(null, s2+replace2); }); }); } function parse_constructs(match, cb) { cb = 'function' === typeof cb ? cb : null; /* main probelm with this function running async is the "include" directive which needs to read external files and may need to do it async, else rest parsing can be sync, specificaly args parsing can be synced even if original call is async since we can reasonably assume args will NOT contain "include" directive */ var match0 = match[0], match1 = match[1], match2 = match[2], match3 = match[3], match4 = match[4], match5 = match[5], match6 = match[6], match7 = match[7], match8 = match[8], match9 = match[9], prefix = match1 || '', ctrl = match4 || match7 || '', rest = match9 || '', startParen = match8 || false, args = '', out = '', paren = 0, l, i, ch, m, err, varname, tplvarname, expr, args2, usedTpl, parse_constructs_sync = function(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9) { return parse_constructs([m0,m1,m2,m3,m4,m5,m6,m7,m8,m9]); }; // parse parentheses and arguments, accurately if (startParen && startParen.length) { paren = 1; l = rest.length; i = 0; while (i < l && paren > 0) { ch = rest.charAt(i++); if ('(' === ch) ++paren; else if (')' === ch) --paren; if (paren > 0) args += ch; } rest = rest.slice(args.length+1); } args = trim(args); if (HAS.call($__directive_aliases, ctrl)) ctrl = $__directive_aliases[ctrl]; m = $__directives.indexOf(ctrl); if (-1 < m) { switch (m) { case 22 /*'local'*/: varname = trim(args); tplvarname = $__variables[$__currentblock][varname]; if (-1 !== $__reserved_var_names.indexOf(tplvarname)) { // should be different from 'this', 'data', .. as these are used internally err = new Contemplate.Exception('Contemplate Parse: Use of reserved name as local variable name "'+tplvarname+'"'); if (cb) { cb(err, null); return; } else { throw err; } } local_variable(varname, null, true); // make it a literal local variable out = "';" + $__TEOL + align('var ' + varname + ';') + $__TEOL; break; case 0 /*'set'*/: case 20 /*'local_set'*/: args = args.replace(re_controls, parse_constructs_sync); args = split_arguments(args, ','); varname = trim(args.shift()); expr = trim(args.join(',')); if (20 === m && !is_local_variable(varname)) { local_variable(varname); // make it a local variable varname = 'var ' + varname; } out = "';" + $__TEOL + align(varname + ' = ('+ expr +');') + $__TEOL; break; case 21 /*'get'*/: args = args.replace(re_controls, parse_constructs_sync); out = prefix + 'Contemplate.get(' + args + ')'; break; case 1 /*'unset'*/: args = args.replace(re_controls, parse_constructs_sync); varname = args; if (varname && varname.length) { varname = trim(varname); out = "';" + $__TEOL + align('if ("undefined" !== typeof(' + varname + ')) delete ' + varname + ';') + $__TEOL; } else { out = "';" + $__TEOL; } break; case 2 /*'isset'*/: args = args.replace(re_controls, parse_constructs_sync); varname = args; out = '("undefined" !== typeof(' + varname + ') && null !== ' + varname + ')'; break; case 3 /*'if'*/: args = args.replace(re_controls, parse_constructs_sync); out = "';" + align([ "" ,"if ("+args+")" ,"{" ,"" ].join($__TEOL)); ++$__ifs; ++$__level; break; case 4 /*'elseif'*/: args = args.replace(re_controls, parse_constructs_sync); --$__level; out = "';" + align([ "" ,"}" ,"else if ("+args+")" ,"{" ,"" ].join($__TEOL)); ++$__level; break; case 5 /*'else'*/: --$__level; out = "';" + align([ "" ,"}" ,"else" ,"{" ,"" ].join($__TEOL)); ++$__level; break; case 6 /*'endif'*/: --$__ifs; --$__level; out = "';" + align([ "" ,"}" ,"" ].join($__TEOL)); break; case 7 /*'for'*/: args = args.replace(re_controls, parse_constructs_sync); var for_expr = args, is_php_style = for_expr.indexOf(' as '), is_python_style = for_expr.indexOf(' in '), o, _o, kv, isAssoc ; if (-1 < is_python_style) { for_expr = [for_expr.slice(0, is_python_style), for_expr.slice(is_python_style+4)]; o = trim(for_expr[1]); _o = local_variable(); kv = for_expr[0].split(','); } else/*if ( -1 < is_php_style )*/ { for_expr = [for_expr.slice(0, is_php_style), for_expr.slice(is_php_style+4)]; o = trim(for_expr[0]); _o = local_variable(); kv = for_expr[1].split('=>'); } isAssoc = kv.length >= 2 // http://jsperf.com/values-extraction/5 // raw 'in' loop with .hasOwnProperty is faster than looping over Object.keys if (isAssoc) { var k = trim(kv[0]), v = trim(kv[1]), _oK = local_variable(), _k = local_variable(), _l = local_variable() ; out = "';"; if (!is_local_variable(k)) { local_variable(k); out += $__TEOL + align('var ' + k + ';'); } if (!is_local_variable(v)) { local_variable(v); out += $__TEOL + align('var ' + v + ';'); } out += align([ "" ,"var "+_o+" = "+o+", "+_oK+" = "+_o+" ? Object.keys("+_o+") : null," ," "+_k+", "+_l+" = "+_o+" ? "+_oK+".length : 0;" ,"if ("+_l+")" ,"{" ," for ("+_k+"=0; "+_k+"<"+_l+"; ++"+_k+")" ," {" ," "+k+" = "+_oK+"["+_k+"]; "+v+" = "+_o+"["+k+"];" ," " ,"" ].join($__TEOL)); $__forType = 2; $__level+=2; } else { var v = trim(kv[0]), _oV = local_variable(), _arr = local_variable(), _k = local_variable(), _kk = local_variable(), _l = local_variable() ; out = "';"; if (!is_local_variable(v)) { local_variable(v); out += $__TEOL + align('var ' + v + ';'); } out += align([ "" ,"var "+_o+" = "+o+", "+_arr+" = !!"+_o+".forEach," ," "+_oV+" = "+_o+" ? ("+_arr+" ? "+_o+" : Object.keys("+_o+")) : null," ," "+_k+", "+_kk+", "+_l+" = "+_oV+" ? "+_oV+".length : 0;" ,"if ("+_l+")" ,"{" ," for ("+_k+"=0; "+_k+"<"+_l+"; ++"+_k+")" ," {" ," "+_kk+" = "+_oV+"["+_k+"];" ," "+v+" = "+_arr+" ? "+_kk+" : "+_o+"["+_kk+"];" ," " ,"" ].join($__TEOL)); $__forType = 1; $__level+=2; } ++$__loops; ++$__loopifs; break; case 8 /*'elsefor'*/: /* else attached to for loop */ if (2 === $__forType) { --$__loopifs; $__level+=-2; out = "';" + align([ "" ," }" ,"}" ,"else" ,"{ " ,"" ].join($__TEOL)); ++$__level; } else { --$__loopifs; $__level+=-2; out = "';" + align([ "" ," }" ,"}" ,"else" ,"{ " ,"" ].join($__TEOL)); ++$__level; } break; case 9 /*'endfor'*/: if ($__loopifs === $__loops) { if (2 === $__forType) { --$__loops; --$__loopifs; $__level+=-2; out = "';" + align([ "" ," }" ,"}" ,"" ].join($__TEOL)); } else { --$__loops; --$__loopifs; $__level+=-2; out = "';" + align([ "" ," }" ,"}" ,"" ].join($__TEOL)); } } else { --$__loops; --$__level; out = "';" + align([ "" ,"}" ,"" ].join($__TEOL)); } break; case 10 /*'extends'*/: var id = trim(args); if ($__strings && HAS.call($__strings, id)) id = $__strings[id]; var ch = id.charAt(0); if (('"' === ch || "'" === ch) && (ch === id.charAt(id.length-1))) id = id.slice(1, -1); // quoted id $__extends = id; out = "';" + $__TEOL; break; case 11 /*'block'*/: out = t_block(args); break; case 12 /*'endblock'*/: out = t_endblock(); break; case 13 /*'include'*/: out = cb ? '' : t_include(args); break; case 14 /*'super'*/: args = args.replace(re_controls, parse_constructs_sync); out = prefix + 'self.sprblock(' + args + ', data)'; break; case 15 /*'getblock'*/: args = args.replace(re_controls, parse_constructs_sync); out = prefix + '__i__.block(' + args + ', data)'; break; case 16 /*'iif'*/: args = split_arguments(args.replace(re_controls, parse_constructs_sync), ','); out = prefix + "(("+args[0]+") ? ("+args[1]+") : ("+args[2]+"))"; break; case 17 /*'empty'*/: args = args.replace(re_controls, parse_constructs_sync); out = prefix + '(("undefined" === typeof(' + args + ')) || (null === ' + args + ') || Contemplate.empty(' + args + '))'; break; case 18 /*'continue'*/: case 19 /*'break'*/: out = "';" + $__TEOL + align(18 === m ? 'continue;' : 'break;') + $__TEOL; break; } if (cb) { if (13 === m)/*'include'*/ { // include may be async now t_include(args, function(err, out) { if (err) { cb(err, null); return; } parse_constructs_async(rest, function(err, rest2) { if (err) { cb(err, null); return; } cb(null, out + rest2); }); }); } else { parse_constructs_async(rest, function(err, rest2) { if (err) { cb(err, null); return; } cb(null, out + rest2); }); } return; } else { return out + rest.replace(re_controls, parse_constructs_sync); } } if (HAS.call($__context.plugins, ctrl) || HAS.call($__global.plugins, ctrl)) { // allow custom plugins as template functions var pl = $__context.plugins[ctrl] || $__global.plugins[ctrl]; args = args.replace(re_controls, parse_constructs_sync); out = pl instanceof Contemplate.InlineTemplate ? pl.render([args].concat(split_arguments(args, ','))) : 'Contemplate.plg_("' + ctrl + '"' + (!args.length ? '' : ','+args) + ')'; if (cb) { parse_constructs_async(rest, function(err, rest2) { if (err) { cb(err, null); return; } cb(null, prefix + out + rest2); }); return; } else { return prefix + out + rest.replace(re_controls, parse_constructs_sync); } } if (HAS.call($__aliases, ctrl)) ctrl = $__aliases[ctrl]; args = args.replace(re_controls, parse_constructs_sync); // aliases and builtin functions switch (ctrl) { case 's': out = 'String(' + args + ')'; break; case 'n': out = 'parseInt(' + args + ')'; break; case 'f': out = 'parseFloat(' + args + ')'; break; case 'q': out = '"\'"+(' + args + ')+"\'"'; break; case 'qq': out = '\'"\'+(' + args + ')+\'"\''; break; case 'concat': out = 'String('+split_arguments(args, ',').join(')+String(')+')'; break; case 'is_array': args = split_arguments(args, ','); if (args.length > 1) out = "(("+args[1]+") ? '[object Array]' === Object.prototype.toString.call("+args[0]+") : '[object Array]' === Object.prototype.toString.call("+args[0]+") || '[object Object]' === Object.prototype.toString.call("+args[0]+"))"; else out = "('[object Array]'===Object.prototype.toString.call("+args[0]+")||'[object Object]'===Object.prototype.toString.call("+args[0]+"))"; break; case 'in_array': args = split_arguments(args, ','); out = '(-1<('+args[1]+').indexOf('+args[0]+'))'; break; case 'tpl': args2 = split_arguments(args, ','); usedTpl = args2[0]; if ('#STR_' === usedTpl.slice(0, 5) && HAS.call($__strings, usedTpl)) { // only literal string support here usedTpl = $__strings[usedTpl].slice(1, -1); // without quotes if (-1 === $__uses.indexOf(usedTpl)) $__uses.push(usedTpl); } // no break default: if (HAS.call(Contemplate, ctrl) && ('function' === typeof Contemplate[ctrl])) { out = 'Contemplate.' + ctrl + '(' + args + ')'; } else { out = ctrl + (startParen ? '('+args+')' : ''); } } if (cb) { parse_constructs_async(rest, function(err, rest2) { if (err) { cb(err, null); return; } cb(null, prefix + out + rest2); }); return; } else { return prefix + out + rest.replace(re_controls, parse_constructs_sync); } } function parse_blocks(s) { var blocks = [], bl = $__allblocks.length, block, delims, tag, rep, tl, rl, pos1, pos2, off, containerblock, echoed, EOL = $__TEOL ; while (bl--) { delims = $__allblocks[bl]; block = delims[0]; pos1 = delims[1]; pos2 = delims[2]; off = delims[3]; containerblock = delims[4]; echoed = delims[5]; tag = "#BLOCK_" + block + "#"; rep = echoed ? "__i__.block('" + block + "', data);" : "'';"; tl = tag.length; rl = rep.length; if (-1 < containerblock) { // adjust the ending position of the container block (if nested) // to compensate for the replacements in this (nested) block $__allblocks[containerblock][3] += rl - (pos2-pos1+1); } // adjust the ending position of this block (if nested) // to compensate for the replacements of any (nested) block(s) pos2 += off; if (1 === $__allblockscnt[block]) { // 1st occurance, block definition blocks.push([block, TT_BLOCK.render({ 'BLOCKCODE' : s.slice( pos1+tl, pos2-tl-1 ) + "';" })]); } s = s.slice(0, pos1) + rep + s.slice(pos2+1); if (1 <= $__allblockscnt[block]) --$__allblockscnt[block]; } //$__allblocks = null; $__allblockscnt = null; $__openblocks = null; return [s, blocks]; } function parse_variable(s, i, l) { if (ALPHA.test(s[i])) { var strings = {}, variables = [], subvariables, id, variable, property, variable_raw, variable_main, variable_rest, len, lp, bracket, delim, ch, str_, q, escaped, si, is_prop_access, tok, strid, sub, space = 0, hasStrings = false ; // main variable variable = s.charAt(i++); while (i < l && ALPHANUM.test(ch=s.charAt(i))) { variable += ch; ++i; } variable_raw = variable; // transform into tpl variable //variable_main = "data['"+variable_raw+"']"; variable_main = "data."+variable_raw; variable_rest = ''; ++$__idcnt; id = "#VAR_"+$__idcnt+"#"; len = variable_raw.length; $__variables[$__currentblock][id] = variable_raw; // extra space space = 0; while (i < l && SPACE.test(s.charAt(i))) { ++space; ++i; } // optional properties while (i < l && ('.' === s.charAt(i) || '[' === s.charAt(i) || '->' === s.substring(i, i+2))) { delim = s.charAt(i++); // -> (php) object notation property if ('-' === delim) delim += s.charAt(i++); // extra space while (i < l && SPACE.test(s.charAt(i))) { ++space; ++i; } // alpha-numeric dot property if ('.' === delim) { // property property = ''; while (i < l && ALPHANUM.test(s.charAt(i))) { property += s.charAt(i++); } lp = property.length; if (lp) { // transform into tpl variable bracketed property //variable_rest += "['" + property + "']"; variable_rest += "." + property; len += space + 1 + lp; space = 0; } else { break; } } // alpha-numeric (php) object notation property else if ('->' === delim /*&& ALPHA.test(s.charAt(i))*/) { // property property = ''; while (i < l && ALPHANUM.test(s.charAt(i))) { property += s.charAt(i++); } lp = property.length; if (lp) { // transform into tpl variable object property //variable_rest += "['" + property + "']"; variable_rest += "." + property; len += space + 2 + lp; space = 0; } else { break; } } // bracketed property else if ('[' === delim) { bracket = ''; while (i < l) { ch = s.charAt(i); // spaces if (SPACE.test(ch)) { ++space; ++i; } // literal string property else if ('"' === ch || "'" === ch) { //property = parse_string(s, ch, i+1, l); str_ = q = ch; escaped = false; si = i+1; while (si < l) { str_ += (ch=s.charAt(si++)); if (q === ch && !escaped) break; escaped = (!escaped && '\\' === ch); } property = str_; ++$__idcnt; strid = "#STR_"+$__idcnt+"#"; strings[strid] = property; lp = property.length; i += lp; len += space + lp; space = 0; hasStrings = true; bracket += strid; } // numeric array property else if (NUM.test(ch)) { property = s.charAt(i++); while (i < l && NUM.test(s.charAt(i))) { property += s.charAt(i++); } lp = property.length; len += space + lp; space = 0; bracket += property; } // sub-variable as property else if ('$' === ch) { sub = s.slice(i+1); subvariables = parse_variable(sub, 0, sub.length); if (subvariables) { // transform into tpl variable property property = subvariables[subvariables.length-1]; lp = property[4]; i += lp + 1; len += space + 1 + lp; space = 0; variables = variables.concat(subvariables); hasStrings = hasStrings || property[5]; bracket += property[0]; } else { bracket += ch; ++len; ++i; } } // identifiers else if (ALPHA.test(ch)) { len += space + 1; ++i; if (space > 0) { bracket += " "; space = 0; } is_prop_access = (2 < i && '-' === s.charAt(i-3) && '>' === s.charAt(i-2)); tok = ch; while (i < l && ALPHANUM.test(ch=s.charAt(i))) { ++i; ++len; tok += ch; } if (!is_prop_access && 'as' !== tok && 'in' !== tok && 'null' !== tok && 'false' !== tok && 'true' !== tok) { tok = '#ID_'+tok+'#'; } bracket += tok; } // close bracket else if (']' === ch) { variable_rest += delim + bracket.replace(re_controls, function(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9) { return parse_constructs([m0,m1,m2,m3,m4,m5,m6,m7,m8,m9]); }) + ch; len += space + 2; space = 0; ++i; break; } // rest else { bracket += ch; ++len; ++i; } } } // extra space while (i < l && SPACE.test(s.charAt(i))) { ++space; ++i; } } variables.push([id, variable_raw, variable_main, variable_rest, len, hasStrings, strings]); return variables } return null; } var str_re = /#STR_\d+#/g; function parse_async(tpl, leftTplSep, rightTplSep, withblocks, cb) { var t1, t2, p1, p2, l1, l2, len, parsed, s, i, tag, tagTpl, strings, variables, hasVariables, hasStrings, varname, id, countl, index, ch, out, tok, v, tokv, multisplit_re = InlineTemplate.multisplit_re, ind, q, str_, escaped, si, space, blockTag, hasBlock, notFoundBlock, special_chars = "$'\" \n\r\t\v\0%", non_compatibility_mode = true, is_prop_access, isphp, isjs, ispy, code, indent, l3, indenttype, m ; t1 = leftTplSep; l1 = t1.length; t2 = rightTplSep; l2 = t2.length; parsed = ''; var parse_chunk = function parse_chunk() { if (!tpl || !tpl.length) { parse_finish(); return; } p1 = tpl.indexOf(t1); if (-1 === p1) { s = tpl; if ($__escape) s = s.split("\\").join("\\\\"); // escape escapes parsed += s .split("'").join("\\'") // escape single quotes accurately (used by parse function) .split(/*"\n"*/ /\n/).join($__preserveLines) // preserve lines ; parse_finish(); return; } p2 = tpl.indexOf(t2, p1+l1); if (-1 === p2) p2 = tpl.length; if (p1 > 0) { s = tpl.slice(0, p1); if ($__escape) s = s.split("\\").join("\\\\"); // escape escapes parsed += s .split("'").join("\\'") // escape single quotes accurately (used by parse function) .split(/*"\n"*/ /\n/).join($__preserveLines) // preserve lines ; } // php literal code block isphp = 'php:' === tpl.slice(p1+l1, p1+l1+4); // js literal code block isjs = 'js:' === tpl.slice(p1+l1, p1+l1+3); // py literal code block ispy = 'py:' === tpl.slice(p1+l1, p1+l1+3); if (isphp || isjs || ispy) { // include if in same language else ignore if (isjs) { if ('=' === tpl.slice(p1+l1+3, p1+l1+4)) { parsed += "';" + align("\n/* js code start */") + align("\n__p__ += String(" + trim(tpl.slice(p1+l1+4, p2)) + ");") + align("\n/* js code end */\n__p__ += '"); } else { indent = 0; l3 = 0; indenttype = 'none'; if (m = tpl.slice(p1+l1+3).match(INDENT)) { indenttype = m[1]; indent = parseInt(m[2]); l3 = m[0].length; } code = remove_blank_lines(tpl.slice(p1+l1+3+l3, p2)); if ('predent' === indenttype) { $__level = Math.max(0, $__level + indent); } parsed += "';" + align("\n/* js code start */"); if (trim(code).length) { parsed += "\n" + align(code); } if ('postdent' === indenttype) { $__level = Math.max(0, $__level + indent); } parsed += align("\n/* js code end */\n__p__ += '"); } } tpl = tpl.slice(p2+l2); parse_chunk(); return; } // template TAG s = tpl.slice(p1+l1, p2); tpl = tpl.slice(p2+l2); // parse each template tag section accurately // refined parsing countl = s.length; variables = []; strings = {}; hasVariables = false; hasStrings = false; hasBlock = false; index = 0; space = 0; ch = ''; out = ''; while (index < countl) { ch = s.charAt(index++); ind = special_chars.indexOf(ch); if (-1 < ind) { // variable if (0 === ind) { if (space > 0) { out += " "; space = 0; } tok = parse_variable(s, index, countl); if (tok) { for (v=0,len=tok.length; v ind) { if (space > 0) { out += " "; space = 0; } //tok = parse_string(s, ch, index, countl); str_ = q = ch; escaped = false; si = index; while (si < countl) { str_ += (ch=s.charAt(si++)); if (q === ch && !escaped) break; escaped = (!escaped && '\\' === ch); } tok = str_; ++$__idcnt; id = "#STR_"+$__idcnt+"#"; strings[id] = tok; out += id; index += tok.length-1; hasStrings = true; } // spaces else if (9 > ind) { ++space; } // directive or identifier or atom in compatibility mode else//if (9 === ind) { if (space > 0) { out += " "; space = 0; } q = ch; if (non_compatibility_mode || index >= countl || !ALPHA.test(ch=s.charAt(index))) { out += q; continue; } ++index; tok = ch; while (index < countl && ALPHANUM.test(ch = s.charAt(index))) { ++index; tok += ch; } tok = '#ID_'+tok+'#'; out += tok; } } // directive or identifier or atom and not variable object property access else if (non_compatibility_mode && ALPHA.test(ch)) { if (space > 0) { out += " "; space = 0; } is_prop_access = (2 < index && '-' === s.charAt(index-3) && '>' === s.charAt(index-2)); tok = ch; while (index < countl && ALPHANUM.test(ch=s.charAt(index))) { ++index; tok += ch; } if (!is_prop_access && 'as' !== tok && 'in' !== tok && 'null' !== tok && 'false' !== tok && 'true' !== tok) { tok = '#ID_'+tok+'#'; } out += tok; } // rest, bypass else { if (space > 0) { out += " "; space = 0; } out += ch; } } // fix literal data notation, not needed here //out = str_replace(array('{', '}', '[', ']', ':'), array('array(', ')','array(', ')', '=>'), out); // fix pending "->" arrow-notation for object variable out = out.split('->').join('.'); tag = "\t" + out + "\v"; $__startblock = null; $__endblock = null; $__blockptr = -1; $__strings = strings; parse_controls(); }; var after_parse_controls = function after_parse_controls() { // check for blocks if ($__startblock) { $__startblock = "#BLOCK_"+$__startblock+"#"; hasBlock = true; } else if ($__endblock) { $__endblock = "#/BLOCK_"+$__endblock+"#"; hasBlock = true; } notFoundBlock = hasBlock; // replacements /*.replace( re_repls, "' + ($1) + '" );*/ if (9 === tag.charCodeAt(0) && 11 === tag.charCodeAt(tag.length-1)) tag = "' + ("+trim(tag.slice(1, -1))+") + '"; if (hasVariables) { // replace variables for (v=variables.length-1; v>=0; --v) { id = variables[v][0]; varname = variables[v][1]; tag = tag .split(id+'__RAW__').join(varname) .split(id).join(( HAS.call($__locals[$__currentblock], varname) ? ((2 === $__locals[$__currentblock][varname] ? '' : '_loc_') + varname) /* local (loop) variable */ : (variables[v][2]) /* default (data) variable */ ) + variables[v][3]) ; } } if (hasStrings) { // replace strings (accurately) tagTpl = multisplit_re(tag, str_re); tag = ''; for (v=0,len=tagTpl.length; v0 ? parse_blocks(parsed) : [parsed, []]) : parsed); }; parse_chunk(); } function parse(tpl, leftTplSep, rightTplSep, withblocks, cb) { if ('function' === typeof cb) { parse_async(tpl, leftTplSep, rightTplSep, withblocks, cb); return; } var t1, t2, p1, p2, l1, l2, len, parsed, s, i, tag, tagTpl, strings, variables, hasVariables, hasStrings, varname, id, countl, index, ch, out, tok, v, tokv, multisplit_re = InlineTemplate.multisplit_re, ind, q, str_, escaped, si, space, blockTag, hasBlock, notFoundBlock, special_chars = "$'\" \n\r\t\v\0%", non_compatibility_mode = true, is_prop_access, isphp, isjs, ispy, code, indent, l3, indenttype, m ; t1 = leftTplSep; l1 = t1.length; t2 = rightTplSep; l2 = t2.length; parsed = ''; while (tpl && tpl.length) { p1 = tpl.indexOf(t1); if (-1 === p1) { s = tpl; if ($__escape) s = s.split("\\").join("\\\\"); // escape escapes parsed += s .split("'").join("\\'") // escape single quotes accurately (used by parse function) .split(/*"\n"*/ /\n/).join($__preserveLines) // preserve lines ; break; } p2 = tpl.indexOf(t2, p1+l1); if (-1 === p2) p2 = tpl.length; if (p1 > 0) { s = tpl.slice(0, p1); if ($__escape) s = s.split("\\").join("\\\\"); // escape escapes parsed += s .split("'").join("\\'") // escape single quotes accurately (used by parse function) .split(/*"\n"*/ /\n/).join($__preserveLines) // preserve lines ; } // php literal code block isphp = 'php:' === tpl.slice(p1+l1, p1+l1+4); // js literal code block isjs = 'js:' === tpl.slice(p1+l1, p1+l1+3); // py literal code block ispy = 'py:' === tpl.slice(p1+l1, p1+l1+3); if (isphp || isjs || ispy) { // include if in same language else ignore if (isjs) { if ('=' === tpl.slice(p1+l1+3, p1+l1+4)) { parsed += "';" + align("\n/* js code start */") + align("\n__p__ += String(" + trim(tpl.slice(p1+l1+4, p2)) + ");") + align("\n/* js code end */\n__p__ += '"); } else { indent = 0; l3 = 0; indenttype = 'none'; if (m = tpl.slice(p1+l1+3).match(INDENT)) { indenttype = m[1]; indent = parseInt(m[2]); l3 = m[0].length; } code = remove_blank_lines(tpl.slice(p1+l1+3+l3, p2)); if ('predent' === indenttype) { $__level = Math.max(0, $__level + indent); } parsed += "';" + align("\n/* js code start */"); if (trim(code).length) { parsed += "\n" + align(code); } if ('postdent' === indenttype) { $__level = Math.max(0, $__level + indent); } parsed += align("\n/* js code end */\n__p__ += '"); } } tpl = tpl.slice(p2+l2); continue; } // template TAG s = tpl.slice(p1+l1, p2); tpl = tpl.slice(p2+l2); // parse each template tag section accurately // refined parsing countl = s.length; variables = []; strings = {}; hasVariables = false; hasStrings = false; hasBlock = false; index = 0; space = 0; ch = ''; out = ''; while (index < countl) { ch = s.charAt(index++); ind = special_chars.indexOf(ch); if (-1 < ind) { // variable if (0 === ind) { if (space > 0) { out += " "; space = 0; } tok = parse_variable(s, index, countl); if (tok) { for (v=0,len=tok.length; v ind) { if (space > 0) { out += " "; space = 0; } //tok = parse_string(s, ch, index, countl); str_ = q = ch; escaped = false; si = index; while (si < countl) { str_ += (ch=s.charAt(si++)); if (q === ch && !escaped) break; escaped = (!escaped && '\\' === ch); } tok = str_; ++$__idcnt; id = "#STR_"+$__idcnt+"#"; strings[id] = tok; out += id; index += tok.length-1; hasStrings = true; } // spaces else if (9 > ind) { ++space; } // directive or identifier or atom in compatibility mode else//if (9 === ind) { if (space > 0) { out += " "; space = 0; } q = ch; if (non_compatibility_mode || index >= countl || !ALPHA.test(ch=s.charAt(index))) { out += q; continue; } ++index; tok = ch; while (index < countl && ALPHANUM.test(ch = s.charAt(index))) { ++index; tok += ch; } tok = '#ID_'+tok+'#'; out += tok; } } // directive or identifier or atom and not variable object property access else if (non_compatibility_mode && ALPHA.test(ch)) { if (space > 0) { out += " "; space = 0; } is_prop_access = (2 < index && '-' === s.charAt(index-3) && '>' === s.charAt(index-2)); tok = ch; while (index < countl && ALPHANUM.test(ch=s.charAt(index))) { ++index; tok += ch; } if (!is_prop_access && 'as' !== tok && 'in' !== tok && 'null' !== tok && 'false' !== tok && 'true' !== tok) { tok = '#ID_'+tok+'#'; } out += tok; } // rest, bypass else { if (space > 0) { out += " "; space = 0; } out += ch; } } // fix literal data notation, not needed here //out = str_replace(array('{', '}', '[', ']', ':'), array('array(', ')','array(', ')', '=>'), out); // fix pending "->" arrow-notation for object variable out = out.split('->').join('.'); tag = "\t" + out + "\v"; $__startblock = null; $__endblock = null; $__blockptr = -1; $__strings = strings; // replace constructs, functions, etc.. tag = tag.replace(re_controls, function(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9) { return parse_constructs([m0,m1,m2,m3,m4,m5,m6,m7,m8,m9]); }); // check for blocks if ($__startblock) { $__startblock = "#BLOCK_"+$__startblock+"#"; hasBlock = true; } else if ($__endblock) { $__endblock = "#/BLOCK_"+$__endblock+"#"; hasBlock = true; } notFoundBlock = hasBlock; // replacements /*.replace( re_repls, "' + ($1) + '" );*/ if (9 === tag.charCodeAt(0) && 11 === tag.charCodeAt(tag.length-1)) tag = "' + ("+trim(tag.slice(1,-1))+") + '"; if (hasVariables) { // replace variables for (v=variables.length-1; v>=0; --v) { id = variables[v][0]; varname = variables[v][1]; tag = tag .split(id+'__RAW__').join(varname) .split(id).join(( HAS.call($__locals[$__currentblock], varname) ? ((2 === $__locals[$__currentblock][varname] ? '' : '_loc_') + varname) /* local (loop) variable */ : (variables[v][2]) /* default (data) variable */ ) + variables[v][3]) ; } } if (hasStrings) { // replace strings (accurately) tagTpl = multisplit_re(tag, str_re); tag = ''; for (v=0,len=tagTpl.length; v0 ? parse_blocks(parsed) : [parsed, []]) : parsed; } function get_cached_template_name(id, ctx, cacheDir) { var filename, path; if ((isNode || isXPCOM) && (-1 !== id.indexOf('/') || -1 !== id.indexOf('\\'))) { filename = basename(id); path = trim(dirname(id), '/\\'); if (path.length) path += '/'; } else { filename = id; path = ''; } return cacheDir + path + filename.replace(UNDERLN, '_') + '_tpl__' + ctx.replace(UNDERLN, '_') + '.js'; } function get_cached_template_class(id, ctx) { var filename; if ((isNode || isXPCOM) && (-1 !== id.indexOf('/') || -1 !== id.indexOf('\\'))) { filename = basename(id); } else { filename = id; } return 'Contemplate_' + filename.replace(UNDERLN, '_') + '__' + ctx.replace(UNDERLN, '_'); } function get_template_contents(id, contx, cb) { cb = 'function' === typeof cb ? cb : null; var proceed = function() { var template = contx.templates[id] || $__global.templates[id] || null; if (!template) { if (cb) { // async cb(null, ''); } return ''; } if (template[1]) //inline tpl { if (cb) { // async cb(null, template[0]); return ''; } else { // sync return template[0]; } } else { // nodejs, xpcom if (isNode || isXPCOM) { if (cb) { // async fread_async(template[0], contx.encoding, function(err, data) { if (err) { cb(err, ''); } else { cb(null, data); } }); return ''; } else { // sync return fread(template[0], contx.encoding); } } // client-side js and #id of DOM script-element given as template holder else if ('#' === template[0].charAt(0)) { if (cb) { // async cb(null, window.document.getElementById(template[0].slice(1)).innerHTML || ''); return ''; } else { // sync return window.document.getElementById(template[0].slice(1)).innerHTML || ''; } } // client-side js and url given as template location else { if (cb) { // async fread_async(template[0], contx.encoding, function(err, data) { if (err) { cb(err, null); } else { cb(null, data); } }); return ''; } else { // sync return fread(template[0], contx.encoding); } } } }; if (!Contemplate.hasTpl(id, contx.id)) { if (cb) { Contemplate.findTpl(id, contx.id, function(err, found) { if (err || !found) { cb(null, ''); return; } var tpldef = {}; tpldef[id] = found; Contemplate.add(tpldef, contx.id); proceed(); }); } else { // supposed to be sync operation if no callback given var found = Contemplate.findTpl(id, contx.id); if (!found) return ''; var tpldef = {}; tpldef[id] = found; Contemplate.add(tpldef, contx.id); return proceed(); } } else { return proceed(); } } function create_template_render_function(id, contx, seps, cb) { cb = 'function' === typeof cb ? cb : null; var tpl, blocks, funcs = {}, b, bl, func, renderf, EOL = $__TEOL; if (cb) { get_template_contents(id, contx, function(err, tpl) { if (err) { cb(err, null); return; } tpl = get_separators(tpl, seps); reset_state(); parse(tpl, $__leftTplSep, $__rightTplSep, true, function(err, blocks) { if (err) { cb(err, null); return; } clear_state(); renderf = blocks[0]; blocks = blocks[1]; bl = blocks.length; // Convert the template into pure JavaScript func = TT_FUNC.render({ 'FCODE' : $__extends ? "__p__ = '';" : "__p__ = '" + renderf + "';" }); // defined blocks for (b=0; b= usedTpls.length) { cb(null, tpl); return; } Contemplate.tpl(usedTpls[i], null, options, function(err, usedtpl) { ++i; load_one(); }); }; load_one(); } else { cb(null, tpl); } }; // inline templates saved only in-memory if (template[1]) { var setSuper = function(tpl, cb) { sprTpl = $__extends || tpl._extendsTpl; if (sprTpl) { Contemplate.tpl(sprTpl, null, options, function(err, spr) { if (err) { cb(err, null); return; } tpl.extend(spr); cb(null, tpl); }); } else { cb(null, tpl); } }; // dynamic in-memory caching during page-request tpl = new Contemplate.Template(id).ctx(contx); if (parsed) { // already parsed code was given tpl.setRenderFunction(FUNC("Contemplate", parsed)); setSuper(tpl, function(err, ctpl) { if (!err) setUsedTpls(ctpl, cb); else cb(err, null); }); } else { // parse code and create template class create_template_render_function(id, contx, options.separators, function(err, funcs) { if (err) { cb(err, null); return; } tpl.setRenderFunction(funcs[0]).setBlocks(funcs[1]).usesTpl($__uses); setSuper(tpl, function(err, ctpl) { if (!err) setUsedTpls(ctpl, cb); else cb(err, null); }); }); } } else { if (!isNode && !isXPCOM) contx.cacheMode = Contemplate.CACHE_TO_DISK_NONE; var create_and_load_tpl = function(do_create, check_exists) { if (false === do_create) { if (false === check_exists) { tplclass = import_module(cachedTplClass, cachedTplFile)(Contemplate); tpl = (new tplclass(id))/*.setId(id)*/.ctx(contx); if (sprTpl = tpl._extendsTpl) { Contemplate.tpl(sprTpl, null, options, function(err, spr) { if (err) { cb(err, null); return; } tpl.extend(spr); setUsedTpls(tpl, cb); }); } else { setUsedTpls(tpl, cb); } } else { fexists_async(cachedTplFile, function(err, exists) { if (err || !exists) { cb(err || new Error('Could not create or read file "'+cachedTplFile+'"!'), null); return; } tplclass = import_module(cachedTplClass, cachedTplFile)(Contemplate); tpl = (new tplclass(id))/*.setId(id)*/.ctx(contx); if (sprTpl = tpl._extendsTpl) { Contemplate.tpl(sprTpl, null, options, function(err, spr) { if (err) { cb(err, null); return; } tpl.extend(spr); setUsedTpls(tpl, cb); }); } else { setUsedTpls(tpl, cb); } } ); } } else { create_cached_template(id, contx, cachedTplFile, cachedTplClass, options.separators, function(err, res) { if (err) { cb(err, null); return; } fexists_async(cachedTplFile, function(err, exists) { if (err || !exists) { cb(err || new Error('Could not create or read file "'+cachedTplFile+'"!'), null); return; } tplclass = import_module(cachedTplClass, cachedTplFile)(Contemplate); tpl = (new tplclass(id))/*.setId(id)*/.ctx(contx); if (sprTpl = tpl._extendsTpl) { Contemplate.tpl(sprTpl, null, options, function(err, spr) { if (err) { cb(err, null); return; } tpl.extend(spr); setUsedTpls(tpl, cb); }); } else { setUsedTpls(tpl, cb); } } ); } ); } }; if (true !== options.autoUpdate && Contemplate.CACHE_TO_DISK_NOUPDATE === contx.cacheMode) { cachedTplFile = get_cached_template_name(id, contx.id, contx.cacheDir); cachedTplClass = get_cached_template_class(id, contx.id); fexists_async(cachedTplFile, function(err, exists) { if (!exists) { if (-1 !== id.indexOf('/') || -1 !== id.indexOf('\\')) { fname = basename(id); fpath = trim(dirname(id), '/\\'); } else { fname = id; fpath = ''; } if (fpath.length) { create_path(fpath, contx.cacheDir, parseInt('0755', 8), function(err, res) { if (err) { cb(err, null); return; } create_and_load_tpl(); }); } else { create_and_load_tpl(); } } else { create_and_load_tpl(false, false); } }); } else if (true === options.autoUpdate || Contemplate.CACHE_TO_DISK_AUTOUPDATE === contx.cacheMode) { cachedTplFile = get_cached_template_name(id, contx.id, contx.cacheDir); cachedTplClass = get_cached_template_class(id, contx.id); fexists_async(cachedTplFile, function(err, exists) { if (!exists) { // if tpl not exist create it if (-1 !== id.indexOf('/') || -1 !== id.indexOf('\\')) { fname = basename(id); fpath = trim(dirname(id), '/\\'); } else { fname = id; fpath = ''; } if (fpath.length) { create_path(fpath, contx.cacheDir, parseInt('0755',8), function(err, res) { if (err) { cb(err, null); return; } create_and_load_tpl(); }); } else { create_and_load_tpl(); } } else { fstat_async(cachedTplFile, function(err, stat) { if (err) { cb(err, null); return; } fstat_async(template[0], function(err, stat2) { if (err) { cb(err, null); return; } if (stat.mtime.getTime() <= stat2.mtime.getTime()) { // is out-of-sync re-create it create_and_load_tpl(); } else { create_and_load_tpl(false, false); } }); }); } } ); return null; } else { // dynamic in-memory caching during page-request create_template_render_function(id, contx, options.separators, function(err, funcs) { if (err) { cb(err, null); return; } tpl = (new Contemplate.Template(id)).ctx(contx).setRenderFunction(funcs[0]).setBlocks(funcs[1]).usesTpl($__uses); sprTpl = $__extends; if (sprTpl) { Contemplate.tpl(sprTpl, null, options, function(err, spr) { if (err) { cb(err, null); return; } tpl.extend(spr); setUsedTpls(tpl, cb); }); } else { setUsedTpls(tpl, cb); } }); } } } else { // inline templates saved only in-memory if (template[1]) { // dynamic in-memory caching during page-request tpl = (new Contemplate.Template(id)).ctx(contx); if (parsed) { // already parsed code was given tpl.setRenderFunction(FUNC("Contemplate", parsed)); } else { // parse code and create template class funcs = create_template_render_function(id, contx, options.separators); tpl.setRenderFunction(funcs[0]).setBlocks(funcs[1]).usesTpl($__uses); } sprTpl = $__extends || tpl._extendsTpl; if (sprTpl) tpl.extend(Contemplate.tpl(sprTpl, null, options)); return tpl; } else { if (!isNode && !isXPCOM) contx.cacheMode = Contemplate.CACHE_TO_DISK_NONE; if (true !== options.autoUpdate && Contemplate.CACHE_TO_DISK_NOUPDATE === contx.cacheMode) { cachedTplFile = get_cached_template_name(id, contx.id, contx.cacheDir); cachedTplClass = get_cached_template_class(id, contx.id); exists = fexists(cachedTplFile); if (!exists) { if (-1 !== id.indexOf('/') || -1 !== id.indexOf('\\')) { fname = basename(id); fpath = trim(dirname(id), '/\\'); } else { fname = id; fpath = ''; } if (fpath.length) create_path(fpath, contx.cacheDir, parseInt('0755', 8)); create_cached_template(id, contx, cachedTplFile, cachedTplClass, options.separators); } if (fexists(cachedTplFile)) { tplclass = import_module(cachedTplClass, cachedTplFile)(Contemplate); tpl = (new tplclass(id))/*.setId(id)*/.ctx(contx); if (tpl._extendsTpl) tpl.extend(Contemplate.tpl(tpl._extendsTpl, null, options)); return tpl; } return null; } else if (true === options.autoUpdate || Contemplate.CACHE_TO_DISK_AUTOUPDATE === contx.cacheMode) { cachedTplFile = get_cached_template_name(id, contx.id, contx.cacheDir); cachedTplClass = get_cached_template_class(id, contx.id); exists = fexists(cachedTplFile); if (!exists) { // if tpl not exist create it if (-1 !== id.indexOf('/') || -1 !== id.indexOf('\\')) { fname = basename(id); fpath = trim(dirname(id), '/\\'); } else { fname = id; fpath = ''; } if (fpath.length) create_path(fpath, contx.cacheDir, parseInt('0755', 8)); create_cached_template(id, contx, cachedTplFile, cachedTplClass, options.separators); } else { stat = fstat(cachedTplFile); stat2 = fstat(template[0]); if (stat.mtime.getTime() <= stat2.mtime.getTime()) { // is out-of-sync re-create it create_cached_template(id, contx, cachedTplFile, cachedTplClass, options.separators); } } if (fexists(cachedTplFile)) { tplclass = import_module(cachedTplClass, cachedTplFile)(Contemplate); tpl = (new tplclass(id))/*.setId(id)*/.ctx(contx); if (tpl._extendsTpl) tpl.extend(Contemplate.tpl(tpl._extendsTpl, null, options)); return tpl; } return null; } else { // dynamic in-memory caching during page-request funcs = create_template_render_function(id, contx, options.separators); tpl = (new Contemplate.Template(id)).ctx(contx).setRenderFunction(funcs[0]).setBlocks(funcs[1]).usesTpl($__uses); sprTpl = $__extends || tpl._extendsTpl; if (sprTpl) tpl.extend(Contemplate.tpl(sprTpl, null, options)); return tpl; } } } } function split_and_filter(r, s, regex) { return s.split(r).map(function(x) {return trim(x);}).filter(function(x) {return 0= l) { cb(null, true); return; } if (false === exists0) { fmkdir_async(current, mode, function(err, res) { if (err) { cb(err, null); return; } if (i+1 < l) { ++i; current += '/' + parts[i]; create_one_level(); } else { cb(null, true); } }); } else { fexists_async(current, function(err, exists) { if (err) { cb(err, null); return; } if (!exists) exists0 = false; fmkdir_async(current, mode, function(err, res) { if (err) { cb(err, null); return; } if (i+1 < l) { ++i; current += '/' + parts[i]; create_one_level(); } else { cb(null, true); } }); }); } }; create_one_level(); } else { for(i=0,l=parts.length; i 1) { for (j=0; j= templateDirs.length) { cb(null, null); return; } var path = rtrim(templateDirs[dir],'/\\') + '/' + filename; fexists_async(path, function(err, exists) { if (!err && exists) { cb(null, path); } else { ++dir; search_one(); } }); }; if (is_callable(contx.templateFinder)) { // supposed to be async operation with callback given contx.templateFinder(tpl, function(found) { cb(null, found); }); return; } if (contx.templateDirs && contx.templateDirs.length) { templateDirs = contx.templateDirs; filename = ltrim(tpl,'/\\'); dir = 0; search_one(); return; } if (contx != $__global) { contx = $__global; if (is_callable(contx.templateFinder)) { // supposed to be async operation with callback given contx.templateFinder(tpl, function(found) { cb(null, found); }); return; } if (contx.templateDirs && contx.templateDirs.length) { templateDirs = contx.templateDirs; filename = ltrim(tpl,'/\\'); dir = 0; search_one(); return; } } cb(null, null); } else { var filename, path, dir, l; if (is_callable(contx.templateFinder)) { // supposed to be sync operation if no callback provided return contx.templateFinder(tpl); } if (contx.templateDirs && contx.templateDirs.length) { filename = ltrim(tpl, '/\\'); for(dir=0,l=contx.templateDirs.length; dir 0 ? ('object'===typeof args[0] ? Contemplate.join(sep, args[0], skip_empty) : (skip_empty&&(null==args[0]||!String(args[0]).length) ? '' : String(args[0]))) : ''; for (i=1; i 0) out += sep + s; } return out; } ,keys: function(o) { return o ? array_keys(o) : []; } ,values: function(o) { return o ? array_values(o) : []; } ,items: function(o) { return o; } ,count: count ,is_array: function(v, strict) { var to_string = toString.call(v); return strict ? '[object Array]' === to_string : ('[object Array]' === to_string) || ('[object Object]' === to_string); } ,in_array: function(v, a) { return -1 < a.indexOf(v); } ,is_list: is_array ,haskey: function(v/*, key1, key2, etc.. */) { var args, i, tmp; if (!v || !Contemplate.is_array(v)) return false; args = arguments; tmp = v; for (i=1; i 0 ? new Array(n+1).join(ch||' ')+sp : sp; } function rawurlencode(str) { // Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current // PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following. return encodeURIComponent('' + str).replace(re_2, '%21').replace(re_3, '%27').replace(re_4, '%28'). replace(re_5, '%29').replace(re_6, '%2A'); } function urlencode(str) { // Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current // PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following. return encodeURIComponent('' + str).replace(re_2, '%21').replace(re_3, '%27').replace(re_4, '%28'). replace(re_5, '%29').replace(re_6, '%2A').replace(re_7, '+'); } function rawurldecode(str) { return decodeURIComponent(''+str); } function urldecode(str) { return rawurldecode(('' + str).split('+').join('%20')); } function parse_str(str) { var strArr = str.replace(/^&+|&+$/g, '').split('&'), sal = strArr.length, i, j, ct, p, lastObj, obj, chr, tmp, key, value, postLeftBracketPos, keys, keysLen, lastkey, array = {}, possibleLists = [], prevkey, prevobj ; for (i=0; i -1) key = key.slice(0, j); if (key && '[' !== key.charAt(0)) { keys = []; postLeftBracketPos = 0; for (j=0; j ct && p.match(/^\d+$/g) ) { ct = +p; } } } key = ct + 1;*/ key = true; } } if (true === key) { lastObj.push(value); } else { if (key == +key) possibleLists.push({key:prevkey, obj:prevobj}); lastObj[key] = value; } } } for (i=possibleLists.length-1; i>=0; --i) { // safe to pass multiple times same obj, it is possible obj = possibleLists[i].key ? possibleLists[i].obj[possibleLists[i].key] : possibleLists[i].obj; if (is_numeric_array(obj)) { obj = array_values(obj); if (possibleLists[i].key) possibleLists[i].obj[possibleLists[i].key] = obj; else array = obj; } } return array; } function http_build_query_helper(key, val, arg_separator, PHP_QUERY_RFC3986) { var k, tmp, encode = PHP_QUERY_RFC3986 ? rawurlencode : urlencode; if (true === val) val = "1"; else if (false === val) val = "0"; if (null != val) { if ("object" === typeof(val)) { tmp = []; for (k in val) { if (HAS.call(val, k) && null != val[k]) { tmp.push(http_build_query_helper(key + "[" + k + "]", val[k], arg_separator, PHP_QUERY_RFC3986)); } } return tmp.join(arg_separator); } else { return encode(key) + "=" + encode(val); } } else { return ''; } } function http_build_query(data, arg_separator, PHP_QUERY_RFC3986) { var value, key, query, tmp = []; if (arguments.length < 2) arg_separator = "&"; if (arguments.length < 3) PHP_QUERY_RFC3986 = false; for (key in data) { if (!HAS.call(data, key)) continue; value = data[key]; query = http_build_query_helper(key, value, arg_separator, PHP_QUERY_RFC3986); if ('' != query) tmp.push(query); } return tmp.join(arg_separator); } function php_time() { return floor(new Date().getTime() / 1000); } function php_date(format, timestamp) { var formatted_datetime, f, i, l, jsdate, locale = default_date_locale ; // JS Date if (timestamp instanceof Date) jsdate = new Date(timestamp); // UNIX timestamp (auto-convert to int) else if ("number" === typeof timestamp) jsdate = new Date(timestamp * 1000); // undefined else/*if ( null === timestamp || undef === timestamp )*/ jsdate = new Date(); var D = {}, tzo = jsdate.getTimezoneOffset(), atzo = abs(tzo), m = jsdate.getMonth(), jmod10; // 24-Hours; 0..23 D.G = jsdate.getHours(); // Day of month; 1..31 D.j = jsdate.getDate(); jmod10 = D.j%10; // Month; 1...12 D.n = m + 1; // Full year; e.g. 1980...2010 D.Y = jsdate.getFullYear(); // Day of week; 0[Sun]..6[Sat] D.w = jsdate.getDay(); // ISO-8601 day of week; 1[Mon]..7[Sun] D.N = D.w || 7; // Day of month w/leading 0; 01..31 D.d = pad(D.j, 2, '0'); // Shorthand day name; Mon...Sun D.D = locale.day_short[D.w]; // Full day name; Monday...Sunday D.l = locale.day[D.w]; // Ordinal suffix for day of month; st, nd, rd, th D.S = locale.ordinal.ord[D.j] ? locale.ordinal.ord[D.j] : (locale.ordinal.ord[jmod10] ? locale.ordinal.ord[jmod10] : locale.ordinal.nth); // Day of year; 0..365 D.z = round((new Date(D.Y, m, D.j) - new Date(D.Y, 0, 1)) / 864e5); // ISO-8601 week number D.W = pad(1 + round((new Date(D.Y, m, D.j - D.N + 3) - new Date(D.Y, 0, 4)) / 864e5 / 7), 2, '0'); // Full month name; January...December D.F = locale.month[m]; // Month w/leading 0; 01...12 D.m = pad(D.n, 2, '0'); // Shorthand month name; Jan...Dec D.M = locale.month_short[m]; // Days in month; 28...31 D.t = (new Date(D.Y, m+1, 0)).getDate(); // Is leap year?; 0 or 1 D.L = D.Y % 4 === 0 & D.Y % 100 !== 0 | D.Y % 400 === 0; // ISO-8601 year D.o = D.Y + (11 === m && D.W < 9 ? 1 : (0 === m && D.W > 9 ? -1 : 0)); // Last two digits of year; 00...99 D.y = D.Y.toString().slice(-2); // am or pm D.a = D.G > 11 ? locale.meridian.pm : locale.meridian.am; // AM or PM D.A = D.G > 11 ? locale.meridian.PM : locale.meridian.AM; // Swatch Internet time; 000..999 D.B = pad(floor((jsdate.getUTCHours() * 36e2 + jsdate.getUTCMinutes() * 60 + jsdate.getUTCSeconds() + 36e2) / 86.4) % 1e3, 3, '0'); // 12-Hours; 1..12 D.g = (D.G % 12) || 12; // 12-Hours w/leading 0; 01..12 D.h = pad(D.g, 2, '0'); // 24-Hours w/leading 0; 00..23 D.H = pad(D.G, 2, '0'); // Minutes w/leading 0; 00..59 D.i = pad(jsdate.getMinutes(), 2, '0'); // Seconds w/leading 0; 00..59 D.s = pad(jsdate.getSeconds(), 2, '0'); // Microseconds; 000000-999000 D.u = pad(jsdate.getMilliseconds() * 1000, 6, '0'); // Timezone identifier; e.g. Atlantic/Azores, ... // The following works, but requires inclusion of the very large // timezone_abbreviations_list() function. /* return that.date_default_timezone_get(); */ D.e = ''; // DST observed?; 0 or 1 D.I = ((new Date(D.Y, 0) - Date.UTC(D.Y, 0)) !== (new Date(D.Y, 6) - Date.UTC(D.Y, 6))) ? 1 : 0; // Difference to GMT in hour format; e.g. +0200 D.O = (tzo > 0 ? "-" : "+") + pad(floor(atzo / 60) * 100 + atzo % 60, 4, '0'); // Difference to GMT w/colon; e.g. +02:00 D.P = (D.O.substr(0, 3) + ":" + D.O.substr(3, 2)); // Timezone abbreviation; e.g. EST, MDT, ... D.T = 'UTC'; // Timezone offset in seconds (-43200...50400) D.Z = -tzo * 60; // Seconds since UNIX epoch D.U = jsdate / 1000 | 0; // ISO-8601 date. 'Y-m-d\\TH:i:sP' D.c = D.Y+'-'+D.m+'-'+D.d+'\\'+D.T+D.H+':'+D.i+':'+D.s+D.P; // RFC 2822 'D, d M Y H:i:s O' D.r = D.D+', '+D.d+' '+D.M+' '+D.Y+' '+D.H+':'+D.i+':'+D.s+' '+D.O; formatted_datetime = ''; for (i=0,l=format.length; i 0) { if (leftJustify || !zeroPad) sv = pad_(sv, minWidth, customPadChar, leftJustify); else sv = sv.slice(0, prefix.length) + pad_('', diff, '0', true) + sv.slice(prefix.length); } return sv; } function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad) { // Note: casts negative numbers to positive ones var number = value >>> 0; prefix = prefix && number && { '2': '0b', '8': '0', '16': '0x' }[base] || ''; value = prefix + pad_(number.toString(base), precision||0, '0', false); return justify(value, prefix, leftJustify, minWidth, zeroPad); } function formatString(value, leftJustify, minWidth, precision, zeroPad, customPadChar) { if (null != precision) value = value.slice(0, precision); return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar); } function sprintf() { /* * More info at: http://phpjs.org * * This is version: 3.24 * php.js is copyright 2011 Kevin van Zonneveld. */ // http://kevin.vanzonneveld.net // + original by: Ash Searle (http://hexmen.com/blog/) // + namespaced by: Michael White (http://getsprink.com) // + tweaked by: Jack // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + input by: Paulo Freitas // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + input by: Brett Zamir (http://brett-zamir.me) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Dj // + improved by: Allidylls // * example 1: sprintf("%01.2f", 123.1); // * returns 1: 123.10 // * example 2: sprintf("[%10s]", 'monkey'); // * returns 2: '[ monkey]' // * example 3: sprintf("[%'#10s]", 'monkey'); // * returns 3: '[####monkey]' // * example 4: sprintf("%d", 123456789012345); // * returns 4: '123456789012345' var i = 1, fmt = arguments[0], a = arguments; var do_format = function do_format(substring, valueIndex, flags, minWidth, _, precision, type) { var number, prefix, method, textTransform, value; if ('%%' == substring) return '%'; // parse flags var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, j, customPadChar = ' ', flagsl = flags.length; for (j=0; flags && j < flagsl; ++j) { switch (flags.charAt(j)) { case ' ': positivePrefix = ' '; break; case '+': positivePrefix = '+'; break; case '-': leftJustify = true; break; case "'": customPadChar = flags.charAt(j + 1); break; case '0': zeroPad = true; break; case '#': prefixBaseX = true; break; } } // parameters may be null, undefined, empty-string or real valued // we want to ignore null, undefined and empty-string values if (!minWidth) minWidth = 0; else if ('*' == minWidth) minWidth = +a[i++]; else if ('*' == minWidth.charAt(0)) minWidth = +a[minWidth.slice(1, -1)]; else minWidth = +minWidth; // Note: undocumented perl feature: if (0 > minWidth) { minWidth = -minWidth; leftJustify = true; } if (!isFinite(minWidth)) { throw new Error('sprintf: (minimum-)width must be finite'); } if (!precision) precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined; else if ('*' == precision) precision = +a[i++]; else if ('*' == precision.charAt(0)) precision = +a[precision.slice(1, -1)]; else precision = +precision; // grab value using valueIndex if required? value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; switch (type) { case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar); case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad); case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad); case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad); case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad); case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase(); case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad); case 'i': case 'd': number = +value || 0; number = Math.round(number - number % 1); // Plain Math.round doesn't just truncate prefix = number < 0 ? '-' : positivePrefix; value = prefix + pad_(String(Math.abs(number)), precision, '0', false); return justify(value, prefix, leftJustify, minWidth, zeroPad); case 'e': case 'E': case 'f': // Should handle locales (as per setlocale) case 'F': case 'g': case 'G': number = +value; prefix = number < 0 ? '-' : positivePrefix; method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; value = prefix + Math.abs(number)[method](precision); return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform](); default: return substring; } }; return fmt.replace(sprintf.format_re, do_format); } sprintf.format_re = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g; // init the engine on load Contemplate.init(); // export it return Contemplate; });