Skip to content

Commit 54da667

Browse files
authored
Fix 298633 (#3233)
1 parent d1208d5 commit 54da667

File tree

2 files changed

+449
-120
lines changed

2 files changed

+449
-120
lines changed

packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteList.ts

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
import { getClosestAncestorBlockGroupIndex } from 'roosterjs-content-model-dom';
2-
import type { DeleteSelectionStep, ContentModelListItem } from 'roosterjs-content-model-types';
1+
import {
2+
createListItem,
3+
getClosestAncestorBlockGroupIndex,
4+
mutateBlock,
5+
} from 'roosterjs-content-model-dom';
6+
import type {
7+
DeleteSelectionStep,
8+
ContentModelListItem,
9+
ContentModelBlock,
10+
} from 'roosterjs-content-model-types';
311

412
/**
513
* @internal
@@ -10,21 +18,65 @@ export const deleteList: DeleteSelectionStep = context => {
1018
}
1119

1220
const { paragraph, marker, path } = context.insertPoint;
21+
const index = getClosestAncestorBlockGroupIndex<ContentModelListItem>(
22+
path,
23+
['ListItem'],
24+
['TableCell', 'FormatContainer']
25+
);
26+
const item = path[index];
27+
const parent = path[index + 1];
1328

14-
if (paragraph.segments[0] == marker) {
15-
const index = getClosestAncestorBlockGroupIndex<ContentModelListItem>(
16-
path,
17-
['ListItem'],
18-
['TableCell', 'FormatContainer']
19-
);
20-
const item = path[index] as ContentModelListItem | undefined;
21-
const lastLevel = item?.levels[item.levels.length - 1];
22-
23-
if (lastLevel && item?.blocks[0] == paragraph) {
24-
if (lastLevel.format.displayForDummyItem == 'block') {
25-
item.levels.pop();
29+
if (
30+
item?.blockGroupType == 'ListItem' &&
31+
item.levels.length > 0 &&
32+
paragraph.segments[0] == marker &&
33+
parent
34+
) {
35+
const mutableList = mutateBlock(item);
36+
const lastLevel = mutableList.levels[mutableList.levels.length - 1];
37+
const listItemIndex = parent.blocks.indexOf(item);
38+
const previousItem = parent.blocks[listItemIndex - 1];
39+
40+
// 1. If the last level is dummy, just remove it (legacy behavior)
41+
// 2. If focus is at the beginning of list item and previous block is a list item with the same level count,
42+
// merge current list item into previous one
43+
// 3. Otherwise, split the list item. Keep the blocks before the paragraph in the current list item,
44+
// move the rest to a new list item (if there are multiple levels) or directly to parent (if only one level)
45+
if (lastLevel.format.displayForDummyItem == 'block') {
46+
mutableList.levels.pop();
47+
48+
context.deleteResult = 'range';
49+
} else if (
50+
item.blocks[0] == paragraph &&
51+
previousItem?.blockType == 'BlockGroup' &&
52+
previousItem.blockGroupType == 'ListItem' &&
53+
previousItem.levels.length == mutableList.levels.length
54+
) {
55+
const mutablePreviousItem = mutateBlock(previousItem);
56+
57+
mutablePreviousItem.blocks.push(...mutableList.blocks);
58+
mutateBlock(parent).blocks.splice(listItemIndex, 1);
59+
60+
context.deleteResult = 'range';
61+
} else {
62+
const removedBlocks = mutableList.blocks.splice(
63+
mutableList.blocks.indexOf(paragraph),
64+
mutableList.blocks.length
65+
);
66+
67+
if (mutableList.levels.length > 1) {
68+
const newListItem = createListItem(
69+
mutableList.levels.slice(0, -1),
70+
mutableList.format
71+
);
72+
73+
newListItem.blocks = removedBlocks.map(
74+
block => mutateBlock(block) as ContentModelBlock
75+
);
76+
77+
mutateBlock(parent).blocks.splice(listItemIndex + 1, 0, newListItem);
2678
} else {
27-
lastLevel.format.displayForDummyItem = 'block';
79+
mutateBlock(parent).blocks.splice(listItemIndex + 1, 0, ...removedBlocks);
2880
}
2981

3082
context.deleteResult = 'range';

0 commit comments

Comments
 (0)