[IMP] web: introduce LegacyComponent

This commit introduces LegacyComponent and removes patches on Component.
LegacyComponent is used instead of Component when the component
uses features from owl 1 like getting its `el` or `trigger` an event.

Part-of: odoo/odoo#85389
This commit is contained in:
Michael (mcm)
2022-03-01 09:57:39 +00:00
parent 138d881cd9
commit d6946775a2
4 changed files with 99 additions and 79 deletions
+1
View File
@@ -361,6 +361,7 @@ This module provides the core of the Odoo Web Client.
'web/static/lib/owl/owl.js',
'web/static/src/owl2_compatibility/*.js',
'web/static/src/legacy/js/component_extension.js',
'web/static/src/legacy/legacy_component.js',
'web/static/lib/jquery/jquery.js',
'web/static/lib/jquery.ui/jquery-ui.js',
'web/static/lib/jquery/jquery.browser.js',
@@ -1,45 +1,10 @@
(function () {
const { Component } = owl;
owl.Component.env = {};
/**
* Symbol used in ComponentWrapper to redirect Owl events to Odoo legacy
* events.
*/
odoo.widgetSymbol = Symbol('widget');
/**
* Add a new method to owl Components to ensure that no performed RPC is
* resolved/rejected when the component is destroyed.
*/
Component.prototype.rpc = function () {
return new Promise((resolve, reject) => {
return this.env.services.rpc(...arguments)
.then(result => {
if (owl.status(this) !== "destroyed") {
resolve(result);
}
})
.catch(reason => {
if (owl.status(this) !== "destroyed") {
reject(reason);
}
});
});
};
/**
* Patch Component.__trigger method to call a hook that adds a listener
* for the triggered event just before triggering it. This is useful if
* there are legacy widgets in the ancestors. In that case, there would be
* a widgetSymbol key in the environment, corresponding to the hook to call
* (see ComponentWrapper).
*/
const originalTrigger = owl.Component.prototype.__trigger;
Component.prototype.__trigger = function (evType, payload) {
if (this.env[odoo.widgetSymbol]) {
this.env[odoo.widgetSymbol](evType);
}
originalTrigger.call(this, evType, payload);
};
})();
@@ -0,0 +1,97 @@
/** @odoo-module **/
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* @deprecated
* This component SHOULD NOT be used!
* It's used in legacy when components should work like in owl 1.
*
* If you need to get the component's `el` then use `useRef`
* and if you need to send info to the component's parent then use props.
*
* e.g.
* // OWL 1
* class Component_OWL1 extends owl.Component {
* static template = owl.tags.xml`
* <button t-on-click="() => this.trigger('up')">click me</button>
* `;
* mounted() {
* this.el.style = "color: red";
* }
* }
*
* // OWL 2
* class Component_OWL2 extends owl.Component {
* static template = owl.xml`
* <button t-ref="btn" t-on-click="() => props.up()">click me</button>
* `;
* setup() {
* this.btnRef = useRef("btn");
* owl.onMounted(() => {
* this.btnRef.el.style = "color: red";
* });
* }
* }
*/
export class LegacyComponent extends owl.Component {
get el() {
const bdom = this.__owl__.bdom;
if (!bdom) {
return null;
}
if (hasOwnProperty.call(bdom, "component")) {
return bdom.component.el;
} else {
return bdom.firstNode();
}
}
/**
* Add a new method to owl Components to ensure that no performed RPC is
* resolved/rejected when the component is destroyed.
*/
rpc() {
return new Promise((resolve, reject) => {
return this.env.services
.rpc(...arguments)
.then((result) => {
if (owl.status(this) !== "destroyed") {
resolve(result);
}
})
.catch((reason) => {
if (owl.status(this) !== "destroyed") {
reject(reason);
}
});
});
}
/**
* Emit a custom event of type 'eventType' with the given 'payload' on the
* component's el, if it exists. However, note that the event will only bubble
* up to the parent DOM nodes. Thus, it must be called between mounted() and
* willUnmount().
*/
trigger(eventType, payload) {
this.__trigger(eventType, payload);
}
/**
* Private trigger method, allows to choose the component which triggered
* the event in the first place
*/
__trigger(eventType, payload) {
if (this.env[odoo.widgetSymbol]) {
this.env[odoo.widgetSymbol](eventType);
}
if (this.el) {
const ev = new CustomEvent(eventType, {
bubbles: true,
cancelable: true,
detail: payload,
});
this.el.dispatchEvent(ev);
}
}
}
@@ -1,43 +0,0 @@
(function () {
const hasOwnProperty = Object.prototype.hasOwnProperty;
owl.Component = class extends owl.Component {
get el() {
const bdom = this.__owl__.bdom;
if (!bdom) {
return null;
}
if (hasOwnProperty.call(bdom, "component")) {
return bdom.component.el;
} else {
return bdom.firstNode();
}
}
/**
* Emit a custom event of type 'eventType' with the given 'payload' on the
* component's el, if it exists. However, note that the event will only bubble
* up to the parent DOM nodes. Thus, it must be called between mounted() and
* willUnmount().
*/
trigger(eventType, payload) {
this.__trigger(eventType, payload);
}
/**
* Private trigger method, allows to choose the component which triggered
* the event in the first place
*/
__trigger(eventType, payload) {
if (this.el) {
const ev = new CustomEvent(eventType, {
bubbles: true,
cancelable: true,
detail: payload,
});
this.el.dispatchEvent(ev);
}
}
};
owl.Component.env = {};
})();