Skip to content

Commit df5e739

Browse files
committed
[FIX] html_editor: prevent header content loss on type change
Problem: When trying to change the header type of "All products" in the "/shop" page on Website, the title disappears. Cause: The title is `h1[data-oe-field]`. When we update it, we replace the node with a new header node. This triggers `handleMutations` with both the removed node and the new node. The old removed node with no content is processed in `normalizeHandler`, which causes removal of the content from the new node as well. Solution: We disable `setTag` on `o_editable`. Steps to reproduce: 1. Enter Website. 2. Go to the cart and select the header "Order Summary". 3. Attempt to change the font style (Header 1, Header 2, etc.). → The header disappears. opw-5106712 closes odoo#233286 X-original-commit: a10217b Signed-off-by: David Monjoie (dmo) <dmo@odoo.com> Signed-off-by: Walid Sahli (wasa) <wasa@odoo.com>
1 parent c743e07 commit df5e739

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

addons/html_builder/static/src/core/setup_editor_plugin.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export class SetupEditorPlugin extends Plugin {
99
clean_for_save_handlers: this.cleanForSave.bind(this),
1010
closest_savable_providers: withSequence(10, (el) => el.closest(".o_editable")),
1111
o_editable_selectors: "[data-oe-model]",
12+
unremovable_node_predicates: (node) => node.classList?.contains("o_editable"),
1213
};
1314

1415
setup() {

addons/html_builder/static/tests/editor.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,4 +276,14 @@ describe("font types", () => {
276276
expect(".o-we-toolbar .btn[name='font']").toHaveText("Small");
277277
expect(editor.editable.querySelector("p")).toHaveClass("small");
278278
});
279+
280+
test("Should not be able to change tag of `o_editable` element", async () => {
281+
const { getEditor } = await setupHTMLBuilder(`<h1 class="o_editable">abcd</h1>`);
282+
const editor = getEditor();
283+
const h1 = editor.editable.querySelector("h1");
284+
setSelection({ anchorNode: h1, anchorOffset: 0, focusOffset: 1 });
285+
await waitFor(".o-we-toolbar");
286+
await expandToolbar();
287+
expect(".o-we-toolbar .btn[name='font']").toHaveCount(0);
288+
});
279289
});

addons/html_editor/static/src/core/dom_plugin.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,30 @@ export class DomPlugin extends Plugin {
574574
this.dependencies.selection.setSelection({ anchorNode, anchorOffset });
575575
}
576576

577+
/**
578+
* Determines if a block element can be safely retagged.
579+
*
580+
* Certain blocks (like 'o_editable') should not be retagged because doing so
581+
* will recreate the block, potentially causing issues. This function checks
582+
* if retagging a block is safe.
583+
*
584+
* @param {HTMLElement} block
585+
* @returns {boolean}
586+
*/
587+
isRetaggingSafe(block) {
588+
return !(
589+
(isParagraphRelatedElement(block) ||
590+
isListItemElement(block) ||
591+
isPhrasingContent(block)) &&
592+
this.getResource("unremovable_node_predicates").some((predicate) => predicate(block))
593+
);
594+
}
595+
577596
getBlocksToSet() {
578597
const targetedBlocks = [...this.dependencies.selection.getTargetedBlocks()];
579598
return targetedBlocks.filter(
580599
(block) =>
600+
this.isRetaggingSafe(block) &&
581601
!descendants(block).some((descendant) => targetedBlocks.includes(descendant)) &&
582602
block.isContentEditable
583603
);

0 commit comments

Comments
 (0)