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 60a43a2d294..cdbd7c9cbd4 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -2423,7 +2423,7 @@ var SnippetsMenu = Widget.extend({ $selectorSiblings = $(unique(($selectorSiblings || $()).add($selectorChildren.children()).get())); } - var noDropZonesSelector = '[data-invisible="1"], .o_we_no_overlay, :not(:visible), :not(:o_editable)'; + var noDropZonesSelector = '[data-invisible="1"], .o_we_no_overlay, :not(:visible)'; if ($selectorSiblings) { $selectorSiblings.not(`.oe_drop_zone, .oe_drop_clone, ${noDropZonesSelector}`).each(function () { var data; @@ -2835,6 +2835,13 @@ var SnippetsMenu = Widget.extend({ _computeSelectorFunctions: function (selector, exclude, target, noCheck, isChildren, excludeParent) { var self = this; + // TODO in master: FOR_DROP should be a param of the function. + const forDropID = 'FOR_DROP'; + const forDrop = exclude && exclude.startsWith(forDropID); + if (forDrop) { + exclude = exclude.substring(forDropID.length); + } + // The `:not(.o_editable_media)` part is handled outside of the selector // (see filterFunc). // Note: the `:not([contenteditable="true"])` part was there for that @@ -2856,10 +2863,19 @@ var SnippetsMenu = Widget.extend({ // When noCheck is true, we only check the exclude. return true; } - // `o_editable_media` bypasses the `o_not_editable` class. - if (this.classList.contains('o_editable_media')) { + // `o_editable_media` bypasses the `o_not_editable` class except for + // drag & drop. + if (!forDrop && this.classList.contains('o_editable_media')) { return weUtils.shouldEditableMediaBeEditable(this); } + if (forDrop && !isChildren) { + // it's a drop-in. + return !$(this) + .is('.o_not_editable :not([contenteditable="true"]), .o_not_editable'); + } + if (isChildren) { + return !$(this).is('.o_not_editable *'); + } return !$(this) .is('.o_not_editable:not(.s_social_media) :not([contenteditable="true"])'); }; @@ -2956,8 +2972,8 @@ var SnippetsMenu = Widget.extend({ 'base_target': target, 'selector': self._computeSelectorFunctions(selector, exclude, target, noCheck), '$el': $style, - 'drop-near': $style.data('drop-near') && self._computeSelectorFunctions($style.data('drop-near'), '', false, noCheck, true, excludeParent), - 'drop-in': $style.data('drop-in') && self._computeSelectorFunctions($style.data('drop-in'), '', false, noCheck), + 'drop-near': $style.data('drop-near') && self._computeSelectorFunctions($style.data('drop-near'), 'FOR_DROP', false, noCheck, true, excludeParent), + 'drop-in': $style.data('drop-in') && self._computeSelectorFunctions($style.data('drop-in'), 'FOR_DROP', false, noCheck), 'drop-exclude-ancestor': this.dataset.dropExcludeAncestor, 'drop-lock-within': this.dataset.dropLockWithin, 'data': Object.assign({string: $style.attr('string')}, $style.data()), diff --git a/addons/website/static/tests/tours/drag_and_drop_on_non_editable.js b/addons/website/static/tests/tours/drag_and_drop_on_non_editable.js new file mode 100644 index 00000000000..2c8d3146aee --- /dev/null +++ b/addons/website/static/tests/tours/drag_and_drop_on_non_editable.js @@ -0,0 +1,36 @@ +/** @odoo-module **/ + +import wTourUtils from '@website/js/tours/tour_utils'; + +wTourUtils.registerWebsitePreviewTour("test_drag_and_drop_on_non_editable", { + test: true, + url: "/", + edition: true, +}, () => [ + wTourUtils.dragNDrop({ + id: "s_company_team", + name: "Team", + }), + { + content: "Click on an editable media in non editable env.", + trigger: "iframe .s_company_team .o_not_editable > .o_editable_media", + }, + { + content: "Verify that the Replace options is in the editor.", + trigger: "we-button[data-replace-media]", + isCheck: true, + }, + wTourUtils.goBackToBlocks(), + Object.assign(wTourUtils.dragNDrop({ + id: "s_text_highlight", + name: "Text Highlight", + }), { + content: "Drag and drop the Text Highlight building block next to the Team block media.", + run: "drag_and_drop_native iframe .s_company_team .o_not_editable > .o_editable_media", + }), + { + content: "Verify that the Text Highlight building block isn't in a non editable element.", + trigger: "iframe .s_company_team :not(.o_not_editable) > .s_text_highlight", + isCheck: true, + }, +]); diff --git a/addons/website/tests/test_snippets.py b/addons/website/tests/test_snippets.py index 75a88b7a563..90fbd71577c 100644 --- a/addons/website/tests/test_snippets.py +++ b/addons/website/tests/test_snippets.py @@ -95,3 +95,6 @@ class TestSnippets(HttpCase): website.cookies_bar = True self.start_tour(self.env['website'].get_client_action_url('/'), 'snippet_popup_and_scrollbar', login='admin') self.start_tour(self.env['website'].get_client_action_url('/'), 'snippet_popup_and_animations', login='admin') + + def test_drag_and_drop_on_non_editable(self): + self.start_tour(self.env['website'].get_client_action_url('/'), 'test_drag_and_drop_on_non_editable', login='admin')