From 1ebc7c301b8808885fbca7890007499dfec80e07 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Tue, 9 Nov 2021 15:36:47 +0000 Subject: [PATCH] [FIX] web_editor, website: fix onFocus/onBlur flow + add test The flow has been broken multiple times across the years. Let's add a test in all stable versions. For the 14.0 forward-port, the test came with a fix which restores the 13.0 flow which we tried to change in 14.0... but only ended up broking it. Indeed, with [1], the 13.0 was fixed. And, with [2], we tried to simplify the flow... but the explanation given by the commit is just wrong: the flow was just broken and the simplification that was to be done in fact practically never occurs. The more the reason to add a test, proving how the flow is working. The simplification may be done someday but not sure it is really worth it. For the 15.0 forward-port, another fix was needed because of [3] which introduced a bug which makes the onBlur method be called multiple times when hiding a whole editor hierarchy. [1]: https://github.com/odoo/odoo/commit/076992bdf099f3a645c9a1ef6df2cdcccbf1c2b2 [2]: https://github.com/odoo/odoo/commit/5c007305c9998ade32c6677cac5552101c3a96af [3]: https://github.com/odoo/odoo/commit/806a8db35b5e0e6a461422f5bba7c97180c3ef29 closes odoo/odoo#79734 X-original-commit: 0acc5e784b15d9c963660da3781763448503f33e Signed-off-by: Romain Derie (rde) Signed-off-by: Quentin Smetz (qsm) --- .../static/src/js/editor/snippets.editor.js | 19 ++++- .../tour_utils/focus_blur_snippets_options.js | 19 +++++ .../static/tests/tours/focus_blur_snippets.js | 81 +++++++++++++++++++ addons/website/tests/test_ui.py | 51 ++++++++++++ 4 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 addons/website/static/tests/tour_utils/focus_blur_snippets_options.js create mode 100644 addons/website/static/tests/tours/focus_blur_snippets.js 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")