From 5e2b68093834c09e9bdd21d1b65632a2cf67660a Mon Sep 17 00:00:00 2001 From: Bryan Valverde U Date: Thu, 11 Jul 2024 12:22:36 -0600 Subject: [PATCH] Fix #2734 by Setting List Metadata `applyListStyleFromLevel: true` when toggling a list (#2743) * init * Tests * add missing file --- .../lib/modelApi/list/setListType.ts | 12 ++++ .../test/modelApi/list/setListTypeTest.ts | 26 ++++---- .../publicApi/list/toggleNumberingTest.ts | 1 + .../autoFormat/list/keyboardListTrigger.ts | 18 ++++++ .../list/keyboardListTriggerTest.ts | 62 ++++++++++++++++--- 5 files changed, 99 insertions(+), 20 deletions(-) diff --git a/packages/roosterjs-content-model-api/lib/modelApi/list/setListType.ts b/packages/roosterjs-content-model-api/lib/modelApi/list/setListType.ts index 977f1d17118..1144f8aa1ae 100644 --- a/packages/roosterjs-content-model-api/lib/modelApi/list/setListType.ts +++ b/packages/roosterjs-content-model-api/lib/modelApi/list/setListType.ts @@ -6,6 +6,7 @@ import { mutateBlock, normalizeContentModel, setParagraphNotImplicit, + updateListMetadata, } from 'roosterjs-content-model-dom'; import type { ContentModelListItem, @@ -121,6 +122,17 @@ export function setListType( mutateBlock(parent).blocks.splice(index, 1, newListItem); existingListItems.push(newListItem); + + const levelIndex = newListItem.levels.length - 1; + const level = mutateBlock(newListItem).levels[levelIndex]; + + if (level) { + updateListMetadata(level, metadata => + Object.assign({}, metadata, { + applyListStyleFromLevel: true, + }) + ); + } } else { existingListItems.forEach( x => (mutateBlock(x).levels[0].format.marginBottom = '0px') diff --git a/packages/roosterjs-content-model-api/test/modelApi/list/setListTypeTest.ts b/packages/roosterjs-content-model-api/test/modelApi/list/setListTypeTest.ts index 2d9c7120c63..dc55413d65b 100644 --- a/packages/roosterjs-content-model-api/test/modelApi/list/setListTypeTest.ts +++ b/packages/roosterjs-content-model-api/test/modelApi/list/setListTypeTest.ts @@ -78,7 +78,7 @@ describe('indent', () => { marginTop: undefined, textAlign: undefined, }, - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, }, ], blocks: [para], @@ -138,7 +138,9 @@ describe('indent', () => { marginTop: '0px', textAlign: undefined, }, - dataset: {}, + dataset: { + editingInfo: '{"applyListStyleFromLevel":true}', + }, }, ], blocks: [para], @@ -364,7 +366,7 @@ describe('indent', () => { marginTop: undefined, textAlign: undefined, }, - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, }, ], blocks: [para3], @@ -420,7 +422,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { startNumberOverride: 1, direction: 'rtl', @@ -500,7 +502,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { startNumberOverride: 1, direction: undefined, @@ -529,7 +531,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { direction: undefined, marginBottom: undefined, @@ -584,7 +586,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { startNumberOverride: 1, direction: undefined, @@ -641,7 +643,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { startNumberOverride: 1, direction: undefined, @@ -669,7 +671,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { startNumberOverride: undefined, direction: undefined, @@ -697,7 +699,7 @@ describe('indent', () => { levels: [ { listType: 'OL', - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, format: { direction: undefined, marginBottom: undefined, @@ -779,7 +781,7 @@ describe('indent', () => { marginTop: undefined, textAlign: undefined, }, - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, }, ], formatHolder: { @@ -809,7 +811,7 @@ describe('indent', () => { marginTop: undefined, textAlign: undefined, }, - dataset: {}, + dataset: { editingInfo: '{"applyListStyleFromLevel":true}' }, }, ], formatHolder: { diff --git a/packages/roosterjs-content-model-api/test/publicApi/list/toggleNumberingTest.ts b/packages/roosterjs-content-model-api/test/publicApi/list/toggleNumberingTest.ts index a2056062992..febaeab11cc 100644 --- a/packages/roosterjs-content-model-api/test/publicApi/list/toggleNumberingTest.ts +++ b/packages/roosterjs-content-model-api/test/publicApi/list/toggleNumberingTest.ts @@ -1,6 +1,7 @@ import * as setListType from '../../../lib/modelApi/list/setListType'; import { IEditor } from 'roosterjs-content-model-types'; import { toggleNumbering } from '../../../lib/publicApi/list/toggleNumbering'; + import { ContentModelDocument, ContentModelFormatter, diff --git a/packages/roosterjs-content-model-plugins/lib/autoFormat/list/keyboardListTrigger.ts b/packages/roosterjs-content-model-plugins/lib/autoFormat/list/keyboardListTrigger.ts index 14ee7c25f28..a3d707c1f7a 100644 --- a/packages/roosterjs-content-model-plugins/lib/autoFormat/list/keyboardListTrigger.ts +++ b/packages/roosterjs-content-model-plugins/lib/autoFormat/list/keyboardListTrigger.ts @@ -1,10 +1,13 @@ import { getListTypeStyle } from './getListTypeStyle'; +import { getOperationalBlocks, isBlockGroupOfType } from 'roosterjs-content-model-dom'; import { + getListAnnounceData, setListType, setModelListStartNumber, setModelListStyle, } from 'roosterjs-content-model-api'; import type { + ContentModelListItem, FormatContentModelContext, ReadonlyContentModelDocument, ShallowMutableContentModelParagraph, @@ -26,6 +29,7 @@ export function keyboardListTrigger( const { listType, styleType, index } = listStyleType; triggerList(model, listType, styleType, index); context.canUndoByBackspace = true; + setAnnounceData(model, context); return true; } @@ -48,9 +52,23 @@ const triggerList = ( isOrderedList ? { orderedStyleType: styleType, + applyListStyleFromLevel: false, } : { unorderedStyleType: styleType, + applyListStyleFromLevel: false, } ); }; +function setAnnounceData(model: ReadonlyContentModelDocument, context: FormatContentModelContext) { + const [paragraphOrListItems] = getOperationalBlocks( + model, + ['ListItem'], + [] // Set stop types to be empty so we can find list items even cross the boundary of table, then we can always operation on the list item if any + ); + + if (paragraphOrListItems && isBlockGroupOfType(paragraphOrListItems.block, 'ListItem')) { + const { path, block } = paragraphOrListItems; + context.announceData = getListAnnounceData([block, ...path]); + } +} diff --git a/packages/roosterjs-content-model-plugins/test/autoFormat/list/keyboardListTriggerTest.ts b/packages/roosterjs-content-model-plugins/test/autoFormat/list/keyboardListTriggerTest.ts index a2cb74f5401..efcc84ef7e9 100644 --- a/packages/roosterjs-content-model-plugins/test/autoFormat/list/keyboardListTriggerTest.ts +++ b/packages/roosterjs-content-model-plugins/test/autoFormat/list/keyboardListTriggerTest.ts @@ -12,7 +12,8 @@ describe('keyboardListTrigger', () => { context: FormatContentModelContext, expectedResult: boolean, shouldSearchForBullet: boolean = true, - shouldSearchForNumbering: boolean = true + shouldSearchForNumbering: boolean = true, + expectedContext?: any ) { const result = keyboardListTrigger( model, @@ -22,6 +23,9 @@ describe('keyboardListTrigger', () => { shouldSearchForNumbering ); expect(result).toBe(expectedResult); + if (expectedContext) { + expect(context).toEqual(expectedContext); + } } it('trigger numbering list', () => { @@ -49,7 +53,16 @@ describe('keyboardListTrigger', () => { }, paragraph, { canUndoByBackspace: true } as any, - true + true /* expectedResult */, + undefined /* shouldSearchForBullet */, + undefined /* shouldSearchForNumbering */, + { + canUndoByBackspace: true, + announceData: { + defaultStrings: 'announceListItemNumbering', + formatStrings: ['1'], + }, + } ); }); @@ -118,7 +131,13 @@ describe('keyboardListTrigger', () => { }, paragraph, { canUndoByBackspace: true } as any, - true + true, + undefined /* shouldSearchForBullet */, + undefined /* shouldSearchForNumbering */, + { + canUndoByBackspace: true, + announceData: { defaultStrings: 'announceListItemNumbering', formatStrings: ['2'] }, + } ); }); @@ -147,7 +166,10 @@ describe('keyboardListTrigger', () => { }, paragraph, { canUndoByBackspace: true } as any, - false + false, + undefined /* shouldSearchForBullet */, + undefined /* shouldSearchForNumbering */, + { canUndoByBackspace: true } ); }); @@ -176,7 +198,13 @@ describe('keyboardListTrigger', () => { }, paragraph, { canUndoByBackspace: true } as any, - true + true, + undefined /* shouldSearchForBullet */, + undefined /* shouldSearchForNumbering */, + { + canUndoByBackspace: true, + announceData: { defaultStrings: 'announceListItemBullet' }, + } ); }); @@ -205,7 +233,10 @@ describe('keyboardListTrigger', () => { }, paragraph, {} as any, - false + false, + undefined, + undefined, + {} ); }); @@ -384,7 +415,16 @@ describe('keyboardListTrigger', () => { }, paragraph, { canUndoByBackspace: true } as any, - true + true, + undefined /* shouldSearchForBullet */, + undefined /* shouldSearchForNumbering */, + { + canUndoByBackspace: true, + announceData: { + defaultStrings: 'announceListItemNumbering', + formatStrings: ['3'], + }, + } ); }); @@ -493,7 +533,13 @@ describe('keyboardListTrigger', () => { }, paragraph, { canUndoByBackspace: true } as any, - true + true, + undefined /* shouldSearchForBullet */, + undefined /* shouldSearchForNumbering */, + { + canUndoByBackspace: true, + announceData: { defaultStrings: 'announceListItemNumbering', formatStrings: ['A'] }, + } ); }); });