From e126cd3bb2b20bc993d2472eee5fe16cc7a74ea9 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Wed, 16 Sep 2020 11:51:38 +0000 Subject: [IMP] web_editor, website: improve editor loading effects - Share the code for tab switching loading and slow option loading. - Now add a loading effect over the content when the content is changed and a loading effect over the editor panel when the editor panel is being changed Part of https://github.com/odoo/odoo/pull/55614 task-2213114 closes odoo/odoo#55614 Signed-off-by: Quentin Smetz (qsm) --- .../static/src/js/editor/snippets.editor.js | 105 +++++++++------------ .../static/src/scss/wysiwyg_snippets.scss | 14 +++ 2 files changed, 61 insertions(+), 58 deletions(-) (limited to 'addons/web_editor') 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 d05c2d876b2..4254afe270f 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -897,6 +897,9 @@ var SnippetsMenu = Widget.extend({ '.modal .close', '.o_we_crop_widget', ].join(', '); + + this.loadingTimers = {}; + this.loadingElements = {}; }, /** * @override @@ -912,7 +915,7 @@ var SnippetsMenu = Widget.extend({ /** * @override */ - start: function () { + async start() { var defs = [this._super.apply(this, arguments)]; this.ownerDocument = this.$el[0].ownerDocument; this.$document = $(this.ownerDocument); @@ -931,14 +934,13 @@ var SnippetsMenu = Widget.extend({ })[0] ); - this._addTabLoading(this.tabs.BLOCKS); - this.options.getScrollOptions = this._getScrollOptions.bind(this); // Fetch snippet templates and compute it - defs.push(this._loadSnippetsTemplates().then(() => { - return this._updateInvisibleDOM(); - })); + defs.push((async () => { + await this._loadSnippetsTemplates(); + await this._updateInvisibleDOM(); + })()); // Prepare snippets editor environment this.$snippetEditorArea = $('
', { @@ -1279,21 +1281,6 @@ var SnippetsMenu = Widget.extend({ } }); }, - /** - * @private - * @param {this.tabs.VALUE} [tab='OPTIONS'] - the tab to select - */ - _addTabLoading: function (tab) { - const loadingEl = document.createElement('div'); - loadingEl.classList.add('o_we_ui_loading', 'text-center', 'pt-5'); - const loadingIconEl = document.createElement('i'); - loadingIconEl.classList.add('fa', 'fa-circle-o-notch', 'fa-spin', 'fa-3x'); - loadingEl.appendChild(loadingIconEl); - this._updateLeftPanelContent({ - content: loadingEl, - tab: tab || this.tabs.OPTIONS, - }); - }, /** * Adds an entry for every invisible snippet in the left panel box. * The entries will contains an 'Edit' button to activate their snippet. @@ -1320,7 +1307,7 @@ var SnippetsMenu = Widget.extend({ this.invisibleDOMMap.set($invisEntry[0], el); }); return Promise.all(proms); - }); + }, false); }, /** * Disable the overlay editor of the active snippet and activate the new one @@ -1345,7 +1332,10 @@ var SnippetsMenu = Widget.extend({ if ($snippet && !$snippet.is(':visible')) { return; } - return this._execWithLoadingEffect(() => { + const exec = previewMode + ? action => this._mutex.exec(action) + : action => this._execWithLoadingEffect(action, false); + return exec(() => { return new Promise(resolve => { // Take the first parent of the provided DOM (or itself) which // should have an associated snippet editor and create + enable it. @@ -1402,7 +1392,7 @@ var SnippetsMenu = Widget.extend({ await this._destroyEditors(); const html = await this.loadSnippets(invalidateCache); await this._computeSnippetTemplates(html); - }); + }, false); }, /** * @private @@ -2022,46 +2012,27 @@ var SnippetsMenu = Widget.extend({ }, /** * @private + * @returns {HTMLElement} */ - _addLoadingEffect() { - if (this.currentLoader) { - return; - } + _createLoadingElement() { const loaderContainer = document.createElement('div'); const loader = document.createElement('i'); const loaderContainerClassList = [ + 'o_we_ui_loading', 'd-flex', - 'h-100', - 'w-100', - 'bg-black-50', - 'position-absolute', + 'justify-content-center', + 'align-items-center', ]; const loaderClassList = [ 'fa', 'fa-circle-o-notch', 'fa-spin', 'fa-4x', - 'w-100', - 'text-white', - 'text-center', - 'position-absolute', - 'align-self-center', ]; loaderContainer.classList.add(...loaderContainerClassList); loader.classList.add(...loaderClassList); loaderContainer.appendChild(loader); - this.el.appendChild(loaderContainer); - this.currentLoader = loaderContainer; - }, - /** - * @private - */ - _removeLoadingEffect() { - if (!this.currentLoader) { - return; - } - this.currentLoader.remove(); - this.currentLoader = undefined; + return loaderContainer; }, /** * Adds the action to the mutex queue and sets a loading effect over the @@ -2070,16 +2041,34 @@ var SnippetsMenu = Widget.extend({ * * @private * @param {function} action + * @param {boolean} [contentLoading=true] + * @param {number} [delay=500] * @returns {Promise} */ - async _execWithLoadingEffect(action) { + async _execWithLoadingEffect(action, contentLoading = true, delay = 500) { const mutexExecResult = this._mutex.exec(action); - if (!this.loadingTimer) { - this.loadingTimer = setTimeout(() => this._addLoadingEffect(), 500); + if (!this.loadingTimers[contentLoading]) { + this.loadingTimers[contentLoading] = setTimeout(() => { + this.loadingElements[contentLoading] = this._createLoadingElement(); + if (contentLoading) { + this.$snippetEditorArea.append(this.loadingElements[contentLoading]); + } else { + this.el.appendChild(this.loadingElements[contentLoading]); + } + }, delay); this._mutex.getUnlockedDef().then(() => { - clearTimeout(this.loadingTimer); - this.loadingTimer = undefined; - this._removeLoadingEffect(); + // 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 (this.loadingElements[contentLoading]) { + this.loadingElements[contentLoading].remove(); + this.loadingElements[contentLoading] = null; + } }); } return mutexExecResult; @@ -2244,7 +2233,7 @@ var SnippetsMenu = Widget.extend({ const isVisible = await this._execWithLoadingEffect(async () => { const editor = await this._createSnippetEditor($snippet); return editor.toggleTargetVisibility(); - }); + }, true); $(ev.currentTarget).find('.fa') .toggleClass('fa-eye', isVisible) .toggleClass('fa-eye-slash', !isVisible); @@ -2377,7 +2366,7 @@ var SnippetsMenu = Widget.extend({ }; } this.trigger_up('request_save', data); - }); + }, true); }, /** * @private @@ -2386,7 +2375,7 @@ var SnippetsMenu = Widget.extend({ * @param {function} ev.data.exec */ _onSnippetEditionRequest: function (ev) { - this._execWithLoadingEffect(ev.data.exec); + this._execWithLoadingEffect(ev.data.exec, true); }, /** * @private diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss index 404646b0584..f01bcb710a0 100644 --- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss +++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss @@ -1731,3 +1731,17 @@ we-select.o_we_shape_menu { } } } + +.o_we_ui_loading { + @include o-position-absolute(0, 0, 0, 0); + z-index: $o-we-zindex; + background-color: $o-we-sidebar-content-backdrop-bg; + color: $o-we-fg-lighter; +} +#oe_manipulators > .o_we_ui_loading { + // hacky solution to be over the content, ideally that loader should only + // be over the content being reloaded (with a covering similar to the editor + // overlay covering). + position: fixed; + left: $o-we-sidebar-width; +} -- cgit v1.2.3