diff options
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r-- | lib/handlebars/compiler/javascript-compiler.js | 82 |
1 files changed, 57 insertions, 25 deletions
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 3e4f5e1..9f40792 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -77,10 +77,12 @@ JavaScriptCompiler.prototype = { this.hashes = []; this.compileStack = []; this.inlineStack = []; + this.blockParams = []; this.compileChildren(environment, options); this.useDepths = this.useDepths || environment.useDepths || this.options.compat; + this.useBlockParams = this.useBlockParams || environment.useBlockParams; var opcodes = environment.opcodes, opcode, @@ -127,6 +129,9 @@ JavaScriptCompiler.prototype = { if (this.useDepths) { ret.useDepths = true; } + if (this.useBlockParams) { + ret.useBlockParams = true; + } if (this.options.compat) { ret.compat = true; } @@ -186,6 +191,9 @@ JavaScriptCompiler.prototype = { var params = ["depth0", "helpers", "partials", "data"]; + if (this.useBlockParams || this.useDepths) { + params.push('blockParams'); + } if (this.useDepths) { params.push('depths'); } @@ -385,9 +393,7 @@ JavaScriptCompiler.prototype = { // Looks up the value of `name` on the current context and pushes // it onto the stack. lookupOnContext: function(parts, falsy, scoped) { - /*jshint -W083 */ - var i = 0, - len = parts.length; + var i = 0; if (!scoped && this.options.compat && !this.lastContext) { // The depthed query is expected to handle the undefined logic for the root level that @@ -397,19 +403,21 @@ JavaScriptCompiler.prototype = { this.pushContext(); } - for (; i < len; i++) { - this.replaceStack(function(current) { - var lookup = this.nameLookup(current, parts[i], 'context'); - // We want to ensure that zero and false are handled properly if the context (falsy flag) - // needs to have the special handling for these values. - if (!falsy) { - return [' != null ? ', lookup, ' : ', current]; - } else { - // Otherwise we can use generic falsy handling - return [' && ', lookup]; - } - }); - } + this.resolvePath('context', parts, i, falsy); + }, + + // [lookupBlockParam] + // + // On stack, before: ... + // On stack, after: blockParam[name], ... + // + // Looks up the value of `parts` on the given block param and pushes + // it onto the stack. + lookupBlockParam: function(blockParamId, parts) { + this.useBlockParams = true; + + this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); + this.resolvePath('context', parts, 1); }, // [lookupData] @@ -426,9 +434,23 @@ JavaScriptCompiler.prototype = { this.pushStackLiteral('this.data(data, ' + depth + ')'); } - for (var i = 0, len = parts.length; i < len; i++) { + this.resolvePath('data', parts, 0, true); + }, + + resolvePath: function(type, parts, i, falsy) { + /*jshint -W083 */ + var len = parts.length; + for (; i < len; i++) { this.replaceStack(function(current) { - return [' && ', this.nameLookup(current, parts[i], 'data')]; + var lookup = this.nameLookup(current, parts[i], type); + // We want to ensure that zero and false are handled properly if the context (falsy flag) + // needs to have the special handling for these values. + if (!falsy) { + return [' != null ? ', lookup, ' : ', current]; + } else { + // Otherwise we can use generic falsy handling + return [' && ', lookup]; + } }); } }, @@ -661,8 +683,12 @@ JavaScriptCompiler.prototype = { hash.values[key] = value; }, - pushId: function(type, name) { - if (type === 'PathExpression') { + pushId: function(type, name, child) { + if (type === 'BlockParam') { + this.pushStackLiteral( + 'blockParams[' + name[0] + '].path[' + name[1] + ']' + + (child ? ' + ' + JSON.stringify('.' + child) : '')); + } else if (type === 'PathExpression') { this.pushString(name); } else if (type === 'SubExpression') { this.pushStackLiteral('true'); @@ -693,11 +719,13 @@ JavaScriptCompiler.prototype = { this.context.environments[index] = child; this.useDepths = this.useDepths || compiler.useDepths; + this.useBlockParams = this.useBlockParams || compiler.useBlockParams; } else { child.index = index; child.name = 'program' + index; this.useDepths = this.useDepths || child.useDepths; + this.useBlockParams = this.useBlockParams || child.useBlockParams; } } }, @@ -712,11 +740,12 @@ JavaScriptCompiler.prototype = { programExpression: function(guid) { var child = this.environment.children[guid], - useDepths = this.useDepths; + programParams = [child.index, 'data', child.blockParams]; - var programParams = [child.index, 'data']; - - if (useDepths) { + if (this.useBlockParams || this.useDepths) { + programParams.push('blockParams'); + } + if (this.useDepths) { programParams.push('depths'); } @@ -943,7 +972,10 @@ JavaScriptCompiler.prototype = { } if (this.options.data) { - options.data = "data"; + options.data = 'data'; + } + if (this.useBlockParams) { + options.blockParams = 'blockParams'; } return options; }, |