[REF] component: use 'component' instead of 'widget'

This commit is contained in:
Géry Debongnie
2019-06-20 09:42:33 +02:00
parent 5524c2e323
commit e6a5934162
22 changed files with 553 additions and 586 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ find some more information [here](doc/comparison.md).
## Example ## Example
Here is a short example to illustrate interactive widgets: Here is a short example to illustrate interactive components:
```xml ```xml
<templates> <templates>
+1 -1
View File
@@ -87,7 +87,7 @@ For example, a simple fade in/out effect can be done with this:
} }
``` ```
The `t-transition` directive can be combined with `t-widget`. The `t-transition` directive can be applied on a node element or on a component.
Notes: Notes:
+4 -4
View File
@@ -91,17 +91,17 @@ there is a syntax highlighter for jsx here on github!
This is actually a big difference between OWL and React/Vue: components in OWL This is actually a big difference between OWL and React/Vue: components in OWL
are totally asynchronous. They have two asynchronous hooks in their lifecycle: are totally asynchronous. They have two asynchronous hooks in their lifecycle:
- `willStart` (before the widget starts rendering) - `willStart` (before the component starts rendering)
- `willUpdateProps` (before new props are set) - `willUpdateProps` (before new props are set)
Both these methods can be implemented and return a promise. The rendering will Both these methods can be implemented and return a promise. The rendering will
then wait for these promises to be completed before patching the DOM. This is then wait for these promises to be completed before patching the DOM. This is
useful for some use cases: for example, a widget may want to fetch an external useful for some use cases: for example, a component may want to fetch an external
library (a calendar widget may need a specialized calendar rendering library), library (a calendar component may need a specialized calendar rendering library),
in its willStart hook. in its willStart hook.
```javascript ```javascript
class MyCalendarWidget extends owl.Component { class MyCalendarComponent extends owl.Component {
... ...
willStart() { willStart() {
+87 -87
View File
@@ -4,7 +4,7 @@
- [Overview](#overview) - [Overview](#overview)
- [Example](#example) - [Example](#example)
- [Root Widget And Environment](#root-widget-and-environment) - [Root Component And Environment](#root-component-and-environment)
- [Reference](#reference) - [Reference](#reference)
- [Properties](#properties) - [Properties](#properties)
- [Static Properties](#static-properties) - [Static Properties](#static-properties)
@@ -28,11 +28,11 @@ OWL components are the building blocks for user interface. They are designed to
1. **declarative:** the user interface should be described in term of the state 1. **declarative:** the user interface should be described in term of the state
of the application, not as a sequence of imperative steps. of the application, not as a sequence of imperative steps.
2. **composable:** each widget can seamlessly be created in a parent widget by 2. **composable:** each component can seamlessly be created in a parent component by
a simple directive in its template. a simple tag or directive in its template.
3. **asynchronous rendering:** the framework will transparently wait for each 3. **asynchronous rendering:** the framework will transparently wait for each
subwidgets to be ready before applying the rendering. It uses native promises sub components to be ready before applying the rendering. It uses native promises
under the hood. under the hood.
4. **uses QWeb as a template system:** the templates are described in XML 4. **uses QWeb as a template system:** the templates are described in XML
@@ -41,7 +41,7 @@ OWL components are the building blocks for user interface. They are designed to
OWL components are defined as a subclass of Component. The rendering is OWL components are defined as a subclass of Component. The rendering is
exclusively done by a [QWeb](qweb.md) template (which needs to be preloaded in QWeb). exclusively done by a [QWeb](qweb.md) template (which needs to be preloaded in QWeb).
Rendering a component generates a virtual dom representation Rendering a component generates a virtual dom representation
of the widget, which is then patched to the DOM, in order to apply the changes in an efficient way. of the component, which is then patched to the DOM, in order to apply the changes in an efficient way.
OWL components observe their states, and rerender themselves whenever it is OWL components observe their states, and rerender themselves whenever it is
changed. This is done by an [observer](observer.md). changed. This is done by an [observer](observer.md).
@@ -76,10 +76,10 @@ a state object is defined. It is not mandatory to use the state object, but it
is certainly encouraged. The state object is [observed](observer.md), and any is certainly encouraged. The state object is [observed](observer.md), and any
change to it will cause a rerendering. change to it will cause a rerendering.
## Root Widget And Environment ## Root Component And Environment
Most of the time, Owl widget will be created automatically by the `t-widget` Most of the time, an Owl component will be created automatically by a tag (or the `t-component`
directive in a template. There is however an obvious exception: the root widget directive) in a template. There is however an obvious exception: the root component
of an Owl application has to be created manually: of an Owl application has to be created manually:
```js ```js
@@ -91,7 +91,7 @@ const app = new App(env);
app.mount(document.body); app.mount(document.body);
``` ```
The root widget needs an environment. In Owl, an environment is an object with The root component needs an environment. In Owl, an environment is an object with
a `qweb` key, which has to be a [QWeb](qweb.md) instance. This qweb instance will a `qweb` key, which has to be a [QWeb](qweb.md) instance. This qweb instance will
be used to render everything. be used to render everything.
@@ -102,7 +102,7 @@ easy to test a component.
## Reference ## Reference
An Owl component is a small class which represent a widget or some UI element. An Owl component is a small class which represent a component or some UI element.
It exists in the context of an environment (`env`), which is propagated from a It exists in the context of an environment (`env`), which is propagated from a
parent to its children. The environment needs to have a QWeb instance, which parent to its children. The environment needs to have a QWeb instance, which
will be used to render the component template. will be used to render the component template.
@@ -123,7 +123,7 @@ find a template with the component name (or one of its ancestor).
- **`state`** (Object): this is the location of the component's state, if there is - **`state`** (Object): this is the location of the component's state, if there is
any. After the willStart method, the `state` property is observed, and each any. After the willStart method, the `state` property is observed, and each
change will cause the widget to rerender itself. change will cause the component to rerender itself.
- **`props`** (Object): this is an object given (in the constructor) by the parent - **`props`** (Object): this is an object given (in the constructor) by the parent
to configure the component. It can be dynamically changed later by the parent, to configure the component. It can be dynamically changed later by the parent,
@@ -131,7 +131,7 @@ find a template with the component name (or one of its ancestor).
As such, it should not ever be modified by the component!! As such, it should not ever be modified by the component!!
- **`refs`** (Object): the `refs` object contains all references to sub DOM nodes - **`refs`** (Object): the `refs` object contains all references to sub DOM nodes
or sub widgets defined by a `t-ref` directive in the component's template. or sub components defined by a `t-ref` directive in the component's template.
### Static Properties ### Static Properties
@@ -163,7 +163,7 @@ find a template with the component name (or one of its ancestor).
DOM in the same stack frame. DOM in the same stack frame.
- **`shouldUpdate(nextProps)`**: this method is called each time a component's props - **`shouldUpdate(nextProps)`**: this method is called each time a component's props
are updated. It returns a boolean, which indicates if the widget should are updated. It returns a boolean, which indicates if the component should
ignore a props update. If it returns false, then `willUpdateProps` will not ignore a props update. If it returns false, then `willUpdateProps` will not
be called, and no rendering will occur. Its default implementation is to be called, and no rendering will occur. Its default implementation is to
always return true. This is an optimization, similar to React's `shouldComponentUpdate`. Most of the time, this should not be used, but it always return true. This is an optimization, similar to React's `shouldComponentUpdate`. Most of the time, this should not be used, but it
@@ -239,7 +239,7 @@ perform some action before the initial rendering of a component.
It will be called exactly once before the initial rendering. It is useful It will be called exactly once before the initial rendering. It is useful
in some cases, for example, to load external assets (such as a JS library) in some cases, for example, to load external assets (such as a JS library)
before the widget is rendered. Another use case is to load data from a server. before the component is rendered. Another use case is to load data from a server.
```javascript ```javascript
async willStart() { async willStart() {
@@ -251,7 +251,7 @@ At this point, the component is not yet rendered. Note that a slow `willStart` m
interface. Therefore, some care should be made to make this method as interface. Therefore, some care should be made to make this method as
fast as possible. fast as possible.
The widget rendering will take place after `willStart` is completed. The component rendering will take place after `willStart` is completed.
#### `mounted()` #### `mounted()`
@@ -296,8 +296,8 @@ scrollbar.
Note that modifying the state object is not allowed here. This method is called just Note that modifying the state object is not allowed here. This method is called just
before an actual DOM patch, and is only intended to be used to save some local before an actual DOM patch, and is only intended to be used to save some local
DOM state. Also, it will not be called if the widget is not in the DOM (this can DOM state. Also, it will not be called if the component is not in the DOM (this can
happen with widgets with `t-keepalive`). happen with components with `t-keepalive`).
The return value of this method will be given as the first argument of the The return value of this method will be given as the first argument of the
corresponding `patched` call. corresponding `patched` call.
@@ -309,12 +309,12 @@ likely via a change in its state/props or environment).
This method is not called on the initial render. It is useful to interact This method is not called on the initial render. It is useful to interact
with the DOM (for example, through an external library) whenever the with the DOM (for example, through an external library) whenever the
component was patched. Note that this hook will not be called if the widget is component was patched. Note that this hook will not be called if the compoent is
not in the DOM (this can happen with widgets with `t-keepalive`). not in the DOM (this can happen with components with `t-keepalive`).
The `snapshot` parameter is the result of the previous `willPatch` call. The `snapshot` parameter is the result of the previous `willPatch` call.
Updating the widget state in this hook is possible, but not encouraged. Updating the compoent state in this hook is possible, but not encouraged.
One need to be careful, because updates here will cause rerender, which in One need to be careful, because updates here will cause rerender, which in
turn will cause other calls to patched. So, we need to be particularly turn will cause other calls to patched. So, we need to be particularly
careful at avoiding endless cycles. careful at avoiding endless cycles.
@@ -342,78 +342,78 @@ components are declared with a tagname corresponding to the class name. It has
to be capitalized. to be capitalized.
```xml ```xml
<div t-name="ParentWidget"> <div t-name="ParentComponent">
<span>some text</span> <span>some text</span>
<MyWidget info="13" /> <MyComponent info="13" />
</div> </div>
``` ```
```js ```js
class ParentWidget extends owl.Component { class ParentComponent extends owl.Component {
widgets = { MyWidget: MyWidget}; components = { MyComponent: MyComponent};
... ...
} }
``` ```
In this example, the `ParentWidget`'s template creates a widget `MyWidget` just In this example, the `ParentComponent`'s template creates a component `MyComponent` just
after the span. The `info` key will be added to the subwidget's `props`. Each after the span. The `info` key will be added to the subcomponent's `props`. Each
`props` is a string which represents a javascript (QWeb) expression, so it is `props` is a string which represents a javascript (QWeb) expression, so it is
dynamic. If it is necessary to give a string, this can be done by quoting it: dynamic. If it is necessary to give a string, this can be done by quoting it:
`someString="'somevalue'"`. `someString="'somevalue'"`.
Note that the rendering context for the template is the widget itself. This means Note that the rendering context for the template is the component itself. This means
that the template can access `state`, `props`, `env`, or any methods defined in the widget. that the template can access `state`, `props`, `env`, or any methods defined in the component.
```xml ```xml
<div t-name="ParentWidget"> <div t-name="ParentComponent">
<ChildWidget count="state.val" /> <ChildComponent count="state.val" />
</div> </div>
``` ```
```js ```js
class ParentWidget { class ParentComponent {
widgets = { ChildWidget }; components = { ChildComponent };
state = { val: 4 }; state = { val: 4 };
} }
``` ```
Whenever the template is rendered, it will automatically create the subwidget Whenever the template is rendered, it will automatically create the subcomponent
`ChildWidget` at the correct place. It needs to find the reference to the `ChildComponent` at the correct place. It needs to find the reference to the
actual component class in the special `widgets` key, or the class registered in actual component class in the special `components` key, or the class registered in
QWeb's global registry (see `register` function of QWeb). It first looks inside QWeb's global registry (see `register` function of QWeb). It first looks inside
the local `widgets` key, then fallbacks on the global registry. the local `components` key, then fallbacks on the global registry.
_Props_: In this example, the child widget will receive the object `{count: 4}` in its _Props_: In this example, the child component will receive the object `{count: 4}` in its
constructor. This will be assigned to the `props` variable, which can be accessed constructor. This will be assigned to the `props` variable, which can be accessed
on the widget (and also, in the template). Whenever the state is updated, then on the component (and also, in the template). Whenever the state is updated, then
the subwidget will also be updated automatically. the sub component will also be updated automatically.
Note that there are some restrictions on prop names: `class`, `style` and any Note that there are some restrictions on prop names: `class`, `style` and any
string which starts with `t-` are not allowed. string which starts with `t-` are not allowed.
The `t-widget` directive can also be used to accept dynamic values with string interpolation (like the [`t-attf-`](qweb.md#dynamic-attributes) directive): The `t-component` directive can also be used to accept dynamic values with string interpolation (like the [`t-attf-`](qweb.md#dynamic-attributes) directive):
```xml ```xml
<div t-name="ParentWidget"> <div t-name="ParentComponent">
<t t-widget="ChildWidget{{id}}" /> <t t-component="ChildComponent{{id}}" />
</div> </div>
``` ```
```js ```js
class ParentWidget { class ParentComponent {
widgets = { ChildWidget1, ChildWidget2 }; components = { ChildComponent1, ChildComponent2 };
state = { id: 1 }; state = { id: 1 };
} }
``` ```
**CSS and style:** there is some specific support to allow the parent to declare **CSS and style:** there is some specific support to allow the parent to declare
additional css classes or style for the sub widget: css declared in `class`, `style`, `t-att-class` or `t-att-style` will be added to the additional css classes or style for the sub component: css declared in `class`, `style`, `t-att-class` or `t-att-style` will be added to the
root widget element. root component element.
```xml ```xml
<div t-name="ParentWidget"> <div t-name="ParentComponent">
<MyWidget class="someClass" style="font-weight:bold;" info="13" /> <MyComponent class="someClass" style="font-weight:bold;" info="13" />
</div> </div>
``` ```
@@ -425,7 +425,7 @@ class that need to be removed. This is why we only support the explicit syntax
with a class object: with a class object:
```xml ```xml
<MyWidget t-att-class="{a: state.flagA, b: state.flagB}" /> <MyComponent t-att-class="{a: state.flagA, b: state.flagB}" />
``` ```
### Event Handling ### Event Handling
@@ -448,7 +448,7 @@ A _pure_ DOM event is directly triggered by a user interaction (e.g. a `click`).
This will be roughly translated in javascript like this: This will be roughly translated in javascript like this:
```js ```js
button.addEventListener("click", widget.someMethod.bind(widget)); button.addEventListener("click", component.someMethod.bind(component));
``` ```
The suffix (`click` in this example) is simply the name of the actual DOM The suffix (`click` in this example) is simply the name of the actual DOM
@@ -457,11 +457,11 @@ event.
A _business_ DOM event is triggered by a call to `trigger` on a component. A _business_ DOM event is triggered by a call to `trigger` on a component.
```xml ```xml
<MyWidget t-on-menu-loaded="someMethod" /> <MyComponent t-on-menu-loaded="someMethod" />
``` ```
```js ```js
class MyWidget { class MyComponent {
someWhere() { someWhere() {
const payload = ...; const payload = ...;
this.trigger('menu-loaded', payload); this.trigger('menu-loaded', payload);
@@ -471,12 +471,12 @@ A _business_ DOM event is triggered by a call to `trigger` on a component.
The call to `trigger` generates a [_CustomEvent_](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events) The call to `trigger` generates a [_CustomEvent_](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events)
of type `menu-loaded` and dispatches it on the component's DOM element of type `menu-loaded` and dispatches it on the component's DOM element
(`this.el`). The event bubbles and is cancelable. The parent widget listening (`this.el`). The event bubbles and is cancelable. The parent component listening
to event `menu-loaded` will receive the payload in its `someMethod` handler to event `menu-loaded` will receive the payload in its `someMethod` handler
(in the `detail` property of the event), whenever the event is triggered. (in the `detail` property of the event), whenever the event is triggered.
```js ```js
class ParentWidget { class ParentComponent {
someMethod(ev) { someMethod(ev) {
const payload = ev.detail; const payload = ev.detail;
... ...
@@ -640,7 +640,7 @@ is inserted into the DOM.
``` ```
```js ```js
class MyWidget extends owl.Component { class MyComponent extends owl.Component {
... ...
focusMe() { focusMe() {
this.refs.someInput.focus(); this.refs.someInput.focus();
@@ -671,27 +671,27 @@ component (with some code like `app.mount(document.body)`).
2. when it is done, template `A` is rendered. 2. when it is done, template `A` is rendered.
- widget `B` is created - component `B` is created
1. `willStart` is called on `B` 1. `willStart` is called on `B`
2. template `B` is rendered 2. template `B` is rendered
- widget `C` is created - component `C` is created
1. `willStart` is called on `C` 1. `willStart` is called on `C`
2. template `C` is rendered 2. template `C` is rendered
- widget `D` is created - component `D` is created
1. `willStart` is called on `D` 1. `willStart` is called on `D`
2. template `D` is rendered 2. template `D` is rendered
- widget `E` is created - component `E` is created
1. `willStart` is called on `E` 1. `willStart` is called on `E`
2. template `E` is rendered 2. template `E` is rendered
3. widget `A` is patched into a detached DOM element. This will create the actual 3. component `A` is patched into a detached DOM element. This will create the actual
widget `A` DOM structure. The patching process will cause recursively the component `A` DOM structure. The patching process will cause recursively the
patching of the `B`, `C`, `D` and `E` DOM trees. (so the actual full DOM tree is created patching of the `B`, `C`, `D` and `E` DOM trees. (so the actual full DOM tree is created
in one pass) in one pass)
4. the widget `A` root element is actually appended to `document.body` 4. the component `A` root element is actually appended to `document.body`
5. The method `mounted` is called recursively on all widgets in the following 5. The method `mounted` is called recursively on all components in the following
order: `B`, `D`, `E`, `C`, `A`. order: `B`, `D`, `E`, `C`, `A`.
**Scenario 2: rerendering a component**. Now, let's assume that the user clicked on some **Scenario 2: rerendering a component**. Now, let's assume that the user clicked on some
@@ -699,7 +699,7 @@ button in `C`, and this results in a state update, which is supposed to:
- update `D`, - update `D`,
- remove `E`, - remove `E`,
- add new widget `F`. - add new component `F`.
So, the component tree should look like this: So, the component tree should look like this:
@@ -716,17 +716,17 @@ Here is what Owl will do:
1. because of a state change, the method `render` is called on `C` 1. because of a state change, the method `render` is called on `C`
2. template `C` is rendered again 2. template `C` is rendered again
- widget `D` is updated: - component `D` is updated:
1. hook `willUpdateProps` is called on `D` (async) 1. hook `willUpdateProps` is called on `D` (async)
2. template `D` is rerendered 2. template `D` is rerendered
- widget `F` is created: - component `F` is created:
1. hook `willStart` is called on `E` (async) 1. hook `willStart` is called on `E` (async)
2. template `F` is rendered 2. template `F` is rendered
3. `willPatch` hooks are called recursively on widgets `C`, `D` (not on `F`, 3. `willPatch` hooks are called recursively on components `C`, `D` (not on `F`,
because it is not mounted yet) because it is not mounted yet)
4. widget `C` is patched, which will cause recursively: 4. component `C` is patched, which will cause recursively:
2. `willUnmount` hook on `E`, then destruction of `E`, 2. `willUnmount` hook on `E`, then destruction of `E`,
3. (initial) patching of `F`, then hook `mounted` is called on `F` 3. (initial) patching of `F`, then hook `mounted` is called on `F`
@@ -830,42 +830,42 @@ Like the `t-on` directive, it can work either on a DOM node, or on a component:
```xml ```xml
<div> <div>
<div t-ref="someDiv"/> <div t-ref="someDiv"/>
<SubWidget t-ref="someWidget"/> <SubComponent t-ref="someComponent"/>
</div> </div>
``` ```
In this example, the widget will be able to access the `div` and the component In this example, the component will be able to access the `div` and the component
inside the special `refs` variable: inside the special `refs` variable:
```js ```js
this.refs.someDiv; this.refs.someDiv;
this.refs.someWidget; this.refs.someComponent;
``` ```
This is useful for various usecases: for example, integrating with an external This is useful for various usecases: for example, integrating with an external
library that needs to render itself inside an actual DOM node. Or for calling library that needs to render itself inside an actual DOM node. Or for calling
some method on a sub widget. some method on a sub component.
Note: if used on a component, the reference will be set in the `refs` Note: if used on a component, the reference will be set in the `refs`
variable between `willPatch` and `patched`. variable between `willPatch` and `patched`.
The `t-ref` directive also accepts dynamic values with string interpolation The `t-ref` directive also accepts dynamic values with string interpolation
(like the [`t-attf-`](qweb.md#dynamic-attributes) and (like the [`t-attf-`](qweb.md#dynamic-attributes) and
`t-widget` directives). For example, if we have `t-component` directives). For example, if we have
`id` set to 44 in the rendering context, `id` set to 44 in the rendering context,
```xml ```xml
<div t-ref="widget_{{id}}"/> <div t-ref="component_{{id}}"/>
``` ```
```js ```js
this.refs.widget_44; this.refs.component_44;
``` ```
### Slots ### Slots
To make generic components, it is useful to be able for a parent widget to _inject_ To make generic components, it is useful to be able for a parent component to _inject_
some sub template, but still be the owner. For example, a generic dialog widget some sub template, but still be the owner. For example, a generic dialog component
will need to render some content, some footer, but with the parent as the will need to render some content, some footer, but with the parent as the
rendering context. rendering context.
@@ -886,8 +886,8 @@ This is what _slots_ are for.
Slots are defined by the caller, with the `t-set` directive: Slots are defined by the caller, with the `t-set` directive:
```xml ```xml
<div t-name="SomeWidget"> <div t-name="SomeComponent">
<div>some widget</div> <div>some component</div>
<Dialog title="Some Dialog"> <Dialog title="Some Dialog">
<t t-set="content"> <t t-set="content">
<div>hey</div> <div>hey</div>
@@ -899,7 +899,7 @@ Slots are defined by the caller, with the `t-set` directive:
</div> </div>
``` ```
In this example, the widget `Dialog` will render the slots `content` and `footer` In this example, the component `Dialog` will render the slots `content` and `footer`
with its parent as rendering context. This means that clicking on the button with its parent as rendering context. This means that clicking on the button
will execute the `doSomething` method on the parent, not on the dialog. will execute the `doSomething` method on the parent, not on the dialog.
@@ -922,7 +922,7 @@ is not allowed. A workaround could be to wrap the content in a div:
</div> </div>
``` ```
Default slot: the first element inside the widget which is not a named slot will Default slot: the first element inside the component which is not a named slot will
be considered the `default` slot. For example: be considered the `default` slot. For example:
```xml ```xml
@@ -946,23 +946,23 @@ components.
There are two different common problems with Owl asynchronous rendering model: There are two different common problems with Owl asynchronous rendering model:
- any widget can delay the rendering (initial and subsequent) of the whole - any component can delay the rendering (initial and subsequent) of the whole
application application
- for a given widget, there are two independant situations that will trigger an - for a given component, there are two independant situations that will trigger an
asynchronous rerendering: a change in the state, or a change in the props. asynchronous rerendering: a change in the state, or a change in the props.
These changes may be done at different times, and Owl has no way of knowing These changes may be done at different times, and Owl has no way of knowing
how to reconcile the resulting renderings. how to reconcile the resulting renderings.
Here are a few tips on how to work with asynchronous widgets: Here are a few tips on how to work with asynchronous components:
1. Minimize the use of asynchronous widgets! 1. Minimize the use of asynchronous components!
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-asyncroot` directive (to use alongside 4. For all the other cases, the `t-asyncroot` directive (to use alongside
`t-widget`) is there to help you. When this directive is met, a new rendering `t-component`) 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 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 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 be used on an asynchronous component, to prevent it from delaying the
@@ -972,7 +972,7 @@ Here are a few tips on how to work with asynchronous widgets:
(triggered by state or props changes). (triggered by state or props changes).
```xml ```xml
<div t-name="ParentWidget"> <div t-name="ParentComponent">
<SyncChild /> <SyncChild />
<AsyncChild t-asyncroot="1"/> <AsyncChild t-asyncroot="1"/>
</div> </div>
+4 -4
View File
@@ -58,16 +58,16 @@ To build an application (or a sub-part of an application), we need two things:
need. In practice, it could context some user session information, some need. In practice, it could context some user session information, some
configuration keys (for example, isMobile = true/false if we are in mobile mode). configuration keys (for example, isMobile = true/false if we are in mobile mode).
- a description of the user interface: there should be a root widget, which can - a description of the user interface: there should be a root component, which can
have sub widgets have sub components
Here are a few steps that we may take to get started: Here are a few steps that we may take to get started:
- get the templates - get the templates
- create a qweb engine, with the templates - create a qweb engine, with the templates
- create an environment - create an environment
- create an instance of the root widget - create an instance of the root component
- mount the root widget to a DOM element - mount the root component to a DOM element
Let us now add the javascript to make it work, in `app.js`: Let us now add the javascript to make it work, in `app.js`:
+8 -8
View File
@@ -44,7 +44,7 @@ with a few interesting points:
- it compiles templates into functions that output a virtual DOM instead of a - it compiles templates into functions that output a virtual DOM instead of a
string. This is necessary for the component system. string. This is necessary for the component system.
- it has a few extra directives: `t-widget`, `t-on`, ... - it has a few extra directives: `t-component`, `t-on`, ...
## Directives ## Directives
@@ -67,7 +67,7 @@ needs. Here is a list of all Owl specific directives:
| Name | Description | | Name | Description |
| -------------------------------------------- | ----------------------------------------------------------------------------------- | | -------------------------------------------- | ----------------------------------------------------------------------------------- |
| `t-widget`, `t-keepalive`, `t-asyncroot` | [Defining a sub component](component.md#composition) | | `t-component`, `t-keepalive`, `t-asyncroot` | [Defining a sub component](component.md#composition) |
| `t-ref` | [Setting a reference to a dom node or a sub component](component.md#references) | | `t-ref` | [Setting a reference to a dom node or a sub component](component.md#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) |
@@ -108,7 +108,7 @@ It's API is quite simple:
const TEMPLATES = ` const TEMPLATES = `
<templates> <templates>
<div t-name="App" class="main">main</div> <div t-name="App" class="main">main</div>
<div t-name="OtherWidget">other widget</div> <div t-name="OtherComponent">other component</div>
</templates>`; </templates>`;
qweb.addTemplates(TEMPLATES); qweb.addTemplates(TEMPLATES);
``` ```
@@ -117,12 +117,12 @@ It's API is quite simple:
which is a virtual representation of the DOM (see [vdom doc](vdom.md)). which is a virtual representation of the DOM (see [vdom doc](vdom.md)).
```js ```js
const vnode = qweb.render("App", widget); const vnode = qweb.render("App", component);
``` ```
- **`register(name, Component)`**: static function to register an OWL Component - **`register(name, Component)`**: static function to register an OWL Component
to QWeb's global registry. Globally registered Components can be used in to QWeb's global registry. Globally registered Components can be used in
templates (see the `t-widget` directive). This is useful for commonly used templates (see the `t-component` directive). This is useful for commonly used
components accross the application. components accross the application.
```js ```js
@@ -131,8 +131,8 @@ It's API is quite simple:
... ...
class ParentWidget extends owl.Component { ... } class ParentComponent extends owl.Component { ... }
qweb.addTemplate("ParentWidget", "<div><Dialog/></div>"); qweb.addTemplate("ParentComponent", "<div><Dialog/></div>");
``` ```
## Reference ## Reference
@@ -179,7 +179,7 @@ root nodes.
QWeb expressions are strings that will be processed at compile time. Each variable in QWeb expressions are strings that will be processed at compile time. Each variable in
the javascript expression will be replaced by a lookup in the context (so, the the javascript expression will be replaced by a lookup in the context (so, the
widget). For example, `a + b.c(d)` will be converted into: component). For example, `a + b.c(d)` will be converted into:
```js ```js
context["a"] + context["b"].c(context["d"]); context["a"] + context["b"].c(context["d"]);
+27 -27
View File
@@ -42,8 +42,8 @@ export interface Meta<T extends Env, Props> {
isDestroyed: boolean; isDestroyed: boolean;
parent: Component<T, any, any> | null; parent: Component<T, any, any> | null;
children: { [key: number]: Component<T, any, any> }; children: { [key: number]: Component<T, any, any> };
// children mapping: from templateID to widgetID // children mapping: from templateID to componentID
// should it be a map number => Widget? // should it be a map number => Component?
cmap: { [key: number]: number }; cmap: { [key: number]: number };
renderId: number; renderId: number;
@@ -62,7 +62,7 @@ export interface Meta<T extends Env, Props> {
const TEMPLATE_MAP: { [key: number]: { [name: string]: string } } = {}; const TEMPLATE_MAP: { [key: number]: { [name: string]: string } } = {};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Widget // Component
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let nextId = 1; let nextId = 1;
@@ -71,8 +71,8 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
template?: string; template?: string;
/** /**
* The `el` is the root element of the widget. Note that it could be null: * The `el` is the root element of the component. Note that it could be null:
* this is the case if the widget is not mounted yet, or is destroyed. * this is the case if the component is not mounted yet, or is destroyed.
*/ */
get el(): HTMLElement | null { get el(): HTMLElement | null {
return this.__owl__.vnode ? (<any>this).__owl__.vnode.elm : null; return this.__owl__.vnode ? (<any>this).__owl__.vnode.elm : null;
@@ -97,21 +97,21 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
/** /**
* Creates an instance of Component. * Creates an instance of Component.
* *
* The root widget of a component tree needs an environment: * The root component of a component tree needs an environment:
* *
* ```javascript * ```javascript
* const root = new RootWidget(env, props); * const root = new RootComponent(env, props);
* ``` * ```
* *
* Every other widget simply needs a reference to its parent: * Every other component simply needs a reference to its parent:
* *
* ```javascript * ```javascript
* const child = new SomeWidget(parent, props); * const child = new SomeComponent(parent, props);
* ``` * ```
* *
* Note that most of the time, only the root widget needs to be created by * Note that most of the time, only the root component needs to be created by
* hand. Other widgets should be created automatically by the framework (with * hand. Other components should be created automatically by the framework (with
* the t-widget directive in a template) * the t-component directive in a template)
*/ */
constructor(parent: Component<T, any, any> | T, props?: Props) { constructor(parent: Component<T, any, any> | T, props?: Props) {
const defaultProps = (<any>this.constructor).defaultProps; const defaultProps = (<any>this.constructor).defaultProps;
@@ -122,9 +122,9 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
this._validateProps(props || {}); this._validateProps(props || {});
} }
// is this a good idea? // is this a good idea?
// Pro: if props is empty, we can create easily a widget // Pro: if props is empty, we can create easily a component
// Con: this is not really safe // Con: this is not really safe
// Pro: but creating widget (by a template) is always unsafe anyway // Pro: but creating component (by a template) is always unsafe anyway
this.props = <Props>props || <Props>{}; this.props = <Props>props || <Props>{};
let id: number = nextId++; let id: number = nextId++;
let p: Component<T, any, any> | null = null; let p: Component<T, any, any> | null = null;
@@ -157,7 +157,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
* *
* It will be called exactly once before the initial rendering. It is useful * It will be called exactly once before the initial rendering. It is useful
* in some cases, for example, to load external assets (such as a JS library) * in some cases, for example, to load external assets (such as a JS library)
* before the widget is rendered. * before the component is rendered.
* *
* Note that a slow willStart method will slow down the rendering of the user * Note that a slow willStart method will slow down the rendering of the user
* interface. Therefore, some effort should be made to make this method as * interface. Therefore, some effort should be made to make this method as
@@ -207,7 +207,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
* with the DOM (for example, through an external library) whenever the * with the DOM (for example, through an external library) whenever the
* component was updated. * component was updated.
* *
* Updating the widget state in this hook is possible, but not encouraged. * Updating the component state in this hook is possible, but not encouraged.
* One need to be careful, because updates here will cause rerender, which in * One need to be careful, because updates here will cause rerender, which in
* turn will cause other calls to updated. So, we need to be particularly * turn will cause other calls to updated. So, we need to be particularly
* careful at avoiding endless cycles. * careful at avoiding endless cycles.
@@ -284,8 +284,8 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
* - call the willUnmount hooks if necessary * - call the willUnmount hooks if necessary
* - remove the dom node from the dom * - remove the dom node from the dom
* *
* This should only be called manually if you created the widget. Most widgets * This should only be called manually if you created the component. Most
* will be automatically destroyed. * components will be automatically destroyed.
*/ */
destroy() { destroy() {
const __owl__ = this.__owl__; const __owl__ = this.__owl__;
@@ -308,8 +308,8 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
} }
/** /**
* This method is the correct way to update the environment of a widget. Doing * This method is the correct way to update the environment of a component. Doing
* this will cause a full rerender of the widget and its children, so this is * this will cause a full rerender of the component and its children, so this is
* an operation that should not be done frequently. * an operation that should not be done frequently.
* *
* A good usecase for updating the environment would be to update some mostly * A good usecase for updating the environment would be to update some mostly
@@ -499,9 +499,9 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
} }
// this part is critical for the patching process to be done correctly. The // this part is critical for the patching process to be done correctly. The
// tricky part is that a child widget can be rerendered on its own, which // tricky part is that a child component can be rerendered on its own, which
// will update its own vnode representation without the knowledge of the // will update its own vnode representation without the knowledge of the
// parent widget. With this, we make sure that the parent widget will be // parent component. With this, we make sure that the parent component will be
// able to patch itself properly after // able to patch itself properly after
vnode.key = __owl__.id; vnode.key = __owl__.id;
__owl__.renderProps = this.props; __owl__.renderProps = this.props;
@@ -510,7 +510,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
} }
/** /**
* Only called by qweb t-widget directive * Only called by qweb t-component directive
*/ */
_mount(vnode: VNode, elm: HTMLElement): VNode { _mount(vnode: VNode, elm: HTMLElement): VNode {
const __owl__ = this.__owl__; const __owl__ = this.__owl__;
@@ -522,7 +522,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
} }
/** /**
* Only called by qweb t-widget directive (when t-keepalive is set) * Only called by qweb t-component directive (when t-keepalive is set)
*/ */
_remount() { _remount() {
const __owl__ = this.__owl__; const __owl__ = this.__owl__;
@@ -593,7 +593,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
for (let i = 0, l = propsDef.length; i < l; i++) { for (let i = 0, l = propsDef.length; i < l; i++) {
if (!(propsDef[i] in props)) { if (!(propsDef[i] in props)) {
throw new Error( throw new Error(
`Missing props '${propsDef[i]}' (widget '${this.constructor.name}')` `Missing props '${propsDef[i]}' (component '${this.constructor.name}')`
); );
} }
} }
@@ -603,7 +603,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
if (!(propName in props)) { if (!(propName in props)) {
if (propsDef[propName] && !propsDef[propName].optional) { if (propsDef[propName] && !propsDef[propName].optional) {
throw new Error( throw new Error(
`Missing props '${propName}' (widget '${this.constructor.name}')` `Missing props '${propName}' (component '${this.constructor.name}')`
); );
} else { } else {
break; break;
@@ -612,7 +612,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
let isValid = isValidProp(props[propName], propsDef[propName]); let isValid = isValidProp(props[propName], propsDef[propName]);
if (!isValid) { if (!isValid) {
throw new Error( throw new Error(
`Props '${propName}' of invalid type in widget '${ `Props '${propName}' of invalid type in component '${
this.constructor.name this.constructor.name
}'` }'`
); );
+1 -1
View File
@@ -29,7 +29,7 @@ export class EventBus {
* Add a listener for the 'eventType' events. * Add a listener for the 'eventType' events.
* *
* Note that the 'owner' of this event can be anything, but will more likely * Note that the 'owner' of this event can be anything, but will more likely
* be a widget or a class. The idea is that the callback will be called with * be a component or a class. The idea is that the callback will be called with
* the proper owner bound. * the proper owner bound.
* *
* Also, the owner should be kind of unique. This will be used to remove the * Also, the owner should be kind of unique. This will be used to remove the
+6 -6
View File
@@ -130,7 +130,7 @@ let nextID = 1;
export class QWeb { export class QWeb {
templates: { [name: string]: Template } = {}; templates: { [name: string]: Template } = {};
utils = UTILS; utils = UTILS;
static widgets = Object.create(null); static components = Object.create(null);
// dev mode enables better error messages or more costly validations // dev mode enables better error messages or more costly validations
static dev: boolean = false; static dev: boolean = false;
@@ -140,7 +140,7 @@ export class QWeb {
// able to map a qweb instance to a template name. // able to map a qweb instance to a template name.
id = nextID++; id = nextID++;
// slots contains sub templates defined with t-set inside t-widget nodes, and // slots contains sub templates defined with t-set inside t-component nodes, and
// are meant to be used by the t-slot directive. // are meant to be used by the t-slot directive.
slots = {}; slots = {};
nextSlotId = 1; nextSlotId = 1;
@@ -161,10 +161,10 @@ export class QWeb {
} }
static register(name: string, Component: any) { static register(name: string, Component: any) {
if (QWeb.widgets[name]) { if (QWeb.components[name]) {
throw new Error(`Component '${name}' has already been registered`); throw new Error(`Component '${name}' has already been registered`);
} }
QWeb.widgets[name] = Component; QWeb.components[name] = Component;
} }
/** /**
@@ -349,8 +349,8 @@ export class QWeb {
const firstLetter = node.tagName[0]; const firstLetter = node.tagName[0];
if (firstLetter === firstLetter.toUpperCase()) { if (firstLetter === firstLetter.toUpperCase()) {
// this is a component, we modify in place the xml document to change // this is a component, we modify in place the xml document to change
// <SomeComponent ... /> to <t t-widget="SomeComponent" ... /> // <SomeComponent ... /> to <t t-component="SomeComponent" ... />
node.setAttribute('t-widget', node.tagName); node.setAttribute('t-component', node.tagName);
node.nodeValue = 't'; node.nodeValue = 't';
} }
const attributes = (<Element>node).attributes; const attributes = (<Element>node).attributes;
+1 -1
View File
@@ -272,7 +272,7 @@ QWeb.addDirective({
let shouldWarn = let shouldWarn =
nodeCopy.tagName !== "t" && !nodeCopy.hasAttribute("t-key"); nodeCopy.tagName !== "t" && !nodeCopy.hasAttribute("t-key");
if (!shouldWarn && node.tagName === "t") { if (!shouldWarn && node.tagName === "t") {
if (node.hasAttribute("t-widget") && !node.hasAttribute("t-key")) { if (node.hasAttribute("t-component") && !node.hasAttribute("t-key")) {
shouldWarn = true; shouldWarn = true;
} }
if ( if (
+71 -71
View File
@@ -10,7 +10,7 @@ import { VNode } from "./vdom";
* - t-on * - t-on
* - t-ref * - t-ref
* - t-transition * - t-transition
* - t-widget/t-keepalive * - t-component/t-keepalive
* - t-mounted * - t-mounted
* - t-slot * - t-slot
* - t-model * - t-model
@@ -191,21 +191,21 @@ QWeb.addDirective({
}); });
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// t-widget // t-component
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, { const T_COMPONENT_MODS_CODE = Object.assign({}, MODS_CODE, {
self: "if (e.target !== vn.elm) {return}" self: "if (e.target !== vn.elm) {return}"
}); });
/** /**
* The t-widget directive is certainly a complicated and hard to maintain piece * The t-component directive is certainly a complicated and hard to maintain piece
* of code. To help you, fellow developer, if you have to maintain it, I offer * of code. To help you, fellow developer, if you have to maintain it, I offer
* you this advice: Good luck... * you this advice: Good luck...
* *
* Since it is not 'direct' code, but rather code that generates other code, it * Since it is not 'direct' code, but rather code that generates other code, it
* is not easy to understand. To help you, here is a detailed and commented * is not easy to understand. To help you, here is a detailed and commented
* explanation of the code generated by the t-widget directive for the following * explanation of the code generated by the t-component directive for the following
* situation: * situation:
* ```xml * ```xml
* <Child * <Child
@@ -216,23 +216,23 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* *
* ```js * ```js
* // we assign utils on top of the function because it will be useful for * // we assign utils on top of the function because it will be useful for
* // each widgets * // each components
* let utils = this.utils; * let utils = this.utils;
* *
* // this is the virtual node representing the parent div * // this is the virtual node representing the parent div
* let c1 = [], p1 = { key: 1 }; * let c1 = [], p1 = { key: 1 };
* var vn1 = h("div", p1, c1); * var vn1 = h("div", p1, c1);
* *
* // t-widget directive: we start by evaluating the expression given by t-key: * // t-component directive: we start by evaluating the expression given by t-key:
* let key5 = "somestring"; * let key5 = "somestring";
* *
* // def3 is the promise that will contain later either the new widget * // def3 is the promise that will contain later either the new component
* // creation, or the props update... * // creation, or the props update...
* let def3; * let def3;
* *
* // this is kind of tricky: we need here to find if the widget was already * // this is kind of tricky: we need here to find if the component was already
* // created by a previous rendering. This is done by checking the internal * // created by a previous rendering. This is done by checking the internal
* // `cmap` (children map) of the parent widget: it maps keys to widget ids, * // `cmap` (children map) of the parent component: it maps keys to component ids,
* // and, then, if there is an id, we look into the children list to get the * // and, then, if there is an id, we look into the children list to get the
* // instance * // instance
* let w4 = * let w4 =
@@ -240,9 +240,9 @@ 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 * // We keep the index of the position of the component in the closure. We push
* // null to reserve the slot, and will replace it later by the widget vnode, * // null to reserve the slot, and will replace it later by the component vnode,
* // when it will be ready (do not forget that preparing/rendering a widget is * // when it will be ready (do not forget that preparing/rendering a component is
* // asynchronous) * // asynchronous)
* let _2_index = c1.length; * let _2_index = c1.length;
* c1.push(null); * c1.push(null);
@@ -252,7 +252,7 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* // computation, so it is certainly better to do it only once * // computation, so it is certainly better to do it only once
* let props4 = { flag: context["state"].flag }; * let props4 = { flag: context["state"].flag };
* *
* // If we have a widget, currently rendering, but not ready yet, we do not want * // If we have a component, currently rendering, but not ready yet, we do not want
* // to wait for it to be ready if we can avoid it * // to wait for it to be ready if we can avoid it
* if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) { * if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode) {
* // we check if the props are the same. In that case, we can simply reuse * // we check if the props are the same. In that case, we can simply reuse
@@ -260,7 +260,7 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* if (utils.shallowEqual(props4, w4.__owl__.renderProps)) { * if (utils.shallowEqual(props4, w4.__owl__.renderProps)) {
* def3 = w4.__owl__.renderPromise; * def3 = w4.__owl__.renderPromise;
* } else { * } else {
* // if the props are not the same, we destroy the widget and starts anew. * // if the props are not the same, we destroy the component and starts anew.
* // this will be faster than waiting for its rendering, then updating it * // this will be faster than waiting for its rendering, then updating it
* w4.destroy(); * w4.destroy();
* w4 = false; * w4 = false;
@@ -268,29 +268,29 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* } * }
* *
* if (!w4) { * if (!w4) {
* // in this situation, we need to create a new widget. First step is * // in this situation, we need to create a new component. First step is
* // to get a reference to the class, then create an instance with * // to get a reference to the class, then create an instance with
* // current context as parent, and the props. * // current context as parent, and the props.
* let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; * let W4 = context.component && context.components[componentKey4] || QWeb.component[componentKey4];
* if (!W4) { * if (!W4) {
* throw new Error("Cannot find the definition of widget 'child'"); * throw new Error("Cannot find the definition of component 'child'");
* } * }
* w4 = new W4(owner, props4); * w4 = new W4(owner, props4);
* *
* // Whenever we rerender the parent widget, we need to be sure that we * // Whenever we rerender the parent component, we need to be sure that we
* // are able to find the widget instance. To do that, we register it to * // are able to find the component instance. To do that, we register it to
* // the parent cmap (children map). Note that the 'template' key is * // the parent cmap (children map). Note that the 'template' key is
* // used here, since this is what identify the widget from the template * // used here, since this is what identify the component from the template
* // perspective. * // perspective.
* context.__owl__.cmap[key5] = w4.__owl__.id; * context.__owl__.cmap[key5] = w4.__owl__.id;
* *
* // _prepare is called, to basically call willStart, then render the * // _prepare is called, to basically call willStart, then render the
* // widget * // component
* def3 = w4._prepare(); * def3 = w4._prepare();
* *
* def3 = def3.then(vnode => { * def3 = def3.then(vnode => {
* // we create here a virtual node for the parent (NOT the widget). This * // we create here a virtual node for the parent (NOT the component). This
* // means that the vdom of the parent will be stopped here, and from * // means that the vdom of the parent will be stopped here, and from
* // the parent's perspective, it simply is a vnode with no children. * // the parent's perspective, it simply is a vnode with no children.
* // However, it shares the same dom element with the component root * // However, it shares the same dom element with the component root
@@ -298,16 +298,16 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* let pvnode = h(vnode.sel, { key: key5 }); * let pvnode = h(vnode.sel, { key: key5 });
* *
* // we add hooks to the parent vnode so we can interact with the new * // we add hooks to the parent vnode so we can interact with the new
* // widget at the proper time * // component at the proper time
* pvnode.data.hook = { * pvnode.data.hook = {
* insert(vn) { * insert(vn) {
* // the _mount method will patch the widget vdom into the elm vn.elm, * // the _mount method will patch the component vdom into the elm vn.elm,
* // then call the mounted hooks. However, suprisingly, the snabbdom * // then call the mounted hooks. However, suprisingly, the snabbdom
* // patch method actually replace the elm by a new elm, so we need * // patch method actually replace the elm by a new elm, so we need
* // to synchronise the pvnode elm with the resulting elm * // to synchronise the pvnode elm with the resulting elm
* let nvn = w4._mount(vnode, vn.elm); * let nvn = w4._mount(vnode, vn.elm);
* pvnode.elm = nvn.elm; * pvnode.elm = nvn.elm;
* // what follows is only present if there are animations on the widget * // what follows is only present if there are animations on the component
* utils.transitionInsert(vn, "fade"); * utils.transitionInsert(vn, "fade");
* }, * },
* remove() { * remove() {
@@ -317,7 +317,7 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* }, * },
* destroy() { * destroy() {
* // if there are animations, we delay the call to destroy on the * // if there are animations, we delay the call to destroy on the
* // widget, if not, we call it directly. * // component, if not, we call it directly.
* let finalize = () => { * let finalize = () => {
* w4.destroy(); * w4.destroy();
* }; * };
@@ -328,19 +328,19 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
* c1[_2_index] = pvnode; * c1[_2_index] = pvnode;
* *
* // we keep here a reference to the parent vnode (representing the * // we keep here a reference to the parent vnode (representing the
* // widget, so we can reuse it later whenever we update the widget * // component, so we can reuse it later whenever we update the component
* w4.__owl__.pvnode = pvnode; * w4.__owl__.pvnode = pvnode;
* }); * });
* } else { * } else {
* // this is the 'update' path of the directive. * // this is the 'update' path of the directive.
* // the call to _updateProps is the actual widget update * // the call to _updateProps is the actual component update
* // Note that we only update the props if we cannot reuse the previous * // Note that we only update the props if we cannot reuse the previous
* // rendering work (in the case it was rendered with the same props) * // rendering work (in the case it was rendered with the same props)
* def3 = def3 || w4._updateProps(props4, extra.forceUpdate, extra.patchQueue); * def3 = def3 || w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
* def3 = def3.then(() => { * def3 = def3.then(() => {
* // if widget was destroyed in the meantime, we do nothing (so, this * // if component was destroyed in the meantime, we do nothing (so, this
* // means that the parent's element children list will have a null in * // means that the parent's element children list will have a null in
* // the widget's position, which will cause the pvnode to be removed * // the component's position, which will cause the pvnode to be removed
* // when it is patched. * // when it is patched.
* if (w4.__owl__.isDestroyed) { * if (w4.__owl__.isDestroyed) {
* return; * return;
@@ -360,11 +360,11 @@ const T_WIDGET_MODS_CODE = Object.assign({}, MODS_CODE, {
*/ */
QWeb.addDirective({ QWeb.addDirective({
name: "widget", name: "component",
extraNames: ["props", "keepalive", "asyncroot"], extraNames: ["props", "keepalive", "asyncroot"],
priority: 100, priority: 100,
atNodeEncounter({ ctx, value, node, qweb }): boolean { atNodeEncounter({ ctx, value, node, qweb }): boolean {
ctx.addLine("//WIDGET"); ctx.addLine("//COMPONENT");
ctx.rootContext.shouldDefineOwner = true; ctx.rootContext.shouldDefineOwner = true;
ctx.rootContext.shouldDefineQWeb = true; ctx.rootContext.shouldDefineQWeb = true;
ctx.rootContext.shouldDefineUtils = true; ctx.rootContext.shouldDefineUtils = true;
@@ -408,7 +408,7 @@ QWeb.addDirective({
.join(","); .join(",");
let dummyID = ctx.generateID(); let dummyID = ctx.generateID();
let defID = ctx.generateID(); let defID = ctx.generateID();
let widgetID = ctx.generateID(); let componentID = ctx.generateID();
let keyID = key && ctx.generateID(); let keyID = key && ctx.generateID();
if (key) { if (key) {
// we bind a variable to the key (could be a complex expression, so we // we bind a variable to the key (could be a complex expression, so we
@@ -419,8 +419,8 @@ QWeb.addDirective({
let templateID = key let templateID = key
? `key${keyID}` ? `key${keyID}`
: ctx.inLoop : ctx.inLoop
? `String(-${widgetID} - i)` ? `String(-${componentID} - i)`
: String(widgetID); : String(componentID);
let ref = node.getAttribute("t-ref"); let ref = node.getAttribute("t-ref");
let refExpr = ""; let refExpr = "";
@@ -428,21 +428,21 @@ QWeb.addDirective({
if (ref) { if (ref) {
refKey = `ref${ctx.generateID()}`; refKey = `ref${ctx.generateID()}`;
ctx.addLine(`const ${refKey} = ${ctx.interpolate(ref)};`); ctx.addLine(`const ${refKey} = ${ctx.interpolate(ref)};`);
refExpr = `context.refs[${refKey}] = w${widgetID};`; refExpr = `context.refs[${refKey}] = w${componentID};`;
} }
let transitionsInsertCode = ""; let transitionsInsertCode = "";
if (transition) { if (transition) {
transitionsInsertCode = `utils.transitionInsert(vn, '${transition}');`; transitionsInsertCode = `utils.transitionInsert(vn, '${transition}');`;
} }
let finalizeWidgetCode = `w${widgetID}.${ let finalizeComponentCode = `w${componentID}.${
keepAlive ? "unmount" : "destroy" keepAlive ? "unmount" : "destroy"
}();`; }();`;
if (ref && !keepAlive) { if (ref && !keepAlive) {
finalizeWidgetCode += `delete context.refs[${refKey}];`; finalizeComponentCode += `delete context.refs[${refKey}];`;
} }
if (transition) { if (transition) {
finalizeWidgetCode = `let finalize = () => { finalizeComponentCode = `let finalize = () => {
${finalizeWidgetCode} ${finalizeComponentCode}
}; };
utils.transitionRemove(vn, '${transition}', finalize);`; utils.transitionRemove(vn, '${transition}', finalize);`;
} }
@@ -475,7 +475,7 @@ QWeb.addDirective({
vn.elm.classList.add(k); vn.elm.classList.add(k);
} }
}`; }`;
updateClassCode = `let cl=w${widgetID}.el.classList;for (let k in ${attVar}) {if (${attVar}[k]) {cl.add(k)} else {cl.remove(k)}}`; updateClassCode = `let cl=w${componentID}.el.classList;for (let k in ${attVar}) {if (${attVar}[k]) {cl.add(k)} else {cl.remove(k)}}`;
} }
let eventsCode = events let eventsCode = events
.map(function([eventName, mods, handlerName, extraArgs]) { .map(function([eventName, mods, handlerName, extraArgs]) {
@@ -487,7 +487,7 @@ QWeb.addDirective({
handler = `function (e) {`; handler = `function (e) {`;
handler += mods handler += mods
.map(function(mod) { .map(function(mod) {
return T_WIDGET_MODS_CODE[mod]; return T_COMPONENT_MODS_CODE[mod];
}) })
.join(""); .join("");
handler += `owner['${handlerName}'].call(${params}, e);}`; handler += `owner['${handlerName}'].call(${params}, e);}`;
@@ -503,47 +503,47 @@ QWeb.addDirective({
} }
ctx.addLine( ctx.addLine(
`let w${widgetID} = ${templateID} in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[${templateID}]] : false;` `let w${componentID} = ${templateID} in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[${templateID}]] : false;`
); );
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`); ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
if (async) { if (async) {
ctx.addLine(`const patchQueue${widgetID} = [];`); ctx.addLine(`const patchQueue${componentID} = [];`);
ctx.addLine( ctx.addLine(
`c${ `c${
ctx.parentNode ctx.parentNode
}.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);` }.push(w${componentID} && w${componentID}.__owl__.pvnode || null);`
); );
} else { } else {
ctx.addLine(`c${ctx.parentNode}.push(null);`); ctx.addLine(`c${ctx.parentNode}.push(null);`);
} }
ctx.addLine(`let props${widgetID} = {${propStr}};`); ctx.addLine(`let props${componentID} = {${propStr}};`);
ctx.addIf( ctx.addIf(
`w${widgetID} && w${widgetID}.__owl__.renderPromise && !w${widgetID}.__owl__.vnode` `w${componentID} && w${componentID}.__owl__.renderPromise && !w${componentID}.__owl__.vnode`
); );
ctx.addIf( ctx.addIf(
`utils.shallowEqual(props${widgetID}, w${widgetID}.__owl__.renderProps)` `utils.shallowEqual(props${componentID}, w${componentID}.__owl__.renderProps)`
); );
ctx.addLine(`def${defID} = w${widgetID}.__owl__.renderPromise;`); ctx.addLine(`def${defID} = w${componentID}.__owl__.renderPromise;`);
ctx.addElse(); ctx.addElse();
ctx.addLine(`w${widgetID}.destroy();`); ctx.addLine(`w${componentID}.destroy();`);
ctx.addLine(`w${widgetID} = false;`); ctx.addLine(`w${componentID} = false;`);
ctx.closeIf(); ctx.closeIf();
ctx.closeIf(); ctx.closeIf();
ctx.addIf(`!w${widgetID}`); ctx.addIf(`!w${componentID}`);
// new widget // new component
ctx.addLine(`let widgetKey${widgetID} = ${ctx.interpolate(value)};`); ctx.addLine(`let componentKey${componentID} = ${ctx.interpolate(value)};`);
ctx.addLine( ctx.addLine(
`let W${widgetID} = context.widgets && context.widgets[widgetKey${widgetID}] || QWeb.widgets[widgetKey${widgetID}];` `let W${componentID} = context.components && context.components[componentKey${componentID}] || QWeb.components[componentKey${componentID}];`
); );
// maybe only do this in dev mode... // maybe only do this in dev mode...
ctx.addLine( ctx.addLine(
`if (!W${widgetID}) {throw new Error('Cannot find the definition of widget "' + widgetKey${widgetID} + '"')}` `if (!W${componentID}) {throw new Error('Cannot find the definition of component "' + componentKey${componentID} + '"')}`
); );
ctx.addLine(`w${widgetID} = new W${widgetID}(owner, props${widgetID});`); ctx.addLine(`w${componentID} = new W${componentID}(owner, props${componentID});`);
ctx.addLine( ctx.addLine(
`context.__owl__.cmap[${templateID}] = w${widgetID}.__owl__.id;` `context.__owl__.cmap[${templateID}] = w${componentID}.__owl__.id;`
); );
// SLOTS // SLOTS
@@ -551,7 +551,7 @@ QWeb.addDirective({
const clone = <Element>node.cloneNode(true); const clone = <Element>node.cloneNode(true);
const slotNodes = clone.querySelectorAll("[t-set]"); const slotNodes = clone.querySelectorAll("[t-set]");
const slotId = qweb.nextSlotId++; const slotId = qweb.nextSlotId++;
ctx.addLine(`w${widgetID}.__owl__.slotId = ${slotId};`); ctx.addLine(`w${componentID}.__owl__.slotId = ${slotId};`);
if (slotNodes.length) { if (slotNodes.length) {
for (let i = 0, length = slotNodes.length; i < length; i++) { for (let i = 0, length = slotNodes.length; i < length; i++) {
const slotNode = slotNodes[i]; const slotNode = slotNodes[i];
@@ -569,28 +569,28 @@ QWeb.addDirective({
} }
} }
ctx.addLine(`def${defID} = w${widgetID}._prepare();`); ctx.addLine(`def${defID} = w${componentID}._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
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${componentID}._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;${refExpr}${transitionsInsertCode}},remove() {},destroy(vn) {${finalizeComponentCode}}}});c${
ctx.parentNode ctx.parentNode
}[_${dummyID}_index]=pvnode;w${widgetID}.__owl__.pvnode = pvnode;});` }[_${dummyID}_index]=pvnode;w${componentID}.__owl__.pvnode = pvnode;});`
); );
ctx.addElse(); ctx.addElse();
// need to update widget // need to update component
const patchQueueCode = async ? `patchQueue${widgetID}` : "extra.patchQueue"; const patchQueueCode = async ? `patchQueue${componentID}` : "extra.patchQueue";
ctx.addLine( ctx.addLine(
`def${defID} = def${defID} || w${widgetID}._updateProps(props${widgetID}, extra.forceUpdate, ${patchQueueCode});` `def${defID} = def${defID} || w${componentID}._updateProps(props${componentID}, extra.forceUpdate, ${patchQueueCode});`
); );
let keepAliveCode = ""; let keepAliveCode = "";
if (keepAlive) { if (keepAlive) {
keepAliveCode = `pvnode.data.hook.insert = vn => {vn.elm.parentNode.replaceChild(w${widgetID}.el,vn.elm);vn.elm=w${widgetID}.el;w${widgetID}._remount();};`; keepAliveCode = `pvnode.data.hook.insert = vn => {vn.elm.parentNode.replaceChild(w${componentID}.el,vn.elm);vn.elm=w${componentID}.el;w${componentID}._remount();};`;
} }
ctx.addLine( ctx.addLine(
`def${defID} = def${defID}.then(()=>{if (w${widgetID}.__owl__.isDestroyed) {return};${ `def${defID} = def${defID}.then(()=>{if (w${componentID}.__owl__.isDestroyed) {return};${
tattStyle ? `w${widgetID}.el.style=${tattStyle};` : "" tattStyle ? `w${componentID}.el.style=${tattStyle};` : ""
}${updateClassCode}let pvnode=w${widgetID}.__owl__.pvnode;${keepAliveCode}c${ }${updateClassCode}let pvnode=w${componentID}.__owl__.pvnode;${keepAliveCode}c${
ctx.parentNode ctx.parentNode
}[_${dummyID}_index]=pvnode;});` }[_${dummyID}_index]=pvnode;});`
); );
@@ -598,7 +598,7 @@ QWeb.addDirective({
if (async) { if (async) {
ctx.addLine( ctx.addLine(
`def${defID}.then(w${widgetID}._applyPatchQueue.bind(w${widgetID}, patchQueue${widgetID}));` `def${defID}.then(w${componentID}._applyPatchQueue.bind(w${componentID}, patchQueue${componentID}));`
); );
} else { } else {
ctx.addLine(`extra.promises.push(def${defID});`); ctx.addLine(`extra.promises.push(def${defID});`);
+9 -9
View File
@@ -9,7 +9,7 @@ exports[`animations t-transition combined with component 1`] = `
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -24,9 +24,9 @@ exports[`animations t-transition combined with component 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`Child\`; let componentKey4 = \`Child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -43,7 +43,7 @@ exports[`animations t-transition combined with component 1`] = `
}" }"
`; `;
exports[`animations t-transition combined with t-widget and t-if 1`] = ` exports[`animations t-transition combined with t-component and t-if 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -53,7 +53,7 @@ exports[`animations t-transition combined with t-widget and t-if 1`] = `
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
if (context['state'].display) { if (context['state'].display) {
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -68,9 +68,9 @@ exports[`animations t-transition combined with t-widget and t-if 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`Child\`; let componentKey4 = \`Child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
+98 -98
View File
@@ -22,7 +22,7 @@ exports[`async rendering delayed component with t-asyncroot directive 1`] = `
let c4 = [], p4 = {key:4,attrs:{class: _3}}; let c4 = [], p4 = {key:4,attrs:{class: _3}};
var vn4 = h('div', p4, c4); var vn4 = h('div', p4, c4);
c1.push(vn4); c1.push(vn4);
//WIDGET //COMPONENT
let def6; let def6;
let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false; let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false;
let _5_index = c4.length; let _5_index = c4.length;
@@ -37,9 +37,9 @@ exports[`async rendering delayed component with t-asyncroot directive 1`] = `
} }
} }
if (!w7) { if (!w7) {
let widgetKey7 = \`Child\`; let componentKey7 = \`Child\`;
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7]; let W7 = context.components && context.components[componentKey7] || QWeb.components[componentKey7];
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')} if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
w7 = new W7(owner, props7); w7 = new W7(owner, props7);
context.__owl__.cmap[7] = w7.__owl__.id; context.__owl__.cmap[7] = w7.__owl__.id;
def6 = w7._prepare(); def6 = w7._prepare();
@@ -49,7 +49,7 @@ exports[`async rendering delayed component with t-asyncroot directive 1`] = `
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;}); def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;});
} }
extra.promises.push(def6); extra.promises.push(def6);
//WIDGET //COMPONENT
let def9; let def9;
let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false; let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false;
let _8_index = c4.length; let _8_index = c4.length;
@@ -65,9 +65,9 @@ exports[`async rendering delayed component with t-asyncroot directive 1`] = `
} }
} }
if (!w10) { if (!w10) {
let widgetKey10 = \`AsyncChild\`; let componentKey10 = \`AsyncChild\`;
let W10 = context.widgets && context.widgets[widgetKey10] || QWeb.widgets[widgetKey10]; let W10 = context.components && context.components[componentKey10] || QWeb.components[componentKey10];
if (!W10) {throw new Error('Cannot find the definition of widget \\"' + widgetKey10 + '\\"')} if (!W10) {throw new Error('Cannot find the definition of component \\"' + componentKey10 + '\\"')}
w10 = new W10(owner, props10); w10 = new W10(owner, props10);
context.__owl__.cmap[10] = w10.__owl__.id; context.__owl__.cmap[10] = w10.__owl__.id;
def9 = w10._prepare(); def9 = w10._prepare();
@@ -103,7 +103,7 @@ exports[`async rendering fast component with t-asyncroot directive 1`] = `
let c4 = [], p4 = {key:4,attrs:{class: _3}}; let c4 = [], p4 = {key:4,attrs:{class: _3}};
var vn4 = h('div', p4, c4); var vn4 = h('div', p4, c4);
c1.push(vn4); c1.push(vn4);
//WIDGET //COMPONENT
let def6; let def6;
let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false; let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false;
let _5_index = c4.length; let _5_index = c4.length;
@@ -119,9 +119,9 @@ exports[`async rendering fast component with t-asyncroot directive 1`] = `
} }
} }
if (!w7) { if (!w7) {
let widgetKey7 = \`Child\`; let componentKey7 = \`Child\`;
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7]; let W7 = context.components && context.components[componentKey7] || QWeb.components[componentKey7];
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')} if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
w7 = new W7(owner, props7); w7 = new W7(owner, props7);
context.__owl__.cmap[7] = w7.__owl__.id; context.__owl__.cmap[7] = w7.__owl__.id;
def6 = w7._prepare(); def6 = w7._prepare();
@@ -131,7 +131,7 @@ exports[`async rendering fast component with t-asyncroot directive 1`] = `
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;}); def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;});
} }
def6.then(w7._applyPatchQueue.bind(w7, patchQueue7)); def6.then(w7._applyPatchQueue.bind(w7, patchQueue7));
//WIDGET //COMPONENT
let def9; let def9;
let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false; let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false;
let _8_index = c4.length; let _8_index = c4.length;
@@ -146,9 +146,9 @@ exports[`async rendering fast component with t-asyncroot directive 1`] = `
} }
} }
if (!w10) { if (!w10) {
let widgetKey10 = \`AsyncChild\`; let componentKey10 = \`AsyncChild\`;
let W10 = context.widgets && context.widgets[widgetKey10] || QWeb.widgets[widgetKey10]; let W10 = context.components && context.components[componentKey10] || QWeb.components[componentKey10];
if (!W10) {throw new Error('Cannot find the definition of widget \\"' + widgetKey10 + '\\"')} if (!W10) {throw new Error('Cannot find the definition of component \\"' + componentKey10 + '\\"')}
w10 = new W10(owner, props10); w10 = new W10(owner, props10);
context.__owl__.cmap[10] = w10.__owl__.id; context.__owl__.cmap[10] = w10.__owl__.id;
def9 = w10._prepare(); def9 = w10._prepare();
@@ -162,7 +162,7 @@ exports[`async rendering fast component with t-asyncroot directive 1`] = `
}" }"
`; `;
exports[`async rendering t-widget with t-asyncroot directive: mixed re-renderings 1`] = ` exports[`async rendering t-component with t-asyncroot directive: mixed re-renderings 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -184,7 +184,7 @@ exports[`async rendering t-widget with t-asyncroot directive: mixed re-rendering
let c4 = [], p4 = {key:4,attrs:{class: _3}}; let c4 = [], p4 = {key:4,attrs:{class: _3}};
var vn4 = h('div', p4, c4); var vn4 = h('div', p4, c4);
c1.push(vn4); c1.push(vn4);
//WIDGET //COMPONENT
let def6; let def6;
let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false; let w7 = 7 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[7]] : false;
let _5_index = c4.length; let _5_index = c4.length;
@@ -199,9 +199,9 @@ exports[`async rendering t-widget with t-asyncroot directive: mixed re-rendering
} }
} }
if (!w7) { if (!w7) {
let widgetKey7 = \`Child\`; let componentKey7 = \`Child\`;
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7]; let W7 = context.components && context.components[componentKey7] || QWeb.components[componentKey7];
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')} if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
w7 = new W7(owner, props7); w7 = new W7(owner, props7);
context.__owl__.cmap[7] = w7.__owl__.id; context.__owl__.cmap[7] = w7.__owl__.id;
def6 = w7._prepare(); def6 = w7._prepare();
@@ -211,7 +211,7 @@ exports[`async rendering t-widget with t-asyncroot directive: mixed re-rendering
def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;}); def6 = def6.then(()=>{if (w7.__owl__.isDestroyed) {return};let pvnode=w7.__owl__.pvnode;c4[_5_index]=pvnode;});
} }
extra.promises.push(def6); extra.promises.push(def6);
//WIDGET //COMPONENT
let def9; let def9;
let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false; let w10 = 10 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[10]] : false;
let _8_index = c4.length; let _8_index = c4.length;
@@ -227,9 +227,9 @@ exports[`async rendering t-widget with t-asyncroot directive: mixed re-rendering
} }
} }
if (!w10) { if (!w10) {
let widgetKey10 = \`AsyncChild\`; let componentKey10 = \`AsyncChild\`;
let W10 = context.widgets && context.widgets[widgetKey10] || QWeb.widgets[widgetKey10]; let W10 = context.components && context.components[componentKey10] || QWeb.components[componentKey10];
if (!W10) {throw new Error('Cannot find the definition of widget \\"' + widgetKey10 + '\\"')} if (!W10) {throw new Error('Cannot find the definition of component \\"' + componentKey10 + '\\"')}
w10 = new W10(owner, props10); w10 = new W10(owner, props10);
context.__owl__.cmap[10] = w10.__owl__.id; context.__owl__.cmap[10] = w10.__owl__.id;
def9 = w10._prepare(); def9 = w10._prepare();
@@ -243,7 +243,7 @@ exports[`async rendering t-widget with t-asyncroot directive: mixed re-rendering
}" }"
`; `;
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-component dynamic t-att-style is properly added and updated on widget root el 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -252,7 +252,7 @@ exports[`class and style attributes with t-widget dynamic t-att-style is properl
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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;
@@ -268,9 +268,9 @@ exports[`class and style attributes with t-widget dynamic t-att-style is properl
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -284,7 +284,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`] = ` exports[`class and style attributes with t-component t-att-class is properly added/removed on widget root el 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -293,7 +293,7 @@ exports[`class and style attributes with t-widget t-att-class is properly added/
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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;
@@ -309,9 +309,9 @@ exports[`class and style attributes with t-widget t-att-class is properly added/
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -329,7 +329,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`] = ` exports[`composition sub components with some state rendered in a loop 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -353,7 +353,7 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
context.number_index = i; context.number_index = i;
context.number = _3[i]; context.number = _3[i];
context.number_value = _4[i]; context.number_value = _4[i];
//WIDGET //COMPONENT
let key8 = context['number']; let key8 = context['number'];
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;
@@ -369,9 +369,9 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
} }
} }
if (!w7) { if (!w7) {
let widgetKey7 = \`ChildWidget\`; let componentKey7 = \`ChildWidget\`;
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7]; let W7 = context.components && context.components[componentKey7] || QWeb.components[componentKey7];
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')} if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')}
w7 = new W7(owner, props7); w7 = new W7(owner, props7);
context.__owl__.cmap[key8] = w7.__owl__.id; context.__owl__.cmap[key8] = w7.__owl__.id;
def6 = w7._prepare(); def6 = w7._prepare();
@@ -386,7 +386,7 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
}" }"
`; `;
exports[`composition t-widget with dynamic value 1`] = ` exports[`composition t-component with dynamic value 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -395,7 +395,7 @@ exports[`composition t-widget with dynamic value 1`] = `
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -410,9 +410,9 @@ exports[`composition t-widget with dynamic value 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = (context['state'].widget); let componentKey4 = (context['state'].widget);
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -426,7 +426,7 @@ exports[`composition t-widget with dynamic value 1`] = `
}" }"
`; `;
exports[`composition t-widget with dynamic value 2 1`] = ` exports[`composition t-component with dynamic value 2 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -435,7 +435,7 @@ exports[`composition t-widget with dynamic value 2 1`] = `
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -450,9 +450,9 @@ exports[`composition t-widget with dynamic value 2 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`Widget\${context['state'].widget}\`; let componentKey4 = \`Widget\${context['state'].widget}\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -466,7 +466,7 @@ exports[`composition t-widget with dynamic value 2 1`] = `
}" }"
`; `;
exports[`other directives with t-widget t-on with handler bound to argument 1`] = ` exports[`other directives with t-component t-on with handler bound to argument 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -475,7 +475,7 @@ exports[`other directives with t-widget t-on with handler bound to argument 1`]
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -490,9 +490,9 @@ exports[`other directives with t-widget t-on with handler bound to argument 1`]
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -506,7 +506,7 @@ exports[`other directives with t-widget t-on with handler bound to argument 1`]
}" }"
`; `;
exports[`other directives with t-widget t-on with handler bound to empty object (with non empty inner string) 1`] = ` exports[`other directives with t-component t-on with handler bound to empty object (with non empty inner string) 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -515,7 +515,7 @@ exports[`other directives with t-widget t-on with handler bound to empty object
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -530,9 +530,9 @@ exports[`other directives with t-widget t-on with handler bound to empty object
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -546,7 +546,7 @@ exports[`other directives with t-widget t-on with handler bound to empty object
}" }"
`; `;
exports[`other directives with t-widget t-on with handler bound to empty object 1`] = ` exports[`other directives with t-component t-on with handler bound to empty object 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -555,7 +555,7 @@ exports[`other directives with t-widget t-on with handler bound to empty object
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -570,9 +570,9 @@ exports[`other directives with t-widget t-on with handler bound to empty object
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -586,7 +586,7 @@ exports[`other directives with t-widget t-on with handler bound to empty object
}" }"
`; `;
exports[`other directives with t-widget t-on with handler bound to object 1`] = ` exports[`other directives with t-component t-on with handler bound to object 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -595,7 +595,7 @@ exports[`other directives with t-widget t-on with handler bound to object 1`] =
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -610,9 +610,9 @@ exports[`other directives with t-widget t-on with handler bound to object 1`] =
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -626,7 +626,7 @@ exports[`other directives with t-widget t-on with handler bound to object 1`] =
}" }"
`; `;
exports[`other directives with t-widget t-on with prevent and self modifiers (order matters) 1`] = ` exports[`other directives with t-component t-on with prevent and self modifiers (order matters) 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -635,7 +635,7 @@ exports[`other directives with t-widget t-on with prevent and self modifiers (or
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -650,9 +650,9 @@ exports[`other directives with t-widget t-on with prevent and self modifiers (or
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`Child\`; let componentKey4 = \`Child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -666,7 +666,7 @@ exports[`other directives with t-widget t-on with prevent and self modifiers (or
}" }"
`; `;
exports[`other directives with t-widget t-on with self and prevent modifiers (order matters) 1`] = ` exports[`other directives with t-component t-on with self and prevent modifiers (order matters) 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -675,7 +675,7 @@ exports[`other directives with t-widget t-on with self and prevent modifiers (or
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -690,9 +690,9 @@ exports[`other directives with t-widget t-on with self and prevent modifiers (or
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -706,7 +706,7 @@ exports[`other directives with t-widget t-on with self and prevent modifiers (or
}" }"
`; `;
exports[`other directives with t-widget t-on with self modifier 1`] = ` exports[`other directives with t-component t-on with self modifier 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -715,7 +715,7 @@ exports[`other directives with t-widget t-on with self modifier 1`] = `
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -730,9 +730,9 @@ exports[`other directives with t-widget t-on with self modifier 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -746,7 +746,7 @@ exports[`other directives with t-widget t-on with self modifier 1`] = `
}" }"
`; `;
exports[`other directives with t-widget t-on with stop and/or prevent modifiers 1`] = ` exports[`other directives with t-component t-on with stop and/or prevent modifiers 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
let utils = this.utils; let utils = this.utils;
@@ -755,7 +755,7 @@ exports[`other directives with t-widget t-on with stop and/or prevent modifiers
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -770,9 +770,9 @@ exports[`other directives with t-widget t-on with stop and/or prevent modifiers
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -795,7 +795,7 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
let key5 = 'somestring'; let key5 = 'somestring';
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;
@@ -811,9 +811,9 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`child\`; let componentKey4 = \`child\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[key5] = w4.__owl__.id; context.__owl__.cmap[key5] = w4.__owl__.id;
def3 = w4._prepare(); def3 = w4._prepare();
@@ -983,7 +983,7 @@ exports[`t-slot directive can define and call slots 1`] = `
var h = this.utils.h; var h = this.utils.h;
let c1 = [], p1 = {key:1}; let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1); var vn1 = h('div', p1, c1);
//WIDGET //COMPONENT
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; let _2_index = c1.length;
@@ -998,9 +998,9 @@ exports[`t-slot directive can define and call slots 1`] = `
} }
} }
if (!w4) { if (!w4) {
let widgetKey4 = \`Dialog\`; let componentKey4 = \`Dialog\`;
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.components && context.components[componentKey4] || QWeb.components[componentKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of component \\"' + componentKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
context.__owl__.cmap[4] = w4.__owl__.id; context.__owl__.cmap[4] = w4.__owl__.id;
w4.__owl__.slotId = 1; w4.__owl__.slotId = 1;
-33
View File
@@ -1,33 +0,0 @@
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);
}
}
+8 -8
View File
@@ -18,7 +18,7 @@ import {
// - fixture: a div, appended to the DOM, intended to be the target of dom // - fixture: a div, appended to the DOM, intended to be the target of dom
// manipulations. Note that it is removed after each test. // manipulations. Note that it is removed after each test.
// - qweb: a new QWeb instance // - qweb: a new QWeb instance
// - env: a WEnv, necessary to create new widgets // - env: a WEnv, necessary to create new components
// - cssEl: a stylesheet injected into the dom // - cssEl: a stylesheet injected into the dom
let fixture: HTMLElement; let fixture: HTMLElement;
@@ -179,7 +179,7 @@ describe("animations", () => {
); );
env.qweb.addTemplate("Child", `<span>blue</span>`); env.qweb.addTemplate("Child", `<span>blue</span>`);
class Parent extends Widget { class Parent extends Widget {
widgets = { Child: Child }; components = { Child: Child };
} }
class Child extends Widget {} class Child extends Widget {}
const widget = new Parent(env); const widget = new Parent(env);
@@ -209,16 +209,16 @@ describe("animations", () => {
expect(fixture.innerHTML).toBe('<div><span class="">blue</span></div>'); expect(fixture.innerHTML).toBe('<div><span class="">blue</span></div>');
}); });
test("t-transition combined with t-widget and t-if", async () => { test("t-transition combined with t-component and t-if", async () => {
expect.assertions(8); expect.assertions(8);
env.qweb.addTemplate( env.qweb.addTemplate(
"Parent", "Parent",
`<div><t t-if="state.display" t-widget="Child" t-transition="chimay"/></div>` `<div><t t-if="state.display" t-component="Child" t-transition="chimay"/></div>`
); );
env.qweb.addTemplate("Child", `<span>blue</span>`); env.qweb.addTemplate("Child", `<span>blue</span>`);
class Parent extends Widget { class Parent extends Widget {
widgets = { Child: Child }; components = { Child: Child };
state = { display: true }; state = { display: true };
} }
class Child extends Widget {} class Child extends Widget {}
@@ -351,21 +351,21 @@ describe("animations", () => {
); );
}); });
test("t-transition combined with t-widget, remove and re-add before transitionend", async () => { test("t-transition combined with t-component, remove and re-add before transitionend", async () => {
expect.assertions(11); expect.assertions(11);
env.qweb.addTemplates( env.qweb.addTemplates(
`<templates> `<templates>
<div t-name="Parent"> <div t-name="Parent">
<button t-on-click="toggle">Toggle</button> <button t-on-click="toggle">Toggle</button>
<t t-if="state.flag" t-widget="Child" t-transition="chimay"/> <t t-if="state.flag" t-component="Child" t-transition="chimay"/>
</div> </div>
<span t-name="Child">blue</span> <span t-name="Child">blue</span>
</templates>` </templates>`
); );
class Child extends Widget {} class Child extends Widget {}
class Parent extends Widget { class Parent extends Widget {
widgets = { Child }; components = { Child };
constructor(parent) { constructor(parent) {
super(parent); super(parent);
this.state = { flag: false }; this.state = { flag: false };
+171 -171
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -54,7 +54,7 @@ describe("props validation", () => {
try { try {
await w._updateProps({}); await w._updateProps({});
} catch (e) { } catch (e) {
expect(e.message).toBe("Missing props 'message' (widget 'TestWidget')"); expect(e.message).toBe("Missing props 'message' (component 'TestWidget')");
} }
}); });
@@ -65,7 +65,7 @@ describe("props validation", () => {
expect(() => { expect(() => {
new TestWidget(env); new TestWidget(env);
}).toThrow("Missing props 'message' (widget 'TestWidget')"); }).toThrow("Missing props 'message' (component 'TestWidget')");
}); });
test("validate simple types", async () => { test("validate simple types", async () => {
@@ -93,7 +93,7 @@ describe("props validation", () => {
expect(() => { expect(() => {
new TestWidget(env, { p: test.ko }); new TestWidget(env, { p: test.ko });
}).toThrow("Props 'p' of invalid type in widget"); }).toThrow("Props 'p' of invalid type in component");
} }
}); });
@@ -122,7 +122,7 @@ describe("props validation", () => {
expect(() => { expect(() => {
new TestWidget(env, { p: test.ko }); new TestWidget(env, { p: test.ko });
}).toThrow("Props 'p' of invalid type in widget"); }).toThrow("Props 'p' of invalid type in component");
} }
}); });
@@ -139,7 +139,7 @@ describe("props validation", () => {
expect(() => { expect(() => {
new TestWidget(env, { p: 1 }); new TestWidget(env, { p: 1 });
}).toThrow("Props 'p' of invalid type in widget"); }).toThrow("Props 'p' of invalid type in component");
}); });
test("can validate an optional props", async () => { test("can validate an optional props", async () => {
+10 -10
View File
@@ -541,7 +541,7 @@ describe("connecting a component to store", () => {
); );
env.qweb.addTemplate("Todo", `<span><t t-esc="props.msg"/></span>`); env.qweb.addTemplate("Todo", `<span><t t-esc="props.msg"/></span>`);
class App extends Component<any, any, any> { class App extends Component<any, any, any> {
widgets = { Todo }; components = { Todo };
} }
class Todo extends Component<any, any, any> {} class Todo extends Component<any, any, any> {}
const state = { todos: [] }; const state = { todos: [] };
@@ -632,7 +632,7 @@ describe("connecting a component to store", () => {
</templates> </templates>
`); `);
class App extends Component<any, any, any> { class App extends Component<any, any, any> {
widgets = { Todo }; components = { Todo };
} }
class Todo extends Component<any, any, any> {} class Todo extends Component<any, any, any> {}
@@ -686,11 +686,11 @@ describe("connecting a component to store", () => {
"Parent", "Parent",
` `
<div> <div>
<t t-if="state.child" t-widget="ConnectedChild"/> <t t-if="state.child" t-component="ConnectedChild"/>
</div>` </div>`
); );
class Parent extends Component<any, any, any> { class Parent extends Component<any, any, any> {
widgets = { ConnectedChild }; components = { ConnectedChild };
constructor(env: Env) { constructor(env: Env) {
super(env); super(env);
@@ -739,7 +739,7 @@ describe("connecting a component to store", () => {
</div>` </div>`
); );
class TodoList extends Component<any, any, any> { class TodoList extends Component<any, any, any> {
widgets = { ConnectedTodo }; components = { ConnectedTodo };
} }
function mapStoreToProps(state) { function mapStoreToProps(state) {
@@ -806,7 +806,7 @@ describe("connecting a component to store", () => {
</div>` </div>`
); );
class TodoList extends Component<any, any, any> { class TodoList extends Component<any, any, any> {
widgets = { ConnectedTodo }; components = { ConnectedTodo };
} }
function mapStoreToProps(state) { function mapStoreToProps(state) {
@@ -843,7 +843,7 @@ describe("connecting a component to store", () => {
</div>` </div>`
); );
class App extends Component<any, any, any> { class App extends Component<any, any, any> {
widgets = { ConnectedBeer }; components = { ConnectedBeer };
state = { beerId: 1 }; state = { beerId: 1 };
} }
@@ -927,7 +927,7 @@ describe("connecting a component to store", () => {
</div>` </div>`
); );
class App extends Component<any, any, any> { class App extends Component<any, any, any> {
widgets = { ConnectedBeer }; components = { ConnectedBeer };
state = { beerId: 0 }; state = { beerId: 0 };
} }
@@ -999,7 +999,7 @@ describe("connecting a component to store", () => {
</div>` </div>`
); );
class App extends Component<any, any, any> { class App extends Component<any, any, any> {
widgets = { ConnectedBeer }; components = { ConnectedBeer };
state = { beerId: 0 }; state = { beerId: 0 };
} }
@@ -1079,7 +1079,7 @@ describe("connecting a component to store", () => {
` `
); );
class Parent extends Component<any, any, any> { class Parent extends Component<any, any, any> {
widgets = { Child: ConnectedChild }; components = { Child: ConnectedChild };
} }
const ConnectedParent = connect( const ConnectedParent = connect(
Parent, Parent,
+2 -2
View File
@@ -20,7 +20,7 @@ class Counter extends owl.Component {
// Message Widget // Message Widget
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class Message extends owl.Component { class Message extends owl.Component {
widgets = { Counter }; components = { Counter };
shouldUpdate(nextProps) { shouldUpdate(nextProps) {
return nextProps.message !== this.props.message; return nextProps.message !== this.props.message;
@@ -36,7 +36,7 @@ class Message extends owl.Component {
// Root Widget // Root Widget
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class App extends owl.Component { class App extends owl.Component {
widgets = { Message }; components = { Message };
state = { messages: [], multipleFlag: false, clearAfterFlag: false }; state = { messages: [], multipleFlag: false, clearAfterFlag: false };
mounted() { mounted() {
+2 -2
View File
@@ -30,7 +30,7 @@
<div class="right-thing"> <div class="right-thing">
<div class="content" t-on-remove-message="removeMessage"> <div class="content" t-on-remove-message="removeMessage">
<t t-foreach="state.messages" t-as="message"> <t t-foreach="state.messages" t-as="message">
<t t-widget="Message" t-key="message.id" message="message"/> <Message t-key="message.id" message="message"/>
</t> </t>
</div> </div>
</div> </div>
@@ -40,7 +40,7 @@
<span class="author"><t t-esc="props.message.author"/></span> <span class="author"><t t-esc="props.message.author"/></span>
<span class="msg"><t t-esc="props.message.msg"/></span> <span class="msg"><t t-esc="props.message.msg"/></span>
<button class="remove" t-on-click="removeMessage">Remove</button> <button class="remove" t-on-click="removeMessage">Remove</button>
<t t-widget="Counter"/> <Counter/>
</div> </div>
<div t-name="Counter"> <div t-name="Counter">
+1 -1
View File
@@ -161,7 +161,7 @@ class App extends owl.Component {
super(...args); super(...args);
this.version = owl.__info__.version; this.version = owl.__info__.version;
this.SAMPLES = SAMPLES; this.SAMPLES = SAMPLES;
this.widgets = { TabbedEditor }; this.components = { TabbedEditor };
this.state = { this.state = {
js: SAMPLES[0].code, js: SAMPLES[0].code,
+36 -36
View File
@@ -8,9 +8,9 @@ class Counter extends owl.Component {
} }
} }
// Main root widget // Main root component
class App extends owl.Component { class App extends owl.Component {
widgets = { Counter }; components = { Counter };
} }
// Application setup // Application setup
@@ -49,8 +49,8 @@ class Counter extends owl.Component {
} }
class App extends owl.Component { class App extends owl.Component {
state = { flag: false, widgetFlag: false, numbers: [] }; state = { flag: false, componentFlag: false, numbers: [] };
widgets = { Counter }; components = { Counter };
toggle(key) { toggle(key) {
this.state[key] = !this.state[key]; this.state[key] = !this.state[key];
@@ -83,12 +83,12 @@ const ANIMATION_XML = `<templates>
</div> </div>
</div> </div>
<h2>Transition on sub widgets</h2> <h2>Transition on sub components</h2>
<div class="demo"> <div class="demo">
<button t-on-click="toggle('widgetFlag')">Toggle widget</button> <button t-on-click="toggle('componentFlag')">Toggle component</button>
<div> <div>
<Counter t-if="state.widgetFlag" t-transition="fade"/> <Counter t-if="state.componentFlag" t-transition="fade"/>
</div> </div>
</div> </div>
@@ -173,12 +173,12 @@ const ANIMATION_CSS = `button {
const LIFECYCLE_DEMO = `// This example shows all the possible lifecycle hooks const LIFECYCLE_DEMO = `// This example shows all the possible lifecycle hooks
// //
// The root widget controls a sub widget (DemoWidget). It logs all its lifecycle // The root component controls a sub component (DemoComponent). It logs all its lifecycle
// methods in the console. Try modifying its state by clicking on it, or by // methods in the console. Try modifying its state by clicking on it, or by
// clicking on the two main buttons, and look into the console to see what // clicking on the two main buttons, and look into the console to see what
// happens. // happens.
class DemoWidget extends owl.Component { class DemoComponent extends owl.Component {
constructor() { constructor() {
super(...arguments); super(...arguments);
this.state = { n: 0 }; this.state = { n: 0 };
@@ -208,14 +208,14 @@ class DemoWidget extends owl.Component {
} }
class App extends owl.Component { class App extends owl.Component {
widgets = { DemoWidget }; components = { DemoComponent };
state = { n: 0, flag: true }; state = { n: 0, flag: true };
increment() { increment() {
this.state.n++; this.state.n++;
} }
toggleSubWidget() { toggleSubComponent() {
this.state.flag = !this.state.flag; this.state.flag = !this.state.flag;
} }
} }
@@ -226,17 +226,17 @@ app.mount(document.body);
`; `;
const LIFECYCLE_DEMO_XML = `<templates> const LIFECYCLE_DEMO_XML = `<templates>
<div t-name="DemoWidget" t-on-click="increment" class="demo"> <div t-name="DemoComponent" t-on-click="increment" class="demo">
<div>Demo Sub Widget</div> <div>Demo Sub Component</div>
<div>(click on me to update me)</div> <div>(click on me to update me)</div>
<div>Props: <t t-esc="props.n"/>, State: <t t-esc="state.n"/>. </div> <div>Props: <t t-esc="props.n"/>, State: <t t-esc="state.n"/>. </div>
</div> </div>
<div t-name="App"> <div t-name="App">
<button t-on-click="increment">Increment Parent State</button> <button t-on-click="increment">Increment Parent State</button>
<button t-on-click="toggleSubWidget">Toggle SubWidget</button> <button t-on-click="toggleSubComponent">Toggle SubComponent</button>
<div t-if="state.flag"> <div t-if="state.flag">
<DemoWidget n="state.n"/> <DemoComponent n="state.n"/>
</div> </div>
</div> </div>
</templates>`; </templates>`;
@@ -406,7 +406,7 @@ function mapStoreToProps(state) {
} }
class TodoApp extends owl.Component { class TodoApp extends owl.Component {
widgets = { TodoItem }; components = { TodoItem };
state = { filter: "all" }; state = { filter: "all" };
get visibleTodos() { get visibleTodos() {
@@ -910,7 +910,7 @@ const RESPONSIVE = `// In this example, we show how we can modify keys in the gl
// //
// The main idea is to have a "isMobile" key in the environment, then listen // The main idea is to have a "isMobile" key in the environment, then listen
// to resize events and update the env if needed. Then, the whole interface // to resize events and update the env if needed. Then, the whole interface
// will be updated, creating and destroying widgets as needed. // will be updated, creating and destroying components as needed.
// //
// To see this in action, try resizing the window. The application will switch // To see this in action, try resizing the window. The application will switch
// to mobile mode whenever it has less than 768px. // to mobile mode whenever it has less than 768px.
@@ -921,14 +921,14 @@ const RESPONSIVE = `// In this example, we show how we can modify keys in the gl
class Navbar extends owl.Component {} class Navbar extends owl.Component {}
class ControlPanel extends owl.Component { class ControlPanel extends owl.Component {
widgets = { MobileSearchView }; components = { MobileSearchView };
} }
class FormView extends owl.Component { class FormView extends owl.Component {
widgets = { AdvancedWidget }; components = { AdvancedComponent };
} }
class AdvancedWidget extends owl.Component {} class AdvancedComponent extends owl.Component {}
class Chatter extends owl.Component { class Chatter extends owl.Component {
messages = Array.from(Array(100).keys()); messages = Array.from(Array(100).keys());
@@ -938,7 +938,7 @@ class MobileSearchView extends owl.Component {}
class App extends owl.Component { class App extends owl.Component {
widgets = { Navbar, ControlPanel, FormView, Chatter }; components = { Navbar, ControlPanel, FormView, Chatter };
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -974,12 +974,12 @@ const RESPONSIVE_XML = `<templates>
<div t-name="ControlPanel" class="controlpanel"> <div t-name="ControlPanel" class="controlpanel">
<h2>Control Panel</h2> <h2>Control Panel</h2>
<t t-if="env.isMobile" t-widget="MobileSearchView"/> <MobileSearchView t-if="env.isMobile" />
</div> </div>
<div t-name="FormView" class="formview"> <div t-name="FormView" class="formview">
<h2>Form View</h2> <h2>Form View</h2>
<t t-if="!env.isMobile" t-widget="AdvancedWidget"/> <AdvancedComponent t-if="!env.isMobile" />
</div> </div>
<div t-name="Chatter" class="chatter"> <div t-name="Chatter" class="chatter">
@@ -989,8 +989,8 @@ const RESPONSIVE_XML = `<templates>
<div t-name="MobileSearchView">Mobile searchview</div> <div t-name="MobileSearchView">Mobile searchview</div>
<div t-name="AdvancedWidget"> <div t-name="AdvancedComponent">
This widget is only created in desktop mode. This component is only created in desktop mode.
<button>Button!</button> <button>Button!</button>
</div> </div>
@@ -1072,7 +1072,7 @@ const RESPONSIVE_CSS = `body {
const SLOTS = `// We show here how slots can be used to create generic components. const SLOTS = `// We show here how slots can be used to create generic components.
// In this example, the Card component is basically only a container. It is not // In this example, the Card component is basically only a container. It is not
// aware of its content. It just knows where it should be (with t-slot). // aware of its content. It just knows where it should be (with t-slot).
// The parent widget define the content with t-set. // The parent component define the content with t-set.
// //
// Note that the t-on-click event, defined in the App template, is executed in // Note that the t-on-click event, defined in the App template, is executed in
// the context of the App component, even though it is inside the Card component // the context of the App component, even though it is inside the Card component
@@ -1093,9 +1093,9 @@ class Counter extends owl.Component {
} }
} }
// Main root widget // Main root component
class App extends owl.Component { class App extends owl.Component {
widgets = {Card, Counter}; components = {Card, Counter};
state = {a: 1, b: 3}; state = {a: 1, b: 3};
inc(key, delta) { inc(key, delta) {
@@ -1188,13 +1188,13 @@ const SLOTS_CSS = `.main {
const ASYNC_COMPONENTS = `// This example will not work if your browser does not support ESNext class fields 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 (slow). // In this example, we have 2 sub components, one of them being async (slow).
// However, we don't want renderings of the other sub widget to be delayed // However, we don't want renderings of the other sub component to be delayed
// because of the slow widget. We use the 't-asyncroot' directive for this // because of the slow component. We use the 't-asyncroot' directive for this
// purpose. Try removing it to see the difference. // purpose. Try removing it to see the difference.
class App extends owl.Component { class App extends owl.Component {
widgets = {SlowWidget, NotificationList}; components = {SlowComponent, NotificationList};
state = { value: 0, notifs: [] }; state = { value: 0, notifs: [] };
increment() { increment() {
@@ -1208,9 +1208,9 @@ class App extends owl.Component {
} }
} }
class SlowWidget extends owl.Component { class SlowComponent extends owl.Component {
willUpdateProps() { willUpdateProps() {
// simulate a widget that needs to perform async stuff (e.g. an RPC) // simulate a component that needs to perform async stuff (e.g. an RPC)
// with the updated props before re-rendering itself // with the updated props before re-rendering itself
return new Promise(resolve => setTimeout(resolve, 1500)); return new Promise(resolve => setTimeout(resolve, 1500));
} }
@@ -1226,11 +1226,11 @@ app.mount(document.body);
const ASYNC_COMPONENTS_XML = `<templates> const ASYNC_COMPONENTS_XML = `<templates>
<div t-name="App" class="app"> <div t-name="App" class="app">
<button t-on-click="increment">Increment</button> <button t-on-click="increment">Increment</button>
<SlowWidget value="state.value"/> <SlowComponent value="state.value"/>
<NotificationList t-asyncroot="1" notifications="state.notifs"/> <NotificationList t-asyncroot="1" notifications="state.notifs"/>
</div> </div>
<div t-name="SlowWidget" class="value" > <div t-name="SlowComponent" class="value" >
Current value: <t t-esc="props.value"/> Current value: <t t-esc="props.value"/>
</div> </div>