mirror of
				https://github.com/ls125781003/tvboxtg.git
				synced 2025-10-31 05:42:18 +00:00 
			
		
		
		
	4.9
up
This commit is contained in:
		
							
								
								
									
										577
									
								
								小米/api/jinja.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										577
									
								
								小米/api/jinja.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,577 @@ | ||||
| /*! | ||||
|  * Jinja Templating for JavaScript v0.1.8 | ||||
|  * https://github.com/sstur/jinja-js | ||||
|  * | ||||
|  * This is a slimmed-down Jinja2 implementation [http://jinja.pocoo.org/] | ||||
|  * | ||||
|  * In the interest of simplicity, it deviates from Jinja2 as follows: | ||||
|  * - Line statements, cycle, super, macro tags and block nesting are not implemented | ||||
|  * - auto escapes html by default (the filter is "html" not "e") | ||||
|  * - Only "html" and "safe" filters are built in | ||||
|  * - Filters are not valid in expressions; `foo|length > 1` is not valid | ||||
|  * - Expression Tests (`if num is odd`) not implemented (`is` translates to `==` and `isnot` to `!=`) | ||||
|  * | ||||
|  * Notes: | ||||
|  * - if property is not found, but method '_get' exists, it will be called with the property name (and cached) | ||||
|  * - `{% for n in obj %}` iterates the object's keys; get the value with `{% for n in obj %}{{ obj[n] }}{% endfor %}` | ||||
|  * - subscript notation `a[0]` takes literals or simple variables but not `a[item.key]` | ||||
|  * - `.2` is not a valid number literal; use `0.2` | ||||
|  * | ||||
|  */ | ||||
| /*global require, exports, module, define */ | ||||
|  | ||||
| (function (global, factory) { | ||||
|     typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||||
|         typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||||
|             (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jinja = {})); | ||||
| })(this, (function (jinja) { | ||||
|     "use strict"; | ||||
|     var STRINGS = /'(\\.|[^'])*'|"(\\.|[^"'"])*"/g; | ||||
|     var IDENTS_AND_NUMS = /([$_a-z][$\w]*)|([+-]?\d+(\.\d+)?)/g; | ||||
|     var NUMBER = /^[+-]?\d+(\.\d+)?$/; | ||||
|     //non-primitive literals (array and object literals) | ||||
|     var NON_PRIMITIVES = /\[[@#~](,[@#~])*\]|\[\]|\{([@i]:[@#~])(,[@i]:[@#~])*\}|\{\}/g; | ||||
|     //bare identifiers such as variables and in object literals: {foo: 'value'} | ||||
|     var IDENTIFIERS = /[$_a-z][$\w]*/ig; | ||||
|     var VARIABLES = /i(\.i|\[[@#i]\])*/g; | ||||
|     var ACCESSOR = /(\.i|\[[@#i]\])/g; | ||||
|     var OPERATORS = /(===?|!==?|>=?|<=?|&&|\|\||[+\-\*\/%])/g; | ||||
|     //extended (english) operators | ||||
|     var EOPS = /(^|[^$\w])(and|or|not|is|isnot)([^$\w]|$)/g; | ||||
|     var LEADING_SPACE = /^\s+/; | ||||
|     var TRAILING_SPACE = /\s+$/; | ||||
|  | ||||
|     var START_TOKEN = /\{\{\{|\{\{|\{%|\{#/; | ||||
|     var TAGS = { | ||||
|         '{{{': /^('(\\.|[^'])*'|"(\\.|[^"'"])*"|.)+?\}\}\}/, | ||||
|         '{{': /^('(\\.|[^'])*'|"(\\.|[^"'"])*"|.)+?\}\}/, | ||||
|         '{%': /^('(\\.|[^'])*'|"(\\.|[^"'"])*"|.)+?%\}/, | ||||
|         '{#': /^('(\\.|[^'])*'|"(\\.|[^"'"])*"|.)+?#\}/ | ||||
|     }; | ||||
|  | ||||
|     var delimeters = { | ||||
|         '{%': 'directive', | ||||
|         '{{': 'output', | ||||
|         '{#': 'comment' | ||||
|     }; | ||||
|  | ||||
|     var operators = { | ||||
|         and: '&&', | ||||
|         or: '||', | ||||
|         not: '!', | ||||
|         is: '==', | ||||
|         isnot: '!=' | ||||
|     }; | ||||
|  | ||||
|     var constants = { | ||||
|         'true': true, | ||||
|         'false': false, | ||||
|         'null': null | ||||
|     }; | ||||
|  | ||||
|     function Parser() { | ||||
|         this.nest = []; | ||||
|         this.compiled = []; | ||||
|         this.childBlocks = 0; | ||||
|         this.parentBlocks = 0; | ||||
|         this.isSilent = false; | ||||
|     } | ||||
|  | ||||
|     Parser.prototype.push = function (line) { | ||||
|         if (!this.isSilent) { | ||||
|             this.compiled.push(line); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.parse = function (src) { | ||||
|         this.tokenize(src); | ||||
|         return this.compiled; | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.tokenize = function (src) { | ||||
|         var lastEnd = 0, parser = this, trimLeading = false; | ||||
|         matchAll(src, START_TOKEN, function (open, index, src) { | ||||
|             //here we match the rest of the src against a regex for this tag | ||||
|             var match = src.slice(index + open.length).match(TAGS[open]); | ||||
|             match = (match ? match[0] : ''); | ||||
|             //here we sub out strings so we don't get false matches | ||||
|             var simplified = match.replace(STRINGS, '@'); | ||||
|             //if we don't have a close tag or there is a nested open tag | ||||
|             if (!match || ~simplified.indexOf(open)) { | ||||
|                 return index + 1; | ||||
|             } | ||||
|             var inner = match.slice(0, 0 - open.length); | ||||
|             //check for white-space collapse syntax | ||||
|             if (inner.charAt(0) === '-') var wsCollapseLeft = true; | ||||
|             if (inner.slice(-1) === '-') var wsCollapseRight = true; | ||||
|             inner = inner.replace(/^-|-$/g, '').trim(); | ||||
|             //if we're in raw mode and we are not looking at an "endraw" tag, move along | ||||
|             if (parser.rawMode && (open + inner) !== '{%endraw') { | ||||
|                 return index + 1; | ||||
|             } | ||||
|             var text = src.slice(lastEnd, index); | ||||
|             lastEnd = index + open.length + match.length; | ||||
|             if (trimLeading) text = trimLeft(text); | ||||
|             if (wsCollapseLeft) text = trimRight(text); | ||||
|             if (wsCollapseRight) trimLeading = true; | ||||
|             if (open === '{{{') { | ||||
|                 //liquid-style: make {{{x}}} => {{x|safe}} | ||||
|                 open = '{{'; | ||||
|                 inner += '|safe'; | ||||
|             } | ||||
|             parser.textHandler(text); | ||||
|             parser.tokenHandler(open, inner); | ||||
|         }); | ||||
|         var text = src.slice(lastEnd); | ||||
|         if (trimLeading) text = trimLeft(text); | ||||
|         this.textHandler(text); | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.textHandler = function (text) { | ||||
|         this.push('write(' + JSON.stringify(text) + ');'); | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.tokenHandler = function (open, inner) { | ||||
|         var type = delimeters[open]; | ||||
|         if (type === 'directive') { | ||||
|             this.compileTag(inner); | ||||
|         } else if (type === 'output') { | ||||
|             var extracted = this.extractEnt(inner, STRINGS, '@'); | ||||
|             //replace || operators with ~ | ||||
|             extracted.src = extracted.src.replace(/\|\|/g, '~').split('|'); | ||||
|             //put back || operators | ||||
|             extracted.src = extracted.src.map(function (part) { | ||||
|                 return part.split('~').join('||'); | ||||
|             }); | ||||
|             var parts = this.injectEnt(extracted, '@'); | ||||
|             if (parts.length > 1) { | ||||
|                 var filters = parts.slice(1).map(this.parseFilter.bind(this)); | ||||
|                 this.push('filter(' + this.parseExpr(parts[0]) + ',' + filters.join(',') + ');'); | ||||
|             } else { | ||||
|                 this.push('filter(' + this.parseExpr(parts[0]) + ');'); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.compileTag = function (str) { | ||||
|         var directive = str.split(' ')[0]; | ||||
|         var handler = tagHandlers[directive]; | ||||
|         if (!handler) { | ||||
|             throw new Error('Invalid tag: ' + str); | ||||
|         } | ||||
|         handler.call(this, str.slice(directive.length).trim()); | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.parseFilter = function (src) { | ||||
|         src = src.trim(); | ||||
|         var match = src.match(/[:(]/); | ||||
|         var i = match ? match.index : -1; | ||||
|         if (i < 0) return JSON.stringify([src]); | ||||
|         var name = src.slice(0, i); | ||||
|         var args = src.charAt(i) === ':' ? src.slice(i + 1) : src.slice(i + 1, -1); | ||||
|         args = this.parseExpr(args, {terms: true}); | ||||
|         return '[' + JSON.stringify(name) + ',' + args + ']'; | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.extractEnt = function (src, regex, placeholder) { | ||||
|         var subs = [], isFunc = typeof placeholder == 'function'; | ||||
|         src = src.replace(regex, function (str) { | ||||
|             var replacement = isFunc ? placeholder(str) : placeholder; | ||||
|             if (replacement) { | ||||
|                 subs.push(str); | ||||
|                 return replacement; | ||||
|             } | ||||
|             return str; | ||||
|         }); | ||||
|         return {src: src, subs: subs}; | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.injectEnt = function (extracted, placeholder) { | ||||
|         var src = extracted.src, subs = extracted.subs, isArr = Array.isArray(src); | ||||
|         var arr = (isArr) ? src : [src]; | ||||
|         var re = new RegExp('[' + placeholder + ']', 'g'), i = 0; | ||||
|         arr.forEach(function (src, index) { | ||||
|             arr[index] = src.replace(re, function () { | ||||
|                 return subs[i++]; | ||||
|             }); | ||||
|         }); | ||||
|         return isArr ? arr : arr[0]; | ||||
|     }; | ||||
|  | ||||
|     //replace complex literals without mistaking subscript notation with array literals | ||||
|     Parser.prototype.replaceComplex = function (s) { | ||||
|         var parsed = this.extractEnt(s, /i(\.i|\[[@#i]\])+/g, 'v'); | ||||
|         parsed.src = parsed.src.replace(NON_PRIMITIVES, '~'); | ||||
|         return this.injectEnt(parsed, 'v'); | ||||
|     }; | ||||
|  | ||||
|     //parse expression containing literals (including objects/arrays) and variables (including dot and subscript notation) | ||||
|     //valid expressions: `a + 1 > b.c or c == null`, `a and b[1] != c`, `(a < b) or (c < d and e)`, 'a || [1]` | ||||
|     Parser.prototype.parseExpr = function (src, opts) { | ||||
|         opts = opts || {}; | ||||
|         //extract string literals -> @ | ||||
|         var parsed1 = this.extractEnt(src, STRINGS, '@'); | ||||
|         //note: this will catch {not: 1} and a.is; could we replace temporarily and then check adjacent chars? | ||||
|         parsed1.src = parsed1.src.replace(EOPS, function (s, before, op, after) { | ||||
|             return (op in operators) ? before + operators[op] + after : s; | ||||
|         }); | ||||
|         //sub out non-string literals (numbers/true/false/null) -> # | ||||
|         // the distinction is necessary because @ can be object identifiers, # cannot | ||||
|         var parsed2 = this.extractEnt(parsed1.src, IDENTS_AND_NUMS, function (s) { | ||||
|             return (s in constants || NUMBER.test(s)) ? '#' : null; | ||||
|         }); | ||||
|         //sub out object/variable identifiers -> i | ||||
|         var parsed3 = this.extractEnt(parsed2.src, IDENTIFIERS, 'i'); | ||||
|         //remove white-space | ||||
|         parsed3.src = parsed3.src.replace(/\s+/g, ''); | ||||
|  | ||||
|         //the rest of this is simply to boil the expression down and check validity | ||||
|         var simplified = parsed3.src; | ||||
|         //sub out complex literals (objects/arrays) -> ~ | ||||
|         // the distinction is necessary because @ and # can be subscripts but ~ cannot | ||||
|         while (simplified !== (simplified = this.replaceComplex(simplified))) ; | ||||
|         //now @ represents strings, # represents other primitives and ~ represents non-primitives | ||||
|         //replace complex variables (those with dot/subscript accessors) -> v | ||||
|         while (simplified !== (simplified = simplified.replace(/i(\.i|\[[@#i]\])+/, 'v'))) ; | ||||
|         //empty subscript or complex variables in subscript, are not permitted | ||||
|         simplified = simplified.replace(/[iv]\[v?\]/g, 'x'); | ||||
|         //sub in "i" for @ and # and ~ and v (now "i" represents all literals, variables and identifiers) | ||||
|         simplified = simplified.replace(/[@#~v]/g, 'i'); | ||||
|         //sub out operators | ||||
|         simplified = simplified.replace(OPERATORS, '%'); | ||||
|         //allow 'not' unary operator | ||||
|         simplified = simplified.replace(/!+[i]/g, 'i'); | ||||
|         var terms = opts.terms ? simplified.split(',') : [simplified]; | ||||
|         terms.forEach(function (term) { | ||||
|             //simplify logical grouping | ||||
|             while (term !== (term = term.replace(/\(i(%i)*\)/g, 'i'))) ; | ||||
|             if (!term.match(/^i(%i)*/)) { | ||||
|                 throw new Error('Invalid expression: ' + src + " " + term); | ||||
|             } | ||||
|         }); | ||||
|         parsed3.src = parsed3.src.replace(VARIABLES, this.parseVar.bind(this)); | ||||
|         parsed2.src = this.injectEnt(parsed3, 'i'); | ||||
|         parsed1.src = this.injectEnt(parsed2, '#'); | ||||
|         return this.injectEnt(parsed1, '@'); | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.parseVar = function (src) { | ||||
|         var args = Array.prototype.slice.call(arguments); | ||||
|         var str = args.pop(), index = args.pop(); | ||||
|         //quote bare object identifiers (might be a reserved word like {while: 1}) | ||||
|         if (src === 'i' && str.charAt(index + 1) === ':') { | ||||
|             return '"i"'; | ||||
|         } | ||||
|         var parts = ['"i"']; | ||||
|         src.replace(ACCESSOR, function (part) { | ||||
|             if (part === '.i') { | ||||
|                 parts.push('"i"'); | ||||
|             } else if (part === '[i]') { | ||||
|                 parts.push('get("i")'); | ||||
|             } else { | ||||
|                 parts.push(part.slice(1, -1)); | ||||
|             } | ||||
|         }); | ||||
|         return 'get(' + parts.join(',') + ')'; | ||||
|     }; | ||||
|  | ||||
|     //escapes a name to be used as a javascript identifier | ||||
|     Parser.prototype.escName = function (str) { | ||||
|         return str.replace(/\W/g, function (s) { | ||||
|             return '$' + s.charCodeAt(0).toString(16); | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
|     Parser.prototype.parseQuoted = function (str) { | ||||
|         if (str.charAt(0) === "'") { | ||||
|             str = str.slice(1, -1).replace(/\\.|"/, function (s) { | ||||
|                 if (s === "\\'") return "'"; | ||||
|                 return s.charAt(0) === '\\' ? s : ('\\' + s); | ||||
|             }); | ||||
|             str = '"' + str + '"'; | ||||
|         } | ||||
|         //todo: try/catch or deal with invalid characters (linebreaks, control characters) | ||||
|         return JSON.parse(str); | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     //the context 'this' inside tagHandlers is the parser instance | ||||
|     var tagHandlers = { | ||||
|         'if': function (expr) { | ||||
|             this.push('if (' + this.parseExpr(expr) + ') {'); | ||||
|             this.nest.unshift('if'); | ||||
|         }, | ||||
|         'else': function () { | ||||
|             if (this.nest[0] === 'for') { | ||||
|                 this.push('}, function() {'); | ||||
|             } else { | ||||
|                 this.push('} else {'); | ||||
|             } | ||||
|         }, | ||||
|         'elseif': function (expr) { | ||||
|             this.push('} else if (' + this.parseExpr(expr) + ') {'); | ||||
|         }, | ||||
|         'endif': function () { | ||||
|             this.nest.shift(); | ||||
|             this.push('}'); | ||||
|         }, | ||||
|         'for': function (str) { | ||||
|             var i = str.indexOf(' in '); | ||||
|             var name = str.slice(0, i).trim(); | ||||
|             var expr = str.slice(i + 4).trim(); | ||||
|             this.push('each(' + this.parseExpr(expr) + ',' + JSON.stringify(name) + ',function() {'); | ||||
|             this.nest.unshift('for'); | ||||
|         }, | ||||
|         'endfor': function () { | ||||
|             this.nest.shift(); | ||||
|             this.push('});'); | ||||
|         }, | ||||
|         'raw': function () { | ||||
|             this.rawMode = true; | ||||
|         }, | ||||
|         'endraw': function () { | ||||
|             this.rawMode = false; | ||||
|         }, | ||||
|         'set': function (stmt) { | ||||
|             var i = stmt.indexOf('='); | ||||
|             var name = stmt.slice(0, i).trim(); | ||||
|             var expr = stmt.slice(i + 1).trim(); | ||||
|             this.push('set(' + JSON.stringify(name) + ',' + this.parseExpr(expr) + ');'); | ||||
|         }, | ||||
|         'block': function (name) { | ||||
|             if (this.isParent) { | ||||
|                 ++this.parentBlocks; | ||||
|                 var blockName = 'block_' + (this.escName(name) || this.parentBlocks); | ||||
|                 this.push('block(typeof ' + blockName + ' == "function" ? ' + blockName + ' : function() {'); | ||||
|             } else if (this.hasParent) { | ||||
|                 this.isSilent = false; | ||||
|                 ++this.childBlocks; | ||||
|                 blockName = 'block_' + (this.escName(name) || this.childBlocks); | ||||
|                 this.push('function ' + blockName + '() {'); | ||||
|             } | ||||
|             this.nest.unshift('block'); | ||||
|         }, | ||||
|         'endblock': function () { | ||||
|             this.nest.shift(); | ||||
|             if (this.isParent) { | ||||
|                 this.push('});'); | ||||
|             } else if (this.hasParent) { | ||||
|                 this.push('}'); | ||||
|                 this.isSilent = true; | ||||
|             } | ||||
|         }, | ||||
|         'extends': function (name) { | ||||
|             name = this.parseQuoted(name); | ||||
|             var parentSrc = this.readTemplateFile(name); | ||||
|             this.isParent = true; | ||||
|             this.tokenize(parentSrc); | ||||
|             this.isParent = false; | ||||
|             this.hasParent = true; | ||||
|             //silence output until we enter a child block | ||||
|             this.isSilent = true; | ||||
|         }, | ||||
|         'include': function (name) { | ||||
|             name = this.parseQuoted(name); | ||||
|             var incSrc = this.readTemplateFile(name); | ||||
|             this.isInclude = true; | ||||
|             this.tokenize(incSrc); | ||||
|             this.isInclude = false; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     //liquid style | ||||
|     tagHandlers.assign = tagHandlers.set; | ||||
|     //python/django style | ||||
|     tagHandlers.elif = tagHandlers.elseif; | ||||
|  | ||||
|     var getRuntime = function runtime(data, opts) { | ||||
|         var defaults = {autoEscape: 'toJson'}; | ||||
|         var _toString = Object.prototype.toString; | ||||
|         var _hasOwnProperty = Object.prototype.hasOwnProperty; | ||||
|         var getKeys = Object.keys || function (obj) { | ||||
|             var keys = []; | ||||
|             for (var n in obj) if (_hasOwnProperty.call(obj, n)) keys.push(n); | ||||
|             return keys; | ||||
|         }; | ||||
|         var isArray = Array.isArray || function (obj) { | ||||
|             return _toString.call(obj) === '[object Array]'; | ||||
|         }; | ||||
|         var create = Object.create || function (obj) { | ||||
|             function F() { | ||||
|             } | ||||
|  | ||||
|             F.prototype = obj; | ||||
|             return new F(); | ||||
|         }; | ||||
|         var toString = function (val) { | ||||
|             if (val == null) return ''; | ||||
|             return (typeof val.toString == 'function') ? val.toString() : _toString.call(val); | ||||
|         }; | ||||
|         var extend = function (dest, src) { | ||||
|             var keys = getKeys(src); | ||||
|             for (var i = 0, len = keys.length; i < len; i++) { | ||||
|                 var key = keys[i]; | ||||
|                 dest[key] = src[key]; | ||||
|             } | ||||
|             return dest; | ||||
|         }; | ||||
|         //get a value, lexically, starting in current context; a.b -> get("a","b") | ||||
|         var get = function () { | ||||
|             var val, n = arguments[0], c = stack.length; | ||||
|             while (c--) { | ||||
|                 val = stack[c][n]; | ||||
|                 if (typeof val != 'undefined') break; | ||||
|             } | ||||
|             for (var i = 1, len = arguments.length; i < len; i++) { | ||||
|                 if (val == null) continue; | ||||
|                 n = arguments[i]; | ||||
|                 val = (_hasOwnProperty.call(val, n)) ? val[n] : (typeof val._get == 'function' ? (val[n] = val._get(n)) : null); | ||||
|             } | ||||
|             return (val == null) ? '' : val; | ||||
|         }; | ||||
|         var set = function (n, val) { | ||||
|             stack[stack.length - 1][n] = val; | ||||
|         }; | ||||
|         var push = function (ctx) { | ||||
|             stack.push(ctx || {}); | ||||
|         }; | ||||
|         var pop = function () { | ||||
|             stack.pop(); | ||||
|         }; | ||||
|         var write = function (str) { | ||||
|             output.push(str); | ||||
|         }; | ||||
|         var filter = function (val) { | ||||
|             for (var i = 1, len = arguments.length; i < len; i++) { | ||||
|                 var arr = arguments[i], name = arr[0], filter = filters[name]; | ||||
|                 if (filter) { | ||||
|                     arr[0] = val; | ||||
|                     //now arr looks like [val, arg1, arg2] | ||||
|                     val = filter.apply(data, arr); | ||||
|                 } else { | ||||
|                     throw new Error('Invalid filter: ' + name); | ||||
|                 } | ||||
|             } | ||||
|             if (opts.autoEscape && name !== opts.autoEscape && name !== 'safe') { | ||||
|                 //auto escape if not explicitly safe or already escaped | ||||
|                 val = filters[opts.autoEscape].call(data, val); | ||||
|             } | ||||
|             output.push(val); | ||||
|         }; | ||||
|         var each = function (obj, loopvar, fn1, fn2) { | ||||
|             if (obj == null) return; | ||||
|             var arr = isArray(obj) ? obj : getKeys(obj), len = arr.length; | ||||
|             var ctx = {loop: {length: len, first: arr[0], last: arr[len - 1]}}; | ||||
|             push(ctx); | ||||
|             for (var i = 0; i < len; i++) { | ||||
|                 extend(ctx.loop, {index: i + 1, index0: i}); | ||||
|                 fn1(ctx[loopvar] = arr[i]); | ||||
|             } | ||||
|             if (len === 0 && fn2) fn2(); | ||||
|             pop(); | ||||
|         }; | ||||
|         var block = function (fn) { | ||||
|             push(); | ||||
|             fn(); | ||||
|             pop(); | ||||
|         }; | ||||
|         var render = function () { | ||||
|             return output.join(''); | ||||
|         }; | ||||
|         data = data || {}; | ||||
|         opts = extend(defaults, opts || {}); | ||||
|         var filters = extend({ | ||||
|             html: function (val) { | ||||
|                 return toString(val) | ||||
|                     .split('&').join('&') | ||||
|                     .split('<').join('<') | ||||
|                     .split('>').join('>') | ||||
|                     .split('"').join('"'); | ||||
|             }, | ||||
|             safe: function (val) { | ||||
|                 return val; | ||||
|             }, | ||||
|             toJson: function (val) { | ||||
|                 if (typeof val === 'object') { | ||||
|                     return JSON.stringify(val); | ||||
|                 } | ||||
|                 return toString(val); | ||||
|             } | ||||
|         }, opts.filters || {}); | ||||
|         var stack = [create(data || {})], output = []; | ||||
|         return { | ||||
|             get: get, | ||||
|             set: set, | ||||
|             push: push, | ||||
|             pop: pop, | ||||
|             write: write, | ||||
|             filter: filter, | ||||
|             each: each, | ||||
|             block: block, | ||||
|             render: render | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     var runtime; | ||||
|  | ||||
|     jinja.compile = function (markup, opts) { | ||||
|         opts = opts || {}; | ||||
|         var parser = new Parser(); | ||||
|         parser.readTemplateFile = this.readTemplateFile; | ||||
|         var code = []; | ||||
|         code.push('function render($) {'); | ||||
|         code.push('var get = $.get, set = $.set, push = $.push, pop = $.pop, write = $.write, filter = $.filter, each = $.each, block = $.block;'); | ||||
|         code.push.apply(code, parser.parse(markup)); | ||||
|         code.push('return $.render();'); | ||||
|         code.push('}'); | ||||
|         code = code.join('\n'); | ||||
|         if (opts.runtime === false) { | ||||
|             var fn = new Function('data', 'options', 'return (' + code + ')(runtime(data, options))'); | ||||
|         } else { | ||||
|             runtime = runtime || (runtime = getRuntime.toString()); | ||||
|             fn = new Function('data', 'options', 'return (' + code + ')((' + runtime + ')(data, options))'); | ||||
|         } | ||||
|         return {render: fn}; | ||||
|     }; | ||||
|  | ||||
|     jinja.render = function (markup, data, opts) { | ||||
|         var tmpl = jinja.compile(markup); | ||||
|         return tmpl.render(data, opts); | ||||
|     }; | ||||
|  | ||||
|     jinja.templateFiles = []; | ||||
|  | ||||
|     jinja.readTemplateFile = function (name) { | ||||
|         var templateFiles = this.templateFiles || []; | ||||
|         var templateFile = templateFiles[name]; | ||||
|         if (templateFile == null) { | ||||
|             throw new Error('Template file not found: ' + name); | ||||
|         } | ||||
|         return templateFile; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     /*! | ||||
|      * Helpers | ||||
|      */ | ||||
|  | ||||
|     function trimLeft(str) { | ||||
|         return str.replace(LEADING_SPACE, ''); | ||||
|     } | ||||
|  | ||||
|     function trimRight(str) { | ||||
|         return str.replace(TRAILING_SPACE, ''); | ||||
|     } | ||||
|  | ||||
|     function matchAll(str, reg, fn) { | ||||
|         //copy as global | ||||
|         reg = new RegExp(reg.source, 'g' + (reg.ignoreCase ? 'i' : '') + (reg.multiline ? 'm' : '')); | ||||
|         var match; | ||||
|         while ((match = reg.exec(str))) { | ||||
|             var result = fn(match[0], match.index, str); | ||||
|             if (typeof result == 'number') { | ||||
|                 reg.lastIndex = result; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| })); | ||||
		Reference in New Issue
	
	Block a user