| (function() { |
| /* |
| |
| Copyright (C) 2011 by Yehuda Katz |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| THE SOFTWARE. |
| |
| */ |
| |
| // lib/handlebars/browser-prefix.js |
| var Handlebars = {}; |
| |
| (function(Handlebars, undefined) {; |
| // lib/handlebars/base.js |
| |
| Handlebars.VERSION = "1.0.0-rc.3"; |
| Handlebars.COMPILER_REVISION = 2; |
| |
| Handlebars.REVISION_CHANGES = { |
| 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it |
| 2: '>= 1.0.0-rc.3' |
| }; |
| |
| Handlebars.helpers = {}; |
| Handlebars.partials = {}; |
| |
| Handlebars.registerHelper = function(name, fn, inverse) { |
| if (inverse) { |
| fn.not = inverse; |
| } |
| this.helpers[name] = fn; |
| }; |
| |
| Handlebars.registerPartial = function(name, str) { |
| this.partials[name] = str; |
| }; |
| |
| Handlebars.registerHelper('helperMissing', function(arg) { |
| if (arguments.length === 2) { |
| return undefined; |
| } else { |
| throw new Error("Could not find property '" + arg + "'"); |
| } |
| }); |
| |
| var toString = Object.prototype.toString, |
| functionType = "[object Function]"; |
| |
| Handlebars.registerHelper('blockHelperMissing', function(context, options) { |
| var inverse = options.inverse || function() {}, |
| fn = options.fn; |
| |
| var type = toString.call(context); |
| |
| if (type === functionType) { |
| context = context.call(this); |
| } |
| |
| if (context === true) { |
| return fn(this); |
| } else if (context === false || context == null) { |
| return inverse(this); |
| } else if (type === "[object Array]") { |
| if (context.length > 0) { |
| return Handlebars.helpers.each(context, options); |
| } else { |
| return inverse(this); |
| } |
| } else { |
| return fn(context); |
| } |
| }); |
| |
| Handlebars.K = function() {}; |
| |
| Handlebars.createFrame = Object.create || function(object) { |
| Handlebars.K.prototype = object; |
| var obj = new Handlebars.K(); |
| Handlebars.K.prototype = null; |
| return obj; |
| }; |
| |
| Handlebars.logger = { |
| DEBUG: 0, |
| INFO: 1, |
| WARN: 2, |
| ERROR: 3, |
| level: 3, |
| |
| methodMap: { |
| 0: 'debug', |
| 1: 'info', |
| 2: 'warn', |
| 3: 'error' |
| }, |
| |
| // can be overridden in the host environment |
| log: function(level, obj) { |
| if (Handlebars.logger.level <= level) { |
| var method = Handlebars.logger.methodMap[level]; |
| if (typeof console !== 'undefined' && console[method]) { |
| console[method].call(console, obj); |
| } |
| } |
| } |
| }; |
| |
| Handlebars.log = function(level, obj) { |
| Handlebars.logger.log(level, obj); |
| }; |
| |
| Handlebars.registerHelper('each', function(context, options) { |
| var fn = options.fn, |
| inverse = options.inverse; |
| var i = 0, |
| ret = "", |
| data; |
| |
| if (options.data) { |
| data = Handlebars.createFrame(options.data); |
| } |
| |
| if (context && typeof context === 'object') { |
| if (context instanceof Array) { |
| for (var j = context.length; i < j; i++) { |
| if (data) { |
| data.index = i; |
| } |
| ret = ret + fn(context[i], { |
| data: data |
| }); |
| } |
| } else { |
| for (var key in context) { |
| if (context.hasOwnProperty(key)) { |
| if (data) { |
| data.key = key; |
| } |
| ret = ret + fn(context[key], { |
| data: data |
| }); |
| i++; |
| } |
| } |
| } |
| } |
| |
| if (i === 0) { |
| ret = inverse(this); |
| } |
| |
| return ret; |
| }); |
| |
| Handlebars.registerHelper('if', function(context, options) { |
| var type = toString.call(context); |
| if (type === functionType) { |
| context = context.call(this); |
| } |
| |
| if (!context || Handlebars.Utils.isEmpty(context)) { |
| return options.inverse(this); |
| } else { |
| return options.fn(this); |
| } |
| }); |
| |
| Handlebars.registerHelper('unless', function(context, options) { |
| return Handlebars.helpers['if'].call(this, context, { |
| fn: options.inverse, |
| inverse: options.fn |
| }); |
| }); |
| |
| Handlebars.registerHelper('with', function(context, options) { |
| return options.fn(context); |
| }); |
| |
| Handlebars.registerHelper('log', function(context, options) { |
| var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; |
| Handlebars.log(level, context); |
| });; |
| }(Handlebars));; |
| //>>excludeStart('excludeHbsParser', pragmas.excludeHbsParser) |
| // lib/handlebars/compiler/parser.js |
| /* Jison generated parser */ |
| var handlebars = (function() { |
| var parser = { |
| trace: function trace() {}, |
| yy: {}, |
| symbols_: { |
| "error": 2, |
| "root": 3, |
| "program": 4, |
| "EOF": 5, |
| "simpleInverse": 6, |
| "statements": 7, |
| "statement": 8, |
| "openInverse": 9, |
| "closeBlock": 10, |
| "openBlock": 11, |
| "mustache": 12, |
| "partial": 13, |
| "CONTENT": 14, |
| "COMMENT": 15, |
| "OPEN_BLOCK": 16, |
| "inMustache": 17, |
| "CLOSE": 18, |
| "OPEN_INVERSE": 19, |
| "OPEN_ENDBLOCK": 20, |
| "path": 21, |
| "OPEN": 22, |
| "OPEN_UNESCAPED": 23, |
| "OPEN_PARTIAL": 24, |
| "partialName": 25, |
| "params": 26, |
| "hash": 27, |
| "DATA": 28, |
| "param": 29, |
| "STRING": 30, |
| "INTEGER": 31, |
| "BOOLEAN": 32, |
| "hashSegments": 33, |
| "hashSegment": 34, |
| "ID": 35, |
| "EQUALS": 36, |
| "PARTIAL_NAME": 37, |
| "pathSegments": 38, |
| "SEP": 39, |
| "$accept": 0, |
| "$end": 1 |
| }, |
| terminals_: { |
| 2: "error", |
| 5: "EOF", |
| 14: "CONTENT", |
| 15: "COMMENT", |
| 16: "OPEN_BLOCK", |
| 18: "CLOSE", |
| 19: "OPEN_INVERSE", |
| 20: "OPEN_ENDBLOCK", |
| 22: "OPEN", |
| 23: "OPEN_UNESCAPED", |
| 24: "OPEN_PARTIAL", |
| 28: "DATA", |
| 30: "STRING", |
| 31: "INTEGER", |
| 32: "BOOLEAN", |
| 35: "ID", |
| 36: "EQUALS", |
| 37: "PARTIAL_NAME", |
| 39: "SEP" |
| }, |
| productions_: [0, [3, 2], |
| [4, 2], |
| [4, 3], |
| [4, 2], |
| [4, 1], |
| [4, 1], |
| [4, 0], |
| [7, 1], |
| [7, 2], |
| [8, 3], |
| [8, 3], |
| [8, 1], |
| [8, 1], |
| [8, 1], |
| [8, 1], |
| [11, 3], |
| [9, 3], |
| [10, 3], |
| [12, 3], |
| [12, 3], |
| [13, 3], |
| [13, 4], |
| [6, 2], |
| [17, 3], |
| [17, 2], |
| [17, 2], |
| [17, 1], |
| [17, 1], |
| [26, 2], |
| [26, 1], |
| [29, 1], |
| [29, 1], |
| [29, 1], |
| [29, 1], |
| [29, 1], |
| [27, 1], |
| [33, 2], |
| [33, 1], |
| [34, 3], |
| [34, 3], |
| [34, 3], |
| [34, 3], |
| [34, 3], |
| [25, 1], |
| [21, 1], |
| [38, 3], |
| [38, 1] |
| ], |
| performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) { |
| |
| var $0 = $$.length - 1; |
| switch (yystate) { |
| case 1: |
| return $$[$0 - 1]; |
| break; |
| case 2: |
| this.$ = new yy.ProgramNode([], $$[$0]); |
| break; |
| case 3: |
| this.$ = new yy.ProgramNode($$[$0 - 2], $$[$0]); |
| break; |
| case 4: |
| this.$ = new yy.ProgramNode($$[$0 - 1], []); |
| break; |
| case 5: |
| this.$ = new yy.ProgramNode($$[$0]); |
| break; |
| case 6: |
| this.$ = new yy.ProgramNode([], []); |
| break; |
| case 7: |
| this.$ = new yy.ProgramNode([]); |
| break; |
| case 8: |
| this.$ = [$$[$0]]; |
| break; |
| case 9: |
| $$[$0 - 1].push($$[$0]); |
| this.$ = $$[$0 - 1]; |
| break; |
| case 10: |
| this.$ = new yy.BlockNode($$[$0 - 2], $$[$0 - 1].inverse, $$[$0 - 1], $$[$0]); |
| break; |
| case 11: |
| this.$ = new yy.BlockNode($$[$0 - 2], $$[$0 - 1], $$[$0 - 1].inverse, $$[$0]); |
| break; |
| case 12: |
| this.$ = $$[$0]; |
| break; |
| case 13: |
| this.$ = $$[$0]; |
| break; |
| case 14: |
| this.$ = new yy.ContentNode($$[$0]); |
| break; |
| case 15: |
| this.$ = new yy.CommentNode($$[$0]); |
| break; |
| case 16: |
| this.$ = new yy.MustacheNode($$[$0 - 1][0], $$[$0 - 1][1]); |
| break; |
| case 17: |
| this.$ = new yy.MustacheNode($$[$0 - 1][0], $$[$0 - 1][1]); |
| break; |
| case 18: |
| this.$ = $$[$0 - 1]; |
| break; |
| case 19: |
| this.$ = new yy.MustacheNode($$[$0 - 1][0], $$[$0 - 1][1]); |
| break; |
| case 20: |
| this.$ = new yy.MustacheNode($$[$0 - 1][0], $$[$0 - 1][1], true); |
| break; |
| case 21: |
| this.$ = new yy.PartialNode($$[$0 - 1]); |
| break; |
| case 22: |
| this.$ = new yy.PartialNode($$[$0 - 2], $$[$0 - 1]); |
| break; |
| case 23: |
| break; |
| case 24: |
| this.$ = [ |
| [$$[$0 - 2]].concat($$[$0 - 1]), $$[$0] |
| ]; |
| break; |
| case 25: |
| this.$ = [ |
| [$$[$0 - 1]].concat($$[$0]), null |
| ]; |
| break; |
| case 26: |
| this.$ = [ |
| [$$[$0 - 1]], $$[$0] |
| ]; |
| break; |
| case 27: |
| this.$ = [ |
| [$$[$0]], null |
| ]; |
| break; |
| case 28: |
| this.$ = [ |
| [new yy.DataNode($$[$0])], null |
| ]; |
| break; |
| case 29: |
| $$[$0 - 1].push($$[$0]); |
| this.$ = $$[$0 - 1]; |
| break; |
| case 30: |
| this.$ = [$$[$0]]; |
| break; |
| case 31: |
| this.$ = $$[$0]; |
| break; |
| case 32: |
| this.$ = new yy.StringNode($$[$0]); |
| break; |
| case 33: |
| this.$ = new yy.IntegerNode($$[$0]); |
| break; |
| case 34: |
| this.$ = new yy.BooleanNode($$[$0]); |
| break; |
| case 35: |
| this.$ = new yy.DataNode($$[$0]); |
| break; |
| case 36: |
| this.$ = new yy.HashNode($$[$0]); |
| break; |
| case 37: |
| $$[$0 - 1].push($$[$0]); |
| this.$ = $$[$0 - 1]; |
| break; |
| case 38: |
| this.$ = [$$[$0]]; |
| break; |
| case 39: |
| this.$ = [$$[$0 - 2], $$[$0]]; |
| break; |
| case 40: |
| this.$ = [$$[$0 - 2], new yy.StringNode($$[$0])]; |
| break; |
| case 41: |
| this.$ = [$$[$0 - 2], new yy.IntegerNode($$[$0])]; |
| break; |
| case 42: |
| this.$ = [$$[$0 - 2], new yy.BooleanNode($$[$0])]; |
| break; |
| case 43: |
| this.$ = [$$[$0 - 2], new yy.DataNode($$[$0])]; |
| break; |
| case 44: |
| this.$ = new yy.PartialNameNode($$[$0]); |
| break; |
| case 45: |
| this.$ = new yy.IdNode($$[$0]); |
| break; |
| case 46: |
| $$[$0 - 2].push($$[$0]); |
| this.$ = $$[$0 - 2]; |
| break; |
| case 47: |
| this.$ = [$$[$0]]; |
| break; |
| } |
| }, |
| table: [{ |
| 3: 1, |
| 4: 2, |
| 5: [2, 7], |
| 6: 3, |
| 7: 4, |
| 8: 6, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 5], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 1: [3] |
| }, { |
| 5: [1, 17] |
| }, { |
| 5: [2, 6], |
| 7: 18, |
| 8: 6, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 19], |
| 20: [2, 6], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 5: [2, 5], |
| 6: 20, |
| 8: 21, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 5], |
| 20: [2, 5], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 17: 23, |
| 18: [1, 22], |
| 21: 24, |
| 28: [1, 25], |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 5: [2, 8], |
| 14: [2, 8], |
| 15: [2, 8], |
| 16: [2, 8], |
| 19: [2, 8], |
| 20: [2, 8], |
| 22: [2, 8], |
| 23: [2, 8], |
| 24: [2, 8] |
| }, { |
| 4: 28, |
| 6: 3, |
| 7: 4, |
| 8: 6, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 5], |
| 20: [2, 7], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 4: 29, |
| 6: 3, |
| 7: 4, |
| 8: 6, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 5], |
| 20: [2, 7], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 5: [2, 12], |
| 14: [2, 12], |
| 15: [2, 12], |
| 16: [2, 12], |
| 19: [2, 12], |
| 20: [2, 12], |
| 22: [2, 12], |
| 23: [2, 12], |
| 24: [2, 12] |
| }, { |
| 5: [2, 13], |
| 14: [2, 13], |
| 15: [2, 13], |
| 16: [2, 13], |
| 19: [2, 13], |
| 20: [2, 13], |
| 22: [2, 13], |
| 23: [2, 13], |
| 24: [2, 13] |
| }, { |
| 5: [2, 14], |
| 14: [2, 14], |
| 15: [2, 14], |
| 16: [2, 14], |
| 19: [2, 14], |
| 20: [2, 14], |
| 22: [2, 14], |
| 23: [2, 14], |
| 24: [2, 14] |
| }, { |
| 5: [2, 15], |
| 14: [2, 15], |
| 15: [2, 15], |
| 16: [2, 15], |
| 19: [2, 15], |
| 20: [2, 15], |
| 22: [2, 15], |
| 23: [2, 15], |
| 24: [2, 15] |
| }, { |
| 17: 30, |
| 21: 24, |
| 28: [1, 25], |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 17: 31, |
| 21: 24, |
| 28: [1, 25], |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 17: 32, |
| 21: 24, |
| 28: [1, 25], |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 25: 33, |
| 37: [1, 34] |
| }, { |
| 1: [2, 1] |
| }, { |
| 5: [2, 2], |
| 8: 21, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 19], |
| 20: [2, 2], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 17: 23, |
| 21: 24, |
| 28: [1, 25], |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 5: [2, 4], |
| 7: 35, |
| 8: 6, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 19], |
| 20: [2, 4], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 5: [2, 9], |
| 14: [2, 9], |
| 15: [2, 9], |
| 16: [2, 9], |
| 19: [2, 9], |
| 20: [2, 9], |
| 22: [2, 9], |
| 23: [2, 9], |
| 24: [2, 9] |
| }, { |
| 5: [2, 23], |
| 14: [2, 23], |
| 15: [2, 23], |
| 16: [2, 23], |
| 19: [2, 23], |
| 20: [2, 23], |
| 22: [2, 23], |
| 23: [2, 23], |
| 24: [2, 23] |
| }, { |
| 18: [1, 36] |
| }, { |
| 18: [2, 27], |
| 21: 41, |
| 26: 37, |
| 27: 38, |
| 28: [1, 45], |
| 29: 39, |
| 30: [1, 42], |
| 31: [1, 43], |
| 32: [1, 44], |
| 33: 40, |
| 34: 46, |
| 35: [1, 47], |
| 38: 26 |
| }, { |
| 18: [2, 28] |
| }, { |
| 18: [2, 45], |
| 28: [2, 45], |
| 30: [2, 45], |
| 31: [2, 45], |
| 32: [2, 45], |
| 35: [2, 45], |
| 39: [1, 48] |
| }, { |
| 18: [2, 47], |
| 28: [2, 47], |
| 30: [2, 47], |
| 31: [2, 47], |
| 32: [2, 47], |
| 35: [2, 47], |
| 39: [2, 47] |
| }, { |
| 10: 49, |
| 20: [1, 50] |
| }, { |
| 10: 51, |
| 20: [1, 50] |
| }, { |
| 18: [1, 52] |
| }, { |
| 18: [1, 53] |
| }, { |
| 18: [1, 54] |
| }, { |
| 18: [1, 55], |
| 21: 56, |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 18: [2, 44], |
| 35: [2, 44] |
| }, { |
| 5: [2, 3], |
| 8: 21, |
| 9: 7, |
| 11: 8, |
| 12: 9, |
| 13: 10, |
| 14: [1, 11], |
| 15: [1, 12], |
| 16: [1, 13], |
| 19: [1, 19], |
| 20: [2, 3], |
| 22: [1, 14], |
| 23: [1, 15], |
| 24: [1, 16] |
| }, { |
| 14: [2, 17], |
| 15: [2, 17], |
| 16: [2, 17], |
| 19: [2, 17], |
| 20: [2, 17], |
| 22: [2, 17], |
| 23: [2, 17], |
| 24: [2, 17] |
| }, { |
| 18: [2, 25], |
| 21: 41, |
| 27: 57, |
| 28: [1, 45], |
| 29: 58, |
| 30: [1, 42], |
| 31: [1, 43], |
| 32: [1, 44], |
| 33: 40, |
| 34: 46, |
| 35: [1, 47], |
| 38: 26 |
| }, { |
| 18: [2, 26] |
| }, { |
| 18: [2, 30], |
| 28: [2, 30], |
| 30: [2, 30], |
| 31: [2, 30], |
| 32: [2, 30], |
| 35: [2, 30] |
| }, { |
| 18: [2, 36], |
| 34: 59, |
| 35: [1, 60] |
| }, { |
| 18: [2, 31], |
| 28: [2, 31], |
| 30: [2, 31], |
| 31: [2, 31], |
| 32: [2, 31], |
| 35: [2, 31] |
| }, { |
| 18: [2, 32], |
| 28: [2, 32], |
| 30: [2, 32], |
| 31: [2, 32], |
| 32: [2, 32], |
| 35: [2, 32] |
| }, { |
| 18: [2, 33], |
| 28: [2, 33], |
| 30: [2, 33], |
| 31: [2, 33], |
| 32: [2, 33], |
| 35: [2, 33] |
| }, { |
| 18: [2, 34], |
| 28: [2, 34], |
| 30: [2, 34], |
| 31: [2, 34], |
| 32: [2, 34], |
| 35: [2, 34] |
| }, { |
| 18: [2, 35], |
| 28: [2, 35], |
| 30: [2, 35], |
| 31: [2, 35], |
| 32: [2, 35], |
| 35: [2, 35] |
| }, { |
| 18: [2, 38], |
| 35: [2, 38] |
| }, { |
| 18: [2, 47], |
| 28: [2, 47], |
| 30: [2, 47], |
| 31: [2, 47], |
| 32: [2, 47], |
| 35: [2, 47], |
| 36: [1, 61], |
| 39: [2, 47] |
| }, { |
| 35: [1, 62] |
| }, { |
| 5: [2, 10], |
| 14: [2, 10], |
| 15: [2, 10], |
| 16: [2, 10], |
| 19: [2, 10], |
| 20: [2, 10], |
| 22: [2, 10], |
| 23: [2, 10], |
| 24: [2, 10] |
| }, { |
| 21: 63, |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 5: [2, 11], |
| 14: [2, 11], |
| 15: [2, 11], |
| 16: [2, 11], |
| 19: [2, 11], |
| 20: [2, 11], |
| 22: [2, 11], |
| 23: [2, 11], |
| 24: [2, 11] |
| }, { |
| 14: [2, 16], |
| 15: [2, 16], |
| 16: [2, 16], |
| 19: [2, 16], |
| 20: [2, 16], |
| 22: [2, 16], |
| 23: [2, 16], |
| 24: [2, 16] |
| }, { |
| 5: [2, 19], |
| 14: [2, 19], |
| 15: [2, 19], |
| 16: [2, 19], |
| 19: [2, 19], |
| 20: [2, 19], |
| 22: [2, 19], |
| 23: [2, 19], |
| 24: [2, 19] |
| }, { |
| 5: [2, 20], |
| 14: [2, 20], |
| 15: [2, 20], |
| 16: [2, 20], |
| 19: [2, 20], |
| 20: [2, 20], |
| 22: [2, 20], |
| 23: [2, 20], |
| 24: [2, 20] |
| }, { |
| 5: [2, 21], |
| 14: [2, 21], |
| 15: [2, 21], |
| 16: [2, 21], |
| 19: [2, 21], |
| 20: [2, 21], |
| 22: [2, 21], |
| 23: [2, 21], |
| 24: [2, 21] |
| }, { |
| 18: [1, 64] |
| }, { |
| 18: [2, 24] |
| }, { |
| 18: [2, 29], |
| 28: [2, 29], |
| 30: [2, 29], |
| 31: [2, 29], |
| 32: [2, 29], |
| 35: [2, 29] |
| }, { |
| 18: [2, 37], |
| 35: [2, 37] |
| }, { |
| 36: [1, 61] |
| }, { |
| 21: 65, |
| 28: [1, 69], |
| 30: [1, 66], |
| 31: [1, 67], |
| 32: [1, 68], |
| 35: [1, 27], |
| 38: 26 |
| }, { |
| 18: [2, 46], |
| 28: [2, 46], |
| 30: [2, 46], |
| 31: [2, 46], |
| 32: [2, 46], |
| 35: [2, 46], |
| 39: [2, 46] |
| }, { |
| 18: [1, 70] |
| }, { |
| 5: [2, 22], |
| 14: [2, 22], |
| 15: [2, 22], |
| 16: [2, 22], |
| 19: [2, 22], |
| 20: [2, 22], |
| 22: [2, 22], |
| 23: [2, 22], |
| 24: [2, 22] |
| }, { |
| 18: [2, 39], |
| 35: [2, 39] |
| }, { |
| 18: [2, 40], |
| 35: [2, 40] |
| }, { |
| 18: [2, 41], |
| 35: [2, 41] |
| }, { |
| 18: [2, 42], |
| 35: [2, 42] |
| }, { |
| 18: [2, 43], |
| 35: [2, 43] |
| }, { |
| 5: [2, 18], |
| 14: [2, 18], |
| 15: [2, 18], |
| 16: [2, 18], |
| 19: [2, 18], |
| 20: [2, 18], |
| 22: [2, 18], |
| 23: [2, 18], |
| 24: [2, 18] |
| }], |
| defaultActions: { |
| 17: [2, 1], |
| 25: [2, 28], |
| 38: [2, 26], |
| 57: [2, 24] |
| }, |
| parseError: function parseError(str, hash) { |
| throw new Error(str); |
| }, |
| parse: function parse(input) { |
| var self = this, |
| stack = [0], |
| vstack = [null], |
| lstack = [], |
| table = this.table, |
| yytext = "", |
| yylineno = 0, |
| yyleng = 0, |
| recovering = 0, |
| TERROR = 2, |
| EOF = 1; |
| this.lexer.setInput(input); |
| this.lexer.yy = this.yy; |
| this.yy.lexer = this.lexer; |
| this.yy.parser = this; |
| if (typeof this.lexer.yylloc == "undefined") |
| this.lexer.yylloc = {}; |
| var yyloc = this.lexer.yylloc; |
| lstack.push(yyloc); |
| var ranges = this.lexer.options && this.lexer.options.ranges; |
| if (typeof this.yy.parseError === "function") |
| this.parseError = this.yy.parseError; |
| |
| function popStack(n) { |
| stack.length = stack.length - 2 * n; |
| vstack.length = vstack.length - n; |
| lstack.length = lstack.length - n; |
| } |
| |
| function lex() { |
| var token; |
| token = self.lexer.lex() || 1; |
| if (typeof token !== "number") { |
| token = self.symbols_[token] || token; |
| } |
| return token; |
| } |
| var symbol, preErrorSymbol, state, action, a, r, yyval = {}, |
| p, len, newState, expected; |
| while (true) { |
| state = stack[stack.length - 1]; |
| if (this.defaultActions[state]) { |
| action = this.defaultActions[state]; |
| } else { |
| if (symbol === null || typeof symbol == "undefined") { |
| symbol = lex(); |
| } |
| action = table[state] && table[state][symbol]; |
| } |
| if (typeof action === "undefined" || !action.length || !action[0]) { |
| var errStr = ""; |
| if (!recovering) { |
| expected = []; |
| for (p in table[state]) |
| if (this.terminals_[p] && p > 2) { |
| expected.push("'" + this.terminals_[p] + "'"); |
| } |
| if (this.lexer.showPosition) { |
| errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; |
| } else { |
| errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"); |
| } |
| this.parseError(errStr, { |
| text: this.lexer.match, |
| token: this.terminals_[symbol] || symbol, |
| line: this.lexer.yylineno, |
| loc: yyloc, |
| expected: expected |
| }); |
| } |
| } |
| if (action[0] instanceof Array && action.length > 1) { |
| throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); |
| } |
| switch (action[0]) { |
| case 1: |
| stack.push(symbol); |
| vstack.push(this.lexer.yytext); |
| lstack.push(this.lexer.yylloc); |
| stack.push(action[1]); |
| symbol = null; |
| if (!preErrorSymbol) { |
| yyleng = this.lexer.yyleng; |
| yytext = this.lexer.yytext; |
| yylineno = this.lexer.yylineno; |
| yyloc = this.lexer.yylloc; |
| if (recovering > 0) |
| recovering--; |
| } else { |
| symbol = preErrorSymbol; |
| preErrorSymbol = null; |
| } |
| break; |
| case 2: |
| len = this.productions_[action[1]][1]; |
| yyval.$ = vstack[vstack.length - len]; |
| yyval._$ = { |
| first_line: lstack[lstack.length - (len || 1)].first_line, |
| last_line: lstack[lstack.length - 1].last_line, |
| first_column: lstack[lstack.length - (len || 1)].first_column, |
| last_column: lstack[lstack.length - 1].last_column |
| }; |
| if (ranges) { |
| yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; |
| } |
| r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); |
| if (typeof r !== "undefined") { |
| return r; |
| } |
| if (len) { |
| stack = stack.slice(0, -1 * len * 2); |
| vstack = vstack.slice(0, -1 * len); |
| lstack = lstack.slice(0, -1 * len); |
| } |
| stack.push(this.productions_[action[1]][0]); |
| vstack.push(yyval.$); |
| lstack.push(yyval._$); |
| newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; |
| stack.push(newState); |
| break; |
| case 3: |
| return true; |
| } |
| } |
| return true; |
| } |
| }; |
| /* Jison generated lexer */ |
| var lexer = (function() { |
| var lexer = ({ |
| EOF: 1, |
| parseError: function parseError(str, hash) { |
| if (this.yy.parser) { |
| this.yy.parser.parseError(str, hash); |
| } else { |
| throw new Error(str); |
| } |
| }, |
| setInput: function(input) { |
| this._input = input; |
| this._more = this._less = this.done = false; |
| this.yylineno = this.yyleng = 0; |
| this.yytext = this.matched = this.match = ''; |
| this.conditionStack = ['INITIAL']; |
| this.yylloc = { |
| first_line: 1, |
| first_column: 0, |
| last_line: 1, |
| last_column: 0 |
| }; |
| if (this.options.ranges) this.yylloc.range = [0, 0]; |
| this.offset = 0; |
| return this; |
| }, |
| input: function() { |
| var ch = this._input[0]; |
| this.yytext += ch; |
| this.yyleng++; |
| this.offset++; |
| this.match += ch; |
| this.matched += ch; |
| var lines = ch.match(/(?:\r\n?|\n).*/g); |
| if (lines) { |
| this.yylineno++; |
| this.yylloc.last_line++; |
| } else { |
| this.yylloc.last_column++; |
| } |
| if (this.options.ranges) this.yylloc.range[1]++; |
| |
| this._input = this._input.slice(1); |
| return ch; |
| }, |
| unput: function(ch) { |
| var len = ch.length; |
| var lines = ch.split(/(?:\r\n?|\n)/g); |
| |
| this._input = ch + this._input; |
| this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); |
| //this.yyleng -= len; |
| this.offset -= len; |
| var oldLines = this.match.split(/(?:\r\n?|\n)/g); |
| this.match = this.match.substr(0, this.match.length - 1); |
| this.matched = this.matched.substr(0, this.matched.length - 1); |
| |
| if (lines.length - 1) this.yylineno -= lines.length - 1; |
| var r = this.yylloc.range; |
| |
| this.yylloc = { |
| first_line: this.yylloc.first_line, |
| last_line: this.yylineno + 1, |
| first_column: this.yylloc.first_column, |
| last_column: lines ? |
| (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len |
| }; |
| |
| if (this.options.ranges) { |
| this.yylloc.range = [r[0], r[0] + this.yyleng - len]; |
| } |
| return this; |
| }, |
| more: function() { |
| this._more = true; |
| return this; |
| }, |
| less: function(n) { |
| this.unput(this.match.slice(n)); |
| }, |
| pastInput: function() { |
| var past = this.matched.substr(0, this.matched.length - this.match.length); |
| return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, ""); |
| }, |
| upcomingInput: function() { |
| var next = this.match; |
| if (next.length < 20) { |
| next += this._input.substr(0, 20 - next.length); |
| } |
| return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); |
| }, |
| showPosition: function() { |
| var pre = this.pastInput(); |
| var c = new Array(pre.length + 1).join("-"); |
| return pre + this.upcomingInput() + "\n" + c + "^"; |
| }, |
| next: function() { |
| if (this.done) { |
| return this.EOF; |
| } |
| if (!this._input) this.done = true; |
| |
| var token, |
| match, |
| tempMatch, |
| index, |
| col, |
| lines; |
| if (!this._more) { |
| this.yytext = ''; |
| this.match = ''; |
| } |
| var rules = this._currentRules(); |
| for (var i = 0; i < rules.length; i++) { |
| tempMatch = this._input.match(this.rules[rules[i]]); |
| if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { |
| match = tempMatch; |
| index = i; |
| if (!this.options.flex) break; |
| } |
| } |
| if (match) { |
| lines = match[0].match(/(?:\r\n?|\n).*/g); |
| if (lines) this.yylineno += lines.length; |
| this.yylloc = { |
| first_line: this.yylloc.last_line, |
| last_line: this.yylineno + 1, |
| first_column: this.yylloc.last_column, |
| last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length |
| }; |
| this.yytext += match[0]; |
| this.match += match[0]; |
| this.matches = match; |
| this.yyleng = this.yytext.length; |
| if (this.options.ranges) { |
| this.yylloc.range = [this.offset, this.offset += this.yyleng]; |
| } |
| this._more = false; |
| this._input = this._input.slice(match[0].length); |
| this.matched += match[0]; |
| token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]); |
| if (this.done && this._input) this.done = false; |
| if (token) return token; |
| else return; |
| } |
| if (this._input === "") { |
| return this.EOF; |
| } else { |
| return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { |
| text: "", |
| token: null, |
| line: this.yylineno |
| }); |
| } |
| }, |
| lex: function lex() { |
| var r = this.next(); |
| if (typeof r !== 'undefined') { |
| return r; |
| } else { |
| return this.lex(); |
| } |
| }, |
| begin: function begin(condition) { |
| this.conditionStack.push(condition); |
| }, |
| popState: function popState() { |
| return this.conditionStack.pop(); |
| }, |
| _currentRules: function _currentRules() { |
| return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; |
| }, |
| topState: function() { |
| return this.conditionStack[this.conditionStack.length - 2]; |
| }, |
| pushState: function begin(condition) { |
| this.begin(condition); |
| } |
| }); |
| lexer.options = {}; |
| lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) { |
| |
| var YYSTATE = YY_START |
| switch ($avoiding_name_collisions) { |
| case 0: |
| if (yy_.yytext.slice(-1) !== "\\") this.begin("mu"); |
| if (yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0, yy_.yyleng - 1), this.begin("emu"); |
| if (yy_.yytext) return 14; |
| |
| break; |
| case 1: |
| return 14; |
| break; |
| case 2: |
| if (yy_.yytext.slice(-1) !== "\\") this.popState(); |
| if (yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0, yy_.yyleng - 1); |
| return 14; |
| |
| break; |
| case 3: |
| yy_.yytext = yy_.yytext.substr(0, yy_.yyleng - 4); |
| this.popState(); |
| return 15; |
| break; |
| case 4: |
| this.begin("par"); |
| return 24; |
| break; |
| case 5: |
| return 16; |
| break; |
| case 6: |
| return 20; |
| break; |
| case 7: |
| return 19; |
| break; |
| case 8: |
| return 19; |
| break; |
| case 9: |
| return 23; |
| break; |
| case 10: |
| return 23; |
| break; |
| case 11: |
| this.popState(); |
| this.begin('com'); |
| break; |
| case 12: |
| yy_.yytext = yy_.yytext.substr(3, yy_.yyleng - 5); |
| this.popState(); |
| return 15; |
| break; |
| case 13: |
| return 22; |
| break; |
| case 14: |
| return 36; |
| break; |
| case 15: |
| return 35; |
| break; |
| case 16: |
| return 35; |
| break; |
| case 17: |
| return 39; |
| break; |
| case 18: |
| /*ignore whitespace*/ |
| break; |
| case 19: |
| this.popState(); |
| return 18; |
| break; |
| case 20: |
| this.popState(); |
| return 18; |
| break; |
| case 21: |
| yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2).replace(/\\"/g, '"'); |
| return 30; |
| break; |
| case 22: |
| yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2).replace(/\\'/g, "'"); |
| return 30; |
| break; |
| case 23: |
| yy_.yytext = yy_.yytext.substr(1); |
| return 28; |
| break; |
| case 24: |
| return 32; |
| break; |
| case 25: |
| return 32; |
| break; |
| case 26: |
| return 31; |
| break; |
| case 27: |
| return 35; |
| break; |
| case 28: |
| yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2); |
| return 35; |
| break; |
| case 29: |
| return 'INVALID'; |
| break; |
| case 30: |
| /*ignore whitespace*/ |
| break; |
| case 31: |
| this.popState(); |
| return 37; |
| break; |
| case 32: |
| return 5; |
| break; |
| } |
| }; |
| lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|$)))/, /^(?:[\s\S]*?--\}\})/, /^(?:\{\{>)/, /^(?:\{\{#)/, /^(?:\{\{\/)/, /^(?:\{\{\^)/, /^(?:\{\{\s*else\b)/, /^(?:\{\{\{)/, /^(?:\{\{&)/, /^(?:\{\{!--)/, /^(?:\{\{![\s\S]*?\}\})/, /^(?:\{\{)/, /^(?:=)/, /^(?:\.(?=[} ]))/, /^(?:\.\.)/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}\}\})/, /^(?:\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@[a-zA-Z]+)/, /^(?:true(?=[}\s]))/, /^(?:false(?=[}\s]))/, /^(?:-?[0-9]+(?=[}\s]))/, /^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/, /^(?:\[[^\]]*\])/, /^(?:.)/, /^(?:\s+)/, /^(?:[a-zA-Z0-9_$-/]+)/, /^(?:$)/]; |
| lexer.conditions = { |
| "mu": { |
| "rules": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32], |
| "inclusive": false |
| }, |
| "emu": { |
| "rules": [2], |
| "inclusive": false |
| }, |
| "com": { |
| "rules": [3], |
| "inclusive": false |
| }, |
| "par": { |
| "rules": [30, 31], |
| "inclusive": false |
| }, |
| "INITIAL": { |
| "rules": [0, 1, 32], |
| "inclusive": true |
| } |
| }; |
| return lexer; |
| })() |
| parser.lexer = lexer; |
| |
| function Parser() { |
| this.yy = {}; |
| } |
| Parser.prototype = parser; |
| parser.Parser = Parser; |
| return new Parser; |
| })();; |
| // lib/handlebars/compiler/base.js |
| |
| Handlebars.Parser = handlebars; |
| |
| Handlebars.parse = function(input) { |
| |
| // Just return if an already-compile AST was passed in. |
| if (input.constructor === Handlebars.AST.ProgramNode) { |
| return input; |
| } |
| |
| Handlebars.Parser.yy = Handlebars.AST; |
| return Handlebars.Parser.parse(input); |
| };; |
| // lib/handlebars/compiler/ast.js |
| (function() { |
| Handlebars.AST = {}; |
| |
| Handlebars.AST.ProgramNode = function(statements, inverse) { |
| this.type = "program"; |
| this.statements = statements; |
| if (inverse) { |
| this.inverse = new Handlebars.AST.ProgramNode(inverse); |
| } |
| }; |
| |
| Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) { |
| this.type = "mustache"; |
| this.escaped = !unescaped; |
| this.hash = hash; |
| |
| var id = this.id = rawParams[0]; |
| var params = this.params = rawParams.slice(1); |
| |
| // a mustache is an eligible helper if: |
| // * its id is simple (a single part, not `this` or `..`) |
| var eligibleHelper = this.eligibleHelper = id.isSimple; |
| |
| // a mustache is definitely a helper if: |
| // * it is an eligible helper, and |
| // * it has at least one parameter or hash segment |
| this.isHelper = eligibleHelper && (params.length || hash); |
| |
| // if a mustache is an eligible helper but not a definite |
| // helper, it is ambiguous, and will be resolved in a later |
| // pass or at runtime. |
| }; |
| |
| Handlebars.AST.PartialNode = function(partialName, context) { |
| this.type = "partial"; |
| this.partialName = partialName; |
| this.context = context; |
| }; |
| |
| Handlebars.AST.BlockNode = function(mustache, program, inverse, close) { |
| var verifyMatch = function(open, close) { |
| if (open.original !== close.original) { |
| throw new Handlebars.Exception(open.original + " doesn't match " + close.original); |
| } |
| }; |
| |
| verifyMatch(mustache.id, close); |
| this.type = "block"; |
| this.mustache = mustache; |
| this.program = program; |
| this.inverse = inverse; |
| |
| if (this.inverse && !this.program) { |
| this.isInverse = true; |
| } |
| }; |
| |
| Handlebars.AST.ContentNode = function(string) { |
| this.type = "content"; |
| this.string = string; |
| }; |
| |
| Handlebars.AST.HashNode = function(pairs) { |
| this.type = "hash"; |
| this.pairs = pairs; |
| }; |
| |
| Handlebars.AST.IdNode = function(parts) { |
| this.type = "ID"; |
| this.original = parts.join("."); |
| |
| var dig = [], |
| depth = 0; |
| |
| for (var i = 0, l = parts.length; i < l; i++) { |
| var part = parts[i]; |
| |
| if (part === ".." || part === "." || part === "this") { |
| if (dig.length > 0) { |
| throw new Handlebars.Exception("Invalid path: " + this.original); |
| } else if (part === "..") { |
| depth++; |
| } else { |
| this.isScoped = true; |
| } |
| } else { |
| dig.push(part); |
| } |
| } |
| |
| this.parts = dig; |
| this.string = dig.join('.'); |
| this.depth = depth; |
| |
| // an ID is simple if it only has one part, and that part is not |
| // `..` or `this`. |
| this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; |
| |
| this.stringModeValue = this.string; |
| }; |
| |
| Handlebars.AST.PartialNameNode = function(name) { |
| this.type = "PARTIAL_NAME"; |
| this.name = name; |
| }; |
| |
| Handlebars.AST.DataNode = function(id) { |
| this.type = "DATA"; |
| this.id = id; |
| }; |
| |
| Handlebars.AST.StringNode = function(string) { |
| this.type = "STRING"; |
| this.string = string; |
| this.stringModeValue = string; |
| }; |
| |
| Handlebars.AST.IntegerNode = function(integer) { |
| this.type = "INTEGER"; |
| this.integer = integer; |
| this.stringModeValue = Number(integer); |
| }; |
| |
| Handlebars.AST.BooleanNode = function(bool) { |
| this.type = "BOOLEAN"; |
| this.bool = bool; |
| this.stringModeValue = bool === "true"; |
| }; |
| |
| Handlebars.AST.CommentNode = function(comment) { |
| this.type = "comment"; |
| this.comment = comment; |
| };; |
| })();; |
| //>>excludeEnd('excludeHbsParser') |
| // lib/handlebars/utils.js |
| |
| var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; |
| |
| Handlebars.Exception = function(message) { |
| var tmp = Error.prototype.constructor.apply(this, arguments); |
| |
| // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. |
| for (var idx = 0; idx < errorProps.length; idx++) { |
| this[errorProps[idx]] = tmp[errorProps[idx]]; |
| } |
| }; |
| Handlebars.Exception.prototype = new Error(); |
| |
| // Build out our basic SafeString type |
| Handlebars.SafeString = function(string) { |
| this.string = string; |
| }; |
| Handlebars.SafeString.prototype.toString = function() { |
| return this.string.toString(); |
| }; |
| |
| (function() { |
| var escape = { |
| "&": "&", |
| "<": "<", |
| ">": ">", |
| '"': """, |
| "'": "'", |
| "`": "`" |
| }; |
| |
| var badChars = /[&<>"'`]/g; |
| var possible = /[&<>"'`]/; |
| |
| var escapeChar = function(chr) { |
| return escape[chr] || "&"; |
| }; |
| |
| Handlebars.Utils = { |
| escapeExpression: function(string) { |
| // don't escape SafeStrings, since they're already safe |
| if (string instanceof Handlebars.SafeString) { |
| return string.toString(); |
| } else if (string == null || string === false) { |
| return ""; |
| } |
| |
| if (!possible.test(string)) { |
| return string; |
| } |
| return string.replace(badChars, escapeChar); |
| }, |
| |
| isEmpty: function(value) { |
| if (!value && value !== 0) { |
| return true; |
| } else if (Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| };; |
| })(); |
| // lib/handlebars/compiler/compiler.js |
| |
| /*jshint eqnull:true*/ |
| Handlebars.Compiler = function() {}; |
| Handlebars.JavaScriptCompiler = function() {}; |
| |
| (function(Compiler, JavaScriptCompiler) { |
| // the foundHelper register will disambiguate helper lookup from finding a |
| // function in a context. This is necessary for mustache compatibility, which |
| // requires that context functions in blocks are evaluated by blockHelperMissing, |
| // and then proceed as if the resulting value was provided to blockHelperMissing. |
| |
| Compiler.prototype = { |
| compiler: Compiler, |
| |
| disassemble: function() { |
| var opcodes = this.opcodes, |
| opcode, out = [], |
| params, param; |
| |
| for (var i = 0, l = opcodes.length; i < l; i++) { |
| opcode = opcodes[i]; |
| |
| if (opcode.opcode === 'DECLARE') { |
| out.push("DECLARE " + opcode.name + "=" + opcode.value); |
| } else { |
| params = []; |
| for (var j = 0; j < opcode.args.length; j++) { |
| param = opcode.args[j]; |
| if (typeof param === "string") { |
| param = "\"" + param.replace("\n", "\\n") + "\""; |
| } |
| params.push(param); |
| } |
| out.push(opcode.opcode + " " + params.join(" ")); |
| } |
| } |
| |
| return out.join("\n"); |
| }, |
| equals: function(other) { |
| var len = this.opcodes.length; |
| if (other.opcodes.length !== len) { |
| return false; |
| } |
| |
| for (var i = 0; i < len; i++) { |
| var opcode = this.opcodes[i], |
| otherOpcode = other.opcodes[i]; |
| if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) { |
| return false; |
| } |
| for (var j = 0; j < opcode.args.length; j++) { |
| if (opcode.args[j] !== otherOpcode.args[j]) { |
| return false; |
| } |
| } |
| } |
| |
| len = this.children.length; |
| if (other.children.length !== len) { |
| return false; |
| } |
| for (i = 0; i < len; i++) { |
| if (!this.children[i].equals(other.children[i])) { |
| return false; |
| } |
| } |
| |
| return true; |
| }, |
| |
| guid: 0, |
| |
| compile: function(program, options) { |
| this.children = []; |
| this.depths = { |
| list: [] |
| }; |
| this.options = options; |
| |
| // These changes will propagate to the other compiler components |
| var knownHelpers = this.options.knownHelpers; |
| this.options.knownHelpers = { |
| 'helperMissing': true, |
| 'blockHelperMissing': true, |
| 'each': true, |
| 'if': true, |
| 'unless': true, |
| 'with': true, |
| 'log': true |
| }; |
| if (knownHelpers) { |
| for (var name in knownHelpers) { |
| this.options.knownHelpers[name] = knownHelpers[name]; |
| } |
| } |
| |
| return this.program(program); |
| }, |
| |
| accept: function(node) { |
| return this[node.type](node); |
| }, |
| |
| program: function(program) { |
| var statements = program.statements, |
| statement; |
| this.opcodes = []; |
| |
| for (var i = 0, l = statements.length; i < l; i++) { |
| statement = statements[i]; |
| this[statement.type](statement); |
| } |
| this.isSimple = l === 1; |
| |
| this.depths.list = this.depths.list.sort(function(a, b) { |
| return a - b; |
| }); |
| |
| return this; |
| }, |
| |
| compileProgram: function(program) { |
| var result = new this.compiler().compile(program, this.options); |
| var guid = this.guid++, |
| depth; |
| |
| this.usePartial = this.usePartial || result.usePartial; |
| |
| this.children[guid] = result; |
| |
| for (var i = 0, l = result.depths.list.length; i < l; i++) { |
| depth = result.depths.list[i]; |
| |
| if (depth < 2) { |
| continue; |
| } else { |
| this.addDepth(depth - 1); |
| } |
| } |
| |
| return guid; |
| }, |
| |
| block: function(block) { |
| var mustache = block.mustache, |
| program = block.program, |
| inverse = block.inverse; |
| |
| if (program) { |
| program = this.compileProgram(program); |
| } |
| |
| if (inverse) { |
| inverse = this.compileProgram(inverse); |
| } |
| |
| var type = this.classifyMustache(mustache); |
| |
| if (type === "helper") { |
| this.helperMustache(mustache, program, inverse); |
| } else if (type === "simple") { |
| this.simpleMustache(mustache); |
| |
| // now that the simple mustache is resolved, we need to |
| // evaluate it by executing `blockHelperMissing` |
| this.opcode('pushProgram', program); |
| this.opcode('pushProgram', inverse); |
| this.opcode('emptyHash'); |
| this.opcode('blockValue'); |
| } else { |
| this.ambiguousMustache(mustache, program, inverse); |
| |
| // now that the simple mustache is resolved, we need to |
| // evaluate it by executing `blockHelperMissing` |
| this.opcode('pushProgram', program); |
| this.opcode('pushProgram', inverse); |
| this.opcode('emptyHash'); |
| this.opcode('ambiguousBlockValue'); |
| } |
| |
| this.opcode('append'); |
| }, |
| |
| hash: function(hash) { |
| var pairs = hash.pairs, |
| pair, val; |
| |
| this.opcode('pushHash'); |
| |
| for (var i = 0, l = pairs.length; i < l; i++) { |
| pair = pairs[i]; |
| val = pair[1]; |
| |
| if (this.options.stringParams) { |
| this.opcode('pushStringParam', val.stringModeValue, val.type); |
| } else { |
| this.accept(val); |
| } |
| |
| this.opcode('assignToHash', pair[0]); |
| } |
| this.opcode('popHash'); |
| }, |
| |
| partial: function(partial) { |
| var partialName = partial.partialName; |
| this.usePartial = true; |
| |
| if (partial.context) { |
| this.ID(partial.context); |
| } else { |
| this.opcode('push', 'depth0'); |
| } |
| |
| this.opcode('invokePartial', partialName.name); |
| this.opcode('append'); |
| }, |
| |
| content: function(content) { |
| this.opcode('appendContent', content.string); |
| }, |
| |
| mustache: function(mustache) { |
| var options = this.options; |
| var type = this.classifyMustache(mustache); |
| |
| if (type === "simple") { |
| this.simpleMustache(mustache); |
| } else if (type === "helper") { |
| this.helperMustache(mustache); |
| } else { |
| this.ambiguousMustache(mustache); |
| } |
| |
| if (mustache.escaped && !options.noEscape) { |
| this.opcode('appendEscaped'); |
| } else { |
| this.opcode('append'); |
| } |
| }, |
| |
| ambiguousMustache: function(mustache, program, inverse) { |
| var id = mustache.id, |
| name = id.parts[0], |
| isBlock = program != null || inverse != null; |
| |
| this.opcode('getContext', id.depth); |
| |
| this.opcode('pushProgram', program); |
| this.opcode('pushProgram', inverse); |
| |
| this.opcode('invokeAmbiguous', name, isBlock); |
| }, |
| |
| simpleMustache: function(mustache) { |
| var id = mustache.id; |
| |
| if (id.type === 'DATA') { |
| this.DATA(id); |
| } else if (id.parts.length) { |
| this.ID(id); |
| } else { |
| // Simplified ID for `this` |
| this.addDepth(id.depth); |
| this.opcode('getContext', id.depth); |
| this.opcode('pushContext'); |
| } |
| |
| this.opcode('resolvePossibleLambda'); |
| }, |
| |
| helperMustache: function(mustache, program, inverse) { |
| var params = this.setupFullMustacheParams(mustache, program, inverse), |
| name = mustache.id.parts[0]; |
| |
| if (this.options.knownHelpers[name]) { |
| this.opcode('invokeKnownHelper', params.length, name); |
| } else if (this.knownHelpersOnly) { |
| throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name); |
| } else { |
| this.opcode('invokeHelper', params.length, name); |
| } |
| }, |
| |
| ID: function(id) { |
| this.addDepth(id.depth); |
| this.opcode('getContext', id.depth); |
| |
| var name = id.parts[0]; |
| if (!name) { |
| this.opcode('pushContext'); |
| } else { |
| this.opcode('lookupOnContext', id.parts[0]); |
| } |
| |
| for (var i = 1, l = id.parts.length; i < l; i++) { |
| this.opcode('lookup', id.parts[i]); |
| } |
| }, |
| |
| DATA: function(data) { |
| this.options.data = true; |
| this.opcode('lookupData', data.id); |
| }, |
| |
| STRING: function(string) { |
| this.opcode('pushString', string.string); |
| }, |
| |
| INTEGER: function(integer) { |
| this.opcode('pushLiteral', integer.integer); |
| }, |
| |
| BOOLEAN: function(bool) { |
| this.opcode('pushLiteral', bool.bool); |
| }, |
| |
| comment: function() {}, |
| |
| // HELPERS |
| opcode: function(name) { |
| this.opcodes.push({ |
| opcode: name, |
| args: [].slice.call(arguments, 1) |
| }); |
| }, |
| |
| declare: function(name, value) { |
| this.opcodes.push({ |
| opcode: 'DECLARE', |
| name: name, |
| value: value |
| }); |
| }, |
| |
| addDepth: function(depth) { |
| if (isNaN(depth)) { |
| throw new Error("EWOT"); |
| } |
| if (depth === 0) { |
| return; |
| } |
| |
| if (!this.depths[depth]) { |
| this.depths[depth] = true; |
| this.depths.list.push(depth); |
| } |
| }, |
| |
| classifyMustache: function(mustache) { |
| var isHelper = mustache.isHelper; |
| var isEligible = mustache.eligibleHelper; |
| var options = this.options; |
| |
| // if ambiguous, we can possibly resolve the ambiguity now |
| if (isEligible && !isHelper) { |
| var name = mustache.id.parts[0]; |
| |
| if (options.knownHelpers[name]) { |
| isHelper = true; |
| } else if (options.knownHelpersOnly) { |
| isEligible = false; |
| } |
| } |
| |
| if (isHelper) { |
| return "helper"; |
| } else if (isEligible) { |
| return "ambiguous"; |
| } else { |
| return "simple"; |
| } |
| }, |
| |
| pushParams: function(params) { |
| var i = params.length, |
| param; |
| |
| while (i--) { |
| param = params[i]; |
| |
| if (this.options.stringParams) { |
| if (param.depth) { |
| this.addDepth(param.depth); |
| } |
| |
| this.opcode('getContext', param.depth || 0); |
| this.opcode('pushStringParam', param.stringModeValue, param.type); |
| } else { |
| this[param.type](param); |
| } |
| } |
| }, |
| |
| setupMustacheParams: function(mustache) { |
| var params = mustache.params; |
| this.pushParams(params); |
| |
| if (mustache.hash) { |
| this.hash(mustache.hash); |
| } else { |
| this.opcode('emptyHash'); |
| } |
| |
| return params; |
| }, |
| |
| // this will replace setupMustacheParams when we're done |
| setupFullMustacheParams: function(mustache, program, inverse) { |
| var params = mustache.params; |
| this.pushParams(params); |
| |
| this.opcode('pushProgram', program); |
| this.opcode('pushProgram', inverse); |
| |
| if (mustache.hash) { |
| this.hash(mustache.hash); |
| } else { |
| this.opcode('emptyHash'); |
| } |
| |
| return params; |
| } |
| }; |
| |
| var Literal = function(value) { |
| this.value = value; |
| }; |
| |
| JavaScriptCompiler.prototype = { |
| // PUBLIC API: You can override these methods in a subclass to provide |
| // alternative compiled forms for name lookup and buffering semantics |
| nameLookup: function(parent, name /* , type*/ ) { |
| if (/^[0-9]+$/.test(name)) { |
| return parent + "[" + name + "]"; |
| } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { |
| return parent + "." + name; |
| } else { |
| return parent + "['" + name + "']"; |
| } |
| }, |
| |
| appendToBuffer: function(string) { |
| if (this.environment.isSimple) { |
| return "return " + string + ";"; |
| } else { |
| return { |
| appendToBuffer: true, |
| content: string, |
| toString: function() { |
| return "buffer += " + string + ";"; |
| } |
| }; |
| } |
| }, |
| |
| initializeBuffer: function() { |
| return this.quotedString(""); |
| }, |
| |
| namespace: "Handlebars", |
| // END PUBLIC API |
| |
| compile: function(environment, options, context, asObject) { |
| this.environment = environment; |
| this.options = options || {}; |
| |
| Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n"); |
| |
| this.name = this.environment.name; |
| this.isChild = !!context; |
| this.context = context || { |
| programs: [], |
| environments: [], |
| aliases: {} |
| }; |
| |
| this.preamble(); |
| |
| this.stackSlot = 0; |
| this.stackVars = []; |
| this.registers = { |
| list: [] |
| }; |
| this.compileStack = []; |
| this.inlineStack = []; |
| |
| this.compileChildren(environment, options); |
| |
| var opcodes = environment.opcodes, |
| opcode; |
| |
| this.i = 0; |
| |
| for (l = opcodes.length; this.i < l; this.i++) { |
| opcode = opcodes[this.i]; |
| |
| if (opcode.opcode === 'DECLARE') { |
| this[opcode.name] = opcode.value; |
| } else { |
| this[opcode.opcode].apply(this, opcode.args); |
| } |
| } |
| |
| return this.createFunctionContext(asObject); |
| }, |
| |
| nextOpcode: function() { |
| var opcodes = this.environment.opcodes; |
| return opcodes[this.i + 1]; |
| }, |
| |
| eat: function() { |
| this.i = this.i + 1; |
| }, |
| |
| preamble: function() { |
| var out = []; |
| |
| if (!this.isChild) { |
| var namespace = this.namespace; |
| var copies = "helpers = helpers || " + namespace + ".helpers;"; |
| if (this.environment.usePartial) { |
| copies = copies + " partials = partials || " + namespace + ".partials;"; |
| } |
| if (this.options.data) { |
| copies = copies + " data = data || {};"; |
| } |
| out.push(copies); |
| } else { |
| out.push(''); |
| } |
| |
| if (!this.environment.isSimple) { |
| out.push(", buffer = " + this.initializeBuffer()); |
| } else { |
| out.push(""); |
| } |
| |
| // track the last context pushed into place to allow skipping the |
| // getContext opcode when it would be a noop |
| this.lastContext = 0; |
| this.source = out; |
| }, |
| |
| createFunctionContext: function(asObject) { |
| var locals = this.stackVars.concat(this.registers.list); |
| |
| if (locals.length > 0) { |
| this.source[1] = this.source[1] + ", " + locals.join(", "); |
| } |
| |
| // Generate minimizer alias mappings |
| if (!this.isChild) { |
| for (var alias in this.context.aliases) { |
| this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; |
| } |
| } |
| |
| if (this.source[1]) { |
| this.source[1] = "var " + this.source[1].substring(2) + ";"; |
| } |
| |
| // Merge children |
| if (!this.isChild) { |
| this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; |
| } |
| |
| if (!this.environment.isSimple) { |
| this.source.push("return buffer;"); |
| } |
| |
| var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; |
| |
| for (var i = 0, l = this.environment.depths.list.length; i < l; i++) { |
| params.push("depth" + this.environment.depths.list[i]); |
| } |
| |
| // Perform a second pass over the output to merge content when possible |
| var source = this.mergeSource(); |
| |
| if (!this.isChild) { |
| var revision = Handlebars.COMPILER_REVISION, |
| versions = Handlebars.REVISION_CHANGES[revision]; |
| source = "this.compilerInfo = [" + revision + ",'" + versions + "'];\n" + source; |
| } |
| |
| if (asObject) { |
| params.push(source); |
| |
| return Function.apply(this, params); |
| } else { |
| var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}'; |
| Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n"); |
| return functionSource; |
| } |
| }, |
| mergeSource: function() { |
| // WARN: We are not handling the case where buffer is still populated as the source should |
| // not have buffer append operations as their final action. |
| var source = '', |
| buffer; |
| for (var i = 0, len = this.source.length; i < len; i++) { |
| var line = this.source[i]; |
| if (line.appendToBuffer) { |
| if (buffer) { |
| buffer = buffer + '\n + ' + line.content; |
| } else { |
| buffer = line.content; |
| } |
| } else { |
| if (buffer) { |
| source += 'buffer += ' + buffer + ';\n '; |
| buffer = undefined; |
| } |
| source += line + '\n '; |
| } |
| } |
| return source; |
| }, |
| |
| // [blockValue] |
| // |
| // On stack, before: hash, inverse, program, value |
| // On stack, after: return value of blockHelperMissing |
| // |
| // The purpose of this opcode is to take a block of the form |
| // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and |
| // replace it on the stack with the result of properly |
| // invoking blockHelperMissing. |
| blockValue: function() { |
| this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; |
| |
| var params = ["depth0"]; |
| this.setupParams(0, params); |
| |
| this.replaceStack(function(current) { |
| params.splice(1, 0, current); |
| return "blockHelperMissing.call(" + params.join(", ") + ")"; |
| }); |
| }, |
| |
| // [ambiguousBlockValue] |
| // |
| // On stack, before: hash, inverse, program, value |
| // Compiler value, before: lastHelper=value of last found helper, if any |
| // On stack, after, if no lastHelper: same as [blockValue] |
| // On stack, after, if lastHelper: value |
| ambiguousBlockValue: function() { |
| this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; |
| |
| var params = ["depth0"]; |
| this.setupParams(0, params); |
| |
| var current = this.topStack(); |
| params.splice(1, 0, current); |
| |
| // Use the options value generated from the invocation |
| params[params.length - 1] = 'options'; |
| |
| this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); |
| }, |
| |
| // [appendContent] |
| // |
| // On stack, before: ... |
| // On stack, after: ... |
| // |
| // Appends the string value of `content` to the current buffer |
| appendContent: function(content) { |
| this.source.push(this.appendToBuffer(this.quotedString(content))); |
| }, |
| |
| // [append] |
| // |
| // On stack, before: value, ... |
| // On stack, after: ... |
| // |
| // Coerces `value` to a String and appends it to the current buffer. |
| // |
| // If `value` is truthy, or 0, it is coerced into a string and appended |
| // Otherwise, the empty string is appended |
| append: function() { |
| // Force anything that is inlined onto the stack so we don't have duplication |
| // when we examine local |
| this.flushInline(); |
| var local = this.popStack(); |
| this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }"); |
| if (this.environment.isSimple) { |
| this.source.push("else { " + this.appendToBuffer("''") + " }"); |
| } |
| }, |
| |
| // [appendEscaped] |
| // |
| // On stack, before: value, ... |
| // On stack, after: ... |
| // |
| // Escape `value` and append it to the buffer |
| appendEscaped: function() { |
| this.context.aliases.escapeExpression = 'this.escapeExpression'; |
| |
| this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")")); |
| }, |
| |
| // [getContext] |
| // |
| // On stack, before: ... |
| // On stack, after: ... |
| // Compiler value, after: lastContext=depth |
| // |
| // Set the value of the `lastContext` compiler value to the depth |
| getContext: function(depth) { |
| if (this.lastContext !== depth) { |
| this.lastContext = depth; |
| } |
| }, |
| |
| // [lookupOnContext] |
| // |
| // On stack, before: ... |
| // On stack, after: currentContext[name], ... |
| // |
| // Looks up the value of `name` on the current context and pushes |
| // it onto the stack. |
| lookupOnContext: function(name) { |
| this.push(this.nameLookup('depth' + this.lastContext, name, 'context')); |
| }, |
| |
| // [pushContext] |
| // |
| // On stack, before: ... |
| // On stack, after: currentContext, ... |
| // |
| // Pushes the value of the current context onto the stack. |
| pushContext: function() { |
| this.pushStackLiteral('depth' + this.lastContext); |
| }, |
| |
| // [resolvePossibleLambda] |
| // |
| // On stack, before: value, ... |
| // On stack, after: resolved value, ... |
| // |
| // If the `value` is a lambda, replace it on the stack by |
| // the return value of the lambda |
| resolvePossibleLambda: function() { |
| this.context.aliases.functionType = '"function"'; |
| |
| this.replaceStack(function(current) { |
| return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current; |
| }); |
| }, |
| |
| // [lookup] |
| // |
| // On stack, before: value, ... |
| // On stack, after: value[name], ... |
| // |
| // Replace the value on the stack with the result of looking |
| // up `name` on `value` |
| lookup: function(name) { |
| this.replaceStack(function(current) { |
| return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context'); |
| }); |
| }, |
| |
| // [lookupData] |
| // |
| // On stack, before: ... |
| // On stack, after: data[id], ... |
| // |
| // Push the result of looking up `id` on the current data |
| lookupData: function(id) { |
| this.push(this.nameLookup('data', id, 'data')); |
| }, |
| |
| // [pushStringParam] |
| // |
| // On stack, before: ... |
| // On stack, after: string, currentContext, ... |
| // |
| // This opcode is designed for use in string mode, which |
| // provides the string value of a parameter along with its |
| // depth rather than resolving it immediately. |
| pushStringParam: function(string, type) { |
| this.pushStackLiteral('depth' + this.lastContext); |
| |
| this.pushString(type); |
| |
| if (typeof string === 'string') { |
| this.pushString(string); |
| } else { |
| this.pushStackLiteral(string); |
| } |
| }, |
| |
| emptyHash: function() { |
| this.pushStackLiteral('{}'); |
| |
| if (this.options.stringParams) { |
| this.register('hashTypes', '{}'); |
| } |
| }, |
| pushHash: function() { |
| this.hash = { |
| values: [], |
| types: [] |
| }; |
| }, |
| popHash: function() { |
| var hash = this.hash; |
| this.hash = undefined; |
| |
| if (this.options.stringParams) { |
| this.register('hashTypes', '{' + hash.types.join(',') + '}'); |
| } |
| this.push('{\n ' + hash.values.join(',\n ') + '\n }'); |
| }, |
| |
| // [pushString] |
| // |
| // On stack, before: ... |
| // On stack, after: quotedString(string), ... |
| // |
| // Push a quoted version of `string` onto the stack |
| pushString: function(string) { |
| this.pushStackLiteral(this.quotedString(string)); |
| }, |
| |
| // [push] |
| // |
| // On stack, before: ... |
| // On stack, after: expr, ... |
| // |
| // Push an expression onto the stack |
| push: function(expr) { |
| this.inlineStack.push(expr); |
| return expr; |
| }, |
| |
| // [pushLiteral] |
| // |
| // On stack, before: ... |
| // On stack, after: value, ... |
| // |
| // Pushes a value onto the stack. This operation prevents |
| // the compiler from creating a temporary variable to hold |
| // it. |
| pushLiteral: function(value) { |
| this.pushStackLiteral(value); |
| }, |
| |
| // [pushProgram] |
| // |
| // On stack, before: ... |
| // On stack, after: program(guid), ... |
| // |
| // Push a program expression onto the stack. This takes |
| // a compile-time guid and converts it into a runtime-accessible |
| // expression. |
| pushProgram: function(guid) { |
| if (guid != null) { |
| this.pushStackLiteral(this.programExpression(guid)); |
| } else { |
| this.pushStackLiteral(null); |
| } |
| }, |
| |
| // [invokeHelper] |
| // |
| // On stack, before: hash, inverse, program, params..., ... |
| // On stack, after: result of helper invocation |
| // |
| // Pops off the helper's parameters, invokes the helper, |
| // and pushes the helper's return value onto the stack. |
| // |
| // If the helper is not found, `helperMissing` is called. |
| invokeHelper: function(paramSize, name) { |
| this.context.aliases.helperMissing = 'helpers.helperMissing'; |
| |
| var helper = this.lastHelper = this.setupHelper(paramSize, name, true); |
| |
| this.push(helper.name); |
| this.replaceStack(function(name) { |
| return name + ' ? ' + name + '.call(' + |
| helper.callParams + ") " + ": helperMissing.call(" + |
| helper.helperMissingParams + ")"; |
| }); |
| }, |
| |
| // [invokeKnownHelper] |
| // |
| // On stack, before: hash, inverse, program, params..., ... |
| // On stack, after: result of helper invocation |
| // |
| // This operation is used when the helper is known to exist, |
| // so a `helperMissing` fallback is not required. |
| invokeKnownHelper: function(paramSize, name) { |
| var helper = this.setupHelper(paramSize, name); |
| this.push(helper.name + ".call(" + helper.callParams + ")"); |
| }, |
| |
| // [invokeAmbiguous] |
| // |
| // On stack, before: hash, inverse, program, params..., ... |
| // On stack, after: result of disambiguation |
| // |
| // This operation is used when an expression like `{{foo}}` |
| // is provided, but we don't know at compile-time whether it |
| // is a helper or a path. |
| // |
| // This operation emits more code than the other options, |
| // and can be avoided by passing the `knownHelpers` and |
| // `knownHelpersOnly` flags at compile-time. |
| invokeAmbiguous: function(name, helperCall) { |
| this.context.aliases.functionType = '"function"'; |
| |
| this.pushStackLiteral('{}'); // Hash value |
| var helper = this.setupHelper(0, name, helperCall); |
| |
| var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); |
| |
| var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context'); |
| var nextStack = this.nextStack(); |
| |
| this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }'); |
| this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }'); |
| }, |
| |
| // [invokePartial] |
| // |
| // On stack, before: context, ... |
| // On stack after: result of partial invocation |
| // |
| // This operation pops off a context, invokes a partial with that context, |
| // and pushes the result of the invocation back. |
| invokePartial: function(name) { |
| var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"]; |
| |
| if (this.options.data) { |
| params.push("data"); |
| } |
| |
| this.context.aliases.self = "this"; |
| this.push("self.invokePartial(" + params.join(", ") + ")"); |
| }, |
| |
| // [assignToHash] |
| // |
| // On stack, before: value, hash, ... |
| // On stack, after: hash, ... |
| // |
| // Pops a value and hash off the stack, assigns `hash[key] = value` |
| // and pushes the hash back onto the stack. |
| assignToHash: function(key) { |
| var value = this.popStack(), |
| type; |
| |
| if (this.options.stringParams) { |
| type = this.popStack(); |
| this.popStack(); |
| } |
| |
| var hash = this.hash; |
| if (type) { |
| hash.types.push("'" + key + "': " + type); |
| } |
| hash.values.push("'" + key + "': (" + value + ")"); |
| }, |
| |
| // HELPERS |
| |
| compiler: JavaScriptCompiler, |
| |
| compileChildren: function(environment, options) { |
| var children = environment.children, |
| child, compiler; |
| |
| for (var i = 0, l = children.length; i < l; i++) { |
| child = children[i]; |
| compiler = new this.compiler(); |
| |
| var index = this.matchExistingProgram(child); |
| |
| if (index == null) { |
| this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children |
| index = this.context.programs.length; |
| child.index = index; |
| child.name = 'program' + index; |
| this.context.programs[index] = compiler.compile(child, options, this.context); |
| this.context.environments[index] = child; |
| } else { |
| child.index = index; |
| child.name = 'program' + index; |
| } |
| } |
| }, |
| matchExistingProgram: function(child) { |
| for (var i = 0, len = this.context.environments.length; i < len; i++) { |
| var environment = this.context.environments[i]; |
| if (environment && environment.equals(child)) { |
| return i; |
| } |
| } |
| }, |
| |
| programExpression: function(guid) { |
| this.context.aliases.self = "this"; |
| |
| if (guid == null) { |
| return "self.noop"; |
| } |
| |
| var child = this.environment.children[guid], |
| depths = child.depths.list, |
| depth; |
| |
| var programParams = [child.index, child.name, "data"]; |
| |
| for (var i = 0, l = depths.length; i < l; i++) { |
| depth = depths[i]; |
| |
| if (depth === 1) { |
| programParams.push("depth0"); |
| } else { |
| programParams.push("depth" + (depth - 1)); |
| } |
| } |
| |
| if (depths.length === 0) { |
| return "self.program(" + programParams.join(", ") + ")"; |
| } else { |
| programParams.shift(); |
| return "self.programWithDepth(" + programParams.join(", ") + ")"; |
| } |
| }, |
| |
| register: function(name, val) { |
| this.useRegister(name); |
| this.source.push(name + " = " + val + ";"); |
| }, |
| |
| useRegister: function(name) { |
| if (!this.registers[name]) { |
| this.registers[name] = true; |
| this.registers.list.push(name); |
| } |
| }, |
| |
| pushStackLiteral: function(item) { |
| return this.push(new Literal(item)); |
| }, |
| |
| pushStack: function(item) { |
| this.flushInline(); |
| |
| var stack = this.incrStack(); |
| if (item) { |
| this.source.push(stack + " = " + item + ";"); |
| } |
| this.compileStack.push(stack); |
| return stack; |
| }, |
| |
| replaceStack: function(callback) { |
| var prefix = '', |
| inline = this.isInline(), |
| stack; |
| |
| // If we are currently inline then we want to merge the inline statement into the |
| // replacement statement via ',' |
| if (inline) { |
| var top = this.popStack(true); |
| |
| if (top instanceof Literal) { |
| // Literals do not need to be inlined |
| stack = top.value; |
| } else { |
| // Get or create the current stack name for use by the inline |
| var name = this.stackSlot ? this.topStackName() : this.incrStack(); |
| |
| prefix = '(' + this.push(name) + ' = ' + top + '),'; |
| stack = this.topStack(); |
| } |
| } else { |
| stack = this.topStack(); |
| } |
| |
| var item = callback.call(this, stack); |
| |
| if (inline) { |
| if (this.inlineStack.length || this.compileStack.length) { |
| this.popStack(); |
| } |
| this.push('(' + prefix + item + ')'); |
| } else { |
| // Prevent modification of the context depth variable. Through replaceStack |
| if (!/^stack/.test(stack)) { |
| stack = this.nextStack(); |
| } |
| |
| this.source.push(stack + " = (" + prefix + item + ");"); |
| } |
| return stack; |
| }, |
| |
| nextStack: function() { |
| return this.pushStack(); |
| }, |
| |
| incrStack: function() { |
| this.stackSlot++; |
| if (this.stackSlot > this.stackVars.length) { |
| this.stackVars.push("stack" + this.stackSlot); |
| } |
| return this.topStackName(); |
| }, |
| topStackName: function() { |
| return "stack" + this.stackSlot; |
| }, |
| flushInline: function() { |
| var inlineStack = this.inlineStack; |
| if (inlineStack.length) { |
| this.inlineStack = []; |
| for (var i = 0, len = inlineStack.length; i < len; i++) { |
| var entry = inlineStack[i]; |
| if (entry instanceof Literal) { |
| this.compileStack.push(entry); |
| } else { |
| this.pushStack(entry); |
| } |
| } |
| } |
| }, |
| isInline: function() { |
| return this.inlineStack.length; |
| }, |
| |
| popStack: function(wrapped) { |
| var inline = this.isInline(), |
| item = (inline ? this.inlineStack : this.compileStack).pop(); |
| |
| if (!wrapped && (item instanceof Literal)) { |
| return item.value; |
| } else { |
| if (!inline) { |
| this.stackSlot--; |
| } |
| return item; |
| } |
| }, |
| |
| topStack: function(wrapped) { |
| var stack = (this.isInline() ? this.inlineStack : this.compileStack), |
| item = stack[stack.length - 1]; |
| |
| if (!wrapped && (item instanceof Literal)) { |
| return item.value; |
| } else { |
| return item; |
| } |
| }, |
| |
| quotedString: function(str) { |
| return '"' + str |
| .replace(/\\/g, '\\\\') |
| .replace(/"/g, '\\"') |
| .replace(/\n/g, '\\n') |
| .replace(/\r/g, '\\r') + '"'; |
| }, |
| |
| setupHelper: function(paramSize, name, missingParams) { |
| var params = []; |
| this.setupParams(paramSize, params, missingParams); |
| var foundHelper = this.nameLookup('helpers', name, 'helper'); |
| |
| return { |
| params: params, |
| name: foundHelper, |
| callParams: ["depth0"].concat(params).join(", "), |
| helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") |
| }; |
| }, |
| |
| // the params and contexts arguments are passed in arrays |
| // to fill in |
| setupParams: function(paramSize, params, useRegister) { |
| var options = [], |
| contexts = [], |
| types = [], |
| param, inverse, program; |
| |
| options.push("hash:" + this.popStack()); |
| |
| inverse = this.popStack(); |
| program = this.popStack(); |
| |
| // Avoid setting fn and inverse if neither are set. This allows |
| // helpers to do a check for `if (options.fn)` |
| if (program || inverse) { |
| if (!program) { |
| this.context.aliases.self = "this"; |
| program = "self.noop"; |
| } |
| |
| if (!inverse) { |
| this.context.aliases.self = "this"; |
| inverse = "self.noop"; |
| } |
| |
| options.push("inverse:" + inverse); |
| options.push("fn:" + program); |
| } |
| |
| for (var i = 0; i < paramSize; i++) { |
| param = this.popStack(); |
| params.push(param); |
| |
| if (this.options.stringParams) { |
| types.push(this.popStack()); |
| contexts.push(this.popStack()); |
| } |
| } |
| |
| if (this.options.stringParams) { |
| options.push("contexts:[" + contexts.join(",") + "]"); |
| options.push("types:[" + types.join(",") + "]"); |
| options.push("hashTypes:hashTypes"); |
| } |
| |
| if (this.options.data) { |
| options.push("data:data"); |
| } |
| |
| options = "{" + options.join(",") + "}"; |
| if (useRegister) { |
| this.register('options', options); |
| params.push('options'); |
| } else { |
| params.push(options); |
| } |
| return params.join(", "); |
| } |
| }; |
| |
| var reservedWords = ( |
| "break else new var" + |
| " case finally return void" + |
| " catch for switch while" + |
| " continue function this with" + |
| " default if throw" + |
| " delete in try" + |
| " do instanceof typeof" + |
| " abstract enum int short" + |
| " boolean export interface static" + |
| " byte extends long super" + |
| " char final native synchronized" + |
| " class float package throws" + |
| " const goto private transient" + |
| " debugger implements protected volatile" + |
| " double import public let yield" |
| ).split(" "); |
| |
| var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; |
| |
| for (var i = 0, l = reservedWords.length; i < l; i++) { |
| compilerWords[reservedWords[i]] = true; |
| } |
| |
| JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { |
| if (!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) { |
| return true; |
| } |
| return false; |
| }; |
| |
| //>>excludeStart('excludeHbsParser', pragmas.excludeHbsParser) |
| Handlebars.precompile = function(input, options) { |
| if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { |
| throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); |
| } |
| |
| options = options || {}; |
| if (!('data' in options)) { |
| options.data = true; |
| } |
| var ast = Handlebars.parse(input); |
| var environment = new Compiler().compile(ast, options); |
| return new JavaScriptCompiler().compile(environment, options); |
| }; |
| |
| Handlebars.compile = function(input, options) { |
| if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { |
| throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); |
| } |
| |
| options = options || {}; |
| if (!('data' in options)) { |
| options.data = true; |
| } |
| var compiled; |
| |
| function compile() { |
| var ast = Handlebars.parse(input); |
| var environment = new Compiler().compile(ast, options); |
| var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true); |
| return Handlebars.template(templateSpec); |
| } |
| |
| // Template is only compiled on first use and cached after that point. |
| return function(context, options) { |
| if (!compiled) { |
| compiled = compile(); |
| } |
| return compiled.call(this, context, options); |
| }; |
| }; |
| //>>excludeEnd('excludeHbsParser') |
| |
| ; |
| // lib/handlebars/runtime.js |
| |
| Handlebars.VM = { |
| template: function(templateSpec) { |
| // Just add water |
| var container = { |
| escapeExpression: Handlebars.Utils.escapeExpression, |
| invokePartial: Handlebars.VM.invokePartial, |
| programs: [], |
| program: function(i, fn, data) { |
| var programWrapper = this.programs[i]; |
| if (data) { |
| return Handlebars.VM.program(fn, data); |
| } else if (programWrapper) { |
| return programWrapper; |
| } else { |
| programWrapper = this.programs[i] = Handlebars.VM.program(fn); |
| return programWrapper; |
| } |
| }, |
| programWithDepth: Handlebars.VM.programWithDepth, |
| noop: Handlebars.VM.noop, |
| compilerInfo: null |
| }; |
| |
| return function(context, options) { |
| options = options || {}; |
| var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); |
| |
| var compilerInfo = container.compilerInfo || [], |
| compilerRevision = compilerInfo[0] || 1, |
| currentRevision = Handlebars.COMPILER_REVISION; |
| |
| if (compilerRevision !== currentRevision) { |
| if (compilerRevision < currentRevision) { |
| var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision], |
| compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision]; |
| throw "Template was precompiled with an older version of Handlebars than the current runtime. " + |
| "Please update your precompiler to a newer version (" + runtimeVersions + ") or downgrade your runtime to an older version (" + compilerVersions + ")."; |
| } else { |
| // Use the embedded version info since the runtime doesn't know about this revision yet |
| throw "Template was precompiled with a newer version of Handlebars than the current runtime. " + |
| "Please update your runtime to a newer version (" + compilerInfo[1] + ")."; |
| } |
| } |
| |
| return result; |
| }; |
| }, |
| |
| programWithDepth: function(fn, data, $depth) { |
| var args = Array.prototype.slice.call(arguments, 2); |
| |
| return function(context, options) { |
| options = options || {}; |
| |
| return fn.apply(this, [context, options.data || data].concat(args)); |
| }; |
| }, |
| program: function(fn, data) { |
| return function(context, options) { |
| options = options || {}; |
| |
| return fn(context, options.data || data); |
| }; |
| }, |
| noop: function() { |
| return ""; |
| }, |
| invokePartial: function(partial, name, context, helpers, partials, data) { |
| var options = { |
| helpers: helpers, |
| partials: partials, |
| data: data |
| }; |
| |
| if (partial === undefined) { |
| throw new Handlebars.Exception("The partial " + name + " could not be found"); |
| } else if (partial instanceof Function) { |
| return partial(context, options); |
| } else if (!Handlebars.compile) { |
| throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); |
| } else { |
| partials[name] = Handlebars.compile(partial, { |
| data: data !== undefined |
| }); |
| return partials[name](context, options); |
| } |
| } |
| }; |
| |
| Handlebars.template = Handlebars.VM.template;; |
| // lib/handlebars/browser-suffix.js |
| })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);; |
| |
| // AMD Define |
| define(function() { |
| return Handlebars; |
| }); |
| |
| })(); |