[FIX] web_editor: format and style are lost when copy content
Before this commit: Format and style are lost when copying content that has some style or format applied on it. After this commit: Now, able to copy content with its format and style. Task-3263360 closes odoo/odoo#142984 X-original-commit: 8083b990845eeb5b1fa6aaaa21617f16d4d5a780 Signed-off-by: Geelen Sébastien (sge) <sge@odoo.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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('<p>bcd</p>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<p>bcd</p>');
|
||||
},
|
||||
});
|
||||
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<br>efg');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('abc<br>efg');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('<p>abc<br>efg</p>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<p>abc<br>efg</p>');
|
||||
},
|
||||
});
|
||||
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: '<p>[<span style="font-size: 16px;">Test</span> <span style="font-size: 48px;"><font style="color: rgb(255, 0, 0);">Test</font></span>]</p>',
|
||||
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('<p><span style="font-size: 16px;">Test</span> <span style="font-size: 48px;"><font style="color: rgb(255, 0, 0);">Test</font></span></p>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<p><span style="font-size: 16px;">Test</span> <span style="font-size: 48px;"><font style="color: rgb(255, 0, 0);">Test</font></span></p>');
|
||||
},
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p><strong><em><u><font class="text-o-color-1">hello [there]</font></u></em></strong></p>',
|
||||
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('<p><strong><em><u><font class="text-o-color-1">there</font></u></em></strong></p>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<p><strong><em><u><font class="text-o-color-1">there</font></u></em></strong></p>');
|
||||
},
|
||||
});
|
||||
});
|
||||
it('should copy the selection as a single list item', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<ul><li>[First]</li><li>Second</li>',
|
||||
stepFunction: async editor => {
|
||||
const clipboardData = new DataTransfer();
|
||||
triggerEvent(editor.editable, 'copy', { clipboardData });
|
||||
window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('First');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('<li>First</li>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<li>First</li>');
|
||||
},
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<ul><li>First [List]</li><li>Second</li>',
|
||||
stepFunction: async editor => {
|
||||
const clipboardData = new DataTransfer();
|
||||
triggerEvent(editor.editable, 'copy', { clipboardData });
|
||||
window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('List');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('<li>List</li>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<li>List</li>');
|
||||
},
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<ul><li><span style="font-size: 48px;"><font style="color: rgb(255, 0, 0);">[First]</font></span></li><li>Second</li>',
|
||||
stepFunction: async editor => {
|
||||
const clipboardData = new DataTransfer();
|
||||
triggerEvent(editor.editable, 'copy', { clipboardData });
|
||||
window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('First');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('<li><span style="font-size: 48px;"><font style="color: rgb(255, 0, 0);">First</font></span></li>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<li><span style="font-size: 48px;"><font style="color: rgb(255, 0, 0);">First</font></span></li>');
|
||||
},
|
||||
});
|
||||
})
|
||||
it('should copy the selection as a list with multiple list items', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<ul><li>[First</li><li>Second]</li>',
|
||||
stepFunction: async editor => {
|
||||
const clipboardData = new DataTransfer();
|
||||
triggerEvent(editor.editable, 'copy', { clipboardData });
|
||||
window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('First\nSecond');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('<ul><li>First</li><li>Second</li></ul>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<ul><li>First</li><li>Second</li></ul>');
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Cut', () => {
|
||||
@@ -105,8 +171,8 @@ describe('Cut', () => {
|
||||
const clipboardData = new DataTransfer();
|
||||
await triggerEvent(editor.editable, 'cut', { 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('<p>bcd</p>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<p>bcd</p>');
|
||||
},
|
||||
contentAfter: '<p>a[]e</p>',
|
||||
});
|
||||
@@ -116,8 +182,8 @@ describe('Cut', () => {
|
||||
const clipboardData = new DataTransfer();
|
||||
await triggerEvent(editor.editable, 'cut', { clipboardData });
|
||||
window.chai.expect(clipboardData.getData('text/plain')).to.be.equal('abc\nefg');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('abc<br>efg');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('abc<br>efg');
|
||||
window.chai.expect(clipboardData.getData('text/html')).to.be.equal('<p>abc<br>efg</p>');
|
||||
window.chai.expect(clipboardData.getData('text/odoo-editor')).to.be.equal('<p>abc<br>efg</p>');
|
||||
},
|
||||
contentAfter: '<p>[]<br></p>',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user