mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: make sure default slot is applied
Before this commit, owl was erroneously defining default slots in most cases, even though they are empty. The problem occurs when the content of a component slots is a t-set-slot, and we remove that, then use the rest as default slots, even though it is only reduced to a set of text nodes. With this commit, we only consider the content as default content if it is not only a sequence of text nodes containing only spaces. closes #882
This commit is contained in:
@@ -44,23 +44,23 @@ exports[`t-slot directive can define and call slots 2`] = `
|
||||
) {
|
||||
// Template name: \\"Dialog\\"
|
||||
let h = this.h;
|
||||
let c8 = [], p8 = {key:8};
|
||||
let vn8 = h('div', p8, c8);
|
||||
let c9 = [], p9 = {key:9};
|
||||
let vn9 = h('div', p9, c9);
|
||||
let c10 = [], p10 = {key:10};
|
||||
let vn10 = h('div', p10, c10);
|
||||
c9.push(vn10);
|
||||
const slot11 = this.constructor.slots[context.__owl__.slotId + '_' + 'header'];
|
||||
if (slot11) {
|
||||
slot11.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c10, parent: extra.parent || context}));
|
||||
c8.push(vn9);
|
||||
const slot10 = this.constructor.slots[context.__owl__.slotId + '_' + 'header'];
|
||||
if (slot10) {
|
||||
slot10.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c9, parent: extra.parent || context}));
|
||||
}
|
||||
let c12 = [], p12 = {key:12};
|
||||
let vn12 = h('div', p12, c12);
|
||||
c9.push(vn12);
|
||||
const slot13 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer'];
|
||||
if (slot13) {
|
||||
slot13.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c12, parent: extra.parent || context}));
|
||||
let c11 = [], p11 = {key:11};
|
||||
let vn11 = h('div', p11, c11);
|
||||
c8.push(vn11);
|
||||
const slot12 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer'];
|
||||
if (slot12) {
|
||||
slot12.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c11, parent: extra.parent || context}));
|
||||
}
|
||||
return vn9;
|
||||
return vn8;
|
||||
}"
|
||||
`;
|
||||
|
||||
@@ -136,23 +136,23 @@ exports[`t-slot directive can define and call slots using old t-set keyword 2`]
|
||||
) {
|
||||
// Template name: \\"__template__1\\"
|
||||
let h = this.h;
|
||||
let c8 = [], p8 = {key:8};
|
||||
let vn8 = h('div', p8, c8);
|
||||
let c9 = [], p9 = {key:9};
|
||||
let vn9 = h('div', p9, c9);
|
||||
let c10 = [], p10 = {key:10};
|
||||
let vn10 = h('div', p10, c10);
|
||||
c9.push(vn10);
|
||||
const slot11 = this.constructor.slots[context.__owl__.slotId + '_' + 'header'];
|
||||
if (slot11) {
|
||||
slot11.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c10, parent: extra.parent || context}));
|
||||
c8.push(vn9);
|
||||
const slot10 = this.constructor.slots[context.__owl__.slotId + '_' + 'header'];
|
||||
if (slot10) {
|
||||
slot10.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c9, parent: extra.parent || context}));
|
||||
}
|
||||
let c12 = [], p12 = {key:12};
|
||||
let vn12 = h('div', p12, c12);
|
||||
c9.push(vn12);
|
||||
const slot13 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer'];
|
||||
if (slot13) {
|
||||
slot13.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c12, parent: extra.parent || context}));
|
||||
let c11 = [], p11 = {key:11};
|
||||
let vn11 = h('div', p11, c11);
|
||||
c8.push(vn11);
|
||||
const slot12 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer'];
|
||||
if (slot12) {
|
||||
slot12.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c11, parent: extra.parent || context}));
|
||||
}
|
||||
return vn9;
|
||||
return vn8;
|
||||
}"
|
||||
`;
|
||||
|
||||
@@ -215,6 +215,45 @@ exports[`t-slot directive dafault slots can define a default content 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-slot directive default slot next to named slot, with default content 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
// Template name: \\"__template__2\\"
|
||||
let utils = this.constructor.utils;
|
||||
let QWeb = this.constructor;
|
||||
let parent = context;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
let vn1 = h('div', p1, c1);
|
||||
// Component 'Dialog'
|
||||
let w2 = '__3__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__3__']] : false;
|
||||
let props2 = {};
|
||||
if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) {
|
||||
w2.destroy();
|
||||
w2 = false;
|
||||
}
|
||||
if (w2) {
|
||||
w2.__updateProps(props2, extra.fiber, utils.combine(context, scope));
|
||||
let pvnode = w2.__owl__.pvnode;
|
||||
c1.push(pvnode);
|
||||
} else {
|
||||
let componentKey2 = \`Dialog\`;
|
||||
let W2 = scope['Dialog'] || context.constructor.components[componentKey2] || QWeb.components[componentKey2];
|
||||
if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')}
|
||||
w2 = new W2(parent, props2);
|
||||
parent.__owl__.cmap['__3__'] = w2.__owl__.id;
|
||||
w2.__owl__.slotId = 1;
|
||||
let fiber = w2.__prepare(extra.fiber, utils.combine(context, scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; });
|
||||
let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}});
|
||||
c1.push(pvnode);
|
||||
w2.__owl__.pvnode = pvnode;
|
||||
}
|
||||
w2.__owl__.parentLastFiberId = extra.fiber.id;
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-slot directive default slot work with text nodes 1`] = `
|
||||
"function anonymous(context, extra
|
||||
) {
|
||||
@@ -233,15 +272,15 @@ exports[`t-slot directive dynamic t-slot call 1`] = `
|
||||
let utils = this.constructor.utils;
|
||||
let scope = Object.create(context);
|
||||
let h = this.h;
|
||||
let c10 = [], p10 = {key:10,on:{}};
|
||||
let vn10 = h('button', p10, c10);
|
||||
extra.handlers['click__11__'] = extra.handlers['click__11__'] || function (e) {if (context.__owl__.status === 5){return}utils.getComponent(context)['toggle'](e);};
|
||||
p10.on['click'] = extra.handlers['click__11__'];
|
||||
const slot12 = this.constructor.slots[context.__owl__.slotId + '_' + (scope['current'].slot)];
|
||||
if (slot12) {
|
||||
slot12.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c10, parent: extra.parent || context}));
|
||||
let c9 = [], p9 = {key:9,on:{}};
|
||||
let vn9 = h('button', p9, c9);
|
||||
extra.handlers['click__10__'] = extra.handlers['click__10__'] || function (e) {if (context.__owl__.status === 5){return}utils.getComponent(context)['toggle'](e);};
|
||||
p9.on['click'] = extra.handlers['click__10__'];
|
||||
const slot11 = this.constructor.slots[context.__owl__.slotId + '_' + (scope['current'].slot)];
|
||||
if (slot11) {
|
||||
slot11.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c9, parent: extra.parent || context}));
|
||||
}
|
||||
return vn10;
|
||||
return vn9;
|
||||
}"
|
||||
`;
|
||||
|
||||
|
||||
@@ -467,6 +467,48 @@ describe("t-slot directive", () => {
|
||||
expect(QWeb.slots["1_default"].toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("default slot next to named slot, with default content", async () => {
|
||||
class Dialog extends Component {
|
||||
// We're using 2 slots here: a "default" one and a "footer",
|
||||
// both having default children nodes.
|
||||
static template = xml`
|
||||
<div class="Dialog">
|
||||
<div class="content">
|
||||
<t t-slot="default">
|
||||
Default content
|
||||
</t>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<t t-slot="footer">
|
||||
Default footer
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
// Here we're trying to assign the "footer" slot with some content
|
||||
static components = { Dialog };
|
||||
static template = xml`
|
||||
<div>
|
||||
<Dialog>
|
||||
<t t-set-slot="footer">
|
||||
Overridden footer
|
||||
</t>
|
||||
</Dialog>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
await mount(App, { target: fixture });
|
||||
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><div class="Dialog"><div class="content"> Default content </div><div class="footer"> Overridden footer </div></div></div>'
|
||||
);
|
||||
expect(QWeb.TEMPLATES[App.template].fn.toString()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("multiple roots are allowed in a named slot", async () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
|
||||
Reference in New Issue
Block a user