Skip to content

Commit

Permalink
Update logic to decide if we need to merge a table on paste. (#2022)
Browse files Browse the repository at this point in the history
* Fix TableSelectionCopy

* update unit tests

* Fix 2

* address comment
  • Loading branch information
BryanValverdeU authored Aug 15, 2023
1 parent e1a5c28 commit a2b9804
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { ContentModelBlockFormat, FormatParser } from 'roosterjs-content-model-types';
import { domToContentModel } from 'roosterjs-content-model-dom';
import { formatWithContentModel } from './formatWithContentModel';
import { FormatWithContentModelContext } from '../../publicTypes/parameter/FormatWithContentModelContext';
import { IContentModelEditor } from '../../publicTypes/IContentModelEditor';
import { mergeModel } from '../../modelApi/common/mergeModel';
import { NodePosition } from 'roosterjs-editor-types';
import {
ContentModelBlockFormat,
ContentModelDocument,
FormatParser,
} from 'roosterjs-content-model-types';
import ContentModelBeforePasteEvent, {
ContentModelBeforePasteEventData,
} from '../../publicTypes/event/ContentModelBeforePasteEvent';
Expand Down Expand Up @@ -84,19 +89,8 @@ export default function paste(
formatWithContentModel(
editor,
'Paste',
(model, context) => {
if (customizedMerge) {
customizedMerge(model, pasteModel);
} else {
mergeModel(model, pasteModel, context, {
mergeFormat: applyCurrentFormat ? 'keepSourceEmphasisFormat' : 'none',
mergeTable:
pasteModel.blocks.length === 1 &&
pasteModel.blocks[0].blockType === 'Table',
});
}
return true;
},
(model, context) =>
mergePasteContent(model, context, pasteModel, applyCurrentFormat, customizedMerge),
{
changeSource: ChangeSource.Paste,
getChangeData: () => clipboardData,
Expand All @@ -105,6 +99,45 @@ export default function paste(
}
}

/**
* @internal
* Export only for unit test
*/
export function mergePasteContent(
model: ContentModelDocument,
context: FormatWithContentModelContext,
pasteModel: ContentModelDocument,
applyCurrentFormat: boolean,
customizedMerge:
| undefined
| ((source: ContentModelDocument, target: ContentModelDocument) => void)
): boolean {
if (customizedMerge) {
customizedMerge(model, pasteModel);
} else {
mergeModel(model, pasteModel, context, {
mergeFormat: applyCurrentFormat ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
});
}
return true;
}

function shouldMergeTable(pasteModel: ContentModelDocument): boolean | undefined {
// If model contains a table and a paragraph element after the table with a single BR segment, remove the Paragraph after the table
if (
pasteModel.blocks.length == 2 &&
pasteModel.blocks[0].blockType === 'Table' &&
pasteModel.blocks[1].blockType === 'Paragraph' &&
pasteModel.blocks[1].segments.length === 1 &&
pasteModel.blocks[1].segments[0].segmentType === 'Br'
) {
pasteModel.blocks.splice(1);
}
// Only merge table when the document contain a single table.
return pasteModel.blocks.length === 1 && pasteModel.blocks[0].blockType === 'Table';
}

function createBeforePasteEventData(
editor: IContentModelEditor,
clipboardData: ClipboardData,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as cloneModelFile from '../../../lib/modelApi/common/cloneModel';
import * as contentModelToDomFile from 'roosterjs-content-model-dom/lib/modelToDom/contentModelToDom';
import * as createRangeF from 'roosterjs-editor-dom/lib/selection/createRange';
import * as deleteSelectionsFile from '../../../lib/modelApi/edit/deleteSelection';
import * as extractClipboardItemsFile from 'roosterjs-editor-dom/lib/clipboard/extractClipboardItems';
import * as iterateSelectionsFile from '../../../lib/modelApi/selection/iterateSelections';
Expand Down Expand Up @@ -199,7 +200,7 @@ describe('ContentModelCopyPastePlugin |', () => {
it('Selection not Collapsed and table selection', () => {
// Arrange
const table = document.createElement('table');
table.id = 'image';
table.id = 'table';
// Arrange
selectionRangeExValue = <SelectionRangeEx>{
type: SelectionRangeTypes.TableSelection,
Expand All @@ -209,6 +210,7 @@ describe('ContentModelCopyPastePlugin |', () => {
table,
};

spyOn(createRangeF, 'default').and.callThrough();
spyOn(deleteSelectionsFile, 'deleteSelection');
spyOn(contentModelToDomFile, 'contentModelToDom').and.callFake(() => {
const container = document.createElement('div');
Expand All @@ -228,6 +230,7 @@ describe('ContentModelCopyPastePlugin |', () => {
domEvents.copy?.(<Event>{});

// Assert
expect(createRangeF.default).toHaveBeenCalledWith(<any>table.parentElement);
expect(getSelectionRangeEx).toHaveBeenCalled();
expect(deleteSelectionsFile.deleteSelection).not.toHaveBeenCalled();
expect(contentModelToDomFile.contentModelToDom).toHaveBeenCalledWith(
Expand Down Expand Up @@ -264,6 +267,7 @@ describe('ContentModelCopyPastePlugin |', () => {
image,
};

spyOn(createRangeF, 'default').and.callThrough();
spyOn(deleteSelectionsFile, 'deleteSelection');
spyOn(contentModelToDomFile, 'contentModelToDom').and.callFake(() => {
div.appendChild(image);
Expand All @@ -280,6 +284,7 @@ describe('ContentModelCopyPastePlugin |', () => {
domEvents.copy?.(<Event>{});

// Assert
expect(createRangeF.default).toHaveBeenCalledWith(<any>image);
expect(getSelectionRangeEx).toHaveBeenCalled();
expect(deleteSelectionsFile.deleteSelection).not.toHaveBeenCalled();
expect(contentModelToDomFile.contentModelToDom).toHaveBeenCalledWith(
Expand Down Expand Up @@ -394,7 +399,7 @@ describe('ContentModelCopyPastePlugin |', () => {
it('Selection not Collapsed and table selection', () => {
// Arrange
const table = document.createElement('table');
table.id = 'image';
table.id = 'table';
selectionRangeExValue = <SelectionRangeEx>{
type: SelectionRangeTypes.TableSelection,
ranges: [new Range()],
Expand All @@ -403,6 +408,7 @@ describe('ContentModelCopyPastePlugin |', () => {
table,
};

spyOn(createRangeF, 'default').and.callThrough();
spyOn(deleteSelectionsFile, 'deleteSelection');
spyOn(contentModelToDomFile, 'contentModelToDom').and.callFake(() => {
const container = document.createElement('div');
Expand All @@ -422,6 +428,7 @@ describe('ContentModelCopyPastePlugin |', () => {
domEvents.cut?.(<Event>{});

// Assert
expect(createRangeF.default).toHaveBeenCalledWith(<any>table.parentElement);
expect(getSelectionRangeEx).toHaveBeenCalled();
expect(contentModelToDomFile.contentModelToDom).toHaveBeenCalledWith(
document,
Expand Down Expand Up @@ -460,6 +467,7 @@ describe('ContentModelCopyPastePlugin |', () => {
image,
};

spyOn(createRangeF, 'default').and.callThrough();
spyOn(deleteSelectionsFile, 'deleteSelection');
spyOn(contentModelToDomFile, 'contentModelToDom').and.callFake(() => {
div.appendChild(image);
Expand All @@ -476,6 +484,7 @@ describe('ContentModelCopyPastePlugin |', () => {
domEvents.cut?.(<Event>{});

// Assert
expect(createRangeF.default).toHaveBeenCalledWith(<any>image);
expect(getSelectionRangeEx).toHaveBeenCalled();
expect(contentModelToDomFile.contentModelToDom).toHaveBeenCalledWith(
document,
Expand Down
Loading

0 comments on commit a2b9804

Please sign in to comment.