mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
+5
-3
@@ -497,10 +497,10 @@ directive is there to help.
|
||||
Whenever a node has a `t-transition` directive, with a `name` value, the following
|
||||
will happen:
|
||||
|
||||
At node creation:
|
||||
At node insertion:
|
||||
|
||||
- the css classes `name-enter` and `name-enter-active` will be added before the
|
||||
node is added to the DOM,
|
||||
- the css classes `name-enter` and `name-enter-active` will be added directly
|
||||
when the node is inserted into the DOM,
|
||||
- on the next animation frame: the css class `name-enter` will be removed and the
|
||||
class `name-enter-to` will be added (so they can be used to trigger css
|
||||
transition effects),
|
||||
@@ -535,6 +535,8 @@ For example, a simple fade in/out effect can be done with this:
|
||||
}
|
||||
```
|
||||
|
||||
The `t-transition` directive can be combined with `t-widget`.
|
||||
|
||||
Note: more information on animations are available [here](doc/animations.md).
|
||||
|
||||
### `t-mounted` directive
|
||||
|
||||
@@ -269,6 +269,9 @@ export class QWeb {
|
||||
// pollute the rendering context by adding some keys in it.
|
||||
ctx.code.unshift(" let owner = context;");
|
||||
}
|
||||
if (ctx.shouldDefineUtils) {
|
||||
ctx.code.unshift(" let utils = this.utils;");
|
||||
}
|
||||
|
||||
if (!ctx.rootNode) {
|
||||
throw new Error("A template should have one root node");
|
||||
@@ -613,6 +616,7 @@ export class Context {
|
||||
rootContext: Context;
|
||||
caller: Element | undefined;
|
||||
shouldDefineOwner: boolean = false;
|
||||
shouldDefineUtils: boolean = false;
|
||||
shouldProtectContext: boolean = false;
|
||||
inLoop: boolean = false;
|
||||
inPreTag: boolean = false;
|
||||
|
||||
+38
-11
@@ -192,7 +192,10 @@ QWeb.addDirective({
|
||||
* explanation of the code generated by the t-widget directive for the following
|
||||
* situation:
|
||||
* ```xml
|
||||
* <t t-widget="child" t-key="'somestring'" t-props="{flag:state.flag}"/>
|
||||
* <t t-widget="child"
|
||||
* t-key="'somestring'"
|
||||
* t-props="{flag:state.flag}"
|
||||
* t-transition="fade"/>
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
@@ -252,6 +255,8 @@ QWeb.addDirective({
|
||||
* }
|
||||
* w4 = new W4(owner, props4);
|
||||
*
|
||||
* let utils = this.utils;
|
||||
*
|
||||
* // Whenever we rerender the parent widget, we need to be sure that we
|
||||
* // are able to find the widget instance. To do that, we register it to
|
||||
* // the parent cmap (children map). Note that the 'template' key is
|
||||
@@ -281,15 +286,21 @@ QWeb.addDirective({
|
||||
* // to synchronise the pvnode elm with the resulting elm
|
||||
* let nvn = w4._mount(vnode, vn.elm);
|
||||
* pvnode.elm = nvn.elm;
|
||||
* // what follows is only present if there are animations on the widget
|
||||
* utils.transitionInsert(vn.elm, "fade");
|
||||
* },
|
||||
* remove() {
|
||||
* // apparently, in some cases, it is necessary to call the destroy
|
||||
* // method here
|
||||
* w4.destroy();
|
||||
* // override with empty function to prevent from removing the node
|
||||
* // directly. It will be removed when destroy is called anyway, which
|
||||
* // delays the removal if there are animations.
|
||||
* },
|
||||
* destroy() {
|
||||
* // and here...
|
||||
* w4.destroy();
|
||||
* // if there are animations, we delay the call to destroy on the
|
||||
* // widget, if not, we call it directly.
|
||||
* let finalize = () => {
|
||||
* w4.destroy();
|
||||
* };
|
||||
* utils.transitionRemove(vn.elm, "fade", finalize);
|
||||
* }
|
||||
* };
|
||||
* // the pvnode is inserted at the correct position in the div's children
|
||||
@@ -332,16 +343,20 @@ QWeb.addDirective({
|
||||
atNodeEncounter({ ctx, value, node }): boolean {
|
||||
ctx.addLine("//WIDGET");
|
||||
ctx.rootContext.shouldDefineOwner = true;
|
||||
ctx.rootContext.shouldDefineUtils = true;
|
||||
let props = node.getAttribute("t-props");
|
||||
let keepAlive = node.getAttribute("t-keepalive") ? true : false;
|
||||
|
||||
// t-on- events...
|
||||
// t-on- events and t-transition
|
||||
const events: [string, string][] = [];
|
||||
let transition: string = "";
|
||||
const attributes = (<Element>node).attributes;
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
const name = attributes[i].name;
|
||||
if (name.startsWith("t-on-")) {
|
||||
events.push([name.slice(5), attributes[i].textContent!]);
|
||||
} else if (name === "t-transition") {
|
||||
transition = attributes[i].textContent!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,13 +393,23 @@ QWeb.addDirective({
|
||||
ctx.addLine(`const ${refKey} = ${ctx.formatExpression(ref)}`);
|
||||
refExpr = `context.refs[${refKey}] = w${widgetID};`;
|
||||
}
|
||||
|
||||
let transitionsInsertCode = "";
|
||||
if (transition) {
|
||||
transitionsInsertCode = `utils.transitionInsert(vn.elm, '${transition}');`;
|
||||
}
|
||||
let finalizeWidgetCode = `w${widgetID}.${
|
||||
keepAlive ? "unmount" : "destroy"
|
||||
}()`;
|
||||
}();`;
|
||||
if (ref) {
|
||||
finalizeWidgetCode += `;delete context.refs[${refKey}]`;
|
||||
finalizeWidgetCode += `delete context.refs[${refKey}];`; // FIXME: shouldn't we keep ref if keepAlive is true?
|
||||
}
|
||||
if (transition) {
|
||||
finalizeWidgetCode = `let finalize = () => {
|
||||
${finalizeWidgetCode}
|
||||
};
|
||||
utils.transitionRemove(vn.elm, '${transition}', finalize);`;
|
||||
}
|
||||
|
||||
let createHook = "";
|
||||
let classAttr = node.getAttribute("class");
|
||||
let tattClass = node.getAttribute("t-att-class");
|
||||
@@ -447,8 +472,10 @@ QWeb.addDirective({
|
||||
ctx.addLine(`w${widgetID}.on('${event}', owner, owner['${method}'])`);
|
||||
}
|
||||
ctx.addLine(`def${defID} = w${widgetID}._prepare();`);
|
||||
// hack: specify empty remove hook to prevent the node from being removed from the DOM
|
||||
// FIXME: click to re-add widget during remove transition -> leak
|
||||
ctx.addLine(
|
||||
`def${defID} = def${defID}.then(vnode=>{${createHook}let pvnode=h(vnode.sel, {key: ${templateID}, hook: {insert(vn){let nvn=w${widgetID}._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;${refExpr}},remove(){${finalizeWidgetCode}},destroy(){${finalizeWidgetCode}}}});c${
|
||||
`def${defID} = def${defID}.then(vnode=>{${createHook}let pvnode=h(vnode.sel, {key: ${templateID}, hook: {insert(vn) {let nvn=w${widgetID}._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;${refExpr}${transitionsInsertCode}},remove() {},destroy(vn) {${finalizeWidgetCode}}}});c${
|
||||
ctx.parentNode
|
||||
}[_${dummyID}_index]=pvnode;w${widgetID}.__owl__.pvnode = pvnode;});`
|
||||
);
|
||||
|
||||
@@ -1,8 +1,85 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`animations t-transition combined with t-widget 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
var vn1 = h('div', p1, c1);
|
||||
//WIDGET
|
||||
let _2_index = c1.length;
|
||||
c1.push(null);
|
||||
let def3;
|
||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||
let props4 = {};
|
||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode && props4 !== w4.__owl__.renderProps) {
|
||||
w4.destroy();
|
||||
w4 = false
|
||||
}
|
||||
if (!w4) {
|
||||
let W4 = context.widgets['Child'];
|
||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"Child\\"\`)}
|
||||
w4 = new W4(owner, props4);
|
||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||
def3 = w4._prepare();
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;utils.transitionInsert(vn.elm, 'chimay');},remove() {},destroy(vn) {let finalize = () => {
|
||||
w4.destroy();
|
||||
};
|
||||
utils.transitionRemove(vn.elm, 'chimay', finalize);}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
}
|
||||
extra.promises.push(def3);
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`animations t-transition combined with t-widget and t-if 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
var vn1 = h('div', p1, c1);
|
||||
if (context['state'].display) {
|
||||
//WIDGET
|
||||
let _2_index = c1.length;
|
||||
c1.push(null);
|
||||
let def3;
|
||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||
let props4 = {};
|
||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode && props4 !== w4.__owl__.renderProps) {
|
||||
w4.destroy();
|
||||
w4 = false
|
||||
}
|
||||
if (!w4) {
|
||||
let W4 = context.widgets['Child'];
|
||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"Child\\"\`)}
|
||||
w4 = new W4(owner, props4);
|
||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||
def3 = w4._prepare();
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;utils.transitionInsert(vn.elm, 'chimay');},remove() {},destroy(vn) {let finalize = () => {
|
||||
w4.destroy();
|
||||
};
|
||||
utils.transitionRemove(vn.elm, 'chimay', finalize);}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
}
|
||||
extra.promises.push(def3);
|
||||
}
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`class and style attributes with t-widget dynamic t-att-style is properly added and updated on widget root el 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
@@ -24,7 +101,7 @@ exports[`class and style attributes with t-widget dynamic t-att-style is properl
|
||||
w4 = new W4(owner, props4);
|
||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||
def3 = w4._prepare();
|
||||
def3 = def3.then(vnode=>{vnode.data.hook = {create(_, vn){vn.elm.style = _5}};let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn){let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove(){w4.destroy()},destroy(){w4.destroy()}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
def3 = def3.then(vnode=>{vnode.data.hook = {create(_, vn){vn.elm.style = _5}};let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};w4.el.style=_5;let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
@@ -37,6 +114,7 @@ exports[`class and style attributes with t-widget dynamic t-att-style is properl
|
||||
exports[`class and style attributes with t-widget t-att-class is properly added/removed on widget root el 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
@@ -62,7 +140,7 @@ exports[`class and style attributes with t-widget t-att-class is properly added/
|
||||
if (_5[k]) {
|
||||
vn.elm.classList.add(k);
|
||||
}
|
||||
}}};let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn){let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove(){w4.destroy()},destroy(){w4.destroy()}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
}}};let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let cl=w4.el.classList;for (let k in _5) {if (_5[k]) {cl.add(k)} else {cl.remove(k)}}let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
@@ -75,6 +153,7 @@ exports[`class and style attributes with t-widget t-att-class is properly added/
|
||||
exports[`composition sub widgets with some state rendered in a loop 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
context = Object.create(context);
|
||||
var h = this.utils.h;
|
||||
@@ -109,7 +188,7 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
|
||||
w7 = new W7(owner, props7);
|
||||
context.__owl__.cmap[key8] = w7.__owl__.id;
|
||||
def6 = w7._prepare();
|
||||
def6 = def6.then(vnode=>{let pvnode=h(vnode.sel, {key: key8, hook: {insert(vn){let nvn=w7._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove(){w7.destroy()},destroy(){w7.destroy()}}});c1[_5_index]=pvnode;w7.__owl__.pvnode = pvnode;});
|
||||
def6 = def6.then(vnode=>{let pvnode=h(vnode.sel, {key: key8, hook: {insert(vn) {let nvn=w7._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w7.destroy();}}});c1[_5_index]=pvnode;w7.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def6 = w7._updateProps(props7, extra.forceUpdate, extra.patchQueue);
|
||||
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c1[_5_index]=pvnode;});
|
||||
@@ -123,6 +202,7 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
|
||||
exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
@@ -144,7 +224,7 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
||||
w4 = new W4(owner, props4);
|
||||
context.__owl__.cmap[key5] = w4.__owl__.id;
|
||||
def3 = w4._prepare();
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: key5, hook: {insert(vn){let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove(){w4.destroy()},destroy(){w4.destroy()}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: key5, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
@@ -157,6 +237,7 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
||||
exports[`random stuff/miscellaneous t-props should not be undefined (snapshotting) 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
let utils = this.utils;
|
||||
let owner = context;
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
@@ -177,7 +258,7 @@ exports[`random stuff/miscellaneous t-props should not be undefined (snapshottin
|
||||
w4 = new W4(owner, props4);
|
||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||
def3 = w4._prepare();
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn){let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove(){w4.destroy()},destroy(){w4.destroy()}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
function anonymous(context, extra) {
|
||||
var h = this.utils.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
var vn1 = h('div', p1, c1);
|
||||
if (context['state'].display) {
|
||||
//WIDGET
|
||||
let _2_index = c1.length;
|
||||
c1.push(null);
|
||||
let def3;
|
||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||
let props4 = {};
|
||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode && props4 !== w4.__owl__.renderProps) {
|
||||
w4.destroy();
|
||||
w4 = false
|
||||
}
|
||||
if (!w4) {
|
||||
let W4 = context.widgets['Child'];
|
||||
if (!W4) {throw new Error(`Cannot find the definition of widget "Child"`)}
|
||||
w4 = new W4(owner, props4);
|
||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||
def3 = w4._prepare();
|
||||
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert: (vn) => {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;this.utils.transitionInsert(vn.elm, 'chimay');},remove: () => {},destroy: (vn) => {let finalize = () => {
|
||||
w4.destroy();
|
||||
};
|
||||
this.utils.transitionRemove(vn.elm, 'chimay', finalize);}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||
} else {
|
||||
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||
}
|
||||
extra.promises.push(def3);
|
||||
}
|
||||
|
||||
}
|
||||
+97
-2
@@ -1778,7 +1778,6 @@ describe("random stuff/miscellaneous", () => {
|
||||
"C:_patch",
|
||||
"E:willUnmount",
|
||||
"E:destroy",
|
||||
"E:destroy", // maybe should look into this
|
||||
"F:_patch(from _mount)",
|
||||
"F:mounted",
|
||||
"D:_patch",
|
||||
@@ -2281,7 +2280,7 @@ describe("t-mounted directive", () => {
|
||||
widget.f = jest.fn();
|
||||
await widget.mount(fixture);
|
||||
|
||||
patchNextFrame((cb) => cb());
|
||||
patchNextFrame(cb => cb());
|
||||
expect(widget.f).toHaveBeenCalledTimes(0);
|
||||
|
||||
widget.state.flag = true;
|
||||
@@ -2426,4 +2425,100 @@ describe("animations", () => {
|
||||
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(spanNode.className).toBe("");
|
||||
});
|
||||
|
||||
test("t-transition combined with t-widget", async () => {
|
||||
expect.assertions(5);
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div><t t-widget="Child" t-transition="chimay"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("Child", `<span>blue</span>`);
|
||||
class Parent extends Widget {
|
||||
widgets = { Child: Child };
|
||||
}
|
||||
class Child extends Widget {}
|
||||
const widget = new Parent(env);
|
||||
|
||||
let def = makeDeferred();
|
||||
var spanNode;
|
||||
patchNextFrame(cb => {
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-enter chimay-enter-active">blue</span></div>'
|
||||
);
|
||||
cb(performance.now());
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-enter-active chimay-enter-to">blue</span></div>'
|
||||
);
|
||||
def.resolve();
|
||||
});
|
||||
await widget.mount(fixture);
|
||||
spanNode = widget.el!.children[0];
|
||||
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-enter chimay-enter-active">blue</span></div>'
|
||||
);
|
||||
|
||||
await def; // wait for the mocked repaint to be done
|
||||
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe('<div><span class="">blue</span></div>');
|
||||
});
|
||||
|
||||
test("t-transition combined with t-widget and t-if", async () => {
|
||||
expect.assertions(8);
|
||||
|
||||
env.qweb.addTemplate(
|
||||
"Parent",
|
||||
`<div><t t-if="state.display" t-widget="Child" t-transition="chimay"/></div>`
|
||||
);
|
||||
env.qweb.addTemplate("Child", `<span>blue</span>`);
|
||||
class Parent extends Widget {
|
||||
widgets = { Child: Child };
|
||||
state = { display: true };
|
||||
}
|
||||
class Child extends Widget {}
|
||||
const widget = new Parent(env);
|
||||
|
||||
let def = makeDeferred();
|
||||
var spanNode;
|
||||
patchNextFrame(cb => {
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-enter chimay-enter-active">blue</span></div>'
|
||||
);
|
||||
cb(performance.now());
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-enter-active chimay-enter-to">blue</span></div>'
|
||||
);
|
||||
def.resolve();
|
||||
});
|
||||
await widget.mount(fixture);
|
||||
spanNode = widget.el!.children[0];
|
||||
|
||||
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-enter chimay-enter-active">blue</span></div>'
|
||||
);
|
||||
|
||||
await def; // wait for the mocked repaint to be done
|
||||
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe('<div><span class="">blue</span></div>');
|
||||
|
||||
// remove span from the DOM
|
||||
def = makeDeferred();
|
||||
widget.state.display = false;
|
||||
patchNextFrame(cb => {
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-leave chimay-leave-active">blue</span></div>'
|
||||
);
|
||||
cb(performance.now());
|
||||
expect(fixture.innerHTML).toBe(
|
||||
'<div><span class="chimay-leave-active chimay-leave-to">blue</span></div>'
|
||||
);
|
||||
def.resolve();
|
||||
});
|
||||
await def; // wait for the mocked repaint to be done
|
||||
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||
expect(fixture.innerHTML).toBe("<div></div>");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user