From 95aaa99312d19e5d7fac866dead4d484b000131b Mon Sep 17 00:00:00 2001 From: Avital Oliver Date: Sat, 19 Apr 2014 00:21:01 -0700 Subject: [PATCH] Fix {{#with}} over a data context that is mutated In `Spacebars.With` we embox the data context. This commit makes that emboxing happen modulo `safeEquals`. So now if you {{#with}} over a helper that returns an object, any time that helper gets invalidated we re-run the computations in the block. Fixes #2046 (though notably that example mutates the data context from within a helper, which could lead to other types of unintended behavior; it's probably in this particular example -- the data context just gets added properties) --- packages/spacebars-tests/template_tests.html | 6 +++++ packages/spacebars-tests/template_tests.js | 23 +++++++++++++++++++- packages/spacebars/spacebars-runtime.js | 2 +- packages/ui/builtins.js | 4 ++-- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/spacebars-tests/template_tests.html b/packages/spacebars-tests/template_tests.html index 05256a6bb5..dbec7e2fbb 100644 --- a/packages/spacebars-tests/template_tests.html +++ b/packages/spacebars-tests/template_tests.html @@ -712,3 +712,9 @@ Hi there! {{bar}} --}} + + diff --git a/packages/spacebars-tests/template_tests.js b/packages/spacebars-tests/template_tests.js index e6b570e6fb..93f1b646ff 100644 --- a/packages/spacebars-tests/template_tests.js +++ b/packages/spacebars-tests/template_tests.js @@ -1877,7 +1877,7 @@ Tinytest.add( } ); -Tinytest.add("spacebars - templates - UI.toHTML", function (test) { +Tinytest.add("spacebars - template - UI.toHTML", function (test) { // run once, verifying that autoruns are stopped var once = function (tmplToRender, tmplForHelper, helper, val) { var count = 0; @@ -1919,3 +1919,24 @@ Tinytest.add( test.equal(canonicalizeHtml(div.innerHTML), ''); } ); + +// Originally reported at https://github.com/meteor/meteor/issues/2046 +Tinytest.add( + "spacebars - template - {{#with}} with mutated data context", + function (test) { + var tmpl = Template.spacebars_test_with_mutated_data_context; + var foo = {value: 0}; + var dep = new Deps.Dependency; + tmpl.foo = function () { + dep.depend(); + return foo; + }; + + var div = renderToDiv(tmpl); + test.equal(canonicalizeHtml(div.innerHTML), '0'); + + foo.value = 1; + dep.changed(); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), '1'); + }); diff --git a/packages/spacebars/spacebars-runtime.js b/packages/spacebars/spacebars-runtime.js index 120356753b..59c2f37a47 100644 --- a/packages/spacebars/spacebars-runtime.js +++ b/packages/spacebars/spacebars-runtime.js @@ -216,7 +216,7 @@ Spacebars.dot = function (value, id1/*, id2, ...*/) { Spacebars.With = function (argFunc, contentBlock, elseContentBlock) { return UI.Component.extend({ init: function () { - this.v = UI.emboxValue(argFunc); + this.v = UI.emboxValue(argFunc, UI.safeEquals); }, render: function () { return UI.If(this.v, UI.With(this.v, contentBlock), elseContentBlock); diff --git a/packages/ui/builtins.js b/packages/ui/builtins.js index a97bead067..2ba0da6f48 100644 --- a/packages/ui/builtins.js +++ b/packages/ui/builtins.js @@ -38,7 +38,7 @@ UI.Unless = function (argFunc, contentBlock, elseContentBlock) { // (Because then, they may be equal references to an object that was mutated, // and we'll never know. We save only a reference to the old object; we don't // do any deep-copying or diffing.) -var safeEquals = function (a, b) { +UI.safeEquals = function (a, b) { if (a !== b) return false; else @@ -67,7 +67,7 @@ UI.With = function (argFunc, contentBlock) { }; block.init = function () { - this.data = UI.emboxValue(argFunc, safeEquals); + this.data = UI.emboxValue(argFunc, UI.safeEquals); }; block.materialized = function () {