mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] owl: update to last version
This commit is contained in:
@@ -1118,7 +1118,7 @@
|
|||||||
// use case is that component's templates are qweb dependant, and need to be
|
// use case is that component's templates are qweb dependant, and need to be
|
||||||
// able to map a qweb instance to a template name.
|
// able to map a qweb instance to a template name.
|
||||||
this.id = nextID++;
|
this.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.
|
||||||
this.slots = {};
|
this.slots = {};
|
||||||
this.nextSlotId = 1;
|
this.nextSlotId = 1;
|
||||||
@@ -1135,10 +1135,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
static register(name, Component) {
|
static register(name, Component) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add a template to the internal template map. Note that it is not
|
* Add a template to the internal template map. Note that it is not
|
||||||
@@ -1300,8 +1300,8 @@
|
|||||||
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 = node.attributes;
|
const attributes = node.attributes;
|
||||||
@@ -1537,7 +1537,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QWeb.widgets = Object.create(null);
|
QWeb.components = Object.create(null);
|
||||||
// dev mode enables better error messages or more costly validations
|
// dev mode enables better error messages or more costly validations
|
||||||
QWeb.dev = false;
|
QWeb.dev = false;
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -1640,7 +1640,7 @@
|
|||||||
// qweb instances.
|
// qweb instances.
|
||||||
const TEMPLATE_MAP = {};
|
const TEMPLATE_MAP = {};
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Widget
|
// Component
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
let nextId = 1;
|
let nextId = 1;
|
||||||
class Component {
|
class Component {
|
||||||
@@ -1650,21 +1650,21 @@
|
|||||||
/**
|
/**
|
||||||
* 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, props) {
|
constructor(parent, props) {
|
||||||
this.refs = {};
|
this.refs = {};
|
||||||
@@ -1676,9 +1676,9 @@
|
|||||||
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 || {};
|
this.props = props || {};
|
||||||
let id = nextId++;
|
let id = nextId++;
|
||||||
let p = null;
|
let p = null;
|
||||||
@@ -1706,8 +1706,8 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 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() {
|
get el() {
|
||||||
return this.__owl__.vnode ? this.__owl__.vnode.elm : null;
|
return this.__owl__.vnode ? this.__owl__.vnode.elm : null;
|
||||||
@@ -1718,7 +1718,7 @@
|
|||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -1764,7 +1764,7 @@
|
|||||||
* 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.
|
||||||
@@ -1833,8 +1833,8 @@
|
|||||||
* - 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__;
|
||||||
@@ -1855,8 +1855,8 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -2027,9 +2027,9 @@
|
|||||||
__owl__.observer.allowMutations = true;
|
__owl__.observer.allowMutations = true;
|
||||||
}
|
}
|
||||||
// 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;
|
||||||
@@ -2037,7 +2037,7 @@
|
|||||||
return __owl__.renderPromise;
|
return __owl__.renderPromise;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Only called by qweb t-widget directive
|
* Only called by qweb t-component directive
|
||||||
*/
|
*/
|
||||||
_mount(vnode, elm) {
|
_mount(vnode, elm) {
|
||||||
const __owl__ = this.__owl__;
|
const __owl__ = this.__owl__;
|
||||||
@@ -2048,7 +2048,7 @@
|
|||||||
return __owl__.vnode;
|
return __owl__.vnode;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 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__;
|
||||||
@@ -2114,7 +2114,7 @@
|
|||||||
// list of strings (prop names)
|
// list of strings (prop names)
|
||||||
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(`Missing props '${propsDef[i]}' (widget '${this.constructor.name}')`);
|
throw new Error(`Missing props '${propsDef[i]}' (component '${this.constructor.name}')`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2123,7 +2123,7 @@
|
|||||||
for (let propName in propsDef) {
|
for (let propName in propsDef) {
|
||||||
if (!(propName in props)) {
|
if (!(propName in props)) {
|
||||||
if (propsDef[propName] && !propsDef[propName].optional) {
|
if (propsDef[propName] && !propsDef[propName].optional) {
|
||||||
throw new Error(`Missing props '${propName}' (widget '${this.constructor.name}')`);
|
throw new Error(`Missing props '${propName}' (component '${this.constructor.name}')`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
@@ -2131,7 +2131,7 @@
|
|||||||
}
|
}
|
||||||
let isValid = isValidProp(props[propName], propsDef[propName]);
|
let isValid = isValidProp(props[propName], propsDef[propName]);
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
throw new Error(`Props '${propName}' of invalid type in widget '${this.constructor.name}'`);
|
throw new Error(`Props '${propName}' of invalid type in component '${this.constructor.name}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2199,7 +2199,7 @@
|
|||||||
* 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
|
||||||
@@ -2497,7 +2497,7 @@
|
|||||||
const nodeCopy = node.cloneNode(true);
|
const nodeCopy = node.cloneNode(true);
|
||||||
let shouldWarn = nodeCopy.tagName !== "t" && !nodeCopy.hasAttribute("t-key");
|
let shouldWarn = 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 (!shouldWarn &&
|
if (!shouldWarn &&
|
||||||
@@ -2548,7 +2548,7 @@
|
|||||||
* - 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
|
||||||
@@ -2703,19 +2703,19 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// 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
|
||||||
@@ -2726,23 +2726,23 @@
|
|||||||
*
|
*
|
||||||
* ```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 =
|
||||||
@@ -2750,9 +2750,9 @@
|
|||||||
* ? 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);
|
||||||
@@ -2762,7 +2762,7 @@
|
|||||||
* // 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
|
||||||
@@ -2770,7 +2770,7 @@
|
|||||||
* 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;
|
||||||
@@ -2778,29 +2778,29 @@
|
|||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -2808,16 +2808,16 @@
|
|||||||
* 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() {
|
||||||
@@ -2827,7 +2827,7 @@
|
|||||||
* },
|
* },
|
||||||
* 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();
|
||||||
* };
|
* };
|
||||||
@@ -2838,19 +2838,19 @@
|
|||||||
* 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;
|
||||||
@@ -2869,11 +2869,11 @@
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
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 }) {
|
atNodeEncounter({ ctx, value, node, qweb }) {
|
||||||
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;
|
||||||
@@ -2916,7 +2916,7 @@
|
|||||||
.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
|
||||||
@@ -2927,27 +2927,27 @@
|
|||||||
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 = "";
|
||||||
let refKey = "";
|
let refKey = "";
|
||||||
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}.${keepAlive ? "unmount" : "destroy"}();`;
|
let finalizeComponentCode = `w${componentID}.${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);`;
|
||||||
}
|
}
|
||||||
@@ -2979,19 +2979,30 @@
|
|||||||
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]) {
|
||||||
let params = extraArgs
|
let params = "owner";
|
||||||
? `owner, ${ctx.formatExpression(extraArgs)}`
|
if (extraArgs) {
|
||||||
: "owner";
|
if (ctx.inLoop) {
|
||||||
|
let argId = ctx.generateID();
|
||||||
|
// we need to evaluate the arguments now, because the handler will
|
||||||
|
// be set asynchronously later when the widget is ready, and the
|
||||||
|
// context might be different.
|
||||||
|
ctx.addLine(`let arg${argId} = ${ctx.formatExpression(extraArgs)};`);
|
||||||
|
params = `owner, arg${argId}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params = `owner, ${ctx.formatExpression(extraArgs)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
let handler;
|
let handler;
|
||||||
if (mods.length > 0) {
|
if (mods.length > 0) {
|
||||||
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);}`;
|
||||||
@@ -3006,38 +3017,38 @@
|
|||||||
const styleCode = styleExpr ? `vn.elm.style = ${styleExpr};` : "";
|
const styleCode = styleExpr ? `vn.elm.style = ${styleExpr};` : "";
|
||||||
createHook = `vnode.data.hook = {create(_, vn){${classCode}${styleCode}${eventsCode}}};`;
|
createHook = `vnode.data.hook = {create(_, vn){${classCode}${styleCode}${eventsCode}}};`;
|
||||||
}
|
}
|
||||||
ctx.addLine(`let w${widgetID} = ${templateID} in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[${templateID}]] : false;`);
|
ctx.addLine(`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(`c${ctx.parentNode}.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);`);
|
ctx.addLine(`c${ctx.parentNode}.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(`w${widgetID} && w${widgetID}.__owl__.renderPromise && !w${widgetID}.__owl__.vnode`);
|
ctx.addIf(`w${componentID} && w${componentID}.__owl__.renderPromise && !w${componentID}.__owl__.vnode`);
|
||||||
ctx.addIf(`utils.shallowEqual(props${widgetID}, w${widgetID}.__owl__.renderProps)`);
|
ctx.addIf(`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(`let W${widgetID} = context.widgets && context.widgets[widgetKey${widgetID}] || QWeb.widgets[widgetKey${widgetID}];`);
|
ctx.addLine(`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(`if (!W${widgetID}) {throw new Error('Cannot find the definition of widget "' + widgetKey${widgetID} + '"')}`);
|
ctx.addLine(`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(`context.__owl__.cmap[${templateID}] = w${widgetID}.__owl__.id;`);
|
ctx.addLine(`context.__owl__.cmap[${templateID}] = w${componentID}.__owl__.id;`);
|
||||||
// SLOTS
|
// SLOTS
|
||||||
if (node.childElementCount) {
|
if (node.childElementCount) {
|
||||||
const clone = node.cloneNode(true);
|
const clone = 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];
|
||||||
@@ -3054,21 +3065,23 @@
|
|||||||
qweb.slots[`${slotId}_default`] = slotFn.bind(qweb);
|
qweb.slots[`${slotId}_default`] = slotFn.bind(qweb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(`def${defID} = def${defID}.then(vnode=>{${createHook}let pvnode=h(vnode.sel, {key: ${templateID}, hook: {insert(vn) {let nvn=w${widgetID}._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;${refExpr}${transitionsInsertCode}},remove() {},destroy(vn) {${finalizeWidgetCode}}}});c${ctx.parentNode}[_${dummyID}_index]=pvnode;w${widgetID}.__owl__.pvnode = pvnode;});`);
|
ctx.addLine(`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}[_${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
|
||||||
ctx.addLine(`def${defID} = def${defID} || w${widgetID}._updateProps(props${widgetID}, extra.forceUpdate, ${patchQueueCode});`);
|
? `patchQueue${componentID}`
|
||||||
|
: "extra.patchQueue";
|
||||||
|
ctx.addLine(`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(`def${defID} = def${defID}.then(()=>{if (w${widgetID}.__owl__.isDestroyed) {return};${tattStyle ? `w${widgetID}.el.style=${tattStyle};` : ""}${updateClassCode}let pvnode=w${widgetID}.__owl__.pvnode;${keepAliveCode}c${ctx.parentNode}[_${dummyID}_index]=pvnode;});`);
|
ctx.addLine(`def${defID} = def${defID}.then(()=>{if (w${componentID}.__owl__.isDestroyed) {return};${tattStyle ? `w${componentID}.el.style=${tattStyle};` : ""}${updateClassCode}let pvnode=w${componentID}.__owl__.pvnode;${keepAliveCode}c${ctx.parentNode}[_${dummyID}_index]=pvnode;});`);
|
||||||
ctx.closeIf();
|
ctx.closeIf();
|
||||||
if (async) {
|
if (async) {
|
||||||
ctx.addLine(`def${defID}.then(w${widgetID}._applyPatchQueue.bind(w${widgetID}, patchQueue${widgetID}));`);
|
ctx.addLine(`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});`);
|
||||||
@@ -3261,7 +3274,6 @@
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let nextID$1 = 1;
|
|
||||||
function connect(Comp, mapStoreToProps, options = {}) {
|
function connect(Comp, mapStoreToProps, options = {}) {
|
||||||
let hashFunction = options.hashFunction || null;
|
let hashFunction = options.hashFunction || null;
|
||||||
const getStore = options.getStore || (env => env.store);
|
const getStore = options.getStore || (env => env.store);
|
||||||
@@ -3357,7 +3369,7 @@
|
|||||||
// this is necessary for Owl to be able to properly deduce templates.
|
// this is necessary for Owl to be able to properly deduce templates.
|
||||||
// Otherwise, all connected components would have the same name, and then
|
// Otherwise, all connected components would have the same name, and then
|
||||||
// each component after the first will necessarily have the same template.
|
// each component after the first will necessarily have the same template.
|
||||||
let name = `ConnectedComponent${nextID$1++}`;
|
let name = `Connected${Comp.name}`;
|
||||||
Object.defineProperty(Result, "name", { value: name });
|
Object.defineProperty(Result, "name", { value: name });
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@@ -3497,8 +3509,8 @@
|
|||||||
exports.utils = utils;
|
exports.utils = utils;
|
||||||
|
|
||||||
exports.__info__.version = '0.15.0';
|
exports.__info__.version = '0.15.0';
|
||||||
exports.__info__.date = '2019-06-18T13:03:02.358Z';
|
exports.__info__.date = '2019-06-21T19:47:14.131Z';
|
||||||
exports.__info__.hash = 'a7cd007';
|
exports.__info__.hash = '63a8fcd';
|
||||||
exports.__info__.url = 'https://github.com/odoo/owl';
|
exports.__info__.url = 'https://github.com/odoo/owl';
|
||||||
|
|
||||||
}(this.owl = this.owl || {}));
|
}(this.owl = this.owl || {}));
|
||||||
|
|||||||
+1
-1
@@ -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
@@ -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>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user