UNPKG

@univerjs/docs-ui

Version:

Editor UI layer for Univer Docs.

1,229 lines (1,211 loc) • 877 kB
import { BaselineOffset, BlockType, BooleanNumber, BuildTextUtils, COLORS, ColorKit, CommandType, CustomRangeType, DEFAULT_DOCUMENT_PARAGRAPH_LINE_SPACING, DEFAULT_DOCUMENT_PARAGRAPH_SPACE_ABOVE, DEFAULT_DOCUMENT_PARAGRAPH_SPACE_BELOW, DEFAULT_EMPTY_DOCUMENT_VALUE, DEFAULT_STYLES, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DOCS_ZEN_EDITOR_UNIT_ID_KEY, DOC_RANGE_TYPE, DashStyleType, DataStreamTreeNodeType, DataStreamTreeTokenType, DependentOn, Direction, Disposable, DisposableCollection, DocumentFlavor, DrawingTypeEnum, EDITOR_ACTIVATED, FOCUSING_COMMENT_EDITOR, FOCUSING_COMMON_DRAWINGS, FOCUSING_DOC, FOCUSING_EDITOR_STANDALONE, FOCUSING_UNIVER_EDITOR, HorizontalAlign, ICommandService, IConfigService, IConfirmService, IContextService, ILogService, IUndoRedoService, IUniverInstanceService, Inject, Injector, InterceptorManager, JSONX, LRUMap, LocaleService, MODERN_DOCUMENT_DEFAULT_MARGIN, MODERN_DOCUMENT_WIDTH, MemoryCursor, ModernDocumentWidthMode, NAMED_STYLE_MAP, NamedStyleType, ObjectRelativeFromH, ObjectRelativeFromV, PAGE_SIZE, PAPER_TYPES, PRESET_LIST_TYPE, PageOrientType, Plugin, PositionedObjectLayoutType, PresetListType, QuickListTypeMap, RANGE_DIRECTION, Rectangle, RedoCommandId, RxDisposable, SHEET_EDITOR_UNITS, SliceBodyType, SpacingRule, TableAlignmentType, TableRowHeightRule, TableSizeType, TableTextWrapType, TextX, TextXActionType, ThemeService, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, VerticalAlign, checkForSubstrings, createIdentifier, createInterceptorKey, createInternalEditorID, debounce, deepCompare, fromEventSubject, generateRandomId, getBodySlice, getPlainText, isCommentEditorID, isInternalEditorID, isSafeUrl, merge, mergeOverrideWithDependencies, normalizeBody, sequenceExecuteAsync, skipParseTagNames, toDisposable, touchDependencies } from "@univerjs/core"; import { DocInterceptorService, DocSelectionManagerService, DocSkeletonManagerService, DocStateEmitService, RichTextEditingMutation, SetTextSelectionsOperation } from "@univerjs/docs"; import { CURSOR_TYPE, DeviceInputEventType, DocBackground, DocumentEditArea, DocumentSkeletonPageType, Documents, GlyphType, IRenderManagerService, Layer, Liquid, NORMAL_TEXT_SELECTION_PLUGIN_STYLE, PageLayoutType, Path, Rect, RegularPolygon, ScrollBar, ScrollTimer, Shape, TRANSFORM_CHANGE_OBSERVABLE_TYPE, UniverRenderEnginePlugin, Vector2, Viewport, getColor, getDocsTableRenderViewport, getLastColumn, getLastLine, getNextWheelZoomRatio, getNumberUnitValue, getOffsetRectForDom, getPageFromPath, getParagraphByGlyph, getSystemHighlightColor, getTableIdAndSliceIndex, hasListGlyph, isFirstGlyph, isIndentByGlyph, lineIterator, parseDataStreamToTree, pixelToPt, ptToPixel, pxToNum } from "@univerjs/engine-render"; import { BuiltInUIPart, COLOR_PICKER_COMPONENT, COMMON_LABEL_COMPONENT, ComponentManager, ContextMenuGroup, ContextMenuPanel, ContextMenuPosition, CopyCommand, CutCommand, FILE_PNG_CLIPBOARD_MIME_TYPE, FILE__BMP_CLIPBOARD_MIME_TYPE, FILE__JPEG_CLIPBOARD_MIME_TYPE, FILE__WEBP_CLIPBOARD_MIME_TYPE, FONT_FAMILY_COMPONENT, FONT_FAMILY_ITEM_COMPONENT, FONT_SIZE_COMPONENT, FONT_SIZE_LIST, HEADING_ITEM_COMPONENT, HEADING_LIST, HTML_CLIPBOARD_MIME_TYPE, ICanvasPopupService, IClipboardInterfaceService, IContextMenuService, ILayoutService, IMenuManagerService, IShortcutService, ISidebarService, IUIPartsService, KeyCode, MenuItemType, MenuManagerPosition, MetaKeys, PLAIN_TEXT_CLIPBOARD_MIME_TYPE, PasteCommand, RectPopup, RibbonInsertGroup, RibbonStartGroup, Slider, ToolbarItem, connectInjector, getMenuHiddenObservable, imageMimeTypeSet, useConfigValue, useDependency, useEvent, useObservable } from "@univerjs/ui"; import { ImageSourceType } from "@univerjs/drawing"; import { BehaviorSubject, Observable, Subject, animationFrameScheduler, combineLatest, distinctUntilChanged, filter, first, fromEvent, map, merge as merge$1, of, switchMap, take, takeUntil, throttleTime } from "rxjs"; import { AlignTextBothIcon, CatalogueIcon, DeleteIcon, DocSettingIcon, H1Icon, H2Icon, H3Icon, H4Icon, H5Icon, HorizontallyIcon, LeftIcon, LeftJustifyingIcon, RightJustifyingIcon, TextTypeIcon, TodoListDoubleIcon } from "@univerjs/icons"; import { bufferTime, filter as filter$1, map as map$1 } from "rxjs/operators"; import { createElement, forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react"; import { Button, Checkbox, InputNumber, Select, Tooltip, borderClassName, clsx, scrollbarClassName } from "@univerjs/design"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; //#region src/basics/docs-view-key.ts /** * Copyright 2023-present DreamNum Co., Ltd. * * 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. */ let DOCS_VIEW_KEY = /* @__PURE__ */ function(DOCS_VIEW_KEY) { DOCS_VIEW_KEY["MAIN"] = "__Document_Render_Main__"; DOCS_VIEW_KEY["BACKGROUND"] = "__Document_Render_Background__"; return DOCS_VIEW_KEY; }({}); let VIEWPORT_KEY = /* @__PURE__ */ function(VIEWPORT_KEY) { VIEWPORT_KEY["VIEW_MAIN"] = "viewMain"; VIEWPORT_KEY["VIEW_TOP"] = "viewTop"; VIEWPORT_KEY["VIEW_LEFT"] = "viewLeft"; VIEWPORT_KEY["VIEW_LEFT_TOP"] = "viewLeftTop"; return VIEWPORT_KEY; }({}); const DOCS_COMPONENT_BACKGROUND_LAYER_INDEX = 0; const DOCS_COMPONENT_MAIN_LAYER_INDEX = 2; const DOCS_COMPONENT_HEADER_LAYER_INDEX = 4; const DOCS_COMPONENT_DEFAULT_Z_INDEX = 10; const NORMAL_TEXT_SELECTION_PLUGIN_NAME = "normalTextSelectionPluginName"; //#endregion //#region src/basics/component-tools.ts function neoGetDocObject(renderContext) { const { mainComponent, scene, engine, components } = renderContext; return { document: mainComponent, docBackground: components.get("__Document_Render_Background__"), scene, engine }; } /** @deprecated After migrating to `RenderUnit`, use `neoGetDocObject` instead. */ function getDocObject(univerInstanceService, renderManagerService) { const documentModel = univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC); if (!documentModel) return null; const unitId = documentModel.getUnitId(); const currentRender = renderManagerService.getRenderById(unitId); if (currentRender == null) return; const { mainComponent, scene, engine, components } = currentRender; return { document: mainComponent, docBackground: components.get("__Document_Render_Background__"), scene, engine }; } function getDocObjectById(unitId, renderManagerService) { const currentRender = renderManagerService.getRenderById(unitId); if (currentRender == null) return; const { mainComponent, scene, engine, components } = currentRender; return { document: mainComponent, docBackground: components.get("__Document_Render_Background__"), scene, engine }; } //#endregion //#region src/basics/custom-decoration-factory.ts function addCustomDecorationFactory(param) { const { unitId, ranges, id, type, segmentId } = param; const doMutation = { id: RichTextEditingMutation.id, params: { unitId, actions: [], textRanges: void 0, segmentId } }; const jsonX = JSONX.getInstance(); const textX = BuildTextUtils.customDecoration.add({ ranges, id, type }); doMutation.params.actions = jsonX.editOp(textX.serialize()); return doMutation; } function addCustomDecorationBySelectionFactory(accessor, param) { const { segmentId, id, type, unitId: propUnitId } = param; const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const documentDataModel = propUnitId ? univerInstanceService.getUnit(propUnitId, UniverInstanceType.UNIVER_DOC) : univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC); if (!documentDataModel) return false; const unitId = documentDataModel.getUnitId(); const selections = docSelectionManagerService.getTextRanges({ unitId, subUnitId: unitId }); if (!selections) return false; if (!documentDataModel.getBody()) return false; return addCustomDecorationFactory({ unitId, ranges: selections, id, type, segmentId }); } function deleteCustomDecorationFactory(accessor, params) { const { unitId, id, segmentId } = params; const documentDataModel = accessor.get(IUniverInstanceService).getUnit(unitId); if (!documentDataModel) return false; const doMutation = { id: RichTextEditingMutation.id, params: { unitId, actions: [], textRanges: void 0, segmentId } }; const textX = BuildTextUtils.customDecoration.delete({ id, segmentId, documentDataModel }); if (!textX) return false; const jsonX = JSONX.getInstance(); doMutation.params.actions = jsonX.editOp(textX.serialize()); return doMutation; } //#endregion //#region src/basics/paragraph.ts function hasParagraphInTable(paragraph, tables) { return tables.some((table) => paragraph.startIndex > table.startIndex && paragraph.startIndex < table.endIndex); } function getTextRunAtPosition(body, position, defaultStyle, cacheStyle, isCellEditor) { const { textRuns = [], dataStream } = body; const isFormula = isCellEditor && dataStream.startsWith("="); const retTextRun = { st: 0, ed: 0, ts: {} }; if (isFormula) return retTextRun; for (let i = textRuns.length - 1; i >= 0; i--) { const textRun = textRuns[i]; const { st, ed } = textRun; if (position > st && position <= ed) { retTextRun.st = st; retTextRun.ed = ed; retTextRun.ts = { ...retTextRun.ts, ...textRun.ts }; } } if (position === 0) { const textRun = textRuns === null || textRuns === void 0 ? void 0 : textRuns[0]; if (textRun && textRun.st === 0) retTextRun.ts = { ...retTextRun.ts, ...textRun.ts }; } if (cacheStyle) retTextRun.ts = { ...retTextRun.ts, ...cacheStyle }; return retTextRun; } function getCustomRangeAtPosition(customRanges, position, extendRange) { if (extendRange) { const range = customRanges.find((customRange) => position >= customRange.startIndex && position <= customRange.endIndex + 1); return (range === null || range === void 0 ? void 0 : range.wholeEntity) ? null : range; } const range = customRanges.find((customRange) => position > customRange.startIndex && position <= customRange.endIndex); return (range === null || range === void 0 ? void 0 : range.wholeEntity) ? null : range; } function getCustomDecorationAtPosition(customDecorations, position) { return customDecorations.filter((customDecoration) => position > customDecoration.startIndex && position <= customDecoration.endIndex); } //#endregion //#region src/basics/transform-position.ts function docDrawingPositionToTransform(position) { return { left: position.positionH.posOffset, top: position.positionV.posOffset, width: position.size.width, height: position.size.height }; } function transformToDocDrawingPosition(transform, marginLeft = 0, marginTop = 0) { return { size: { width: transform.width, height: transform.height }, positionH: { relativeFrom: ObjectRelativeFromH.MARGIN, posOffset: (transform.left || 0) - marginLeft }, positionV: { relativeFrom: ObjectRelativeFromV.PAGE, posOffset: (transform.top || 0) - marginTop }, angle: transform.angle || 0 }; } //#endregion //#region \0@oxc-project+runtime@0.133.0/helpers/esm/typeof.js function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) { return typeof o; } : function(o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } //#endregion //#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPrimitive.js function toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } //#endregion //#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPropertyKey.js function toPropertyKey(t) { var i = toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } //#endregion //#region \0@oxc-project+runtime@0.133.0/helpers/esm/defineProperty.js function _defineProperty(e, r, t) { return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } //#endregion //#region \0@oxc-project+runtime@0.133.0/helpers/esm/decorateParam.js function __decorateParam(paramIndex, decorator) { return function(target, key) { decorator(target, key, paramIndex); }; } //#endregion //#region \0@oxc-project+runtime@0.133.0/helpers/esm/decorate.js function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } //#endregion //#region src/services/doc-auto-format.service.ts let DocAutoFormatService = class DocAutoFormatService extends Disposable { constructor(_univerInstanceService, _textSelectionManagerService) { super(); this._univerInstanceService = _univerInstanceService; this._textSelectionManagerService = _textSelectionManagerService; _defineProperty(this, "_matches", /* @__PURE__ */ new Map()); } registerAutoFormat(match) { const matchList = this._matches.get(match.id); if (matchList) { matchList.push(match); matchList.sort((a, b) => { var _b$priority, _a$priority; return ((_b$priority = b.priority) !== null && _b$priority !== void 0 ? _b$priority : 0) - ((_a$priority = a.priority) !== null && _a$priority !== void 0 ? _a$priority : 0); }); } else this._matches.set(match.id, [match]); return toDisposable(() => { const matchList = this._matches.get(match.id); if (matchList) { const index = matchList.findIndex((i) => i === match); if (index >= 0) matchList.splice(index, 1); } }); } onAutoFormat(id, params) { var _this$_matches$get, _docRanges$find; const autoFormats = (_this$_matches$get = this._matches.get(id)) !== null && _this$_matches$get !== void 0 ? _this$_matches$get : []; const unit = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC); const docRanges = this._textSelectionManagerService.getDocRanges(); const selection = (_docRanges$find = docRanges.find((range) => range.isActive)) !== null && _docRanges$find !== void 0 ? _docRanges$find : docRanges[0]; if (unit && selection) { var _doc$getBody$paragrap, _doc$getBody, _doc$getBody$dataStre, _doc$getBody2, _doc$getBody$customRa, _doc$getBody3, _matched$getMutations; const doc = unit.getSelfOrHeaderFooterModel(selection.segmentId); const context = { unit: doc, selection, isBody: !selection.segmentId, paragraphs: BuildTextUtils.range.getParagraphsInRange(selection, (_doc$getBody$paragrap = (_doc$getBody = doc.getBody()) === null || _doc$getBody === void 0 ? void 0 : _doc$getBody.paragraphs) !== null && _doc$getBody$paragrap !== void 0 ? _doc$getBody$paragrap : [], (_doc$getBody$dataStre = (_doc$getBody2 = doc.getBody()) === null || _doc$getBody2 === void 0 ? void 0 : _doc$getBody2.dataStream) !== null && _doc$getBody$dataStre !== void 0 ? _doc$getBody$dataStre : ""), customRanges: BuildTextUtils.customRange.getCustomRangesInterestsWithSelection(selection, (_doc$getBody$customRa = (_doc$getBody3 = doc.getBody()) === null || _doc$getBody3 === void 0 ? void 0 : _doc$getBody3.customRanges) !== null && _doc$getBody$customRa !== void 0 ? _doc$getBody$customRa : []), commandId: id, commandParams: params }; const matched = autoFormats.find((i) => i.match(context)); return (_matched$getMutations = matched === null || matched === void 0 ? void 0 : matched.getMutations(context)) !== null && _matched$getMutations !== void 0 ? _matched$getMutations : []; } return []; } }; DocAutoFormatService = __decorate([__decorateParam(0, IUniverInstanceService), __decorateParam(1, Inject(DocSelectionManagerService))], DocAutoFormatService); //#endregion //#region src/commands/commands/auto-format.command.ts const TabCommandId = "doc.command.tab"; const TabCommand = { id: TabCommandId, type: CommandType.COMMAND, async handler(accessor, params) { return (await sequenceExecuteAsync(accessor.get(DocAutoFormatService).onAutoFormat(TabCommand.id, params), accessor.get(ICommandService))).result; } }; const AfterSpaceCommandId = "doc.command.after-space"; const AfterSpaceCommand = { id: AfterSpaceCommandId, type: CommandType.COMMAND, async handler(accessor) { return (await sequenceExecuteAsync(accessor.get(DocAutoFormatService).onAutoFormat(AfterSpaceCommand.id), accessor.get(ICommandService))).result; } }; const EnterCommand = { id: "doc.command.enter", type: CommandType.COMMAND, async handler(accessor) { return (await sequenceExecuteAsync(accessor.get(DocAutoFormatService).onAutoFormat(EnterCommand.id), accessor.get(ICommandService))).result; } }; //#endregion //#region src/services/doc-menu-style.service.ts const BODY_DEFAULT_FONTSIZE = 11; const HEADER_FOOTER_DEFAULT_FONTSIZE = 9; const DEFAULT_TEXT_STYLE = { /** * fontFamily */ ff: "Arial", /** * fontSize */ fs: BODY_DEFAULT_FONTSIZE }; let DocMenuStyleService = class DocMenuStyleService extends Disposable { constructor(_textSelectionManagerService, _univerInstanceService, _renderManagerService) { super(); this._textSelectionManagerService = _textSelectionManagerService; this._univerInstanceService = _univerInstanceService; this._renderManagerService = _renderManagerService; _defineProperty(this, "_cacheStyle", null); this._init(); } _init() { this._listenDocRangeChange(); } _listenDocRangeChange() { this.disposeWithMe(this._textSelectionManagerService.textSelection$.subscribe(() => { this._clearStyleCache(); })); } getStyleCache() { return this._cacheStyle; } getDefaultStyle() { var _this$_renderManagerS; const docDataModel = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC); if (docDataModel == null) return { ...DEFAULT_TEXT_STYLE }; const unitId = docDataModel === null || docDataModel === void 0 ? void 0 : docDataModel.getUnitId(); const docSkeletonManagerService = (_this$_renderManagerS = this._renderManagerService.getRenderById(unitId)) === null || _this$_renderManagerS === void 0 ? void 0 : _this$_renderManagerS.with(DocSkeletonManagerService); const docViewModel = docSkeletonManagerService === null || docSkeletonManagerService === void 0 ? void 0 : docSkeletonManagerService.getViewModel(); if (docViewModel == null) return { ...DEFAULT_TEXT_STYLE }; if (docViewModel.getEditArea() === DocumentEditArea.BODY) return { ...DEFAULT_TEXT_STYLE }; else return { ...DEFAULT_TEXT_STYLE, fs: HEADER_FOOTER_DEFAULT_FONTSIZE }; } setStyleCache(style) { this._cacheStyle = { ...this._cacheStyle, ...style }; } _clearStyleCache() { this._cacheStyle = null; } }; DocMenuStyleService = __decorate([ __decorateParam(0, Inject(DocSelectionManagerService)), __decorateParam(1, IUniverInstanceService), __decorateParam(2, IRenderManagerService) ], DocMenuStyleService); //#endregion //#region src/commands/util.ts /** * Get the skeleton of the command's target. * @param accessor The injection accessor. * @param unitId Unit ID. */ function getCommandSkeleton(accessor, unitId) { var _renderManagerService; return (_renderManagerService = accessor.get(IRenderManagerService).getRenderById(unitId)) === null || _renderManagerService === void 0 ? void 0 : _renderManagerService.with(DocSkeletonManagerService); } function getRichTextEditPath(docDataModel, segmentId = "") { if (!segmentId) return ["body"]; const { headers, footers } = docDataModel.getSnapshot(); if (headers == null && footers == null) throw new Error("Document data model must have headers or footers when update by segment id"); if ((headers === null || headers === void 0 ? void 0 : headers[segmentId]) != null) return [ "headers", segmentId, "body" ]; else if ((footers === null || footers === void 0 ? void 0 : footers[segmentId]) != null) return [ "footers", segmentId, "body" ]; else throw new Error("Segment id not found in headers or footers"); } //#endregion //#region src/commands/commands/break-line.command.ts function generateParagraphs(dataStream, prevParagraph, borderBottom) { const paragraphs = []; for (let i = 0, len = dataStream.length; i < len; i++) { if (dataStream[i] !== DataStreamTreeTokenType.PARAGRAPH) continue; paragraphs.push({ startIndex: i }); } if (prevParagraph) for (const paragraph of paragraphs) { if (prevParagraph.bullet) paragraph.bullet = Tools.deepClone(prevParagraph.bullet); if (prevParagraph.paragraphStyle) { paragraph.paragraphStyle = Tools.deepClone(prevParagraph.paragraphStyle); delete paragraph.paragraphStyle.borderBottom; if (prevParagraph.paragraphStyle.headingId) paragraph.paragraphStyle.headingId = generateRandomId(6); } } if (borderBottom) for (const paragraph of paragraphs) { if (!paragraph.paragraphStyle) paragraph.paragraphStyle = {}; paragraph.paragraphStyle.borderBottom = borderBottom; } return paragraphs; } const BreakLineCommand = { id: "doc.command.break-line", type: CommandType.COMMAND, handler: (accessor, params) => { var _params$textRange, _originBody$paragraph, _prevParagraph$bullet, _prevParagraph$paragr; const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const commandService = accessor.get(ICommandService); const docMenuStyleService = accessor.get(DocMenuStyleService); const activeTextRange = (_params$textRange = params === null || params === void 0 ? void 0 : params.textRange) !== null && _params$textRange !== void 0 ? _params$textRange : docSelectionManagerService.getActiveTextRange(); const rectRanges = docSelectionManagerService.getRectRanges(); if (activeTextRange == null) return false; if (rectRanges && rectRanges.length) { const { startOffset } = activeTextRange; docSelectionManagerService.replaceDocRanges([{ startOffset, endOffset: startOffset }]); return true; } const { horizontalLine } = params !== null && params !== void 0 ? params : {}; const { segmentId } = activeTextRange; const docDataModel = univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC); const originBody = docDataModel === null || docDataModel === void 0 ? void 0 : docDataModel.getSelfOrHeaderFooterModel(segmentId !== null && segmentId !== void 0 ? segmentId : "").getBody(); if (docDataModel == null || originBody == null) return false; const unitId = docDataModel.getUnitId(); const { startOffset, endOffset } = activeTextRange; const prevParagraph = ((_originBody$paragraph = originBody.paragraphs) !== null && _originBody$paragraph !== void 0 ? _originBody$paragraph : []).find((p) => p.startIndex >= startOffset); if (!prevParagraph) return false; const isAtParagraphEnd = startOffset === prevParagraph.startIndex; const prevParagraphIndex = prevParagraph.startIndex; const curTextRun = getTextRunAtPosition(originBody, endOffset, docMenuStyleService.getDefaultStyle(), docMenuStyleService.getStyleCache()); const insertBody = { dataStream: DataStreamTreeTokenType.PARAGRAPH, paragraphs: generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, prevParagraph, horizontalLine), textRuns: [{ st: 0, ed: 1, ts: { ...curTextRun.ts } }] }; if (docDataModel == null) return false; const activeRange = docSelectionManagerService.getActiveTextRange(); if (originBody == null) return false; const { collapsed } = activeTextRange; const cursorMove = insertBody.dataStream.length; const textRanges = [{ startOffset: startOffset + cursorMove, endOffset: startOffset + cursorMove, style: activeRange === null || activeRange === void 0 ? void 0 : activeRange.style, collapsed }]; const doMutation = { id: RichTextEditingMutation.id, params: { unitId, actions: [], textRanges, debounce: true } }; const textX = new TextX(); const jsonX = JSONX.getInstance(); if (collapsed) { if (startOffset > 0) textX.push({ t: TextXActionType.RETAIN, len: startOffset }); textX.push({ t: TextXActionType.INSERT, body: insertBody, len: insertBody.dataStream.length }); } else { const dos = BuildTextUtils.selection.delete([activeTextRange], originBody, 0, insertBody); textX.push(...dos); } if (((_prevParagraph$bullet = prevParagraph.bullet) === null || _prevParagraph$bullet === void 0 ? void 0 : _prevParagraph$bullet.listType) === PresetListType.CHECK_LIST_CHECKED || ((_prevParagraph$paragr = prevParagraph.paragraphStyle) === null || _prevParagraph$paragr === void 0 ? void 0 : _prevParagraph$paragr.headingId)) { var _prevParagraph$paragr2; if (activeTextRange.endOffset < prevParagraphIndex) textX.push({ t: TextXActionType.RETAIN, len: prevParagraphIndex - activeTextRange.endOffset }); textX.push({ t: TextXActionType.RETAIN, len: 1, body: { dataStream: "", paragraphs: [{ ...prevParagraph, paragraphStyle: { ...prevParagraph.paragraphStyle, ...isAtParagraphEnd ? { headingId: void 0, namedStyleType: void 0 } : null }, startIndex: 0, bullet: ((_prevParagraph$paragr2 = prevParagraph.paragraphStyle) === null || _prevParagraph$paragr2 === void 0 ? void 0 : _prevParagraph$paragr2.headingId) ? void 0 : { ...prevParagraph.bullet, listType: PresetListType.CHECK_LIST } }] }, coverType: UpdateDocsAttributeType.REPLACE }); } doMutation.params.textRanges = [{ startOffset: startOffset + cursorMove, endOffset: startOffset + cursorMove, collapsed }]; const path = getRichTextEditPath(docDataModel, segmentId); doMutation.params.actions = jsonX.editOp(textX.serialize(), path); const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); } }; //#endregion //#region src/commands/commands/table/table.ts function genEmptyTable(rowCount, colCount) { let dataStream = DataStreamTreeTokenType.TABLE_START; const paragraphs = []; const sectionBreaks = []; for (let i = 0; i < rowCount; i++) { dataStream += DataStreamTreeTokenType.TABLE_ROW_START; for (let j = 0; j < colCount; j++) { dataStream += `${DataStreamTreeTokenType.TABLE_CELL_START}\r\n${DataStreamTreeTokenType.TABLE_CELL_END}`; paragraphs.push({ startIndex: dataStream.length - 3, paragraphStyle: { spaceAbove: { v: 3 }, lineSpacing: 2, spaceBelow: { v: 0 } } }); sectionBreaks.push({ startIndex: dataStream.length - 2 }); } dataStream += DataStreamTreeTokenType.TABLE_ROW_END; } dataStream += DataStreamTreeTokenType.TABLE_END; return { dataStream, paragraphs, sectionBreaks }; } function getEmptyTableCell() { return { margin: { start: { v: 10 }, end: { v: 10 }, top: { v: 5 }, bottom: { v: 5 } } }; } function getEmptyTableRow(col) { const tableCell = getEmptyTableCell(); return { tableCells: [...new Array(col).fill(null).map(() => Tools.deepClone(tableCell))], trHeight: { val: { v: 30 }, hRule: TableRowHeightRule.AUTO } }; } function getTableColumn(width) { return { size: { type: TableSizeType.SPECIFIED, width: { v: width } } }; } function genTableSource(rowCount, colCount, pageContentWidth) { const tableColumn = getTableColumn(pageContentWidth / colCount); const tableRow = getEmptyTableRow(colCount); return { tableRows: [...new Array(rowCount).fill(null).map(() => Tools.deepClone(tableRow))], tableColumns: [...new Array(colCount).fill(null).map(() => Tools.deepClone(tableColumn))], tableId: generateRandomId(6), align: TableAlignmentType.START, indent: { v: 0 }, textWrap: TableTextWrapType.NONE, position: { positionH: { relativeFrom: ObjectRelativeFromH.PAGE, posOffset: 0 }, positionV: { relativeFrom: ObjectRelativeFromV.PAGE, posOffset: 0 } }, dist: { distB: 0, distL: 0, distR: 0, distT: 0 }, cellMargin: { start: { v: 10 }, end: { v: 10 }, top: { v: 5 }, bottom: { v: 5 } }, size: { type: TableSizeType.UNSPECIFIED, width: { v: pageContentWidth } } }; } function getRangeInfoFromRanges(textRange, rectRanges) { if (!textRange && !rectRanges) return null; if (rectRanges && rectRanges.length > 0) { let startOffset = Number.POSITIVE_INFINITY; let endOffset = Number.NEGATIVE_INFINITY; const segmentId = ""; for (const rectRange of rectRanges) { const { startOffset: st, endOffset: ed, segmentId: sid } = rectRange; if (st == null || ed == null || sid == null) continue; startOffset = Math.min(startOffset, st); endOffset = Math.max(endOffset, ed); } if (Number.isFinite(startOffset) && Number.isFinite(endOffset)) return { startOffset, endOffset, segmentId }; } else if (textRange) { const { startOffset, endOffset, segmentId } = textRange; if (startOffset == null || endOffset == null || segmentId == null) return null; return { startOffset, endOffset, segmentId }; } } function getInsertRowBody(col) { let dataStream = DataStreamTreeTokenType.TABLE_ROW_START; const paragraphs = []; const sectionBreaks = []; for (let i = 0; i < col; i++) { dataStream += `${DataStreamTreeTokenType.TABLE_CELL_START}\r\n${DataStreamTreeTokenType.TABLE_CELL_END}`; paragraphs.push({ startIndex: dataStream.length - 3, paragraphStyle: { spaceAbove: { v: 3 }, lineSpacing: 2, spaceBelow: { v: 0 } } }); sectionBreaks.push({ startIndex: dataStream.length - 2 }); } dataStream += DataStreamTreeTokenType.TABLE_ROW_END; return { dataStream, paragraphs, sectionBreaks }; } function getInsertColumnBody() { const dataStream = `${DataStreamTreeTokenType.TABLE_CELL_START}\r\n${DataStreamTreeTokenType.TABLE_CELL_END}`; const paragraphs = []; const sectionBreaks = []; paragraphs.push({ startIndex: 1, paragraphStyle: { spaceAbove: { v: 3 }, lineSpacing: 2, spaceBelow: { v: 0 } } }); sectionBreaks.push({ startIndex: 2 }); return { dataStream, paragraphs, sectionBreaks }; } function getInsertRowActionsParams(rangeInfo, position, viewModel) { var _viewModel$getBody; const { startOffset, endOffset, segmentId } = rangeInfo; const vm = viewModel.getSelfOrHeaderFooterViewModel(segmentId); const index = position === 0 ? startOffset : endOffset; let tableRow = null; const tableId = (_viewModel$getBody = viewModel.getBody()) === null || _viewModel$getBody === void 0 || (_viewModel$getBody = _viewModel$getBody.tables) === null || _viewModel$getBody === void 0 || (_viewModel$getBody = _viewModel$getBody.find((t) => index >= t.startIndex && index <= t.endIndex)) === null || _viewModel$getBody === void 0 ? void 0 : _viewModel$getBody.tableId; let rowIndex = 0; for (const section of vm.getChildren()) { for (const paragraph of section.children) { const { children } = paragraph; const table = children[0]; if (table) { for (const row of table.children) if (row.startIndex <= index && index <= row.endIndex) { rowIndex = table.children.indexOf(row); tableRow = row; break; } } if (tableRow) break; } if (tableRow) break; } if (tableRow == null || tableId == null) return null; return { offset: position === 0 ? tableRow.startIndex : tableRow.endIndex + 1, colCount: tableRow.children.length, tableId, insertRowIndex: position === 0 ? rowIndex : rowIndex + 1 }; } function getInsertColumnActionsParams(rangeInfo, position, viewModel) { var _viewModel$getBody2; const { startOffset, endOffset, segmentId } = rangeInfo; const vm = viewModel.getSelfOrHeaderFooterViewModel(segmentId); const index = position === 0 ? startOffset : endOffset; const tableId = (_viewModel$getBody2 = viewModel.getBody()) === null || _viewModel$getBody2 === void 0 || (_viewModel$getBody2 = _viewModel$getBody2.tables) === null || _viewModel$getBody2 === void 0 || (_viewModel$getBody2 = _viewModel$getBody2.find((t) => index >= t.startIndex && index <= t.endIndex)) === null || _viewModel$getBody2 === void 0 ? void 0 : _viewModel$getBody2.tableId; const offsets = []; let table = null; let columnIndex = -1; for (const section of vm.getChildren()) { for (const paragraph of section.children) { const { children } = paragraph; const tableNode = children[0]; if (tableNode) { if (index < tableNode.startIndex || index > tableNode.endIndex) continue; table = tableNode; for (const row of tableNode.children) { for (const cell of row.children) { const cellIndex = row.children.indexOf(cell); if (index >= cell.startIndex && index <= cell.endIndex) { columnIndex = cellIndex; break; } } if (columnIndex !== -1) break; } } if (table) break; } if (table) break; } if (table == null || tableId == null || columnIndex === -1) return null; let cursor = 0; for (const row of table.children) { const cell = row.children[columnIndex]; const insertIndex = position === 0 ? cell.startIndex : cell.endIndex + 1; offsets.push(insertIndex - cursor); cursor = insertIndex; } return { offsets, tableId, columnIndex, rowCount: table.children.length }; } function getColumnWidths(pageWidth, tableColumns, insertColumnIndex) { const widths = []; let newColWidth = tableColumns[insertColumnIndex].size.width.v; let totalWidth = 0; for (let i = 0; i < tableColumns.length; i++) totalWidth += tableColumns[i].size.width.v; totalWidth += newColWidth; for (let i = 0; i < tableColumns.length; i++) widths.push(tableColumns[i].size.width.v / totalWidth * pageWidth); newColWidth = newColWidth / totalWidth * pageWidth; return { widths, newColWidth }; } function getDeleteRowsActionsParams(rangeInfo, viewModel) { var _viewModel$getBody3; const { startOffset, endOffset, segmentId } = rangeInfo; const vm = viewModel.getSelfOrHeaderFooterViewModel(segmentId); const tableId = (_viewModel$getBody3 = viewModel.getBody()) === null || _viewModel$getBody3 === void 0 || (_viewModel$getBody3 = _viewModel$getBody3.tables) === null || _viewModel$getBody3 === void 0 || (_viewModel$getBody3 = _viewModel$getBody3.find((t) => startOffset >= t.startIndex && endOffset <= t.endIndex)) === null || _viewModel$getBody3 === void 0 ? void 0 : _viewModel$getBody3.tableId; const rowIndexes = []; let offset = -1; let len = 0; let cursor = -1; let selectWholeTable = false; for (const section of vm.getChildren()) { for (const paragraph of section.children) { const { children } = paragraph; const table = children[0]; if (table) { if (startOffset < table.startIndex || endOffset > table.endIndex) continue; cursor = table.startIndex + 3; for (const row of table.children) { const rowIndex = table.children.indexOf(row); const { startIndex, endIndex } = row; if (startOffset >= startIndex && startOffset <= endIndex) { offset = startIndex; rowIndexes.push(rowIndex); len += endIndex - startIndex + 1; } else if (startIndex > startOffset && endIndex < endOffset) { rowIndexes.push(rowIndex); len += endIndex - startIndex + 1; } else if (endOffset >= startIndex && endOffset <= endIndex) { rowIndexes.push(rowIndex); len += endIndex - startIndex + 1; } if (rowIndexes.length === table.children.length) selectWholeTable = true; } } if (rowIndexes.length) break; } if (rowIndexes.length) break; } if (tableId == null || rowIndexes.length === 0) return null; return { tableId, rowIndexes, offset, len, cursor, selectWholeTable }; } function getDeleteColumnsActionParams(rangeInfo, viewModel) { var _viewModel$getBody4; const { startOffset, endOffset, segmentId } = rangeInfo; const vm = viewModel.getSelfOrHeaderFooterViewModel(segmentId); const tableId = (_viewModel$getBody4 = viewModel.getBody()) === null || _viewModel$getBody4 === void 0 || (_viewModel$getBody4 = _viewModel$getBody4.tables) === null || _viewModel$getBody4 === void 0 || (_viewModel$getBody4 = _viewModel$getBody4.find((t) => startOffset >= t.startIndex && endOffset <= t.endIndex)) === null || _viewModel$getBody4 === void 0 ? void 0 : _viewModel$getBody4.tableId; const offsets = []; let table = null; const columnIndexes = []; let cursor = -1; let startColumnIndex = -1; let endColumnIndex = -1; for (const section of vm.getChildren()) { for (const paragraph of section.children) { const { children } = paragraph; const tableNode = children[0]; if (tableNode) { if (startOffset < tableNode.startIndex || endOffset > tableNode.endIndex) continue; table = tableNode; for (const row of tableNode.children) for (const cell of row.children) { const cellIndex = row.children.indexOf(cell); if (startOffset >= cell.startIndex && startOffset <= cell.endIndex) startColumnIndex = cellIndex; if (endOffset >= cell.startIndex && endOffset <= cell.endIndex) endColumnIndex = cellIndex; } } if (table) break; } if (table) break; } if (table == null || tableId == null) return null; for (let i = startColumnIndex; i <= endColumnIndex; i++) columnIndexes.push(i); let delta = 0; for (const row of table.children) { const startCell = row.children[startColumnIndex]; const endCell = row.children[endColumnIndex]; offsets.push({ retain: startCell.startIndex - delta, delete: endCell.endIndex - startCell.startIndex + 1 }); delta = endCell.endIndex + 1; } cursor = table.startIndex + 3; return { offsets, tableId, columnIndexes, cursor, selectWholeTable: columnIndexes.length === table.children[0].children.length, rowCount: table.children.length }; } function getDeleteTableActionParams(rangeInfo, viewModel) { var _viewModel$getBody5; const { startOffset, endOffset, segmentId } = rangeInfo; const vm = viewModel.getSelfOrHeaderFooterViewModel(segmentId); const tableId = (_viewModel$getBody5 = viewModel.getBody()) === null || _viewModel$getBody5 === void 0 || (_viewModel$getBody5 = _viewModel$getBody5.tables) === null || _viewModel$getBody5 === void 0 || (_viewModel$getBody5 = _viewModel$getBody5.find((t) => startOffset >= t.startIndex && endOffset <= t.endIndex)) === null || _viewModel$getBody5 === void 0 ? void 0 : _viewModel$getBody5.tableId; let offset = -1; let len = 0; let cursor = -1; for (const section of vm.getChildren()) { for (const paragraph of section.children) { const { children } = paragraph; const table = children[0]; if (table) { if (startOffset < table.startIndex || endOffset > table.endIndex) continue; offset = table.startIndex; len = table.endIndex - table.startIndex + 1; cursor = table.startIndex; } if (table) break; } if (len > 0) break; } if (tableId == null) return null; return { tableId, offset, len, cursor }; } function getDeleteRowContentActionParams(rangeInfo, viewModel) { var _viewModel$getBody6; const { startOffset, endOffset, segmentId } = rangeInfo; const vm = viewModel.getSelfOrHeaderFooterViewModel(segmentId); const tableId = (_viewModel$getBody6 = viewModel.getBody()) === null || _viewModel$getBody6 === void 0 || (_viewModel$getBody6 = _viewModel$getBody6.tables) === null || _viewModel$getBody6 === void 0 || (_viewModel$getBody6 = _viewModel$getBody6.find((t) => startOffset >= t.startIndex && endOffset <= t.endIndex)) === null || _viewModel$getBody6 === void 0 ? void 0 : _viewModel$getBody6.tableId; const offsets = []; let table = null; let cursor = -1; let rowIndex = -1; let startColumnIndex = -1; let endColumnIndex = -1; for (const section of vm.getChildren()) { for (const paragraph of section.children) { const { children } = paragraph; const tableNode = children[0]; if (tableNode) { if (startOffset < tableNode.startIndex || endOffset > tableNode.endIndex) continue; table = tableNode; for (const row of tableNode.children) { const rIndex = tableNode.children.indexOf(row); for (const cell of row.children) { const cellIndex = row.children.indexOf(cell); if (startOffset >= cell.startIndex && startOffset <= cell.endIndex) { rowIndex = rIndex; startColumnIndex = cellIndex; } if (endOffset >= cell.startIndex && endOffset <= cell.endIndex) endColumnIndex = cellIndex; } } } if (table) break; } if (table) break; } if (table == null || tableId == null || rowIndex === -1) return null; const row = table.children[rowIndex]; for (let i = startColumnIndex; i <= endColumnIndex; i++) { const cell = row.children[i]; offsets.push({ retain: cell.startIndex + 1, delete: cell.endIndex - cell.startIndex - 3 }); } cursor = table.startIndex + 3; return { offsets, tableId, cursor, rowCount: table.children.length }; } function getCellOffsets(viewModel, range, position) { const { startOffset } = range; let targetTable = null; for (const section of viewModel.getChildren()) { for (const paragraph of section.children) { const table = paragraph.children[0]; if (table) { if (startOffset > table.startIndex && startOffset < table.endIndex) { targetTable = table; break; } } } if (targetTable) break; } if (targetTable == null) return null; let cellIndex = -1; let rowIndex = -1; let targetRow = null; for (const row of targetTable.children) { for (const cell of row.children) if (startOffset > cell.startIndex && startOffset < cell.endIndex) { cellIndex = row.children.indexOf(cell); rowIndex = targetTable.children.indexOf(row); targetRow = row; break; } if (cellIndex > -1) break; } if (cellIndex === -1 || rowIndex === -1 || targetRow == null) return null; let newCell = null; if (position === 0) { newCell = targetRow.children[cellIndex + 1]; if (!newCell) { const nextRow = targetTable.children[rowIndex + 1]; if (nextRow) newCell = nextRow.children[0]; } } else { newCell = targetRow.children[cellIndex - 1]; if (!newCell) { const prevRow = targetTable.children[rowIndex - 1]; if (prevRow) newCell = prevRow.children[prevRow.children.length - 1]; } } if (newCell) { const { startIndex, endIndex } = newCell; return { startOffset: startIndex + 1, endOffset: endIndex - 2 }; } } //#endregion //#region src/commands/commands/clipboard.inner.command.ts function getCustomBlockIdsInSelections(body, selections) { const customBlockIds = []; const { customBlocks = [] } = body; for (const selection of selections) { const { startOffset, endOffset } = selection; if (startOffset == null || endOffset == null) continue; for (const customBlock of customBlocks) { const { startIndex } = customBlock; if (startIndex >= startOffset && startIndex < endOffset) customBlockIds.push(customBlock.blockId); } } return customBlockIds; } function hasRangeInTable(ranges) { return ranges.some((range) => { const { startNodePosition } = range; return startNodePosition ? (startNodePosition === null || startNodePosition === void 0 ? void 0 : startNodePosition.path.indexOf("cells")) > -1 : false; }); } const UNITS = SHEET_EDITOR_UNITS; const InnerPasteCommand = { id: "doc.command.inner-paste", type: CommandType.COMMAND, handler: async (accessor, params) => { var _body$tables, _body$customBlocks; const { segmentId, textRanges, doc } = params; const commandService = accessor.get(ICommandService); const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const selections = docSelectionManagerService.getTextRanges(); const rectRanges = docSelectionManagerService.getRectRanges(); const { body, tableSource, drawings } = doc; if (!Array.isArray(selections) || selections.length === 0 || body == null) return false; const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); const originBody = docDataModel === null || docDataModel === void 0 ? void 0 : docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody(); if (docDataModel == null || originBody == null) return false; const unitId = docDataModel.getUnitId(); const doMutation = { id: RichTextEditingMutation.id, params: { unitId, actions: [], textRanges, segmentId } }; const memoryCursor = new MemoryCursor(); memoryCursor.reset(); const textX = new TextX(); const jsonX = JSONX.getInstance(); const rawActions = []; const hasTable = !!((_body$tables = body.tables) === null || _body$tables === void 0 ? void 0 : _body$tables.length); const hasCustomBlock = !!((_body$customBlocks = body.customBlocks) === null || _body$customBlocks === void 0 ? void 0 : _body$customBlocks.length); if (hasTable && segmentId) return false; if (hasTable && hasRangeInTable(selections)) return false; if (selections.length && (rectRanges === null || rectRanges === void 0 ? void 0 : rectRanges.length)) return false; for (let i = 0; i < selections.length; i++) { var _originBody$customRan, _originBody$customDec; const selection = selections[i]; const { startOffset, endOffset, collapsed } = selection; const len = startOffset - memoryCursor.cursor; const cloneBody = Tools.deepClone(body); if (hasTable) for (const t of cloneBody.tables) { const { tableId: oldTableId } = t; const tableId = generateRandomId(6); t.tableId = tableId; const table = Tools.deepClone(tableSource[oldTableId]); table.tableId = tableId; const action = jsonX.insertOp(["tableSource", tableId], table); rawActions.push(action); } if (hasCustomBlock && drawings) { var _docDataModel$getSnap, _docDataModel$getSnap2; const drawingLen = (_docDataModel$getSnap = (_docDataModel$getSnap2 = docDataModel.getSnapshot().drawingsOrder) === null || _docDataModel$getSnap2 === void 0 ? void 0 : _docDataModel$getSnap2.length) !== null && _docDataModel$getSnap !== void 0 ? _docDataModel$getSnap : 0; for (const block of cloneBody.customBlocks) { const { blockId } = block; const drawingId = generateRandomId(6); block.blockId = drawingId; const drawing = Tools.deepClone(drawings[blockId]); drawing.drawingId = drawingId; const action = jsonX.insertOp(["drawings", drawingId], drawing); const orderAction = jsonX.insertOp(["drawingsOrder", drawingLen], drawingId); rawActions.push(action); rawActions.push(orderAction); } } const customRange = getCustomRangeAtPosition((_originBody$customRan = originBody.customRanges) !== null && _originBody$customRan !== void 0 ? _originBody$customRan : [], endOffset, UNITS.includes(unitId)); const customDecorations = getCustomDecorationAtPosition((_originBody$customDec = originBody.customDecorations) !== null && _originBody$customDec !== void 0 ? _originBody$customDec : [], endOffset); if (customRange) cloneBody.customRanges = [{ ...customRange, startIndex: 0, endIndex: body.dataStream.length - 1 }]; if (customDecorations.length) cloneBody.customDecorations = customDecorations.map((customDecoration) => ({ ...customDecoration, startIndex: 0, endIndex: body.dataStream.length - 1 })); if (collapsed) { textX.push({ t: TextXActionType.RETAIN, len }); textX.push({ t: TextXActionType.INSERT, body: cloneBody, len: body.dataStream.length }); } else { const dos = BuildTextUtils.selection.delete([selection], body, memoryCursor.cursor, cloneBody, selections.length === 1); textX.push(...dos); } memoryCursor.reset(); memoryCursor.moveCursor(endOffset); } const path = getRichTextEditPath(docDataModel, segmentId); rawActions.push(jsonX.editOp(textX.serialize(), path)); doMutation.params.actions = rawActions.reduce((acc, cur) => { return JSONX.compose(acc, cur); }, null); const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); } }; function adjustSelectionByTable(selection, tables) { const { startOffset, endOffset } = selection; const endsWithTable = tables.some((t) => t.startIndex === endOffset); const newEndOffset = Math.max(startOffset, endsWithTable ? endOffset - 1 : endOffset); return { ...selection, endOffset: newEndOffset, collapsed: startOffset === newEndOffset }; } function getCutActionsFromTextRanges(selections, docDataModel, segmentId) { var _docDataModel$getDraw, _docDataModel$getDraw2; const originBody = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody(); const textX = new TextX(); const jsonX = JSONX.getInstance(); const rawActions = []; if (originBody == null) return rawActions; const { tables = [] } = originBody; const memoryCursor = new MemoryCursor(); memoryCursor.reset(); for (let i = 0; i < selections.length; i++) { const selection = adjustSelection