diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index f9107514cc2..7cc8ccfeda9 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -60,6 +60,8 @@ const hasValidSelection = OdooEditorLib.hasValidSelection; const parseHTML = OdooEditorLib.parseHTML; const closestBlock = OdooEditorLib.closestBlock; const getRangePosition = OdooEditorLib.getRangePosition; +const getCursorDirection = OdooEditorLib.getCursorDirection; +const DIRECTIONS = OdooEditorLib.DIRECTIONS; function getJqueryFromDocument(doc) { if (doc.defaultView && doc.defaultView.$) { @@ -1562,8 +1564,17 @@ export class Wysiwyg extends Component { anchorOffset = focusOffset = index; } } else { - anchorNode = link; - focusNode = link; + const isDirectionRight = getCursorDirection(selection.anchorNode, 0, selection.focusNode, 0) === DIRECTIONS.RIGHT; + if ( + closestElement(selection.anchorNode, 'a') === link && + closestElement(selection.focusNode, 'a') === link + ) { + [anchorNode, focusNode] = isDirectionRight + ? [selection.anchorNode, selection.focusNode] + : [selection.focusNode, selection.anchorNode]; + } else { + [anchorNode, focusNode] = [link, link]; + } } if (!focusOffset) { focusOffset = focusNode.childNodes.length || focusNode.length; diff --git a/addons/website/static/tests/tours/edit_megamenu.js b/addons/website/static/tests/tours/edit_megamenu.js index f12f6e9bc4c..30b18d7b533 100644 --- a/addons/website/static/tests/tours/edit_megamenu.js +++ b/addons/website/static/tests/tours/edit_megamenu.js @@ -94,3 +94,86 @@ wTourUtils.registerWebsitePreviewTour('edit_megamenu', { run: function () {}, // it's a check }, ]); +wTourUtils.registerWebsitePreviewTour('edit_megamenu_big_icons_subtitles', { + test: true, + url: '/', + edition: true, +}, () => [ + // Add a megamenu item to the top menu. + { + content: "Click on a menu item", + trigger: 'iframe #top_menu .nav-item a', + }, + { + content: "Click on 'Link' to open Link Dialog", + trigger: 'iframe .o_edit_menu_popover a.js_edit_menu', + }, + { + content: "Trigger the link dialog (click 'Add Mega Menu Item')", + extra_trigger: ".o_website_dialog", + trigger: '.modal-body a:eq(1)', + }, + { + content: "Write a label for the new menu item", + trigger: '.modal-dialog .o_website_dialog input', + run: 'text Megaaaaa2!', + }, + { + content: "Confirm the mega menu label", + trigger: '.modal-footer .btn-primary', + }, + { + content: "Save the website menu with a new mega menu", + trigger: '.modal-footer .btn-primary', + extra_trigger: '.oe_menu_editor [data-is-mega-menu="true"] .js_menu_label:contains("Megaaaaa2!")', + }, + { + trigger: '#oe_snippets.o_loaded', + run() {}, + }, + { + content: "Check for the new mega menu", + trigger: 'iframe #top_menu:has(.nav-item a.o_mega_menu_toggle:contains("Megaaaaa2!"))', + run: function () {}, // it's a check + }, + // Edit a menu item + wTourUtils.clickOnExtraMenuItem({extra_trigger: ".o_website_preview.editor_enable.editor_has_snippets:not(.o_is_blocked)"}, true), + toggleMegaMenu({extra_trigger: 'iframe #top_menu .nav-item a.o_mega_menu_toggle:contains("Megaaaaa2!")'}), + { + content: "Select the first menu link of the first column", + trigger: 'iframe .s_mega_menu_odoo_menu .row > div:first-child .nav > :first-child', + }, + wTourUtils.changeOption("MegaMenuLayout", "we-toggler"), + { + content: "Select Big Icons Subtitles mega menu", + trigger: '[data-select-label="Big Icons Subtitles"]', + }, + { + content: "Select the h4 of first menu link of the first column", + trigger: 'iframe .s_mega_menu_big_icons_subtitles .row > div:first-child .nav > :first-child h4', + run: function (actions) { + // Clicking on the h4 element first time leads to the selection of + // the entire a.nav-link, due to presence of `o_default_snippet_text` class + // hence, specify the selection on the h4 element + actions.click(); + const iframeDocument = document.querySelector('.o_iframe').contentDocument; + const range = iframeDocument.createRange(); + range.selectNodeContents(this.$anchor[0]); + const sel = iframeDocument.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + }, + }, + { + content: "Convert it to Bold", + trigger: '#oe_snippets #toolbar #bold', + }, + ...wTourUtils.clickOnSave(), + wTourUtils.clickOnExtraMenuItem({}, true), + toggleMegaMenu(), + { + content: "The menu item should only convert selected text to Bold.", + trigger: 'iframe .s_mega_menu_big_icons_subtitles .row > div:first-child .nav > :first-child span:not(:has(strong))', + run: function () {}, // it's a check + }, +]); diff --git a/addons/website/tests/test_ui.py b/addons/website/tests/test_ui.py index 08ef385bb60..92ef59e4edf 100644 --- a/addons/website/tests/test_ui.py +++ b/addons/website/tests/test_ui.py @@ -450,6 +450,9 @@ class TestUi(odoo.tests.HttpCase): def test_30_website_text_animations(self): self.start_tour("/", 'text_animations', login='admin') + def test_31_website_edit_megamenu_big_icons_subtitles(self): + self.start_tour(self.env['website'].get_client_action_url('/'), 'edit_megamenu_big_icons_subtitles', login='admin') + def test_website_media_dialog_image_shape(self): self.start_tour("/", 'website_media_dialog_image_shape', login='admin')