PHP Classes

File: src/js/Contemplate.js

Recommend this page to a friend!
  Classes of Nikos M.   Contemplate   src/js/Contemplate.js   Download  
File: src/js/Contemplate.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Contemplate
Template engine that provides programming controls
Author: By
Last change: v.1.6.0

* local keyword to define literal local vars, some names are reserved
* literal code can communicate to and fro template code
* better variable parsing, any valid expression can be inside variable bracket notation
* update tests
Date: 1 year ago
Size: 171,862 bytes
 

Contents

Class file image Download
/** * 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<l; ++i) { c = s.charAt(i); if (' ' === c || "\t" === c) initial_space += c; else break; } sl = initial_space.length; if (sl) { s = s.slice(sl); pos = s.indexOf("\n", 0); while (-1 !== pos) { if (initial_space === s.slice(pos+1, pos+1+sl)) { s = s.slice(0, pos+1) + s.slice(pos+1+sl); } pos = s.indexOf("\n", pos + 1); } } } return s; } function remove_blank_lines(s) { var lines = s.split("\n"), n = lines.length, start = 0, end = n-1, i, l; for (i=0; i<n; ++i) { l = lines[i]; if (l.length && !ALL_SPACE.test(l)) { start = i; break; } } for (i=n-1; 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; i<l; ++i) { c = s.charAt(i); if ("\n" === c) { aligned += "\n" + alignment; is_line_start = true; } else if (is_line_start) { // consistently replace tabs with our tabbed spaces if (SPACE.test(c)) { aligned += "\t" === c ? $__pad : c; } else { aligned += c; is_line_start = false; } } else { aligned += c; } } } else { aligned = s; } return aligned; } function merge() { var args = arguments, l = args.length; if (l < 1) return; var merged = args[0], i, k, o; for (i=1; i<l; ++i) { o = args[i]; if (o) for (k in o) if (HAS.call(o,k)) merged[k] = o[k]; } return merged; } function get_separators(text, separators) { var line, seps, pos, i, l; if (separators) { seps = trim(separators).split(" "); $__leftTplSep = trim(seps[0]); $__rightTplSep = trim(seps[1]); } else { // tpl separators are defined on 1st (non-empty) line of tpl content l = text.length; i = 0; pos = 0; line = ""; while (i < l && -1 < pos && !line.length) { pos = text.indexOf("\n", i); line = -1 < pos ? trim(text.slice(i, pos+1)) : ""; i = pos+1; } if (line.length) { seps = line.split(" "); $__leftTplSep = trim(seps[0]); $__rightTplSep = trim(seps[1]); text = text.slice(pos+1); } } return text; } function split_arguments(args, delim) { args = trim(args); if (!args.length) return ['']; if (arguments.length < 2) delim = ','; var a = [], paren = [], s = '', i = 0, l = args.length, c; while (i < l) { c = args.charAt(i++); if (delim === c && !paren.length) { a.push(trim(s)); s = ''; continue; } s += c; if ('(' === c) { paren.unshift(')'); } else if ('{' === c) { paren.unshift('}'); } else if ('[' === c) { paren.unshift(']'); } else if (')' === c || '}' === c || ']' === c) { if (!paren.length || paren[0] !== c) break; paren.shift(); } } if (s.length) a.push(trim(s)); if (i < l) a.push(trim(args.slice(i))); return a; } function local_variable(variable, block, literal) { if (null == variable) { return '_loc_' + (++$__idcnt); } else { if (null == block) block = $__currentblock; if (!HAS.call($__locals[block], $__variables[block][variable])) $__locals[block][$__variables[block][variable]] = literal ? 2 : 1; return variable; } } function is_local_variable(variable, block) { if (null == block) block = $__currentblock; //if ('_loc_' === variable.slice(0, 5)) return 1; return HAS.call($__locals[block], $__variables[block][variable]) ? $__locals[block][$__variables[block][variable]] : 0; } // // Control structures // function t_include(id, cb) { var tpl, state, ch, contx = $__context; id = trim(id); if ($__strings && HAS.call($__strings, id)) id = $__strings[id]; ch = id.charAt(0); if (('"' === ch || "'" === ch) && (ch === id.charAt(id.length-1))) id = id.slice(1, -1); // quoted id if ('function' === typeof cb) { // cache it if (!HAS.call(contx.partials, id) /*&& !HAS.call($__global.partials,id)*/) { get_template_contents(id, contx, function(err, tpl) { if (err) { cb(err, null); return; } tpl = get_separators(tpl); state = push_state(); reset_state(); parse(tpl, $__leftTplSep, $__rightTplSep, false, function(err, text) { if (err) { cb(err, null); return; } contx.partials[id] = [" " + text + "';" + $__TEOL, $__uses ? $__uses.slice() : []]; pop_state(state); // add usedTpls used inside include tpl to current usedTpls for (var uses = contx.partials[id][1],usedTpl=0; usedTpl<uses.length; ++usedTpl) { if (-1 === $__uses.indexOf(uses[usedTpl])) $__uses.push(uses[usedTpl]); } cb(null, align(contx.partials[id][0])); } ); }); } else { // add usedTpls used inside include tpl to current usedTpls for (var uses = contx.partials[id][1],usedTpl=0; usedTpl<uses.length; ++usedTpl) { if (-1 === $__uses.indexOf(uses[usedTpl])) $__uses.push(uses[usedTpl]); } cb(null, align(contx.partials[id][0])); } return ''; } else { // cache it if (!HAS.call(contx.partials, id) /*&& !HAS.call($__global.partials,id)*/) { tpl = get_template_contents(id, contx); tpl = get_separators(tpl); state = push_state(); reset_state(); contx.partials[id] = [" " + parse(tpl, $__leftTplSep, $__rightTplSep, false) + "';" + $__TEOL, $__uses ? $__uses.slice() : []]; pop_state(state); } // add usedTpls used inside include tpl to current usedTpls for (var uses = contx.partials[id][1],usedTpl=0; usedTpl<uses.length; ++usedTpl) { if (-1 === $__uses.indexOf(uses[usedTpl])) $__uses.push(uses[usedTpl]); } return align(contx.partials[id][0] /*|| $__global.partials[id][0]*/); } } function t_block(block) { block = block.split(','); var echoed = !(block.length>1 ? "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<len; ++v) { tokv = tok[v]; id = tokv[0]; //$__variables[$__currentblock][id] = tokv[1]; if (tokv[5]) strings = merge(strings, tokv[6]); } out += id; index += tokv[4]; variables = variables.concat(tok); hasVariables = true; hasStrings = hasStrings || tokv[5]; } else { out += '$'; } } // literal string else if (3 > 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; v<len; ++v) { if (tagTpl[v][0]) { // and replace blocks (accurately) if (notFoundBlock) { if ($__startblock) { blockTag = tagTpl[v][1].indexOf($__startblock); if (-1 !== blockTag) { $__allblocks[$__blockptr-1][1] = blockTag + parsed.length + tag.length; notFoundBlock = false; } } else//if ($__endblock) { blockTag = tagTpl[v][1].indexOf($__endblock); if (-1 !== blockTag) { $__allblocks[$__blockptr-1][2] = blockTag + parsed.length + tag.length + $__endblock.length; notFoundBlock = false; } } } tag += tagTpl[v][1]; } else { tag += strings[tagTpl[v][1]]; } } } else if (hasBlock) { // replace blocks (accurately) if ($__startblock) $__allblocks[$__blockptr-1][1] = parsed.length + tag.indexOf($__startblock); else//if ($__endblock) $__allblocks[$__blockptr-1][2] = parsed.length + tag.indexOf($__endblock) + $__endblock.length; } // replace tpl separators if (/*"\v"*/11 === tag.charCodeAt(tag.length-1)) { tag = tag.slice(0, -1) + align($__tplEnd); } if (/*"\t"*/9 === tag.charCodeAt(0)) { tag = $__tplStart + tag.slice(1); if (hasBlock) { // update blocks (accurately) blockTag = $__tplStart.length-1; if ($__startblock) $__allblocks[$__blockptr-1][1] += blockTag; else//if ($__endblock) $__allblocks[$__blockptr-1][2] += blockTag; } } parsed += tag; // continue until end parse_chunk(); }; var parse_controls = function parse_controls() { // replace constructs, functions, etc.. parse_constructs_async(tag, function(err, repl) { if (err) { cb(err, null); return; } tag = repl; after_parse_controls(); }); }; var parse_finish = function parse_finish() { cb(null, false !== withblocks ? ($__allblocks.length>0 ? 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<len; ++v) { tokv = tok[v]; id = tokv[0]; //$__variables[$__currentblock][id] = tokv[1]; if (tokv[5]) strings = merge(strings, tokv[6]); } out += id; index += tokv[4]; variables = variables.concat(tok); hasVariables = true; hasStrings = hasStrings || tokv[5]; } else { out += '$'; } } // literal string else if (3 > 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; v<len; ++v) { if (tagTpl[v][0]) { // and replace blocks (accurately) if (notFoundBlock) { if ($__startblock) { blockTag = tagTpl[v][1].indexOf($__startblock); if (-1 !== blockTag) { $__allblocks[$__blockptr-1][1] = blockTag + parsed.length + tag.length; notFoundBlock = false; } } else//if ($__endblock) { blockTag = tagTpl[v][1].indexOf($__endblock); if (-1 !== blockTag) { $__allblocks[$__blockptr-1][2] = blockTag + parsed.length + tag.length + $__endblock.length; notFoundBlock = false; } } } tag += tagTpl[v][1]; } else { tag += strings[tagTpl[v][1]]; } } } else if (hasBlock) { // replace blocks (accurately) if ($__startblock) $__allblocks[$__blockptr-1][1] = parsed.length + tag.indexOf($__startblock); else//if ($__endblock) $__allblocks[$__blockptr-1][2] = parsed.length + tag.indexOf($__endblock) + $__endblock.length; } // replace tpl separators if (/*"\v"*/11 === tag.charCodeAt(tag.length-1)) { tag = tag.slice(0,-1) + align($__tplEnd); } if (/*"\t"*/9 === tag.charCodeAt(0)) { tag = $__tplStart + tag.slice(1); if (hasBlock) { // update blocks (accurately) blockTag = $__tplStart.length-1; if ($__startblock) $__allblocks[$__blockptr-1][1] += blockTag; else//if ($__endblock) $__allblocks[$__blockptr-1][2] += blockTag; } } parsed += tag; } return false !== withblocks ? ($__allblocks.length>0 ? 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<bl; ++b) funcs[blocks[b][0]] = FUNC("Contemplate,data,self,__i__", blocks[b][1]); cb(null, [FUNC("Contemplate", func), funcs]); }); }); return null; } else { tpl = get_template_contents(id, contx); tpl = get_separators(tpl, seps); reset_state(); blocks = parse(tpl, $__leftTplSep, $__rightTplSep, true); 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<bl; ++b) funcs[blocks[b][0]] = FUNC("Contemplate,data,self,__i__", blocks[b][1]); return [FUNC("Contemplate", func), funcs]; } } function create_cached_template(id, contx, filename, classname, seps, cb) { cb = 'function' === typeof cb ? cb : null; var tpl, funcs = {}, prefixCode, extendCode, renderCode, b, bl, sblocks, blocks, 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; // tpl-defined blocks sblocks = []; for (b=0; b<bl; ++b) sblocks.push(EOL + TT_BlockCode.render({ 'BLOCKNAME' : blocks[b][0] ,'BLOCKMETHODNAME' : blocks[b][0] ,'BLOCKMETHODCODE' : align(blocks[b][1], 1) })); sblocks = sblocks.length ? EOL + "self._blocks = {" + EOL + sblocks.join(',' + EOL) + EOL + "};" + EOL : ''; renderCode = TT_RCODE.render({ 'RCODE' : $__extends ? "__p__ = '';" : "__p__ += '" + renderf + "';" }); //extendCode = $__extends ? "self.extend('" + $__extends + "');" : ''; extendCode = $__extends ? "self._extendsTpl = '" + $__extends + "';" : ''; extendCode += EOL + "self._usesTpl = [" + ($__uses.length ? "'"+$__uses.join("','")+"'" : '') + "];"; prefixCode = contx.prefix ? contx.prefix : ''; // generate tpl class var classCode = TT_ClassCode.render({ 'CLASSNAME' : classname ,'TPLID' : id ,'PREFIXCODE' : prefixCode ,'EXTENDCODE' : align(extendCode, 1) ,'BLOCKS' : align(sblocks, 1) ,'RENDERCODE' : align(renderCode, 1) }); fwrite_async(filename, classCode, contx.encoding, function(err, res) { cb(err, res); }); }); }); return null; } else { tpl = get_template_contents(id, contx); tpl = get_separators(tpl, seps); reset_state(); blocks = parse(tpl, $__leftTplSep, $__rightTplSep, true); clear_state(); renderf = blocks[0]; blocks = blocks[1]; bl = blocks.length; // tpl-defined blocks sblocks = []; for (b=0; b<bl; ++b) sblocks.push(EOL + TT_BlockCode.render({ 'BLOCKNAME' : blocks[b][0] ,'BLOCKMETHODNAME' : blocks[b][0] ,'BLOCKMETHODCODE' : align(blocks[b][1], 1) })); sblocks = sblocks.length ? EOL + "self._blocks = {" + EOL + sblocks.join(',' + EOL) + EOL + "};" + EOL : ''; renderCode = TT_RCODE.render({ 'RCODE' : $__extends ? "__p__ = '';" : "__p__ += '" + renderf + "';" }); //extendCode = $__extends ? "self.extend('" + $__extends + "');" : ''; extendCode = $__extends ? "self._extendsTpl = '" + $__extends + "';" : ''; extendCode += EOL + "self._usesTpl = [" + ($__uses.length ? "'"+$__uses.join("','")+"'" : '') + "];"; prefixCode = contx.prefix ? contx.prefix : ''; // generate tpl class var classCode = TT_ClassCode.render({ 'CLASSNAME' : classname ,'TPLID' : id ,'PREFIXCODE' : prefixCode ,'EXTENDCODE' : align(extendCode, 1) ,'BLOCKS' : align(sblocks, 1) ,'RENDERCODE' : align(renderCode, 1) }); return fwrite(filename, classCode, contx.encoding); } } function get_cached_template(id, contx, options, cb) { cb = 'function' === typeof cb ? cb : null; var template, tplclass, tpl, sprTpl, funcs, cachedTplFile, cachedTplClass, stat, stat2, exists, fname, fpath, parsed; template = contx.templates[id] || $__global.templates[id] || null; if (!template) { if (cb) { cb(null, null); } return null; } options = options || {context:contx.id,autoUpdate:false}; parsed = options.parsed || null; if (HAS.call(options, 'parsed')) delete options.parsed; if (cb) { var setUsedTpls = function(tpl, cb) { var usedTpls = tpl._usesTpl && tpl._usesTpl.length ? tpl._usesTpl : null; if (usedTpls) { var i = 0, load_one = function load_one() { if (i >= 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<x.length;}); } function create_path(path, root, mode, cb) { path = trim(path); if (!path.length) return; mode = mode || parseInt('0755', 8); root = root || ''; var i, l, parts = split_and_filter(DS_RE, path), current = rtrim(root, '/\\'), exists0 = true; if ('function' === typeof cb) { i = 0; l = parts.length; current += '/' + parts[i]; var create_one_level = function create_one_level() { if (i >= 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<l; ++i) { current += '/' + parts[i]; if (!fexists(current) /*&& !fis_dir(current)*/) fmkdir(current, mode); } } } function ContemplateException(msg) { this.name = 'ContemplateException'; this.message = msg; } ContemplateException[PROTO] = Object.create(Error[PROTO]); // can use inline templates for plugins etc.. to enable non-linear plugin compile-time replacement function InlineTemplate(tpl, replacements, compiled) { var self = this; if (!(self instanceof InlineTemplate)) return new InlineTemplate(tpl, replacements, compiled); self.id = null; self._renderer = null; self._parsed = false; // lazy init, only if needed, as and when needed self._args = [tpl, replacements, compiled]; self.tpl = null; } InlineTemplate.multisplit = function multisplit(tpl, reps, as_array) { var r, sr, s, i, j, a, b, c, al, bl/*, as_array = is_array(reps)*/; as_array = !!as_array; a = [[1, tpl]]; for (r in reps) { if (!HAS.call(reps, r)) continue; c = []; sr = as_array ? reps[r] : r; s = [0, reps[r]]; for (i=0,al=a.length; i<al; ++i) { if (1 === a[i][0]) { b = a[i][1].split(sr); bl = b.length; c.push([1, b[0]]); if (bl > 1) { for (j=0; j<bl-1; ++j) { c.push(s); c.push([1, b[j+1]]); } } } else { c.push(a[i]); } } a = c; } return a; }; InlineTemplate.multisplit_re = function multisplit_re(tpl, re) { re = re.global ? re : new RegExp(re.source, re.ignoreCase ? "gi" : "g"); /* make sure global flag is added */ var a = [], i = 0, m; while (m = re.exec(tpl)) { a.push([1, tpl.slice(i, re.lastIndex - m[0].length)]); a.push([0, m[1] ? m[1] : m[0]]); i = re.lastIndex; } a.push([1, tpl.slice(i)]); return a; }; InlineTemplate.compile = function(tpl) { var l = tpl.length, i, notIsSub, s, out = '"use strict";' + "\n" + 'return ('; ; for (i=0; i<l; ++i) { notIsSub = tpl[i][0]; s = tpl[i][1]; if (notIsSub) out += "'" + s.replace(SQUOTE, "\\'").replace(NEWLINE, "' + \"\\n\" + '") + "'"; else out += " + String(args['" + s + "']) + "; } out += ');'; return FUNC('args', out); }; InlineTemplate[PROTO] = { constructor: InlineTemplate ,id: null ,tpl: null ,_renderer: null ,_parsed: false ,_args: null ,dispose: function() { var self = this; self.id = null; self.tpl = null; self._renderer = null; self._parsed = null; self._args = null; return self; } ,render: function(args) { var self = this; args = args || []; if (!self._parsed) // lazy init, only if needed, as and when needed { var tpl = self._args[0], replacements = self._args[1], compiled = self._args[2]; self.tpl = replacements instanceof RegExp ? InlineTemplate.multisplit_re(tpl||'', replacements) : InlineTemplate.multisplit(tpl||'', replacements||{}); if (true === compiled) { self._renderer = InlineTemplate.compile(self.tpl); self.render = self._renderer; } self._args = null; self._parsed = true; } if (is_callable(self._renderer)) return self._renderer(args); var tpl = self.tpl, l = tpl.length, i, notIsSub, s, out = '' ; for (i=0; i<l; ++i) { notIsSub = tpl[i][0]; s = tpl[i][1]; out += (notIsSub ? s : args[s]); } return out; } }; function Template(id) { var self = this; if (!(self instanceof Template)) return new Template(id); self._renderer = null; self._blocks = null; self._extends = null; self._extendsTpl = null; self._usesTpl = null; self._ctx = null; self._autonomus = false; self.id = null; if (id) self.id = id; } Template.spr = function(data, __i__) { var self = this, r, __ctx = false; !__i__&&(__i__=self)&&(self._autonomus||(__ctx=Contemplate._set_ctx(self._ctx))); r = self._extends.render(data, __i__); __ctx&&Contemplate._set_ctx(__ctx); return r; }; Template.fixr = function(tpl) { tpl.render = tpl._extends instanceof Template ? Template.spr : (is_callable(tpl._renderer) ? tpl._renderer : tpl.constructor[PROTO].render); return tpl; }; Template[PROTO] = { constructor: Template ,id: null ,_renderer: null ,_blocks: null ,_extends: null ,_extendsTpl: null ,_usesTpl: null ,_ctx: null ,_autonomus: false // public methods ,dispose: function() { var self = this; self._renderer = null; self._blocks = null; self._extends = null; self._extendsTpl = null; self._usesTpl = null; self._ctx = null; self._autonomus = null; self.id = null; return self; } ,setId: function(id) { if (id) this.id = id; return this; } ,ctx: function(ctx) { this._ctx = ctx; return this; } ,autonomus: function(enable) { this._autonomus = !arguments.length ? true : !!enable; return this; } ,extend: function(tpl) { var self = this; self._extends = tpl && tpl.substr ? Contemplate.tpl(tpl) : (tpl instanceof Template ? tpl : null); Template.fixr(self); return self; } ,usesTpl: function(usedTpls) { var self = this; self._usesTpl = [].concat(usedTpls); return self; } ,setRenderFunction: function(renderfunc) { var self = this; self._renderer = is_callable(renderfunc) ? renderfunc(Contemplate) : null; Template.fixr(self); return self; } ,setBlocks: function(blocks) { var self = this; if ('object' === typeof blocks) self._blocks = merge(self._blocks || {}, blocks); return self; } ,sprblock: function(block, data/*, __i__*/) { var self = this; //__i__ = __i__ || self; if (self._extends) return self._extends.block(block, data, self._extends); return ''; } ,block: function(block, data, __i__) { var self = this, r = '', __ctx = false, blocks = self._blocks; !__i__&&(__i__=self)&&(self._autonomus||(__ctx=Contemplate._set_ctx(self._ctx))); if (blocks && HAS.call(blocks, block)) r = blocks[block](Contemplate, data, self, __i__); else if (self._extends) r = self._extends.block(block, data, __i__); __ctx&&Contemplate._set_ctx(__ctx); return r; } ,render: function(data, __i__) { return ''; } } // aliases Template[PROTO].renderBlock = Template[PROTO].block; Template[PROTO].renderSuperBlock = Template[PROTO].sprblock; function Ctx(id) { var self = this; self.id = id; self.cacheDir = './'; self.cacheMode = 0; self.cache = {}; self.templateDirs = []; self.templateFinder = null; self.templates = {}; self.partials = {}; self.plugins = {}; self.prefix = ''; self.encoding = isXPCOM ? 'UTF-8' : 'utf8'; } Ctx[PROTO] = { constructor: Ctx ,id: null ,cacheDir: null ,cacheMode: null ,cache: null ,templateDirs: null ,templateFinder: null ,templates: null ,partials: null ,plugins: null ,prefix: null ,encoding: null ,dispose: function() { var self = this; self.id = null; self.cacheDir = null; self.cacheMode = null; self.templateDirs = null; self.templateFinder = null; self.templates = null; self.partials = null; self.plugins = null; self.prefix = null; self.encoding = null; if (self.cache) { for(var tpl in self.cache) if (HAS.call(self.cache, tpl)) self.cache[tpl].dispose(); } self.cache = null; } }; Contemplate = { // constants VERSION: __version__ ,CACHE_TO_DISK_NONE: 0 ,CACHE_TO_DISK_AUTOUPDATE: 2 ,CACHE_TO_DISK_NOUPDATE: 4 ,Exception: ContemplateException ,Template: Template ,InlineTemplate: InlineTemplate ,Ctx: Ctx ,init: function() { if ($__isInited) return; // a default global context $__global = new Ctx('global'); $__ctx = { 'global' : $__global }; $__context = $__global; // pre-compute the needed regular expressions $__preserveLines = $__preserveLinesDefault; $__tplStart = "';" + $__TEOL; $__tplEnd = $__TEOL + "__p__ += '"; // make compilation templates TT_ClassCode = new InlineTemplate([ "#PREFIXCODE#" ,"!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];} );" ,"}('undefined' !== typeof self ? self : this,'#CLASSNAME#',function() {" ,"\"use strict\";" ,"return function(Contemplate) {" ,"/* Contemplate cached template '#TPLID#', constructor */" ,"function #CLASSNAME#(id)" ,"{" ," var self = this;" ," Contemplate.Template.call(self, id);" ," /* tpl-defined blocks render code starts here */" ,"#BLOCKS#" ," /* tpl-defined blocks render code ends here */" ," /* extend tpl assign code starts here */" ,"#EXTENDCODE#" ," /* extend tpl assign code ends here */" ,"}" ,"/* extends main Contemplate.Template class */" ,"#CLASSNAME#.prototype = Object.create(Contemplate.Template.prototype);" ,"/* render method */" ,"#CLASSNAME#.prototype.render = function(data, __i__) {" ," \"use strict\";" ," var self = this, __p__ = '', __ctx = false;" ," !__i__&&(__i__=self)&&(self._autonomus||(__ctx=Contemplate._set_ctx(self._ctx)));" ," /* tpl main render code starts here */" ,"#RENDERCODE#" ," /* tpl main render code ends here */" ," __ctx&&Contemplate._set_ctx(__ctx);" ," return __p__;" ,"};" ,"// export it" ,"return #CLASSNAME#;" ,"};" ,"});" ,"" ].join($__TEOL), { "#PREFIXCODE#" : "PREFIXCODE" ,"#CLASSNAME#" : "CLASSNAME" ,"#TPLID#" : "TPLID" ,"#BLOCKS#" : "BLOCKS" ,"#EXTENDCODE#" : "EXTENDCODE" ,"#RENDERCODE#" : "RENDERCODE" }, false); TT_BlockCode = new InlineTemplate([ "" ,"/* tpl block render method for block '#BLOCKNAME#' */" ,"'#BLOCKMETHODNAME#': function(Contemplate, data, self, __i__) {" ,"#BLOCKMETHODCODE#" ,"}" ,"" ].join($__TEOL), { "#BLOCKNAME#" : "BLOCKNAME" ,"#BLOCKMETHODNAME#" : "BLOCKMETHODNAME" ,"#BLOCKMETHODCODE#" : "BLOCKMETHODCODE" }, false); TT_BLOCK = new InlineTemplate([ "\"use strict\";" ,"var __p__ = '';" ,"#BLOCKCODE#" ,"return __p__;" ,"" ].join($__TEOL), { "#BLOCKCODE#" : "BLOCKCODE" }, false); TT_FUNC = new InlineTemplate([ "return function(data, __i__){" ,"\"use strict\";" ,"var self = this, __p__ = '', __ctx = false;" ,"!__i__&&(__i__=self)&&(self._autonomus||(__ctx=Contemplate._set_ctx(self._ctx)));" ,"#FCODE#" ,"__ctx&&Contemplate._set_ctx(__ctx);" ,"return __p__;" ,"};" ].join($__TEOL), { "#FCODE#" : "FCODE" }, false); TT_RCODE = new InlineTemplate([ "" ,"#RCODE#" ,"" ].join($__TEOL), { "#RCODE#" : "RCODE" }, false); clear_state(); $__isInited = true; } ,_set_ctx: function(ctx) { var contx = $__context; /*if ( ctx instanceof Ctx ) $__context = ctx; else if ( ctx && HAS.call($__ctx,ctx) ) $__context = $__ctx[ctx]; else $__context = $__global;*/ $__context = ctx ? ctx : $__global; return contx; } // // Main API methods // ,createCtx: function(ctx) { if (ctx && 'global' !== ctx && !HAS.call($__ctx,ctx)) $__ctx[ctx] = new Ctx(ctx); } ,disposeCtx: function(ctx) { if (ctx && 'global' !== ctx && HAS.call($__ctx, ctx)) { $__ctx[ctx].dispose(); delete $__ctx[ctx]; } } ,setTemplateSeparators: function(seps) { if (seps) { if (seps['left']) $__leftTplSep = ''+seps['left']; if (seps['right']) $__rightTplSep = ''+seps['right']; } } ,setPreserveLines: function(enable) { if (arguments.length < 1) enable = true; $__preserveLines = !!enable ? $__preserveLinesDefault : ''; } ,hasPlugin: function(name, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; return !!name && (HAS.call(contx.plugins, name) || HAS.call($__global.plugins, name)); } ,addPlugin: function(name, pluginCode, ctx) { var contx; if (name && pluginCode) { if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; contx.plugins[name] = pluginCode; } } ,plg_: function(plg) { var args = arguments; if (HAS.call($__context.plugins, plg) && is_callable($__context.plugins[plg])) { return $__context.plugins[plg].apply(null, slice.call(args, 1)); } else if (HAS.call($__global.plugins, plg) && is_callable($__global.plugins[plg])) { return $__global.plugins[plg].apply(null, slice.call(args, 1)); } return ''; } ,setPrefixCode: function(preCode, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; if (preCode) contx.prefix = '' + preCode; } ,setEncoding: function(encoding, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx,ctx) ? $__ctx[ctx] : $__context; contx.encoding = encoding; } ,setCacheDir: function(dir, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; contx.cacheDir = rtrim(dir, '/\\') + '/'; } ,setCacheMode: function(mode, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; contx.cacheMode = isNode || isXPCOM ? mode : Contemplate.CACHE_TO_DISK_NONE; } ,setTemplateDirs: function(dirs, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; contx.templateDirs = [].concat(dirs); } ,getTemplateDirs: function(ctx) { var contx; if (arguments.length < 1) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; return contx.templateDirs; } ,setTemplateFinder: function(finder, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; contx.templateFinder = is_callable(finder) ? finder : null; } ,clearCache: function(all, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; contx.cache = {}; if (all) contx.partials = {}; } ,add: function(tpls, ctx) { var contx, tplID; if (tpls && ("object" === typeof tpls)) { if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; for (tplID in tpls) { if (!HAS.call(tpls, tplID)) continue; if (is_array(tpls[tplID])) { // unified way to add tpls both as reference and inline // inline tpl, passed as array if (tpls[tplID][0]) contx.templates[tplID] = [tpls[tplID][0], true]; } else { contx.templates[tplID] = [tpls[tplID], false]; } } } } ,hasTpl: function(tpl, ctx) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; return !!tpl && (HAS.call(contx.templates, tpl) || HAS.call($__global.templates, tpl)); } ,getTemplateContents: function(id, ctx, cb) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; if (is_callable(cb)) { get_template_contents(id, contx, function(err, tpl) { cb(err, tpl); }); } else { return get_template_contents(id, contx); } } ,getTemplateContentsPromise: function(id, ctx) { if ('function' === typeof Promise) { return new Promise(function(resolve, reject) { Contemplate.getTemplateContents(id, ctx, function(err, data) { if (err) reject(err); else resolve(data); }); }); } return null; } ,findTpl: function(tpl, ctx, cb) { var contx; if (arguments.length < 2) ctx = 'global'; contx = ctx && HAS.call($__ctx, ctx) ? $__ctx[ctx] : $__context; if (is_callable(cb)) { var templateDirs, filename, dir, search_one = function search_one() { if (dir >= 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<l; ++dir) { path = rtrim(contx.templateDirs[dir],'/\\') + '/' + filename; if (fexists(path)) return path; } return null; } if (contx != $__global) { contx = $__global 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<l; ++dir) { path = rtrim(contx.templateDirs[dir],'/\\') + '/' + filename; if (fexists(path)) return path; } return null; } } } return null; } ,findTplPromise: function(tpl, ctx) { if ('function' === typeof Promise) { if (arguments.length < 2) ctx = 'global'; return new Promise(function(resolve, reject) { Contemplate.findTpl(tpl, ctx, function(err, found) { if (err) reject(err); else resolve(found); }); }); } return null; } ,parseTpl: function(tpl, options, cb) { var parsed, leftSep, rightSep, separators, _ctx, contx = null; // see what context this template may use if (options && options.substr) { if (HAS.call($__ctx, options)) contx = $__ctx[options]; // preset context else contx = $__global; // global context options = {}; } options = merge({ 'separators': null }, options); if (options.context) { if (HAS.call($__ctx, options.context)) contx = $__ctx[options.context]; // preset context else if (!contx) contx = $__global; // global context delete options.context; } if (!contx) contx = $__global; // global context leftSep = $__leftTplSep; rightSep = $__rightTplSep; separators = options && options.separators ? options.separators : null; if (separators) { leftSep = separators[0]; rightSep = separators[1]; } if (is_callable(cb)) { _ctx = $__context; $__context = contx; reset_state(); parse(tpl, leftSep, rightSep, true, function(err, parsed) { clear_state(); $__context = _ctx; cb(err, parsed); }); return null; } else { _ctx = $__context; $__context = contx; reset_state(); parsed = parse(tpl, leftSep, rightSep, true); clear_state(); $__context = _ctx; return parsed; } } ,parseTplPromise: function(tpl, options) { if ('function' === typeof Promise) { return new Promise(function(resolve, reject) { Contemplate.parseTpl(tpl, options, function(err, parsed) { if (err) reject(err); else resolve(parsed); }); }); } return null; } // // Main Template functions // ,tpl: function(tpl, data, options, cb) { cb = is_callable(cb) ? cb : null; var tmpl, contx, _ctx; if (tpl instanceof Contemplate.Template) { tmpl = tpl; if (cb) { // Provide some basic currying to the user cb(null, data && ("object" === typeof data) ? tmpl.render(data) : tmpl); return null; } else { // Provide some basic currying to the user return data && ("object" === typeof data) ? tmpl.render(data) : tmpl; } } else { // see what context this template may use contx = null; if (null == options) options = {}; if (options && options.substr) { if (HAS.call($__ctx, options)) contx = $__ctx[options]; // preset context else contx = $__context; // current context options = {}; } options = merge({ 'separators': null ,'autoUpdate': false ,'refresh': false ,'escape': true ,'standalone': false }, options); if (options.context) { if (HAS.call($__ctx, options.context)) contx = $__ctx[options.context]; // preset context else if (!contx) contx = $__context; // current context delete options.context; } if (!contx) contx = $__context; // current context $__escape = false !== options.escape; if (cb) { var proceed = function() { // asynchronous loading, parsing and writing if (!!options.refresh || (!contx.cache[tpl] && !$__global.cache[tpl])) { _ctx = $__context; $__context = contx; get_cached_template(tpl, contx, options, function(err, ctpl) { $__context = _ctx; if (err) { cb(err, null); return; } contx.cache[tpl] = ctpl; tmpl = contx.cache[tpl] || $__global.cache[tpl]; tmpl.autonomus(options.standalone); cb(null, data && ("object"===typeof data) ? tmpl.render(data) : tmpl); }); } else { tmpl = contx.cache[tpl] || $__global.cache[tpl]; tmpl.autonomus(options.standalone); cb(null, data && ("object"===typeof data) ? tmpl.render(data) : tmpl); } }; if (null == options['parsed'] && !Contemplate.hasTpl(tpl, contx.id)) { // async operation Contemplate.findTpl(tpl, contx.id, function(err, path) { if (!path) { cb(null, data && "object"===typeof data ? '' : null); return; } var tpldef = {}; tpldef[tpl] = path; Contemplate.add(tpldef, contx.id); proceed(); }); } else { proceed(); } return null; } else { if (null == options['parsed'] && !Contemplate.hasTpl(tpl, contx.id)) { // sync operation var path = Contemplate.findTpl(tpl, contx.id); if (!path) return data && "object"===typeof data ? '' : null; var tpldef = {}; tpldef[tpl] = path; Contemplate.add(tpldef, contx.id); } // Figure out if we're getting a template, or if we need to // load the template - and be sure to cache the result. if (!!options.refresh || (!contx.cache[tpl] && !$__global.cache[tpl])) { _ctx = $__context; $__context = contx; contx.cache[tpl] = get_cached_template(tpl, contx, options); $__context = _ctx; } tmpl = contx.cache[tpl] || $__global.cache[tpl]; tmpl.autonomus(options.standalone); // Provide some basic currying to the user return data && ("object"===typeof data) ? tmpl.render(data) : tmpl; } } } ,tplPromise: function(tpl, data, options) { if ('function' === typeof Promise) { return new Promise(function(resolve, reject) { Contemplate.tpl(tpl, data, options, function(err, tpl) { if (err) reject(err); else resolve(tpl); }); }); } return null; } ,inline: function(tpl, reps, compiled) { return (tpl instanceof Contemplate.InlineTemplate) ? tpl.render(reps) : Contemplate.InlineTemplate(tpl, reps, compiled); } ,concat: function() { return join.call(arguments, ''); } ,join: function(sep, args, skip_empty) { if (null == args) return ''; skip_empty = true === skip_empty; if ('object' !== typeof args) return skip_empty&&!String(args).length ? '' : String(args); if (null == sep) sep = ''; var i, l = args.length, s, out = l > 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<l; ++i) { s = 'object' === typeof args[i] ? Contemplate.join(sep, args[i], skip_empty) : (skip_empty&&(null==args[i]||!String(args[i]).length) ? '' : String(args[i])); if (!skip_empty || s.length > 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<args.length; ++i) { if (null == tmp || !Contemplate.is_array(tmp) || !HAS.call(tmp,args[i])) return false; tmp = tmp[args[i]]; } return true; } ,time: php_time ,date: function(format, timestamp) { if (arguments.length < 2) timestamp = php_time(); return php_date(format, timestamp); } ,lowercase: function(s) { return String(s).toLowerCase(); } ,uppercase: function(s) { return String(s).toUpperCase(); } ,striptags: function(s) { return s.replace(TAG_RE, ''); } ,e: function(s, entities) { // http://jsperf.com/split-join-vs-regex-replace/10 var i = 0, l = s.length, r = '', c, cd; if (entities) { for (i=0; i<l; ++i) { c = s.charAt(i); cd = c.charCodeAt(0); switch (cd) { case 34: r += "&quot;"; break; case 38: r += "&amp;"; break; case 39: r += "&apos;"; break; case 60: r += "&lt;"; break; case 62: r += "&gt;"; break; default: r += c; } } } else { for (i=0; i<l; ++i) { c = s.charAt(i); cd = c.charCodeAt(0); switch (cd) { case 34: case 38: case 39: case 60: case 62: r += "&#"+cd+";"; break; default: r += c; } } } return r; } ,json_encode: function(v) { return JSON.stringify(v); } ,json_decode: function(v) { return JSON.parse(v); } ,urlencode: urlencode ,urldecode: urldecode ,buildquery: function(data) { return http_build_query(data, '&'); } ,parsequery: function(str) { return parse_str(str); } ,queryvar: function(url, add_keys, remove_keys) { var keys, key, value, k, l, last, q, to_str; if (null != remove_keys) { // https://davidwalsh.name/php-remove-variable keys = [].concat(remove_keys); l = keys.length; for (k=0; k<l; ++k) { url = url.replace(RE('(\\?|&)' + urlencode( keys[k] ).replace(re_9, '\\$1') + '(\\[[^\\[\\]]*\\])*(=[^&]+)?','g'), '$1'); } url = url.replace(AMP_RE, '&').replace('?&', '?'); last = url.slice(-1); if ('?' === last || '&' === last) { url = url.slice(0,-1); } } if (!!add_keys) { keys = Keys(add_keys); l = keys.length; q = -1 === url.indexOf('?') ? '?' : '&'; for(k=0; k<l; ++k) { key = keys[k]; value = add_keys[key]; key = urlencode(key); to_str = toString.call(value); if ('[object Array]' === to_str || '[object Object]' === to_str) { if ('[object Array]' === to_str) { for (var v=0,vl=value.length; v<vl; ++v) { url += q + key + '[]=' + urlencode(value[v]); q = '&'; } } else { for (var kvalue=Keys(value),v=0,vl=kvalue.length; v<vl; ++v) { url += q + key + '[' + urlencode(kvalue[v]) + ']=' + urlencode(value[kvalue[v]]); q = '&'; } } } else { url += q + key + '=' + urlencode(value); } q = '&'; } } return url; } ,get: function(v, keys, default_value) { default_value = null != default_value ? default_value : null; if (!Contemplate.is_array(keys, true)) keys = [keys]; var o = v, k = 0, l = keys.length, found = 1, key, keyGetter; for (k=0; k<l; ++k) { key = String(keys[k]); if (HAS.call(o, key)) { o = o[key]; } else { keyGetter = 'get' + key.charAt(0).toUpperCase() + key.substring(1); if (/*HAS.call(o, keyGetter) &&*/ is_callable(o[keyGetter])) { o = o[keyGetter](); } else { found = 0; break; } } } return found ? o : default_value; } ,uuid: function(namespace) { return [namespace||'UUID', ++$__uuid, php_time()].join('_'); } ,merge: merge //,local_variable: local_variable //,is_local_variable: is_local_variable // extra for js version ,empty: empty ,trim: trim ,ltrim: ltrim ,rtrim: rtrim ,sprintf: sprintf ,vsprintf: function(fmt, args) { return sprintf.apply(null, [fmt].concat(args||[])); } }; // Template Engine end here // // var default_date_locale = { meridian: {am:'am', pm:'pm', AM:'AM', PM:'PM'} ,ordinal: {ord:{1:'st',2:'nd',3:'rd'}, nth:'th'} ,timezone: ['UTC','EST','MDT'] ,timezone_short: ['UTC','EST','MDT'] ,day: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'] ,day_short: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] ,month: ['January','February','March','April','May','June','July','August','September','October','November','December'] ,month_short: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] }, Keys = Obj.keys, join = Arr[PROTO].join, slice = Arr[PROTO].slice, floor = Math.floor, round = Math.round, abs = Math.abs, re_1 = /([\s\S]*?)(&(?:#\d+|#x[\da-f]+|[a-zA-Z][\da-z]*);|$)/g, re_2 = /!/g, re_3 = /'/g, re_4 = /\(/g, re_5 = /\)/g, re_6 = /\*/g, re_7 = /%20/g, re_8 = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g, re_9 = /([\[\]\(\)\.\?\/\*\{\}\+\$\^\:\\])/g, rtrim_re = /[ \s\u00A0]+$/g, ltrim_re = /^[ \s\u00A0]+/g, trim_re = /^[ \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]+|[ \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]+$/g, fileurl_2_nsfile = function(file_uri) { // NetUtil.newURI(file_uri).QueryInterface(Ci.nsIFileURL).file // http://stackoverflow.com/q/24817347/3591273 /*var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService), url = ios.newURI(file_uri, null, null), // url is a nsIURI // file is a nsIFile file = url.QueryInterface(Ci.nsIFileURL).file;*/ return Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI(file_uri, null, null).QueryInterface(Ci.nsIFileURL).file; }, fexists = isXPCOM ? function fexists(file) { // file is URI, i.e file://... return fileurl_2_nsfile(file).exists(); } : (isNode ? function fexists(file) { return fs.existsSync(file); } : function fexists(file) { return true; }), fexists_async = isXPCOM ? function fexists_async(file, cb) { // file is URI, i.e file://... if (cb) cb(null, fexists(file)); } : (isNode ? function fexists_async(file, cb) { // exists is deprecated due to incompatible callback signature //fs.exists(file, cb); fs.stat(file, function(err, stat) { if (!cb) return; if (!err) { // exists cb(null, true); } else if ('ENOENT' === err.code) { // file does not exist cb(null, false); } else // some other error { cb(err, null); } }); } : function fexists_async(file, cb) { if (cb) cb(null, true); }), fis_dir = isXPCOM ? function fis_dir(file) { return fileurl_2_nsfile(file).isDirectory(); } : (isNode ? function fis_dir(file) { return fs.lstatSync(file).isDirectory(); } : function fis_dir(file) { return false; }), fis_dir_async = isXPCOM ? function fis_dir_async(file, cb) { if (cb) cb(null, fileurl_2_nsfile(file).isDirectory()); } : (isNode ? function fis_dir_async(file, cb) { fs.lstat(file, function(err, stats){ if (cb) cb(err, err ? null : stats.isDirectory()); }); } : function fis_dir_async(file, cb) { if (cb) cb(null, false); }), fmkdir = isXPCOM ? function fmkdir(file, mode) { var nsfile = fileurl_2_nsfile(file); return nsfile.create(nsfile.DIRECTORY_TYPE, mode); } : (isNode ? function fmkdir(file, mode) { return fs.mkdirSync(file, mode); } : function fmkdir(file, mode) { // do nothing return false; }), fmkdir_async = isXPCOM ? function fmkdir_async(file, mode, cb) { var res = fmkdir(file, mode); if (cb) cb(null, res); } : (isNode ? function fmkdir_async(file, mode, cb) { fs.mkdir(file, mode, function(err) { if (cb) cb(err, err ? false : true); }); } : function fmkdir_async(file, mode, cb) { // do nothing if (cb) cb(null, false); }), fstat = isXPCOM ? function fstat(file) { // file is URI, i.e file://... var mtime = fileurl_2_nsfile(file).lastModifiedTime; return {mtime: !!mtime ? new Date(mtime) : false}; } : (isNode ? function fstat(file) { return fs.statSync(file); } : function fstat(file) { // http://stackoverflow.com/a/5748207/3591273 var xhr = XHR(), mtime, stats = {mtime: false}; xhr.open('HEAD', file, false); // 'false' makes the request synchronous xhr.send(null); if (200 === xhr.status) { mtime = new Date(xhr.getResponseHeader('Last-Modified')); if (xhr.toString() === 'Invalid Date') mtime = false; stats.mtime = mtime; } return stats; }), fstat_async = isXPCOM ? function fstat_async(file, cb) { if (cb) cb(null, fstat(file)); } : (isNode ? function fstat_async(file, cb) { fs.stat(file, cb); } : function fstat_async(file, cb) { // http://stackoverflow.com/a/5748207/3591273 var xhr = XHR(), mtime, stats = {mtime: false}; xhr.open('HEAD', file, true); // 'true' makes the request asynchronous xhr.onload = function() { if (200 === xhr.status) { mtime = new Date(xhr.getResponseHeader('Last-Modified')); if (mtime.toString() === 'Invalid Date') mtime = false; stats.mtime = mtime; } if (cb) cb(null, stats); }; xhr.send(null); }), fread = isXPCOM ? function fread(file, enc) { // file is URI, i.e file://... var data = '', stream, conv, len, str = {value:''}, read = 0; // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); conv = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream); stream.init(fileurl_2_nsfile(file), -1, 0, 0); conv.init(stream, enc||'UTF-8', 0, 0); do { // read as much as we can and put it in str.value read = conv.readString(0xffffffff, str); data += str.value; } while (0 != read); conv.close(); // this closes stream return data; } : (isNode ? function fread(file, enc) { return fs.readFileSync(file, {encoding:enc||'utf8'})/*.toString()*/; } : function fread(file, enc) { var xhr = XHR(); // plain text with enc encoding format xhr.open('GET', file, false); // 'false' makes the request synchronous // http://stackoverflow.com/questions/9855127/setting-xmlhttprequest-responsetype-forbidden-all-of-a-sudden xhr.setRequestHeader("Content-Type", "text/plain; charset="+(enc||'utf8')+""); xhr.overrideMimeType("text/plain; charset="+(enc||'utf8')+""); xhr.send(null); return 200 === xhr.status ? xhr.responseText : ''; }), fread_async = isXPCOM ? function fread_async(file, enc, cb) { // file is URI, i.e file://... // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O NetUtil.asyncFetch(fileurl_2_nsfile(file), function(stream, status) { var err = !Components.isSuccessCode(status), data = err ? '' : NetUtil.readInputStreamToString(stream, stream.available(), {charset:enc||'UTF-8'}); if (cb) cb(err, data); }); } : (isNode ? function fread_async(file, enc, cb) { fs.readFile(file, {encoding:enc||'utf8'}, cb); } : function fread_async(file, enc, cb) { var xhr = XHR(); // plain text with enc encoding format xhr.open('GET', file, true); // 'true' makes the request asynchronous xhr.responseType = "text"; xhr.setRequestHeader("Content-Type", "text/plain; charset="+(enc||'utf8')+""); xhr.overrideMimeType("text/plain; charset="+(enc||'utf8')+""); xhr.onload = function() { var err = 200 !== xhr.status, data = err ? '' : xhr.responseText; if (cb) cb(err, data); }; xhr.send(null); }), // https://github.com/moxystudio/node-proper-lockfile // https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Overlay_Extensions/Firefox_addons_developer_guide/Using_XPCOM%E2%80%94Implementing_advanced_processes // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions fwrite = isXPCOM ? function fwrite(file, data, enc) { // file is URI, i.e file://... var stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream), conv = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream); // use 0x02 | 0x10 to open file for appending. // write, create, truncate // In a c file operation, we have no need to set file mode with or operation, // directly using "r" or "w" usually. // if you are sure there will never ever be any non-ascii text in data you can // also call foStream.write(data, data.length) directly // https://bugzilla.mozilla.org/show_bug.cgi?id=572890 stream.init(fileurl_2_nsfile( file ), 0x02|0x08|0x20, 0x1B6/*0666*/, 0); conv.init(stream, enc||"UTF-8", 0, 0); conv.writeString(data); conv.close(); // this closes stream } : (isNode ? function fwrite(file, data, enc) { fs.writeFileSync(file, data, {encoding:enc||'utf8'})/*.toString()*/; } : function fwrite(file, data, enc) { }), fwrite_async = isXPCOM ? function fwrite_async(file, data, enc, cb) { // file is URI, i.e file://... // http://stackoverflow.com/questions/9777773/reading-writing-file-on-local-machine var istream, ostream, conv; ostream = FileUtils.openSafeFileOutputStream(fileurl_2_nsfile(file)); conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); conv.charset = enc||"UTF-8"; istream = conv.convertToInputStream(data); NetUtil.asyncCopy(istream, ostream, function(status) { if (cb) cb(Components.isSuccessCode(status)); }); } : (isNode ? function fwrite_async(file, data, enc, cb) { fs.writeFile(file, data, {encoding: enc||'utf8'}, function(err,res) { cb(err,res); }); } : function fwrite_async(file, data, enc, cb) { if (cb) cb(null); }), FUNC = isXPCOM ? function FUNC(a, f) { // create new sandbox instance // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Language_Bindings/Components.utils.Sandbox /*system principal*/ /*null*/ /*null principal*/ var principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal), sandbox = new Cu.Sandbox(principal, { sandboxName: 'contemplate_sandbox_' + $__context.id, sameZoneAs: Contemplate, wantComponents: false, wantExportHelpers: false, wantXrays: true, wantGlobalProperties: [] }), fn_uuid = Contemplate.uuid('dyna_func'); sandbox.Contemplate = Contemplate; /*return */Cu.evalInSandbox(';function '+fn_uuid+'('+a+'){'+f+'};', sandbox); return sandbox[fn_uuid]; } : function FUNC(a, f) { return new Function(a, f); }/*, ASYNC_SUPPORTED = isXPCOM ? false : (function() { var test = null; try { test = (new Function('', 'return async function(){};'))(); } catch (e) { return false; } return is_callable(test) && is_asyncf(test); })(), ASYNC_FUNC = ASYNC_SUPPORTED ? function ASYNC_FUNC(a, f) { return FUNC('', 'return async function('+a+'){'+f+'};')(); } : FUNC*/ ; // utilities function RE(r, f) { return new RegExp(r, f||''); } function empty(o) { // exactly like php's empty function if (!o || !Boolean(o) || "0" === o) return true; var to_string = toString.call(o); if ((o instanceof Array || o instanceof String || '[object Array]' === to_string || '[object String]' === to_string) && !o.length) return true; if ((o instanceof Object || '[object Object]' === to_string) && !array_keys(o).length ) return true; return false; } // php-like functions, mostly adapted and optimised from phpjs project, https://github.com/kvz/phpjs function is_callable(o) { return 'function' === typeof o; } /*function is_asyncf(o) { return /*('function' === typeof o) &&* ('AsyncFunction' === o.constructor.name); }*/ // http://jsperf.com/instanceof-array-vs-array-isarray/6 function is_array(o) { return o && (/*(o.constructor === Arr)*/(o instanceof Arr) || ('[object Array]' === toString.call(o))); } function is_object(o) { return o && (/*(o.constructor === Obj)(o instanceof Obj) ||*/ ('[object Object]' === toString.call(o))); } function count(mixed_var) { return null == mixed_var ? 0 : (is_array(mixed_var) ? mixed_var.length : (is_object(mixed_var) ? array_keys(mixed_var).length : 1)); } function array_keys(o) { if (is_callable(Object.keys)) return Object.keys(o); var v, k, l; if (is_array(o)) { v = new Array(l=o.length); for(k=0; k<l; ++k) v[k] = String(k); } else { v = []; for (k in o) if (HAS.call(o, k)) v.push(k); } return v; } function array_values(o) { if (is_array(o)) return o; if (is_callable(Object.values)) return Object.values(o); var v = [], k; for (k in o) if (HAS.call(o, k)) v.push(o[k]); return v; } function is_numeric_array(o) { if (is_array(o)) return true; if (is_object(o)) { var k = array_keys(o), i, l = k.length; for (i=0; i<l; ++i) if (i !== +k[i]) return false; return true; } return false; } function ltrim(str, charlist) { return (str+'').replace( !charlist ? ltrim_re : RE('^[' + (charlist+'').replace(re_9, '\\$1') + ']+', 'g'), ''); } function rtrim(str, charlist) { return (str+'').replace( !charlist ? rtrim_re : RE('[' + (charlist+'').replace(re_9, '\\$1') + ']+$', 'g'), ''); } function trim(str, charlist) { return (str+'').replace( !charlist ? trim_re : RE('^[' + (charlist=(charlist+'').replace(re_9, '\\$1')) + ']+|[' + charlist + ']+$', 'g'), ''); } function basename(s) { var lastChar = s.charAt(s.length-1); if ('/' === lastChar || '\\' === lastChar) { s = s.slice(0, -1); } return s.split(DS_RE).pop(); } function dirname(s) { var lastChar = s.charAt(s.length-1); if ('/' === lastChar || '\\' === lastChar) { s = s.slice(0, -1); } return s.replace(BASENAME_RE, ''); } function pad(s, len, ch) { var sp = s.toString(), n = len-sp.length; return n > 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<sal; ++i) { tmp = strArr[i].split('='); key = rawurldecode(trim(tmp[0])); value = (tmp.length < 2) ? '' : rawurldecode(trim(tmp[1])); j = key.indexOf('\x00'); if (j > -1) key = key.slice(0, j); if (key && '[' !== key.charAt(0)) { keys = []; postLeftBracketPos = 0; for (j=0; j<key.length; ++j) { if ('[' === key.charAt(j) && !postLeftBracketPos) { postLeftBracketPos = j + 1; } else if (']' === key.charAt(j)) { if (postLeftBracketPos) { if (!keys.length) { keys.push(key.slice(0, postLeftBracketPos - 1)); } keys.push(key.substr(postLeftBracketPos, j - postLeftBracketPos)); postLeftBracketPos = 0; if ('[' !== key.charAt(j + 1)) break; } } } if (!keys.length) keys = [key]; for (j=0; j<keys[0].length; ++j) { chr = keys[0].charAt(j); if (' ' === chr || '.' === chr || '[' === chr) { keys[0] = keys[0].substr(0, j) + '_' + keys[0].substr(j + 1); } if ('[' === chr) break; } obj = array; key = null; lastObj = obj; lastkey = keys.length ? trim(keys[keys.length-1].replace(/^['"]|['"]$/g, '')) : null; for (j=0, keysLen=keys.length; j<keysLen; ++j) { prevkey = key; key = keys[ j ].replace(/^['"]|['"]$/g, ''); prevobj = lastObj; lastObj = obj; if ('' !== trim(key) || 0 === j) { if (!HAS.call(obj, key)) obj[key] = (j+1 === keysLen-1) && (''===lastkey) ? [] : {}; obj = obj[key]; } else { // To insert new dimension /*ct = -1; for ( p in obj ) { if ( HAS.call(obj,p) ) { if ( +p > 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<l; ++i) { f = format.charAt(i); formatted_datetime += HAS.call(D, f) ? D[f] : f; } return formatted_datetime; } function pad_(s, n, c, right) { if (null == c) c = ' '; var str = String(s), l = str.length, p = l < n ? new Array(n-l+1).join(c) : ''; return !!right ? str+p : p+str; } function justify(value, prefix, leftJustify, minWidth, zeroPad, customPadChar) { var sv = String(value), diff = minWidth - sv.length; if (diff > 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; });