From 5a164d0ca5a4dbda07b38fd55199bb65dfeda55e Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sat, 31 Dec 2016 00:32:03 +0100 Subject: [PATCH] Fix for #1252: Using @partial-block twice in a template not possible Fixes #1252 - This fix treats partial-blocks more like closures and uses the closure-context of the "invokePartial"-function to store the @partial-block for the partial. - Adds a tes for the fix --- lib/handlebars/runtime.js | 24 ++++++++++++++---------- spec/partials.js | 7 +++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 103b5afab..5a79b7103 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -210,12 +210,7 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa export function resolvePartial(partial, context, options) { if (!partial) { if (options.name === '@partial-block') { - let data = options.data; - while (data['partial-block'] === noop) { - data = data._parent; - } - partial = data['partial-block']; - data['partial-block'] = noop; + partial = options.data['partial-block']; } else { partial = options.partials[options.name]; } @@ -228,6 +223,8 @@ export function resolvePartial(partial, context, options) { } export function invokePartial(partial, context, options) { + // Use the current closure context to save the partial-block if this partial + const currentPartialBlock = options.data && options.data['partial-block']; options.partial = true; if (options.ids) { options.data.contextPath = options.ids[0] || options.data.contextPath; @@ -236,10 +233,17 @@ export function invokePartial(partial, context, options) { let partialBlock; if (options.fn && options.fn !== noop) { options.data = createFrame(options.data); - partialBlock = options.data['partial-block'] = options.fn; - - if (partialBlock.partials) { - options.partials = Utils.extend({}, options.partials, partialBlock.partials); + // Wrapper function to get access to currentPartialBlock from the closure + let fn = options.fn; + partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options) { + // Restore the partial-block from the closure for the execution of the block + // i.e. the part inside the block of the partial call. + options.data = createFrame(options.data); + options.data['partial-block'] = currentPartialBlock; + return fn(context, options); + }; + if (fn.partials) { + options.partials = Utils.extend({}, options.partials, fn.partials); } } diff --git a/spec/partials.js b/spec/partials.js index d6baba504..cbec58863 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -249,6 +249,13 @@ describe('partials', function() { true, 'success'); }); + it('should be able to render the partial-block twice', function() { + shouldCompileToWithPartials( + '{{#> dude}}success{{/dude}}', + [{}, {}, {dude: '{{> @partial-block }} {{> @partial-block }}'}], + true, + 'success success'); + }); it('should render block from partial with context', function() { shouldCompileToWithPartials( '{{#> dude}}{{value}}{{/dude}}',