[FIX] web_editor: should select only selected node in destroyLinkTools

Before this commit:

`destroyLinkTools` function sets the selection to entire link. However, in
case where a website snippet had a structure like
```html
<a>
    <div>
        <i class=fa-xxx>​</i>
        <div>
            <h4>Text</h4>
            <font>Text</font>
        </div>
    </div>
</a>
```
selecting the complete link caused problem. The toolbar couldn't be
updated correctly, also one could not change the a tag of a single element
within the link.

After this commit:

`destroyLinkTools` selects the `anchorNode` and the `focusnode` of the
selection instead of entire link.

task-3245819

closes odoo/odoo#151752

X-original-commit: e88ffecc4bdb0480fc1d47af14558f28f72a665d
Signed-off-by: Antoine Guenet (age) <age@odoo.com>
This commit is contained in:
Deependra Solanki
2024-02-01 09:49:54 +00:00
parent 51e4ac9e09
commit d824587776
3 changed files with 99 additions and 2 deletions
@@ -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;
@@ -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
},
]);
+3
View File
@@ -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')