mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] portal: portal as a Directive
Before this commit, portal was a Component, now is a directive. This commit also clean some unused code, and fix an issue on the clean optimization when a portal is found in a condition or a loop.
This commit is contained in:
committed by
Aaron Bohy
parent
c221721d7f
commit
90167c5436
@@ -1,5 +1,59 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
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;
|
||||
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let b3 = text(\` Portal\`);
|
||||
let b4 = text(ctx['portalId']);
|
||||
return multi([b3, b4]);
|
||||
}
|
||||
|
||||
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'];
|
||||
c_block1[i1] = withKey(callPortal(ctx, node, key, '#outside', portalContent1), key1);
|
||||
}
|
||||
return list(c_block1, true);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
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 block2 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`, true);
|
||||
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let b4 = text(\` Portal\`);
|
||||
let b5 = text(ctx['portalId']);
|
||||
return multi([b4, b5]);
|
||||
}
|
||||
|
||||
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'];
|
||||
let txt1 = ctx['portalId'];
|
||||
let b6 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
c_block1[i1] = withKey(block2([txt1], [b6]), key1);
|
||||
}
|
||||
return list(c_block1, true);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`Portal Portal composed with t-slot 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
@@ -22,14 +76,14 @@ exports[`Portal Portal composed with t-slot 2`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||
let { callSlot } = helpers;
|
||||
let { callPortal, callSlot } = helpers;
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return callSlot(ctx, node, key, 'default', false, {});
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
return component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
return callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -52,16 +106,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 block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<p>2</p>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(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);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -71,18 +126,17 @@ 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 block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<p>2</p>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block2();
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
const props1 = {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}
|
||||
helpers.validateProps(\`Portal\`, props1, ctx)
|
||||
let b3 = component(\`Portal\`, props1, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -92,10 +146,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 block2 = createBlock(\`<span>1</span>\`);
|
||||
let block2 = createBlock(\`<span>1</span>\`, true);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
|
||||
}
|
||||
|
||||
@@ -103,9 +158,9 @@ exports[`Portal conditional use of Portal (with sub Component) 1`] = `
|
||||
let b2,b4;
|
||||
b2 = block2();
|
||||
if (ctx['state'].hasPortal) {
|
||||
b4 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
||||
b4 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
}
|
||||
return multi([b2, b4]);
|
||||
return multi([b2, b4], true);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -128,11 +183,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 block2 = createBlock(\`<span>1</span>\`);
|
||||
let block3 = createBlock(\`<p>2</p>\`);
|
||||
let block2 = createBlock(\`<span>1</span>\`, true);
|
||||
let block3 = createBlock(\`<p>2</p>\`, true);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block3();
|
||||
}
|
||||
|
||||
@@ -140,9 +196,33 @@ exports[`Portal conditional use of Portal 1`] = `
|
||||
let b2,b4;
|
||||
b2 = block2();
|
||||
if (ctx['state'].hasPortal) {
|
||||
b4 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
b4 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
}
|
||||
return multi([b2, b4]);
|
||||
return multi([b2, b4], true);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
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 block2 = createBlock(\`<div><span>hasPortal</span><block-child-0/></div>\`, true);
|
||||
let block3 = createBlock(\`<p>thePortal</p>\`, true);
|
||||
|
||||
function portalContent1(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);
|
||||
b2 = block2([], [b4]);
|
||||
}
|
||||
return multi([b2], true);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -151,17 +231,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block1 = createBlock(\`<div><block-child-0/><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(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 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
||||
b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
}
|
||||
return block1([], [b3]);
|
||||
}
|
||||
@@ -186,11 +267,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block3 = createBlock(\`<span><block-text-0/></span>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let b3;
|
||||
if (ctx['state'].val) {
|
||||
let txt1 = ctx['state'].val;
|
||||
@@ -200,7 +282,7 @@ exports[`Portal portal could have dynamically no content 1`] = `
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b4 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b4 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b4]);
|
||||
}
|
||||
}"
|
||||
@@ -210,15 +292,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return component(\`Child\`, {error: ctx['state'].error}, key + \`__1\`, node, ctx);
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -242,15 +325,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -274,12 +358,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block3 = createBlock(\`<span><block-text-0/></span>\`);
|
||||
let block4 = createBlock(\`<div/>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let b3,b4;
|
||||
if (ctx['state'].val) {
|
||||
let txt1 = ctx['state'].val;
|
||||
@@ -291,7 +376,7 @@ exports[`Portal portal with dynamic body 1`] = `
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b5 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b5 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b5]);
|
||||
}
|
||||
}"
|
||||
@@ -301,19 +386,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block3 = createBlock(\`<div>1</div>\`);
|
||||
let block4 = createBlock(\`<p>2</p>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let b3 = block3();
|
||||
let b4 = block4();
|
||||
return multi([b3, b4]);
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b5 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b5 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b5]);
|
||||
}
|
||||
}"
|
||||
@@ -323,10 +409,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let b3;
|
||||
if (false) {
|
||||
b3 = text('ABC');
|
||||
@@ -335,7 +422,7 @@ exports[`Portal portal with no content 1`] = `
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b4 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b4 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b4]);
|
||||
}
|
||||
}"
|
||||
@@ -345,15 +432,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return text('only text');
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -363,16 +451,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<div>2</div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block2();
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#does-not-exist',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#does-not-exist', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -382,15 +471,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -432,17 +522,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 block1 = createBlock(\`<div><span>1</span><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<p><block-text-0/></p>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
let txt1 = ctx['a'].b.c;
|
||||
return block2([txt1]);
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -452,16 +543,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 block1 = createBlock(\`<div><span>1</span><block-child-0/><div id=\\"local-target\\"/></div>\`);
|
||||
let block2 = createBlock(\`<p>2</p>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block2();
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#local-target', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -471,58 +563,57 @@ 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 block1 = createBlock(\`<div><div id=\\"local-target\\"/><span>1</span><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<p>2</p>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block2();
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#local-target', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`Portal: Props validation target is mandatory 1`] = `
|
||||
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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<div>2</div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block2();
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
const props1 = {slots: {'default': {__render: slot1, __ctx: ctx}}}
|
||||
helpers.validateProps(\`Portal\`, props1, ctx)
|
||||
let b3 = component(\`Portal\`, props1, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, ' ', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`Portal: Props validation target is not list 1`] = `
|
||||
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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
let block2 = createBlock(\`<div>2</div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return block2();
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
const props1 = {target: ['body'],slots: {'default': {__render: slot1, __ctx: ctx}}}
|
||||
helpers.validateProps(\`Portal\`, props1, ctx)
|
||||
let b3 = component(\`Portal\`, props1, key + \`__1\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, 'aa', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
@@ -532,15 +623,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 block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||
|
||||
function slot1(ctx, node, key = \\"\\") {
|
||||
function portalContent1(ctx, node, key = \\"\\") {
|
||||
return component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
|
||||
}
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let b3 = component(\`Portal\`, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
|
||||
let b3 = callPortal(ctx, node, key, '#outside', portalContent1);
|
||||
return block1([], [b3]);
|
||||
}
|
||||
}"
|
||||
|
||||
+198
-78
@@ -8,9 +8,9 @@ import {
|
||||
onWillUnmount,
|
||||
useState,
|
||||
} from "../../src";
|
||||
import { Portal, xml } from "../../src/";
|
||||
import { elem, makeTestFixture, nextTick, snapshotEverything } from "../helpers";
|
||||
import { xml } from "../../src/";
|
||||
import { DEV_MSG } from "../../src/app/app";
|
||||
import { elem, makeTestFixture, nextTick, snapshotEverything } from "../helpers";
|
||||
|
||||
let fixture: HTMLElement;
|
||||
let originalconsoleWarn = console.warn;
|
||||
@@ -52,13 +52,12 @@ afterEach(() => {
|
||||
describe("Portal", () => {
|
||||
test("basic use of portal", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<span>1</span>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<p>2</p>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -70,13 +69,12 @@ describe("Portal", () => {
|
||||
|
||||
test("simple catchError with portal", async () => {
|
||||
class Boom extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<span>1</span>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<p><t t-esc="a.b.c"/></p>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -107,13 +105,12 @@ describe("Portal", () => {
|
||||
|
||||
test("basic use of portal in dev mode", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<span>1</span>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<p>2</p>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -125,12 +122,11 @@ describe("Portal", () => {
|
||||
|
||||
test("conditional use of Portal", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<span>1</span>
|
||||
<Portal target="'#outside'" t-if="state.hasPortal">
|
||||
<t t-portal="'#outside'" t-if="state.hasPortal">
|
||||
<p>2</p>
|
||||
</Portal>`;
|
||||
</t>`;
|
||||
|
||||
state = useState({ hasPortal: false });
|
||||
}
|
||||
@@ -157,12 +153,12 @@ describe("Portal", () => {
|
||||
static template = xml`<p><t t-esc="props.val"/></p>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Portal, Child };
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<span>1</span>
|
||||
<Portal t-if="state.hasPortal" target="'#outside'">
|
||||
<t t-portal="'#outside'" t-if="state.hasPortal">
|
||||
<Child val="state.val"/>
|
||||
</Portal>`;
|
||||
</t>`;
|
||||
state = useState({ hasPortal: false, val: 1 });
|
||||
}
|
||||
|
||||
@@ -190,14 +186,13 @@ describe("Portal", () => {
|
||||
|
||||
test("with target in template (before portal)", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<div id="local-target"></div>
|
||||
<span>1</span>
|
||||
<Portal target="'#local-target'">
|
||||
<t t-portal="'#local-target'">
|
||||
<p>2</p>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -209,13 +204,12 @@ describe("Portal", () => {
|
||||
|
||||
test("with target in template (after portal)", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<span>1</span>
|
||||
<Portal target="'#local-target'">
|
||||
<t t-portal="'#local-target'">
|
||||
<p>2</p>
|
||||
</Portal>
|
||||
</t>
|
||||
<div id="local-target"></div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -228,12 +222,11 @@ describe("Portal", () => {
|
||||
|
||||
test("portal with target not in dom", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#does-not-exist'">
|
||||
<t t-portal="'#does-not-exist'">
|
||||
<div>2</div>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -269,12 +262,12 @@ describe("Portal", () => {
|
||||
}
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Portal, Child };
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<Child val="state.val"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
state = useState({ val: 1 });
|
||||
}
|
||||
@@ -292,12 +285,11 @@ describe("Portal", () => {
|
||||
|
||||
test("portal with only text as content", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<t t-esc="'only text'"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -308,12 +300,11 @@ describe("Portal", () => {
|
||||
|
||||
test("portal with no content", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<t t-if="false" t-esc="'ABC'"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -324,13 +315,12 @@ describe("Portal", () => {
|
||||
|
||||
test("portal with many children", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<div>1</div>
|
||||
<p>2</p>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
addOutsideDiv(fixture);
|
||||
@@ -340,13 +330,12 @@ describe("Portal", () => {
|
||||
|
||||
test("portal with dynamic body", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<span t-if="state.val" t-esc="state.val"/>
|
||||
<div t-else=""/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
state = useState({ val: "ab" });
|
||||
}
|
||||
@@ -363,12 +352,11 @@ describe("Portal", () => {
|
||||
|
||||
test("portal could have dynamically no content", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<span t-if="state.val" t-esc="state.val"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
state = useState({ val: "ab" });
|
||||
}
|
||||
@@ -396,12 +384,12 @@ describe("Portal", () => {
|
||||
}
|
||||
|
||||
class Parent extends Component {
|
||||
static components = { Portal, Child };
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal t-if="state.hasChild" target="'#outside'">
|
||||
<t t-portal="'#outside'" t-if="state.hasChild">
|
||||
<Child val="state.val"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
state = useState({ hasChild: false, val: 1 });
|
||||
setup() {
|
||||
@@ -461,12 +449,12 @@ describe("Portal", () => {
|
||||
state = {};
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Portal, Child };
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'" >
|
||||
<t t-portal="'#outside'" >
|
||||
<Child error="state.error"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
state = { error: false };
|
||||
setup() {
|
||||
@@ -492,12 +480,12 @@ describe("Portal", () => {
|
||||
<button>child</button>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Portal, Child };
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<Child />
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
const env = {};
|
||||
@@ -519,11 +507,11 @@ describe("Portal", () => {
|
||||
}
|
||||
}
|
||||
class Child extends Component {
|
||||
static components = { Portal, Child2 };
|
||||
static components = { Child2 };
|
||||
static template = xml`
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<t t-slot="default"/>
|
||||
</Portal>`;
|
||||
</t>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Child, Child2 };
|
||||
@@ -545,6 +533,111 @@ describe("Portal", () => {
|
||||
elem(childInst!).dispatchEvent(new CustomEvent("custom"));
|
||||
expect(steps).toEqual(["custom"]);
|
||||
});
|
||||
|
||||
test("Add and remove portals", async () => {
|
||||
class Parent extends Component {
|
||||
static template = xml`
|
||||
<t t-portal="'#outside'" t-foreach="portalIds" t-as="portalId" t-key="portalId">
|
||||
Portal<t t-esc="portalId"/>
|
||||
</t>`;
|
||||
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"> Portal1</div>');
|
||||
|
||||
parent.portalIds.push(2);
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe('<div id="outside"> Portal1 Portal2</div>');
|
||||
|
||||
parent.portalIds.pop();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe('<div id="outside"> Portal1</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`
|
||||
<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>`;
|
||||
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"> Portal1</div><div>1</div>');
|
||||
|
||||
parent.portalIds.push(2);
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div id="outside"> Portal1 Portal2</div><div>1</div><div>2</div>'
|
||||
);
|
||||
|
||||
parent.portalIds.pop();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe('<div id="outside"> Portal1</div><div>1</div>');
|
||||
|
||||
parent.portalIds.pop();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
|
||||
});
|
||||
|
||||
test("conditional use of Portal with div", async () => {
|
||||
class Parent extends Component {
|
||||
static template = xml`
|
||||
<t t-if="state.hasPortal">
|
||||
<div>
|
||||
<span>hasPortal</span>
|
||||
<t t-portal="'#outside'">
|
||||
<p>thePortal</p>
|
||||
</t>
|
||||
</div>
|
||||
</t>`;
|
||||
|
||||
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>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Portal: UI/UX", () => {
|
||||
@@ -554,12 +647,12 @@ describe("Portal: UI/UX", () => {
|
||||
<input id="target-me" t-att-placeholder="props.val"/>`;
|
||||
}
|
||||
class Parent extends Component {
|
||||
static components = { Portal, Child };
|
||||
static components = { Child };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="'#outside'">
|
||||
<t t-portal="'#outside'">
|
||||
<Child val="state.val"/>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
state = useState({ val: "ab" });
|
||||
}
|
||||
@@ -582,17 +675,13 @@ describe("Portal: UI/UX", () => {
|
||||
});
|
||||
|
||||
describe("Portal: Props validation", () => {
|
||||
test("target is mandatory", async () => {
|
||||
const consoleInfo = console.info;
|
||||
console.info = jest.fn();
|
||||
|
||||
test("target is mandatory 1", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal>
|
||||
<t t-portal>
|
||||
<div>2</div>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
let error: Error;
|
||||
@@ -602,21 +691,16 @@ describe("Portal: Props validation", () => {
|
||||
error = e as Error;
|
||||
}
|
||||
expect(error!).toBeDefined();
|
||||
expect(error!.message).toBe(`Missing props 'target' (component 'Portal')`);
|
||||
console.info = consoleInfo;
|
||||
expect(mockConsoleWarn).toBeCalledTimes(1);
|
||||
expect(error!.message).toContain(`attribute without value.`);
|
||||
});
|
||||
|
||||
test("target is not list", async () => {
|
||||
const consoleInfo = console.info;
|
||||
console.info = jest.fn();
|
||||
test("target is mandatory 2", async () => {
|
||||
class Parent extends Component {
|
||||
static components = { Portal };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Portal target="['body']">
|
||||
<t t-portal="">
|
||||
<div>2</div>
|
||||
</Portal>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
let error: Error;
|
||||
@@ -626,8 +710,44 @@ describe("Portal: Props validation", () => {
|
||||
error = e as Error;
|
||||
}
|
||||
expect(error!).toBeDefined();
|
||||
expect(error!.message).toBe(`Invalid Prop 'target' in component 'Portal'`);
|
||||
console.info = consoleInfo;
|
||||
expect(mockConsoleWarn).toBeCalledTimes(1);
|
||||
expect(error!.message).toBe(`Unexpected token ','`);
|
||||
});
|
||||
|
||||
test("target must be a valid selector", async () => {
|
||||
class Parent extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<t t-portal="' '">
|
||||
<div>2</div>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
let error: Error;
|
||||
try {
|
||||
await mount(Parent, fixture, { dev: true });
|
||||
} catch (e) {
|
||||
error = e as Error;
|
||||
}
|
||||
expect(error!).toBeDefined();
|
||||
expect(error!.message).toBe(`' ' is not a valid selector`);
|
||||
});
|
||||
|
||||
test("target must be a valid selector 2", async () => {
|
||||
class Parent extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<t t-portal="'aa'">
|
||||
<div>2</div>
|
||||
</t>
|
||||
</div>`;
|
||||
}
|
||||
let error: Error;
|
||||
try {
|
||||
await mount(Parent, fixture, { dev: true });
|
||||
} catch (e) {
|
||||
error = e as Error;
|
||||
}
|
||||
expect(error!).toBeDefined();
|
||||
expect(error!.message).toBe(`invalid portal target`);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user