diff --git a/doc/reference/slots.md b/doc/reference/slots.md
index 6f34c2c5..59061fb3 100644
--- a/doc/reference/slots.md
+++ b/doc/reference/slots.md
@@ -37,16 +37,16 @@ rendering context.
```
-Slots are defined by the caller, with the `t-set` directive:
+Slots are defined by the caller, with the `t-set-slot` directive:
```xml
some component
@@ -57,6 +57,9 @@ In this example, the component `Dialog` will render the slots `content` and `foo
with its parent as rendering context. This means that clicking on the button
will execute the `doSomething` method on the parent, not on the dialog.
+Note: Owl previously used the `t-set` directive to define the content of a slot.
+This is deprecated and should no longer be used in new code.
+
## Reference
Default slot: the first element inside the component which is not a named slot will
diff --git a/roadmap.md b/roadmap.md
index 0d6183e5..d122c610 100644
--- a/roadmap.md
+++ b/roadmap.md
@@ -16,6 +16,8 @@ change!
### 2.x (2020? 2021? 2022?)
+- stop support for `t-set` directive to define the content of a slot
+
Maybe:
- reimplement vdom to use *block* system, like Vue 3, which should make Owl
diff --git a/src/component/directive.ts b/src/component/directive.ts
index ee1bf14b..8cfbc731 100644
--- a/src/component/directive.ts
+++ b/src/component/directive.ts
@@ -400,7 +400,16 @@ QWeb.addDirective({
if (hasSlots) {
const clone = node.cloneNode(true);
- const slotNodes: Element[] = [];
+ const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
+
+ // The next code is a fallback for compatibility reason. It accepts t-set
+ // elements that are direct children with a non empty body as nodes defining
+ // the content of a slot.
+ //
+ // This is wrong, but is necessary to prevent breaking all existing Owl
+ // code using slots. This will be removed in v2.0 someday. Meanwhile,
+ // please use t-set-slot everywhere you need to set the content of a
+ // slot.
for (let el of clone.children) {
if (el.getAttribute("t-set") && el.hasChildNodes()) {
slotNodes.push(el);
@@ -412,8 +421,15 @@ QWeb.addDirective({
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");
+ let key = slotNode.getAttribute("t-set-slot")!;
+ slotNode.removeAttribute("t-set-slot");
+
+ // here again, this code should be removed when we stop supporting
+ // using t-set to define the content of named slots.
+ if (!key) {
+ key = slotNode.getAttribute("t-set")!;
+ slotNode.removeAttribute("t-set");
+ }
const slotFn = qweb._compile(`slot_${key}_template`, slotNode, ctx);
QWeb.slots[`${slotId}_${key}`] = slotFn;
}
diff --git a/tests/component/__snapshots__/slots.test.ts.snap b/tests/component/__snapshots__/slots.test.ts.snap
index 448927e4..ad82605c 100644
--- a/tests/component/__snapshots__/slots.test.ts.snap
+++ b/tests/component/__snapshots__/slots.test.ts.snap
@@ -90,6 +90,96 @@ exports[`t-slot directive can define and call slots 4`] = `
}"
`;
+exports[`t-slot directive can define and call slots using old t-set keyword 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);
+ // Component 'Dialog'
+ let w2 = '__3__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__3__']] : false;
+ let props2 = {};
+ if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) {
+ w2.destroy();
+ w2 = false;
+ }
+ if (w2) {
+ w2.__updateProps(props2, extra.fiber, Object.assign(Object.create(context), scope));
+ let pvnode = w2.__owl__.pvnode;
+ c1.push(pvnode);
+ } else {
+ let componentKey2 = \`Dialog\`;
+ let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Dialog'];
+ if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')}
+ 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 pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}});
+ c1.push(pvnode);
+ w2.__owl__.pvnode = pvnode;
+ }
+ w2.__owl__.parentLastFiberId = extra.fiber.id;
+ return vn1;
+}"
+`;
+
+exports[`t-slot directive can define and call slots using old t-set keyword 2`] = `
+"function anonymous(context, extra
+) {
+ // Template name: \\"__template__1\\"
+ let h = this.h;
+ let c6 = [], p6 = {key:6};
+ let vn6 = h('div', p6, c6);
+ let c7 = [], p7 = {key:7};
+ let vn7 = h('div', p7, c7);
+ c6.push(vn7);
+ const slot8 = this.constructor.slots[context.__owl__.slotId + '_' + 'header'];
+ if (slot8) {
+ slot8.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c7, parent: extra.parent || context}));
+ }
+ let c9 = [], p9 = {key:9};
+ let vn9 = h('div', p9, c9);
+ c6.push(vn9);
+ const slot10 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer'];
+ if (slot10) {
+ slot10.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c9, parent: extra.parent || context}));
+ }
+ return vn6;
+}"
+`;
+
+exports[`t-slot directive can define and call slots using old t-set keyword 3`] = `
+"function anonymous(context, extra
+) {
+ // Template name: \\"slot_header_template\\"
+ let h = this.h;
+ let c1 = extra.parentNode;
+ let c4 = [], p4 = {key:4};
+ let vn4 = h('span', p4, c4);
+ c1.push(vn4);
+ c4.push({text: \`header\`});
+}"
+`;
+
+exports[`t-slot directive can define and call slots using old t-set keyword 4`] = `
+"function anonymous(context, extra
+) {
+ // Template name: \\"slot_footer_template\\"
+ let h = this.h;
+ let c1 = extra.parentNode;
+ let c5 = [], p5 = {key:5};
+ let vn5 = h('span', p5, c5);
+ c1.push(vn5);
+ c5.push({text: \`footer\`});
+}"
+`;
+
exports[`t-slot directive content is the default slot 1`] = `
"function anonymous(context, extra
) {
diff --git a/tests/component/slots.test.ts b/tests/component/slots.test.ts
index f43b87bb..7c475807 100644
--- a/tests/component/slots.test.ts
+++ b/tests/component/slots.test.ts
@@ -41,8 +41,8 @@ describe("t-slot directive", () => {
@@ -67,6 +67,38 @@ describe("t-slot directive", () => {
expect(QWeb.slots["1_footer"].toString()).toMatchSnapshot();
});
+ test("can define and call slots using old t-set keyword", async () => {
+ // NOTE: this test should be removed once we stop supporting the t-set directive
+ // for defining slot content.
+ class Dialog extends Component {
+ static template = xml`
+