From aaa58f674a1dd099d31cded9557cf29a0a6ad169 Mon Sep 17 00:00:00 2001 From: Jiuqing Song Date: Wed, 5 Jun 2024 11:01:46 -0700 Subject: [PATCH] improve --- .../roosterjs-content-model-dom/lib/index.ts | 4 +-- .../lib/modelApi/editing/deleteSelection.ts | 17 +++------- .../lib/modelApi/editing/runEditSteps.ts | 25 ++++++++++++++ .../lib/edit/EditPlugin.ts | 10 ++---- .../lib/edit/keyboardEnter.ts | 34 +++++++------------ .../test/edit/EditPluginTest.ts | 10 +++--- .../edit/inputSteps/handleEnterOnListTest.ts | 2 +- .../test/edit/keyboardEnterTest.ts | 2 +- 8 files changed, 55 insertions(+), 49 deletions(-) create mode 100644 packages/roosterjs-content-model-dom/lib/modelApi/editing/runEditSteps.ts diff --git a/packages/roosterjs-content-model-dom/lib/index.ts b/packages/roosterjs-content-model-dom/lib/index.ts index f10c7245898..9aa77b83c05 100644 --- a/packages/roosterjs-content-model-dom/lib/index.ts +++ b/packages/roosterjs-content-model-dom/lib/index.ts @@ -102,8 +102,6 @@ export { cacheGetEventData } from './domUtils/event/cacheGetEventData'; export { isBlockGroupOfType } from './modelApi/typeCheck/isBlockGroupOfType'; -export { getClosestAncestorBlockGroupIndex } from './modelApi/editing/getClosestAncestorBlockGroupIndex'; - export { iterateSelections } from './modelApi/selection/iterateSelections'; export { getFirstSelectedListItem, @@ -134,6 +132,8 @@ export { setTableCellBackgroundColor } from './modelApi/editing/setTableCellBack export { retrieveModelFormatState } from './modelApi/editing/retrieveModelFormatState'; export { getListStyleTypeFromString } from './modelApi/editing/getListStyleTypeFromString'; export { getSegmentTextFormat } from './modelApi/editing/getSegmentTextFormat'; +export { getClosestAncestorBlockGroupIndex } from './modelApi/editing/getClosestAncestorBlockGroupIndex'; +export { runEditSteps } from './modelApi/editing/runEditSteps'; export { updateImageMetadata, getImageMetadata } from './modelApi/metadata/updateImageMetadata'; export { diff --git a/packages/roosterjs-content-model-dom/lib/modelApi/editing/deleteSelection.ts b/packages/roosterjs-content-model-dom/lib/modelApi/editing/deleteSelection.ts index adcd718f964..c97057efb06 100644 --- a/packages/roosterjs-content-model-dom/lib/modelApi/editing/deleteSelection.ts +++ b/packages/roosterjs-content-model-dom/lib/modelApi/editing/deleteSelection.ts @@ -1,12 +1,12 @@ import { deleteExpandedSelection } from './deleteExpandedSelection'; import { mutateBlock } from '../common/mutate'; +import { runEditSteps } from './runEditSteps'; import type { DeleteSelectionContext, DeleteSelectionResult, DeleteSelectionStep, FormatContentModelContext, ReadonlyContentModelDocument, - ValidDeleteSelectionContext, } from 'roosterjs-content-model-types'; /** @@ -22,23 +22,16 @@ export function deleteSelection( formatContext?: FormatContentModelContext ): DeleteSelectionResult { const context = deleteExpandedSelection(model, formatContext); + const steps = additionalSteps.filter( + (x: DeleteSelectionStep | null): x is DeleteSelectionStep => !!x + ); - additionalSteps.forEach(step => { - if (step && isValidDeleteSelectionContext(context)) { - step(context); - } - }); + runEditSteps(steps, context); mergeParagraphAfterDelete(context); return context; } -function isValidDeleteSelectionContext( - context: DeleteSelectionContext -): context is ValidDeleteSelectionContext { - return !!context.insertPoint; -} - // If we end up with multiple paragraphs impacted, we need to merge them function mergeParagraphAfterDelete(context: DeleteSelectionContext) { const { insertPoint, deleteResult, lastParagraph, lastTableContext } = context; diff --git a/packages/roosterjs-content-model-dom/lib/modelApi/editing/runEditSteps.ts b/packages/roosterjs-content-model-dom/lib/modelApi/editing/runEditSteps.ts new file mode 100644 index 00000000000..368e97fcbd5 --- /dev/null +++ b/packages/roosterjs-content-model-dom/lib/modelApi/editing/runEditSteps.ts @@ -0,0 +1,25 @@ +import type { + DeleteSelectionContext, + DeleteSelectionResult, + DeleteSelectionStep, + ValidDeleteSelectionContext, +} from 'roosterjs-content-model-types'; + +/** + * Run editing steps on top of a given context object which includes current insert point and previous editing result + * @param steps The editing steps to run + * @param context Context for the editing steps. + */ +export function runEditSteps(steps: DeleteSelectionStep[], context: DeleteSelectionResult) { + steps.forEach(step => { + if (step && isValidDeleteSelectionContext(context)) { + step(context); + } + }); +} + +function isValidDeleteSelectionContext( + context: DeleteSelectionContext +): context is ValidDeleteSelectionContext { + return !!context.insertPoint; +} diff --git a/packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts b/packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts index 5ee5b9232c6..add783a2ab1 100644 --- a/packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts +++ b/packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts @@ -26,7 +26,7 @@ export class EditPlugin implements EditorPlugin { private disposer: (() => void) | null = null; private shouldHandleNextInputEvent = false; private selectionAfterDelete: DOMSelection | null = null; - private handleEnterKey = false; + private handleNormalEnter = false; /** * Get name of this plugin @@ -43,7 +43,7 @@ export class EditPlugin implements EditorPlugin { */ initialize(editor: IEditor) { this.editor = editor; - this.handleEnterKey = this.editor.isExperimentalFeatureEnabled('PersistCache'); + this.handleNormalEnter = this.editor.isExperimentalFeatureEnabled('PersistCache'); if (editor.getEnvironment().isAndroid) { this.disposer = this.editor.attachDomEvent({ @@ -157,11 +157,7 @@ export class EditPlugin implements EditorPlugin { break; case 'Enter': - if (this.handleEnterKey) { - keyboardEnter(editor, rawEvent); - } else { - keyboardInput(editor, rawEvent); - } + keyboardEnter(editor, rawEvent, this.handleNormalEnter); break; default: diff --git a/packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts b/packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts index 07ed60355ca..ef765e5e231 100644 --- a/packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts +++ b/packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts @@ -1,17 +1,17 @@ import { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote'; -import { deleteSelection, normalizeContentModel } from 'roosterjs-content-model-dom'; +import { deleteSelection, normalizeContentModel, runEditSteps } from 'roosterjs-content-model-dom'; import { handleEnterOnList } from './inputSteps/handleEnterOnList'; import { handleEnterOnParagraph } from './inputSteps/handleEnterOnParagraph'; -import type { - DeleteSelectionContext, - IEditor, - ValidDeleteSelectionContext, -} from 'roosterjs-content-model-types'; +import type { IEditor } from 'roosterjs-content-model-types'; /** * @internal */ -export function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent) { +export function keyboardEnter( + editor: IEditor, + rawEvent: KeyboardEvent, + handleNormalEnter: boolean +) { const selection = editor.getDOMSelection(); editor.formatContentModel( @@ -25,15 +25,13 @@ export function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent) { // so further delete steps can keep working result.deleteResult = 'notDeleted'; - const steps = rawEvent.shiftKey - ? [handleEnterOnParagraph] - : [handleEnterOnList, deleteEmptyQuote, handleEnterOnParagraph]; + const steps = rawEvent.shiftKey ? [] : [handleEnterOnList, deleteEmptyQuote]; - steps.forEach(step => { - if (isValidDeleteSelectionContext(result)) { - step(result); - } - }); + if (handleNormalEnter) { + steps.push(handleEnterOnParagraph); + } + + runEditSteps(steps, result); } if (result.deleteResult == 'range') { @@ -54,9 +52,3 @@ export function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent) { } ); } - -function isValidDeleteSelectionContext( - context: DeleteSelectionContext -): context is ValidDeleteSelectionContext { - return !!context.insertPoint; -} diff --git a/packages/roosterjs-content-model-plugins/test/edit/EditPluginTest.ts b/packages/roosterjs-content-model-plugins/test/edit/EditPluginTest.ts index 0c895000cbb..9296ddbc17a 100644 --- a/packages/roosterjs-content-model-plugins/test/edit/EditPluginTest.ts +++ b/packages/roosterjs-content-model-plugins/test/edit/EditPluginTest.ts @@ -123,7 +123,7 @@ describe('EditPlugin', () => { expect(keyboardEnterSpy).not.toHaveBeenCalled(); }); - it('Enter, keyboardEnter not enabled', () => { + it('Enter, normal enter not enabled', () => { plugin = new EditPlugin(); const rawEvent = { which: 13, key: 'Enter' } as any; const addUndoSnapshotSpy = jasmine.createSpy('addUndoSnapshot'); @@ -138,12 +138,12 @@ describe('EditPlugin', () => { }); expect(keyboardDeleteSpy).not.toHaveBeenCalled(); - expect(keyboardInputSpy).toHaveBeenCalledWith(editor, rawEvent); - expect(keyboardEnterSpy).not.toHaveBeenCalled(); + expect(keyboardInputSpy).not.toHaveBeenCalled(); + expect(keyboardEnterSpy).toHaveBeenCalledWith(editor, rawEvent, false); expect(keyboardTabSpy).not.toHaveBeenCalled(); }); - it('Enter, keyboardEnter enabled', () => { + it('Enter, normal enter enabled', () => { isExperimentalFeatureEnabledSpy.and.callFake( (featureName: string) => featureName == 'PersistCache' ); @@ -162,7 +162,7 @@ describe('EditPlugin', () => { expect(keyboardDeleteSpy).not.toHaveBeenCalled(); expect(keyboardInputSpy).not.toHaveBeenCalled(); - expect(keyboardEnterSpy).toHaveBeenCalledWith(editor, rawEvent); + expect(keyboardEnterSpy).toHaveBeenCalledWith(editor, rawEvent, true); expect(keyboardTabSpy).not.toHaveBeenCalled(); }); 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 34a9ddd18d9..81aeb2f74ca 100644 --- a/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnListTest.ts +++ b/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnListTest.ts @@ -1828,7 +1828,7 @@ describe('handleEnterOnList - keyboardEnter', () => { }, }); - keyboardEnter(editor, mockedEvent); + keyboardEnter(editor, mockedEvent, true); }, input, expectedResult, diff --git a/packages/roosterjs-content-model-plugins/test/edit/keyboardEnterTest.ts b/packages/roosterjs-content-model-plugins/test/edit/keyboardEnterTest.ts index b18a6d0b6f6..8bfe3820021 100644 --- a/packages/roosterjs-content-model-plugins/test/edit/keyboardEnterTest.ts +++ b/packages/roosterjs-content-model-plugins/test/edit/keyboardEnterTest.ts @@ -60,7 +60,7 @@ describe('keyboardEnter', () => { expect(); }); - keyboardEnter(editor, rawEvent); + keyboardEnter(editor, rawEvent, true); expect(formatContentModelSpy).toHaveBeenCalledTimes(1); expect(input).toEqual(output);