[FIX] web_editor: backspace should keep current node
Before this commit: On backspace current node is removed and it's content were moved to it's preceding node. After this commit: Now keeping the current node it removes preceding node if empty and if not empty then merge current node to previous node. Task-2909314 task-3186679 X-original-commit: bca7f0455ce56268a592c924ac22f9f2dc6541db Part-of: odoo/odoo#134327 Co-authored-by: Sanjay Sharma <shsa@odoo.com>
This commit is contained in:
co-authored by
Sanjay Sharma
parent
78fcad9176
commit
d8d30bc7b1
@@ -775,7 +775,6 @@ export class OdooEditor extends EventTarget {
|
||||
|
||||
sanitize(target) {
|
||||
this.observerFlush();
|
||||
|
||||
let record;
|
||||
if (!target) {
|
||||
// If the target is not given,
|
||||
@@ -783,6 +782,9 @@ export class OdooEditor extends EventTarget {
|
||||
// in the mutations from the last step.
|
||||
for (record of this._currentStep.mutations) {
|
||||
const node = this.idFind(record.parentId || record.id) || this.editable;
|
||||
if (!this.editable.contains(node)) {
|
||||
continue;
|
||||
}
|
||||
target = target
|
||||
? commonParentGet(target, node, this.editable)
|
||||
: node;
|
||||
@@ -2028,7 +2030,9 @@ export class OdooEditor extends EventTarget {
|
||||
insertedZws = zws;
|
||||
}
|
||||
let start = range.startContainer;
|
||||
const startBlock = closestBlock(start);
|
||||
let end = range.endContainer;
|
||||
const endBlock = closestBlock(end);
|
||||
// Let the DOM split and delete the range.
|
||||
const doJoin =
|
||||
(closestBlock(start) !== closestBlock(range.commonAncestorContainer) ||
|
||||
@@ -2100,6 +2104,21 @@ export class OdooEditor extends EventTarget {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the oDeleteBackward loop have emptied the start block and the
|
||||
// range end in another element (rangeStart != rangeEnd), we delete
|
||||
// the start block and move the cursor to the end block.
|
||||
if (
|
||||
startBlock &&
|
||||
startBlock.textContent === '\u200B' &&
|
||||
endBlock &&
|
||||
startBlock !== endBlock &&
|
||||
!isEmptyBlock(endBlock) &&
|
||||
paragraphRelatedElements.includes(endBlock.nodeName)
|
||||
) {
|
||||
startBlock.remove();
|
||||
setSelection(endBlock, 0);
|
||||
fillEmpty(endBlock);
|
||||
}
|
||||
if (insertedZws) {
|
||||
// Remove the zero-width space (zws) that was added to preserve the
|
||||
// parent styles, then call `fillEmpty` to properly add a flagged
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
isNotEditableNode,
|
||||
createDOMPathGenerator,
|
||||
closestElement,
|
||||
closestBlock,
|
||||
} from '../utils/utils.js';
|
||||
|
||||
Text.prototype.oDeleteBackward = function (offset, alreadyMoved = false) {
|
||||
@@ -141,6 +142,29 @@ HTMLElement.prototype.oDeleteBackward = function (offset, alreadyMoved = false,
|
||||
return;
|
||||
}
|
||||
|
||||
/** If we are at the beninning of a block node,
|
||||
* And the previous node is empty, remove it.
|
||||
*
|
||||
* E.g. (previousEl == empty)
|
||||
* <p><br></p><h1>[]def</h1> + BACKSPACE
|
||||
* <=> <h1>[]def</h1>
|
||||
*
|
||||
* E.g. (previousEl != empty)
|
||||
* <h3>abc</h3><h1>[]def</h1> + BACKSPACE
|
||||
* <=> <h3>abc[]def</h3>
|
||||
*/
|
||||
const previousElementSiblingClosestBlock = closestBlock(this.previousElementSibling);
|
||||
if (
|
||||
previousElementSiblingClosestBlock &&
|
||||
(isEmptyBlock(previousElementSiblingClosestBlock) ||
|
||||
previousElementSiblingClosestBlock.textContent === '\u200B') &&
|
||||
paragraphRelatedElements.includes(this.nodeName)
|
||||
) {
|
||||
previousElementSiblingClosestBlock.remove();
|
||||
setSelection(this, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backspace at the beginning of a block node. If it doesn't have a left
|
||||
* block and it is one of the special block formatting tags below then
|
||||
|
||||
@@ -57,6 +57,8 @@ export const YOUTUBE_URL_GET_VIDEO_ID =
|
||||
/^(?:(?:https?:)?\/\/)?(?:(?:www|m)\.)?(?:youtube\.com|youtu\.be)(?:\/(?:[\w-]+\?v=|embed\/|v\/)?)([^\s?&#]+)(?:\S+)?$/i;
|
||||
export const EMAIL_REGEX = /^(mailto:)?[\w-.]+@(?:[\w-]+\.)+[\w-]{2,4}$/i;
|
||||
|
||||
export const PROTECTED_BLOCK_TAG = ['TR','TD','TABLE','TBODY','UL','OL','LI'];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Position and sizes
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -836,12 +836,11 @@ X[]
|
||||
contentAfter: '<h1>ab[]</h1>',
|
||||
});
|
||||
});
|
||||
it('should merge a heading1 with text into an empty paragraph (keeping the heading)', async () => {
|
||||
it('should remove empty paragraph (keeping the heading)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p><br>[]</p><h1>ab</h1>',
|
||||
stepFunction: deleteForward,
|
||||
// JW cAfter: '<h1>[]ab</h1>',
|
||||
contentAfter: '<p>[]ab</p>',
|
||||
contentAfter: '<h1>[]ab</h1>',
|
||||
});
|
||||
});
|
||||
it('should merge a text following a paragraph (keeping the text)', async () => {
|
||||
@@ -858,12 +857,11 @@ X[]
|
||||
});
|
||||
});
|
||||
describe('With attributes', () => {
|
||||
it('should merge a paragraph without class into an empty paragraph with a class', async () => {
|
||||
it('should remove empty paragraph with class', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p class="a"><br>[]</p><p>abc</p>',
|
||||
stepFunction: deleteForward,
|
||||
// JW cAfter: '<p>[]abc</p>',
|
||||
contentAfter: '<p class="a">[]abc</p>',
|
||||
contentAfter: '<p>[]abc</p>',
|
||||
});
|
||||
});
|
||||
it('should merge two paragraphs with spans of same classes', async () => {
|
||||
@@ -1248,28 +1246,92 @@ X[]
|
||||
contentAfter: '<h1>ab []gh</h1>',
|
||||
});
|
||||
});
|
||||
it('should delete a selection from the beginning of a heading1 with a format to the middle of a paragraph', async () => {
|
||||
// Forward selection
|
||||
it('should delete a selection from the beginning of a heading1 with a format to the middle of a paragraph + start of editable', async () => {
|
||||
//Forward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><b>[abcd</b></h1><p>ef]gh</p>',
|
||||
contentBefore: '<h1><b>[abcd</b></h1><p>ef]gh1</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh1</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[<b>abcd</b></h1><p>ef]gh</p>',
|
||||
contentBefore: '<h1>[<b>abcd</b></h1><p>ef]gh2</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh2</p>',
|
||||
});
|
||||
// Backward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><b>]abcd</b></h1><p>ef[gh</p>',
|
||||
contentBefore: '<h1><b>]abcd</b></h1><p>ef[gh3</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh3</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>]<b>abcd</b></h1><p>ef[gh</p>',
|
||||
contentBefore: '<h1>]<b>abcd</b></h1><p>ef[gh4</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh4</p>',
|
||||
});
|
||||
});
|
||||
it('should delete a selection from the beginning of a heading1 with a format to the middle of a paragraph + content', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>content</p><h1><b>[abcd</b></h1><p>ef]gh1</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<p>content</p><p>[]gh1</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>content</p><h1>[<b>abcd</b></h1><p>ef]gh2</p>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<p>content</p><p>[]gh2</p>',
|
||||
});
|
||||
});
|
||||
it('should delete a selection from the beginning of a heading1 to the end of a paragraph', async () => {
|
||||
//Forward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[abcd</h1><p>ef]</p><h2>1</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]<br></h1><h2>1</h2>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[abcd</h1><p>ef]</p><h2>2</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]<br></h1><h2>2</h2>',
|
||||
});
|
||||
// Backward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>]abcd</h1><p>ef[</p><h2>3</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]<br></h1><h2>3</h2>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>]abcd</h1><p>ef[</p><h2>4</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<h1>[]<br></h1><h2>4</h2>',
|
||||
});
|
||||
});
|
||||
it('should delete a selection from the beginning of a heading1 with a format to the end of a paragraph', async () => {
|
||||
//Forward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><u>[abcd</u></h1><p>ef]</p><h2>1</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfterEdit: '<h1><u data-oe-zws-empty-inline="">[]\u200B</u><br></h1><h2>1</h2>',
|
||||
contentAfter: '<h1>[]<br></h1><h2>1</h2>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[<u>abcd</u></h1><p>ef]</p><h2>2</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfterEdit: '<h1><u data-oe-zws-empty-inline="">[]\u200B</u><br></h1><h2>2</h2>',
|
||||
contentAfter: '<h1>[]<br></h1><h2>2</h2>',
|
||||
});
|
||||
// Backward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><u>]abcd</u></h1><p>ef[</p><h2>3</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfterEdit: '<h1><u data-oe-zws-empty-inline="">[]\u200B</u><br></h1><h2>3</h2>',
|
||||
contentAfter: '<h1>[]<br></h1><h2>3</h2>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>]<u>abcd</u></h1><p>ef[</p><h2>4</h2>',
|
||||
stepFunction: deleteForward,
|
||||
contentAfterEdit: '<h1><u data-oe-zws-empty-inline="">[]\u200B</u><br></h1><h2>4</h2>',
|
||||
contentAfter: '<h1>[]<br></h1><h2>4</h2>',
|
||||
});
|
||||
});
|
||||
it('should not break unbreakables', async () => {
|
||||
@@ -1726,94 +1788,115 @@ X[]
|
||||
});
|
||||
it('should not break unbreakables', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[]<br></div>` +
|
||||
`<div class="oe_unbreakable">abc</div></div></div></div>`,
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[]<br></div>` +
|
||||
`<div class="oe_unbreakable">abc</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[]<br></div>` +
|
||||
`<div class="oe_unbreakable">abc</div></div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[]<br></div>` +
|
||||
`<div class="oe_unbreakable">abc</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[ab</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[ab</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">e]f</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">e]f1</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[]<br></div>` +
|
||||
`<div class="oe_unbreakable">f</div></div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[]<br></div>` +
|
||||
`<div class="oe_unbreakable">f1</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[b</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">a[b</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">e]f</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">e]f2</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[]</div>` +
|
||||
`<div class="oe_unbreakable">f</div></div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">a[]</div>` +
|
||||
`<div class="oe_unbreakable">f2</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[b</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">3a[b</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">ef]</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">ef]</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[]</div>` +
|
||||
`</div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">3a[]</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[ab</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[ab</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">ef]</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">ef4]</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[]<br></div>` +
|
||||
`</div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[]<br></div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[ab</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[ab</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">ef</div></div>` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">gh</div>` +
|
||||
`<div class="oe_unbreakable">ef</div>` +
|
||||
`</div>` +
|
||||
`<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">gh</div>` +
|
||||
`<div class="oe_unbreakable">ij</div>` +
|
||||
`<div class="oe_unbreakable">k]l</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">k]l5</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">[]<br></div>` +
|
||||
`</div><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">l</div></div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">[]<br></div>` +
|
||||
`</div>` +
|
||||
`<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">l5</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[b</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">a[b</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">ef</div></div>` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">gh</div>` +
|
||||
`<div class="oe_unbreakable">ef</div>` +
|
||||
`</div>` +
|
||||
`<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">gh</div>` +
|
||||
`<div class="oe_unbreakable">ij</div>` +
|
||||
`<div class="oe_unbreakable">k]l</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">k]l6</div>` +
|
||||
`</div>`,
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[]</div>` +
|
||||
`</div><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">l</div></div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">a[]</div>` +
|
||||
`</div>` +
|
||||
`<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">l6</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[b</div>` +
|
||||
contentBefore: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">7a[b</div>` +
|
||||
`<div class="oe_unbreakable">cd</div>` +
|
||||
`<div class="oe_unbreakable">ef</div></div>` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">gh</div>` +
|
||||
`<div class="oe_unbreakable">ef</div>` +
|
||||
`</div>` +
|
||||
`<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">gh</div>` +
|
||||
`<div class="oe_unbreakable">ij</div>` +
|
||||
`<div class="oe_unbreakable">kl]</div></div></div></div>`,
|
||||
`<div class="oe_unbreakable">kl]</div>` +
|
||||
`</div>`,
|
||||
stepFunction: editor => deleteBackward(editor),
|
||||
contentAfter: `<div class="oe_unbreakable"><div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable"><div class="oe_unbreakable">a[]</div>` +
|
||||
`</div></div></div>`,
|
||||
contentAfter: `<div class="oe_unbreakable">` +
|
||||
`<div class="oe_unbreakable">7a[]</div>` +
|
||||
`</div>`,
|
||||
});
|
||||
});
|
||||
it('should merge the following inline text node', async () => {
|
||||
@@ -2278,12 +2361,11 @@ X[]
|
||||
contentAfter: '<h1>ab[]</h1>',
|
||||
});
|
||||
});
|
||||
it('should merge a heading1 with text into an empty paragraph (keeping the heading)', async () => {
|
||||
it('should remove empty paragraph (keeping the heading)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p><br></p><h1>[]ab</h1>',
|
||||
stepFunction: deleteBackward,
|
||||
// JW cAfter: '<h1>[]ab</h1>',
|
||||
contentAfter: '<p>[]ab</p>',
|
||||
contentAfter: '<h1>[]ab</h1>',
|
||||
});
|
||||
});
|
||||
it('should merge with previous node (default behaviour)', async () => {
|
||||
@@ -2337,12 +2419,11 @@ X[]
|
||||
});
|
||||
});
|
||||
describe('With attributes', () => {
|
||||
it('should merge a paragraph without class into an empty paragraph with a class', async () => {
|
||||
it('should remove paragraph with class', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p class="a"><br></p><p>[]abc</p>',
|
||||
stepFunction: deleteBackward,
|
||||
// JW cAfter: '<p>[]abc</p>',
|
||||
contentAfter: '<p class="a">[]abc</p>',
|
||||
contentAfter: '<p>[]abc</p>',
|
||||
});
|
||||
});
|
||||
it('should merge two paragraphs with spans of same classes', async () => {
|
||||
@@ -2602,7 +2683,7 @@ X[]
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>abc</p><h1><br></h1><p>[]def</p>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>abc</p><h1>[]def</h1>',
|
||||
contentAfter: '<p>abc</p><p>[]def</p>',
|
||||
});
|
||||
});
|
||||
it('should remove only one br between contents', async () => {
|
||||
@@ -2829,25 +2910,25 @@ X[]
|
||||
it('should delete a selection from the beginning of a heading1 with a format to the middle of a paragraph', async () => {
|
||||
// Forward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><b>[abcd</b></h1><p>ef]gh</p>',
|
||||
contentBefore: '<h1><b>[abcd</b></h1><p>ef]gh1</p>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh1</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>[<b>abcd</b></h1><p>ef]gh</p>',
|
||||
contentBefore: '<h1>[<b>abcd</b></h1><p>ef]gh2</p>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh2</p>',
|
||||
});
|
||||
// Backward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><b>]abcd</b></h1><p>ef[gh</p>',
|
||||
contentBefore: '<h1><b>]abcd</b></h1><p>ef[gh3</p>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh3</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1>]<b>abcd</b></h1><p>ef[gh</p>',
|
||||
contentBefore: '<h1>]<b>abcd</b></h1><p>ef[gh4</p>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<h1>[]gh</h1>',
|
||||
contentAfter: '<p>[]gh4</p>',
|
||||
});
|
||||
});
|
||||
it('should delete a heading (triple click backspace)', async () => {
|
||||
|
||||
Reference in New Issue
Block a user