diff --git a/packages/core/src/docs/data-model/text-x/build-utils/custom-decoration.ts b/packages/core/src/docs/data-model/text-x/build-utils/custom-decoration.ts new file mode 100644 index 00000000000..967f1bbd76f --- /dev/null +++ b/packages/core/src/docs/data-model/text-x/build-utils/custom-decoration.ts @@ -0,0 +1,109 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ITextRange } from '../../../../sheets/typedef'; +import type { DocumentDataModel } from '../../document-data-model'; +import { CustomDecorationType } from '../../../../types/interfaces'; +import { TextXActionType } from '../action-types'; +import { TextX } from '../text-x'; + +interface IAddCustomDecorationParam { + ranges: ITextRange[]; + id: string; + type: CustomDecorationType; +} + +export function addCustomDecorationTextX(param: IAddCustomDecorationParam) { + const { ranges, id, type } = param; + + const textX = new TextX(); + let cursor = 0; + + for (let i = 0; i < ranges.length; i++) { + const range = ranges[i]; + const { startOffset: start, endOffset: end } = range; + if (start > 0) { + textX.push({ + t: TextXActionType.RETAIN, + len: start - cursor, + }); + } + + textX.push({ + t: TextXActionType.RETAIN, + body: { + dataStream: '', + customDecorations: [{ + id, + type, + startIndex: 0, + endIndex: end - start - 1, + }], + }, + len: end - start, + }); + + cursor = end; + } + + return textX; +} + +export interface IDeleteCustomRangeParam { + id: string; + segmentId?: string; + documentDataModel: DocumentDataModel; +} + +export function deleteCustomDecorationTextX(params: IDeleteCustomRangeParam) { + const { id, segmentId, documentDataModel } = params; + const body = documentDataModel?.getBody(); + if (!documentDataModel || !body) { + return false; + } + + const decoration = documentDataModel.getSelfOrHeaderFooterModel(segmentId)?.getBody()?.customDecorations?.find((d) => d.id === id); + if (!decoration) { + return false; + } + + const textX = new TextX(); + const { startIndex, endIndex } = decoration; + const len = endIndex - startIndex + 1; + + textX.push({ + t: TextXActionType.RETAIN, + len: startIndex, + }); + + textX.push({ + t: TextXActionType.RETAIN, + len, + body: { + dataStream: '', + customDecorations: [ + { + startIndex: 0, + endIndex: len - 1, + id, + type: CustomDecorationType.DELETED, + }, + ], + }, + }); + + return textX; +} diff --git a/packages/core/src/docs/data-model/text-x/build-utils/index.ts b/packages/core/src/docs/data-model/text-x/build-utils/index.ts index 4cc24b0dc64..5e6664d7eba 100644 --- a/packages/core/src/docs/data-model/text-x/build-utils/index.ts +++ b/packages/core/src/docs/data-model/text-x/build-utils/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { addCustomDecorationTextX, deleteCustomDecorationTextX } from './custom-decoration'; import { copyCustomRange, getCustomRangesInterestsWithSelection, isIntersecting } from './custom-range'; import { changeParagraphBulletNestLevel, setParagraphBullet, switchParagraphBullet, toggleChecklistParagraph } from './paragraph'; import { fromPlainText, getPlainText, isEmptyDocument } from './parse'; @@ -29,6 +30,11 @@ export class BuildTextUtils { isIntersecting, }; + static customDecoration = { + add: addCustomDecorationTextX, + delete: deleteCustomDecorationTextX, + }; + static selection = { replace: replaceSelectionTextX, makeSelection, diff --git a/packages/docs-ui/src/basics/custom-decoration-factory.ts b/packages/docs-ui/src/basics/custom-decoration-factory.ts index bd6fb66458a..9458407b3eb 100644 --- a/packages/docs-ui/src/basics/custom-decoration-factory.ts +++ b/packages/docs-ui/src/basics/custom-decoration-factory.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import type { DocumentDataModel, IAccessor, IMutationInfo } from '@univerjs/core'; +import type { CustomDecorationType, DocumentDataModel, IAccessor, IMutationInfo } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import type { ITextRangeWithStyle } from '@univerjs/engine-render'; -import { CustomDecorationType, IUniverInstanceService, JSONX, TextX, TextXActionType, UniverInstanceType } from '@univerjs/core'; +import { BuildTextUtils, IUniverInstanceService, JSONX, UniverInstanceType } from '@univerjs/core'; import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; interface IAddCustomDecorationParam { @@ -37,39 +37,13 @@ export function addCustomDecorationFactory(param: IAddCustomDecorationParam) { unitId, actions: [], textRanges: undefined, + noHistory: true, + segmentId, }, }; - const textX = new TextX(); const jsonX = JSONX.getInstance(); - let cursor = 0; - - for (let i = 0; i < ranges.length; i++) { - const range = ranges[i]; - const { startOffset: start, endOffset: end } = range; - if (start > 0) { - textX.push({ - t: TextXActionType.RETAIN, - len: start - cursor, - }); - } - - textX.push({ - t: TextXActionType.RETAIN, - body: { - dataStream: '', - customDecorations: [{ - id, - type, - startIndex: 0, - endIndex: end - start - 1, - }], - }, - len: end - start, - }); - - cursor = end; - } + const textX = BuildTextUtils.customDecoration.add({ ranges, id, type }); doMutation.params.actions = jsonX.editOp(textX.serialize()); return doMutation; @@ -125,13 +99,7 @@ export function deleteCustomDecorationFactory(accessor: IAccessor, params: IDele const univerInstanceService = accessor.get(IUniverInstanceService); const documentDataModel = univerInstanceService.getUnit(unitId); - const body = documentDataModel?.getBody(); - if (!documentDataModel || !body) { - return false; - } - - const decoration = documentDataModel.getBody()?.customDecorations?.find((d) => d.id === id); - if (!decoration) { + if (!documentDataModel) { return false; } @@ -141,34 +109,16 @@ export function deleteCustomDecorationFactory(accessor: IAccessor, params: IDele unitId, actions: [], textRanges: undefined, + noHistory: true, + segmentId, }, }; - const textX = new TextX(); + const textX = BuildTextUtils.customDecoration.delete({ id, segmentId, documentDataModel }); + if (!textX) { + return false; + } const jsonX = JSONX.getInstance(); - const { startIndex, endIndex } = decoration; - const len = endIndex - startIndex + 1; - - textX.push({ - t: TextXActionType.RETAIN, - len: startIndex, - }); - - textX.push({ - t: TextXActionType.RETAIN, - len, - body: { - dataStream: '', - customDecorations: [ - { - startIndex: 0, - endIndex: len - 1, - id, - type: CustomDecorationType.DELETED, - }, - ], - }, - }); doMutation.params.actions = jsonX.editOp(textX.serialize()); return doMutation;