From 09b720eff1a7378351e04661d3df1c3be31ee965 Mon Sep 17 00:00:00 2001 From: "Guillaume (gdi)" Date: Wed, 2 Mar 2022 12:35:27 +0000 Subject: [PATCH] [IMP] web_editor, website: initialize the editor's tooltips The editor offers bootstrap tooltips, but these were not all initialized and therefore appeared as standard HTML tooltips. This commit fixes that by initializing all the tooltips so that they all have the same style. Details: - The bootstrap tooltips are now available in translate mode. - With bootstrap 5, only one bootstrap component can be initialized on a HTML element. This is why the tooltips are now initialized on the first child when there is another bootstrap component. - Some tests have been adapted. task-2777738 closes odoo/odoo#85666 Signed-off-by: Romain Derie (rde) --- .../static/src/js/editor/snippets.editor.js | 79 +++++++++++++------ .../src/js/wysiwyg/widgets/color_palette.js | 2 - addons/web_editor/static/src/xml/editor.xml | 30 +++---- addons/web_editor/static/src/xml/wysiwyg.xml | 18 ++--- .../website/static/tests/tours/link_tools.js | 2 +- .../static/tests/tours/website_form_editor.js | 8 +- addons/website/views/snippets/snippets.xml | 8 +- .../static/tests/tours/newsletter_block.js | 4 +- 8 files changed, 84 insertions(+), 67 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 0ce3b2b266e..a1dc75e0981 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -1811,6 +1811,33 @@ var SnippetsMenu = Widget.extend({ this._checkEditorToolbarVisibilityCallback = this._checkEditorToolbarVisibility.bind(this); $(this.options.wysiwyg.odooEditor.document.body).on('click', this._checkEditorToolbarVisibilityCallback); + // Add tooltips on we-title elements whose text overflows and on all + // elements with available tooltip text. Note that the tooltips of the + // blocks should not be taken into account here because they have + // tooltips with a particular behavior (see _showSnippetTooltip). + this.tooltips = new Tooltip(this.el, { + selector: 'we-title, [title]:not(.oe_snippet)', + placement: 'bottom', + delay: 100, + // Ensure the tooltips have a good position when in iframe. + container: this.el, + // Prevent horizontal scroll when tooltip is displayed. + boundary: this.el.ownerDocument.body, + title: function () { + const el = this; + if (el.tagName !== 'WE-TITLE') { + return el.title; + } + // On Firefox, el.scrollWidth is equal to el.clientWidth when + // overflow: hidden, so we need to update the style before to + // get the right values. + el.style.setProperty('overflow', 'scroll', 'important'); + const tipContent = el.scrollWidth > el.clientWidth ? el.innerHTML : ''; + el.style.removeProperty('overflow'); + return tipContent; + }, + }); + if (this.options.enableTranslation) { // Load the sidebar with the style tab only. await this._loadSnippetsTemplates(); @@ -1948,30 +1975,6 @@ var SnippetsMenu = Widget.extend({ const $autoFocusEls = $('.o_we_snippet_autofocus'); this._activateSnippet($autoFocusEls.length ? $autoFocusEls.first() : false); - // Add tooltips on we-title elements whose text overflows - new Tooltip(this.el, { - selector: 'we-title', - placement: 'bottom', - delay: 100, - // Ensure the tooltips have a good position when in iframe. - container: this.el, - // Prevent horizontal scroll when tooltip is displayed. - boundary: this.el.ownerDocument.body, - title: function () { - const el = this; - if (el.tagName !== 'WE-TITLE') { - return el.title; - } - // On Firefox, el.scrollWidth is equal to el.clientWidth when - // overflow: hidden, so we need to update the style before to - // get the right values. - el.style.setProperty('overflow', 'scroll', 'important'); - const tipContent = el.scrollWidth > el.clientWidth ? el.innerHTML : ''; - el.style.removeProperty('overflow'); - return tipContent; - }, - }); - return Promise.all(defs).then(() => { const $undoButton = this.$('.o_we_external_history_buttons button[data-action="undo"]'); const $redoButton = this.$('.o_we_external_history_buttons button[data-action="redo"]'); @@ -2019,6 +2022,8 @@ var SnippetsMenu = Widget.extend({ core.bus.off('deactivate_snippet', this, this._onDeactivateSnippet); $(document.body).off('click', this._checkEditorToolbarVisibilityCallback); this.el.ownerDocument.body.classList.remove('editor_has_snippets'); + // Dispose BS tooltips. + this.tooltips.dispose(); }, //-------------------------------------------------------------------------- @@ -3310,6 +3315,7 @@ var SnippetsMenu = Widget.extend({ * @param {this.tabs.VALUE} [tab='blocks'] - the tab to select */ _updateRightPanelContent: function ({content, tab, ...options}) { + this._hideActiveTooltip(); this._closeWidgets(); this._currentTab = tab || this.tabs.BLOCKS; @@ -3433,6 +3439,28 @@ var SnippetsMenu = Widget.extend({ forceEmptyTab: true, }); }, + /** + * Hides the active tooltip. + * + * @private + */ + _hideActiveTooltip() { + // The BS documentation says that "Tooltips that use delegation (which + // are created using the selector option) cannot be individually + // destroyed on descendant trigger elements". So we remove the active + // tooltips manually. + // For instance, without this, clicking on "Hide in Desktop" on a + // snippet will leave the tooltip "forever" visible even if the "Hide in + // Desktop" button is gone. + const tooltipClass = 'aria-describedby'; + const tooltippedEl = this.el.querySelector(`[${tooltipClass}^="tooltip"]`); + if (tooltippedEl) { + const tooltipEl = document.getElementById(tooltippedEl.getAttribute(tooltipClass)); + if (tooltipEl) { + Tooltip.getInstance(tooltipEl).hide(); + } + } + }, //-------------------------------------------------------------------------- // Handlers @@ -4200,6 +4228,9 @@ var SnippetsMenu = Widget.extend({ } this._buttonAction = true; let removeLoadingEffect; + // Remove the tooltip now, because the button will be disabled and so, + // the tooltip will not be removable (see BS doc). + this._hideActiveTooltip(); if (addLoadingEffect) { removeLoadingEffect = dom.addButtonLoadingEffect(button); } diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js b/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js index 9787fdf2909..40a5ccb1efa 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js @@ -782,7 +782,6 @@ const ColorPaletteWidget = Widget.extend({ * @param {Event} ev */ _onColorButtonEnter: function (ev) { - ev.stopPropagation(); this.trigger_up('color_hover', Object.assign(this.getSelectedColors(), this._getButtonInfo(ev.currentTarget))); }, /** @@ -792,7 +791,6 @@ const ColorPaletteWidget = Widget.extend({ * @param {Event} ev */ _onColorButtonLeave: function (ev) { - ev.stopPropagation(); this.trigger_up('color_leave', Object.assign(this.getSelectedColors(), { target: ev.target, })); diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml index afda59e56d8..8fd9e9c54d2 100644 --- a/addons/web_editor/static/src/xml/editor.xml +++ b/addons/web_editor/static/src/xml/editor.xml @@ -9,9 +9,8 @@