mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] slots: allow t-call and components in slot default content
This commit is contained in:
committed by
Aaron Bohy
parent
5d8141a67c
commit
3f66d9fe6c
@@ -19,7 +19,7 @@ function callSlot(
|
|||||||
name: string,
|
name: string,
|
||||||
dynamic: boolean,
|
dynamic: boolean,
|
||||||
extra: any,
|
extra: any,
|
||||||
defaultSlot?: (ctx: any, key: string) => BDom
|
defaultContent?: (ctx: any, node: any, key: string) => BDom
|
||||||
): BDom {
|
): BDom {
|
||||||
const slots = (ctx.props && ctx.props.slots) || {};
|
const slots = (ctx.props && ctx.props.slots) || {};
|
||||||
const { __render, __ctx, __scope } = slots[name] || {};
|
const { __render, __ctx, __scope } = slots[name] || {};
|
||||||
@@ -28,13 +28,13 @@ function callSlot(
|
|||||||
slotScope[__scope] = extra || {};
|
slotScope[__scope] = extra || {};
|
||||||
}
|
}
|
||||||
const slotBDom = __render ? __render(slotScope, parent, key) : null;
|
const slotBDom = __render ? __render(slotScope, parent, key) : null;
|
||||||
if (defaultSlot) {
|
if (defaultContent) {
|
||||||
let child1: BDom | undefined = undefined;
|
let child1: BDom | undefined = undefined;
|
||||||
let child2: BDom | undefined = undefined;
|
let child2: BDom | undefined = undefined;
|
||||||
if (slotBDom) {
|
if (slotBDom) {
|
||||||
child1 = dynamic ? toggler(name, slotBDom) : slotBDom;
|
child1 = dynamic ? toggler(name, slotBDom) : slotBDom;
|
||||||
} else {
|
} else {
|
||||||
child2 = defaultSlot(parent, key);
|
child2 = defaultContent(ctx, parent, key);
|
||||||
}
|
}
|
||||||
return multi([child1, child2]);
|
return multi([child1, child2]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1095,9 +1095,9 @@ export class CodeGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ast.defaultContent) {
|
if (ast.defaultContent) {
|
||||||
let name = this.generateId("defaultSlot");
|
let name = this.generateId("defaultContent");
|
||||||
const slot = new CodeTarget(name);
|
const slot = new CodeTarget(name);
|
||||||
slot.signature = "ctx => {";
|
slot.signature = "(ctx, node, key) => {";
|
||||||
this.functions.push(slot);
|
this.functions.push(slot);
|
||||||
const initialTarget = this.target;
|
const initialTarget = this.target;
|
||||||
const subCtx: Context = createContext(ctx);
|
const subCtx: Context = createContext(ctx);
|
||||||
|
|||||||
@@ -133,6 +133,87 @@ exports[`slots can render only empty slot 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`slots can use component in default-content of t-slot 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||||
|
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`\`);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`slots can use component in default-content of t-slot 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||||
|
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
||||||
|
|
||||||
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
|
return component(\`GrandChild\`, {}, key + \`__2\`, node, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return callSlot(ctx, node, key, 'default', false, {}, defaultContent1);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`slots can use component in default-content of t-slot 3`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||||
|
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`slots can use t-call in default-content of t-slot 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||||
|
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`\`);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`slots can use t-call in default-content of t-slot 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||||
|
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
||||||
|
const callTemplate_3 = getTemplate(\`__template__9\`);
|
||||||
|
|
||||||
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
|
return callTemplate_3.call(this, ctx, node, key + \`__2\`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return callSlot(ctx, node, key, 'default', false, {}, defaultContent1);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`slots can use t-call in default-content of t-slot 3`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||||
|
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`slots content is the default slot (variation) 1`] = `
|
exports[`slots content is the default slot (variation) 1`] = `
|
||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
@@ -206,12 +287,12 @@ exports[`slots dafault slots can define a default content 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\`default content\`);
|
return text(\`default content\`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -240,12 +321,12 @@ exports[`slots default content is not rendered if named slot is provided 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\`default content\`);
|
return text(\`default content\`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultContent1);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -279,12 +360,12 @@ exports[`slots default content is not rendered if slot is provided 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\`default content\`);
|
return text(\`default content\`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -317,17 +398,17 @@ exports[`slots default slot next to named slot, with default content 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<div class=\\"Dialog\\"><div class=\\"content\\"><block-child-0/></div><div class=\\"footer\\"><block-child-1/></div></div>\`);
|
let block1 = createBlock(\`<div class=\\"Dialog\\"><div class=\\"content\\"><block-child-0/></div><div class=\\"footer\\"><block-child-1/></div></div>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\` Default content \`);
|
return text(\` Default content \`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSlot2 = ctx => {
|
const defaultContent2 = (ctx, node, key) => {
|
||||||
return text(\` Default footer \`);
|
return text(\` Default footer \`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1);
|
||||||
let b5 = callSlot(ctx, node, key, 'footer', false, {}, defaultSlot2);
|
let b5 = callSlot(ctx, node, key, 'footer', false, {}, defaultContent2);
|
||||||
return block1([], [b3, b5]);
|
return block1([], [b3, b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -469,13 +550,13 @@ exports[`slots dynamic t-slot call with default 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-child-0/></button>\`);
|
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-child-0/></button>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\` owl \`);
|
return text(\` owl \`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let d1 = [ctx['toggle'], ctx];
|
let d1 = [ctx['toggle'], ctx];
|
||||||
let b3 = callSlot(ctx, node, key, (ctx['current'].slot), true, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, (ctx['current'].slot), true, {}, defaultContent1);
|
||||||
return block1([d1], [b3]);
|
return block1([d1], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -806,12 +887,12 @@ exports[`slots named slots can define a default content 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
let block1 = createBlock(\`<span><block-child-0/></span>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\`default content\`);
|
return text(\`default content\`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultContent1);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -840,17 +921,17 @@ exports[`slots named slots inside slot, again 1`] = `
|
|||||||
|
|
||||||
let block1 = createBlock(\`<child><block-child-0/><block-child-1/><block-child-2/></child>\`);
|
let block1 = createBlock(\`<child><block-child-0/><block-child-1/><block-child-2/></child>\`);
|
||||||
|
|
||||||
const defaultSlot1 = ctx => {
|
const defaultContent1 = (ctx, node, key) => {
|
||||||
return text(\`default1\`);
|
return text(\`default1\`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSlot2 = ctx => {
|
const defaultContent2 = (ctx, node, key) => {
|
||||||
return text(\`default2\`);
|
return text(\`default2\`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let b3 = callSlot(ctx, node, key, 'brol1', false, {}, defaultSlot1);
|
let b3 = callSlot(ctx, node, key, 'brol1', false, {}, defaultContent1);
|
||||||
let b5 = callSlot(ctx, node, key, 'brol2', false, {}, defaultSlot2);
|
let b5 = callSlot(ctx, node, key, 'brol2', false, {}, defaultContent2);
|
||||||
let b6 = callSlot(ctx, node, key, 'default', false, {});
|
let b6 = callSlot(ctx, node, key, 'default', false, {});
|
||||||
return block1([], [b3, b5, b6]);
|
return block1([], [b3, b5, b6]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1434,4 +1434,33 @@ describe("slots", () => {
|
|||||||
}
|
}
|
||||||
expect(error).toBeNull();
|
expect(error).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("can use t-call in default-content of t-slot", async () => {
|
||||||
|
const template = xml``;
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-slot="default"><t t-call="${template}"/></t>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`<Child/>`;
|
||||||
|
static components = { Child };
|
||||||
|
}
|
||||||
|
await mount(Parent, fixture);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("can use component in default-content of t-slot", async () => {
|
||||||
|
class GrandChild extends Component {
|
||||||
|
static template = xml``;
|
||||||
|
}
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-slot="default"><GrandChild/></t>`;
|
||||||
|
static components = { GrandChild };
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`<Child/>`;
|
||||||
|
static components = { Child };
|
||||||
|
}
|
||||||
|
await mount(Parent, fixture);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user