Skip to content
Snippets Groups Projects
Commit 3431751c authored by qsm-odoo's avatar qsm-odoo
Browse files

[FIX] web: load editor assets in the right order

Before this commit, 50% of the time, the design of the editor in the
website appeared broken. This was because the two editor assets (the
web_editor one and the website one) are lazy loaded... but their load
order was not deterministic. The bug was introduced with the new editor
merged with https://github.com/odoo/odoo/pull/29775

.

In fact the lazy loading system introduced by the `loadLibs` function
of the ajax module was designed to allow sequential and/or parallel
loading of JS files... but not of assets bundles (for CSS it is always
forced to parallel because only the DOM order matters anyway). This
commit shares the code to allow sequential and/or parallel loading of
assets bundles. It also forces the asset bundle resources to be loaded
after css and js resources.

closes odoo/odoo#34544

Signed-off-by: default avatarQuentin Smetz (qsm) <qsm@odoo.com>
parent fc53b110
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@ odoo.define('web.ajax', function (require) {
"use strict";
var config = require('web.config');
var concurrency = require('web.concurrency');
var core = require('web.core');
var utils = require('web.utils');
var time = require('web.time');
......@@ -10,6 +11,10 @@ var contentdisposition = require('web.contentdisposition');
var _t = core._t;
// Create the final object containing all the functions first to allow monkey
// patching them correctly if ever needed.
var ajax = {};
function genericJsonRpc (fct_name, params, settings, fct) {
var shadow = settings.shadow || false;
delete settings.shadow;
......@@ -486,46 +491,81 @@ var loadAsset = (function () {
})();
/**
* Loads the given js and css libraries. Note that the ajax loadJS and loadCSS methods
* don't do anything if the given file is already loaded.
* Loads the given js/css libraries and asset bundles. Note that no library or
* asset will be loaded if it was already done before.
*
* @param {Object} libs
* @Param {Array | Array<Array>} [libs.jsLibs=[]] The list of JS files that we want to
* load. The list may contain strings (the files to load), or lists of strings. The
* first level is loaded sequentially, and files listed in inner lists are loaded in
* parallel.
* @param {Array<string>} [libs.cssLibs=[]] A list of css files, to be loaded in
* parallel
* @param {Array<string>} [libs.assetLibs=[]] A list of xmlId. The loaded template
* contains the script and link to be loaded
* @param {Array<string|string[]>} [libs.assetLibs=[]]
* The list of assets to load. Each list item may be a string (the xmlID
* of the asset to load) or a list of strings. The first level is loaded
* sequentially (so use this if the order matters) while the assets in
* inner lists are loaded in parallel (use this for efficiency but only
* if the order does not matter, should rarely be the case for assets).
* @param {string[]} [libs.cssLibs=[]]
* The list of CSS files to load. They will all be loaded in parallel but
* put in the DOM in the given order (only the order in the DOM is used
* to determine priority of CSS rules, not loaded time).
* @param {Array<string|string[]>} [libs.jsLibs=[]]
* The list of JS files to load. Each list item may be a string (the URL
* of the file to load) or a list of strings. The first level is loaded
* sequentially (so use this if the order matters) while the files in inner
* lists are loaded in parallel (use this for efficiency but only
* if the order does not matter).
* @param {string[]} [libs.cssContents=[]]
* List of inline styles to add after loading the CSS files.
* @param {string[]} [libs.jsContents=[]]
* List of inline scripts to add after loading the JS files.
*
* @returns {Deferred}
*/
function loadLibs (libs) {
var defs = [];
_.each(libs.jsLibs || [], function (urls) {
defs.push($.when.apply($, defs).then(function () {
if (typeof(urls) === 'string') {
return ajax.loadJS(urls);
} else {
return $.when.apply($, _.map(urls, function (url) {
return ajax.loadJS(url);
function loadLibs(libs) {
var mutex = new concurrency.Mutex();
mutex.exec(function () {
var defs = [];
var cssLibs = [libs.cssLibs || []]; // Force loading in parallel
defs.push(_loadArray(cssLibs, ajax.loadCSS).then(function () {
if (libs.cssContents && libs.cssContents.length) {
$('head').append($('<style/>', {
html: libs.cssContents.join('\n'),
}));
}
}));
});
_.each(libs.cssLibs || [], function (url) {
defs.push(ajax.loadCSS(url));
});
_.each(libs.assetLibs || [], function (xmlId) {
defs.push(loadAsset(xmlId).then(function (asset) {
return loadLibs(asset);
defs.push(_loadArray(libs.jsLibs || [], ajax.loadJS).then(function () {
if (libs.jsContents && libs.jsContents.length) {
$('head').append($('<script/>', {
html: libs.jsContents.join('\n'),
}));
}
}));
return $.when.apply($, defs);
});
mutex.exec(function () {
return _loadArray(libs.assetLibs || [], function (xmlID) {
return ajax.loadAsset(xmlID).then(function (asset) {
return ajax.loadLibs(asset);
});
});
});
return $.when.apply($, defs);
function _loadArray(array, loadCallback) {
var _mutex = new concurrency.Mutex();
_.each(array, function (urlData) {
_mutex.exec(function () {
if (typeof urlData === 'string') {
return loadCallback(urlData);
}
return $.when.apply($, _.map(urlData, function (url) {
return loadCallback(url);
}));
});
});
return _mutex.getUnlockedDef();
}
return mutex.getUnlockedDef();
}
var ajax = {
_.extend(ajax, {
jsonRpc: jsonRpc,
rpc: rpc,
loadCSS: loadCSS,
......@@ -535,7 +575,7 @@ var ajax = {
loadLibs: loadLibs,
get_file: get_file,
post: post,
};
});
return ajax;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment