From 721f5010b5607053a55ff78c5089d240ec9e4e6f Mon Sep 17 00:00:00 2001 From: Wenzhao Hu <12122021+wzhudev@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:21:43 +0800 Subject: [PATCH] refactor: refactor editor related modules --- .../src/services/undoredo/undoredo.service.ts | 2 +- .../doc-drawing-update.render-controller.ts} | 22 +- packages/docs-drawing-ui/src/plugin.ts | 2 +- .../src/controllers/back-scroll.controller.ts | 122 ----- .../doc-editor-bridge.controller.ts | 2 +- .../src/controllers/drawing.controller.ts | 240 --------- .../doc-floating-object.render-controller.ts} | 0 .../text-selection.render-controller.ts} | 0 packages/docs-ui/src/docs-ui-plugin.ts | 8 +- ...nder.service.ts => docs-render.service.ts} | 12 +- .../doc-view-model-manager.service.ts | 2 + .../render-manager/render-manager.service.ts | 18 +- .../controllers/editor/editing.controller.ts | 94 ---- ...roller.ts => editing.render-controller.ts} | 456 +++++++++++++++-- .../controllers/editor/end-edit.controller.ts | 468 ------------------ .../editor/formula-editor.controller.ts | 26 +- packages/sheets-ui/src/sheets-ui-plugin.ts | 15 +- .../src/controllers/zen-editor.controller.ts | 7 +- .../controllers/ui/ui-desktop.controller.tsx | 8 +- .../ui/src/services/editor/editor.service.ts | 8 +- packages/ui/src/ui-plugin.ts | 2 +- 21 files changed, 484 insertions(+), 1030 deletions(-) rename packages/docs-drawing-ui/src/controllers/{doc-drawing-update.controller.ts => render-controllers/doc-drawing-update.render-controller.ts} (92%) delete mode 100644 packages/docs-ui/src/controllers/back-scroll.controller.ts delete mode 100644 packages/docs-ui/src/controllers/drawing.controller.ts rename packages/docs-ui/src/controllers/{doc-floating-object.controller.ts => render-controllers/doc-floating-object.render-controller.ts} (100%) rename packages/docs-ui/src/controllers/{text-selection.controller.ts => render-controllers/text-selection.render-controller.ts} (100%) rename packages/docs-ui/src/services/{doc-render.service.ts => docs-render.service.ts} (88%) delete mode 100644 packages/sheets-ui/src/controllers/editor/editing.controller.ts rename packages/sheets-ui/src/controllers/editor/{start-edit.controller.ts => editing.render-controller.ts} (59%) delete mode 100644 packages/sheets-ui/src/controllers/editor/end-edit.controller.ts diff --git a/packages/core/src/services/undoredo/undoredo.service.ts b/packages/core/src/services/undoredo/undoredo.service.ts index bc36829057..6fd9391890 100644 --- a/packages/core/src/services/undoredo/undoredo.service.ts +++ b/packages/core/src/services/undoredo/undoredo.service.ts @@ -49,7 +49,7 @@ export interface IUndoRedoService { popUndoToRedo(): void; popRedoToUndo(): void; - clearUndoRedo(unitID: string): void; + clearUndoRedo(unitId: string): void; /** * Batch undo redo elements into a single `IUndoRedoItem` util the returned `IDisposable` is called. diff --git a/packages/docs-drawing-ui/src/controllers/doc-drawing-update.controller.ts b/packages/docs-drawing-ui/src/controllers/render-controllers/doc-drawing-update.render-controller.ts similarity index 92% rename from packages/docs-drawing-ui/src/controllers/doc-drawing-update.controller.ts rename to packages/docs-drawing-ui/src/controllers/render-controllers/doc-drawing-update.render-controller.ts index cadc0526b4..d3969e1104 100644 --- a/packages/docs-drawing-ui/src/controllers/doc-drawing-update.controller.ts +++ b/packages/docs-drawing-ui/src/controllers/render-controllers/doc-drawing-update.render-controller.ts @@ -27,14 +27,14 @@ import { DocSkeletonManagerService, TextSelectionManagerService } from '@univerj import { docDrawingPositionToTransform, transformToDocDrawingPosition } from '@univerjs/docs-ui'; import type { IRenderContext, IRenderModule } from '@univerjs/engine-render'; -import type { IInsertImageOperationParams } from '../commands/operations/insert-image.operation'; -import { InsertDocImageOperation } from '../commands/operations/insert-image.operation'; -import type { IInsertDrawingCommandParams, ISetDrawingCommandParams } from '../commands/commands/interfaces'; -import { type ISetDrawingArrangeCommandParams, SetDocDrawingArrangeCommand } from '../commands/commands/set-drawing-arrange.command'; -import { InsertDocDrawingCommand } from '../commands/commands/insert-doc-drawing.command'; -import { GroupDocDrawingCommand } from '../commands/commands/group-doc-drawing.command'; -import { UngroupDocDrawingCommand } from '../commands/commands/ungroup-doc-drawing.command'; -import { SetDocDrawingCommand } from '../commands/commands/set-doc-drawing.command'; +import type { IInsertImageOperationParams } from '../../commands/operations/insert-image.operation'; +import { InsertDocImageOperation } from '../../commands/operations/insert-image.operation'; +import type { IInsertDrawingCommandParams, ISetDrawingCommandParams } from '../../commands/commands/interfaces'; +import { type ISetDrawingArrangeCommandParams, SetDocDrawingArrangeCommand } from '../../commands/commands/set-drawing-arrange.command'; +import { InsertDocDrawingCommand } from '../../commands/commands/insert-doc-drawing.command'; +import { GroupDocDrawingCommand } from '../../commands/commands/group-doc-drawing.command'; +import { UngroupDocDrawingCommand } from '../../commands/commands/ungroup-doc-drawing.command'; +import { SetDocDrawingCommand } from '../../commands/commands/set-doc-drawing.command'; export class DocDrawingUpdateRenderController extends Disposable implements IRenderModule { constructor( @@ -121,8 +121,6 @@ export class DocDrawingUpdateRenderController extends Disposable implements IRen const { imageId, imageSourceType, source, base64Cache } = imageParam; const { width, height, image } = await getImageSize(base64Cache || ''); - const { width: sceneWidth, height: sceneHeight } = this._context.scene; - this._imageIoService.addImageSourceCache(imageId, imageSourceType, image); let scale = 1; @@ -210,15 +208,11 @@ export class DocDrawingUpdateRenderController extends Disposable implements IRen } const sheetDrawing = this._sheetDrawingService.getDrawingByParam({ unitId, subUnitId, drawingId }); - if (sheetDrawing == null) { return; } - // const { marginLeft, marginTop } = pageMarginCache.get(drawingId) || { marginLeft: 0, marginTop: 0 }; - const docTransform = transformToDocDrawingPosition({ ...sheetDrawing.transform, ...transform }); - if (docTransform == null) { return; } diff --git a/packages/docs-drawing-ui/src/plugin.ts b/packages/docs-drawing-ui/src/plugin.ts index fd76d92e20..eca7bd07d4 100644 --- a/packages/docs-drawing-ui/src/plugin.ts +++ b/packages/docs-drawing-ui/src/plugin.ts @@ -23,7 +23,7 @@ import { UniverDocsDrawingPlugin } from '@univerjs/docs-drawing'; import { IRenderManagerService } from '@univerjs/engine-render'; import { DocDrawingPopupMenuController } from './controllers/drawing-popup-menu.controller'; import { DocDrawingUIController } from './controllers/doc-drawing.controller'; -import { DocDrawingUpdateRenderController } from './controllers/doc-drawing-update.controller'; +import { DocDrawingUpdateRenderController } from './controllers/render-controllers/doc-drawing-update.render-controller'; const PLUGIN_NAME = 'DOCS_DRAWING_UI_PLUGIN'; diff --git a/packages/docs-ui/src/controllers/back-scroll.controller.ts b/packages/docs-ui/src/controllers/back-scroll.controller.ts deleted file mode 100644 index c76be88826..0000000000 --- a/packages/docs-ui/src/controllers/back-scroll.controller.ts +++ /dev/null @@ -1,122 +0,0 @@ -/** - * 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 { IUniverInstanceService, LifecycleStages, OnLifecycle, RxDisposable } from '@univerjs/core'; -import { DocSkeletonManagerService, getDocObject, TextSelectionManagerService, VIEWPORT_KEY } from '@univerjs/docs'; -import { getAnchorBounding, IRenderManagerService, NodePositionConvertToCursor } from '@univerjs/engine-render'; -import { IEditorService } from '@univerjs/ui'; -import { Inject } from '@wendellhu/redi'; -import { takeUntil } from 'rxjs'; - -const ANCHOR_WIDTH = 1.5; - -@OnLifecycle(LifecycleStages.Rendered, BackScrollController) -export class BackScrollController extends RxDisposable { - constructor( - @Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService, - @Inject(TextSelectionManagerService) private readonly _textSelectionManagerService: TextSelectionManagerService, - @IEditorService private readonly _editorService: IEditorService, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService - ) { - super(); - - this._init(); - } - - private _init() { - this._textSelectionManagerService.textSelection$.pipe(takeUntil(this.dispose$)).subscribe((params) => { - if (params == null) { - return; - } - - const { isEditing, unitId } = params; - - if (isEditing) { - this._scrollToSelection(unitId); - } - }); - } - - // Let the selection show on the current screen. - private _scrollToSelection(unitId: string) { - const activeTextRange = this._textSelectionManagerService.getActiveRange(); - const docObject = this._getDocObject(); - const skeleton = this._docSkeletonManagerService.getSkeleton(); - - if (activeTextRange == null || docObject == null || skeleton == null) { - return; - } - - const { collapsed, startNodePosition } = activeTextRange; - - if (!collapsed) { - return; - } - - const documentOffsetConfig = docObject.document.getOffsetConfig(); - const { docsLeft, docsTop } = documentOffsetConfig; - - const convertor = new NodePositionConvertToCursor(documentOffsetConfig, skeleton); - - const { contentBoxPointGroup } = convertor.getRangePointData(startNodePosition, startNodePosition); - - const { left: aLeft, top: aTop, height } = getAnchorBounding(contentBoxPointGroup); - - const left = aLeft + docsLeft; - - const top = aTop + docsTop; - - const viewportMain = docObject.scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); - - const isEditor = !!this._editorService.getEditor(unitId); - - if (viewportMain == null) { - return; - } - - const { - left: boundLeft, - top: boundTop, - right: boundRight, - bottom: boundBottom, - } = viewportMain.getBounding().viewBound; - - let offsetY = 0; - let offsetX = 0; - - const delta = isEditor ? 0 : 100; - - if (top < boundTop) { - offsetY = top - boundTop; - } else if (top > boundBottom - height) { - offsetY = top - boundBottom + height + delta; - } - - if (left < boundLeft) { - offsetX = left - boundLeft; - } else if (left > boundRight - ANCHOR_WIDTH) { - offsetX = left - boundRight + ANCHOR_WIDTH; - } - - const config = viewportMain.transViewportScroll2ScrollValue(offsetX, offsetY); - viewportMain.scrollBy(config); - } - - private _getDocObject() { - return getDocObject(this._univerInstanceService, this._renderManagerService); - } -} diff --git a/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts b/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts index 17e44a267f..6a60d68f2d 100644 --- a/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts +++ b/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts @@ -81,7 +81,7 @@ export class DocEditorBridgeController extends Disposable { } const skeleton = this._renderManagerService.getRenderById(editorDataModel.getUnitId()) - ?.with(DocSkeletonManagerService).getSkeleton()?.skeleton; + ?.with(DocSkeletonManagerService).getSkeleton(); if (editor == null || editor.render == null || skeleton == null || editorDataModel == null) { return; } diff --git a/packages/docs-ui/src/controllers/drawing.controller.ts b/packages/docs-ui/src/controllers/drawing.controller.ts deleted file mode 100644 index 54568ec92a..0000000000 --- a/packages/docs-ui/src/controllers/drawing.controller.ts +++ /dev/null @@ -1,240 +0,0 @@ -/** - * 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 { ICommandInfo } from '@univerjs/core'; -import { - BooleanNumber, - DEFAULT_DOCUMENT_SUB_COMPONENT_ID, - Disposable, - ICommandService, - LifecycleStages, - OnLifecycle, - PositionedObjectLayoutType, -} from '@univerjs/core'; -import type { IRichTextEditingMutationParams } from '@univerjs/docs'; -import { DocSkeletonManagerService, RichTextEditingMutation, SetDocZoomRatioOperation } from '@univerjs/docs'; -import type { Documents, DocumentSkeleton, IRender } from '@univerjs/engine-render'; -import { IRenderManagerService, Liquid } from '@univerjs/engine-render'; -import { IEditorService } from '@univerjs/ui'; -import { Inject } from '@wendellhu/redi'; - -@OnLifecycle(LifecycleStages.Steady, DocFloatingObjectController) -export class DocFloatingObjectController extends Disposable { - private _liquid = new Liquid(); - - private _pageMarginCache = new Map(); - - constructor( - @Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @ICommandService private readonly _commandService: ICommandService, - @IEditorService private readonly _editorService: IEditorService - ) { - super(); - - this._initialize(); - - this._commandExecutedListener(); - } - - private _initialize() { - this._initialRenderRefresh(); - - this._updateOnPluginChange(); - } - - private _updateOnPluginChange() { - // this._drawingManagerService.pluginUpdate$.subscribe((params) => { - // const docsSkeletonObject = this._docSkeletonManagerService.getCurrent(); - - // if (docsSkeletonObject == null) { - // return; - // } - - // const { unitId, skeleton } = docsSkeletonObject; - - // const currentRender = this._renderManagerService.getRenderById(unitId); - - // if (currentRender == null) { - // return; - // } - - // const { mainComponent, components, scene } = currentRender; - - // const docsComponent = mainComponent as Documents; - - // const { left: docsLeft, top: docsTop } = docsComponent; - - // params.forEach((param) => { - // const { unitId, subUnitId, drawingId, drawing } = param; - - // const { left = 0, top = 0, width = 0, height = 0, angle, flipX, flipY, skewX, skewY } = drawing; - - // const cache = this._pageMarginCache.get(drawingId); - - // const marginLeft = cache?.marginLeft || 0; - // const marginTop = cache?.marginTop || 0; - - // skeleton - // ?.getViewModel() - // .getDataModel() - // .updateDrawing(drawingId, { - // left: left - docsLeft - marginLeft, - // top: top - docsTop - marginTop, - // height, - // width, - // }); - // }); - - // skeleton?.calculate(); - // mainComponent?.makeDirty(); - // }); - } - - private _initialRenderRefresh() { - this._docSkeletonManagerService.currentSkeleton$.subscribe((param) => { - if (param == null) { - return; - } - - const { skeleton: documentSkeleton, unitId } = param; - - const currentRender = this._renderManagerService.getRenderById(unitId); - - if (currentRender == null) { - return; - } - - const { mainComponent } = currentRender; - - const docsComponent = mainComponent as Documents; - - // TODO: Why NEED change skeleton here? - docsComponent.changeSkeleton(documentSkeleton); - - this._refreshDrawing(unitId, documentSkeleton, currentRender); - }); - } - - private _commandExecutedListener() { - const updateCommandList = [RichTextEditingMutation.id, SetDocZoomRatioOperation.id]; - - this.disposeWithMe( - this._commandService.onCommandExecuted((command: ICommandInfo) => { - if (updateCommandList.includes(command.id)) { - const params = command.params as IRichTextEditingMutationParams; - const { unitId: commandUnitId } = params; - - const docsSkeletonObject = this._docSkeletonManagerService.getSkeleton(); - - if (docsSkeletonObject == null) { - return; - } - - const { unitId, skeleton } = docsSkeletonObject; - - if (commandUnitId !== unitId) { - return; - } - - const currentRender = this._renderManagerService.getRenderById(unitId); - - if (currentRender == null) { - return; - } - - if (this._editorService.isEditor(unitId)) { - currentRender.mainComponent?.makeDirty(); - return; - } - - this._refreshDrawing(unitId, skeleton, currentRender); - - // this.calculatePagePosition(currentRender); - } - }) - ); - } - - private _refreshDrawing(unitId: string, skeleton: DocumentSkeleton, currentRender: IRender) { - const skeletonData = skeleton?.getSkeletonData(); - - const { mainComponent, scene } = currentRender; - - const documentComponent = mainComponent as Documents; - - if (!skeletonData) { - return; - } - - const { left: docsLeft, top: docsTop, pageLayoutType, pageMarginLeft, pageMarginTop } = documentComponent; - - const { pages } = skeletonData; - - const floatObjects: any[] = []; // IFloatingObjectManagerParam - - const { scaleX, scaleY } = scene.getAncestorScale(); - - this._liquid.reset(); - - this._pageMarginCache.clear(); - - // const objectList: BaseObject[] = []; - // const pageMarginCache = new Map(); - - // const cumPageLeft = 0; - // const cumPageTop = 0; - /** - * TODO: @DR-Univer We should not refresh all floating elements, but instead make a diff. - */ - for (let i = 0, len = pages.length; i < len; i++) { - const page = pages[i]; - const { skeDrawings, marginLeft, marginTop } = page; - // cumPageLeft + = pageWidth + documents.pageMarginLeft; - - this._liquid.translatePagePadding(page); - - skeDrawings.forEach((drawing) => { - const { aLeft, aTop, height, width, drawingId, drawingOrigin } = drawing; - const behindText = drawingOrigin.layoutType === PositionedObjectLayoutType.WRAP_NONE && drawingOrigin.behindDoc === BooleanNumber.TRUE; - - floatObjects.push({ - unitId, - subUnitId: DEFAULT_DOCUMENT_SUB_COMPONENT_ID, - floatingObjectId: drawingId, - behindText, - floatingObject: { - left: aLeft + docsLeft + this._liquid.x, - top: aTop + docsTop + this._liquid.y, - width, - height, - }, - }); - - this._pageMarginCache.set(drawingId, { - marginLeft: this._liquid.x, - marginTop: this._liquid.y, - }); - }); - - this._liquid.restorePagePadding(page); - - this._liquid.translatePage(page, pageLayoutType, pageMarginLeft, pageMarginTop); - } - - // this._floatingObjectManagerService.batchAddOrUpdate(floatObjects); - } -} diff --git a/packages/docs-ui/src/controllers/doc-floating-object.controller.ts b/packages/docs-ui/src/controllers/render-controllers/doc-floating-object.render-controller.ts similarity index 100% rename from packages/docs-ui/src/controllers/doc-floating-object.controller.ts rename to packages/docs-ui/src/controllers/render-controllers/doc-floating-object.render-controller.ts diff --git a/packages/docs-ui/src/controllers/text-selection.controller.ts b/packages/docs-ui/src/controllers/render-controllers/text-selection.render-controller.ts similarity index 100% rename from packages/docs-ui/src/controllers/text-selection.controller.ts rename to packages/docs-ui/src/controllers/render-controllers/text-selection.render-controller.ts diff --git a/packages/docs-ui/src/docs-ui-plugin.ts b/packages/docs-ui/src/docs-ui-plugin.ts index 822f0a3893..f00a6a5c99 100644 --- a/packages/docs-ui/src/docs-ui-plugin.ts +++ b/packages/docs-ui/src/docs-ui-plugin.ts @@ -51,12 +51,12 @@ import { DocClipboardService, IDocClipboardService } from './services/clipboard/ import { DocClipboardController } from './controllers/clipboard.controller'; import { DocEditorBridgeController } from './controllers/doc-editor-bridge.controller'; import { DocRenderController } from './controllers/render-controllers/doc.render-controller'; -import { DocFloatingObjectRenderController } from './controllers/doc-floating-object.controller'; +import { DocFloatingObjectRenderController } from './controllers/render-controllers/doc-floating-object.render-controller'; import { DocZoomRenderController } from './controllers/render-controllers/zoom.render-controller'; -import { DocTextSelectionRenderController } from './controllers/text-selection.controller'; +import { DocTextSelectionRenderController } from './controllers/render-controllers/text-selection.render-controller'; import { DocBackScrollRenderController } from './controllers/render-controllers/back-scroll.render-controller'; import { DocCanvasPopManagerService } from './services/doc-popup-manager.service'; -import { DocsRenderService } from './services/doc-render.service'; +import { DocsRenderService } from './services/docs-render.service'; export class UniverDocsUIPlugin extends Plugin { static override pluginName = DOC_UI_PLUGIN_NAME; @@ -140,8 +140,8 @@ export class UniverDocsUIPlugin extends Plugin { private _initRenderBasics(): void { ([ - DocRenderController, DocSkeletonManagerService, + DocRenderController, DocZoomRenderController, DocBackScrollRenderController, DocFloatingObjectRenderController, diff --git a/packages/docs-ui/src/services/doc-render.service.ts b/packages/docs-ui/src/services/docs-render.service.ts similarity index 88% rename from packages/docs-ui/src/services/doc-render.service.ts rename to packages/docs-ui/src/services/docs-render.service.ts index f1d23f4a8e..57a9035b40 100644 --- a/packages/docs-ui/src/services/doc-render.service.ts +++ b/packages/docs-ui/src/services/docs-render.service.ts @@ -27,10 +27,14 @@ export class DocsRenderService extends RxDisposable { ) { super(); - Promise.resolve().then(() => this._init()); + this._init(); } private _init() { + this._renderManagerService.createRender$ + .pipe(takeUntil(this.dispose$)) + .subscribe((unitId) => this._createRenderWithId(unitId)); + this._instanceSrv.getTypeOfUnitAdded$(UniverInstanceType.UNIVER_DOC) .pipe(takeUntil(this.dispose$)) .subscribe((doc) => this._createRenderer(doc)); @@ -44,12 +48,16 @@ export class DocsRenderService extends RxDisposable { private _createRenderer(doc: DocumentDataModel) { const unitId = doc.getUnitId(); - this._renderManagerService.createRender(unitId); + this._createRenderWithId(unitId); // NOTE@wzhudev: maybe not in univer mode this._renderManagerService.setCurrent(unitId); } + private _createRenderWithId(unitId: string) { + this._renderManagerService.createRender(unitId); + } + private _disposeRenderer(doc: DocumentDataModel) { const unitId = doc.getUnitId(); this._renderManagerService.removeRender(unitId); diff --git a/packages/docs/src/services/doc-view-model-manager.service.ts b/packages/docs/src/services/doc-view-model-manager.service.ts index e06b9b4578..014156af6a 100644 --- a/packages/docs/src/services/doc-view-model-manager.service.ts +++ b/packages/docs/src/services/doc-view-model-manager.service.ts @@ -24,6 +24,8 @@ export interface IDocumentViewModelManagerParam { docViewModel: DocumentViewModel; } +// TODO@wzhudev: move this manager service into render unit + /** * The view model manager is used to manage Doc view model. has a one-to-one correspondence with the doc skeleton. */ diff --git a/packages/engine-render/src/render-manager/render-manager.service.ts b/packages/engine-render/src/render-manager/render-manager.service.ts index 4949eef263..241cd85ce2 100644 --- a/packages/engine-render/src/render-manager/render-manager.service.ts +++ b/packages/engine-render/src/render-manager/render-manager.service.ts @@ -19,7 +19,7 @@ import { Disposable, IUniverInstanceService, toDisposable } from '@univerjs/core import type { DependencyIdentifier, IDisposable } from '@wendellhu/redi'; import { createIdentifier, Inject, Injector } from '@wendellhu/redi'; import type { Observable } from 'rxjs'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; import type { BaseObject } from '../base-object'; import type { DocComponent } from '../components/docs/doc-component'; @@ -32,8 +32,8 @@ import { type IRender, type IRenderModuleCtor, RenderUnit } from './render-unit' export type RenderComponentType = SheetComponent | DocComponent | Slide | BaseObject; export interface IRenderManagerService extends IDisposable { + /** @deprecated */ currentRender$: Observable>; - createRender$: Observable>; addRender(unitId: string, renderer: IRender): void; createRender(unitId: string): IRender; removeRender(unitId: string): void; @@ -41,6 +41,15 @@ export interface IRenderManagerService extends IDisposable { getRenderById(unitId: string): Nullable; getRenderAll(): Map; defaultEngine: Engine; + + // DEPT@Jocs + // Editor should not be coupled in docs-ui. It should be an common service resident in @univerjs/ui. + // However, currently the refactor is not completed so we have to throw an event and let + // docs-ui to create the editor's renderer. + + /** @deprecated */ + createRender$: Observable; + /** @deprecated this design is very very weird! Remove it. */ create(unitId: Nullable): void; /** @deprecated There will be multi units to render at the same time, so there is no *current*. */ @@ -49,9 +58,7 @@ export interface IRenderManagerService extends IDisposable { getFirst(): Nullable; has(unitId: string): boolean; - withCurrentTypeOfUnit(type: UniverInstanceType, id: DependencyIdentifier): Nullable; - registerRenderController(type: UnitType, ctor: IRenderModuleCtor): IDisposable; } @@ -69,7 +76,8 @@ export class RenderManagerService extends Disposable implements IRenderManagerSe private readonly _currentRender$ = new BehaviorSubject>(this._currentUnitId); readonly currentRender$ = this._currentRender$.asObservable(); - private readonly _createRender$ = new BehaviorSubject>(this._currentUnitId); + private readonly _createRender$ = new Subject(); + /** @deprecated */ readonly createRender$ = this._createRender$.asObservable(); get defaultEngine() { diff --git a/packages/sheets-ui/src/controllers/editor/editing.controller.ts b/packages/sheets-ui/src/controllers/editor/editing.controller.ts deleted file mode 100644 index 476ff568c0..0000000000 --- a/packages/sheets-ui/src/controllers/editor/editing.controller.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * 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 { Workbook } from '@univerjs/core'; -import { - DOCS_NORMAL_EDITOR_UNIT_ID_KEY, - IUndoRedoService, - IUniverInstanceService, - LifecycleStages, - ObjectMatrix, - OnLifecycle, - RxDisposable, - UniverInstanceType, -} from '@univerjs/core'; -import type { ISheetData } from '@univerjs/engine-formula'; -import { Inject } from '@wendellhu/redi'; -import { takeUntil } from 'rxjs'; - -@OnLifecycle(LifecycleStages.Rendered, EditingController) -export class EditingController extends RxDisposable { - constructor( - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(IUndoRedoService) private readonly _undoRedoService: IUndoRedoService - ) { - super(); - - this._initialize(); - } - - private _initialize() { - this._initialNormalInput(); - this._listenEditorBlur(); - } - - private _listenEditorBlur() { - this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_DOC) - .pipe(takeUntil(this.dispose$)) - .subscribe((docDataModel) => { - if (docDataModel == null) { - return; - } - - const unitId = docDataModel.getUnitId(); - - // Clear undo redo stack of cell editor when lose focus. - if (unitId !== DOCS_NORMAL_EDITOR_UNIT_ID_KEY) { - this._undoRedoService.clearUndoRedo(DOCS_NORMAL_EDITOR_UNIT_ID_KEY); - } - }); - } - - private _initialNormalInput() { - /** - * const formulaEngine = this.getPluginByName('formula')?.getUniverFormulaEngine(); - * =(sum(max(B1:C10,10)*5-100,((1+1)*2+5)/2,10)+count(B1:C10,10*5-100))*5-100 - * =(sum(max(B1:C10,10)*5-100,((1+1)*2+5)/2,10, lambda(x,y, x*y*x)(sum(1,(1+2)*3),2))+lambda(x,y, x*y*x)(sum(1,(1+2)*3),2)+count(B1:C10,10*5-100))*5-100 - * =((1+2)-A1:B2 + 5)/2 + sum(indirect("A5"):B10 + A1:offset("C5", 1, 1), 100) - * =1+(3*4=4)*5+1 - * =(-(1+2)--@A1:B2 + 5)/2 + -sum(indirect("A5"):B10# + B6# + A1:offset("C5", 1, 1) , 100) + {1,2,3;4,5,6;7,8,10} + lambda(x,y,z, x*y*z)(sum(1,(1+2)*3),2,lambda(x,y, @offset(A1:B0,x#*y#))(1,2):C20) & "美国人才" + sum((1+2%)*30%, 1+2)% - * =lambda(x, y, lambda(x,y, x*lambda(x,y, x*y*x)(x,y))(x,y))(sum(1,2,3), 2) - * =let(x,5,y,4,sum(x,y)+x)) - * =REDUCE(1, A1:C2, LAMBDA(a,b,a+b^2)) - * =sum(, A1:B1) - * formulaEngine?.calculate(`=lambda(x,y, x*y*x)(sum(1,(1+2)*3),2)+1-max(100,200)`); - */ - const sheetData: ISheetData = {}; - this._univerInstanceService - .getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)! - .getSheets() - .forEach((sheet) => { - const sheetConfig = sheet.getConfig(); - sheetData[sheet.getSheetId()] = { - cellData: new ObjectMatrix(sheetConfig.cellData), - rowCount: sheetConfig.rowCount, - columnCount: sheetConfig.columnCount, - rowData: sheetConfig.rowData, - columnData: sheetConfig.columnData, - }; - }); - } -} diff --git a/packages/sheets-ui/src/controllers/editor/start-edit.controller.ts b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts similarity index 59% rename from packages/sheets-ui/src/controllers/editor/start-edit.controller.ts rename to packages/sheets-ui/src/controllers/editor/editing.render-controller.ts index e8098b7ee2..620fb2b5a6 100644 --- a/packages/sheets-ui/src/controllers/editor/start-edit.controller.ts +++ b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts @@ -14,12 +14,15 @@ * limitations under the License. */ -import type { ICommandInfo, IDocumentBody, IPosition, Nullable } from '@univerjs/core'; -import { +import type { ICellData, ICommandInfo, IDocumentBody, IPosition, Nullable, Workbook } from '@univerjs/core'; +import { CellValueType, DEFAULT_EMPTY_DOCUMENT_VALUE, + Direction, Disposable, + DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, EDITOR_ACTIVATED, FOCUSING_EDITOR_BUT_HIDDEN, + FOCUSING_EDITOR_INPUT_FORMULA, FOCUSING_EDITOR_STANDALONE, FOCUSING_FORMULA_EDITOR, FOCUSING_SHEET, @@ -27,10 +30,10 @@ import { HorizontalAlign, ICommandService, IContextService, + isFormulaString, + IUndoRedoService, IUniverInstanceService, - LifecycleStages, LocaleService, - OnLifecycle, toDisposable, Tools, VerticalAlign, @@ -42,10 +45,12 @@ import { DOCS_COMPONENT_MAIN_LAYER_INDEX, DocSkeletonManagerService, DocViewModelManagerService, + MoveCursorOperation, + MoveSelectionOperation, RichTextEditingMutation, TextSelectionManagerService, } from '@univerjs/docs'; -import type { DocumentSkeleton, IDocumentLayoutObject, IEditorInputConfig, Scene } from '@univerjs/engine-render'; +import type { DocumentSkeleton, IDocumentLayoutObject, IEditorInputConfig, IRenderContext, IRenderModule, Scene } from '@univerjs/engine-render'; import { convertTextRotation, DeviceInputEventType, @@ -58,14 +63,19 @@ import { } from '@univerjs/engine-render'; import { IEditorService, KeyCode, SetEditorResizeOperation } from '@univerjs/ui'; import { Inject } from '@wendellhu/redi'; - -import { ClearSelectionFormatCommand } from '@univerjs/sheets'; +import { ClearSelectionFormatCommand, SelectionManagerService, SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand } from '@univerjs/sheets'; import { filter } from 'rxjs'; +import { LexerTreeBuilder, matchToken } from '@univerjs/engine-formula'; + import { getEditorObject } from '../../basics/editor/get-editor-object'; -import { SetCellEditVisibleOperation } from '../../commands/operations/cell-edit.operation'; +import { SetCellEditVisibleArrowOperation, SetCellEditVisibleOperation, SetCellEditVisibleWithF2Operation } from '../../commands/operations/cell-edit.operation'; +import type { IEditorBridgeServiceVisibleParam } from '../../services/editor-bridge.service'; import { IEditorBridgeService } from '../../services/editor-bridge.service'; import { ICellEditorManagerService } from '../../services/editor/cell-editor-manager.service'; import styles from '../../views/sheet-container/index.module.less'; +import { MoveSelectionCommand, MoveSelectionEnterAndTabCommand } from '../../commands/commands/set-selection.command'; +import { MOVE_SELECTION_KEYCODE_LIST } from '../shortcuts/editor.shortcut'; +import { extractStringFromForceString, isForceString } from '../utils/cell-tools'; const HIDDEN_EDITOR_POSITION = -1000; @@ -78,12 +88,23 @@ interface ICanvasOffset { top: number; } -@OnLifecycle(LifecycleStages.Rendered, StartEditController) -export class StartEditController extends Disposable { +enum CursorChange { + InitialState, + StartEditor, + CursorChange, +} + +export class EditingRenderController extends Disposable implements IRenderModule { private _editorVisiblePrevious = false; + /** + * It is used to distinguish whether the user has actively moved the cursor in the editor, mainly through mouse clicks. + */ + private _cursorChange: CursorChange = CursorChange.InitialState; + constructor( - @Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService, + private readonly _context: IRenderContext, + @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, @Inject(DocViewModelManagerService) private readonly _docViewModelManagerService: DocViewModelManagerService, @IContextService private readonly _contextService: IContextService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, @@ -91,6 +112,8 @@ export class StartEditController extends Disposable { @IEditorBridgeService private readonly _editorBridgeService: IEditorBridgeService, @ICellEditorManagerService private readonly _cellEditorManagerService: ICellEditorManagerService, @ITextSelectionRenderManager private readonly _textSelectionRenderManager: ITextSelectionRenderManager, + @Inject(SelectionManagerService) private readonly _selectionManagerService: SelectionManagerService, + @Inject(LexerTreeBuilder) private readonly _lexerTreeBuilder: LexerTreeBuilder, @Inject(TextSelectionManagerService) private readonly _textSelectionManagerService: TextSelectionManagerService, @ICommandService private readonly _commandService: ICommandService, @Inject(LocaleService) protected readonly _localService: LocaleService, @@ -98,21 +121,18 @@ export class StartEditController extends Disposable { ) { super(); - this._initialize(); - - this._commandExecutedListener(); + this._init(); } - override dispose(): void { - super.dispose(); - } - - private _initialize() { + private _init() { this._initialEditFocusListener(); this._initialStartEdit(); this._initialKeyboardListener(); this._initialCursorSync(); this._listenEditorFocus(); + this._commandExecutedListener(); + this._initialExitInput(); + this._cursorStateListener(); } private _listenEditorFocus() { @@ -128,15 +148,14 @@ export class StartEditController extends Disposable { // fix https://github.com/dream-num/univer/issues/628, need to recalculate the cell editor size after it acquire focus. if (this._editorBridgeService.isVisible()) { const param = this._editorBridgeService.getEditCellState(); - const unitId = this._editorBridgeService.getCurrentEditorId(); + const editorId = this._editorBridgeService.getCurrentEditorId(); - if (param == null || unitId == null || !this._editorService.isSheetEditor(unitId)) { + if (param == null || editorId == null || !this._editorService.isSheetEditor(editorId)) { return; } - const skeleton = this._docSkeletonManagerService.getSkeletonByUnitId(unitId)?.skeleton; - - if (skeleton == null) { + const skeleton = this._getEditorSkeleton(editorId); + if (!skeleton) { return; } @@ -149,6 +168,10 @@ export class StartEditController extends Disposable { ); } + private _getEditorSkeleton(editorId: string) { + return this._renderManagerService.getRenderById(editorId)?.with(DocSkeletonManagerService).getSkeleton(); + } + private _initialCursorSync() { this.disposeWithMe( this._cellEditorManagerService.focus$.pipe(filter((f) => !!f)).subscribe(() => { @@ -505,15 +528,11 @@ export class StartEditController extends Disposable { this._contextService.setContextValue(EDITOR_ACTIVATED, true); const { documentModel: documentDataModel } = documentLayoutObject; - - const docParam = this._docSkeletonManagerService.getSkeletonByUnitId(editorUnitId); - - if (docParam == null || documentDataModel == null) { + const skeleton = this._getEditorSkeleton(editorUnitId); + if (!skeleton || !documentDataModel) { return; } - const { skeleton } = docParam; - this._fitTextSize(position, canvasOffset, skeleton, documentLayoutObject, scaleX, scaleY); // move selection if ( @@ -652,20 +671,18 @@ export class StartEditController extends Disposable { return; } - const unitId = this._editorBridgeService.getCurrentEditorId(); - - if (unitId == null) { + const editorId = this._editorBridgeService.getCurrentEditorId(); + if (editorId == null) { return; } - this._editorBridgeService.changeEditorDirty(true); - - const skeleton = this._docSkeletonManagerService.getSkeletonByUnitId(unitId)?.skeleton; - + const skeleton = this._getEditorSkeleton(editorId); if (skeleton == null) { return; } + this._editorBridgeService.changeEditorDirty(true); + const param = this._editorBridgeService.getEditCellState(); if (param == null) { return; @@ -686,6 +703,34 @@ export class StartEditController extends Disposable { } }) ); + + const closeEditorOperation = [SetCellEditVisibleArrowOperation.id]; + this.disposeWithMe( + this._commandService.onCommandExecuted((command: ICommandInfo) => { + if (closeEditorOperation.includes(command.id)) { + const params = command.params as IEditorBridgeServiceVisibleParam & { isShift: boolean }; + const { keycode, isShift } = params; + + /** + * After the user enters the editor and actively moves the editor selection area with the mouse, + * the up, down, left, and right keys can no longer switch editing cells, + * but move the cursor within the editor instead. + */ + if (keycode != null && + (this._cursorChange === CursorChange.CursorChange || this._contextService.getContextValue(FOCUSING_FORMULA_EDITOR)) + ) { + this._moveInEditor(keycode, isShift); + return; + } + + this._editorBridgeService.changeVisible(params); + } + + if (command.id === SetCellEditVisibleWithF2Operation.id) { + this._cursorChange = CursorChange.CursorChange; + } + }) + ); } private _setOpenForCurrent(unitId: Nullable, sheetId: Nullable) { @@ -703,4 +748,341 @@ export class StartEditController extends Disposable { private _getEditorObject() { return getEditorObject(this._editorBridgeService.getCurrentEditorId(), this._renderManagerService); } + + // private _init() { + // this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_DOC) + // .pipe(takeUntil(this.dispose$)) + // .subscribe((docDataModel) => { + // if (docDataModel == null) { + // return; + // } + + // const unitId = docDataModel.getUnitId(); + + // // Clear undo redo stack of cell editor when lose focus. + // // WTF@wzhudev: this should be implemented in end-editor controller. + // if (unitId !== DOCS_NORMAL_EDITOR_UNIT_ID_KEY) { + // this._undoRedoService.clearUndoRedo(DOCS_NORMAL_EDITOR_UNIT_ID_KEY); + // } + // }); + // } + + private _initialExitInput() { + this.disposeWithMe( + this._editorBridgeService.visible$.subscribe(async (param) => { + const { visible, keycode, eventType } = param; + + if (visible === this._editorVisiblePrevious) { + return; + } + + this._editorVisiblePrevious = visible; + + if (visible === true) { + // Change `CursorChange` to changed status, when formula bar clicked. + this._cursorChange = + eventType === DeviceInputEventType.PointerDown + ? CursorChange.CursorChange + : CursorChange.StartEditor; + return; + } + + this._cursorChange = CursorChange.InitialState; + + const selections = this._selectionManagerService.getSelections(); + const currentSelection = this._selectionManagerService.getCurrent(); + + if (currentSelection == null) { + return; + } + + const { unitId: workbookId, sheetId: worksheetId, pluginName } = currentSelection; + + this._exitInput(param); + + if (keycode === KeyCode.ESC) { + // Reselect the current selections, when exist cell editor by press ESC. + if (selections) { + this._commandService.syncExecuteCommand(SetSelectionsOperation.id, { + unitId: workbookId, + subUnitId: worksheetId, + pluginName, + selections, + }); + } + + return; + } + + const editCellState = this._editorBridgeService.getEditCellState(); + + if (editCellState == null) { + return; + } + + const { unitId, sheetId, row, column, documentLayoutObject } = editCellState; + + // If neither the formula bar editor nor the cell editor has been edited, + // it is considered that the content has not changed and returns directly. + const editorIsDirty = this._editorBridgeService.getEditorDirty(); + if (editorIsDirty === false) { + this._moveCursor(keycode); + + return; + } + + const workbook = this._univerInstanceService.getUniverSheetInstance(unitId); + + const worksheet = workbook?.getSheetBySheetId(sheetId); + + if (worksheet == null) { + return; + } + + const cellData: Nullable = getCellDataByInput( + worksheet.getCellRaw(row, column) || {}, + documentLayoutObject, + this._lexerTreeBuilder + ); + + if (cellData == null) { + this._moveCursor(keycode); + + return; + } + + const context = { + subUnitId: sheetId, + unitId, + workbook: workbook!, + worksheet, + row, + col: column, + }; + + /** + * When closing the editor, switch to the current tab of the editor. + */ + if (workbookId === unitId && sheetId !== worksheetId && this._editorBridgeService.isForceKeepVisible()) { + // SetWorksheetActivateCommand handler uses Promise + await this._commandService.executeCommand(SetWorksheetActivateCommand.id, { + subUnitId: sheetId, + unitId, + }); + } + /** + * When switching tabs while the editor is open, + * the operation to refresh the selection will be blocked and needs to be triggered manually. + */ + this._selectionManagerService.refreshSelection(); + + const cell = this._editorBridgeService.interceptor.fetchThroughInterceptors( + this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT + )(cellData, context); + + const finalCell = await this._editorBridgeService.interceptor.fetchThroughInterceptors( + this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT_ASYNC + )(Promise.resolve(cell), context); + + this._commandService.executeCommand(SetRangeValuesCommand.id, { + subUnitId: sheetId, + unitId, + range: { + startRow: row, + startColumn: column, + endRow: row, + endColumn: column, + }, + value: finalCell, + }); + + // moveCursor need to put behind of SetRangeValuesCommand, fix https://github.com/dream-num/univer/issues/1155 + this._moveCursor(keycode); + }) + ); + } + + private _exitInput(param: IEditorBridgeServiceVisibleParam) { + this._contextService.setContextValue(FOCUSING_EDITOR_INPUT_FORMULA, false); + this._contextService.setContextValue(EDITOR_ACTIVATED, false); + this._contextService.setContextValue(FOCUSING_EDITOR_BUT_HIDDEN, false); + this._contextService.setContextValue(FOCUSING_FORMULA_EDITOR, false); + + this._cellEditorManagerService.setState({ + show: param.visible, + }); + const editorUnitId = this._editorBridgeService.getCurrentEditorId(); + if (editorUnitId == null || !this._editorService.isSheetEditor(editorUnitId)) { + return; + } + this._undoRedoService.clearUndoRedo(editorUnitId); + this._undoRedoService.clearUndoRedo(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY); + } + + private _moveCursor(keycode?: KeyCode) { + if (keycode == null || !MOVE_SELECTION_KEYCODE_LIST.includes(keycode)) { + return; + } + + let direction = Direction.LEFT; + + switch (keycode) { + case KeyCode.ENTER: + direction = Direction.DOWN; + break; + case KeyCode.TAB: + direction = Direction.RIGHT; + break; + case KeyCode.ARROW_DOWN: + direction = Direction.DOWN; + break; + case KeyCode.ARROW_UP: + direction = Direction.UP; + break; + case KeyCode.ARROW_LEFT: + direction = Direction.LEFT; + break; + case KeyCode.ARROW_RIGHT: + direction = Direction.RIGHT; + break; + } + + if (keycode === KeyCode.ENTER || keycode === KeyCode.TAB) { + this._commandService.executeCommand(MoveSelectionEnterAndTabCommand.id, { + keycode, + direction, + }); + } else { + this._commandService.executeCommand(MoveSelectionCommand.id, { + direction, + }); + } + } + + private _cursorStateListener() { + /** + * The user's operations follow the sequence of opening the editor and then moving the cursor. + * The logic here predicts the user's first cursor movement behavior based on this rule + */ + + const editorObject = this._getEditorObject(); + if (editorObject == null) { + return; + } + + const { document: documentComponent } = editorObject; + + this.disposeWithMe( + toDisposable( + documentComponent.onPointerDownObserver.add(() => { + if (this._cursorChange === CursorChange.StartEditor) { + this._cursorChange = CursorChange.CursorChange; + } + }) + ) + ); + } + + // TODO: @JOCS, is it necessary to move these commands MoveSelectionOperation\MoveCursorOperation to shortcut? and use multi-commands? + private _moveInEditor(keycode: KeyCode, isShift: boolean) { + let direction = Direction.LEFT; + if (keycode === KeyCode.ARROW_DOWN) { + direction = Direction.DOWN; + } else if (keycode === KeyCode.ARROW_UP) { + direction = Direction.UP; + } else if (keycode === KeyCode.ARROW_RIGHT) { + direction = Direction.RIGHT; + } + + if (isShift) { + this._commandService.executeCommand(MoveSelectionOperation.id, { + direction, + }); + } else { + this._commandService.executeCommand(MoveCursorOperation.id, { + direction, + }); + } + } } + +export function getCellDataByInput( + cellData: ICellData, + documentLayoutObject: IDocumentLayoutObject, + lexerTreeBuilder: LexerTreeBuilder +) { + cellData = Tools.deepClone(cellData); + + const { documentModel } = documentLayoutObject; + if (documentModel == null) { + return null; + } + + const snapshot = documentModel.getSnapshot(); + + const { body } = snapshot; + if (body == null) { + return null; + } + + cellData.t = undefined; + + const data = body.dataStream; + const lastString = data.substring(data.length - 2, data.length); + let newDataStream = lastString === DEFAULT_EMPTY_DOCUMENT_VALUE ? data.substring(0, data.length - 2) : data; + + if (isFormulaString(newDataStream)) { + if (cellData.f === newDataStream) { + return null; + } + const bracketCount = lexerTreeBuilder.checkIfAddBracket(newDataStream); + for (let i = 0; i < bracketCount; i++) { + newDataStream += matchToken.CLOSE_BRACKET; + } + + cellData.f = newDataStream; + cellData.v = null; + cellData.p = null; + } else if (isForceString(newDataStream)) { + const v = extractStringFromForceString(newDataStream); + cellData.v = v; + cellData.f = null; + cellData.si = null; + cellData.p = null; + cellData.t = CellValueType.FORCE_STRING; + } else if (isRichText(body)) { + if (body.dataStream === '\r\n') { + cellData.v = ''; + cellData.f = null; + cellData.si = null; + cellData.p = null; + } else { + cellData.p = snapshot; + cellData.v = null; + cellData.f = null; + cellData.si = null; + } + } else { + // If the data is empty, the data is set to null. + if ((newDataStream === cellData.v || (newDataStream === '' && cellData.v == null)) && cellData.p == null) { + return null; + } + cellData.v = newDataStream; + cellData.f = null; + cellData.si = null; + cellData.p = null; + } + + return cellData; +} + +function isRichText(body: IDocumentBody) { + const { textRuns = [], paragraphs = [] } = body; + + return ( + textRuns.some((textRun) => textRun.ts && !Tools.isEmptyObject(textRun.ts)) || + paragraphs.some((paragraph) => paragraph.bullet) || + paragraphs.length >= 2 + ); +} + diff --git a/packages/sheets-ui/src/controllers/editor/end-edit.controller.ts b/packages/sheets-ui/src/controllers/editor/end-edit.controller.ts deleted file mode 100644 index 0da34baf04..0000000000 --- a/packages/sheets-ui/src/controllers/editor/end-edit.controller.ts +++ /dev/null @@ -1,468 +0,0 @@ -/** - * 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 { ICellData, ICommandInfo, IDocumentBody, Nullable, Observer } from '@univerjs/core'; -import { CellValueType, - DEFAULT_EMPTY_DOCUMENT_VALUE, - Direction, - Disposable, - DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, - EDITOR_ACTIVATED, - FOCUSING_EDITOR_BUT_HIDDEN, - FOCUSING_EDITOR_INPUT_FORMULA, - FOCUSING_FORMULA_EDITOR, - ICommandService, - IContextService, - isFormulaString, - IUndoRedoService, - IUniverInstanceService, - LifecycleStages, - OnLifecycle, - toDisposable, - Tools, -} from '@univerjs/core'; -import { MoveCursorOperation, MoveSelectionOperation } from '@univerjs/docs'; -import { LexerTreeBuilder, matchToken } from '@univerjs/engine-formula'; -import type { IDocumentLayoutObject, IMouseEvent, IPointerEvent } from '@univerjs/engine-render'; -import { DeviceInputEventType, IRenderManagerService } from '@univerjs/engine-render'; -import { - SelectionManagerService, - SetRangeValuesCommand, - SetSelectionsOperation, - SetWorksheetActivateCommand, -} from '@univerjs/sheets'; -import { IEditorService, KeyCode } from '@univerjs/ui'; -import { Inject } from '@wendellhu/redi'; - -import { getEditorObject } from '../../basics/editor/get-editor-object'; -import { MoveSelectionCommand, MoveSelectionEnterAndTabCommand } from '../../commands/commands/set-selection.command'; -import { SetCellEditVisibleArrowOperation, SetCellEditVisibleWithF2Operation } from '../../commands/operations/cell-edit.operation'; -import { ICellEditorManagerService } from '../../services/editor/cell-editor-manager.service'; -import type { IEditorBridgeServiceVisibleParam } from '../../services/editor-bridge.service'; -import { IEditorBridgeService } from '../../services/editor-bridge.service'; -import { MOVE_SELECTION_KEYCODE_LIST } from '../shortcuts/editor.shortcut'; -import { extractStringFromForceString, isForceString } from '../utils/cell-tools'; - -function isRichText(body: IDocumentBody) { - const { textRuns = [], paragraphs = [] } = body; - - return ( - textRuns.some((textRun) => textRun.ts && !Tools.isEmptyObject(textRun.ts)) || - paragraphs.some((paragraph) => paragraph.bullet) || - paragraphs.length >= 2 - ); -} - -enum CursorChange { - InitialState, - StartEditor, - CursorChange, -} - -@OnLifecycle(LifecycleStages.Rendered, EndEditController) -export class EndEditController extends Disposable { - private _cursorChangeObservers: Nullable>; - - private _editorVisiblePrevious = false; - - /** - * It is used to distinguish whether the user has actively moved the cursor in the editor, mainly through mouse clicks. - */ - private _cursorChange: CursorChange = CursorChange.InitialState; - - constructor( - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @ICommandService private readonly _commandService: ICommandService, - @IEditorBridgeService private readonly _editorBridgeService: IEditorBridgeService, - @IContextService private readonly _contextService: IContextService, - @ICellEditorManagerService private readonly _cellEditorManagerService: ICellEditorManagerService, - @Inject(LexerTreeBuilder) private readonly _lexerTreeBuilder: LexerTreeBuilder, - @IUndoRedoService private _undoRedoService: IUndoRedoService, - @Inject(SelectionManagerService) private readonly _selectionManagerService: SelectionManagerService, - @IEditorService private _editorService: IEditorService - ) { - super(); - - this._initialize(); - - this._commandExecutedListener(); - } - - override dispose(): void { - const editorObject = this._getEditorObject(); - - if (editorObject == null) { - return; - } - - const { document: documentComponent } = editorObject; - documentComponent.onPointerDownObserver.remove(this._cursorChangeObservers); - - super.dispose(); - } - - private _initialize() { - this._initialExitInput(); - - this._cursorStateListener(); - } - - // eslint-disable-next-line max-lines-per-function - private _initialExitInput() { - this.disposeWithMe( - // eslint-disable-next-line max-lines-per-function - this._editorBridgeService.visible$.subscribe(async (param) => { - const { visible, keycode, eventType } = param; - - if (visible === this._editorVisiblePrevious) { - return; - } - - this._editorVisiblePrevious = visible; - - if (visible === true) { - // Change `CursorChange` to changed status, when formula bar clicked. - this._cursorChange = - eventType === DeviceInputEventType.PointerDown - ? CursorChange.CursorChange - : CursorChange.StartEditor; - return; - } - - this._cursorChange = CursorChange.InitialState; - - const selections = this._selectionManagerService.getSelections(); - const currentSelection = this._selectionManagerService.getCurrent(); - - if (currentSelection == null) { - return; - } - - const { unitId: workbookId, sheetId: worksheetId, pluginName } = currentSelection; - - this._exitInput(param); - - if (keycode === KeyCode.ESC) { - // Reselect the current selections, when exist cell editor by press ESC. - if (selections) { - this._commandService.syncExecuteCommand(SetSelectionsOperation.id, { - unitId: workbookId, - subUnitId: worksheetId, - pluginName, - selections, - }); - } - - return; - } - - const editCellState = this._editorBridgeService.getEditCellState(); - - if (editCellState == null) { - return; - } - - const { unitId, sheetId, row, column, documentLayoutObject } = editCellState; - - // If neither the formula bar editor nor the cell editor has been edited, - // it is considered that the content has not changed and returns directly. - const editorIsDirty = this._editorBridgeService.getEditorDirty(); - if (editorIsDirty === false) { - this._moveCursor(keycode); - - return; - } - - const workbook = this._univerInstanceService.getUniverSheetInstance(unitId); - - const worksheet = workbook?.getSheetBySheetId(sheetId); - - if (worksheet == null) { - return; - } - - const cellData: Nullable = getCellDataByInput( - worksheet.getCellRaw(row, column) || {}, - documentLayoutObject, - this._lexerTreeBuilder - ); - - if (cellData == null) { - this._moveCursor(keycode); - - return; - } - - const context = { - subUnitId: sheetId, - unitId, - workbook: workbook!, - worksheet, - row, - col: column, - }; - - /** - * When closing the editor, switch to the current tab of the editor. - */ - if (workbookId === unitId && sheetId !== worksheetId && this._editorBridgeService.isForceKeepVisible()) { - // SetWorksheetActivateCommand handler uses Promise - await this._commandService.executeCommand(SetWorksheetActivateCommand.id, { - subUnitId: sheetId, - unitId, - }); - } - /** - * When switching tabs while the editor is open, - * the operation to refresh the selection will be blocked and needs to be triggered manually. - */ - this._selectionManagerService.refreshSelection(); - - const cell = this._editorBridgeService.interceptor.fetchThroughInterceptors( - this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT - )(cellData, context); - - const finalCell = await this._editorBridgeService.interceptor.fetchThroughInterceptors( - this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT_ASYNC - )(Promise.resolve(cell), context); - - this._commandService.executeCommand(SetRangeValuesCommand.id, { - subUnitId: sheetId, - unitId, - range: { - startRow: row, - startColumn: column, - endRow: row, - endColumn: column, - }, - value: finalCell, - }); - - // moveCursor need to put behind of SetRangeValuesCommand, fix https://github.com/dream-num/univer/issues/1155 - this._moveCursor(keycode); - }) - ); - } - - private _exitInput(param: IEditorBridgeServiceVisibleParam) { - this._contextService.setContextValue(FOCUSING_EDITOR_INPUT_FORMULA, false); - this._contextService.setContextValue(EDITOR_ACTIVATED, false); - this._contextService.setContextValue(FOCUSING_EDITOR_BUT_HIDDEN, false); - this._contextService.setContextValue(FOCUSING_FORMULA_EDITOR, false); - - this._cellEditorManagerService.setState({ - show: param.visible, - }); - const editorUnitId = this._editorBridgeService.getCurrentEditorId(); - if (editorUnitId == null || !this._editorService.isSheetEditor(editorUnitId)) { - return; - } - this._undoRedoService.clearUndoRedo(editorUnitId); - this._undoRedoService.clearUndoRedo(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY); - } - - private _moveCursor(keycode?: KeyCode) { - if (keycode == null || !MOVE_SELECTION_KEYCODE_LIST.includes(keycode)) { - return; - } - - let direction = Direction.LEFT; - - switch (keycode) { - case KeyCode.ENTER: - direction = Direction.DOWN; - break; - case KeyCode.TAB: - direction = Direction.RIGHT; - break; - case KeyCode.ARROW_DOWN: - direction = Direction.DOWN; - break; - case KeyCode.ARROW_UP: - direction = Direction.UP; - break; - case KeyCode.ARROW_LEFT: - direction = Direction.LEFT; - break; - case KeyCode.ARROW_RIGHT: - direction = Direction.RIGHT; - break; - } - - if (keycode === KeyCode.ENTER || keycode === KeyCode.TAB) { - this._commandService.executeCommand(MoveSelectionEnterAndTabCommand.id, { - keycode, - direction, - }); - } else { - this._commandService.executeCommand(MoveSelectionCommand.id, { - direction, - }); - } - } - - private _cursorStateListener() { - /** - * The user's operations follow the sequence of opening the editor and then moving the cursor. - * The logic here predicts the user's first cursor movement behavior based on this rule - */ - - const editorObject = this._getEditorObject(); - if (editorObject == null) { - return; - } - - const { document: documentComponent } = editorObject; - - this.disposeWithMe( - toDisposable( - documentComponent.onPointerDownObserver.add(() => { - if (this._cursorChange === CursorChange.StartEditor) { - this._cursorChange = CursorChange.CursorChange; - } - }) - ) - ); - } - - private _commandExecutedListener() { - const updateCommandList = [SetCellEditVisibleArrowOperation.id]; - - this.disposeWithMe( - this._commandService.onCommandExecuted((command: ICommandInfo) => { - if (updateCommandList.includes(command.id)) { - const params = command.params as IEditorBridgeServiceVisibleParam & { isShift: boolean }; - const { keycode, isShift } = params; - - /** - * After the user enters the editor and actively moves the editor selection area with the mouse, - * the up, down, left, and right keys can no longer switch editing cells, - * but move the cursor within the editor instead. - */ - if (keycode != null && - (this._cursorChange === CursorChange.CursorChange || this._contextService.getContextValue(FOCUSING_FORMULA_EDITOR)) - ) { - this._moveInEditor(keycode, isShift); - return; - } - - this._editorBridgeService.changeVisible(params); - } - - if (command.id === SetCellEditVisibleWithF2Operation.id) { - this._cursorChange = CursorChange.CursorChange; - } - }) - ); - } - - // TODO: @JOCS, is it necessary to move these commands MoveSelectionOperation\MoveCursorOperation to shortcut? and use multi-commands? - private _moveInEditor(keycode: KeyCode, isShift: boolean) { - let direction = Direction.LEFT; - if (keycode === KeyCode.ARROW_DOWN) { - direction = Direction.DOWN; - } else if (keycode === KeyCode.ARROW_UP) { - direction = Direction.UP; - } else if (keycode === KeyCode.ARROW_RIGHT) { - direction = Direction.RIGHT; - } - - if (isShift) { - this._commandService.executeCommand(MoveSelectionOperation.id, { - direction, - }); - } else { - this._commandService.executeCommand(MoveCursorOperation.id, { - direction, - }); - } - } - - private _getEditorObject() { - return getEditorObject(this._editorBridgeService.getCurrentEditorId(), this._renderManagerService); - } -} - -export function getCellDataByInput( - cellData: ICellData, - documentLayoutObject: IDocumentLayoutObject, - lexerTreeBuilder: LexerTreeBuilder -) { - cellData = Tools.deepClone(cellData); - - const { documentModel } = documentLayoutObject; - if (documentModel == null) { - return null; - } - - const snapshot = documentModel.getSnapshot(); - - const { body } = snapshot; - if (body == null) { - return null; - } - - cellData.t = undefined; - - const data = body.dataStream; - const lastString = data.substring(data.length - 2, data.length); - let newDataStream = lastString === DEFAULT_EMPTY_DOCUMENT_VALUE ? data.substring(0, data.length - 2) : data; - - if (isFormulaString(newDataStream)) { - if (cellData.f === newDataStream) { - return null; - } - const bracketCount = lexerTreeBuilder.checkIfAddBracket(newDataStream); - for (let i = 0; i < bracketCount; i++) { - newDataStream += matchToken.CLOSE_BRACKET; - } - - cellData.f = newDataStream; - cellData.v = null; - cellData.p = null; - } else if (isForceString(newDataStream)) { - const v = extractStringFromForceString(newDataStream); - cellData.v = v; - cellData.f = null; - cellData.si = null; - cellData.p = null; - cellData.t = CellValueType.FORCE_STRING; - } else if (isRichText(body)) { - if (body.dataStream === '\r\n') { - cellData.v = ''; - cellData.f = null; - cellData.si = null; - cellData.p = null; - } else { - cellData.p = snapshot; - cellData.v = null; - cellData.f = null; - cellData.si = null; - } - } else { - // If the data is empty, the data is set to null. - if ((newDataStream === cellData.v || (newDataStream === '' && cellData.v == null)) && cellData.p == null) { - return null; - } - cellData.v = newDataStream; - cellData.f = null; - cellData.si = null; - cellData.p = null; - } - - return cellData; -} diff --git a/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts b/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts index 8bbfcb9f14..8f68edacad 100644 --- a/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts +++ b/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts @@ -67,7 +67,6 @@ export class FormulaEditorController extends RxDisposable { @IContextService private readonly _contextService: IContextService, @IFormulaEditorManagerService private readonly _formulaEditorManagerService: IFormulaEditorManagerService, @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, - @Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService, @Inject(DocViewModelManagerService) private readonly _docViewModelManagerService: DocViewModelManagerService, @Inject(TextSelectionManagerService) private readonly _textSelectionManagerService: TextSelectionManagerService ) { @@ -423,12 +422,16 @@ export class FormulaEditorController extends RxDisposable { actions: JSONXActions ) { const INCLUDE_LIST = [DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY]; + const currentRender = this._renderManagerService.getRenderById(unitId); + if (currentRender == null) { + return; + } - const docsSkeletonObject = this._docSkeletonManagerService.getSkeletonByUnitId(unitId); + const skeleton = currentRender.with(DocSkeletonManagerService).getSkeleton(); const docDataModel = this._univerInstanceService.getUniverDocInstance(unitId); const docViewModel = this._docViewModelManagerService.getViewModel(unitId); - if (docDataModel == null || docViewModel == null || docsSkeletonObject == null) { + if (docDataModel == null || docViewModel == null) { return; } @@ -439,14 +442,6 @@ export class FormulaEditorController extends RxDisposable { docViewModel.reset(docDataModel); - const { skeleton } = docsSkeletonObject; - - const currentRender = this._renderManagerService.getRenderById(unitId); - - if (currentRender == null) { - return; - } - skeleton.calculate(); if (INCLUDE_LIST.includes(unitId)) { @@ -462,11 +457,11 @@ export class FormulaEditorController extends RxDisposable { ) { const INCLUDE_LIST = [DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY]; - const docsSkeletonObject = this._docSkeletonManagerService.getSkeletonByUnitId(unitId); + const skeleton = this._renderManagerService.getRenderById(unitId)?.with(DocSkeletonManagerService).getSkeleton(); const docDataModel = this._univerInstanceService.getUniverDocInstance(unitId); const docViewModel = this._docViewModelManagerService.getViewModel(unitId); - if (docDataModel == null || docViewModel == null || docsSkeletonObject == null) { + if (docDataModel == null || docViewModel == null || skeleton == null) { return; } @@ -481,8 +476,6 @@ export class FormulaEditorController extends RxDisposable { docViewModel.reset(docDataModel); - const { skeleton } = docsSkeletonObject; - const currentRender = this._renderManagerService.getRenderById(unitId); if (currentRender == null) { @@ -530,10 +523,9 @@ export class FormulaEditorController extends RxDisposable { } private _autoScroll() { - const skeleton = this._docSkeletonManagerService.getSkeletonByUnitId(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY) - ?.skeleton; const position = this._formulaEditorManagerService.getPosition(); + const skeleton = this._renderManagerService.getRenderById(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY)?.with(DocSkeletonManagerService).getSkeleton(); const editorObject = this._renderManagerService.getRenderById(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY); const formulaEditorDataModel = this._univerInstanceService.getUniverDocInstance( diff --git a/packages/sheets-ui/src/sheets-ui-plugin.ts b/packages/sheets-ui/src/sheets-ui-plugin.ts index e3153134e7..f51e5f94f7 100644 --- a/packages/sheets-ui/src/sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/sheets-ui-plugin.ts @@ -26,10 +26,8 @@ import { UniverUIPlugin } from '@univerjs/ui'; import { ActiveWorksheetController } from './controllers/active-worksheet/active-worksheet.controller'; import { AutoHeightController } from './controllers/auto-height.controller'; import { SheetClipboardController } from './controllers/clipboard/clipboard.controller'; -import { EditingController } from './controllers/editor/editing.controller'; -import { EndEditController } from './controllers/editor/end-edit.controller'; import { FormulaEditorController } from './controllers/editor/formula-editor.controller'; -import { StartEditController } from './controllers/editor/start-edit.controller'; +import { EditingRenderController } from './controllers/editor/editing.render-controller'; import { FormatPainterRenderController } from './controllers/render-controllers/format-painter.render-controller'; import { HeaderFreezeRenderController } from './controllers/render-controllers/freeze.render-controller'; import { HeaderMenuRenderController } from './controllers/render-controllers/header-menu.render-controller'; @@ -130,7 +128,6 @@ export class UniverSheetsUIPlugin extends Plugin { // controllers [ActiveWorksheetController], [AutoHeightController], - [EndEditController], [FormulaEditorController], [HeaderFreezeRenderController], [SheetClipboardController], @@ -141,9 +138,7 @@ export class UniverSheetsUIPlugin extends Plugin { useFactory: () => this._injector.createInstance(SheetUIController, this._config), }, ], - [StartEditController], [StatusBarController], - [EditingController], [AutoFillController], [FormatPainterController], @@ -213,8 +208,12 @@ export class UniverSheetsUIPlugin extends Plugin { ForceStringRenderController, CellCustomRenderController, SheetContextMenuRenderController, + + // editor EditorBridgeRenderController, + EditingRenderController, + // permission SheetPermissionInterceptorCanvasRenderController, SheetPermissionInterceptorFormulaRenderController, SheetPermissionRenderController, @@ -227,8 +226,6 @@ export class UniverSheetsUIPlugin extends Plugin { const univerInstanceService = this._univerInstanceService; univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET) .pipe(filter((v) => !!v)) - .subscribe((workbook) => { - univerInstanceService.focusUnit(workbook!.getUnitId()); - }); + .subscribe((workbook) => univerInstanceService.focusUnit(workbook!.getUnitId())); } } diff --git a/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts b/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts index 299b8492f5..73b702228f 100644 --- a/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts +++ b/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts @@ -61,7 +61,6 @@ export class ZenEditorController extends RxDisposable { @IEditorBridgeService private readonly _editorBridgeService: IEditorBridgeService, @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, @Inject(TextSelectionManagerService) private readonly _textSelectionManagerService: TextSelectionManagerService, - @Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService, @Inject(DocViewModelManagerService) private readonly _docViewModelManagerService: DocViewModelManagerService ) { super(); @@ -221,11 +220,11 @@ export class ZenEditorController extends RxDisposable { DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, ]; - const docsSkeletonObject = this._docSkeletonManagerService.getSkeletonByUnitId(unitId); + const skeleton = this._renderManagerService.getRenderById(unitId)?.with(DocSkeletonManagerService); const docDataModel = this._univerInstanceService.getUniverDocInstance(unitId); const docViewModel = this._docViewModelManagerService.getViewModel(unitId); - if (docDataModel == null || docViewModel == null || docsSkeletonObject == null) { + if (docDataModel == null || docViewModel == null || skeleton == null) { return; } @@ -245,8 +244,6 @@ export class ZenEditorController extends RxDisposable { docViewModel.reset(docDataModel); - const { skeleton } = docsSkeletonObject; - const currentRender = this._getDocObject(); if (currentRender == null) { diff --git a/packages/ui/src/controllers/ui/ui-desktop.controller.tsx b/packages/ui/src/controllers/ui/ui-desktop.controller.tsx index 819724588a..25761b7161 100644 --- a/packages/ui/src/controllers/ui/ui-desktop.controller.tsx +++ b/packages/ui/src/controllers/ui/ui-desktop.controller.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Disposable, IUniverInstanceService, LifecycleService, LifecycleStages, toDisposable } from '@univerjs/core'; +import { Disposable, isInternalEditorID, IUniverInstanceService, LifecycleService, LifecycleStages, toDisposable } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import type { IDisposable } from '@wendellhu/redi'; import { Inject, Injector, Optional } from '@wendellhu/redi'; @@ -53,14 +53,12 @@ export class DesktopUIController extends Disposable { this.disposeWithMe(this._layoutService.registerCanvasElement(canvasElement as HTMLCanvasElement)); } - // TODO: this is subject to change in the future + // TODO: this is subject to change in the future for Uni-mode this._renderManagerService.currentRender$.subscribe((renderId) => { if (renderId) { const render = this._renderManagerService.getRenderById(renderId)!; if (!render.unitId) return; - - // const unitType = this._instanceService.getUnitType(render.unitId); - // if (unitType !== UniverInstanceType.UNIVER_SHEET) return; + if (isInternalEditorID(render.unitId)) return; render.engine.setContainer(canvasElement); } diff --git a/packages/ui/src/services/editor/editor.service.ts b/packages/ui/src/services/editor/editor.service.ts index 1da1bfbf76..867acab62c 100644 --- a/packages/ui/src/services/editor/editor.service.ts +++ b/packages/ui/src/services/editor/editor.service.ts @@ -17,7 +17,7 @@ import type { DocumentDataModel, IDocumentBody, IDocumentData, IDocumentStyle, IPosition, Nullable, Workbook } from '@univerjs/core'; import { DEFAULT_EMPTY_DOCUMENT_VALUE, DEFAULT_STYLES, Disposable, EDITOR_ACTIVATED, FOCUSING_EDITOR_INPUT_FORMULA, FOCUSING_EDITOR_STANDALONE, FOCUSING_UNIVER_EDITOR_STANDALONE_SINGLE_MODE, HorizontalAlign, IContextService, IUniverInstanceService, toDisposable, UniverInstanceType, VerticalAlign } from '@univerjs/core'; import type { IDisposable } from '@wendellhu/redi'; -import { createIdentifier, Inject, Injector } from '@wendellhu/redi'; +import { createIdentifier, Inject } from '@wendellhu/redi'; import type { Observable } from 'rxjs'; import { Subject } from 'rxjs'; import type { IRender, ISuccinctTextRangeParam, Scene } from '@univerjs/engine-render'; @@ -353,7 +353,6 @@ export class EditorService extends Disposable implements IEditorService, IDispos private _spreadsheetFocusState: boolean = false; constructor( - @Inject(Injector) private readonly _injector: Injector, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @Inject(LexerTreeBuilder) private readonly _lexerTreeBuilder: LexerTreeBuilder, @@ -617,10 +616,11 @@ export class EditorService extends Disposable implements IEditorService, IDispos register(config: IEditorConfigParam, container: HTMLDivElement): IDisposable { const { initialSnapshot, editorUnitId, canvasStyle = {} } = config; - const documentDataModel = this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_DOC, initialSnapshot || this._getBlank(editorUnitId)); + const documentDataModel = this._univerInstanceService.createUnit( + UniverInstanceType.UNIVER_DOC, initialSnapshot || this._getBlank(editorUnitId) + ); let render = this._renderManagerService.getRenderById(editorUnitId); - if (render == null) { this._renderManagerService.create(editorUnitId); render = this._renderManagerService.getRenderById(editorUnitId)!; diff --git a/packages/ui/src/ui-plugin.ts b/packages/ui/src/ui-plugin.ts index f87bc2c928..6fafa06539 100644 --- a/packages/ui/src/ui-plugin.ts +++ b/packages/ui/src/ui-plugin.ts @@ -144,6 +144,6 @@ export class UniverUIPlugin extends Plugin { private _initUI(): void { // We need to run this async to let other modules do their `onReady` jobs first. - Promise.resolve().then(() => this._injector.get(IUIController).bootstrapWorkbench(this._config)); + setTimeout(() => this._injector.get(IUIController).bootstrapWorkbench(this._config), 16); } }