[IMP] web: Model: small simplifications

Small refactor of some aspects of the main model.js class to make it
more consistent and extensible.
This commit is contained in:
Julien Mougenot
2020-08-04 12:44:18 +00:00
parent 918ccf5b0e
commit f8ab35f9e1
+60 -53
View File
@@ -20,7 +20,7 @@ odoo.define("web/static/src/js/model.js", function (require) {
constructor(config) {
this.config = config;
this.env = this.config.env;
this._shouldLoad = true;
this.shouldLoad = true;
this.state = {};
}
@@ -30,12 +30,23 @@ odoo.define("web/static/src/js/model.js", function (require) {
/**
* Used by the parent model to initiate a load action. The actual
* loading of the extension is determined by the "_shouldLoad" property.
* loading of the extension is determined by the "shouldLoad" property.
* @param {Object} params
*/
async callLoad() {
if (this._shouldLoad) {
this._shouldLoad = false;
await this.load();
async callLoad(params) {
if (this.shouldLoad) {
this.shouldLoad = false;
await this.load(params);
}
}
/**
* @param {string} method
* @param {...any} args
*/
dispatch(method, ...args) {
if (method in this) {
this[method](...args);
}
}
@@ -65,8 +76,8 @@ odoo.define("web/static/src/js/model.js", function (require) {
* @param {Object} [state]
*/
importState(state) {
this._shouldLoad = !state;
if (this._shouldLoad) {
this.shouldLoad = !state;
if (this.shouldLoad) {
this.prepareState();
} else {
Object.assign(this.state, state);
@@ -76,9 +87,10 @@ odoo.define("web/static/src/js/model.js", function (require) {
/**
* Called and awaited on initial model load.
* @abstract
* @param {Object} params
* @returns {Promise}
*/
async load() {
async load(/* params */) {
/* ... */
}
@@ -90,15 +102,6 @@ odoo.define("web/static/src/js/model.js", function (require) {
prepareState() {
/* ... */
}
/**
* Called and awaited after an action dispatch.
* @abstract
* @returns {Promise}
*/
async reloadAfterDispatch() {
/* ... */
}
}
/**
* The layer of an extension indicates with which other extensions this one
@@ -285,40 +288,32 @@ odoo.define("web/static/src/js/model.js", function (require) {
* extension. This method must be overridden if multiple extensions
* return a value with a common method (and dispatchAll does not
* suffice). After the dispatch of the action, all models are partially
* reloaded (@see ModelExtension.reloadAfterDispatch()) and components
* are notified afterwards.
* reloaded and components are notified afterwards.
* @param {string} method
* @param {...any} args
*/
dispatch(method, ...args) {
const isInitialDispatch = !this.dispatching;
this.dispatching = true;
for (const extension of this.extensions.flat()) {
if (method in extension) {
extension[method](...args);
extension.dispatch(method, ...args);
}
if (!isInitialDispatch) {
return;
}
this.dispatching = false;
let rev = this.rev;
// Calls 'after dispatch' hooks
// Purpose: fetch updated data from the server. This is considered
// a loading action and is thus performed by groups instead of
// loading all extensions at once.
this._loadExtensions({ isInitialLoad: false }).then(() => {
// Notifies subscribed components
// Purpose: re-render components bound by 'useModel'
if (rev === this.rev) {
this._notifyComponents();
}
}
if (isInitialDispatch) {
this.dispatching = false;
(async () => {
// Calls 'after dispatch' hooks
// Purpose: fetch updated data from the server. This is
// considered a loading action and is thus performed by groups
// instead of loading all extensions at once.
for (let layer = 0; layer < this.extensions.length; layer++) {
const afterDispatchPromises = [];
for (const extension of this.extensions[layer]) {
afterDispatchPromises.push(extension.reloadAfterDispatch());
}
await Promise.all(afterDispatchPromises);
}
// Notifies subscribed components
// Purpose: re-render components bound by 'useModel'
let rev = this.rev;
await Promise.resolve();
if (rev === this.rev) {
this._notifyComponents();
}
})();
}
});
}
/**
@@ -378,13 +373,7 @@ odoo.define("web/static/src/js/model.js", function (require) {
* @returns {Promise}
*/
async load() {
for (let layer = 0; layer < this.extensions.length; layer++) {
const layerPromises = [];
for (const extension of this.extensions[layer]) {
layerPromises.push(extension.callLoad());
}
await Promise.all(layerPromises);
}
await this._loadExtensions({ isInitialLoad: true });
}
//---------------------------------------------------------------------
@@ -416,6 +405,24 @@ odoo.define("web/static/src/js/model.js", function (require) {
return results;
}
/**
* Private handler to loop over all extension layers sequencially and
* wait for a given callback to be completed on all extensions of a
* same layer.
* @private
* @param {Object} params
* @param {boolean} params.isInitialLoad whether this call comes
* from the initial load.
* @returns {Promise}
*/
async _loadExtensions(params) {
for (let layer = 0; layer < this.extensions.length; layer++) {
await Promise.all(this.extensions[layer].map(
(extension) => extension.callLoad(params)
));
}
}
/**
* @see Context.__notifyComponents() in owl.js for explanation
* @private