From 9f5db3a2cedc3dedd448b89a05bf4ce7ad34935b Mon Sep 17 00:00:00 2001 From: "Julia Roldi (from Dev Box)" Date: Tue, 12 Nov 2024 16:59:27 -0300 Subject: [PATCH] list-bugs --- .../lib/edit/inputSteps/handleEnterOnList.ts | 59 +++- .../edit/inputSteps/handleEnterOnListTest.ts | 328 ++++++++++++++++++ 2 files changed, 377 insertions(+), 10 deletions(-) diff --git a/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnList.ts b/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnList.ts index de044090317..2cae41ef692 100644 --- a/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnList.ts +++ b/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnList.ts @@ -10,6 +10,7 @@ import { import type { ContentModelListItem, DeleteSelectionStep, + ReadonlyContentModelBlock, ReadonlyContentModelBlockGroup, ReadonlyContentModelListItem, ShallowMutableContentModelListItem, @@ -53,19 +54,28 @@ export const handleEnterOnList: DeleteSelectionStep = context => { const nextBlock = listParent.blocks[listIndex + 1]; if (nextBlock) { - const nextListItem = listParent.blocks[listIndex + 1]; - if ( - isBlockGroupOfType(nextListItem, 'ListItem') && - nextListItem.levels[0] + isBlockGroupOfType(nextBlock, 'ListItem') && + nextBlock.levels[0] ) { - nextListItem.levels.forEach(level => { + nextBlock.levels.forEach(level => { // Remove startNumberOverride so that next list item can join current list, unless it is 1. // List start with 1 means it should be an explicit new list and should never join another list before it if (level.format.startNumberOverride !== 1) { level.format.startNumberOverride = undefined; } }); + + if (listItem.levels.length == 0) { + const index = findIndex( + listParent.blocks, + nextBlock.levels.length, + listIndex + ); + nextBlock.levels[ + nextBlock.levels.length - 1 + ].format.startNumberOverride = index; + } } } @@ -75,12 +85,15 @@ export const handleEnterOnList: DeleteSelectionStep = context => { }; const isEmptyListItem = (listItem: ReadonlyContentModelListItem) => { + return listItem.blocks.length === 1 && isEmptyParagraph(listItem.blocks[0]); +}; + +const isEmptyParagraph = (block: ReadonlyContentModelBlock) => { return ( - listItem.blocks.length === 1 && - listItem.blocks[0].blockType === 'Paragraph' && - listItem.blocks[0].segments.length === 2 && - listItem.blocks[0].segments[0].segmentType === 'SelectionMarker' && - listItem.blocks[0].segments[1].segmentType === 'Br' + block.blockType === 'Paragraph' && + block.segments.length === 2 && + block.segments[0].segmentType === 'SelectionMarker' && + block.segments[1].segmentType === 'Br' ); }; @@ -134,3 +147,29 @@ const createNewListLevel = (listItem: ReadonlyContentModelListItem) => { ); }); }; + +const findIndex = ( + blocks: readonly ReadonlyContentModelBlock[], + levelLength: number, + index: number +) => { + let counter = 1; + for (let i = index; i > -1; i--) { + const listItem = blocks[i]; + if ( + isBlockGroupOfType(listItem, 'ListItem') && + listItem.levels.length === levelLength + ) { + counter++; + } else if ( + !( + isBlockGroupOfType(listItem, 'ListItem') && + listItem.levels.length == 0 + ) + ) { + return counter; + } + } + + return counter; +}; diff --git a/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnListTest.ts b/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnListTest.ts index 8a25562b7cf..75d7b96a537 100644 --- a/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnListTest.ts +++ b/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnListTest.ts @@ -2870,4 +2870,332 @@ describe('handleEnterOnList - keyboardEnter', () => { runTest(model, false, expectedModel, false, 1); }); + + it('List item must continue second level', () => { + const model: ContentModelDocument = { + blockGroupType: 'Document', + blocks: [ + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + startNumberOverride: 1, + listStyleType: 'decimal', + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + text: 'test', + segmentType: 'Text', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + listStyleType: 'decimal', + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + { + listType: 'OL', + format: { + listStyleType: 'lower-alpha', + }, + dataset: { + editingInfo: '{"applyListStyleFromLevel":true}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + text: 'test', + segmentType: 'Text', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + listStyleType: 'decimal', + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + isSelected: true, + segmentType: 'SelectionMarker', + format: {}, + }, + { + segmentType: 'Br', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + listStyleType: 'decimal', + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + { + listType: 'OL', + format: { + listStyleType: 'lower-alpha', + }, + dataset: { + editingInfo: '{"applyListStyleFromLevel":true}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + text: 'test', + segmentType: 'Text', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + ], + format: {}, + }; + const expectedModel: ContentModelDocument = { + blockGroupType: 'Document', + blocks: [ + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + startNumberOverride: 1, + listStyleType: 'decimal', + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + text: 'test', + segmentType: 'Text', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + listStyleType: 'decimal', + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + { + listType: 'OL', + format: { + listStyleType: 'lower-alpha', + }, + dataset: { + editingInfo: '{"applyListStyleFromLevel":true}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + text: 'test', + segmentType: 'Text', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + { + segments: [ + { + isSelected: true, + segmentType: 'SelectionMarker', + format: {}, + }, + { + segmentType: 'Br', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + { + formatHolder: { + isSelected: false, + segmentType: 'SelectionMarker', + format: {}, + }, + levels: [ + { + listType: 'OL', + format: { + listStyleType: 'decimal', + startNumberOverride: undefined, + }, + dataset: { + editingInfo: + '{"applyListStyleFromLevel":false,"orderedStyleType":1}', + }, + }, + { + listType: 'OL', + format: { + listStyleType: 'lower-alpha', + startNumberOverride: 2, + }, + dataset: { + editingInfo: '{"applyListStyleFromLevel":true}', + }, + }, + ], + blockType: 'BlockGroup', + format: {}, + blockGroupType: 'ListItem', + blocks: [ + { + segments: [ + { + text: 'test', + segmentType: 'Text', + format: {}, + }, + ], + segmentFormat: {}, + blockType: 'Paragraph', + format: {}, + }, + ], + }, + ], + format: {}, + }; + runTest(model, false, expectedModel, false, 1); + }); });