[REF] web, *: remove patchMixin + imp utils.patch

* hr, hr_holidays, im_livechat, mail, snailmail, website,
  website_livechat

This commit removes `patchMixin` and improve `utils.patch`.
`utils.patch` now supports native classes and has a new parameter
used to patch class members.

`utils.patch` is now used everywhere `patchMixin` was and it must
be used to patch classes.

closes odoo/odoo#65967

Related: odoo/enterprise#16278
Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
Co-authored-by: ged-odoo <ged@odoo.com>
This commit is contained in:
Michael Mattiello (mcm)
2021-02-26 10:39:21 +00:00
co-authored by ged-odoo
parent 907c66cb31
commit 7086488064
44 changed files with 1648 additions and 1440 deletions
+163
View File
@@ -607,6 +607,14 @@ to use inheritance, mixins.
For these reasons, Odoo decided to use its own class system, inspired by John
Resig. The base Class is located in *web.Class*, in the file *class.js*.
.. note ::
Note that the custom class system should be avoided for creating new code. It
will be deprecated at some point, and then removed. New classes should use
the standard ES6 class system.
Creating a subclass
-------------------
@@ -2650,3 +2658,158 @@ For more information, look into the `control_panel_renderer.js <https://github.c
https://api.jquery.com/delegate/
.. _datepicker: https://github.com/Eonasdan/bootstrap-datetimepicker
Patching code
=============
Sometimes we need to modify an object or a class in place. To achieve that, Odoo
provides the utility function ``patch``. It is mostly useful to override/update
the behaviour of some other component/piece of code that one does not control.
Obviously, it is not the primary tool of working with Odoo. It should be used
with care.
Patching a simple object
------------------------
Here is a simple example of how an object can be patched:
.. code-block:: javascript
const { patch } = require("web.utils");
const object = {
field: "a field",
fn() {
// do something
},
};
patch(object, "patch name", {
fn() {
// do things
},
});
When patching functions, we usually want to be able to access the ``parent``
function. Since we are working with patch objects, not ES6 classes, we cannot
use the native ``super`` keyword. So, Odoo provides a special method to simulate
this behaviour: ``this._super``:
.. code-block:: javascript
patch(object, "_super patch", {
fn() {
this._super(...arguments);
// do other things
},
});
.. warning::
``this._super`` is reassigned after each patched function is called.
This means that if you use an asynchronous function in the patch then you
cannot call ``this._super`` after an ``await``, because it may or may not be
the function that you expect. The correct way to do that is to keep a reference
to the initial ``_super` method:
.. code-block:: javascript
patch(object, "async _super patch", {
async myAsyncFn() {
const _super = this._super;
await Promise.resolve();
await _super(...arguments);
// await this._super(...arguments); // this._super is undefined.
},
});
Getters and setters are supported too!
.. code-block:: javascript
patch(object, "getter/setter patch", {
get number() {
return this._super() / 2;
},
set number(value) {
this._super(value * 2);
},
});
Native JS class
---------------
The ``patch`` function is similar to ``OdooClass.include``, but it is designed
to work with anything: object, Odoo class, ES6 class.
However, since ES6 classes work with the javascript prototypal inheritance, when
one wishes to patch a standard method from a class, then we actually need to patch
the ``prototype``:
.. code-block:: javascript
class MyClass {
static myStaticFn() {...}
myPrototypeFn() {...}
}
// this will patch static properties!!!
patch(MyClass, "static patch", {
myStaticFn() {...},
});
// this is probably the usual case: patching a class method
patch(MyClass.prototype, "prototype patch", {
myPrototypeFn() {...},
});
Also, Javascript handle the constructor in a special native way which makes it
impossible to be patched. The only workaround is to call a method in the original
constructor and patch that method instead:
.. code-block:: javascript
class MyClass {
constructor() {
this.setup();
}
setup() {
this.number = 1;
}
}
patch(MyClass.prototype, "constructor", {
setup() {
this._super(...arguments);
this.doubleNumber = this.number * 2;
},
});
Note that for this reason, Owl component have all the ``setup`` method builtin.
Therefore, patching a component constructor is always possible:
.. code-block:: javascript
patch(MyComponent.prototype, "my patch", {
setup() {
useMyHook();
},
});
Removing a patch
-----------------
We can also remove the patch by calling the ``unpatch`` function. This is really
only useful for tests.
.. code-block:: javascript
unpatch(object, "patch name");