fix(docs): scroll to selection (#3458)

This commit is contained in:
Ran Luo
2024-09-18 18:18:46 +08:00
committed by GitHub
parent c357724305
commit 3cf7b461dc
4 changed files with 48 additions and 27 deletions
@@ -44,6 +44,7 @@ import { getDocObject } from '../basics/component-tools';
import { findAboveCell, findBellowCell, findLineBeforeAndAfterTable, findTableAfterLine, findTableBeforeLine, firstLineInCell, firstLineInTable, lastLineInCell, lastLineInTable } from '../basics/table';
import { MoveCursorOperation, MoveSelectionOperation } from '../commands/operations/doc-cursor.operation';
import { NodePositionConvertToCursor } from '../services/selection/convert-text-range';
import { DocBackScrollRenderController } from './render-controllers/back-scroll.render-controller';
import type { IMoveCursorOperationParams } from '../commands/operations/doc-cursor.operation';
@OnLifecycle(LifecycleStages.Rendered, DocMoveCursorController)
@@ -167,6 +168,8 @@ export class DocMoveCursorController extends Disposable {
style,
},
], false);
this._scrollToFocusNodePosition(docDataModel.getUnitId(), focusOffset);
} else {
const focusGlyph = skeleton.findNodeByCharIndex(focusOffset, segmentId, segmentPage);
const documentOffsetConfig = docObject.document.getOffsetConfig();
@@ -206,6 +209,8 @@ export class DocMoveCursorController extends Disposable {
style,
},
], false);
this._scrollToFocusNodePosition(docDataModel.getUnitId(), newActiveRange.endOffset);
}
}
@@ -298,6 +303,8 @@ export class DocMoveCursorController extends Disposable {
style,
},
], false);
this._scrollToFocusNodePosition(docDataModel.getUnitId(), cursor);
} else {
const startNode = skeleton.findNodeByCharIndex(startOffset, segmentId, segmentPage);
const endNode = skeleton.findNodeByCharIndex(endOffset, segmentId, segmentPage);
@@ -331,6 +338,7 @@ export class DocMoveCursorController extends Disposable {
style,
},
], false);
return;
}
@@ -346,6 +354,8 @@ export class DocMoveCursorController extends Disposable {
style,
},
], false);
this._scrollToFocusNodePosition(docDataModel.getUnitId(), newActiveRange.endOffset);
}
}
@@ -552,6 +562,20 @@ export class DocMoveCursorController extends Disposable {
}
}
private _scrollToFocusNodePosition(unitId: string, offset: number) {
const backScrollController = this._renderManagerService.getRenderById(unitId)?.with(DocBackScrollRenderController);
if (backScrollController == null) {
return;
}
// Scroll to the offset.
backScrollController.scrollToRange({
startOffset: offset,
endOffset: offset,
collapsed: true,
});
}
private _getDocObject() {
return getDocObject(this._univerInstanceService, this._renderManagerService);
}
@@ -14,14 +14,12 @@
* limitations under the License.
*/
import { Inject, IUniverInstanceService, RxDisposable } from '@univerjs/core';
import { Inject, RxDisposable } from '@univerjs/core';
import { DocSelectionManagerService, DocSkeletonManagerService } from '@univerjs/docs';
import { IRenderManagerService } from '@univerjs/engine-render';
import { IEditorService } from '@univerjs/ui';
import { takeUntil } from 'rxjs';
import type { DocumentDataModel, ITextRange, Nullable } from '@univerjs/core';
import type { INodePosition, IRenderContext, IRenderModule } from '@univerjs/engine-render';
import { getDocObject } from '../../basics/component-tools';
import type { Documents, INodePosition, IRenderContext, IRenderModule } from '@univerjs/engine-render';
import { VIEWPORT_KEY } from '../../basics/docs-view-key';
import { NodePositionConvertToCursor } from '../../services/selection/convert-text-range';
import { getAnchorBounding } from '../../services/selection/text-range';
@@ -33,8 +31,7 @@ export class DocBackScrollRenderController extends RxDisposable implements IRend
private readonly _context: IRenderContext<DocumentDataModel>,
@Inject(DocSelectionManagerService) private readonly _textSelectionManagerService: DocSelectionManagerService,
@IEditorService private readonly _editorService: IEditorService,
@Inject(IUniverInstanceService) private readonly _univerInstanceService: IUniverInstanceService,
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService
@Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService
) {
super();
@@ -49,34 +46,34 @@ export class DocBackScrollRenderController extends RxDisposable implements IRend
const { isEditing, unitId } = params;
if (isEditing) {
this._scrollToSelection(unitId);
if (unitId !== this._context.unitId || !isEditing) {
return;
}
this._scrollToSelection();
});
}
scrollToRange(unitId: string, range: ITextRange) {
const docSkeletonManagerService = this._renderManagerService.getRenderById(unitId)?.with(DocSkeletonManagerService);
const skeleton = docSkeletonManagerService?.getSkeleton();
scrollToRange(range: ITextRange) {
const skeleton = this._docSkeletonManagerService.getSkeleton();
if (!skeleton) {
return;
}
const { startOffset } = range;
const anchorNodePosition = skeleton.findNodePositionByCharIndex(startOffset);
// const focusNodePosition = startOffset !== endOffset ? skeleton.findNodePositionByCharIndex(endOffset) : null;
this.scrollToNode(unitId, anchorNodePosition);
this.scrollToNode(anchorNodePosition);
}
scrollToNode(unitId: string, startNodePosition: Nullable<INodePosition>) {
const docObject = this._getDocObject();
const docSkeletonManagerService = this._renderManagerService.getRenderById(unitId)?.with(DocSkeletonManagerService);
const skeleton = docSkeletonManagerService?.getSkeleton();
scrollToNode(startNodePosition: Nullable<INodePosition>) {
const { unitId, scene, mainComponent } = this._context;
const skeleton = this._docSkeletonManagerService.getSkeleton();
if (docObject == null || skeleton == null) {
if (mainComponent == null || skeleton == null) {
return;
}
const documentOffsetConfig = docObject.document.getOffsetConfig();
const documentOffsetConfig = (mainComponent as Documents).getOffsetConfig();
const { docsLeft, docsTop } = documentOffsetConfig;
const convertor = new NodePositionConvertToCursor(documentOffsetConfig, skeleton);
@@ -89,7 +86,7 @@ export class DocBackScrollRenderController extends RxDisposable implements IRend
const top = aTop + docsTop;
const viewportMain = docObject.scene.getViewport(VIEWPORT_KEY.VIEW_MAIN);
const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN);
const isEditor = !!this._editorService.getEditor(unitId);
@@ -126,7 +123,7 @@ export class DocBackScrollRenderController extends RxDisposable implements IRend
}
// Let the selection show on the current screen.
private _scrollToSelection(unitId: string) {
private _scrollToSelection() {
const activeTextRange = this._textSelectionManagerService.getActiveTextRange();
if (activeTextRange == null) {
return;
@@ -138,10 +135,6 @@ export class DocBackScrollRenderController extends RxDisposable implements IRend
return;
}
this.scrollToNode(unitId, startNodePosition);
}
private _getDocObject() {
return getDocObject(this._univerInstanceService, this._renderManagerService);
this.scrollToNode(startNodePosition);
}
}
@@ -448,6 +448,10 @@ export class DocSelectionRenderService extends RxDisposable implements IRenderMo
this._moving(moveOffsetX, moveOffsetY);
scrollTimer.scrolling(moveOffsetX, moveOffsetY, () => {
this._moving(moveOffsetX, moveOffsetY);
});
preMoveOffsetX = moveOffsetX;
preMoveOffsetY = moveOffsetY;
}));
@@ -29,7 +29,7 @@ function scrollToTop(accessor: IAccessor) {
endOffset: 0,
};
if (backScrollController) {
backScrollController.scrollToRange(DOCS_ZEN_EDITOR_UNIT_ID_KEY, textRange as ITextRange);
backScrollController.scrollToRange(textRange as ITextRange);
}
}