Skip to content

Commit a7bdb43

Browse files
authored
Content Model: Fix overwrite table cell bug (#2240)
1 parent 2bee980 commit a7bdb43

File tree

8 files changed

+34
-7
lines changed

8 files changed

+34
-7
lines changed

packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import type { ContentModelBlockGroup, DomToModelContext } from 'roosterjs-conten
77
* @internal
88
*/
99
export function addSelectionMarker(group: ContentModelBlockGroup, context: DomToModelContext) {
10-
const marker = createSelectionMarker(context.segmentFormat);
10+
const segmentFormat = {
11+
...context.defaultFormat,
12+
...context.segmentFormat,
13+
};
14+
const marker = createSelectionMarker(segmentFormat);
1115

1216
addDecorators(marker, context);
1317

14-
addSegment(group, marker, context.blockFormat);
18+
addSegment(group, marker, context.blockFormat, segmentFormat);
1519
}

packages-content-model/roosterjs-content-model-dom/lib/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export { createListLevel } from './modelApi/creators/createListLevel';
4949
export { addBlock } from './modelApi/common/addBlock';
5050
export { addCode } from './modelApi/common/addDecorators';
5151
export { addLink } from './modelApi/common/addDecorators';
52-
export { ensureParagraph } from './modelApi/common/ensureParagraph';
5352

5453
export { normalizeContentModel } from './modelApi/common/normalizeContentModel';
5554
export { isGeneralSegment } from './modelApi/common/isGeneralSegment';

packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/addSegment.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
ContentModelBlockGroup,
55
ContentModelParagraph,
66
ContentModelSegment,
7+
ContentModelSegmentFormat,
78
} from 'roosterjs-content-model-types';
89

910
/**
@@ -16,9 +17,10 @@ import type {
1617
export function addSegment(
1718
group: ContentModelBlockGroup,
1819
newSegment: ContentModelSegment,
19-
blockFormat?: ContentModelBlockFormat
20+
blockFormat?: ContentModelBlockFormat,
21+
segmentFormat?: ContentModelSegmentFormat
2022
): ContentModelParagraph {
21-
const paragraph = ensureParagraph(group, blockFormat);
23+
const paragraph = ensureParagraph(group, blockFormat, segmentFormat);
2224
const lastSegment = paragraph.segments[paragraph.segments.length - 1];
2325

2426
if (newSegment.segmentType == 'SelectionMarker') {

packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/ensureParagraph.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,26 @@ import type {
44
ContentModelBlockFormat,
55
ContentModelBlockGroup,
66
ContentModelParagraph,
7+
ContentModelSegmentFormat,
78
} from 'roosterjs-content-model-types';
89

910
/**
11+
* @internal
1012
* Ensure there is a Paragraph that can insert segments in a Content Model Block Group
1113
* @param group The parent block group of the target paragraph
1214
* @param blockFormat Format of the paragraph. This is only used if we need to create a new paragraph
1315
*/
1416
export function ensureParagraph(
1517
group: ContentModelBlockGroup,
16-
blockFormat?: ContentModelBlockFormat
18+
blockFormat?: ContentModelBlockFormat,
19+
segmentFormat?: ContentModelSegmentFormat
1720
): ContentModelParagraph {
1821
const lastBlock = group.blocks[group.blocks.length - 1];
1922

2023
if (lastBlock?.blockType == 'Paragraph') {
2124
return lastBlock;
2225
} else {
23-
const paragraph = createParagraph(true, blockFormat);
26+
const paragraph = createParagraph(true, blockFormat, segmentFormat);
2427
addBlock(group, paragraph);
2528

2629
return paragraph;

packages-content-model/roosterjs-content-model-dom/test/domToModel/processors/childProcessorTest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ describe('childProcessor', () => {
325325
{ segmentType: 'SelectionMarker', format: { a: 'b' } as any, isSelected: true },
326326
],
327327
isImplicit: true,
328+
segmentFormat: { a: 'b' } as any,
328329
format: {},
329330
});
330331
});

packages-content-model/roosterjs-content-model-dom/test/domToModel/utils/addSelectionMarkerTest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ describe('addSelectionMarker', () => {
5252
format: { fontWeight: 'bold' },
5353
},
5454
],
55+
segmentFormat: { fontWeight: 'bold' },
5556
},
5657
],
5758
});

packages-content-model/roosterjs-content-model-plugins/lib/edit/keyboardInput.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { deleteSelection, isModifierKey } from 'roosterjs-content-model-core';
2+
import { normalizeContentModel } from 'roosterjs-content-model-dom';
23
import type { IContentModelEditor } from 'roosterjs-content-model-editor';
34
import type { DOMSelection } from 'roosterjs-content-model-types';
45

@@ -26,6 +27,8 @@ export function keyboardInput(editor: IContentModelEditor, rawEvent: KeyboardEve
2627
// We have deleted something, next input should inherit the segment format from deleted content, so set pending format here
2728
context.newPendingFormat = result.insertPoint?.marker.format;
2829

30+
normalizeContentModel(model);
31+
2932
// Do not preventDefault since we still want browser to handle the final input for now
3033
return true;
3134
} else {

packages-content-model/roosterjs-content-model-plugins/test/edit/keyboardInputTest.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as deleteSelection from 'roosterjs-content-model-core/lib/publicApi/selection/deleteSelection';
2+
import * as normalizeContentModel from 'roosterjs-content-model-dom/lib/modelApi/common/normalizeContentModel';
23
import { IContentModelEditor } from 'roosterjs-content-model-editor';
34
import { keyboardInput } from '../../lib/edit/keyboardInput';
45
import {
@@ -14,6 +15,7 @@ describe('keyboardInput', () => {
1415
let getDOMSelectionSpy: jasmine.Spy;
1516
let deleteSelectionSpy: jasmine.Spy;
1617
let mockedModel: ContentModelDocument;
18+
let normalizeContentModelSpy: jasmine.Spy;
1719
let mockedContext: FormatWithContentModelContext;
1820
let formatResult: boolean | undefined;
1921

@@ -34,6 +36,7 @@ describe('keyboardInput', () => {
3436
});
3537
getDOMSelectionSpy = jasmine.createSpy('getDOMSelection');
3638
deleteSelectionSpy = spyOn(deleteSelection, 'deleteSelection');
39+
normalizeContentModelSpy = spyOn(normalizeContentModel, 'normalizeContentModel');
3740

3841
editor = {
3942
getDOMSelection: getDOMSelectionSpy,
@@ -69,6 +72,7 @@ describe('keyboardInput', () => {
6972
newEntities: [],
7073
newImages: [],
7174
});
75+
expect(normalizeContentModelSpy).not.toHaveBeenCalled();
7276
});
7377

7478
it('Letter input, expanded selection, no modifier key, deleteSelection returns not deleted', () => {
@@ -100,6 +104,7 @@ describe('keyboardInput', () => {
100104
clearModelCache: true,
101105
skipUndoSnapshot: true,
102106
});
107+
expect(normalizeContentModelSpy).not.toHaveBeenCalled();
103108
});
104109

105110
it('Letter input, expanded selection, no modifier key, deleteSelection returns range', () => {
@@ -132,6 +137,7 @@ describe('keyboardInput', () => {
132137
skipUndoSnapshot: true,
133138
newPendingFormat: undefined,
134139
});
140+
expect(normalizeContentModelSpy).toHaveBeenCalledWith(mockedModel);
135141
});
136142

137143
it('Letter input, table selection, no modifier key, deleteSelection returns range', () => {
@@ -161,6 +167,7 @@ describe('keyboardInput', () => {
161167
skipUndoSnapshot: true,
162168
newPendingFormat: undefined,
163169
});
170+
expect(normalizeContentModelSpy).toHaveBeenCalledWith(mockedModel);
164171
});
165172

166173
it('Letter input, image selection, no modifier key, deleteSelection returns range', () => {
@@ -190,6 +197,7 @@ describe('keyboardInput', () => {
190197
skipUndoSnapshot: true,
191198
newPendingFormat: undefined,
192199
});
200+
expect(normalizeContentModelSpy).toHaveBeenCalledWith(mockedModel);
193201
});
194202

195203
it('Letter input, no selection, no modifier key, deleteSelection returns range', () => {
@@ -214,6 +222,7 @@ describe('keyboardInput', () => {
214222
newEntities: [],
215223
newImages: [],
216224
});
225+
expect(normalizeContentModelSpy).not.toHaveBeenCalled();
217226
});
218227

219228
it('Letter input, expanded selection, has modifier key, deleteSelection returns range', () => {
@@ -244,6 +253,7 @@ describe('keyboardInput', () => {
244253
newEntities: [],
245254
newImages: [],
246255
});
256+
expect(normalizeContentModelSpy).not.toHaveBeenCalled();
247257
});
248258

249259
it('Space input, table selection, no modifier key, deleteSelection returns range', () => {
@@ -273,6 +283,7 @@ describe('keyboardInput', () => {
273283
skipUndoSnapshot: true,
274284
newPendingFormat: undefined,
275285
});
286+
expect(normalizeContentModelSpy).toHaveBeenCalledWith(mockedModel);
276287
});
277288

278289
it('Backspace input, table selection, no modifier key, deleteSelection returns range', () => {
@@ -299,6 +310,7 @@ describe('keyboardInput', () => {
299310
newEntities: [],
300311
newImages: [],
301312
});
313+
expect(normalizeContentModelSpy).not.toHaveBeenCalled();
302314
});
303315

304316
it('Enter input, table selection, no modifier key, deleteSelection returns range', () => {
@@ -328,6 +340,7 @@ describe('keyboardInput', () => {
328340
skipUndoSnapshot: true,
329341
newPendingFormat: undefined,
330342
});
343+
expect(normalizeContentModelSpy).toHaveBeenCalledWith(mockedModel);
331344
});
332345

333346
it('Letter input, expanded selection, no modifier key, deleteSelection returns range, has segment format', () => {
@@ -366,5 +379,6 @@ describe('keyboardInput', () => {
366379
skipUndoSnapshot: true,
367380
newPendingFormat: mockedFormat,
368381
});
382+
expect(normalizeContentModelSpy).toHaveBeenCalledWith(mockedModel);
369383
});
370384
});

0 commit comments

Comments
 (0)