[IMP] portal: compile t-portal in an internal Component Portal

This commit also clean-up the deepRemove for the Portal that is not
needed any more.
This commit is contained in:
Jorge Pinna Puissant
2022-01-17 15:40:43 +01:00
committed by Géry Debongnie
parent 6ff6d59895
commit 9577d70b4b
11 changed files with 496 additions and 240 deletions
-32
View File
@@ -146,7 +146,6 @@ describe("qweb parser", () => {
content: [],
},
],
deepRemove: false,
});
});
@@ -254,7 +253,6 @@ describe("qweb parser", () => {
content: [],
},
],
deepRemove: false,
});
});
@@ -505,7 +503,6 @@ describe("qweb parser", () => {
},
tElif: null,
tElse: null,
deepRemove: false,
},
],
});
@@ -521,7 +518,6 @@ describe("qweb parser", () => {
},
tElif: null,
tElse: null,
deepRemove: false,
});
});
@@ -542,7 +538,6 @@ describe("qweb parser", () => {
},
tElif: null,
tElse: null,
deepRemove: false,
});
});
@@ -559,7 +554,6 @@ describe("qweb parser", () => {
type: ASTType.Text,
value: "else",
},
deepRemove: false,
});
});
@@ -578,7 +572,6 @@ describe("qweb parser", () => {
},
],
tElse: null,
deepRemove: false,
});
});
@@ -600,7 +593,6 @@ describe("qweb parser", () => {
type: ASTType.Text,
value: "else",
},
deepRemove: false,
});
});
@@ -658,7 +650,6 @@ describe("qweb parser", () => {
},
],
},
deepRemove: false,
});
});
@@ -740,7 +731,6 @@ describe("qweb parser", () => {
},
tElif: null,
tElse: null,
deepRemove: false,
});
});
@@ -763,7 +753,6 @@ describe("qweb parser", () => {
content: { type: ASTType.Text, value: "1" },
tElif: null,
tElse: { type: ASTType.TSet, name: "ourvar", value: "0", defaultValue: null, body: null },
deepRemove: false,
},
],
});
@@ -793,7 +782,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -809,7 +797,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -835,7 +822,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -851,7 +837,6 @@ describe("qweb parser", () => {
hasNoIndex: true,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -879,7 +864,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -898,7 +882,6 @@ describe("qweb parser", () => {
condition: "condition",
tElif: null,
tElse: null,
deepRemove: false,
content: {
type: ASTType.DomNode,
tag: "span",
@@ -916,7 +899,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -949,7 +931,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -977,7 +958,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
},
],
});
@@ -1015,7 +995,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -1038,7 +1017,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -1060,7 +1038,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: false,
hasNoValue: false,
deepRemove: false,
});
});
@@ -1080,7 +1057,6 @@ describe("qweb parser", () => {
hasNoIndex: false,
hasNoLast: true,
hasNoValue: true,
deepRemove: false,
});
});
@@ -1130,7 +1106,6 @@ describe("qweb parser", () => {
condition: "condition",
tElif: null,
tElse: null,
deepRemove: false,
content: {
type: ASTType.TCall,
name: "blabla",
@@ -1285,7 +1260,6 @@ describe("qweb parser", () => {
ns: null,
},
],
deepRemove: false,
},
},
},
@@ -1628,7 +1602,6 @@ describe("qweb parser", () => {
hasNoValue: true,
key: "item_index",
memo: "",
deepRemove: false,
type: ASTType.TForEach,
});
});
@@ -1800,10 +1773,6 @@ describe("qweb parser", () => {
});
});
test("t-portal must be in a <t> node", async () => {
expect(() => parse(`<div t-portal="target">Content</div>`)).toThrowError();
});
test("t-portal with t-if", async () => {
expect(parse(`<t t-portal="target" t-if="condition">Content</t>`)).toEqual({
condition: "condition",
@@ -1815,7 +1784,6 @@ describe("qweb parser", () => {
tElif: null,
tElse: null,
type: ASTType.TIf,
deepRemove: true,
});
});
});
+254 -83
View File
@@ -4,9 +4,9 @@ exports[`Portal Add and remove portals 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, callPortal, withKey } = helpers;
let { prepareList, Portal, capture, withKey } = helpers;
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let b3 = text(\` Portal\`);
let b4 = text(ctx['portalId']);
return multi([b3, b4]);
@@ -18,9 +18,37 @@ exports[`Portal Add and remove portals 1`] = `
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
c_block1[i1] = withKey(callPortal(ctx, node, key, '#outside', portalContent1), key1);
const ctx1 = capture(ctx);
c_block1[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1, true);
return list(c_block1);
}
}"
`;
exports[`Portal Add and remove portals on div 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, Portal, capture, withKey } = helpers;
let block2 = createBlock(\`<div> Portal<block-text-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let txt1 = ctx['portalId'];
return block2([txt1]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
const ctx1 = capture(ctx);
c_block1[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
}
}"
`;
@@ -29,11 +57,11 @@ exports[`Portal Add and remove portals with t-foreach 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, callPortal, withKey } = helpers;
let { prepareList, Portal, capture, withKey } = helpers;
let block2 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`, true);
let block2 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let b4 = text(\` Portal\`);
let b5 = text(ctx['portalId']);
return multi([b4, b5]);
@@ -46,10 +74,43 @@ exports[`Portal Add and remove portals with t-foreach 1`] = `
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
let txt1 = ctx['portalId'];
let b6 = callPortal(ctx, node, key, '#outside', portalContent1);
const ctx1 = capture(ctx);
let b6 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
c_block1[i1] = withKey(block2([txt1], [b6]), key1);
}
return list(c_block1, true);
return list(c_block1);
}
}"
`;
exports[`Portal Add and remove portals with t-foreach inside div 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, Portal, capture, withKey } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block3 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b5 = text(\` Portal\`);
let b6 = text(ctx['portalId']);
return multi([b5, b6]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['portalIds']);
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`portalId\`] = v_block2[i1];
let key1 = ctx['portalId'];
let txt1 = ctx['portalId'];
const ctx1 = capture(ctx);
let b7 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([txt1], [b7]), key1);
}
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
`;
@@ -76,14 +137,14 @@ exports[`Portal Portal composed with t-slot 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal, callSlot } = helpers;
let { Portal, callSlot } = helpers;
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, {});
}
return function template(ctx, node, key = \\"\\") {
return callPortal(ctx, node, key, '#outside', portalContent1);
return component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
}
}"
`;
@@ -106,17 +167,17 @@ exports[`Portal basic use of portal 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
let block2 = createBlock(\`<p>2</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -126,17 +187,37 @@ exports[`Portal basic use of portal in dev mode 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
let block2 = createBlock(\`<p>2</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
`;
exports[`Portal basic use of portal on div 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { Portal } = helpers;
let block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
let block2 = createBlock(\`<div><p>2</p></div>\`);
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -146,11 +227,11 @@ exports[`Portal conditional use of Portal (with sub Component) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block2 = createBlock(\`<span>1</span>\`, true);
let block2 = createBlock(\`<span>1</span>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
}
@@ -158,9 +239,9 @@ exports[`Portal conditional use of Portal (with sub Component) 1`] = `
let b2,b4;
b2 = block2();
if (ctx['state'].hasPortal) {
b4 = callPortal(ctx, node, key, '#outside', portalContent1);
b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
}
return multi([b2, b4], true);
return multi([b2, b4]);
}
}"
`;
@@ -183,12 +264,12 @@ exports[`Portal conditional use of Portal 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block2 = createBlock(\`<span>1</span>\`, true);
let block3 = createBlock(\`<p>2</p>\`, true);
let block2 = createBlock(\`<span>1</span>\`);
let block3 = createBlock(\`<p>2</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block3();
}
@@ -196,9 +277,99 @@ exports[`Portal conditional use of Portal 1`] = `
let b2,b4;
b2 = block2();
if (ctx['state'].hasPortal) {
b4 = callPortal(ctx, node, key, '#outside', portalContent1);
b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
}
return multi([b2, b4], true);
return multi([b2, b4]);
}
}"
`;
exports[`Portal conditional use of Portal with child and div 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].hasPortal) {
b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
}
return multi([b2]);
}
}"
`;
exports[`Portal conditional use of Portal with child and div 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, Portal, capture, withKey } = helpers;
let block1 = createBlock(\`<div><span>hasPortal</span><block-child-0/></div>\`);
let block3 = createBlock(\`<p>thePortal</p>\`);
function slot1(ctx, node, key = \\"\\") {
return block3();
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1]);
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1];
let key1 = ctx['elem'];
const ctx1 = capture(ctx);
c_block2[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
`;
exports[`Portal conditional use of Portal with child and div, variation 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block2 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].hasPortal) {
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
b2 = block2([], [b3]);
}
return multi([b2]);
}
}"
`;
exports[`Portal conditional use of Portal with child and div, variation 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, Portal, capture, withKey } = helpers;
let block2 = createBlock(\`<span>hasPortal</span>\`);
let block4 = createBlock(\`<p>thePortal</p>\`);
function slot1(ctx, node, key = \\"\\") {
return block4();
}
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
ctx = Object.create(ctx);
const [k_block3, v_block3, l_block3, c_block3] = prepareList([1]);
for (let i1 = 0; i1 < l_block3; i1++) {
ctx[\`elem\`] = v_block3[i1];
let key1 = ctx['elem'];
const ctx1 = capture(ctx);
c_block3[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b3 = list(c_block3);
return multi([b2, b3]);
}
}"
`;
@@ -207,22 +378,22 @@ exports[`Portal conditional use of Portal with div 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block2 = createBlock(\`<div><span>hasPortal</span><block-child-0/></div>\`, true);
let block3 = createBlock(\`<p>thePortal</p>\`, true);
let block2 = createBlock(\`<div><span>hasPortal</span><block-child-0/></div>\`);
let block3 = createBlock(\`<p>thePortal</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block3();
}
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].hasPortal) {
let b4 = callPortal(ctx, node, key, '#outside', portalContent1);
let b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
b2 = block2([], [b4]);
}
return multi([b2], true);
return multi([b2]);
}
}"
`;
@@ -231,18 +402,18 @@ exports[`Portal lifecycle hooks of portal sub component are properly called 1`]
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
}
return function template(ctx, node, key = \\"\\") {
let b3;
if (ctx['state'].hasChild) {
b3 = callPortal(ctx, node, key, '#outside', portalContent1);
b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
}
return block1([], [b3]);
}
@@ -267,12 +438,12 @@ exports[`Portal portal could have dynamically no content 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block3 = createBlock(\`<span><block-text-0/></span>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let b3;
if (ctx['state'].val) {
let txt1 = ctx['state'].val;
@@ -282,7 +453,7 @@ exports[`Portal portal could have dynamically no content 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b4 = callPortal(ctx, node, key, '#outside', portalContent1);
let b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b4]);
}
}"
@@ -292,16 +463,16 @@ exports[`Portal portal destroys on crash 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {error: ctx['state'].error}, key + \`__1\`, node, ctx);
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -325,16 +496,16 @@ exports[`Portal portal with child and props 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -358,13 +529,13 @@ exports[`Portal portal with dynamic body 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block3 = createBlock(\`<span><block-text-0/></span>\`);
let block4 = createBlock(\`<div/>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let b3,b4;
if (ctx['state'].val) {
let txt1 = ctx['state'].val;
@@ -376,7 +547,7 @@ exports[`Portal portal with dynamic body 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b5 = callPortal(ctx, node, key, '#outside', portalContent1);
let b5 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -386,20 +557,20 @@ exports[`Portal portal with many children 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block3 = createBlock(\`<div>1</div>\`);
let block4 = createBlock(\`<p>2</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let b3 = block3();
let b4 = block4();
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
let b5 = callPortal(ctx, node, key, '#outside', portalContent1);
let b5 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -409,11 +580,11 @@ exports[`Portal portal with no content 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let b3;
if (false) {
b3 = text('ABC');
@@ -422,7 +593,7 @@ exports[`Portal portal with no content 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b4 = callPortal(ctx, node, key, '#outside', portalContent1);
let b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b4]);
}
}"
@@ -432,16 +603,16 @@ exports[`Portal portal with only text as content 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return text('only text');
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -451,17 +622,17 @@ exports[`Portal portal with target not in dom 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block2 = createBlock(\`<div>2</div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#does-not-exist', portalContent1);
let b3 = component(Portal, {target: '#does-not-exist',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -471,16 +642,16 @@ exports[`Portal portal's parent's env is not polluted 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -522,18 +693,18 @@ exports[`Portal simple catchError with portal 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
let block2 = createBlock(\`<p><block-text-0/></p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
let txt1 = ctx['a'].b.c;
return block2([txt1]);
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -543,17 +714,17 @@ exports[`Portal with target in template (after portal) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><span>1</span><block-child-0/><div id=\\"local-target\\"/></div>\`);
let block2 = createBlock(\`<p>2</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#local-target', portalContent1);
let b3 = component(Portal, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -563,17 +734,17 @@ exports[`Portal with target in template (before portal) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><div id=\\"local-target\\"/><span>1</span><block-child-0/></div>\`);
let block2 = createBlock(\`<p>2</p>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#local-target', portalContent1);
let b3 = component(Portal, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -583,17 +754,17 @@ exports[`Portal: Props validation target must be a valid selector 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block2 = createBlock(\`<div>2</div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, ' ', portalContent1);
let b3 = component(Portal, {target: ' ',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -603,17 +774,17 @@ exports[`Portal: Props validation target must be a valid selector 2 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block2 = createBlock(\`<div>2</div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return block2();
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, 'aa', portalContent1);
let b3 = component(Portal, {target: 'aa',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -623,16 +794,16 @@ exports[`Portal: UI/UX focus is kept across re-renders 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callPortal } = helpers;
let { Portal } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function portalContent1(ctx, node, key = \\"\\") {
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
}
return function template(ctx, node, key = \\"\\") {
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
+177
View File
@@ -66,7 +66,24 @@ describe("Portal", () => {
expect(fixture.innerHTML).toBe('<div id="outside"><p>2</p></div><div><span>1</span></div>');
});
test("basic use of portal on div", async () => {
class Parent extends Component {
static template = xml`
<div>
<span>1</span>
<div t-portal="'#outside'">
<p>2</p>
</div>
</div>`;
}
addOutsideDiv(fixture);
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe(
'<div id="outside"><div><p>2</p></div></div><div><span>1</span></div>'
);
});
test("simple catchError with portal", async () => {
class Boom extends Component {
static template = xml`
@@ -565,6 +582,39 @@ describe("Portal", () => {
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
});
test("Add and remove portals on div", async () => {
class Parent extends Component {
static template = xml`
<div t-portal="'#outside'" t-foreach="portalIds" t-as="portalId" t-key="portalId">
Portal<t t-esc="portalId"/>
</div>`;
portalIds = useState([] as any);
}
addOutsideDiv(fixture);
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
parent.portalIds.push(1);
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"><div> Portal1</div></div>');
parent.portalIds.push(2);
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"><div> Portal1</div><div> Portal2</div></div>'
);
parent.portalIds.pop();
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"><div> Portal1</div></div>');
parent.portalIds.pop();
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
});
test("Add and remove portals with t-foreach", async () => {
class Parent extends Component {
static template = xml`
@@ -638,6 +688,133 @@ describe("Portal", () => {
'<div id="outside"><p>thePortal</p></div><div><span>hasPortal</span></div>'
);
});
test("conditional use of Portal with child and div", async () => {
class Child extends Component {
static template = xml`
<div>
<span>hasPortal</span>
<t t-foreach="[1]" t-as="elem" t-key="elem">
<t t-portal="'#outside'">
<p>thePortal</p>
</t>
</t>
</div>`;
}
class Parent extends Component {
static template = xml`
<t t-if="state.hasPortal">
<Child />
</t>`;
static components = { Child };
state = useState({ hasPortal: false });
}
addOutsideDiv(fixture);
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
parent.state.hasPortal = true;
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"><p>thePortal</p></div><div><span>hasPortal</span></div>'
);
parent.state.hasPortal = false;
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
parent.state.hasPortal = true;
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"><p>thePortal</p></div><div><span>hasPortal</span></div>'
);
});
test("conditional use of Portal with child and div, variation", async () => {
class Child extends Component {
static template = xml`
<span>hasPortal</span>
<t t-foreach="[1]" t-as="elem" t-key="elem">
<t t-portal="'#outside'">
<p>thePortal</p>
</t>
</t>`;
}
class Parent extends Component {
static template = xml`
<t t-if="state.hasPortal">
<div>
<Child />
</div>
</t>`;
static components = { Child };
state = useState({ hasPortal: false });
}
addOutsideDiv(fixture);
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
parent.state.hasPortal = true;
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"><p>thePortal</p></div><div><span>hasPortal</span></div>'
);
parent.state.hasPortal = false;
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
parent.state.hasPortal = true;
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"><p>thePortal</p></div><div><span>hasPortal</span></div>'
);
});
test("Add and remove portals with t-foreach inside div", async () => {
class Parent extends Component {
static template = xml`
<div>
<t t-foreach="portalIds" t-as="portalId" t-key="portalId">
<div>
<t t-esc="portalId"/>
<t t-portal="'#outside'">
Portal<t t-esc="portalId"/>
</t>
</div>
</t>
</div>`;
portalIds = useState([] as any);
}
addOutsideDiv(fixture);
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe('<div id="outside"></div><div></div>');
parent.portalIds.push(1);
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"> Portal1</div><div><div>1</div></div>');
parent.portalIds.push(2);
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"> Portal1 Portal2</div><div><div>1</div><div>2</div></div>'
);
parent.portalIds.pop();
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"> Portal1</div><div><div>1</div></div>');
parent.portalIds.pop();
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"></div><div></div>');
});
});
describe("Portal: UI/UX", () => {