Skip to content

Commit daf4c91

Browse files
committed
feat(docs-history): preserve drawing delete semantics
1 parent 5da6949 commit daf4c91

4 files changed

Lines changed: 126 additions & 13 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Copyright 2023-present DreamNum Co., Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { IRemoveDocDrawingCommandParams } from '../remove-doc-drawing.command';
18+
import { DrawingTypeEnum, ICommandService, ImageSourceType } from '@univerjs/core';
19+
import { DocHistoryAction, RichTextEditingMutation } from '@univerjs/docs';
20+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
21+
import { createFacadeTestBed } from '../../../facade/__tests__/create-test-bed';
22+
import { RemoveDocDrawingCommand } from '../remove-doc-drawing.command';
23+
24+
class MockImage {
25+
width = 800;
26+
height = 400;
27+
onload: (() => void) | null = null;
28+
onerror: (() => void) | null = null;
29+
30+
get src(): string {
31+
return '';
32+
}
33+
34+
set src(_value: string) {
35+
queueMicrotask(() => this.onload?.());
36+
}
37+
}
38+
39+
describe('RemoveDocDrawingCommand', () => {
40+
let testBed: ReturnType<typeof createFacadeTestBed>;
41+
42+
beforeEach(() => {
43+
vi.stubGlobal('Image', MockImage);
44+
testBed = createFacadeTestBed();
45+
});
46+
47+
afterEach(() => {
48+
testBed.univer.dispose();
49+
vi.unstubAllGlobals();
50+
});
51+
52+
it.each([
53+
[DrawingTypeEnum.DRAWING_IMAGE, DocHistoryAction.DeleteImage],
54+
[DrawingTypeEnum.DRAWING_SHAPE, DocHistoryAction.DeleteShape],
55+
[DrawingTypeEnum.DRAWING_CHART, DocHistoryAction.DeleteChart],
56+
])('records the drawing type %s in history metadata', async (drawingType, historyAction) => {
57+
const image = await testBed.document.insertImage({
58+
source: 'data:image/png;base64,image',
59+
imageSourceType: ImageSourceType.BASE64,
60+
width: 160,
61+
height: 90,
62+
textRange: {
63+
startOffset: 3,
64+
endOffset: 3,
65+
collapsed: true,
66+
segmentId: '',
67+
},
68+
});
69+
const commandService = testBed.injector.get(ICommandService);
70+
const mutationSpy = vi.spyOn(commandService, 'syncExecuteCommand');
71+
72+
const result = commandService.syncExecuteCommand<IRemoveDocDrawingCommandParams>(
73+
RemoveDocDrawingCommand.id,
74+
{
75+
unitId: 'test-doc',
76+
drawings: [{
77+
unitId: 'test-doc',
78+
subUnitId: 'test-doc',
79+
drawingId: image!.getId(),
80+
drawingType,
81+
}],
82+
}
83+
);
84+
85+
expect(result).toBe(true);
86+
expect(mutationSpy).toHaveBeenCalledWith(
87+
RichTextEditingMutation.id,
88+
expect.objectContaining({ historyActions: [historyAction] })
89+
);
90+
});
91+
});

packages/docs-drawing/src/commands/commands/remove-doc-drawing.command.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
* limitations under the License.
1515
*/
1616

17-
import type { DocumentDataModel, DrawingTypeEnum, IAccessor, ICommand, IDisposable, IMutationInfo, ITextRangeParam, JSONXActions } from '@univerjs/core';
17+
import type { DocumentDataModel, IAccessor, ICommand, IDisposable, IMutationInfo, ITextRangeParam, JSONXActions } from '@univerjs/core';
1818
import type { IRichTextEditingMutationParams } from '@univerjs/docs';
1919
import type { IDocDrawing } from '../../services/doc-drawing.service';
2020
import {
2121
CommandType,
22+
DrawingTypeEnum,
2223
getRichTextEditPath,
2324
ICommandService,
2425
IUndoRedoService,
@@ -29,7 +30,7 @@ import {
2930
TextXActionType,
3031
UniverInstanceType,
3132
} from '@univerjs/core';
32-
import { DocSelectionManagerService, getContentInsertRange, normalizeTextRange, RichTextEditingMutation } from '@univerjs/docs';
33+
import { DocHistoryAction, DocSelectionManagerService, getContentInsertRange, normalizeTextRange, RichTextEditingMutation } from '@univerjs/docs';
3334
import { IDocDrawingAdapterService } from '../../services/doc-drawing-adapter.service';
3435

3536
export interface IRemoveDocDrawingCommandParam {
@@ -136,9 +137,10 @@ export const RemoveDocDrawingCommand: ICommand = {
136137
const memoryCursor = new MemoryCursor();
137138
const cursorIndex = removeCustomBlocks[0]!.startIndex;
138139
const textRanges = [{ startOffset: cursorIndex, endOffset: cursorIndex }] as IRichTextEditingMutationParams['textRanges'];
140+
const historyActions = getHistoryActions(removeDrawings);
139141
const doMutation: IMutationInfo<IRichTextEditingMutationParams> = {
140142
id: RichTextEditingMutation.id,
141-
params: { unitId, actions: [], textRanges },
143+
params: { unitId, actions: [], textRanges, historyActions },
142144
};
143145
const rawActions: JSONXActions = [];
144146

@@ -174,6 +176,22 @@ export const RemoveDocDrawingCommand: ICommand = {
174176
},
175177
};
176178

179+
function getHistoryActions(drawings: IRemoveDocDrawingCommandParam[]): DocHistoryAction[] {
180+
const historyActions = drawings.flatMap((drawing): DocHistoryAction[] => {
181+
switch (drawing.drawingType) {
182+
case DrawingTypeEnum.DRAWING_IMAGE:
183+
return [DocHistoryAction.DeleteImage];
184+
case DrawingTypeEnum.DRAWING_SHAPE:
185+
return [DocHistoryAction.DeleteShape];
186+
case DrawingTypeEnum.DRAWING_CHART:
187+
return [DocHistoryAction.DeleteChart];
188+
default:
189+
return [];
190+
}
191+
});
192+
return [...new Set(historyActions)];
193+
}
194+
177195
function executeResourceMutationGroups(
178196
mutationGroups: Array<{ redoMutations: IMutationInfo[]; undoMutations: IMutationInfo[] }>,
179197
commandService: ICommandService

packages/docs/src/commands/mutations/core-editing.mutation.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,22 @@ import { DocSelectionManagerService } from '../../services/doc-selection-manager
2323
import { DocSkeletonManagerService } from '../../services/doc-skeleton-manager.service';
2424
import { DocStateEmitService } from '../../services/doc-state-emit.service';
2525

26+
export enum DocHistoryAction {
27+
DeleteChart = 'delete-chart',
28+
DeleteDivider = 'delete-divider',
29+
DeleteImage = 'delete-image',
30+
DeleteShape = 'delete-shape',
31+
EditTableCell = 'edit-table-cell',
32+
FormatParagraph = 'format-paragraph',
33+
InsertCustomRange = 'insert-custom-range',
34+
UpdateImage = 'update-image',
35+
UpdatePageLayout = 'update-page-layout',
36+
}
37+
2638
export interface IRichTextEditingMutationParams extends IMutationCommonParams {
2739
unitId: string;
2840
historyAction?: string;
41+
historyActions?: string[];
2942
actions: JSONXActions;
3043
textRanges: Nullable<ITextRangeWithStyle[]>;
3144
segmentId?: string;

packages/docs/src/index.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17-
export enum DocHistoryAction {
18-
DeleteDivider = 'delete-divider',
19-
EditTableCell = 'edit-table-cell',
20-
FormatParagraph = 'format-paragraph',
21-
InsertCustomRange = 'insert-custom-range',
22-
UpdateImage = 'update-image',
23-
UpdatePageLayout = 'update-page-layout',
24-
}
25-
2617
export { DeleteTextCommand, InsertTextCommand, UpdateTextCommand } from './commands/commands/core-editing.command';
2718
export type {
2819
IDeleteTextCommandParams,
@@ -47,7 +38,7 @@ export type { ISetSectionHeaderFooterLinkCommandParams } from './commands/comman
4738
export { UpdateDocumentParagraphStyleCommand } from './commands/commands/update-document-paragraph-style.command';
4839
export { DeleteDocumentSectionBreakCommand, InsertDocumentColumnBreakCommand, InsertDocumentSectionBreakCommand, UpdateDocumentSectionCommand } from './commands/commands/update-document-section.command';
4940
export type { IDeleteDocumentSectionBreakCommandParams, IDocumentSectionConfig, IDocumentSectionUpdate, IInsertDocumentColumnBreakCommandParams, IInsertDocumentSectionBreakCommandParams, IUpdateDocumentSectionCommandParams } from './commands/commands/update-document-section.command';
50-
export { RichTextEditingMutation } from './commands/mutations/core-editing.mutation';
41+
export { DocHistoryAction, RichTextEditingMutation } from './commands/mutations/core-editing.mutation';
5142
export type { IRichTextEditingMutationParams } from './commands/mutations/core-editing.mutation';
5243
export { SetTextSelectionsOperation } from './commands/operations/text-selection.operation';
5344
export type { ISetTextSelectionsOperationParams } from './commands/operations/text-selection.operation';

0 commit comments

Comments
 (0)