diff --git a/doc/component.md b/doc/component.md index 4905e206..0c4acdaf 100644 --- a/doc/component.md +++ b/doc/component.md @@ -928,6 +928,21 @@ is not allowed. A workaround could be to wrap the content in a div: ``` +Default slot: the first element inside the widget which is not a named slot will +be considered the `default` slot. For example: + +```xml +
+ + some content + +
+ +
+ +
+``` + ### Asynchronous Rendering Working with asynchronous code always adds a lot of complexity to a system. Whenever diff --git a/src/qweb_extensions.ts b/src/qweb_extensions.ts index cdc7b737..28034076 100644 --- a/src/qweb_extensions.ts +++ b/src/qweb_extensions.ts @@ -508,7 +508,11 @@ QWeb.addDirective({ ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`); if (async) { ctx.addLine(`const patchQueue${widgetID} = [];`); - ctx.addLine(`c${ctx.parentNode}.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);`); + ctx.addLine( + `c${ + ctx.parentNode + }.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);` + ); } else { ctx.addLine(`c${ctx.parentNode}.push(null);`); } @@ -543,17 +547,26 @@ QWeb.addDirective({ ); // SLOTS - const slotNodes = node.querySelectorAll("[t-set]"); - if (slotNodes.length) { + if (node.childElementCount) { + const clone = node.cloneNode(true); + const slotNodes = clone.querySelectorAll("[t-set]"); const slotId = qweb.nextSlotId++; - for (let i = 0, length = slotNodes.length; i < length; i++) { - const slotNode = slotNodes[i]; - const key = slotNode.getAttribute("t-set")!; - slotNode.removeAttribute("t-set"); - const slotFn = qweb._compile(`slot_${key}_template`, slotNode); - qweb.slots[`${slotId}_${key}`] = slotFn.bind(qweb); - } ctx.addLine(`w${widgetID}.__owl__.slotId = ${slotId};`); + if (slotNodes.length) { + for (let i = 0, length = slotNodes.length; i < length; i++) { + const slotNode = slotNodes[i]; + slotNode.parentElement!.removeChild(slotNode); + const key = slotNode.getAttribute("t-set")!; + slotNode.removeAttribute("t-set"); + const slotFn = qweb._compile(`slot_${key}_template`, slotNode); + qweb.slots[`${slotId}_${key}`] = slotFn.bind(qweb); + } + } + if (clone.childElementCount) { + const content = clone.children[0]; + const slotFn = qweb._compile(`slot_default_template`, content); + qweb.slots[`${slotId}_default`] = slotFn.bind(qweb); + } } ctx.addLine(`def${defID} = w${widgetID}._prepare();`); diff --git a/tests/component.test.ts b/tests/component.test.ts index 57efd19d..e85adb9a 100644 --- a/tests/component.test.ts +++ b/tests/component.test.ts @@ -3148,4 +3148,27 @@ describe("t-model directive", () => { expect(comp.state.number).toBe("invalid"); expect(fixture.innerHTML).toBe("
invalid
"); }); + + test("content is the default slot", async () => { + env.qweb.addTemplates(` + +
+ + sts rocks + +
+
+
+ `); + class Dialog extends Widget {} + class Parent extends Widget { + widgets = { Dialog }; + } + const parent = new Parent(env); + await parent.mount(fixture); + + expect(fixture.innerHTML).toBe( + "
sts rocks
" + ); + }); });