From 84873c8a22cb2e04fb8269d66047ed978282f201 Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Mon, 7 Oct 2013 10:45:13 -0700 Subject: [PATCH] fix argument binding with dots in Spacebars.index --- packages/spacebars-tests/template_tests.html | 4 ++ packages/spacebars-tests/template_tests.js | 55 ++++++++++++++++++++ packages/spacebars/spacebars.js | 26 +++++---- packages/spacebars/spacebars_tests.js | 9 ++++ 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/packages/spacebars-tests/template_tests.html b/packages/spacebars-tests/template_tests.html index a414eb9725..e183c61ec1 100644 --- a/packages/spacebars-tests/template_tests.html +++ b/packages/spacebars-tests/template_tests.html @@ -91,3 +91,7 @@ content {{/if}} + + diff --git a/packages/spacebars-tests/template_tests.js b/packages/spacebars-tests/template_tests.js index 17768aeb60..e7e011c2e3 100644 --- a/packages/spacebars-tests/template_tests.js +++ b/packages/spacebars-tests/template_tests.js @@ -301,3 +301,58 @@ Tinytest.add("spacebars - templates - block helper component with three helper a Deps.flush(); test.equal(div.innerHTML.trim(), ""); }); + +Tinytest.add("spacebars - templates - block helper with dotted arg", function (test) { + var tmpl = Template.spacebars_template_test_block_helper_dotted_arg; + var R1 = ReactiveVar(1); + var R2 = ReactiveVar(10); + var R3 = ReactiveVar(100); + + var initCount = 0; + tmpl.foo = Template.spacebars_template_test_bracketed_this.extend({ + init: function () { initCount++; } + }); + tmpl.bar = function () { + return { + r1: R1.get(), + baz: function (r3) { + return this.r1 + R2.get() + r3; + } + }; + }; + tmpl.qux = function () { return R3.get(); }; + + var div = renderToDiv(tmpl); + test.equal(div.innerHTML, "[111]"); + test.equal(initCount, 1); + + R1.set(2); + Deps.flush(); + test.equal(div.innerHTML, "[112]"); + test.equal(initCount, 1); + + R2.set(20); + Deps.flush(); + test.equal(div.innerHTML, "[122]"); + test.equal(initCount, 1); + + R3.set(200); + Deps.flush(); + test.equal(div.innerHTML, "[222]"); + test.equal(initCount, 1); + + R2.set(30); + Deps.flush(); + test.equal(div.innerHTML, "[232]"); + test.equal(initCount, 1); + + R1.set(3); + Deps.flush(); + test.equal(div.innerHTML, "[233]"); + test.equal(initCount, 1); + + R3.set(300); + Deps.flush(); + test.equal(div.innerHTML, "[333]"); + test.equal(initCount, 1); +}); \ No newline at end of file diff --git a/packages/spacebars/spacebars.js b/packages/spacebars/spacebars.js index 8cc4bbf940..e91262d606 100644 --- a/packages/spacebars/spacebars.js +++ b/packages/spacebars/spacebars.js @@ -938,21 +938,19 @@ Spacebars.compile = function (inputString, options) { // of `foo.bar.baz` that allows safe indexing of `null` and // indexing of functions to get other functions. // -// `foo` must be one of three types of values, and the return value -// is also one of these three types: -// * Falsy values -// * Non-functions (i.e. constants) -// * Fully "bound" functions, which take no arguments and ignore `this` +// In `Spacebars.index(foo, "bar")`, `foo` is assumed to be either +// a non-function value or a "fully-bound" function wrapping a value, +// taking no arguments and ignoring `this`. // -// `Spacebars.index("foo", bar)` behaves as follows: +// `Spacebars.index(foo, "bar")` behaves as follows: // // * If `foo` is falsy, `foo` is returned. // // * If either `foo` is a function or `foo.bar` is, then a new -// fully-bound function is returned that, when called, will calculate -// a "safe" version of `foo().bar()`, where "dot" on a falsy value -// just returns the falsy value, and function calls are a no-op on -// non-functions. +// function is returned that, when called on arguments `args...`, +// calculates a "safe" version of `foo().bar(args...)`, +// where "dot" on a falsy value just returns the falsy value, +// and function calls are a no-op on non-functions. // // * Otherwise, the non-function `foo.bar` is returned. Spacebars.index = function (value, id1/*, id2, ...*/) { @@ -973,19 +971,19 @@ Spacebars.index = function (value, id1/*, id2, ...*/) { var result = value[id1]; if (typeof result !== 'function') return result; - return function () { - return result.call(value); + return function (/*arguments*/) { + return result.apply(value, arguments); }; } - return function () { + return function (/*arguments*/) { var foo = value(); if (! foo) return foo; // falsy, don't index, pass through var bar = foo[id1]; if (typeof bar !== 'function') return bar; - return bar.call(foo); + return bar.apply(foo, arguments); }; }; diff --git a/packages/spacebars/spacebars_tests.js b/packages/spacebars/spacebars_tests.js index 25f472cac1..3893521edf 100644 --- a/packages/spacebars/spacebars_tests.js +++ b/packages/spacebars/spacebars_tests.js @@ -521,4 +521,13 @@ Tinytest.add("spacebars - Spacebars.index", function (test) { test.equal(Spacebars.index(0, 'abc', 'def'), 0); test.equal(Spacebars.index(function () { return null; }, 'abc', 'def')(), null); test.equal(Spacebars.index(function () { return 0; }, 'abc', 'def')(), 0); + + // test that in `foo.bar`, `bar` may be a function that takes arguments. + test.equal(Spacebars.index( + { one: 1, inc: function (x) { return this.one + x; } }, 'inc')(6), 7); + test.equal(Spacebars.index( + function () { + return { one: 1, inc: function (x) { return this.one + x; } }; + }, 'inc')(8), 9); + });