diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js index e177cdd53de..a79334a99b4 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js @@ -3783,6 +3783,19 @@ export class OdooEditor extends EventTarget { rangeContent.lastChild.remove(); } + const commonAncestorElement = closestElement(range.commonAncestorContainer); + if (commonAncestorElement && !isBlock(rangeContent.firstChild)) { + // Get the list of ancestor elements starting from the provided + // commonAncestorElement up to the block-level element. + const blockEl = closestBlock(commonAncestorElement); + const ancestorsList = [commonAncestorElement, ...ancestors(commonAncestorElement, blockEl)]; + // Wrap rangeContent with clones of their ancestors to keep the styles. + for (const ancestor of ancestorsList) { + const clone = ancestor.cloneNode(); + clone.append(...rangeContent.childNodes); + rangeContent.appendChild(clone); + } + } const dataHtmlElement = document.createElement('data'); dataHtmlElement.append(rangeContent); const odooHtml = dataHtmlElement.innerHTML; diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js index 708046c18e0..9cf5a3b4974 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/copyPaste.test.js @@ -46,8 +46,8 @@ describe('Copy', () => { const clipboardData = new DataTransfer(); await triggerEvent(editor.editable, 'copy', { clipboardData }); window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('bcd'); - window.chai.expect(clipboardData.getData('text/html')).to.be.equal('bcd'); - window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('bcd'); + window.chai.expect(clipboardData.getData('text/html')).to.be.equal('

bcd

'); + window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('

bcd

'); }, }); await testEditor(BasicEditor, { @@ -56,8 +56,8 @@ describe('Copy', () => { const clipboardData = new DataTransfer(); await triggerEvent(editor.editable, 'copy', { clipboardData }); window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('abc\nefg'); - window.chai.expect(clipboardData.getData('text/html')).to.be.equal('abc
efg'); - window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('abc
efg'); + window.chai.expect(clipboardData.getData('text/html')).to.be.equal('

abc
efg

'); + window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('

abc
efg

'); }, }); await testEditor(BasicEditor, { @@ -71,6 +71,72 @@ describe('Copy', () => { }, }); }); + it('should wrap the selected text with clones of ancestors up to a block element to keep styles', async () => { + await testEditor(BasicEditor, { + contentBefore: '

[Test Test]

', + stepFunction: async editor => { + const clipboardData = new DataTransfer(); + triggerEvent(editor.editable, 'copy', { clipboardData }); + window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('Test Test'); + window.chai.expect(clipboardData.getData('text/html')).to.be.equal('

Test Test

'); + window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('

Test Test

'); + }, + }); + await testEditor(BasicEditor, { + contentBefore: '

hello [there]

', + stepFunction: async editor => { + const clipboardData = new DataTransfer(); + triggerEvent(editor.editable, 'copy', { clipboardData }); + window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('there'); + window.chai.expect(clipboardData.getData('text/html')).to.be.equal('

there

'); + window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('

there

'); + }, + }); + }); + it('should copy the selection as a single list item', async () => { + await testEditor(BasicEditor, { + contentBefore: '