diff options
Diffstat (limited to 'addons/website/static/src/js/editor/snippets.editor.js')
| -rw-r--r-- | addons/website/static/src/js/editor/snippets.editor.js | 71 |
1 files changed, 45 insertions, 26 deletions
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; + } }, }); |
