Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sheets-ui): should disable sheet menus on cell editing #3809

Merged
merged 21 commits into from
Oct 22, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ export function isCustomRangeSplitSymbol(text: string) {
return text === DataStreamTreeTokenType.CUSTOM_RANGE_END || text === DataStreamTreeTokenType.CUSTOM_RANGE_START;
}

/**
* Check if two ranges intersect
* @param line1Start - The start of the first range
* @param line1End - The end of the first range
* @param line2Start - The start of the second range
* @param line2End - The end of the second range
* @returns True if the ranges intersect, false otherwise
*/
export function isIntersecting(line1Start: number, line1End: number, line2Start: number, line2End: number) {
if ((line1Start <= line2Start && line1End >= line2Start) ||
(line1Start >= line2Start && line1Start <= line2End)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function getRetainAndDeleteFromReplace(
const textStart = startOffset - memoryCursor;
const textEnd = endOffset - memoryCursor;
const dataStream = body.dataStream;
const relativeCustomRanges = body.customRanges?.filter((customRange) => isIntersecting(customRange.startIndex, customRange.endIndex, startOffset, endOffset));
const relativeCustomRanges = body.customRanges?.filter((customRange) => isIntersecting(customRange.startIndex, customRange.endIndex, startOffset, endOffset - 1));
const toDeleteRanges = new Set(relativeCustomRanges?.filter((customRange) => shouldDeleteCustomRange(startOffset, endOffset - startOffset, customRange, dataStream)));
const retainPoints = new Set<number>();
relativeCustomRanges?.forEach((range) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export function getRetainAndDeleteAndExcludeLineBreak(
(p) => p.startIndex - memoryCursor >= textStart && p.startIndex - memoryCursor < textEnd
);

const relativeCustomRanges = body.customRanges?.filter((customRange) => isIntersecting(customRange.startIndex, customRange.endIndex, startOffset, endOffset));
const relativeCustomRanges = body.customRanges?.filter((customRange) => isIntersecting(customRange.startIndex, customRange.endIndex, startOffset, endOffset - 1));
const toDeleteRanges = new Set(relativeCustomRanges?.filter((customRange) => shouldDeleteCustomRange(startOffset, endOffset - startOffset, customRange, dataStream)));
const retainPoints = new Set<number>();
relativeCustomRanges?.forEach((range) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@
* limitations under the License.
*/

import type { DocumentDataModel } from '@univerjs/core';
import { BuildTextUtils, getBodySlice, ICommandService, IUniverInstanceService, LocaleService, Tools, UniverInstanceType, useDependency, useObservable } from '@univerjs/core';
import { Button, FormLayout, Input } from '@univerjs/design';
import { DocSelectionManagerService } from '@univerjs/docs';
import { DocSelectionRenderService } from '@univerjs/docs-ui';
import { IRenderManagerService } from '@univerjs/engine-render';
import { KeyCode } from '@univerjs/ui';
import React, { useEffect, useState } from 'react';
import type { DocumentDataModel } from '@univerjs/core';
import { AddDocHyperLinkCommand } from '../../commands/commands/add-link.command';
import { UpdateDocHyperLinkCommand } from '../../commands/commands/update-link.command';
import { DocHyperLinkPopupService } from '../../services/hyper-link-popup.service';
Expand All @@ -47,7 +45,6 @@ export const DocHyperLinkEdit = () => {
const editing = useObservable(hyperLinkService.editingLink$);
const commandService = useDependency(ICommandService);
const univerInstanceService = useDependency(IUniverInstanceService);
const renderManagerService = useDependency(IRenderManagerService);

const docSelectionManagerService = useDependency(DocSelectionManagerService);
const [link, setLink] = useState('');
Expand All @@ -58,8 +55,6 @@ export const DocHyperLinkEdit = () => {
? univerInstanceService.getUnit<DocumentDataModel>(editing.unitId, UniverInstanceType.UNIVER_DOC) :
univerInstanceService.getCurrentUnitForType<DocumentDataModel>(UniverInstanceType.UNIVER_DOC);

const docSelectionRenderService = renderManagerService.getRenderById(doc!.getUnitId())?.with(DocSelectionRenderService);

useEffect(() => {
const activeRange = docSelectionManagerService.getActiveTextRange();
if (!activeRange) {
Expand All @@ -82,19 +77,6 @@ export const DocHyperLinkEdit = () => {
}
}, [doc, editing, docSelectionManagerService, univerInstanceService]);

// TODO: @zhangwei, do not use docSelectionRenderService in this component.
useEffect(() => {
if (docSelectionRenderService) {
docSelectionRenderService.blurEditor();
}

return () => {
if (docSelectionRenderService) {
docSelectionRenderService.focusEditor();
}
};
}, [docSelectionRenderService]);

const handleCancel = () => {
hyperLinkService.hideEditPopup();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ export class DocStateChangeManagerService extends RxDisposable {
return;
}

const { isCompositionEnd, ...changeState } = changeStateInfo;
const imeInputManagerService = this._renderManagerService.getRenderById(changeStateInfo.unitId)?.with(DocIMEInputManagerService);
const { isCompositionEnd, isSync, syncer, ...changeState } = changeStateInfo;
const imeInputManagerService = this._renderManagerService.getRenderById(isSync ? syncer! : changeStateInfo.unitId)?.with(DocIMEInputManagerService);

if (imeInputManagerService == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface IRichTextEditingMutationParams extends IMutationCommonParams {
// Whether this mutation is from a sync operation.
isSync?: boolean;
isEditing?: boolean;
syncer?: string;
}

const RichTextEditingMutationId = 'doc.mutation.rich-text-editing';
Expand All @@ -50,6 +51,7 @@ export const RichTextEditingMutation: IMutation<IRichTextEditingMutationParams,

type: CommandType.MUTATION,

// eslint-disable-next-line max-lines-per-function
handler: (accessor, params) => {
const {
unitId,
Expand All @@ -63,8 +65,9 @@ export const RichTextEditingMutation: IMutation<IRichTextEditingMutationParams,
noNeedSetTextRange,
debounce,
isEditing = true,
isSync,
syncer,
} = params;

const univerInstanceService = accessor.get(IUniverInstanceService);
const renderManagerService = accessor.get(IRenderManagerService);
const docStateEmitService = accessor.get(DocStateEmitService);
Expand Down Expand Up @@ -100,7 +103,7 @@ export const RichTextEditingMutation: IMutation<IRichTextEditingMutationParams,
// Make sure update cursor & selection after doc skeleton is calculated.
if (!noNeedSetTextRange && textRanges && trigger != null) {
queueMicrotask(() => {
docSelectionManagerService.replaceTextRanges(textRanges, isEditing, params.options);
docSelectionManagerService.replaceDocRanges(textRanges, { unitId, subUnitId: unitId }, isEditing, params.options);
});
}

Expand All @@ -121,6 +124,8 @@ export const RichTextEditingMutation: IMutation<IRichTextEditingMutationParams,
textRanges: prevTextRanges ?? docRanges,
},
isCompositionEnd,
isSync,
syncer,
};
docStateEmitService.emitStateChangeInfo(changeState);

Expand Down
6 changes: 4 additions & 2 deletions packages/docs/src/services/doc-state-emit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
* limitations under the License.
*/

import { RxDisposable } from '@univerjs/core';
import { BehaviorSubject } from 'rxjs';
import type { JSONXActions, Nullable } from '@univerjs/core';
import type { ITextRangeWithStyle } from '@univerjs/engine-render';
import { RxDisposable } from '@univerjs/core';
import { BehaviorSubject } from 'rxjs';

interface IDocChangeState {
actions: JSONXActions;
Expand All @@ -37,6 +37,8 @@ export interface IDocStateChangeParams {

export interface IDocStateChangeInfo extends IDocStateChangeParams {
isCompositionEnd?: boolean;
isSync?: boolean;
syncer?: string;
}

export class DocStateEmitService extends RxDisposable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

import type { CellValue, Nullable } from '@univerjs/core';
import type { DateValidator } from '@univerjs/sheets-data-validation';
import type { IEditorBridgeServiceVisibleParam } from '@univerjs/sheets-ui';
import type { IDropdownComponentProps } from '../../../services/dropdown-manager.service';
import { CellValueType, DataValidationErrorStyle, ICommandService, LocaleService, numfmt, useDependency } from '@univerjs/core';
import { Button, DatePanel } from '@univerjs/design';
import { DeviceInputEventType } from '@univerjs/engine-render';
import { SetRangeValuesCommand } from '@univerjs/sheets';
import { getCellValueOrigin } from '@univerjs/sheets-data-validation';
import { getPatternType } from '@univerjs/sheets-numfmt';
import { SetCellEditVisibleOperation } from '@univerjs/sheets-ui';
import { KeyCode } from '@univerjs/ui';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import React, { useState } from 'react';
Expand Down Expand Up @@ -90,7 +94,13 @@ export function DateDropdown(props: IDropdownComponentProps) {
t: CellValueType.NUMBER,
}, rule))
) {
commandService.executeCommand(SetRangeValuesCommand.id, {
await commandService.executeCommand(SetCellEditVisibleOperation.id, {
visible: false,
eventType: DeviceInputEventType.Keyboard,
unitId,
keycode: KeyCode.ESC,
} as IEditorBridgeServiceVisibleParam);
await commandService.executeCommand(SetRangeValuesCommand.id, {
unitId,
subUnitId,
range: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { DocumentDataModel } from '@univerjs/core';
import type { IRichTextEditingMutationParams } from '@univerjs/docs';
import type { ISetRangeValuesCommandParams, ISheetLocation } from '@univerjs/sheets';
import type { ListMultipleValidator } from '@univerjs/sheets-data-validation';
import type { IEditorBridgeServiceVisibleParam } from '@univerjs/sheets-ui';
import type { IUniverSheetsDataValidationUIConfig } from '../../../controllers/config.schema';
import type { IDropdownComponentProps } from '../../../services/dropdown-manager.service';
import { BuildTextUtils, DataValidationRenderMode, DataValidationType, ICommandService, IConfigService, IUniverInstanceService, LocaleService, UniverInstanceType, useDependency } from '@univerjs/core';
Expand All @@ -28,7 +29,7 @@ import { DeviceInputEventType } from '@univerjs/engine-render';
import { CheckMarkSingle } from '@univerjs/icons';
import { RangeProtectionPermissionEditPoint, SetRangeValuesCommand, WorkbookEditablePermission, WorksheetEditPermission } from '@univerjs/sheets';
import { deserializeListOptions, getDataValidationCellValue, serializeListOptions } from '@univerjs/sheets-data-validation';
import { IEditorBridgeService, SheetPermissionInterceptorBaseController } from '@univerjs/sheets-ui';
import { IEditorBridgeService, SetCellEditVisibleOperation, SheetPermissionInterceptorBaseController } from '@univerjs/sheets-ui';
import { KeyCode, useObservable } from '@univerjs/ui';
import React, { useEffect, useMemo, useState } from 'react';
import { debounceTime } from 'rxjs';
Expand Down Expand Up @@ -204,7 +205,7 @@ export function ListDropDown(props: IDropdownComponentProps) {
title={multiple ? localeService.t('dataValidation.listMultiple.dropdown') : localeService.t('dataValidation.list.dropdown')}
value={value}
multiple={multiple}
onChange={(newValue) => {
onChange={async (newValue) => {
const str = serializeListOptions(newValue);
const params: ISetRangeValuesCommandParams = {
unitId,
Expand Down Expand Up @@ -232,6 +233,12 @@ export function ListDropDown(props: IDropdownComponentProps) {
});
}

await commandService.executeCommand(SetCellEditVisibleOperation.id, {
visible: false,
eventType: DeviceInputEventType.Keyboard,
unitId,
keycode: KeyCode.ESC,
} as IEditorBridgeServiceVisibleParam);
commandService.executeCommand(SetRangeValuesCommand.id, params);
setLocalValue(str);
if (!multiple) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import type { ICellData, ICommand, IDocumentData, IMutationInfo, Workbook } from '@univerjs/core';
import type { ISetRangeValuesMutationParams } from '@univerjs/sheets';
import { BuildTextUtils, CellValueType, CommandType, CustomRangeType, DataStreamTreeTokenType, generateRandomId, ICommandService, IUndoRedoService, IUniverInstanceService, sequenceExecuteAsync, TextX, Tools, UniverInstanceType } from '@univerjs/core';
import { DocSelectionManagerService } from '@univerjs/docs';
import { addCustomRangeBySelectionFactory } from '@univerjs/docs-ui';
import { IRenderManagerService } from '@univerjs/engine-render';
import { SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets';
Expand Down Expand Up @@ -194,13 +193,9 @@ export const AddRichHyperLinkCommand: ICommand<IAddRichHyperLinkCommandParams> =
}
const { documentId, link } = params;
const commandService = accessor.get(ICommandService);
const textSelectionService = accessor.get(DocSelectionManagerService);
const newId = generateRandomId();
const { payload } = link;
const range = textSelectionService.getActiveTextRange();
if (!range) {
return false;
}

const replaceSelection = addCustomRangeBySelectionFactory(accessor, {
unitId: documentId,
rangeId: newId,
Expand Down
6 changes: 3 additions & 3 deletions packages/sheets-hyper-link-ui/src/controllers/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@
* limitations under the License.
*/

import type { IAccessor, Workbook } from '@univerjs/core';
import type { IMenuItem, IShortcutItem } from '@univerjs/ui';
import { DOCS_ZEN_EDITOR_UNIT_ID_KEY, IUniverInstanceService, UniverInstanceType } from '@univerjs/core';
import { DocSelectionManagerService } from '@univerjs/docs';
import { getSheetCommandTarget, RangeProtectionPermissionEditPoint, SheetsSelectionsService, WorkbookEditablePermission, WorksheetEditPermission, WorksheetInsertHyperlinkPermission, WorksheetSetCellValuePermission } from '@univerjs/sheets';
import { getCurrentRangeDisable$, IEditorBridgeService, whenSheetEditorFocused } from '@univerjs/sheets-ui';
import { getMenuHiddenObservable, KeyCode, MenuGroup, MenuItemType, MenuPosition, MetaKeys } from '@univerjs/ui';
import { map, mergeMap, Observable } from 'rxjs';
import type { IAccessor, Workbook } from '@univerjs/core';
import type { IMenuItem, IShortcutItem } from '@univerjs/ui';
import { InsertHyperLinkOperation, InsertHyperLinkToolbarOperation } from '../commands/operations/popup.operations';
import { getShouldDisableCellLink, shouldDisableAddLink } from '../utils';

const getLinkDisable$ = (accessor: IAccessor) => {
const disableRange$ = getCurrentRangeDisable$(accessor, { workbookTypes: [WorkbookEditablePermission], worksheetTypes: [WorksheetEditPermission, WorksheetSetCellValuePermission, WorksheetInsertHyperlinkPermission], rangeTypes: [RangeProtectionPermissionEditPoint] });
const disableRange$ = getCurrentRangeDisable$(accessor, { workbookTypes: [WorkbookEditablePermission], worksheetTypes: [WorksheetEditPermission, WorksheetSetCellValuePermission, WorksheetInsertHyperlinkPermission], rangeTypes: [RangeProtectionPermissionEditPoint] }, true);
const univerInstanceService = accessor.get(IUniverInstanceService);
const sheetSelectionService = accessor.get(SheetsSelectionsService);
const disableCell$ = univerInstanceService.focused$.pipe(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ export class SheetsHyperLinkPopupController extends Disposable {
this._sheetsHyperLinkPopupService.hideCurrentPopup(HyperLinkEditSourceType.EDITING);
this._sheetsHyperLinkPopupService.endEditing(HyperLinkEditSourceType.EDITING);
this._sheetsHyperLinkPopupService.hideCurrentPopup(HyperLinkEditSourceType.VIEWING);
} else {
this._sheetsHyperLinkPopupService.hideCurrentPopup(HyperLinkEditSourceType.ZEN_EDITOR);
this._sheetsHyperLinkPopupService.endEditing(HyperLinkEditSourceType.ZEN_EDITOR);
}
})
);
Expand Down
6 changes: 3 additions & 3 deletions packages/sheets-hyper-link-ui/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
* limitations under the License.
*/

import type { DocumentDataModel, IAccessor, ITextRange, Workbook, Worksheet } from '@univerjs/core';
import { BuildTextUtils, CustomRangeType, DataValidationType, IUniverInstanceService, UniverInstanceType } from '@univerjs/core';
import { DocSelectionManagerService } from '@univerjs/docs';
import { SheetsSelectionsService } from '@univerjs/sheets';
import type { DocumentDataModel, IAccessor, ITextRange, Workbook, Worksheet } from '@univerjs/core';

export const getShouldDisableCellLink = (worksheet: Worksheet, row: number, col: number) => {
const cell = worksheet.getCell(row, col);
Expand Down Expand Up @@ -67,10 +67,10 @@ export const shouldDisableAddLink = (accessor: IAccessor) => {
}

const body = doc.getSelfOrHeaderFooterModel(activeRange.segmentId).getBody();
const paragraphs = body?.paragraphs;
if (!paragraphs) {
if (!body) {
return true;
}
const paragraphs = body?.paragraphs ?? [];

for (let i = 0, len = paragraphs.length; i < len; i++) {
const p = paragraphs[i];
Expand Down
Loading
Loading