From ee44e5432c19c8957cdf0f3a5bc60a974254e203 Mon Sep 17 00:00:00 2001 From: Jiuqing Song Date: Thu, 28 Mar 2024 14:08:57 -0700 Subject: [PATCH] Leverage DOMInsertPoint, remove posContainer/offset (#2538) --- .../formatContentModel/formatContentModel.ts | 12 ++- .../lib/corePlugin/format/FormatPlugin.ts | 4 +- .../lib/corePlugin/undo/UndoPlugin.ts | 13 ++- .../formatContentModelTest.ts | 78 +++++++++++------ .../test/corePlugin/undo/UndoPluginTest.ts | 87 +++++++------------ .../domToModel/utils/addSelectionMarker.ts | 4 +- .../processors/childProcessorTest.ts | 12 ++- .../processors/textProcessorTest.ts | 18 ++-- .../utils/addSelectionMarkerTest.ts | 6 +- .../lib/pluginState/FormatPluginState.ts | 10 +-- .../lib/pluginState/UndoPluginState.ts | 10 +-- .../lib/editor/EditorAdapter.ts | 6 +- 12 files changed, 132 insertions(+), 128 deletions(-) diff --git a/packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts b/packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts index 6e3df1385c0..001309b4972 100644 --- a/packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts +++ b/packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts @@ -71,8 +71,10 @@ export const formatContentModel: FormatContentModel = (core, formatter, options) core.api.triggerEvent(core, eventData, true /*broadcast*/); if (canUndoByBackspace && selection?.type == 'range') { - core.undo.posContainer = selection.range.startContainer; - core.undo.posOffset = selection.range.startOffset; + core.undo.autoCompleteInsertPoint = { + node: selection.range.startContainer, + offset: selection.range.startOffset, + }; } if (shouldAddSnapshot) { @@ -123,8 +125,10 @@ function handlePendingFormat( if (pendingFormat && selection?.type == 'range' && selection.range.collapsed) { core.format.pendingFormat = { format: { ...pendingFormat }, - posContainer: selection.range.startContainer, - posOffset: selection.range.startOffset, + insertPoint: { + node: selection.range.startContainer, + offset: selection.range.startOffset, + }, }; } } diff --git a/packages/roosterjs-content-model-core/lib/corePlugin/format/FormatPlugin.ts b/packages/roosterjs-content-model-core/lib/corePlugin/format/FormatPlugin.ts index b4c0a279659..973bc685c52 100644 --- a/packages/roosterjs-content-model-core/lib/corePlugin/format/FormatPlugin.ts +++ b/packages/roosterjs-content-model-core/lib/corePlugin/format/FormatPlugin.ts @@ -163,9 +163,9 @@ class FormatPlugin implements PluginWithState { const selection = this.editor.getDOMSelection(); const range = selection?.type == 'range' && selection.range.collapsed ? selection.range : null; - const { posContainer, posOffset } = this.state.pendingFormat; + const { node, offset } = this.state.pendingFormat.insertPoint; - if (range && range.startContainer == posContainer && range.startOffset == posOffset) { + if (range && range.startContainer == node && range.startOffset == offset) { result = true; } } diff --git a/packages/roosterjs-content-model-core/lib/corePlugin/undo/UndoPlugin.ts b/packages/roosterjs-content-model-core/lib/corePlugin/undo/UndoPlugin.ts index 9eccc9f6f5a..df553aa6f57 100644 --- a/packages/roosterjs-content-model-core/lib/corePlugin/undo/UndoPlugin.ts +++ b/packages/roosterjs-content-model-core/lib/corePlugin/undo/UndoPlugin.ts @@ -30,8 +30,7 @@ class UndoPlugin implements PluginWithState { snapshotsManager: createSnapshotsManager(options.snapshots), isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }; } @@ -129,8 +128,7 @@ class UndoPlugin implements PluginWithState { if (evt.key == Backspace && !evt.ctrlKey && this.canUndoAutoComplete(editor)) { evt.preventDefault(); undo(editor); - this.state.posContainer = null; - this.state.posOffset = null; + this.state.autoCompleteInsertPoint = null; this.state.lastKeyPress = evt.key; } else if (!evt.defaultPrevented) { const selection = editor.getDOMSelection(); @@ -232,15 +230,14 @@ class UndoPlugin implements PluginWithState { this.state.snapshotsManager.canUndoAutoComplete() && selection?.type == 'range' && selection.range.collapsed && - selection.range.startContainer == this.state.posContainer && - selection.range.startOffset == this.state.posOffset + selection.range.startContainer == this.state.autoCompleteInsertPoint?.node && + selection.range.startOffset == this.state.autoCompleteInsertPoint.offset ); } private addUndoSnapshot() { this.editor?.takeSnapshot(); - this.state.posContainer = null; - this.state.posOffset = null; + this.state.autoCompleteInsertPoint = null; } private isCtrlOrMetaPressed(editor: IEditor, event: KeyboardEvent) { diff --git a/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts b/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts index 0a57860e19d..32b650ad466 100644 --- a/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts +++ b/packages/roosterjs-content-model-core/test/coreApi/formatContentModel/formatContentModelTest.ts @@ -583,8 +583,10 @@ describe('formatContentModel', () => { it('Has pending format, callback returns true, preserve pending format', () => { core.format.pendingFormat = { format: mockedFormat1, - posContainer: mockedStartContainer1, - posOffset: mockedStartOffset1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, }; formatContentModel(core, (model, context) => { @@ -594,16 +596,20 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat1, - posContainer: mockedStartContainer2, - posOffset: mockedStartOffset2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, } as any); }); it('Has pending format, callback returns false, preserve pending format', () => { core.format.pendingFormat = { format: mockedFormat1, - posContainer: mockedStartContainer1, - posOffset: mockedStartOffset1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, }; formatContentModel(core, (model, context) => { @@ -613,8 +619,10 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat1, - posContainer: mockedStartContainer2, - posOffset: mockedStartOffset2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, } as any); }); @@ -626,8 +634,10 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat2, - posContainer: mockedStartContainer2, - posOffset: mockedStartOffset2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, }); }); @@ -639,16 +649,20 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat2, - posContainer: mockedStartContainer2, - posOffset: mockedStartOffset2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, }); }); it('Has pending format, callback returns true, new format', () => { core.format.pendingFormat = { format: mockedFormat1, - posContainer: mockedStartContainer1, - posOffset: mockedStartOffset1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, }; formatContentModel(core, (model, context) => { @@ -658,16 +672,20 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat2, - posContainer: mockedStartContainer2, - posOffset: mockedStartOffset2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, }); }); it('Has pending format, callback returns false, new format', () => { core.format.pendingFormat = { format: mockedFormat1, - posContainer: mockedStartContainer1, - posOffset: mockedStartOffset1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, }; formatContentModel(core, (model, context) => { @@ -677,16 +695,20 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat2, - posContainer: mockedStartContainer2, - posOffset: mockedStartOffset2, + insertPoint: { + node: mockedStartContainer2, + offset: mockedStartOffset2, + }, }); }); it('Has pending format, callback returns false, preserve format, selection is not collapsed', () => { core.format.pendingFormat = { format: mockedFormat1, - posContainer: mockedStartContainer1, - posOffset: mockedStartOffset1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, }; core.api.getDOMSelection = () => @@ -706,8 +728,10 @@ describe('formatContentModel', () => { expect(core.format.pendingFormat).toEqual({ format: mockedFormat1, - posContainer: mockedStartContainer1, - posOffset: mockedStartOffset1, + insertPoint: { + node: mockedStartContainer1, + offset: mockedStartOffset1, + }, }); }); }); @@ -809,8 +833,10 @@ describe('formatContentModel', () => { expect(core.undo).toEqual({ isNested: false, snapshotsManager: {}, - posContainer: mockedContainer, - posOffset: mockedOffset, + autoCompleteInsertPoint: { + node: mockedContainer, + offset: mockedOffset, + }, } as any); }); diff --git a/packages/roosterjs-content-model-core/test/corePlugin/undo/UndoPluginTest.ts b/packages/roosterjs-content-model-core/test/corePlugin/undo/UndoPluginTest.ts index 1309523cdda..eb0cf93c732 100644 --- a/packages/roosterjs-content-model-core/test/corePlugin/undo/UndoPluginTest.ts +++ b/packages/roosterjs-content-model-core/test/corePlugin/undo/UndoPluginTest.ts @@ -58,8 +58,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(createSnapshotsManagerSpy).toHaveBeenCalledWith(undefined); @@ -81,8 +80,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(createSnapshotsManagerSpy).toHaveBeenCalledWith(mockedSnapshots); @@ -217,8 +215,7 @@ describe('UndoPlugin', () => { it('Not handled exclusively for KeyDown event, selection is not the same', () => { const state = plugin.getState(); - state.posContainer = 'P1' as any; - state.posOffset = 'O1' as any; + state.autoCompleteInsertPoint = { node: 'P1' as any, offset: 'O1' as any }; canUndoAutoCompleteSpy.and.returnValue(true); getDOMSelectionSpy.and.returnValue({ @@ -245,8 +242,7 @@ describe('UndoPlugin', () => { it('Handled exclusively for KeyDown event', () => { const state = plugin.getState(); - state.posContainer = 'P1' as any; - state.posOffset = 'O1' as any; + state.autoCompleteInsertPoint = { node: 'P1' as any, offset: 'O1' as any }; canUndoAutoCompleteSpy.and.returnValue(true); getDOMSelectionSpy.and.returnValue({ @@ -296,8 +292,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalse(); @@ -318,8 +313,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalse(); @@ -340,8 +334,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalse(); @@ -362,8 +355,7 @@ describe('UndoPlugin', () => { const state = plugin.getState(); - state.posContainer = 'C1' as any; - state.posOffset = 'O1' as any; + state.autoCompleteInsertPoint = { node: 'C1' as any, offset: 'O1' as any }; const preventDefaultSpy = jasmine.createSpy('preventDefault'); @@ -384,8 +376,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'Backspace', }); expect(mockedSnapshotsManager.hasNewContent).toBeFalse(); @@ -418,8 +409,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'Backspace', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -448,8 +438,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'Delete', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -478,8 +467,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -511,8 +499,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -545,8 +532,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'Backspace', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -576,8 +562,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -611,8 +596,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'Enter', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -646,8 +630,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'A', }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -677,8 +660,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: ' ', }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -708,8 +690,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: ' ', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -736,8 +717,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'Enter', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -764,8 +744,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'A', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -789,8 +768,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -815,8 +793,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: true, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -838,8 +815,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -861,8 +837,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -884,8 +859,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeFalsy(); @@ -907,8 +881,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: null, }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -935,8 +908,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'B', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); @@ -963,8 +935,7 @@ describe('UndoPlugin', () => { snapshotsManager: mockedSnapshotsManager, isRestoring: false, isNested: false, - posContainer: null, - posOffset: null, + autoCompleteInsertPoint: null, lastKeyPress: 'A', }); expect(mockedSnapshotsManager.hasNewContent).toBeTrue(); diff --git a/packages/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts b/packages/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts index 9c23e18e7ca..5f750aa301c 100644 --- a/packages/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts +++ b/packages/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts @@ -34,8 +34,8 @@ export function addSelectionMarker( const pendingFormat = context.pendingFormat && - context.pendingFormat.posContainer === container && - context.pendingFormat.posOffset === offset + context.pendingFormat.insertPoint.node === container && + context.pendingFormat.insertPoint.offset === offset ? context.pendingFormat.format : undefined; const segmentFormat = { diff --git a/packages/roosterjs-content-model-dom/test/domToModel/processors/childProcessorTest.ts b/packages/roosterjs-content-model-dom/test/domToModel/processors/childProcessorTest.ts index f34c80383cc..64124c3a65e 100644 --- a/packages/roosterjs-content-model-dom/test/domToModel/processors/childProcessorTest.ts +++ b/packages/roosterjs-content-model-dom/test/domToModel/processors/childProcessorTest.ts @@ -127,8 +127,10 @@ describe('childProcessor', () => { format: { a: 'a', } as any, - posContainer: div, - posOffset: 0, + insertPoint: { + node: div, + offset: 0, + }, }; childProcessor(doc, div, context); @@ -173,8 +175,10 @@ describe('childProcessor', () => { format: { a: 'a', } as any, - posContainer: div, - posOffset: 1, + insertPoint: { + node: div, + offset: 1, + }, }; childProcessor(doc, div, context); diff --git a/packages/roosterjs-content-model-dom/test/domToModel/processors/textProcessorTest.ts b/packages/roosterjs-content-model-dom/test/domToModel/processors/textProcessorTest.ts index b84b8a14172..f264ce94157 100644 --- a/packages/roosterjs-content-model-dom/test/domToModel/processors/textProcessorTest.ts +++ b/packages/roosterjs-content-model-dom/test/domToModel/processors/textProcessorTest.ts @@ -754,8 +754,10 @@ describe('textProcessor', () => { format: { a: 'a', } as any, - posContainer: text, - posOffset: 2, + insertPoint: { + node: text, + offset: 2, + }, }; textProcessor(doc, text, context); @@ -813,8 +815,10 @@ describe('textProcessor', () => { format: { a: 'a', } as any, - posContainer: text, - posOffset: 3, + insertPoint: { + node: text, + offset: 3, + }, }; textProcessor(doc, text, context); @@ -874,8 +878,10 @@ describe('textProcessor', () => { format: { a: 'a', } as any, - posContainer: text, - posOffset: 3, + insertPoint: { + node: text, + offset: 3, + }, }; textProcessor(doc, text, context); diff --git a/packages/roosterjs-content-model-dom/test/domToModel/utils/addSelectionMarkerTest.ts b/packages/roosterjs-content-model-dom/test/domToModel/utils/addSelectionMarkerTest.ts index 9b83269e9ff..fb7f401f363 100644 --- a/packages/roosterjs-content-model-dom/test/domToModel/utils/addSelectionMarkerTest.ts +++ b/packages/roosterjs-content-model-dom/test/domToModel/utils/addSelectionMarkerTest.ts @@ -218,8 +218,10 @@ describe('addSelectionMarker', () => { c: 'c3', e: 'e', } as any, - posContainer: mockedContainer, - posOffset: mockedOffset, + insertPoint: { + node: mockedContainer, + offset: mockedOffset, + }, }, }); diff --git a/packages/roosterjs-content-model-types/lib/pluginState/FormatPluginState.ts b/packages/roosterjs-content-model-types/lib/pluginState/FormatPluginState.ts index 05749a346f6..e0581094541 100644 --- a/packages/roosterjs-content-model-types/lib/pluginState/FormatPluginState.ts +++ b/packages/roosterjs-content-model-types/lib/pluginState/FormatPluginState.ts @@ -1,3 +1,4 @@ +import type { DOMInsertPoint } from '../selection/DOMSelection'; import type { ContentModelSegmentFormat } from '../format/ContentModelSegmentFormat'; /** @@ -10,14 +11,9 @@ export interface PendingFormat { format: ContentModelSegmentFormat; /** - * Container node of pending format + * Insert point of pending format */ - posContainer: Node; - - /** - * Offset under container node of pending format - */ - posOffset: number; + insertPoint: DOMInsertPoint; } /** diff --git a/packages/roosterjs-content-model-types/lib/pluginState/UndoPluginState.ts b/packages/roosterjs-content-model-types/lib/pluginState/UndoPluginState.ts index 040e57d44f7..bf0ad3234ea 100644 --- a/packages/roosterjs-content-model-types/lib/pluginState/UndoPluginState.ts +++ b/packages/roosterjs-content-model-types/lib/pluginState/UndoPluginState.ts @@ -1,4 +1,5 @@ import type { SnapshotsManager } from '../parameter/SnapshotsManager'; +import type { DOMInsertPoint } from '../selection/DOMSelection'; /** * The state object for UndoPlugin @@ -20,14 +21,9 @@ export interface UndoPluginState { isNested: boolean; /** - * Container after last auto complete. Undo autoComplete only works if the current position matches this one + * Insert point after last auto complete. Undo autoComplete only works if the current position matches this one */ - posContainer: Node | null; - - /** - * Offset after last auto complete. Undo autoComplete only works if the current position matches this one - */ - posOffset: number | null; + autoCompleteInsertPoint: DOMInsertPoint | null; /** * Last key user pressed diff --git a/packages/roosterjs-editor-adapter/lib/editor/EditorAdapter.ts b/packages/roosterjs-editor-adapter/lib/editor/EditorAdapter.ts index 8ee4773dca3..5ada4b80731 100644 --- a/packages/roosterjs-editor-adapter/lib/editor/EditorAdapter.ts +++ b/packages/roosterjs-editor-adapter/lib/editor/EditorAdapter.ts @@ -772,8 +772,10 @@ export class EditorAdapter extends Editor implements ILegacyEditor { if (selection?.type == 'range') { core.undo.snapshotsManager.hasNewContent = false; - core.undo.posContainer = selection.range.startContainer; - core.undo.posOffset = selection.range.startOffset; + core.undo.autoCompleteInsertPoint = { + node: selection.range.startContainer, + offset: selection.range.startOffset, + }; } } }