diff --git a/addons/html_editor/static/src/core/selection_plugin.js b/addons/html_editor/static/src/core/selection_plugin.js index 0991a2354e859..850b01f950c03 100644 --- a/addons/html_editor/static/src/core/selection_plugin.js +++ b/addons/html_editor/static/src/core/selection_plugin.js @@ -9,7 +9,7 @@ import { } from "@html_editor/utils/dom_info"; import { closestElement, descendants } from "@html_editor/utils/dom_traversal"; import { Plugin } from "../plugin"; -import { DIRECTIONS, childNodeIndex, endPos, nodeSize } from "../utils/position"; +import { DIRECTIONS, childNodeIndex, endPos, nodeSize, startPos } from "../utils/position"; import { getAdjacentCharacter, normalizeCursorPosition, @@ -122,6 +122,9 @@ export class SelectionPlugin extends Plugin { "rectifySelection", // "collapseIfZWS", ]; + static resources = (p) => ({ + shortcuts: [{ hotkey: "control+a", command: "SELECT_ALL" }], + }); setup() { this.resetSelection(); @@ -147,6 +150,22 @@ export class SelectionPlugin extends Plugin { }); } + handleCommand(command, payload) { + switch (command) { + case "SELECT_ALL": + { + const selection = this.getEditableSelection(); + const containerSelector = "#wrap>*, .oe_structure>*, [contenteditable]"; + const container = + selection && closestElement(selection.anchorNode, containerSelector); + const [anchorNode, anchorOffset] = startPos(container); + const [focusNode, focusOffset] = endPos(container); + this.setSelection({ anchorNode, anchorOffset, focusNode, focusOffset }); + } + break; + } + } + resetSelection() { this.activeSelection = this.makeSelection(); } diff --git a/addons/html_editor/static/src/main/link/link_plugin.js b/addons/html_editor/static/src/main/link/link_plugin.js index 49be5fd6aad10..8a62be0036a24 100644 --- a/addons/html_editor/static/src/main/link/link_plugin.js +++ b/addons/html_editor/static/src/main/link/link_plugin.js @@ -20,6 +20,7 @@ export class LinkPlugin extends Plugin { static resources = (p) => ({ split_element_block: { callback: p.handleSplitBlock.bind(p) }, handle_insert_line_break_element: { callback: p.handleInsertLineBreak.bind(p) }, + powerboxCategory: { id: "navigation", name: _t("Navigation"), sequence: 50 }, }); setup() { this.addDomListener(this.editable, "keydown", (ev) => { diff --git a/addons/html_editor/static/src/main/link/link_popover_plugin.js b/addons/html_editor/static/src/main/link/link_popover_plugin.js index 62a55a15e719a..b71b567be0eb1 100644 --- a/addons/html_editor/static/src/main/link/link_popover_plugin.js +++ b/addons/html_editor/static/src/main/link/link_popover_plugin.js @@ -40,8 +40,6 @@ export class LinkPopoverPlugin extends Plugin { isAvailable: isSelectionHasLink, }, ], - - powerboxCategory: { id: "navigation", name: _t("Navigation"), sequence: 50 }, powerboxItems: [ { name: _t("Link"), diff --git a/addons/html_editor/static/tests/selection.test.js b/addons/html_editor/static/tests/selection.test.js index 74b5739ce99a5..0178a66326564 100644 --- a/addons/html_editor/static/tests/selection.test.js +++ b/addons/html_editor/static/tests/selection.test.js @@ -1,5 +1,5 @@ import { describe, expect, test } from "@odoo/hoot"; -import { queryFirst } from "@odoo/hoot-dom"; +import { press, queryFirst } from "@odoo/hoot-dom"; import { animationFrame, tick } from "@odoo/hoot-mock"; import { patchWithCleanup } from "@web/../tests/web_test_helpers"; import { Plugin } from "../src/plugin"; @@ -142,3 +142,19 @@ test("setSelection should not set the selection outside the editable", async () const selection = editor.shared.setSelection(editor.shared.getEditableSelection()); expect(el.contains(selection.anchorNode)).toBe(true); }); + +test("press 'ctrl+a' in 'oe_structure' child should only select his content", async () => { + const { el } = await setupEditor(`

a[]b

cd

`); + press(["ctrl", "a"]); + expect(getContent(el)).toBe(`

[ab]

cd

`); +}); + +test("press 'ctrl+a' in 'contenteditable' should only select his content", async () => { + const { el } = await setupEditor( + `

a[]b

cd

` + ); + press(["ctrl", "a"]); + expect(getContent(el)).toBe( + `

[ab]

cd

` + ); +}); diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index db7db4708b242..13e362fcabee9 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -174,7 +174,6 @@ ], 'web.assets_unit_tests': [ 'mass_mailing/static/tests/mass_mailing_html_field.test.js', - 'mass_mailing/static/tests/mass_mailing_favorite_filter.test.js', ], 'web.qunit_suite_tests': [ 'mass_mailing/static/tests/mass_mailing_favourite_filter_tests.js', diff --git a/addons/mass_mailing/static/src/fields/mass_mailing_html_field/mass_mailing_template_selector.xml b/addons/mass_mailing/static/src/fields/mass_mailing_html_field/mass_mailing_template_selector.xml index 6555e72ea906d..dacc0d36752f1 100644 --- a/addons/mass_mailing/static/src/fields/mass_mailing_html_field/mass_mailing_template_selector.xml +++ b/addons/mass_mailing/static/src/fields/mass_mailing_html_field/mass_mailing_template_selector.xml @@ -19,7 +19,7 @@
diff --git a/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js b/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js index ef7c0e006abce..f6b5e7f5975b9 100644 --- a/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js +++ b/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js @@ -48,13 +48,13 @@ run: 'click', }, { isActive: ["enterprise"], - trigger: 'div[name="body_arch"] :iframe #newsletter', + trigger: 'div[name="body_arch"] .o_mail_theme_selector_new [name="newsletter"]', content: markup(_t('Choose this theme.')), tooltipPosition: 'left', run: 'click', }, { isActive: ["community"], - trigger: 'div[name="body_arch"] :iframe #default', + trigger: 'div[name="body_arch"] .o_mail_theme_selector_new [name="default"]', content: markup(_t('Choose this theme.')), tooltipPosition: 'right', run: 'click', diff --git a/addons/mass_mailing/static/tests/tours/mailing_campaign.js b/addons/mass_mailing/static/tests/tours/mailing_campaign.js index 7d51ac8b98c54..3f3a76bfac701 100644 --- a/addons/mass_mailing/static/tests/tours/mailing_campaign.js +++ b/addons/mass_mailing/static/tests/tours/mailing_campaign.js @@ -29,7 +29,7 @@ registry.category('web_tour.tours').add('mailing_campaign', { }, { content: 'Pick the basic theme', - trigger: ":iframe #basic", + trigger: ".o_mail_theme_selector_new [name='basic']", run: "click", }, { diff --git a/addons/mass_mailing/static/tests/tours/mailing_editor.js b/addons/mass_mailing/static/tests/tours/mailing_editor.js index 3ab8245097213..ba80a326b0050 100644 --- a/addons/mass_mailing/static/tests/tours/mailing_editor.js +++ b/addons/mass_mailing/static/tests/tours/mailing_editor.js @@ -20,7 +20,7 @@ registry.category("web_tour.tours").add('mailing_editor', { run: "click", }, { content: 'choose the theme "empty" to edit the mailing with snippets', - trigger: '[name="body_arch"] :iframe #empty', + trigger: '[name="body_arch"] .o_mail_theme_selector_new [name="empty]', run() { this.anchor.click(); } diff --git a/addons/mass_mailing/static/tests/tours/mailing_editor_theme.js b/addons/mass_mailing/static/tests/tours/mailing_editor_theme.js index 59ccb40963bb7..633e79bddf748 100644 --- a/addons/mass_mailing/static/tests/tours/mailing_editor_theme.js +++ b/addons/mass_mailing/static/tests/tours/mailing_editor_theme.js @@ -35,15 +35,15 @@ registry.category("web_tour.tours").add('mailing_editor_theme', { run: "click", }, { - trigger: ":iframe .o_mail_theme_selector_new", + trigger: ".o_mail_theme_selector_new", }, { content: "Pick the basic theme", - trigger: ':iframe #basic', + trigger: '.o_mail_theme_selector_new [name="basic"]', run: "click", }, { - trigger: ":iframe html:not(:has(.o_mail_theme_selector_new))", + trigger: ":not(:has(.o_mail_theme_selector_new))", }, { content: "Make sure the snippets menu is hidden", @@ -56,7 +56,7 @@ registry.category("web_tour.tours").add('mailing_editor_theme', { run: "click", }, { - trigger: ":iframe .o_mail_theme_selector_new", + trigger: ".o_mail_theme_selector_new", }, { content: "Fill in Subject", @@ -75,7 +75,7 @@ registry.category("web_tour.tours").add('mailing_editor_theme', { }, { content: "Pick the newsletter theme", - trigger: ':iframe #newsletter', + trigger: ':iframe [name="newsletter"]', run: "click", }, { diff --git a/addons/mass_mailing/static/tests/tours/mass_mailing_code_view.js b/addons/mass_mailing/static/tests/tours/mass_mailing_code_view.js index 79b17e2c6e0b1..7e86f6279ae4c 100644 --- a/addons/mass_mailing/static/tests/tours/mass_mailing_code_view.js +++ b/addons/mass_mailing/static/tests/tours/mass_mailing_code_view.js @@ -29,7 +29,7 @@ registry.category("web_tour.tours").add('mass_mailing_code_view_tour', { content: 'Select item from dropdown', run: 'click', }, { - trigger: 'div[name="body_arch"] :iframe #default', + trigger: 'div[name="body_arch"] .o_mail_theme_selector_new [name="default"]', content: markup('Choose this theme.'), run: 'click', }, { diff --git a/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_tabs.js b/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_tabs.js index d800856bba79d..a044447f6b388 100644 --- a/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_tabs.js +++ b/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_tabs.js @@ -19,7 +19,7 @@ registry.category("web_tour.tours").add('snippets_mailing_menu_tabs', { }, { content: "Click on the 'Start From Scratch' template.", - trigger: ':iframe #empty', + trigger: '.o_mail_theme_selector_new [name="empty"]', run: "click", }, { diff --git a/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar.js b/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar.js index 8ba46f73bde5a..81ce7b1c75b63 100644 --- a/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar.js +++ b/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar.js @@ -19,7 +19,7 @@ registry.category("web_tour.tours").add('snippets_mailing_menu_toolbar', { }, { content: "Wait for the theme selector to load.", - trigger: ':iframe .o_mail_theme_selector_new', + trigger: '.o_mail_theme_selector_new', run: "click", }, { @@ -34,12 +34,12 @@ registry.category("web_tour.tours").add('snippets_mailing_menu_toolbar', { }, { content: "Make sure the empty template is an option on non-mobile devices.", - trigger: ':iframe #empty', + trigger: '.o_mail_theme_selector_new [name="empty"]', run: () => null, }, { content: "Click on the default 'welcome' template.", - trigger: ':iframe #default', + trigger: '.o_mail_theme_selector_new [name="default"]', run: "click", }, { // necessary to wait for the cursor to be placed in the first p diff --git a/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar_mobile.js b/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar_mobile.js index 12a3657a7a4a3..c92834b49be70 100644 --- a/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar_mobile.js +++ b/addons/mass_mailing/static/tests/tours/snippets_mailing_menu_toolbar_mobile.js @@ -21,9 +21,9 @@ registry.category("web_tour.tours").add('snippets_mailing_menu_toolbar_mobile', { isActive: ["mobile"], content: "Check templates available in theme selector", - trigger: ':iframe .o_mail_theme_selector_new', + trigger: '.o_mail_theme_selector_new', run: function () { - if (this.anchor.querySelector("#empty")) { + if (this.anchor.querySelector("[name='empty']")) { console.error('The empty template should not be visible on mobile.'); } }, diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index eb7ed971fd409..8688b7ed901e8 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -265,6 +265,7 @@
+