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(`
`);
+ press(["ctrl", "a"]);
+ expect(getContent(el)).toBe(``);
+});
+
+test("press 'ctrl+a' in 'contenteditable' should only select his content", async () => {
+ const { el } = await setupEditor(
+ ``
+ );
+ press(["ctrl", "a"]);
+ expect(getContent(el)).toBe(
+ ``
+ );
+});
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 @@
+