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 59ffb83d28e..5892b6fb965 100644
--- a/addons/web_editor/static/src/js/editor/snippets.editor.js
+++ b/addons/web_editor/static/src/js/editor/snippets.editor.js
@@ -456,6 +456,10 @@ var SnippetEditor = Widget.extend({
// and would thus produce a deadlock. Also, this awaited
// 'activate_snippet' call would allow to remove the 'toggleOverlay' and
// 'toggleOptions' calls at the start of this function.
+ // TODO also to be checked: this not being awaited, the DOM is removed
+ // first, destroying the related editors and not calling onBlur... to
+ // check if this has always been like this or not and this should be
+ // unit tested.
const parent = this.$target[0].parentElement;
const nextSibling = this.$target[0].nextElementSibling;
const previousSibling = this.$target[0].previousElementSibling;
@@ -568,7 +572,7 @@ var SnippetEditor = Widget.extend({
}
if (this.areOptionsShown() === show) {
- return this._customize$Elements;
+ return null;
}
// All onFocus before all ui updates as the onFocus of an option might
@@ -1785,7 +1789,8 @@ var SnippetsMenu = Widget.extend({
}
resolve(null);
}).then(async editorToEnable => {
- if (ifInactiveOptions && this._enabledEditorHierarchy.includes(editorToEnable)) {
+ if (!previewMode && this._enabledEditorHierarchy[0] === editorToEnable
+ || ifInactiveOptions && this._enabledEditorHierarchy.includes(editorToEnable)) {
return editorToEnable;
}
@@ -1802,8 +1807,14 @@ var SnippetsMenu = Widget.extend({
for (let i = this.snippetEditors.length; i--;) {
const editor = this.snippetEditors[i];
editor.toggleOverlay(false, previewMode);
- if (!previewMode && !this._enabledEditorHierarchy.includes(editor)) {
- await editor.toggleOptions(false);
+ if (!previewMode) {
+ const wasShown = !!await editor.toggleOptions(false);
+ if (wasShown) {
+ this._updateRightPanelContent({
+ content: [],
+ tab: this.tabs.BLOCKS,
+ });
+ }
}
}
// ... then enable the right editor or look if some have been
diff --git a/addons/website/static/tests/tour_utils/focus_blur_snippets_options.js b/addons/website/static/tests/tour_utils/focus_blur_snippets_options.js
new file mode 100644
index 00000000000..752a9b193d3
--- /dev/null
+++ b/addons/website/static/tests/tour_utils/focus_blur_snippets_options.js
@@ -0,0 +1,19 @@
+odoo.define('website.tour_focus_blur_snippets_options', function (require) {
+'use strict';
+
+const options = require('web_editor.snippets.options');
+
+const FocusBlur = options.Class.extend({
+ onFocus() {
+ window.focusBlurSnippetsResult.push(`focus ${this.focusBlurName}`);
+ },
+ onBlur() {
+ window.focusBlurSnippetsResult.push(`blur ${this.focusBlurName}`);
+ },
+});
+
+options.registry.FocusBlurParent = FocusBlur.extend({focusBlurName: 'parent'});
+options.registry.FocusBlurChild1 = FocusBlur.extend({focusBlurName: 'child1'});
+options.registry.FocusBlurChild2 = FocusBlur.extend({focusBlurName: 'child2'});
+
+});
diff --git a/addons/website/static/tests/tours/focus_blur_snippets.js b/addons/website/static/tests/tours/focus_blur_snippets.js
new file mode 100644
index 00000000000..d5c05af1957
--- /dev/null
+++ b/addons/website/static/tests/tours/focus_blur_snippets.js
@@ -0,0 +1,81 @@
+odoo.define('website.tour.focus_blur_snippets', function (require) {
+'use strict';
+
+const ajax = require('web.ajax');
+const tour = require('web_tour.tour');
+
+const blockIDToData = {
+ parent: {
+ selector: '.s_focusblur',
+ name: 'section',
+ overlayIndex: 2,
+ },
+ child1: {
+ selector: '.s_focusblur_child1',
+ name: 'first child',
+ overlayIndex: 1,
+ },
+ child2: {
+ selector: '.s_focusblur_child2',
+ name: 'second child',
+ overlayIndex: 0,
+ },
+};
+
+function clickAndCheck(blockID, expected) {
+ const blockData = blockIDToData[blockID] || {};
+
+ return [{
+ content: blockID ? `Enable the ${blockData.name}` : 'Disable all blocks',
+ trigger: blockData.selector || '#wrapwrap',
+ }, {
+ content: 'Once the related overlays are enabled/disabled, check that the focus/blur calls have been correct.',
+ trigger: blockID
+ ? `.oe_overlay.ui-draggable:eq(${blockData.overlayIndex}).oe_active`
+ : `#oe_manipulators:not(:has(.oe_active))`,
+ run: function (actions) {
+ const result = window.focusBlurSnippetsResult;
+ window.focusBlurSnippetsResult = [];
+
+ if (expected.length !== result.length
+ || !expected.every((item, i) => item === result[i])) {
+ console.error(`
+ Expected: ${expected.toString()}
+ Result: ${result.toString()}
+ `);
+ }
+ },
+ }];
+}
+
+window.focusBlurSnippetsResult = [];
+
+tour.register('focus_blur_snippets', {
+ url: '/?enable_editor=1',
+}, [
+ {
+ content: 'First load our custom JS options',
+ trigger: 'body',
+ run: function () {
+ ajax.loadJS('/website/static/tests/tour_utils/focus_blur_snippets_options.js').then(function () {
+ $('body').addClass('focus_blur_snippets_options_loaded');
+ });
+ },
+ },
+ {
+ content: 'Drag the custom block into the page',
+ trigger: '#snippet_structure .oe_snippet:has(.oe_snippet_body.s_focusblur) .oe_snippet_thumbnail',
+ extra_trigger: 'body.focus_blur_snippets_options_loaded',
+ run: 'drag_and_drop #wrap',
+ },
+ ...clickAndCheck('parent', ['focus parent']),
+ ...clickAndCheck(null, ['blur parent']),
+ ...clickAndCheck('child1', ['focus parent', 'focus child1']),
+ ...clickAndCheck('child1', []),
+ ...clickAndCheck(null, ['blur parent', 'blur child1']),
+ ...clickAndCheck('parent', ['focus parent']),
+ ...clickAndCheck('child1', ['blur parent', 'focus parent', 'focus child1']),
+ ...clickAndCheck('child2', ['blur parent', 'blur child1', 'focus parent', 'focus child2']),
+ ...clickAndCheck('parent', ['blur parent', 'blur child2', 'focus parent']),
+]);
+});
diff --git a/addons/website/tests/test_ui.py b/addons/website/tests/test_ui.py
index ab56ea7a6e4..ab5ad731e23 100644
--- a/addons/website/tests/test_ui.py
+++ b/addons/website/tests/test_ui.py
@@ -221,3 +221,54 @@ class TestUi(odoo.tests.HttpCase):
lang = self.env['res.lang']._activate_lang('nl_NL')
self.env['website'].browse(1).write({'language_ids': [(4, lang.id, 0)]})
self.start_tour("/nl/contactus", 'edit_translated_page_redirect', login='admin')
+
+ def test_13_editor_focus_blur_unit_test(self):
+ # TODO this should definitely not be a website python tour test but
+ # while waiting for a proper web_editor qunit JS test suite for the
+ # editor, it is better than no test at all as this was broken multiple
+ # times already.
+ self.env["ir.ui.view"].create([{
+ 'name': 's_focusblur',
+ 'key': 'website.s_focusblur',
+ 'type': 'qweb',
+ 'arch': """
+
+ """,
+ }, {
+ 'name': 's_focusblur_snippets',
+ 'mode': 'extension',
+ 'inherit_id': self.env.ref('website.snippets').id,
+ 'key': 'website.s_focusblur_snippets',
+ 'type': 'qweb',
+ 'arch': """
+
+
+
+
+
+ """,
+ }, {
+ 'name': 's_focusblur_options',
+ 'mode': 'extension',
+ 'inherit_id': self.env.ref('web_editor.snippet_options').id,
+ 'key': 'website.s_focusblur_options',
+ 'type': 'qweb',
+ 'arch': """
+
+
+
+
+
+
+
+ """,
+ }])
+
+ self.start_tour("/?enable_editor=1", "focus_blur_snippets", login="admin")