summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkpdecker <kpdecker@gmail.com>2015-08-03 15:15:09 -0500
committerkpdecker <kpdecker@gmail.com>2015-08-03 15:15:09 -0500
commit279e038ba7ff7e5966a60e36d326e2d4c310f0c6 (patch)
treefe96ba921f7f8dde4492df5ecbb761d8290f837f
parent1c08771215af7377fb8f33a26f64b3af0e06c168 (diff)
downloadhandlebars.js-279e038ba7ff7e5966a60e36d326e2d4c310f0c6.zip
handlebars.js-279e038ba7ff7e5966a60e36d326e2d4c310f0c6.tar.gz
handlebars.js-279e038ba7ff7e5966a60e36d326e2d4c310f0c6.tar.bz2
Avoid depth creation when context remains the same
Creating a new depth value seems to confuse users as they don’t expect things like `if` to require multiple `..` to break out of. With the change, we avoid pushing a context to the depth list if it’s already on the top of the stack, effectively removing cases where `.` and `..` are the same object and multiple `..` references are required. This is a breaking change and all templates that utilize `..` will have to check their usage and confirm that this does not break desired behavior. Helper authors now need to take care to return the same context value whenever it is conceptually the same and to avoid behaviors that may execute children under the current context in some situations and under different contexts under other situations. Fixes #1028
-rw-r--r--lib/handlebars/runtime.js13
-rw-r--r--spec/builtins.js5
-rw-r--r--spec/helpers.js15
3 files changed, 30 insertions, 3 deletions
diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js
index d41b42a..bc12fc9 100644
--- a/lib/handlebars/runtime.js
+++ b/lib/handlebars/runtime.js
@@ -135,7 +135,11 @@ export function template(templateSpec, env) {
let depths,
blockParams = templateSpec.useBlockParams ? [] : undefined;
if (templateSpec.useDepths) {
- depths = options.depths ? [context].concat(options.depths) : [context];
+ if (options.depths) {
+ depths = context !== options.depths[0] ? [context].concat(depths) : options.depths;
+ } else {
+ depths = [context];
+ }
}
return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
@@ -170,12 +174,17 @@ export function template(templateSpec, env) {
export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
function prog(context, options = {}) {
+ let currentDepths = depths;
+ if (depths && context !== depths[0]) {
+ currentDepths = [context].concat(depths);
+ }
+
return fn.call(container,
context,
container.helpers, container.partials,
options.data || data,
blockParams && [options.blockParams].concat(blockParams),
- depths && [context].concat(depths));
+ currentDepths);
}
prog.program = i;
prog.depth = depths ? depths.length : 0;
diff --git a/spec/builtins.js b/spec/builtins.js
index bcacf59..a7f6204 100644
--- a/spec/builtins.js
+++ b/spec/builtins.js
@@ -32,6 +32,11 @@ describe('builtin helpers', function() {
shouldCompileTo(string, {goodbye: function() {return this.foo; }, world: 'world'}, 'cruel world!',
'if with function does not show the contents when returns undefined');
});
+
+ it('should not change the depth list', function() {
+ var string = '{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}';
+ shouldCompileTo(string, {foo: {goodbye: true}, world: 'world'}, 'GOODBYE cruel world!');
+ });
});
describe('#with', function() {
diff --git a/spec/helpers.js b/spec/helpers.js
index 00bcb79..94e503f 100644
--- a/spec/helpers.js
+++ b/spec/helpers.js
@@ -38,6 +38,19 @@ describe('helpers', function() {
shouldCompileTo(string, [{}, helpers], ' {{{{b}}}} {{{{/b}}}} ', 'raw block helper should get nested raw block as raw content');
});
+ it('helper block with identical context', function() {
+ var string = '{{#goodbyes}}{{name}}{{/goodbyes}}';
+ var hash = {name: 'Alan'};
+ var helpers = {goodbyes: function(options) {
+ var out = '';
+ var byes = ['Goodbye', 'goodbye', 'GOODBYE'];
+ for (var i = 0, j = byes.length; i < j; i++) {
+ out += byes[i] + ' ' + options.fn(this) + '! ';
+ }
+ return out;
+ }};
+ shouldCompileTo(string, [hash, helpers], 'Goodbye Alan! goodbye Alan! GOODBYE Alan! ');
+ });
it('helper block with complex lookup expression', function() {
var string = '{{#goodbyes}}{{../name}}{{/goodbyes}}';
var hash = {name: 'Alan'};
@@ -45,7 +58,7 @@ describe('helpers', function() {
var out = '';
var byes = ['Goodbye', 'goodbye', 'GOODBYE'];
for (var i = 0, j = byes.length; i < j; i++) {
- out += byes[i] + ' ' + options.fn(this) + '! ';
+ out += byes[i] + ' ' + options.fn({}) + '! ';
}
return out;
}};