summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler/javascript-compiler.js
diff options
context:
space:
mode:
authorkpdecker <kpdecker@gmail.com>2014-12-26 00:31:57 -0600
committerkpdecker <kpdecker@gmail.com>2014-12-26 00:31:57 -0600
commit396795c983273bb5ca4dc67ddc74eb12f00bf110 (patch)
tree8fa69873ed195fc7b0aa1c909373fa7ccac6785a /lib/handlebars/compiler/javascript-compiler.js
parent9e907e67854ea1ae208fe061452a9c9e2ce9468b (diff)
downloadhandlebars.js-396795c983273bb5ca4dc67ddc74eb12f00bf110.zip
handlebars.js-396795c983273bb5ca4dc67ddc74eb12f00bf110.tar.gz
handlebars.js-396795c983273bb5ca4dc67ddc74eb12f00bf110.tar.bz2
Implement block parameters
Fixes #907
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r--lib/handlebars/compiler/javascript-compiler.js82
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;
},