From 3ffb8a13df4bb0f9ae9e3e8e02a9e1ae6e629838 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 15 May 2013 15:24:28 -0400 Subject: [PATCH 1/3] update to Handlebars 1.0.0-rc.4 --- vendor/assets/javascripts/handlebars.js | 2454 +++++++++-------- .../assets/javascripts/handlebars.runtime.js | 168 +- 2 files changed, 1342 insertions(+), 1280 deletions(-) diff --git a/vendor/assets/javascripts/handlebars.js b/vendor/assets/javascripts/handlebars.js index 9c653ee..96d86ea 100644 --- a/vendor/assets/javascripts/handlebars.js +++ b/vendor/assets/javascripts/handlebars.js @@ -22,31 +22,45 @@ THE SOFTWARE. */ -// lib/handlebars/base.js - -/*jshint eqnull:true*/ -this.Handlebars = {}; +// lib/handlebars/browser-prefix.js +var Handlebars = {}; -(function(Handlebars) { +(function(Handlebars, undefined) { +; +// lib/handlebars/base.js -Handlebars.VERSION = "1.0.0-rc.3"; -Handlebars.COMPILER_REVISION = 2; +Handlebars.VERSION = "1.0.0-rc.4"; +Handlebars.COMPILER_REVISION = 3; 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' + 2: '== 1.0.0-rc.3', + 3: '>= 1.0.0-rc.4' }; Handlebars.helpers = {}; Handlebars.partials = {}; +var toString = Object.prototype.toString, + functionType = '[object Function]', + objectType = '[object Object]'; + Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } + Handlebars.Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } }; Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; + if (toString.call(name) === objectType) { + Handlebars.Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } }; Handlebars.registerHelper('helperMissing', function(arg) { @@ -57,13 +71,9 @@ Handlebars.registerHelper('helperMissing', function(arg) { } }); -var toString = Object.prototype.toString, functionType = "[object Function]"; - Handlebars.registerHelper('blockHelperMissing', function(context, options) { var inverse = options.inverse || function() {}, fn = options.fn; - - var ret = ""; var type = toString.call(context); if(type === functionType) { context = context.call(this); } @@ -154,23 +164,17 @@ Handlebars.registerHelper('if', function(context, options) { }); Handlebars.registerHelper('unless', function(context, options) { - var fn = options.fn, inverse = options.inverse; - options.fn = inverse; - options.inverse = fn; - - return Handlebars.helpers['if'].call(this, 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); + if (!Handlebars.Utils.isEmpty(context)) 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); }); - -}(this.Handlebars)); ; // lib/handlebars/compiler/parser.js /* Jison generated parser */ @@ -562,90 +566,93 @@ lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_STA var YYSTATE=YY_START switch($avoiding_name_collisions) { -case 0: +case 0: yy_.yytext = "\\"; return 14; +break; +case 1: 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; +case 2: return 14; break; -case 2: +case 3: 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; +case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15; break; -case 4: this.begin("par"); return 24; +case 5: this.begin("par"); return 24; break; -case 5: return 16; +case 6: return 16; break; -case 6: return 20; -break; -case 7: return 19; +case 7: return 20; break; case 8: return 19; break; -case 9: return 23; +case 9: return 19; break; case 10: return 23; break; -case 11: this.popState(); this.begin('com'); +case 11: return 23; break; -case 12: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; +case 12: this.popState(); this.begin('com'); break; -case 13: return 22; +case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; break; -case 14: return 36; +case 14: return 22; break; -case 15: return 35; +case 15: return 36; break; case 16: return 35; break; -case 17: return 39; +case 17: return 35; break; -case 18: /*ignore whitespace*/ +case 18: return 39; break; -case 19: this.popState(); return 18; +case 19: /*ignore whitespace*/ break; case 20: this.popState(); return 18; break; -case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30; +case 21: this.popState(); return 18; break; -case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30; +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; +case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30; break; -case 24: return 32; +case 24: yy_.yytext = yy_.yytext.substr(1); return 28; break; case 25: return 32; break; -case 26: return 31; +case 26: return 32; +break; +case 27: return 31; break; -case 27: return 35; +case 28: return 35; break; -case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35; +case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35; break; -case 29: return 'INVALID'; +case 30: return 'INVALID'; break; -case 30: /*ignore whitespace*/ +case 31: /*ignore whitespace*/ break; -case 31: this.popState(); return 37; +case 32: this.popState(); return 37; break; -case 32: return 5; +case 33: 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}}; +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":[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,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"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) { @@ -656,139 +663,133 @@ Handlebars.parse = function(input) { Handlebars.Parser.yy = Handlebars.AST; return Handlebars.Parser.parse(input); }; - -Handlebars.print = function(ast) { - return new Handlebars.PrintVisitor().accept(ast); -};; +; // lib/handlebars/compiler/ast.js -(function() { - - Handlebars.AST = {}; +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.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; +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); + 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 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); + // 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. - }; + // 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.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); } }; - Handlebars.AST.BlockNode = function(mustache, program, inverse, close) { - verifyMatch(mustache.id, close); - this.type = "block"; - this.mustache = mustache; - this.program = program; - this.inverse = inverse; + verifyMatch(mustache.id, close); + this.type = "block"; + this.mustache = mustache; + this.program = program; + this.inverse = inverse; - if (this.inverse && !this.program) { - this.isInverse = true; - } - }; + if (this.inverse && !this.program) { + this.isInverse = true; + } +}; - Handlebars.AST.ContentNode = function(string) { - this.type = "content"; - this.string = string; - }; +Handlebars.AST.ContentNode = function(string) { + this.type = "content"; + this.string = string; +}; - Handlebars.AST.HashNode = function(pairs) { - this.type = "hash"; - this.pairs = pairs; - }; +Handlebars.AST.HashNode = function(pairs) { + this.type = "hash"; + this.pairs = pairs; +}; - Handlebars.AST.IdNode = function(parts) { - this.type = "ID"; - this.original = parts.join("."); +Handlebars.AST.IdNode = function(parts) { + this.type = "ID"; + this.original = parts.join("."); - var dig = [], depth = 0; + var dig = [], depth = 0; - for(var i=0,l=parts.length; i 0) { throw new Handlebars.Exception("Invalid path: " + this.original); } - else if (part === "..") { depth++; } - else { this.isScoped = true; } - } - else { dig.push(part); } + 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.parts = dig; + this.string = dig.join('.'); + this.depth = depth; - this.stringModeValue = this.string; - }; + // 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; - Handlebars.AST.PartialNameNode = function(name) { - this.type = "PARTIAL_NAME"; - this.name = name; - }; + this.stringModeValue = this.string; +}; - Handlebars.AST.DataNode = function(id) { - this.type = "DATA"; - this.id = id; - }; +Handlebars.AST.PartialNameNode = function(name) { + this.type = "PARTIAL_NAME"; + this.name = name; +}; - Handlebars.AST.StringNode = function(string) { - this.type = "STRING"; - this.string = string; - this.stringModeValue = string; - }; +Handlebars.AST.DataNode = function(id) { + this.type = "DATA"; + this.id = id; +}; - Handlebars.AST.IntegerNode = function(integer) { - this.type = "INTEGER"; - this.integer = integer; - this.stringModeValue = Number(integer); - }; +Handlebars.AST.StringNode = function(string) { + this.type = "STRING"; + this.string = string; + this.stringModeValue = string; +}; - Handlebars.AST.BooleanNode = function(bool) { - this.type = "BOOLEAN"; - this.bool = bool; - this.stringModeValue = bool === "true"; - }; +Handlebars.AST.IntegerNode = function(integer) { + this.type = "INTEGER"; + this.integer = integer; + this.stringModeValue = Number(integer); +}; - Handlebars.AST.CommentNode = function(comment) { - this.type = "comment"; - this.comment = comment; - }; +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; +}; +; // lib/handlebars/utils.js var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; @@ -811,1273 +812,1301 @@ Handlebars.SafeString.prototype.toString = function() { return this.string.toString(); }; -(function() { - var escape = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "`": "`" - }; +var escape = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" +}; - var badChars = /[&<>"'`]/g; - var possible = /[&<>"'`]/; +var badChars = /[&<>"'`]/g; +var possible = /[&<>"'`]/; - var escapeChar = function(chr) { - return escape[chr] || "&"; - }; +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 ""; +Handlebars.Utils = { + extend: function(obj, value) { + for(var key in value) { + if(value.hasOwnProperty(key)) { + obj[key] = value[key]; } + } + }, - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - }, + 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 ""; + } - 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; - } + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = string.toString(); + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + }, + + isEmpty: function(value) { + if (!value && value !== 0) { + return true; + } else if(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() {}; +var Compiler = Handlebars.Compiler = function() {}; +var JavaScriptCompiler = 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. +// 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, +Compiler.prototype = { + compiler: Compiler, - disassemble: function() { - var opcodes = this.opcodes, opcode, out = [], params, param; + disassemble: function() { + var opcodes = this.opcodes, opcode, out = [], params, param; - for (var i=0, l=opcodes.length; i 0) { - this.source[1] = this.source[1] + ", " + locals.join(", "); - } + preamble: function() { + var out = []; - // 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.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.source[1]) { - this.source[1] = "var " + this.source[1].substring(2) + ";"; - } + if (!this.environment.isSimple) { + out.push(", buffer = " + this.initializeBuffer()); + } else { + out.push(""); + } - // Merge children - if (!this.isChild) { - this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; - } + // 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; + }, - if (!this.environment.isSimple) { - this.source.push("return buffer;"); - } + createFunctionContext: function(asObject) { + var locals = this.stackVars.concat(this.registers.list); - var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; + if(locals.length > 0) { + this.source[1] = this.source[1] + ", " + locals.join(", "); + } - for(var i=0, l=this.environment.depths.list.length; i 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); - } - } + this.push('(' + prefix + item + ')'); + } else { + // Prevent modification of the context depth variable. Through replaceStack + if (!/^stack/.test(stack)) { + stack = this.nextStack(); } - }, - isInline: function() { - return this.inlineStack.length; - }, - popStack: function(wrapped) { - var inline = this.isInline(), - item = (inline ? this.inlineStack : this.compileStack).pop(); + this.source.push(stack + " = (" + prefix + item + ");"); + } + return stack; + }, - if (!wrapped && (item instanceof Literal)) { - return item.value; - } else { - if (!inline) { - this.stackSlot--; + 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); } - return item; } - }, + } + }, + isInline: function() { + return this.inlineStack.length; + }, - topStack: function(wrapped) { - var stack = (this.isInline() ? this.inlineStack : this.compileStack), - item = stack[stack.length - 1]; + popStack: function(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); - if (!wrapped && (item instanceof Literal)) { - return item.value; - } else { - return item; + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + if (!inline) { + this.stackSlot--; } - }, + return item; + } + }, - quotedString: function(str) { - return '"' + str - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') + '"'; - }, + topStack: function(wrapped) { + var stack = (this.isInline() ? this.inlineStack : this.compileStack), + item = stack[stack.length - 1]; - setupHelper: function(paramSize, name, missingParams) { - var params = []; - this.setupParams(paramSize, params, missingParams); - var foundHelper = this.nameLookup('helpers', name, 'helper'); + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + return item; + } + }, - return { - params: params, - name: foundHelper, - callParams: ["depth0"].concat(params).join(", "), - helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") - }; - }, + quotedString: function(str) { + return '"' + str + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, - // the params and contexts arguments are passed in arrays - // to fill in - setupParams: function(paramSize, params, useRegister) { - var options = [], contexts = [], types = [], param, inverse, program; + setupHelper: function(paramSize, name, missingParams) { + var params = []; + this.setupParams(paramSize, params, missingParams); + var foundHelper = this.nameLookup('helpers', name, 'helper'); - options.push("hash:" + this.popStack()); + return { + params: params, + name: foundHelper, + callParams: ["depth0"].concat(params).join(", "), + helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") + }; + }, - inverse = this.popStack(); - program = this.popStack(); + // the params and contexts arguments are passed in arrays + // to fill in + setupParams: function(paramSize, params, useRegister) { + var options = [], contexts = [], types = [], param, inverse, program; - // 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"; - } + options.push("hash:" + this.popStack()); - if (!inverse) { - this.context.aliases.self = "this"; - inverse = "self.noop"; - } + inverse = this.popStack(); + program = this.popStack(); - options.push("inverse:" + inverse); - options.push("fn:" + program); + // 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"; } - for(var i=0; i= 1.0.0-rc.3' + 2: '== 1.0.0-rc.3', + 3: '>= 1.0.0-rc.4' }; Handlebars.helpers = {}; Handlebars.partials = {}; +var toString = Object.prototype.toString, + functionType = '[object Function]', + objectType = '[object Object]'; + Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } + Handlebars.Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } }; Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; + if (toString.call(name) === objectType) { + Handlebars.Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } }; Handlebars.registerHelper('helperMissing', function(arg) { @@ -57,13 +71,9 @@ Handlebars.registerHelper('helperMissing', function(arg) { } }); -var toString = Object.prototype.toString, functionType = "[object Function]"; - Handlebars.registerHelper('blockHelperMissing', function(context, options) { var inverse = options.inverse || function() {}, fn = options.fn; - - var ret = ""; var type = toString.call(context); if(type === functionType) { context = context.call(this); } @@ -154,23 +164,17 @@ Handlebars.registerHelper('if', function(context, options) { }); Handlebars.registerHelper('unless', function(context, options) { - var fn = options.fn, inverse = options.inverse; - options.fn = inverse; - options.inverse = fn; - - return Handlebars.helpers['if'].call(this, 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); + if (!Handlebars.Utils.isEmpty(context)) 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); }); - -}(this.Handlebars)); ; // lib/handlebars/utils.js @@ -194,48 +198,61 @@ 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 ""; - } +var escape = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" +}; + +var badChars = /[&<>"'`]/g; +var possible = /[&<>"'`]/; + +var escapeChar = function(chr) { + return escape[chr] || "&"; +}; - 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; +Handlebars.Utils = { + extend: function(obj, value) { + for(var key in value) { + if(value.hasOwnProperty(key)) { + obj[key] = value[key]; } } - }; -})();; + }, + + 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 ""; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = string.toString(); + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + }, + + isEmpty: function(value) { + if (!value && value !== 0) { + return true; + } else if(toString.call(value) === "[object Array]" && value.length === 0) { + return true; + } else { + return false; + } + } +}; +; // lib/handlebars/runtime.js + Handlebars.VM = { template: function(templateSpec) { // Just add water @@ -246,13 +263,11 @@ Handlebars.VM = { 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; + programWrapper = Handlebars.VM.program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); } + return programWrapper; }, programWithDepth: Handlebars.VM.programWithDepth, noop: Handlebars.VM.noop, @@ -284,21 +299,27 @@ Handlebars.VM = { }; }, - programWithDepth: function(fn, data, $depth) { - var args = Array.prototype.slice.call(arguments, 2); + programWithDepth: function(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); - return function(context, options) { + var program = function(context, options) { options = options || {}; return fn.apply(this, [context, options.data || data].concat(args)); }; + program.program = i; + program.depth = args.length; + return program; }, - program: function(fn, data) { - return function(context, options) { + program: function(i, fn, data) { + var program = function(context, options) { options = options || {}; return fn(context, options.data || data); }; + program.program = i; + program.depth = 0; + return program; }, noop: function() { return ""; }, invokePartial: function(partial, name, context, helpers, partials, data) { @@ -319,3 +340,6 @@ Handlebars.VM = { Handlebars.template = Handlebars.VM.template; ; +// lib/handlebars/browser-suffix.js +})(Handlebars); +; From 2b1644df2aa27294b0182ab623478615828c420c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Sun, 19 May 2013 22:50:24 -0400 Subject: [PATCH 2/3] fix failing #test_patching_handlebars --- test/patch/patch.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/test/patch/patch.js b/test/patch/patch.js index 79f10b1..9f65388 100644 --- a/test/patch/patch.js +++ b/test/patch/patch.js @@ -1,12 +1,10 @@ -(function(window) { - var originalLookup = window.Handlebars.JavaScriptCompiler.prototype.nameLookup; +var originalLookup = Handlebars.JavaScriptCompiler.prototype.nameLookup; - window.Handlebars.JavaScriptCompiler.prototype.nameLookup = function(parent, name, type) { - if (type === 'context') { - return '"CALLED PATCH"'; - } - else { - return originalLookup.call(this, parent, name, type); - } - }; -})(this); +Handlebars.JavaScriptCompiler.prototype.nameLookup = function(parent, name, type) { + if (type === 'context') { + return '"CALLED PATCH"'; + } + else { + return originalLookup.call(this, parent, name, type); + } +}; From 3bee4d58fc326de0ca0eb729534f97438ad31fc7 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Sun, 19 May 2013 23:12:10 -0400 Subject: [PATCH 3/3] fix bug in generate_known_helpers_hash was previously undetected due to a bug in Handlebars: https://github.com/wycats/handlebars.js/issues/302 --- lib/handlebars_assets/config.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/handlebars_assets/config.rb b/lib/handlebars_assets/config.rb index 6e31f85..f987d4e 100644 --- a/lib/handlebars_assets/config.rb +++ b/lib/handlebars_assets/config.rb @@ -70,6 +70,7 @@ def template_namespace def generate_known_helpers_hash known_helpers.inject({}) do |hash, helper| hash[helper] = true + hash end end