mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
wip
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
|||||||
ASTLog,
|
ASTLog,
|
||||||
ASTMulti,
|
ASTMulti,
|
||||||
ASTSlot,
|
ASTSlot,
|
||||||
|
ASTSlotDefinition,
|
||||||
ASTTCall,
|
ASTTCall,
|
||||||
ASTTCallBlock,
|
ASTTCallBlock,
|
||||||
ASTTEsc,
|
ASTTEsc,
|
||||||
@@ -137,12 +138,14 @@ interface Context {
|
|||||||
index: number | string;
|
index: number | string;
|
||||||
forceNewBlock: boolean;
|
forceNewBlock: boolean;
|
||||||
preventRoot?: boolean;
|
preventRoot?: boolean;
|
||||||
|
ignoreRoot?: boolean;
|
||||||
isLast?: boolean;
|
isLast?: boolean;
|
||||||
translate: boolean;
|
translate: boolean;
|
||||||
tKeyExpr: string | null;
|
tKeyExpr: string | null;
|
||||||
nameSpace?: string;
|
nameSpace?: string;
|
||||||
tModelSelectedExpr?: string;
|
tModelSelectedExpr?: string;
|
||||||
ctxVar?: string;
|
ctxVar?: string;
|
||||||
|
slotVar?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createContext(parentCtx: Context, params?: Partial<Context>): Context {
|
function createContext(parentCtx: Context, params?: Partial<Context>): Context {
|
||||||
@@ -155,6 +158,7 @@ function createContext(parentCtx: Context, params?: Partial<Context>): Context {
|
|||||||
tKeyExpr: null,
|
tKeyExpr: null,
|
||||||
nameSpace: parentCtx.nameSpace,
|
nameSpace: parentCtx.nameSpace,
|
||||||
tModelSelectedExpr: parentCtx.tModelSelectedExpr,
|
tModelSelectedExpr: parentCtx.tModelSelectedExpr,
|
||||||
|
slotVar: parentCtx.slotVar
|
||||||
},
|
},
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
@@ -384,6 +388,9 @@ export class CodeGenerator {
|
|||||||
blockExpr = `toggler(${ctx.tKeyExpr}, ${blockExpr})`;
|
blockExpr = `toggler(${ctx.tKeyExpr}, ${blockExpr})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.ignoreRoot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (block.isRoot && !ctx.preventRoot) {
|
if (block.isRoot && !ctx.preventRoot) {
|
||||||
if (this.target.on) {
|
if (this.target.on) {
|
||||||
blockExpr = this.wrapWithEventCatcher(blockExpr, this.target.on);
|
blockExpr = this.wrapWithEventCatcher(blockExpr, this.target.on);
|
||||||
@@ -465,6 +472,8 @@ export class CodeGenerator {
|
|||||||
return this.compileLog(ast, ctx);
|
return this.compileLog(ast, ctx);
|
||||||
case ASTType.TSlot:
|
case ASTType.TSlot:
|
||||||
return this.compileTSlot(ast, ctx);
|
return this.compileTSlot(ast, ctx);
|
||||||
|
case ASTType.TSetSlot:
|
||||||
|
return this.compileTSetSlot(ast, ctx);
|
||||||
case ASTType.TTranslation:
|
case ASTType.TTranslation:
|
||||||
return this.compileTTranslation(ast, ctx);
|
return this.compileTTranslation(ast, ctx);
|
||||||
case ASTType.TPortal:
|
case ASTType.TPortal:
|
||||||
@@ -1144,52 +1153,31 @@ export class CodeGenerator {
|
|||||||
const props: string[] = ast.props ? this.formatPropObject(ast.props) : [];
|
const props: string[] = ast.props ? this.formatPropObject(ast.props) : [];
|
||||||
|
|
||||||
// slots
|
// slots
|
||||||
let slotDef: string = "";
|
let slotVar: string = "";
|
||||||
if (ast.slots) {
|
if (ast.body) {
|
||||||
let ctxStr = "ctx";
|
slotVar = generateId("slot");
|
||||||
if (this.target.loopLevel || !this.hasSafeContext) {
|
const subCtx = createContext(ctx, { slotVar, ignoreRoot: true });
|
||||||
ctxStr = generateId("ctx");
|
this.target.addLine(`let ${slotVar} = {};`);
|
||||||
this.helpers.add("capture");
|
this.compileAST(ast.body, subCtx);
|
||||||
this.define(ctxStr, `capture(ctx)`);
|
|
||||||
}
|
|
||||||
let slotStr: string[] = [];
|
|
||||||
for (let slotName in ast.slots) {
|
|
||||||
const slotAst = ast.slots[slotName];
|
|
||||||
const params = [];
|
|
||||||
if (slotAst.content) {
|
|
||||||
const name = this.compileInNewTarget("slot", slotAst.content, ctx, slotAst.on);
|
|
||||||
params.push(`__render: ${name}.bind(this), __ctx: ${ctxStr}`);
|
|
||||||
}
|
|
||||||
const scope = ast.slots[slotName].scope;
|
|
||||||
if (scope) {
|
|
||||||
params.push(`__scope: "${scope}"`);
|
|
||||||
}
|
|
||||||
if (ast.slots[slotName].attrs) {
|
|
||||||
params.push(...this.formatPropObject(ast.slots[slotName].attrs!));
|
|
||||||
}
|
|
||||||
const slotInfo = `{${params.join(", ")}}`;
|
|
||||||
slotStr.push(`'${slotName}': ${slotInfo}`);
|
|
||||||
}
|
|
||||||
slotDef = `{${slotStr.join(", ")}}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slotDef && !(ast.dynamicProps || hasSlotsProp)) {
|
if (slotVar && !(ast.dynamicProps || hasSlotsProp)) {
|
||||||
this.helpers.add("markRaw");
|
this.helpers.add("markRaw");
|
||||||
props.push(`slots: markRaw(${slotDef})`);
|
props.push(`slots: markRaw(${slotVar})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let propString = this.getPropString(props, ast.dynamicProps);
|
let propString = this.getPropString(props, ast.dynamicProps);
|
||||||
|
|
||||||
let propVar: string;
|
let propVar: string;
|
||||||
if ((slotDef && (ast.dynamicProps || hasSlotsProp)) || this.dev) {
|
if ((slotVar && (ast.dynamicProps || hasSlotsProp)) || this.dev) {
|
||||||
propVar = generateId("props");
|
propVar = generateId("props");
|
||||||
this.define(propVar!, propString);
|
this.define(propVar!, propString);
|
||||||
propString = propVar!;
|
propString = propVar!;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
|
if (slotVar && (ast.dynamicProps || hasSlotsProp)) {
|
||||||
this.helpers.add("markRaw");
|
this.helpers.add("markRaw");
|
||||||
this.addLine(`${propVar!}.slots = markRaw(Object.assign(${slotDef}, ${propVar!}.slots))`);
|
this.addLine(`${propVar!}.slots = markRaw(Object.assign(${slotVar}, ${propVar!}.slots))`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmap key
|
// cmap key
|
||||||
@@ -1220,7 +1208,7 @@ export class CodeGenerator {
|
|||||||
id,
|
id,
|
||||||
expr: `app.createComponent(${
|
expr: `app.createComponent(${
|
||||||
ast.isDynamic ? null : expr
|
ast.isDynamic ? null : expr
|
||||||
}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, ${
|
}, ${!ast.isDynamic}, ${!!ast.body}, ${!!ast.dynamicProps}, ${
|
||||||
!ast.props && !ast.dynamicProps
|
!ast.props && !ast.dynamicProps
|
||||||
})`,
|
})`,
|
||||||
});
|
});
|
||||||
@@ -1263,6 +1251,37 @@ export class CodeGenerator {
|
|||||||
return `${name}(${expr}, [${handlers.join(",")}])`;
|
return `${name}(${expr}, [${handlers.join(",")}])`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileTSetSlot(ast: ASTSlotDefinition, ctx: Context): string {
|
||||||
|
let ctxStr = "ctx";
|
||||||
|
if (this.target.loopLevel || !this.hasSafeContext) {
|
||||||
|
ctxStr = generateId("ctx");
|
||||||
|
this.helpers.add("capture");
|
||||||
|
this.define(ctxStr, `capture(ctx)`);
|
||||||
|
}
|
||||||
|
// let slotStr: string[] = [];
|
||||||
|
// for (let slotName in ast.slots) {
|
||||||
|
// const slotAst = ast.slots[slotName];
|
||||||
|
const params = [];
|
||||||
|
if (ast.content) {
|
||||||
|
const name = this.compileInNewTarget("slotFn", ast.content, ctx, ast.on);
|
||||||
|
params.push(`__render: ${name}.bind(this), __ctx: ${ctxStr}`);
|
||||||
|
}
|
||||||
|
// ast.scope
|
||||||
|
// const scope = ast.slots[slotName].scope;
|
||||||
|
if (ast.scope) {
|
||||||
|
params.push(`__scope: "${ast.scope}"`);
|
||||||
|
}
|
||||||
|
if (ast.attrs) {
|
||||||
|
params.push(...this.formatPropObject(ast.attrs!));
|
||||||
|
}
|
||||||
|
const slotInfo = `{${params.join(", ")}}`;
|
||||||
|
this.target.addLine(`${ctx.slotVar}['${ast.name}'] = ${slotInfo};`)
|
||||||
|
// slotStr.push(`'${slotName}': ${slotInfo}`);
|
||||||
|
// }
|
||||||
|
// slotDef = `{${slotStr.join(", ")}}`;
|
||||||
|
return "what should go here? anyone knows?";
|
||||||
|
}
|
||||||
|
|
||||||
compileTSlot(ast: ASTSlot, ctx: Context): string {
|
compileTSlot(ast: ASTSlot, ctx: Context): string {
|
||||||
this.helpers.add("callSlot");
|
this.helpers.add("callSlot");
|
||||||
let { block } = ctx;
|
let { block } = ctx;
|
||||||
|
|||||||
+86
-68
@@ -23,6 +23,7 @@ export const enum ASTType {
|
|||||||
TDebug,
|
TDebug,
|
||||||
TLog,
|
TLog,
|
||||||
TSlot,
|
TSlot,
|
||||||
|
TSetSlot,
|
||||||
TCallBlock,
|
TCallBlock,
|
||||||
TTranslation,
|
TTranslation,
|
||||||
TPortal,
|
TPortal,
|
||||||
@@ -120,7 +121,9 @@ export interface ASTTCall {
|
|||||||
context: string | null;
|
context: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SlotDefinition {
|
export interface ASTSlotDefinition {
|
||||||
|
type: ASTType.TSetSlot;
|
||||||
|
name: string;
|
||||||
content: AST | null;
|
content: AST | null;
|
||||||
scope: string | null;
|
scope: string | null;
|
||||||
on: EventHandlers | null;
|
on: EventHandlers | null;
|
||||||
@@ -134,7 +137,8 @@ export interface ASTComponent {
|
|||||||
dynamicProps: string | null;
|
dynamicProps: string | null;
|
||||||
on: EventHandlers | null;
|
on: EventHandlers | null;
|
||||||
props: { [name: string]: string } | null;
|
props: { [name: string]: string } | null;
|
||||||
slots: { [name: string]: SlotDefinition } | null;
|
body: AST | null;
|
||||||
|
// slots: { [name: string]: ASTSlotDefinition } | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ASTSlot {
|
export interface ASTSlot {
|
||||||
@@ -186,6 +190,7 @@ export type AST =
|
|||||||
| ASTTKey
|
| ASTTKey
|
||||||
| ASTComponent
|
| ASTComponent
|
||||||
| ASTSlot
|
| ASTSlot
|
||||||
|
| ASTSlotDefinition
|
||||||
| ASTTCallBlock
|
| ASTTCallBlock
|
||||||
| ASTLog
|
| ASTLog
|
||||||
| ASTDebug
|
| ASTDebug
|
||||||
@@ -238,6 +243,7 @@ function parseNode(node: Node, ctx: ParsingContext): AST | null {
|
|||||||
parseTKey(node, ctx) ||
|
parseTKey(node, ctx) ||
|
||||||
parseTTranslation(node, ctx) ||
|
parseTTranslation(node, ctx) ||
|
||||||
parseTSlot(node, ctx) ||
|
parseTSlot(node, ctx) ||
|
||||||
|
parseTSetSlot(node, ctx) ||
|
||||||
parseTOutNode(node, ctx) ||
|
parseTOutNode(node, ctx) ||
|
||||||
parseComponent(node, ctx) ||
|
parseComponent(node, ctx) ||
|
||||||
parseDOMNode(node, ctx) ||
|
parseDOMNode(node, ctx) ||
|
||||||
@@ -573,12 +579,12 @@ function parseTCall(node: Element, ctx: ParsingContext): AST | null {
|
|||||||
ast.content = [tcall];
|
ast.content = [tcall];
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
if (ast && ast.type === ASTType.TComponent) {
|
// if (ast && ast.type === ASTType.TComponent) {
|
||||||
return {
|
// return {
|
||||||
...ast,
|
// ...ast,
|
||||||
slots: { default: { content: tcall, scope: null, on: null, attrs: null } },
|
// slots: { default: { content: tcall, scope: null, on: null, attrs: null } },
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
const body = parseChildren(node, ctx);
|
const body = parseChildren(node, ctx);
|
||||||
|
|
||||||
@@ -706,8 +712,8 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
|
|||||||
const dynamicProps = node.getAttribute("t-props");
|
const dynamicProps = node.getAttribute("t-props");
|
||||||
node.removeAttribute("t-props");
|
node.removeAttribute("t-props");
|
||||||
|
|
||||||
const defaultSlotScope = node.getAttribute("t-slot-scope");
|
// const defaultSlotScope = node.getAttribute("t-slot-scope");
|
||||||
node.removeAttribute("t-slot-scope");
|
// node.removeAttribute("t-slot-scope");
|
||||||
let on: ASTComponent["on"] = null;
|
let on: ASTComponent["on"] = null;
|
||||||
|
|
||||||
let props: ASTComponent["props"] = null;
|
let props: ASTComponent["props"] = null;
|
||||||
@@ -727,67 +733,14 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let slots: ASTComponent["slots"] | null = null;
|
let body: ASTComponent["body"] = null;
|
||||||
|
|
||||||
|
// let slots: ASTComponent["slots"] | null = null;
|
||||||
if (node.hasChildNodes()) {
|
if (node.hasChildNodes()) {
|
||||||
const clone = <Element>node.cloneNode(true);
|
body = parseChildNodes(node, ctx);
|
||||||
|
|
||||||
// named slots
|
|
||||||
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
|
|
||||||
for (let slotNode of slotNodes) {
|
|
||||||
if (slotNode.tagName !== "t") {
|
|
||||||
throw new OwlError(
|
|
||||||
`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const name = slotNode.getAttribute("t-set-slot")!;
|
|
||||||
|
|
||||||
// check if this is defined in a sub component (in which case it should
|
|
||||||
// be ignored)
|
|
||||||
let el = slotNode.parentElement!;
|
|
||||||
let isInSubComponent = false;
|
|
||||||
while (el !== clone) {
|
|
||||||
if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0].toUpperCase()) {
|
|
||||||
isInSubComponent = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
el = el.parentElement!;
|
|
||||||
}
|
|
||||||
if (isInSubComponent) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
slotNode.removeAttribute("t-set-slot");
|
|
||||||
slotNode.remove();
|
|
||||||
const slotAst = parseNode(slotNode, ctx);
|
|
||||||
let on: SlotDefinition["on"] = null;
|
|
||||||
let attrs: Attrs | null = null;
|
|
||||||
let scope: string | null = null;
|
|
||||||
for (let attributeName of slotNode.getAttributeNames()) {
|
|
||||||
const value = slotNode.getAttribute(attributeName)!;
|
|
||||||
if (attributeName === "t-slot-scope") {
|
|
||||||
scope = value;
|
|
||||||
continue;
|
|
||||||
} else if (attributeName.startsWith("t-on-")) {
|
|
||||||
on = on || {};
|
|
||||||
on[attributeName.slice(5)] = value;
|
|
||||||
} else {
|
|
||||||
attrs = attrs || {};
|
|
||||||
attrs[attributeName] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slots = slots || {};
|
|
||||||
slots[name] = { content: slotAst, on, attrs, scope };
|
|
||||||
}
|
|
||||||
|
|
||||||
// default slot
|
|
||||||
const defaultContent = parseChildNodes(clone, ctx);
|
|
||||||
slots = slots || {};
|
|
||||||
// t-set-slot="default" has priority over content
|
|
||||||
if (defaultContent && !slots.default) {
|
|
||||||
slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots, on };
|
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, body, on };
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -821,6 +774,71 @@ function parseTSlot(node: Element, ctx: ParsingContext): AST | null {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseTSetSlot(node: Element, ctx: ParsingContext): AST | null {
|
||||||
|
if (!node.hasAttribute("t-set-slot")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// const t = el.ownerDocument.createElement("t");
|
||||||
|
|
||||||
|
// const clone = <Element>node.cloneNode(true);
|
||||||
|
|
||||||
|
// // named slots
|
||||||
|
// const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
|
||||||
|
// for (let slotNode of slotNodes) {
|
||||||
|
if (node.tagName !== "t") {
|
||||||
|
throw new OwlError(
|
||||||
|
`Directive 't-set-slot' can only be used on <t> nodes (used on a <${node.tagName}>)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const name = node.getAttribute("t-set-slot")!;
|
||||||
|
|
||||||
|
// // check if this is defined in a sub component (in which case it should
|
||||||
|
// // be ignored)
|
||||||
|
// let el = slotNode.parentElement!;
|
||||||
|
// let isInSubComponent = false;
|
||||||
|
// while (el !== clone) {
|
||||||
|
// if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0].toUpperCase()) {
|
||||||
|
// isInSubComponent = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// el = el.parentElement!;
|
||||||
|
// }
|
||||||
|
// if (isInSubComponent) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
node.removeAttribute("t-set-slot");
|
||||||
|
node.remove();
|
||||||
|
const slotAst = parseNode(node, ctx);
|
||||||
|
let on: ASTSlotDefinition["on"] = null;
|
||||||
|
let attrs: Attrs | null = null;
|
||||||
|
let scope: string | null = null;
|
||||||
|
for (let attributeName of node.getAttributeNames()) {
|
||||||
|
const value = node.getAttribute(attributeName)!;
|
||||||
|
if (attributeName === "t-slot-scope") {
|
||||||
|
scope = value;
|
||||||
|
continue;
|
||||||
|
} else if (attributeName.startsWith("t-on-")) {
|
||||||
|
on = on || {};
|
||||||
|
on[attributeName.slice(5)] = value;
|
||||||
|
} else {
|
||||||
|
attrs = attrs || {};
|
||||||
|
attrs[attributeName] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// slots = slots || {};
|
||||||
|
return { type: ASTType.TSetSlot, name, content: slotAst, on, attrs, scope };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // default slot
|
||||||
|
// const defaultContent = parseChildNodes(clone, ctx);
|
||||||
|
// slots = slots || {};
|
||||||
|
// // t-set-slot="default" has priority over content
|
||||||
|
// if (defaultContent && !slots.default) {
|
||||||
|
// slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
function parseTTranslation(node: Element, ctx: ParsingContext): AST | null {
|
function parseTTranslation(node: Element, ctx: ParsingContext): AST | null {
|
||||||
if (node.getAttribute("t-translation") !== "off") {
|
if (node.getAttribute("t-translation") !== "off") {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -282,6 +282,47 @@ exports[`slots can use t-call in default-content of t-slot 3`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`slots conditional slot 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
let { capture, markRaw } = helpers;
|
||||||
|
const comp1 = app.createComponent(\`Child\`, true, true, false, true);
|
||||||
|
|
||||||
|
function slotFn1(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`blue\`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function slotFn2(ctx, node, key = \\"\\") {
|
||||||
|
return text(\`red\`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let slot1 = {};
|
||||||
|
if (ctx['state'].flag) {
|
||||||
|
const ctx1 = capture(ctx);
|
||||||
|
slot1['abc'] = {__render: slotFn1.bind(this), __ctx: ctx1};
|
||||||
|
} else {
|
||||||
|
const ctx2 = capture(ctx);
|
||||||
|
slot1['abc'] = {__render: slotFn2.bind(this), __ctx: ctx2};
|
||||||
|
}
|
||||||
|
const b4 = comp1({slots: markRaw(slot1)}, key + \`__1\`, node, this, null);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`slots conditional slot 2`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
let { callSlot } = helpers;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return callSlot(ctx, node, key, 'abc', false, {});
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`slots content is the default slot (variation) 1`] = `
|
exports[`slots content is the default slot (variation) 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1933,4 +1933,33 @@ describe("slots", () => {
|
|||||||
"<p>1 hello <div>child</div></p><p>2 hello <div>child</div></p>"
|
"<p>1 hello <div>child</div></p><p>2 hello <div>child</div></p>"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.only("conditional slot", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-slot="abc"/>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<Child>
|
||||||
|
<t t-if="state.flag">
|
||||||
|
<t t-set-slot="abc">blue</t>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<t t-set-slot="abc">red</t>
|
||||||
|
</t>
|
||||||
|
</Child>`;
|
||||||
|
static components = { Child };
|
||||||
|
state = useState({ flag: true});
|
||||||
|
}
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("blue");
|
||||||
|
|
||||||
|
parent.state.flag = false;
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("red");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user