Merge pull request #634 from wycats/name-option
It would be great to have the helper name passed to `blockHelperMissing`
This commit is contained in:
@@ -49,11 +49,13 @@ HandlebarsEnvironment.prototype = {
|
||||
};
|
||||
|
||||
function registerDefaultHelpers(instance) {
|
||||
instance.registerHelper('helperMissing', function(arg) {
|
||||
if(arguments.length === 2) {
|
||||
instance.registerHelper('helperMissing', function(/* [args, ]options */) {
|
||||
if(arguments.length === 1) {
|
||||
// A missing field in a {{foo}} constuct.
|
||||
return undefined;
|
||||
} else {
|
||||
throw new Exception("Missing helper: '" + arg + "'");
|
||||
// Someone is actually trying to call something, blow up.
|
||||
throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ Compiler.prototype = {
|
||||
this.opcode('pushProgram', program);
|
||||
this.opcode('pushProgram', inverse);
|
||||
this.opcode('emptyHash');
|
||||
this.opcode('blockValue');
|
||||
this.opcode('blockValue', sexpr.id.original);
|
||||
} else {
|
||||
this.ambiguousSexpr(sexpr, program, inverse);
|
||||
|
||||
|
||||
@@ -224,11 +224,11 @@ JavaScriptCompiler.prototype = {
|
||||
// `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and
|
||||
// replace it on the stack with the result of properly
|
||||
// invoking blockHelperMissing.
|
||||
blockValue: function() {
|
||||
blockValue: function(name) {
|
||||
this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
|
||||
|
||||
var params = ["depth0"];
|
||||
this.setupParams(0, params);
|
||||
this.setupParams(name, 0, params);
|
||||
|
||||
this.replaceStack(function(current) {
|
||||
params.splice(1, 0, current);
|
||||
@@ -247,7 +247,7 @@ JavaScriptCompiler.prototype = {
|
||||
|
||||
// We're being a bit cheeky and reusing the options value from the prior exec
|
||||
var params = ["depth0"];
|
||||
this.setupParams(0, params, true);
|
||||
this.setupParams('', 0, params, true);
|
||||
|
||||
this.flushInline();
|
||||
|
||||
@@ -504,20 +504,15 @@ JavaScriptCompiler.prototype = {
|
||||
this.context.aliases.helperMissing = 'helpers.helperMissing';
|
||||
this.useRegister('helper');
|
||||
|
||||
var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
|
||||
var helper = this.setupHelper(paramSize, name);
|
||||
var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
|
||||
|
||||
var lookup = 'helper = ' + helper.name + ' || ' + nonHelper;
|
||||
var lookup = 'helper = ' + helper.name + ' || ' + nonHelper + ' || helperMissing';
|
||||
if (helper.paramsInit) {
|
||||
lookup += ',' + helper.paramsInit;
|
||||
}
|
||||
|
||||
this.push(
|
||||
'('
|
||||
+ lookup
|
||||
+ ',helper '
|
||||
+ '? helper.call(' + helper.callParams + ') '
|
||||
+ ': helperMissing.call(' + helper.helperMissingParams + '))');
|
||||
this.push('(' + lookup + ',helper.call(' + helper.callParams + '))');
|
||||
|
||||
// Always flush subexpressions. This is both to prevent the compounding size issue that
|
||||
// occurs when the code has to be duplicated for inlining and also to prevent errors
|
||||
@@ -824,23 +819,23 @@ JavaScriptCompiler.prototype = {
|
||||
.replace(/\u2029/g, '\\u2029') + '"';
|
||||
},
|
||||
|
||||
setupHelper: function(paramSize, name, missingParams) {
|
||||
setupHelper: function(paramSize, name, blockHelper) {
|
||||
var params = [],
|
||||
paramsInit = this.setupParams(paramSize, params, missingParams);
|
||||
paramsInit = this.setupParams(name, paramSize, params, blockHelper);
|
||||
var foundHelper = this.nameLookup('helpers', name, 'helper');
|
||||
|
||||
return {
|
||||
params: params,
|
||||
paramsInit: paramsInit,
|
||||
name: foundHelper,
|
||||
callParams: ["depth0"].concat(params).join(", "),
|
||||
helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
|
||||
callParams: ["depth0"].concat(params).join(", ")
|
||||
};
|
||||
},
|
||||
|
||||
setupOptions: function(paramSize, params) {
|
||||
setupOptions: function(helper, paramSize, params) {
|
||||
var options = [], contexts = [], types = [], param, inverse, program;
|
||||
|
||||
options.push("name:" + this.quotedString(helper));
|
||||
options.push("hash:" + this.popStack());
|
||||
|
||||
if (this.stringParams) {
|
||||
@@ -892,8 +887,8 @@ JavaScriptCompiler.prototype = {
|
||||
|
||||
// the params and contexts arguments are passed in arrays
|
||||
// to fill in
|
||||
setupParams: function(paramSize, params, useRegister) {
|
||||
var options = '{' + this.setupOptions(paramSize, params).join(',') + '}';
|
||||
setupParams: function(helperName, paramSize, params, useRegister) {
|
||||
var options = '{' + this.setupOptions(helperName, paramSize, params).join(',') + '}';
|
||||
|
||||
if (useRegister) {
|
||||
this.useRegister('options');
|
||||
|
||||
+40
-3
@@ -362,9 +362,9 @@ describe('helpers', function() {
|
||||
var context = { hello: "Hello", world: "world" };
|
||||
|
||||
var helpers = {
|
||||
helperMissing: function(helper, context) {
|
||||
if(helper === "link_to") {
|
||||
return new Handlebars.SafeString("<a>" + context + "</a>");
|
||||
helperMissing: function(mesg, options) {
|
||||
if(options.name === "link_to") {
|
||||
return new Handlebars.SafeString("<a>" + mesg + "</a>");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -436,6 +436,43 @@ describe('helpers', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('name field', function() {
|
||||
var context = {};
|
||||
var helpers = {
|
||||
blockHelperMissing: function() {
|
||||
return 'missing: ' + arguments[arguments.length-1].name;
|
||||
},
|
||||
helper: function() {
|
||||
return 'ran: ' + arguments[arguments.length-1].name;
|
||||
}
|
||||
};
|
||||
|
||||
it('should include in ambiguous mustache calls', function() {
|
||||
shouldCompileTo('{{helper}}', [context, helpers], 'ran: helper');
|
||||
});
|
||||
it('should include in helper mustache calls', function() {
|
||||
shouldCompileTo('{{helper 1}}', [context, helpers], 'ran: helper');
|
||||
});
|
||||
it('should include in ambiguous block calls', function() {
|
||||
shouldCompileTo('{{#helper}}{{/helper}}', [context, helpers], 'ran: helper');
|
||||
});
|
||||
it('should include in simple block calls', function() {
|
||||
shouldCompileTo('{{#./helper}}{{/./helper}}', [context, helpers], 'missing: ./helper');
|
||||
});
|
||||
it('should include in helper block calls', function() {
|
||||
shouldCompileTo('{{#helper 1}}{{/helper}}', [context, helpers], 'ran: helper');
|
||||
});
|
||||
it('should include in known helper calls', function() {
|
||||
var template = CompilerContext.compile("{{helper}}", {knownHelpers: {'helper': true}, knownHelpersOnly: true});
|
||||
|
||||
equal(template({}, {helpers: helpers}), 'ran: helper');
|
||||
});
|
||||
|
||||
it('should include full id', function() {
|
||||
shouldCompileTo('{{#foo.helper}}{{/foo.helper}}', [{foo: {}}, helpers], 'missing: foo.helper');
|
||||
});
|
||||
});
|
||||
|
||||
describe('name conflicts', function() {
|
||||
it("helpers take precedence over same-named context properties", function() {
|
||||
var template = CompilerContext.compile("{{goodbye}} {{cruel world}}");
|
||||
|
||||
Reference in New Issue
Block a user