summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorBenoit Socias <bso@odoo.com>2021-01-28 13:17:22 +0000
committerqsm-odoo <qsm@odoo.com>2021-02-15 15:49:15 +0000
commitf2fa17540e130b5cf3f70570a3a97495cfbb7499 (patch)
tree0233ff281b396df6bbccaf62bef0d6df35331f1a /addons
parent768bcf58e8dc215b96b11bafa632c07dc683e297 (diff)
[FIX] website, web_editor: ensure the loader appears on click options
Before this commit the loader did not always get displayed when switching to the options tab. After this commit the loader always gets displayed ASAP when switching to the options tab until the tab is ready and displayed. task-2439295 https://github.com/odoo/odoo/pull/65223 Co-authored-by: Samuel Degueldre <sad@odoo.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.editor.js15
-rw-r--r--addons/website/static/src/js/editor/snippets.editor.js71
2 files changed, 56 insertions, 30 deletions
diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js
index cf194d45082..3997e6df15c 100644
--- a/addons/web_editor/static/src/js/editor/snippets.editor.js
+++ b/addons/web_editor/static/src/js/editor/snippets.editor.js
@@ -2216,22 +2216,29 @@ var SnippetsMenu = Widget.extend({
async _execWithLoadingEffect(action, contentLoading = true, delay = 500) {
const mutexExecResult = this._mutex.exec(action);
if (!this.loadingTimers[contentLoading]) {
- this.loadingTimers[contentLoading] = setTimeout(() => {
+ const addLoader = () => {
this.loadingElements[contentLoading] = this._createLoadingElement();
if (contentLoading) {
this.$snippetEditorArea.append(this.loadingElements[contentLoading]);
} else {
this.el.appendChild(this.loadingElements[contentLoading]);
}
- }, delay);
+ };
+ if (delay) {
+ this.loadingTimers[contentLoading] = setTimeout(addLoader, delay);
+ } else {
+ addLoader();
+ }
this._mutex.getUnlockedDef().then(() => {
// Note: we remove the loading element at the end of the
// execution queue *even if subsequent actions are content
// related or not*. This is a limitation of the loading feature,
// the goal is still to limit the number of elements in that
// queue anyway.
- clearTimeout(this.loadingTimers[contentLoading]);
- this.loadingTimers[contentLoading] = undefined;
+ if (delay) {
+ clearTimeout(this.loadingTimers[contentLoading]);
+ this.loadingTimers[contentLoading] = undefined;
+ }
if (this.loadingElements[contentLoading]) {
this.loadingElements[contentLoading].remove();
diff --git a/addons/website/static/src/js/editor/snippets.editor.js b/addons/website/static/src/js/editor/snippets.editor.js
index c5d64e11d54..77229934eac 100644
--- a/addons/website/static/src/js/editor/snippets.editor.js
+++ b/addons/website/static/src/js/editor/snippets.editor.js
@@ -154,37 +154,56 @@ weSnippetEditor.Class.include({
*/
async _onThemeTabClick(ev) {
// Note: nothing async here but start the loading effect asap
- this._execWithLoadingEffect(async () => new Promise(resolve => setTimeout(() => resolve(), 0)), false, 0);
+ let releaseLoader;
+ try {
+ const promise = new Promise(resolve => releaseLoader = resolve);
+ this._execWithLoadingEffect(() => promise, false, 0);
+ // loader is added to the DOM synchronously
+ await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
+ // ensure loader is rendered: first call asks for the (already done) DOM update,
+ // second call happens only after rendering the first "updates"
- if (!this.topFakeOptionEl) {
- let el;
- for (const [elementName, title] of this.optionsTabStructure) {
- const newEl = document.createElement(elementName);
- newEl.dataset.name = title;
- if (el) {
- el.appendChild(newEl);
- } else {
- this.topFakeOptionEl = newEl;
+ if (!this.topFakeOptionEl) {
+ let el;
+ for (const [elementName, title] of this.optionsTabStructure) {
+ const newEl = document.createElement(elementName);
+ newEl.dataset.name = title;
+ if (el) {
+ el.appendChild(newEl);
+ } else {
+ this.topFakeOptionEl = newEl;
+ }
+ el = newEl;
}
- el = newEl;
+ this.bottomFakeOptionEl = el;
+ this.el.appendChild(this.topFakeOptionEl);
}
- this.bottomFakeOptionEl = el;
- this.el.appendChild(this.topFakeOptionEl);
- }
- // Need all of this in that order so that:
- // - the element is visible and can be enabled and the onFocus method is
- // called each time.
- // - the element is hidden afterwards so it does not take space in the
- // DOM, same as the overlay which may make a scrollbar appear.
- this.topFakeOptionEl.classList.remove('d-none');
- const editor = await this._activateSnippet($(this.bottomFakeOptionEl));
- this.topFakeOptionEl.classList.add('d-none');
- editor.toggleOverlay(false);
+ // Need all of this in that order so that:
+ // - the element is visible and can be enabled and the onFocus method is
+ // called each time.
+ // - the element is hidden afterwards so it does not take space in the
+ // DOM, same as the overlay which may make a scrollbar appear.
+ this.topFakeOptionEl.classList.remove('d-none');
+ const editorPromise = this._activateSnippet($(this.bottomFakeOptionEl));
+ releaseLoader(); // because _activateSnippet uses the same mutex as the loader
+ releaseLoader = undefined;
+ const editor = await editorPromise;
+ this.topFakeOptionEl.classList.add('d-none');
+ editor.toggleOverlay(false);
- this._updateLeftPanelContent({
- tab: this.tabs.THEME,
- });
+ this._updateLeftPanelContent({
+ tab: this.tabs.THEME,
+ });
+ } catch (e) {
+ // Normally the loading effect is removed in case of error during the action but here
+ // the actual activity is happening outside of the action, the effect must therefore
+ // be cleared in case of error as well
+ if (releaseLoader) {
+ releaseLoader();
+ }
+ throw e;
+ }
},
});