diff --git a/src/component/directive.ts b/src/component/directive.ts index 23c349ea..0e82373c 100644 --- a/src/component/directive.ts +++ b/src/component/directive.ts @@ -355,7 +355,7 @@ QWeb.addDirective({ // SLOTS const hasSlots = node.childNodes.length; - let scope = hasSlots ? `Object.assign(Object.create(context), scope)` : "undefined"; + let scope = hasSlots ? `utils.combine(context, scope)` : "undefined"; ctx.addIf(`w${componentID}`); diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts index 947680ed..e4381b94 100644 --- a/src/qweb/qweb.ts +++ b/src/qweb/qweb.ts @@ -126,6 +126,13 @@ const UTILS: Utils = { } return expr; }, + combine(context, scope) { + const clone = Object.create(context); + for (let k in scope) { + clone[k] = scope[k]; + } + return clone; + }, shallowEqual, addNameSpace(vnode) { addNS(vnode.data, vnode.children, vnode.sel); diff --git a/tests/component/__snapshots__/component.test.ts.snap b/tests/component/__snapshots__/component.test.ts.snap index 267d4f16..14c5f113 100644 --- a/tests/component/__snapshots__/component.test.ts.snap +++ b/tests/component/__snapshots__/component.test.ts.snap @@ -518,7 +518,7 @@ exports[`other directives with t-component slot setted value (with t-set) not ac w3 = false; } if (w3) { - w3.__updateProps(props3, extra.fiber, Object.assign(Object.create(context), scope)); + w3.__updateProps(props3, extra.fiber, utils.combine(context, scope)); let pvnode = w3.__owl__.pvnode; c1.push(pvnode); } else { @@ -528,7 +528,7 @@ exports[`other directives with t-component slot setted value (with t-set) not ac w3 = new W3(parent, props3); parent.__owl__.cmap['__4__'] = w3.__owl__.id; w3.__owl__.slotId = 1; - let fiber = w3.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w3.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: '__4__', hook: {remove() {},destroy(vn) {w3.destroy();}}}); c1.push(pvnode); w3.__owl__.pvnode = pvnode; diff --git a/tests/component/__snapshots__/slots.test.ts.snap b/tests/component/__snapshots__/slots.test.ts.snap index 7a512eeb..0a2963dc 100644 --- a/tests/component/__snapshots__/slots.test.ts.snap +++ b/tests/component/__snapshots__/slots.test.ts.snap @@ -19,7 +19,7 @@ exports[`t-slot directive can define and call slots 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, Object.assign(Object.create(context), scope)); + w2.__updateProps(props2, extra.fiber, utils.combine(context, scope)); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { @@ -29,7 +29,7 @@ exports[`t-slot directive can define and call slots 1`] = ` w2 = new W2(parent, props2); parent.__owl__.cmap['__3__'] = w2.__owl__.id; w2.__owl__.slotId = 1; - let fiber = w2.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -111,7 +111,7 @@ exports[`t-slot directive can define and call slots using old t-set keyword 1`] w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, Object.assign(Object.create(context), scope)); + w2.__updateProps(props2, extra.fiber, utils.combine(context, scope)); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { @@ -121,7 +121,7 @@ exports[`t-slot directive can define and call slots using old t-set keyword 1`] w2 = new W2(parent, props2); parent.__owl__.cmap['__3__'] = w2.__owl__.id; w2.__owl__.slotId = 1; - let fiber = w2.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -402,7 +402,7 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = ` w8 = false; } if (w8) { - w8.__updateProps(props8, extra.fiber, Object.assign(Object.create(context), scope)); + w8.__updateProps(props8, extra.fiber, utils.combine(context, scope)); let pvnode = w8.__owl__.pvnode; c7.push(pvnode); } else { @@ -412,7 +412,7 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = ` w8 = new W8(parent, props8); parent.__owl__.cmap[k9] = w8.__owl__.id; w8.__owl__.slotId = 1; - let fiber = w8.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w8.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k9, hook: {remove() {},destroy(vn) {w8.destroy();}}}); c7.push(pvnode); w8.__owl__.pvnode = pvnode; @@ -501,7 +501,7 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = ` w8 = false; } if (w8) { - w8.__updateProps(props8, extra.fiber, Object.assign(Object.create(context), scope)); + w8.__updateProps(props8, extra.fiber, utils.combine(context, scope)); let pvnode = w8.__owl__.pvnode; c7.push(pvnode); } else { @@ -511,7 +511,7 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = ` w8 = new W8(parent, props8); parent.__owl__.cmap[k9] = w8.__owl__.id; w8.__owl__.slotId = 1; - let fiber = w8.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w8.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k9, hook: {remove() {},destroy(vn) {w8.destroy();}}}); c7.push(pvnode); w8.__owl__.pvnode = pvnode; @@ -558,7 +558,7 @@ exports[`t-slot directive slots are rendered with proper context, part 4 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, Object.assign(Object.create(context), scope)); + w2.__updateProps(props2, extra.fiber, utils.combine(context, scope)); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { @@ -568,7 +568,7 @@ exports[`t-slot directive slots are rendered with proper context, part 4 1`] = ` w2 = new W2(parent, props2); parent.__owl__.cmap['__3__'] = w2.__owl__.id; w2.__owl__.slotId = 1; - let fiber = w2.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -593,6 +593,94 @@ exports[`t-slot directive slots are rendered with proper context, part 4 2`] = ` }" `; +exports[`t-slot directive slots in t-foreach in t-foreach 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"__template__2\\" + let utils = this.constructor.utils; + let QWeb = this.constructor; + let parent = context; + let scope = Object.create(context); + let h = this.h; + let c1 = [], p1 = {key:1}; + let vn1 = h('div', p1, c1); + let _2 = scope['tree']; + if (!_2) { throw new Error('QWeb error: Invalid loop expression')} + let _3 = _4 = _2; + if (!(_2 instanceof Array)) { + _3 = Object.keys(_2); + _4 = Object.values(_2); + } + let _length3 = _3.length; + let _origScope5 = scope; + scope = Object.create(scope); + for (let i1 = 0; i1 < _length3; i1++) { + scope.node1_first = i1 === 0 + scope.node1_last = i1 === _length3 - 1 + scope.node1_index = i1 + scope.node1 = _3[i1] + scope.node1_value = _4[i1] + let key1 = scope['node1'].key; + let c6 = [], p6 = {key:\`\${key1}_6\`}; + let vn6 = h('div', p6, c6); + c1.push(vn6); + let _7 = scope['node1'].value; + if (_7 != null) { + c6.push({text: _7}); + } + let c8 = [], p8 = {key:\`\${key1}_8\`}; + let vn8 = h('ul', p8, c8); + c1.push(vn8); + let _9 = scope['node1'].nodes; + if (!_9) { throw new Error('QWeb error: Invalid loop expression')} + let _10 = _11 = _9; + if (!(_9 instanceof Array)) { + _10 = Object.keys(_9); + _11 = Object.values(_9); + } + let _length10 = _10.length; + let _origScope12 = scope; + scope = Object.create(scope); + for (let i2 = 0; i2 < _length10; i2++) { + scope.node2_first = i2 === 0 + scope.node2_last = i2 === _length10 - 1 + scope.node2_index = i2 + scope.node2 = _10[i2] + scope.node2_value = _11[i2] + let key2 = scope['node2'].key; + // Component 'Child' + let k14 = \`__14__\${key1}__\${key2}__\`; + let w13 = k14 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k14]] : false; + let props13 = {}; + if (w13 && w13.__owl__.currentFiber && !w13.__owl__.vnode) { + w13.destroy(); + w13 = false; + } + if (w13) { + w13.__updateProps(props13, extra.fiber, utils.combine(context, scope)); + let pvnode = w13.__owl__.pvnode; + c8.push(pvnode); + } else { + let componentKey13 = \`Child\`; + let W13 = scope['Child'] || context.constructor.components[componentKey13] || QWeb.components[componentKey13]; + if (!W13) {throw new Error('Cannot find the definition of component \\"' + componentKey13 + '\\"')} + w13 = new W13(parent, props13); + parent.__owl__.cmap[k14] = w13.__owl__.id; + w13.__owl__.slotId = 1; + let fiber = w13.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let pvnode = h('dummy', {key: k14, hook: {remove() {},destroy(vn) {w13.destroy();}}}); + c8.push(pvnode); + w13.__owl__.pvnode = pvnode; + } + w13.__owl__.parentLastFiberId = extra.fiber.id; + } + scope = _origScope12; + } + scope = _origScope5; + return vn1; +}" +`; + exports[`t-slot directive t-set t-value in a slot 1`] = ` "function anonymous(context, extra ) { diff --git a/tests/component/slots.test.ts b/tests/component/slots.test.ts index ef679e73..cc197684 100644 --- a/tests/component/slots.test.ts +++ b/tests/component/slots.test.ts @@ -325,6 +325,70 @@ describe("t-slot directive", () => { expect(QWeb.slots["1_default"].toString()).toMatchSnapshot(); }); + test("slots in t-foreach in t-foreach", async () => { + class Child extends Component { + static template = xml` +