From b67cb71048cdff8ff21078b1f298a3185046dd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 3 Dec 2019 17:09:50 +0100 Subject: [PATCH] [FIX] slots: propagate vars to correct function closes #529 --- src/qweb/base_directives.ts | 2 +- src/qweb/extensions.ts | 5 ++- src/qweb/qweb.ts | 4 +-- .../__snapshots__/component.test.ts.snap | 36 +++++++++---------- tests/component/component.test.ts | 30 ++++++++++++++++ tests/qweb/__snapshots__/qweb.test.ts.snap | 22 ++++++------ tests/router/__snapshots__/link.test.ts.snap | 2 +- 7 files changed, 67 insertions(+), 34 deletions(-) diff --git a/src/qweb/base_directives.ts b/src/qweb/base_directives.ts index b8b10a3c..f977d736 100644 --- a/src/qweb/base_directives.ts +++ b/src/qweb/base_directives.ts @@ -237,7 +237,7 @@ QWeb.addDirective({ varCode = `{${content}}`; } ctx.addLine( - `this.recursiveFns['${subTemplateName}'].call(this, context, Object.assign({}, extra, {parentNode: c${ctx.parentNode}, fiber: {vars: ${varCode}, scope}}));` + `this.recursiveFns['${subTemplateName}'].call(this, context, Object.assign({}, extra, {parentNode: c${ctx.parentNode}, vars: ${varCode}, fiber: {scope}}));` ); return true; } diff --git a/src/qweb/extensions.ts b/src/qweb/extensions.ts index 76eaf533..8504150a 100644 --- a/src/qweb/extensions.ts +++ b/src/qweb/extensions.ts @@ -210,8 +210,11 @@ QWeb.addDirective({ ctx.addLine(`let ${parentNode}= []`); ctx.addLine(`result = {}`); } + // if we are in a slot of a component, we need to get the vars from the + // parent fiber instead. + const vars = ctx.allowMultipleRoots ? "extra.fiber.parent.vars" : "extra.fiber.vars"; ctx.addLine( - `slot${slotKey}.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: ${parentNode}, vars: extra.vars, parent: extra.parent || owner}));` + `slot${slotKey}.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: ${parentNode}, parent: extra.parent || owner, vars: ${vars}}));` ); if (!ctx.parentNode) { ctx.addLine(`utils.defineProxy(result, ${parentNode}[0]);`); diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts index 2305b448..7598d73f 100644 --- a/src/qweb/qweb.ts +++ b/src/qweb/qweb.ts @@ -371,12 +371,12 @@ export class QWeb extends EventBus { for (let v in parentContext.variables) { let variable = parentContext.variables[v]; if (variable.id) { - ctx.addLine(`let ${variable.id} = extra.fiber.vars.${variable.id}`); + ctx.addLine(`let ${variable.id} = extra.vars.${variable.id};`); } } } if (parentContext) { - ctx.addLine(" Object.assign(context, extra.fiber.scope);"); + ctx.addLine("Object.assign(context, extra.fiber.scope);"); } this._compileNode(elem, ctx); diff --git a/tests/component/__snapshots__/component.test.ts.snap b/tests/component/__snapshots__/component.test.ts.snap index 4906be27..a0be6107 100644 --- a/tests/component/__snapshots__/component.test.ts.snap +++ b/tests/component/__snapshots__/component.test.ts.snap @@ -1293,14 +1293,14 @@ exports[`t-slot directive can define and call slots 2`] = ` c7.push(vn8); const slot9 = this.constructor.slots[context.__owl__.slotId + '_' + 'header']; if (slot9) { - slot9.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c8, vars: extra.vars, parent: extra.parent || owner})); + slot9.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c8, parent: extra.parent || owner, vars: extra.fiber.vars})); } let c10 = [], p10 = {key:10}; var vn10 = h('div', p10, c10); c7.push(vn10); const slot11 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer']; if (slot11) { - slot11.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c10, vars: extra.vars, parent: extra.parent || owner})); + slot11.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c10, parent: extra.parent || owner, vars: extra.fiber.vars})); } return vn7; }" @@ -1311,7 +1311,7 @@ exports[`t-slot directive can define and call slots 3`] = ` ) { var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1324,7 +1324,7 @@ exports[`t-slot directive can define and call slots 4`] = ` ) { var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c6 = [], p6 = {key:6}; var vn6 = h('span', p6, c6); c1.push(vn6); @@ -1337,7 +1337,7 @@ exports[`t-slot directive content is the default slot 1`] = ` ) { var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1350,7 +1350,7 @@ exports[`t-slot directive default slot work with text nodes 1`] = ` ) { var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); c1.push({text: \`sts rocks\`}); }" `; @@ -1360,7 +1360,7 @@ exports[`t-slot directive multiple roots are allowed in a default slot 1`] = ` ) { var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1377,7 +1377,7 @@ exports[`t-slot directive multiple roots are allowed in a named slot 1`] = ` ) { var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1396,7 +1396,7 @@ exports[`t-slot directive refs are properly bound in slots 1`] = ` context.__owl__.refs = context.__owl__.refs || {}; var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c9 = [], p9 = {key:9,on:{}}; var vn9 = h('button', p9, c9); c1.push(vn9); @@ -1421,7 +1421,7 @@ exports[`t-slot directive slots are rendered with proper context 1`] = ` let owner = context; var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c9 = [], p9 = {key:9,on:{}}; var vn9 = h('button', p9, c9); c1.push(vn9); @@ -1441,7 +1441,7 @@ exports[`t-slot directive slots are rendered with proper context, part 2 1`] = ` var vn13 = h('a', p13, c13); const slot14 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; if (slot14) { - slot14.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c13, vars: extra.vars, parent: extra.parent || owner})); + slot14.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c13, parent: extra.parent || owner, vars: extra.fiber.vars})); } return vn13; }" @@ -1520,7 +1520,7 @@ exports[`t-slot directive slots are rendered with proper context, part 2 3`] = ` ) { var h = this.h; let c7 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); c7.push({text: \`User \`}); var _11 = context['user'].name; if (_11 || _11 === 0) { @@ -1539,7 +1539,7 @@ exports[`t-slot directive slots are rendered with proper context, part 3 1`] = ` var vn13 = h('a', p13, c13); const slot14 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; if (slot14) { - slot14.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c13, vars: extra.vars, parent: extra.parent || owner})); + slot14.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c13, parent: extra.parent || owner, vars: extra.fiber.vars})); } return vn13; }" @@ -1619,8 +1619,8 @@ exports[`t-slot directive slots are rendered with proper context, part 3 3`] = ` ) { var h = this.h; let c7 = extra.parentNode; - let _8 = extra.fiber.vars._8 - Object.assign(context, extra.fiber.scope); + let _8 = extra.vars._8; + Object.assign(context, extra.fiber.scope); if (_8 || _8 === 0) { c7.push({text: _8}); } @@ -1672,8 +1672,8 @@ exports[`t-slot directive slots are rendered with proper context, part 4 2`] = ` ) { var h = this.h; let c1 = extra.parentNode; - let _2 = extra.fiber.vars._2 - Object.assign(context, extra.fiber.scope); + let _2 = extra.vars._2; + Object.assign(context, extra.fiber.scope); if (_2 || _2 === 0) { c1.push({text: _2}); } @@ -1691,7 +1691,7 @@ exports[`t-slot directive template can just return a slot 1`] = ` if (slot8) { let children9= [] result = {} - slot8.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: children9, vars: extra.vars, parent: extra.parent || owner})); + slot8.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: children9, parent: extra.parent || owner, vars: extra.fiber.vars})); utils.defineProxy(result, children9[0]); } return result; diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 445edf61..309becfa 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -4423,6 +4423,36 @@ describe("t-slot directive", () => { await nextTick(); // wait for changes triggered in mounted to be applied expect(fixture.innerHTML).toBe("
B0B1
"); }); + + test("slots in slots, with vars", async () => { + class B extends Component { + static template = xml``; + } + class A extends Component { + static template = xml` +
+ + + +
`; + static components = { B }; + } + class Parent extends Component { + static template = xml` +
+ + +

hey

+
+
`; + static components = { A }; + state = { name: "aaron" }; + } + + const parent = new Parent(); + await parent.mount(fixture); + expect(fixture.innerHTML).toBe("

heyaaron

"); + }); }); describe("t-model directive", () => { diff --git a/tests/qweb/__snapshots__/qweb.test.ts.snap b/tests/qweb/__snapshots__/qweb.test.ts.snap index 0d617962..a9f813b6 100644 --- a/tests/qweb/__snapshots__/qweb.test.ts.snap +++ b/tests/qweb/__snapshots__/qweb.test.ts.snap @@ -1023,7 +1023,7 @@ exports[`t-call (template calling recursive template, part 1 1`] = ` c1.push(vn2); c2.push({text: \`hey\`}); if (false) { - this.recursiveFns['__3'].call(this, context, Object.assign({}, extra, {parentNode: c1, fiber: {vars: {}, scope}})); + this.recursiveFns['__3'].call(this, context, Object.assign({}, extra, {parentNode: c1, vars: {}, fiber: {scope}})); } return vn1; }" @@ -1035,7 +1035,7 @@ exports[`t-call (template calling recursive template, part 1 2`] = ` let owner = context; var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + Object.assign(context, extra.fiber.scope); let c4 = [], p4 = {key:4}; var vn4 = h('div', p4, c4); c1.push(vn4); @@ -1044,7 +1044,7 @@ exports[`t-call (template calling recursive template, part 1 2`] = ` c4.push(vn5); c5.push({text: \`hey\`}); if (false) { - this.recursiveFns['__3'].call(this, context, Object.assign({}, extra, {parentNode: c4, fiber: {vars: {}, scope}})); + this.recursiveFns['__3'].call(this, context, Object.assign({}, extra, {parentNode: c4, vars: {}, fiber: {scope}})); } }" `; @@ -1089,7 +1089,7 @@ exports[`t-call (template calling recursive template, part 2 1`] = ` scope.subtree = context.subtree; context.subtree_value = _8[i1]; scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c3, fiber: {vars: {_v0: context['subtree']}, scope}})); + this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c3, vars: {_v0: context['subtree']}, fiber: {scope}})); } } return vn1; @@ -1104,8 +1104,8 @@ exports[`t-call (template calling recursive template, part 2 2`] = ` const scope = Object.create(null); var h = this.h; let c3 = extra.parentNode; - let _v0 = extra.fiber.vars._v0 - Object.assign(context, extra.fiber.scope); + let _v0 = extra.vars._v0; + Object.assign(context, extra.fiber.scope); let c11 = [], p11 = {key:11}; var vn11 = h('div', p11, c11); c3.push(vn11); @@ -1135,7 +1135,7 @@ exports[`t-call (template calling recursive template, part 2 2`] = ` scope.subtree = context.subtree; context.subtree_value = _16[i1]; scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c11, fiber: {vars: {_v0: context['subtree']}, scope}})); + this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c11, vars: {_v0: context['subtree']}, fiber: {scope}})); } }" `; @@ -1180,7 +1180,7 @@ exports[`t-call (template calling recursive template, part 3 1`] = ` scope.subtree = context.subtree; context.subtree_value = _8[i1]; scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c3, fiber: {vars: {_v0: context['subtree']}, scope}})); + this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c3, vars: {_v0: context['subtree']}, fiber: {scope}})); } } return vn1; @@ -1195,8 +1195,8 @@ exports[`t-call (template calling recursive template, part 3 2`] = ` const scope = Object.create(null); var h = this.h; let c3 = extra.parentNode; - let _v0 = extra.fiber.vars._v0 - Object.assign(context, extra.fiber.scope); + let _v0 = extra.vars._v0; + Object.assign(context, extra.fiber.scope); let c11 = [], p11 = {key:11}; var vn11 = h('div', p11, c11); c3.push(vn11); @@ -1226,7 +1226,7 @@ exports[`t-call (template calling recursive template, part 3 2`] = ` scope.subtree = context.subtree; context.subtree_value = _16[i1]; scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c11, fiber: {vars: {_v0: context['subtree']}, scope}})); + this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c11, vars: {_v0: context['subtree']}, fiber: {scope}})); } }" `; diff --git a/tests/router/__snapshots__/link.test.ts.snap b/tests/router/__snapshots__/link.test.ts.snap index a6705bc2..5c351c23 100644 --- a/tests/router/__snapshots__/link.test.ts.snap +++ b/tests/router/__snapshots__/link.test.ts.snap @@ -14,7 +14,7 @@ exports[`Link component can render simple cases 1`] = ` p7.on['click'] = extra.handlers['click' + 7]; const slot8 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; if (slot8) { - slot8.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c7, vars: extra.vars, parent: extra.parent || owner})); + slot8.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c7, parent: extra.parent || owner, vars: extra.fiber.vars})); } return vn7; }"