mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
committed by
Géry Debongnie
parent
aa406b53e2
commit
e64e415b3b
+19
-2
@@ -10,6 +10,7 @@
|
|||||||
- [Methods](#methods)
|
- [Methods](#methods)
|
||||||
- [Lifecycle](#lifecycle)
|
- [Lifecycle](#lifecycle)
|
||||||
- [Composition](#composition)
|
- [Composition](#composition)
|
||||||
|
- [Asynchronous rendering](#asynchronous-rendering)
|
||||||
- [Event Handling](#event-handling)
|
- [Event Handling](#event-handling)
|
||||||
- [`t-key` directive](#t-key-directive)
|
- [`t-key` directive](#t-key-directive)
|
||||||
- [`t-mounted` directive](#t-mounted-directive)
|
- [`t-mounted` directive](#t-mounted-directive)
|
||||||
@@ -309,7 +310,7 @@ the DOM. This is a good place to remove some listeners, for example.
|
|||||||
|
|
||||||
This is the opposite method of `mounted`.
|
This is the opposite method of `mounted`.
|
||||||
|
|
||||||
## Composition
|
### Composition
|
||||||
|
|
||||||
The example above shows a QWeb template with a `t-on-click` directive. Widget
|
The example above shows a QWeb template with a `t-on-click` directive. Widget
|
||||||
templates are standard [QWeb](qweb.md) templates, but with an extra directive:
|
templates are standard [QWeb](qweb.md) templates, but with an extra directive:
|
||||||
@@ -828,9 +829,25 @@ There are two different common problems with Owl asynchronous rendering model:
|
|||||||
|
|
||||||
Here are a few tips on how to work with asynchronous widgets:
|
Here are a few tips on how to work with asynchronous widgets:
|
||||||
|
|
||||||
1. minimize the use of asynchronous widgets!
|
1. Minimize the use of asynchronous widgets!
|
||||||
2. Maybe move the asynchronous logic in a store, which then triggers (mostly)
|
2. Maybe move the asynchronous logic in a store, which then triggers (mostly)
|
||||||
synchronous renderings
|
synchronous renderings
|
||||||
3. Lazy loading external libraries is a good use case for async rendering. This
|
3. Lazy loading external libraries is a good use case for async rendering. This
|
||||||
is mostly fine, because we can assume that it will only takes a fraction of a
|
is mostly fine, because we can assume that it will only takes a fraction of a
|
||||||
second, and only once (see `owl.utils.loadJS`)
|
second, and only once (see `owl.utils.loadJS`)
|
||||||
|
4. For all the other cases, the `t-async` directive (to use alongside
|
||||||
|
`t-widget`) is there to help you. When this directive is met, a new rendering
|
||||||
|
sub tree is created, such that the rendering of that component (and its
|
||||||
|
children) is not tied to the rendering of the rest of the interface. It can
|
||||||
|
be used on an asynchronous component, to prevent it from delaying the
|
||||||
|
rendering of the whole interface, or on a synchronous one, such that its
|
||||||
|
rendering isn't delayed by other (asynchronous) components. Note that this
|
||||||
|
directive has no effect on the first rendering, but only on subsequent ones
|
||||||
|
(triggered by state or props changes).
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div t-name="ParentWidget">
|
||||||
|
<t t-widget="SyncChild"/>
|
||||||
|
<t t-widget="AsyncChild" t-async="1"/>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|||||||
+2
-2
@@ -66,8 +66,8 @@ The component system in Owl requires additional directives, to express various
|
|||||||
needs. Here is a list of all Owl specific directives:
|
needs. Here is a list of all Owl specific directives:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ------------------------- | --------------------------------------------------------------------------------------- |
|
| ------------------------------------ | --------------------------------------------------------------------------------------- |
|
||||||
| `t-widget`, `t-keepalive` | [Defining a sub component](component.md#composition) |
|
| `t-widget`, `t-keepalive`, `t-async` | [Defining a sub component](component.md#composition) |
|
||||||
| `t-ref` | [Setting a reference to a dom node or a sub component](component.md#keeping-references) |
|
| `t-ref` | [Setting a reference to a dom node or a sub component](component.md#keeping-references) |
|
||||||
| `t-key` | [Defining a key (to help virtual dom reconciliation)](component.md#t-key-directive) |
|
| `t-key` | [Defining a key (to help virtual dom reconciliation)](component.md#t-key-directive) |
|
||||||
| `t-on-*` | [Event handling](component.md#event-handling) |
|
| `t-on-*` | [Event handling](component.md#event-handling) |
|
||||||
|
|||||||
+24
-14
@@ -274,20 +274,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
|||||||
if (shouldPatch && __owl__.isMounted && renderId === __owl__.renderId) {
|
if (shouldPatch && __owl__.isMounted && renderId === __owl__.renderId) {
|
||||||
// we only update the vnode and the actual DOM if no other rendering
|
// we only update the vnode and the actual DOM if no other rendering
|
||||||
// occurred between now and when the render method was initially called.
|
// occurred between now and when the render method was initially called.
|
||||||
const patchLen = patchQueue!.length;
|
this._applyPatchQueue(<any[]>patchQueue);
|
||||||
for (let i = 0; i < patchLen; i++) {
|
|
||||||
const patch = patchQueue![i];
|
|
||||||
patch.push(patch[0].willPatch());
|
|
||||||
}
|
|
||||||
for (let i = 0; i < patchLen; i++) {
|
|
||||||
const patch = patchQueue![i];
|
|
||||||
patch[0]._patch(patch[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = patchLen - 1; i >= 0; i--) {
|
|
||||||
const patch = patchQueue![i];
|
|
||||||
patch[0].patched(patch[2]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,6 +555,29 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
|
|||||||
return <Props>props;
|
return <Props>props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the given patch queue. A patch is a pair [c, vn], where c is a
|
||||||
|
* Component instance and vn a VNode.
|
||||||
|
* 1) Call 'willPatch' on the component of each patch
|
||||||
|
* 2) Call '_patch' on the component of each patch
|
||||||
|
* 3) Call 'patched' on the component of each patch, in inverse order
|
||||||
|
*/
|
||||||
|
_applyPatchQueue(patchQueue: any[]) {
|
||||||
|
const patchLen = patchQueue.length;
|
||||||
|
for (let i = 0; i < patchLen; i++) {
|
||||||
|
const patch = patchQueue[i];
|
||||||
|
patch.push(patch[0].willPatch());
|
||||||
|
}
|
||||||
|
for (let i = 0; i < patchLen; i++) {
|
||||||
|
const patch = patchQueue[i];
|
||||||
|
patch[0]._patch(patch[1]);
|
||||||
|
}
|
||||||
|
for (let i = patchLen - 1; i >= 0; i--) {
|
||||||
|
const patch = patchQueue[i];
|
||||||
|
patch[0].patched(patch[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the component props (or next props) against the (static) props
|
* Validate the component props (or next props) against the (static) props
|
||||||
* description. This is potentially an expensive operation: it may needs to
|
* description. This is potentially an expensive operation: it may needs to
|
||||||
|
|||||||
+24
-12
@@ -225,13 +225,6 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
|
|||||||
* // t-widget directive: we start by evaluating the expression given by t-key:
|
* // t-widget directive: we start by evaluating the expression given by t-key:
|
||||||
* let key5 = "somestring";
|
* let key5 = "somestring";
|
||||||
*
|
*
|
||||||
* // We keep the index of the position of the widget in the closure. We push
|
|
||||||
* // null to reserve the slot, and will replace it later by the widget vnode,
|
|
||||||
* // when it will be ready (do not forget that preparing/rendering a widget is
|
|
||||||
* // asynchronous)
|
|
||||||
* let _2_index = c1.length;
|
|
||||||
* c1.push(null);
|
|
||||||
*
|
|
||||||
* // def3 is the promise that will contain later either the new widget
|
* // def3 is the promise that will contain later either the new widget
|
||||||
* // creation, or the props update...
|
* // creation, or the props update...
|
||||||
* let def3;
|
* let def3;
|
||||||
@@ -246,6 +239,13 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
|
|||||||
* ? context.__owl__.children[context.__owl__.cmap[key5]]
|
* ? context.__owl__.children[context.__owl__.cmap[key5]]
|
||||||
* : false;
|
* : false;
|
||||||
*
|
*
|
||||||
|
* // We keep the index of the position of the widget in the closure. We push
|
||||||
|
* // null to reserve the slot, and will replace it later by the widget vnode,
|
||||||
|
* // when it will be ready (do not forget that preparing/rendering a widget is
|
||||||
|
* // asynchronous)
|
||||||
|
* let _2_index = c1.length;
|
||||||
|
* c1.push(null);
|
||||||
|
*
|
||||||
* // we evaluate here the props given to the component. It is done here to be
|
* // we evaluate here the props given to the component. It is done here to be
|
||||||
* // able to easily reference it later, and also, it might be an expensive
|
* // able to easily reference it later, and also, it might be an expensive
|
||||||
* // computation, so it is certainly better to do it only once
|
* // computation, so it is certainly better to do it only once
|
||||||
@@ -360,7 +360,7 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
|
|||||||
|
|
||||||
QWeb.addDirective({
|
QWeb.addDirective({
|
||||||
name: "widget",
|
name: "widget",
|
||||||
extraNames: ["props", "keepalive"],
|
extraNames: ["props", "keepalive", "async"],
|
||||||
priority: 100,
|
priority: 100,
|
||||||
atNodeEncounter({ ctx, value, node, qweb }): boolean {
|
atNodeEncounter({ ctx, value, node, qweb }): boolean {
|
||||||
ctx.addLine("//WIDGET");
|
ctx.addLine("//WIDGET");
|
||||||
@@ -368,6 +368,7 @@ QWeb.addDirective({
|
|||||||
ctx.rootContext.shouldDefineQWeb = true;
|
ctx.rootContext.shouldDefineQWeb = true;
|
||||||
ctx.rootContext.shouldDefineUtils = true;
|
ctx.rootContext.shouldDefineUtils = true;
|
||||||
let keepAlive = node.getAttribute("t-keepalive") ? true : false;
|
let keepAlive = node.getAttribute("t-keepalive") ? true : false;
|
||||||
|
let async = node.getAttribute("t-async") ? true : false;
|
||||||
|
|
||||||
// t-on- events and t-transition
|
// t-on- events and t-transition
|
||||||
const events: [string, string[], string, string][] = [];
|
const events: [string, string[], string, string][] = [];
|
||||||
@@ -413,8 +414,6 @@ QWeb.addDirective({
|
|||||||
// want to evaluate it only once)
|
// want to evaluate it only once)
|
||||||
ctx.addLine(`let key${keyID} = ${key};`);
|
ctx.addLine(`let key${keyID} = ${key};`);
|
||||||
}
|
}
|
||||||
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
|
|
||||||
ctx.addLine(`c${ctx.parentNode}.push(null);`);
|
|
||||||
ctx.addLine(`let def${defID};`);
|
ctx.addLine(`let def${defID};`);
|
||||||
let templateID = key
|
let templateID = key
|
||||||
? `key${keyID}`
|
? `key${keyID}`
|
||||||
@@ -505,6 +504,13 @@ QWeb.addDirective({
|
|||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`let w${widgetID} = ${templateID} in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[${templateID}]] : false;`
|
`let w${widgetID} = ${templateID} in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[${templateID}]] : false;`
|
||||||
);
|
);
|
||||||
|
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
|
||||||
|
if (async) {
|
||||||
|
ctx.addLine(`const patchQueue${widgetID} = [];`);
|
||||||
|
ctx.addLine(`c${ctx.parentNode}.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);`);
|
||||||
|
} else {
|
||||||
|
ctx.addLine(`c${ctx.parentNode}.push(null);`);
|
||||||
|
}
|
||||||
ctx.addLine(`let props${widgetID} = {${propStr}};`);
|
ctx.addLine(`let props${widgetID} = {${propStr}};`);
|
||||||
ctx.addIf(
|
ctx.addIf(
|
||||||
`w${widgetID} && w${widgetID}.__owl__.renderPromise && !w${widgetID}.__owl__.vnode`
|
`w${widgetID} && w${widgetID}.__owl__.renderPromise && !w${widgetID}.__owl__.vnode`
|
||||||
@@ -551,7 +557,6 @@ QWeb.addDirective({
|
|||||||
|
|
||||||
ctx.addLine(`def${defID} = w${widgetID}._prepare();`);
|
ctx.addLine(`def${defID} = w${widgetID}._prepare();`);
|
||||||
// hack: specify empty remove hook to prevent the node from being removed from the DOM
|
// 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(
|
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}${transitionsInsertCode}},remove() {},destroy(vn) {${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
|
ctx.parentNode
|
||||||
@@ -560,8 +565,9 @@ QWeb.addDirective({
|
|||||||
|
|
||||||
ctx.addElse();
|
ctx.addElse();
|
||||||
// need to update widget
|
// need to update widget
|
||||||
|
const patchQueueCode = async ? `patchQueue${widgetID}` : "extra.patchQueue";
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`def${defID} = def${defID} || w${widgetID}._updateProps(props${widgetID}, extra.forceUpdate, extra.patchQueue);`
|
`def${defID} = def${defID} || w${widgetID}._updateProps(props${widgetID}, extra.forceUpdate, ${patchQueueCode});`
|
||||||
);
|
);
|
||||||
let keepAliveCode = "";
|
let keepAliveCode = "";
|
||||||
if (keepAlive) {
|
if (keepAlive) {
|
||||||
@@ -576,7 +582,13 @@ QWeb.addDirective({
|
|||||||
);
|
);
|
||||||
ctx.closeIf();
|
ctx.closeIf();
|
||||||
|
|
||||||
|
if (async) {
|
||||||
|
ctx.addLine(
|
||||||
|
`def${defID}.then(w${widgetID}._applyPatchQueue.bind(w${widgetID}, patchQueue${widgetID}));`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
ctx.addLine(`extra.promises.push(def${defID});`);
|
ctx.addLine(`extra.promises.push(def${defID});`);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
node.hasAttribute("t-if") ||
|
node.hasAttribute("t-if") ||
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ exports[`animations t-transition combined with t-widget 1`] = `
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -54,10 +54,10 @@ exports[`animations t-transition combined with t-widget and t-if 1`] = `
|
|||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
if (context['state'].display) {
|
if (context['state'].display) {
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
|
|||||||
@@ -1,5 +1,248 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`async rendering delayed t-widget with t-async directive 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let utils = this.utils;
|
||||||
|
let QWeb = this.constructor;
|
||||||
|
let owner = context;
|
||||||
|
var h = this.utils.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
let c2 = [], p2 = {key:2,on:{}};
|
||||||
|
var vn2 = h('button', p2, c2);
|
||||||
|
c1.push(vn2);
|
||||||
|
if (!context['updateApp']) {
|
||||||
|
throw new Error('Missing handler \\\\'' + 'updateApp' + \`\\\\' when evaluating template 'Parent'\`)
|
||||||
|
}
|
||||||
|
extra.handlers['click' + 2] = extra.handlers['click' + 2] || context['updateApp'].bind(owner);
|
||||||
|
p2.on['click'] = extra.handlers['click' + 2];
|
||||||
|
c2.push({text: \`Update App State\`});
|
||||||
|
var _3 = 'children';
|
||||||
|
let c4 = [], p4 = {key:4,attrs:{class: _3}};
|
||||||
|
var vn4 = h('div', p4, c4);
|
||||||
|
c1.push(vn4);
|
||||||
|
//WIDGET
|
||||||
|
let def6;
|
||||||
|
let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false;
|
||||||
|
let _5_index = c4.length;
|
||||||
|
c4.push(null);
|
||||||
|
let props7 = {val:context['state'].val};
|
||||||
|
if (w7 && w7.__owl__.renderPromise && !w7.__owl__.vnode) {
|
||||||
|
if (utils.shallowEqual(props7, w7.__owl__.renderProps)) {
|
||||||
|
def6 = w7.__owl__.renderPromise;
|
||||||
|
} else {
|
||||||
|
w7.destroy();
|
||||||
|
w7 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!w7) {
|
||||||
|
let widgetKey7 = \`Child\`;
|
||||||
|
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7];
|
||||||
|
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')}
|
||||||
|
w7 = new W7(owner, props7);
|
||||||
|
context.__owl__.cmap[7] = w7.__owl__.id;
|
||||||
|
def6 = w7._prepare();
|
||||||
|
def6 = def6.then(vnode=>{let pvnode=h(vnode.sel, {key: 7, hook: {insert(vn) {let nvn=w7._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w7.destroy();}}});c4[_5_index]=pvnode;w7.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def6 = def6 || w7._updateProps(props7, extra.forceUpdate, extra.patchQueue);
|
||||||
|
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;});
|
||||||
|
}
|
||||||
|
extra.promises.push(def6);
|
||||||
|
//WIDGET
|
||||||
|
let def9;
|
||||||
|
let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false;
|
||||||
|
let _8_index = c4.length;
|
||||||
|
const patchQueue10 = [];
|
||||||
|
c4.push(w10 && w10.__owl__.pvnode || null);
|
||||||
|
let props10 = {val:context['state'].val};
|
||||||
|
if (w10 && w10.__owl__.renderPromise && !w10.__owl__.vnode) {
|
||||||
|
if (utils.shallowEqual(props10, w10.__owl__.renderProps)) {
|
||||||
|
def9 = w10.__owl__.renderPromise;
|
||||||
|
} else {
|
||||||
|
w10.destroy();
|
||||||
|
w10 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!w10) {
|
||||||
|
let widgetKey10 = \`AsyncChild\`;
|
||||||
|
let W10 = context.widgets && context.widgets[widgetKey10] || QWeb.widgets[widgetKey10];
|
||||||
|
if (!W10) {throw new Error('Cannot find the definition of widget \\"' + widgetKey10 + '\\"')}
|
||||||
|
w10 = new W10(owner, props10);
|
||||||
|
context.__owl__.cmap[10] = w10.__owl__.id;
|
||||||
|
def9 = w10._prepare();
|
||||||
|
def9 = def9.then(vnode=>{let pvnode=h(vnode.sel, {key: 10, hook: {insert(vn) {let nvn=w10._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w10.destroy();}}});c4[_8_index]=pvnode;w10.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def9 = def9 || w10._updateProps(props10, extra.forceUpdate, patchQueue10);
|
||||||
|
def9 = def9.then(()=>{if (w10.__owl__.isDestroyed) {return};let pvnode=w10.__owl__.pvnode;c4[_8_index]=pvnode;});
|
||||||
|
}
|
||||||
|
def9.then(w10._applyPatchQueue.bind(w10, patchQueue10));
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`async rendering fast t-widget with t-async directive 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let utils = this.utils;
|
||||||
|
let QWeb = this.constructor;
|
||||||
|
let owner = context;
|
||||||
|
var h = this.utils.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
let c2 = [], p2 = {key:2,on:{}};
|
||||||
|
var vn2 = h('button', p2, c2);
|
||||||
|
c1.push(vn2);
|
||||||
|
if (!context['updateApp']) {
|
||||||
|
throw new Error('Missing handler \\\\'' + 'updateApp' + \`\\\\' when evaluating template 'Parent'\`)
|
||||||
|
}
|
||||||
|
extra.handlers['click' + 2] = extra.handlers['click' + 2] || context['updateApp'].bind(owner);
|
||||||
|
p2.on['click'] = extra.handlers['click' + 2];
|
||||||
|
c2.push({text: \`Update App State\`});
|
||||||
|
var _3 = 'children';
|
||||||
|
let c4 = [], p4 = {key:4,attrs:{class: _3}};
|
||||||
|
var vn4 = h('div', p4, c4);
|
||||||
|
c1.push(vn4);
|
||||||
|
//WIDGET
|
||||||
|
let def6;
|
||||||
|
let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false;
|
||||||
|
let _5_index = c4.length;
|
||||||
|
const patchQueue7 = [];
|
||||||
|
c4.push(w7 && w7.__owl__.pvnode || null);
|
||||||
|
let props7 = {val:context['state'].val};
|
||||||
|
if (w7 && w7.__owl__.renderPromise && !w7.__owl__.vnode) {
|
||||||
|
if (utils.shallowEqual(props7, w7.__owl__.renderProps)) {
|
||||||
|
def6 = w7.__owl__.renderPromise;
|
||||||
|
} else {
|
||||||
|
w7.destroy();
|
||||||
|
w7 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!w7) {
|
||||||
|
let widgetKey7 = \`Child\`;
|
||||||
|
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7];
|
||||||
|
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')}
|
||||||
|
w7 = new W7(owner, props7);
|
||||||
|
context.__owl__.cmap[7] = w7.__owl__.id;
|
||||||
|
def6 = w7._prepare();
|
||||||
|
def6 = def6.then(vnode=>{let pvnode=h(vnode.sel, {key: 7, hook: {insert(vn) {let nvn=w7._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w7.destroy();}}});c4[_5_index]=pvnode;w7.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def6 = def6 || w7._updateProps(props7, extra.forceUpdate, patchQueue7);
|
||||||
|
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;});
|
||||||
|
}
|
||||||
|
def6.then(w7._applyPatchQueue.bind(w7, patchQueue7));
|
||||||
|
//WIDGET
|
||||||
|
let def9;
|
||||||
|
let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false;
|
||||||
|
let _8_index = c4.length;
|
||||||
|
c4.push(null);
|
||||||
|
let props10 = {val:context['state'].val};
|
||||||
|
if (w10 && w10.__owl__.renderPromise && !w10.__owl__.vnode) {
|
||||||
|
if (utils.shallowEqual(props10, w10.__owl__.renderProps)) {
|
||||||
|
def9 = w10.__owl__.renderPromise;
|
||||||
|
} else {
|
||||||
|
w10.destroy();
|
||||||
|
w10 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!w10) {
|
||||||
|
let widgetKey10 = \`AsyncChild\`;
|
||||||
|
let W10 = context.widgets && context.widgets[widgetKey10] || QWeb.widgets[widgetKey10];
|
||||||
|
if (!W10) {throw new Error('Cannot find the definition of widget \\"' + widgetKey10 + '\\"')}
|
||||||
|
w10 = new W10(owner, props10);
|
||||||
|
context.__owl__.cmap[10] = w10.__owl__.id;
|
||||||
|
def9 = w10._prepare();
|
||||||
|
def9 = def9.then(vnode=>{let pvnode=h(vnode.sel, {key: 10, hook: {insert(vn) {let nvn=w10._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w10.destroy();}}});c4[_8_index]=pvnode;w10.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def9 = def9 || w10._updateProps(props10, extra.forceUpdate, extra.patchQueue);
|
||||||
|
def9 = def9.then(()=>{if (w10.__owl__.isDestroyed) {return};let pvnode=w10.__owl__.pvnode;c4[_8_index]=pvnode;});
|
||||||
|
}
|
||||||
|
extra.promises.push(def9);
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`async rendering t-widget with t-async directive: mixed re-renderings 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let utils = this.utils;
|
||||||
|
let QWeb = this.constructor;
|
||||||
|
let owner = context;
|
||||||
|
var h = this.utils.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
let c2 = [], p2 = {key:2,on:{}};
|
||||||
|
var vn2 = h('button', p2, c2);
|
||||||
|
c1.push(vn2);
|
||||||
|
if (!context['updateApp']) {
|
||||||
|
throw new Error('Missing handler \\\\'' + 'updateApp' + \`\\\\' when evaluating template 'Parent'\`)
|
||||||
|
}
|
||||||
|
extra.handlers['click' + 2] = extra.handlers['click' + 2] || context['updateApp'].bind(owner);
|
||||||
|
p2.on['click'] = extra.handlers['click' + 2];
|
||||||
|
c2.push({text: \`Update App State\`});
|
||||||
|
var _3 = 'children';
|
||||||
|
let c4 = [], p4 = {key:4,attrs:{class: _3}};
|
||||||
|
var vn4 = h('div', p4, c4);
|
||||||
|
c1.push(vn4);
|
||||||
|
//WIDGET
|
||||||
|
let def6;
|
||||||
|
let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false;
|
||||||
|
let _5_index = c4.length;
|
||||||
|
c4.push(null);
|
||||||
|
let props7 = {val:context['state'].val};
|
||||||
|
if (w7 && w7.__owl__.renderPromise && !w7.__owl__.vnode) {
|
||||||
|
if (utils.shallowEqual(props7, w7.__owl__.renderProps)) {
|
||||||
|
def6 = w7.__owl__.renderPromise;
|
||||||
|
} else {
|
||||||
|
w7.destroy();
|
||||||
|
w7 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!w7) {
|
||||||
|
let widgetKey7 = \`Child\`;
|
||||||
|
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7];
|
||||||
|
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')}
|
||||||
|
w7 = new W7(owner, props7);
|
||||||
|
context.__owl__.cmap[7] = w7.__owl__.id;
|
||||||
|
def6 = w7._prepare();
|
||||||
|
def6 = def6.then(vnode=>{let pvnode=h(vnode.sel, {key: 7, hook: {insert(vn) {let nvn=w7._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w7.destroy();}}});c4[_5_index]=pvnode;w7.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def6 = def6 || w7._updateProps(props7, extra.forceUpdate, extra.patchQueue);
|
||||||
|
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;});
|
||||||
|
}
|
||||||
|
extra.promises.push(def6);
|
||||||
|
//WIDGET
|
||||||
|
let def9;
|
||||||
|
let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false;
|
||||||
|
let _8_index = c4.length;
|
||||||
|
const patchQueue10 = [];
|
||||||
|
c4.push(w10 && w10.__owl__.pvnode || null);
|
||||||
|
let props10 = {val:context['state'].val};
|
||||||
|
if (w10 && w10.__owl__.renderPromise && !w10.__owl__.vnode) {
|
||||||
|
if (utils.shallowEqual(props10, w10.__owl__.renderProps)) {
|
||||||
|
def9 = w10.__owl__.renderPromise;
|
||||||
|
} else {
|
||||||
|
w10.destroy();
|
||||||
|
w10 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!w10) {
|
||||||
|
let widgetKey10 = \`AsyncChild\`;
|
||||||
|
let W10 = context.widgets && context.widgets[widgetKey10] || QWeb.widgets[widgetKey10];
|
||||||
|
if (!W10) {throw new Error('Cannot find the definition of widget \\"' + widgetKey10 + '\\"')}
|
||||||
|
w10 = new W10(owner, props10);
|
||||||
|
context.__owl__.cmap[10] = w10.__owl__.id;
|
||||||
|
def9 = w10._prepare();
|
||||||
|
def9 = def9.then(vnode=>{let pvnode=h(vnode.sel, {key: 10, hook: {insert(vn) {let nvn=w10._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w10.destroy();}}});c4[_8_index]=pvnode;w10.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def9 = def9 || w10._updateProps(props10, extra.forceUpdate, patchQueue10);
|
||||||
|
def9 = def9.then(()=>{if (w10.__owl__.isDestroyed) {return};let pvnode=w10.__owl__.pvnode;c4[_8_index]=pvnode;});
|
||||||
|
}
|
||||||
|
def9.then(w10._applyPatchQueue.bind(w10, patchQueue10));
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`class and style attributes with t-widget dynamic t-att-style is properly added and updated on widget root el 1`] = `
|
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
|
"function anonymous(context,extra
|
||||||
) {
|
) {
|
||||||
@@ -10,11 +253,11 @@ exports[`class and style attributes with t-widget dynamic t-att-style is properl
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
const _5 = context['state'].style;
|
const _5 = context['state'].style;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -51,11 +294,11 @@ exports[`class and style attributes with t-widget t-att-class is properly added/
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
const _5 = {a:context['state'].a,b:context['state'].b};
|
const _5 = {a:context['state'].a,b:context['state'].b};
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -112,10 +355,10 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
|
|||||||
context.number_value = _4[i];
|
context.number_value = _4[i];
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let key8 = context['number'];
|
let key8 = context['number'];
|
||||||
let _5_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def6;
|
let def6;
|
||||||
let w7 = key8 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[key8]] : false;
|
let w7 = key8 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[key8]] : false;
|
||||||
|
let _5_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props7 = {};
|
let props7 = {};
|
||||||
if (w7 && w7.__owl__.renderPromise && !w7.__owl__.vnode) {
|
if (w7 && w7.__owl__.renderPromise && !w7.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props7, w7.__owl__.renderProps)) {
|
if (utils.shallowEqual(props7, w7.__owl__.renderProps)) {
|
||||||
@@ -153,10 +396,10 @@ exports[`composition t-widget with dynamic value 1`] = `
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -193,10 +436,10 @@ exports[`composition t-widget with dynamic value 2 1`] = `
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -233,10 +476,10 @@ exports[`other directives with t-widget t-on with handler bound to argument 1`]
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -273,10 +516,10 @@ exports[`other directives with t-widget t-on with handler bound to empty object
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -313,10 +556,10 @@ exports[`other directives with t-widget t-on with handler bound to empty object
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -353,10 +596,10 @@ exports[`other directives with t-widget t-on with handler bound to object 1`] =
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -393,10 +636,10 @@ exports[`other directives with t-widget t-on with prevent and self modifiers (or
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -433,10 +676,10 @@ exports[`other directives with t-widget t-on with self and prevent modifiers (or
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -473,10 +716,10 @@ exports[`other directives with t-widget t-on with self modifier 1`] = `
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -513,10 +756,10 @@ exports[`other directives with t-widget t-on with stop and/or prevent modifiers
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -554,10 +797,10 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
|||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let key5 = 'somestring';
|
let key5 = 'somestring';
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = key5 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[key5]] : false;
|
let w4 = key5 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[key5]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {flag:context['state'].flag};
|
let props4 = {flag:context['state'].flag};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
@@ -594,10 +837,10 @@ exports[`t-slot directive can define and call slots 1`] = `
|
|||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('div', p1, c1);
|
||||||
//WIDGET
|
//WIDGET
|
||||||
let _2_index = c1.length;
|
|
||||||
c1.push(null);
|
|
||||||
let def3;
|
let def3;
|
||||||
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
let props4 = {};
|
let props4 = {};
|
||||||
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
|
||||||
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
|
||||||
|
|||||||
@@ -2352,6 +2352,194 @@ describe("async rendering", () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
expect(destroyCount).toBe(0);
|
expect(destroyCount).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("delayed t-widget with t-async directive", async () => {
|
||||||
|
env.qweb.addTemplates(`
|
||||||
|
<templates>
|
||||||
|
<div t-name="Parent">
|
||||||
|
<button t-on-click="updateApp">Update App State</button>
|
||||||
|
<div class="children">
|
||||||
|
<t t-widget="Child" val="state.val"/>
|
||||||
|
<t t-widget="AsyncChild" t-async="1" val="state.val"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span t-name="Child"><t t-esc="props.val"/></span>
|
||||||
|
</templates>
|
||||||
|
`);
|
||||||
|
|
||||||
|
let def;
|
||||||
|
class Parent extends Widget {
|
||||||
|
widgets = { Child, AsyncChild };
|
||||||
|
state = { val: 0 };
|
||||||
|
|
||||||
|
updateApp() {
|
||||||
|
this.state.val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Child extends Widget {}
|
||||||
|
class AsyncChild extends Child {
|
||||||
|
willUpdateProps() {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = new Parent(env);
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>0</span><span>0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
// click on button to increment Parent counter
|
||||||
|
def = makeDeferred();
|
||||||
|
fixture.querySelector("button")!.click();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1</span><span>0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
def.resolve();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1</span><span>1</span>"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("fast t-widget with t-async directive", async () => {
|
||||||
|
env.qweb.addTemplates(`
|
||||||
|
<templates>
|
||||||
|
<div t-name="Parent">
|
||||||
|
<button t-on-click="updateApp">Update App State</button>
|
||||||
|
<div class="children">
|
||||||
|
<t t-widget="Child" t-async="1" val="state.val"/>
|
||||||
|
<t t-widget="AsyncChild" val="state.val"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span t-name="Child"><t t-esc="props.val"/></span>
|
||||||
|
</templates>
|
||||||
|
`);
|
||||||
|
|
||||||
|
let def;
|
||||||
|
class Parent extends Widget {
|
||||||
|
widgets = { Child, AsyncChild };
|
||||||
|
state = { val: 0 };
|
||||||
|
|
||||||
|
updateApp() {
|
||||||
|
this.state.val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Child extends Widget {}
|
||||||
|
class AsyncChild extends Child {
|
||||||
|
willUpdateProps() {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = new Parent(env);
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>0</span><span>0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
// click on button to increment Parent counter
|
||||||
|
def = makeDeferred();
|
||||||
|
fixture.querySelector("button")!.click();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1</span><span>0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
def.resolve();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1</span><span>1</span>"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-widget with t-async directive: mixed re-renderings", async () => {
|
||||||
|
env.qweb.addTemplates(`
|
||||||
|
<templates>
|
||||||
|
<div t-name="Parent">
|
||||||
|
<button t-on-click="updateApp">Update App State</button>
|
||||||
|
<div class="children">
|
||||||
|
<t t-widget="Child" val="state.val"/>
|
||||||
|
<t t-widget="AsyncChild" t-async="1" val="state.val"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span t-name="Child" t-on-click="increment">
|
||||||
|
<t t-esc="state.val"/>/<t t-esc="props.val"/>
|
||||||
|
</span>
|
||||||
|
</templates>
|
||||||
|
`);
|
||||||
|
|
||||||
|
let def;
|
||||||
|
class Parent extends Widget {
|
||||||
|
widgets = { Child, AsyncChild };
|
||||||
|
state = { val: 0 };
|
||||||
|
|
||||||
|
updateApp() {
|
||||||
|
this.state.val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Child extends Widget {
|
||||||
|
state = { val: 0 };
|
||||||
|
|
||||||
|
increment() {
|
||||||
|
this.state.val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class AsyncChild extends Child {
|
||||||
|
willUpdateProps() {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = new Parent(env);
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(env.qweb.templates.Parent.fn.toString()).toMatchSnapshot();
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>0/0</span><span>0/0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
// click on button to increment Parent counter
|
||||||
|
def = makeDeferred();
|
||||||
|
fixture.querySelector("button")!.click();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>0/1</span><span>0/0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
// click on each Child to increment their local counter
|
||||||
|
const children = parent.el!.querySelectorAll("span");
|
||||||
|
children[0]!.click();
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1/1</span><span>0/0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
children[1]!.click();
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1/1</span><span>1/0</span>"
|
||||||
|
);
|
||||||
|
|
||||||
|
// finalize first re-rendering (coming from the props update)
|
||||||
|
def.resolve();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(fixture.querySelector(".children")!.innerHTML).toBe(
|
||||||
|
"<span>1/1</span><span>1/1</span>"
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("updating environment", () => {
|
describe("updating environment", () => {
|
||||||
|
|||||||
@@ -1196,6 +1196,94 @@ const SLOTS_CSS = `.main {
|
|||||||
border-top: 1px solid white;
|
border-top: 1px solid white;
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const ASYNC_COMPONENTS = `// This example will not work if your browser does not support ESNext class fields
|
||||||
|
|
||||||
|
// In this example, we have 2 sub widgets, one of them being async. However, we don't want renderings
|
||||||
|
// of the sync sub widget to be delayed because of the async one. We use the 't-async' directive for
|
||||||
|
// this purpose.
|
||||||
|
|
||||||
|
class App extends owl.Component {
|
||||||
|
widgets = {AsyncChild, NotificationManager};
|
||||||
|
state = { value: 0 };
|
||||||
|
|
||||||
|
increment() {
|
||||||
|
this.state.value++;
|
||||||
|
this.refs.notificationManager.notify("Value will be set to " + this.state.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncChild extends owl.Component {
|
||||||
|
willUpdateProps() {
|
||||||
|
// simulate a widget that needs to perform async stuff (e.g. an RPC)
|
||||||
|
// with the updated props before re-rendering itself
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(resolve, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotificationManager extends owl.Component {
|
||||||
|
state = { notifs: [] };
|
||||||
|
|
||||||
|
notify(notif) {
|
||||||
|
this.state.notifs.push(notif);
|
||||||
|
setTimeout(() => {
|
||||||
|
var index = this.state.notifs.indexOf(notif);
|
||||||
|
this.state.notifs.splice(index, 1);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const qweb = new owl.QWeb(TEMPLATES);
|
||||||
|
const app = new App({ qweb });
|
||||||
|
app.mount(document.body);`;
|
||||||
|
|
||||||
|
const ASYNC_COMPONENTS_XML = `<templates>
|
||||||
|
<div t-name="App" class="app">
|
||||||
|
<button t-on-click="increment">Increment</button>
|
||||||
|
<t t-widget="AsyncChild" t-async="1" value="state.value"/>
|
||||||
|
<t t-widget="NotificationManager" t-ref="notificationManager"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="value" t-name="AsyncChild">
|
||||||
|
Current value: <t t-esc="props.value"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="notification_manager" t-name="NotificationManager">
|
||||||
|
<t t-foreach="state.notifs" t-as="notif">
|
||||||
|
<div class="notification"><t t-esc="notif"/></div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</templates>`;
|
||||||
|
|
||||||
|
const ASYNC_COMPONENTS_CSS = `.app {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: darkred;
|
||||||
|
font-size: 30px;
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 26px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification_manager {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.notification {
|
||||||
|
width: 150px;
|
||||||
|
margin: 4px 8px;
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid: black;
|
||||||
|
background-color: lightgray;
|
||||||
|
}`;
|
||||||
|
|
||||||
const EMPTY = `class App extends owl.Component {
|
const EMPTY = `class App extends owl.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1252,6 +1340,12 @@ export const SAMPLES = [
|
|||||||
xml: SLOTS_XML,
|
xml: SLOTS_XML,
|
||||||
css: SLOTS_CSS
|
css: SLOTS_CSS
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Asynchronous components",
|
||||||
|
code: ASYNC_COMPONENTS,
|
||||||
|
xml: ASYNC_COMPONENTS_XML,
|
||||||
|
css: ASYNC_COMPONENTS_CSS
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Empty",
|
description: "Empty",
|
||||||
code: EMPTY
|
code: EMPTY
|
||||||
|
|||||||
Reference in New Issue
Block a user