mirror of
https://github.com/dream-num/univer.git
synced 2026-09-24 15:32:18 +08:00
refactor(filter): refactor filter for demo (#3194)
This commit is contained in:
Vendored
+4
-2
@@ -18,11 +18,13 @@
|
||||
"Redi Injection Identifier": {
|
||||
"prefix": ["@I"],
|
||||
"body": ["@I${1:identifier} private readonly _${2:name}: I${1:identifier},"],
|
||||
"description": "Inject an identifier with Redi."
|
||||
"description": "Inject an identifier with Redi.",
|
||||
"scope": "typescript,typescriptreact"
|
||||
},
|
||||
"Redi Injection": {
|
||||
"prefix": ["@In"],
|
||||
"body": ["@Inject(${1:identifier}) private readonly _${2:name}: ${1:identifier},"],
|
||||
"description": "Inject a class item with Redi."
|
||||
"description": "Inject a class item with Redi.",
|
||||
"scope": "typescript,typescriptreact"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function getLazyPlugins(): Array<[PluginCtor<Plugin>] | [PluginCt
|
||||
|
||||
// ],
|
||||
[UniverSheetsCrosshairHighlightPlugin],
|
||||
[UniverSheetsFilterUIPlugin, { useRemoteFilterValuesGenerator: true }],
|
||||
[UniverSheetsFilterUIPlugin, { useRemoteFilterValuesGenerator: false }],
|
||||
[UniverSheetsFindReplacePlugin],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -25,93 +25,142 @@ import { IContextService } from '../context/context.service';
|
||||
import { ILogService } from '../log/log.service';
|
||||
import { CustomCommandExecutionError } from '../../common/error';
|
||||
|
||||
/**
|
||||
* The type of a command.
|
||||
*/
|
||||
export enum CommandType {
|
||||
/** Command could generate some operations or mutations. */
|
||||
/**
|
||||
* Responsible for creating, orchestrating, and executing MUTATION or OPERATION according to specific business
|
||||
* logic. For example, a delete row COMMAND will generate a delete row MUTATION, an insert row MUTATION for undo,
|
||||
* and a set cell content MUTATION.
|
||||
*/
|
||||
COMMAND = 0,
|
||||
/** An operation that do not require conflict resolve. */
|
||||
/**
|
||||
* MUTATION is the change made to the data saved to snapshot, such as inserting rows and columns,
|
||||
* modifying cell content, modifying filter ranges, etc. If you want to add collaborative editing capabilities to
|
||||
* Univer, it is the smallest unit of conflict resolution.
|
||||
*/
|
||||
OPERATION = 1,
|
||||
/** An operation that need to be resolved before applied on peer client. */
|
||||
/**
|
||||
* OPERATION is the change made to data that is not saved to snapshot, without conflict resolution,
|
||||
* such as modifying scroll position, modifying sidebar state, etc.
|
||||
*/
|
||||
MUTATION = 2,
|
||||
}
|
||||
|
||||
/**
|
||||
* In Univer, all data modifications need to be executed through commands. The command-based approach can better track
|
||||
* changes in values, implement functions such as undo, redo, and collaborative editing, handle complex associated
|
||||
* logic between functions, etc.
|
||||
*
|
||||
* All commands should implements this interface or related {@link IMutation} or {@link IOperation} interface, and
|
||||
* should be registered in the {@link ICommandService}.
|
||||
*/
|
||||
export interface ICommand<P extends object = object, R = boolean> {
|
||||
/**
|
||||
* ${businessName}.${type}.${name}
|
||||
* Identifier of the command. It should be unique in the application unless it is a {@link IMultiCommand}.
|
||||
* Its pattern should be like `<namespace>.<type>.<command-name>`.
|
||||
*
|
||||
* @example { id: 'sheet.command.set-selection-frozen' }
|
||||
*/
|
||||
readonly id: string;
|
||||
readonly type: CommandType;
|
||||
|
||||
handler(accessor: IAccessor, params?: P, options?: IExecutionOptions): Promise<R> | R;
|
||||
|
||||
/**
|
||||
* When this command is unregistered, this function would be called.
|
||||
*
|
||||
* @deprecated
|
||||
* The type of the command.
|
||||
*/
|
||||
onDispose?: () => void;
|
||||
readonly type: CommandType;
|
||||
/**
|
||||
* The handler of the command.
|
||||
* @param accessor The accessor to the dependency injection container.
|
||||
* @param params Params of the command. Params should be serializable.
|
||||
* @param options Options of the command.
|
||||
* @returns The result of the command. By default it should be a boolean value which indicates the command is
|
||||
* executed successfully or not.
|
||||
*/
|
||||
handler(accessor: IAccessor, params?: P, options?: IExecutionOptions): Promise<R> | R;
|
||||
}
|
||||
|
||||
/**
|
||||
* A command that may have multiple implementations. Each implementation should have different `priority`
|
||||
* and `preconditions` callback to determine which implementation should be executed.
|
||||
*/
|
||||
export interface IMultiCommand<P extends object = object, R = boolean> extends ICommand<P, R> {
|
||||
/** The name of the multi command. It should be unique in the application. */
|
||||
name: string;
|
||||
/** @ignore */
|
||||
multi: true;
|
||||
/** Priority of this implementation. Implementation with higher priority will be checked first. */
|
||||
priority: number;
|
||||
|
||||
/**
|
||||
* A callback function that tells `ICommandService` if this implementation should be executed.
|
||||
* @param contextService The context service.
|
||||
* @returns If this implementation should be executed, return `true`, otherwise return `false`.
|
||||
*/
|
||||
preconditions?: (contextService: IContextService) => boolean;
|
||||
}
|
||||
|
||||
export interface IMutationCommonParams {
|
||||
/**
|
||||
* It is used to indicate which {@link CommandType.COMMAND} triggers the mutation.
|
||||
*/
|
||||
trigger?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation would change the model of Univer applications.
|
||||
* {@link CommandType.MUTATION} should implement this interface.
|
||||
*/
|
||||
export interface IMutation<P extends object, R = boolean> extends ICommand<P, R> {
|
||||
type: CommandType.MUTATION;
|
||||
|
||||
/**
|
||||
* Mutations must be a sync process.
|
||||
* @param accessor
|
||||
* @param params Params of the mutation. A mutation must has params.
|
||||
* The handler of the mutation.
|
||||
* @param accessor The accessor to the dependency injection container.
|
||||
* @param params Params of the mutation. Params should be serializable.
|
||||
* @returns The result of the mutation. By default it should be a boolean value which indicates the mutation is
|
||||
* executed successfully or not.
|
||||
*/
|
||||
handler(accessor: IAccessor, params: P): R;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation would change the state of Univer applications. State should only be in memory and does not
|
||||
* require conflicting resolution.
|
||||
* {@link CommandType.OPERATION} should implement this interface.
|
||||
*/
|
||||
export interface IOperation<P extends object = object, R = boolean> extends ICommand<P, R> {
|
||||
type: CommandType.OPERATION;
|
||||
|
||||
/**
|
||||
* Operations must be a sync process.
|
||||
* @param accessor
|
||||
* @param params Params of the operation. A operation must has params.
|
||||
* The handler of the operation.
|
||||
* @param accessor The accessor to the dependency injection container.
|
||||
* @param params Params of the operation. Params should be serializable.
|
||||
* @returns The result of the operation. By default it should be a boolean value which indicates the operation is
|
||||
* executed successfully or not.
|
||||
*/
|
||||
handler(accessor: IAccessor, params: P): R;
|
||||
}
|
||||
|
||||
/**
|
||||
* The command info, only a command id and responsible params
|
||||
* This object represents an execution of a command.
|
||||
*/
|
||||
export interface ICommandInfo<T extends object = object> {
|
||||
id: string;
|
||||
|
||||
type?: CommandType;
|
||||
|
||||
/**
|
||||
* Args should be serializable.
|
||||
* Id of the command being executed.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Type of the command.
|
||||
*/
|
||||
type?: CommandType;
|
||||
/**
|
||||
* Parameters of this execution.
|
||||
*/
|
||||
params?: T;
|
||||
}
|
||||
|
||||
/** This object represents an execution of a {@link CommandType.MUTATION} */
|
||||
export interface IMutationInfo<T extends object = object> {
|
||||
id: string;
|
||||
type?: CommandType.MUTATION;
|
||||
params: T;
|
||||
}
|
||||
|
||||
/** This object represents an execution of a {@link CommandType.OPERATION} */
|
||||
export interface IOperationInfo<T extends object = object> {
|
||||
id: string;
|
||||
type?: CommandType.OPERATION;
|
||||
@@ -119,46 +168,66 @@ export interface IOperationInfo<T extends object = object> {
|
||||
}
|
||||
|
||||
export interface IExecutionOptions {
|
||||
/** This mutation should only be executed on the local machine, and not synced to replicas. */
|
||||
/** This mutation should only be executed on the local machine, and should not be synced to replicas. */
|
||||
onlyLocal?: boolean;
|
||||
|
||||
/** This command is from collaboration peers. */
|
||||
fromCollab?: boolean;
|
||||
|
||||
/** @deprecated */
|
||||
fromChangeset?: boolean;
|
||||
|
||||
[key: PropertyKey]: string | number | boolean | undefined;
|
||||
}
|
||||
|
||||
export type CommandListener = (commandInfo: Readonly<ICommandInfo>, options?: IExecutionOptions) => void;
|
||||
|
||||
/**
|
||||
* The identifier of the command service.
|
||||
*/
|
||||
export const ICommandService = createIdentifier<ICommandService>('anywhere.command-service');
|
||||
/**
|
||||
* The service to register and execute commands.
|
||||
*/
|
||||
export interface ICommandService {
|
||||
/**
|
||||
* Check if a command is already registered at the current command service.
|
||||
*
|
||||
* @param commandId The id of the command.
|
||||
* @returns If the command is registered, return `true`, otherwise return `false`.
|
||||
*/
|
||||
hasCommand(commandId: string): boolean;
|
||||
|
||||
/**
|
||||
* Register a command to the command service.
|
||||
* @param command The command to register.
|
||||
*/
|
||||
registerCommand(command: ICommand<object, unknown>): IDisposable;
|
||||
|
||||
/**
|
||||
* Register a command as a multi command.
|
||||
* @param command The command to register as a multi command.
|
||||
*/
|
||||
registerMultipleCommand(command: ICommand<object, unknown>): IDisposable;
|
||||
|
||||
/**
|
||||
* Execute a command with the given id and parameters.
|
||||
* @param id Identifier of the command.
|
||||
* @param params Parameters of this execution.
|
||||
* @param options Options of this execution.
|
||||
* @returns The result of the execution. It is a boolean value by default which indicates the command is executed.
|
||||
*/
|
||||
executeCommand<P extends object = object, R = boolean>(
|
||||
id: string,
|
||||
params?: P,
|
||||
options?: IExecutionOptions
|
||||
): Promise<R>;
|
||||
|
||||
hasCommand(id: string): boolean;
|
||||
|
||||
/**
|
||||
* Execute a command with the given id and parameters synchronously.
|
||||
* @param id Identifier of the command.
|
||||
* @param params Parameters of this execution.
|
||||
* @param options Options of this execution.
|
||||
* @returns The result of the execution. It is a boolean value by default which indicates the command is executed.
|
||||
*/
|
||||
syncExecuteCommand<P extends object = object, R = boolean>(id: string, params?: P, options?: IExecutionOptions): R;
|
||||
|
||||
/**
|
||||
* Register a callback function that will be executed after a command is executed.
|
||||
* @param listener
|
||||
*/
|
||||
onCommandExecuted(listener: CommandListener): IDisposable;
|
||||
|
||||
/**
|
||||
* Register a callback function that will be executed before a command is executed.
|
||||
* @param listener
|
||||
@@ -166,12 +235,7 @@ export interface ICommandService {
|
||||
beforeCommandExecuted(listener: CommandListener): IDisposable;
|
||||
}
|
||||
|
||||
export const ICommandService = createIdentifier<ICommandService>('anywhere.command-service');
|
||||
|
||||
/**
|
||||
* The registry of commands.
|
||||
*/
|
||||
export class CommandRegistry {
|
||||
class CommandRegistry {
|
||||
private readonly _commands = new Map<string, ICommand>();
|
||||
private readonly _commandTypes = new Map<string, CommandType>();
|
||||
|
||||
@@ -186,8 +250,6 @@ export class CommandRegistry {
|
||||
return toDisposable(() => {
|
||||
this._commands.delete(command.id);
|
||||
this._commandTypes.delete(command.id);
|
||||
|
||||
command.onDispose?.();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,7 +270,7 @@ export class CommandRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
interface ICommandExecutionStackItem extends ICommandInfo { }
|
||||
interface ICommandExecutionStackItem extends ICommandInfo {}
|
||||
|
||||
export const NilCommand: ICommand = {
|
||||
id: 'nil',
|
||||
@@ -476,8 +538,6 @@ class MultiCommand implements IMultiCommand {
|
||||
return toDisposable(() => {
|
||||
const index = this._implementations.indexOf(registry);
|
||||
this._implementations.splice(index, 1);
|
||||
|
||||
implementation.onDispose?.();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ComponentManager, IMenuService, IMessageService, IShortcutService } fro
|
||||
import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui';
|
||||
|
||||
import { distinctUntilChanged } from 'rxjs';
|
||||
import { SheetCanvasPopManagerService } from '@univerjs/sheets-ui';
|
||||
import { SheetCanvasPopManagerService, SheetsRenderService } from '@univerjs/sheets-ui';
|
||||
import { FilterSingle } from '@univerjs/icons';
|
||||
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
@@ -61,9 +61,10 @@ export class SheetsFilterUIDesktopController extends SheetsFilterUIMobileControl
|
||||
@IMenuService private readonly _menuService: IMenuService,
|
||||
@IContextService private readonly _contextService: IContextService,
|
||||
@IMessageService private readonly _messageService: IMessageService,
|
||||
@IRenderManagerService _renderManagerService: IRenderManagerService
|
||||
@Inject(SheetsRenderService) sheetsRenderService: SheetsRenderService,
|
||||
@IRenderManagerService renderManagerService: IRenderManagerService
|
||||
) {
|
||||
super(_renderManagerService);
|
||||
super(renderManagerService, sheetsRenderService);
|
||||
|
||||
this._initCommands();
|
||||
this._initShortcuts();
|
||||
|
||||
@@ -14,21 +14,29 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RxDisposable, UniverInstanceType } from '@univerjs/core';
|
||||
import { Inject, RxDisposable, UniverInstanceType } from '@univerjs/core';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import type { Dependency } from '@univerjs/core';
|
||||
import { SheetsFilterRenderController } from '../views/widgets/render-modules/sheets-filter.render-controller';
|
||||
import { ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation } from '@univerjs/sheets-filter';
|
||||
import { SheetsRenderService } from '@univerjs/sheets-ui';
|
||||
import { SheetsFilterRenderController } from '../views/render-modules/sheets-filter.render-controller';
|
||||
|
||||
export class SheetsFilterUIMobileController extends RxDisposable {
|
||||
constructor(
|
||||
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService
|
||||
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService,
|
||||
@Inject(SheetsRenderService) private _sheetsRenderService: SheetsRenderService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._initRenderControllers();
|
||||
}
|
||||
[
|
||||
SetSheetsFilterRangeMutation,
|
||||
SetSheetsFilterCriteriaMutation,
|
||||
RemoveSheetsFilterMutation,
|
||||
ReCalcSheetsFilterMutation,
|
||||
].forEach((m) => this.disposeWithMe(this._sheetsRenderService.registerSkeletonChangingMutations(m.id)));
|
||||
|
||||
private _initRenderControllers(): void {
|
||||
this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, [SheetsFilterRenderController] as Dependency));
|
||||
this.disposeWithMe(this._renderManagerService.registerRenderModule(
|
||||
UniverInstanceType.UNIVER_SHEET, [SheetsFilterRenderController] as Dependency
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,15 +49,17 @@ export class UniverSheetsFilterUIPlugin extends Plugin {
|
||||
[SheetsFilterPanelService],
|
||||
[SheetsFilterPermissionController],
|
||||
[SheetsFilterUIDesktopController, {
|
||||
useFactory: () => this._injector.createInstance(SheetsFilterUIDesktopController, this._config),
|
||||
useFactory: (): SheetsFilterUIDesktopController =>
|
||||
this._injector.createInstance(SheetsFilterUIDesktopController, this._config),
|
||||
}],
|
||||
] as Dependency[]).forEach((d) => this._injector.add(d));
|
||||
|
||||
if (this._config.useRemoteFilterValuesGenerator && this._rpcChannelService) {
|
||||
this._injector.add([ISheetsGenerateFilterValuesService, {
|
||||
useFactory: () => toModule<ISheetsGenerateFilterValuesService>(
|
||||
this._rpcChannelService!.requestChannel(SHEETS_GENERATE_FILTER_VALUES_SERVICE_NAME)
|
||||
),
|
||||
useFactory: (): ISheetsGenerateFilterValuesService =>
|
||||
toModule<ISheetsGenerateFilterValuesService>(
|
||||
this._rpcChannelService!.requestChannel(SHEETS_GENERATE_FILTER_VALUES_SERVICE_NAME)
|
||||
),
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-34
@@ -17,16 +17,15 @@
|
||||
import type { IDisposable, IRange, Workbook } from '@univerjs/core';
|
||||
import { CommandType, fromCallback, ICommandService, Inject, Injector, RxDisposable, ThemeService } from '@univerjs/core';
|
||||
import type { IRenderContext, IRenderModule, SpreadsheetSkeleton } from '@univerjs/engine-render';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import type { ISelectionStyle, ISheetCommandSharedParams } from '@univerjs/sheets';
|
||||
import { INTERCEPTOR_POINT, SheetInterceptorService } from '@univerjs/sheets';
|
||||
import type { FilterModel } from '@univerjs/sheets-filter';
|
||||
import { FILTER_MUTATIONS, ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation, SheetsFilterService } from '@univerjs/sheets-filter';
|
||||
import { getCoordByCell, ISheetSelectionRenderService, SelectionShape, SheetSkeletonManagerService, SheetsRenderService } from '@univerjs/sheets-ui';
|
||||
import { FILTER_MUTATIONS, SheetsFilterService } from '@univerjs/sheets-filter';
|
||||
import { getCoordByCell, ISheetSelectionRenderService, SelectionShape, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
|
||||
|
||||
import { filter, map, of, startWith, switchMap, takeUntil, throttleTime } from 'rxjs';
|
||||
import type { ISheetsFilterButtonShapeProps } from '../filter-button.shape';
|
||||
import { FILTER_ICON_PADDING, FILTER_ICON_SIZE, SheetsFilterButtonShape } from '../filter-button.shape';
|
||||
import type { ISheetsFilterButtonShapeProps } from '../widgets/filter-button.shape';
|
||||
import { FILTER_ICON_PADDING, FILTER_ICON_SIZE, SheetsFilterButtonShape } from '../widgets/filter-button.shape';
|
||||
|
||||
const DEFAULT_Z_INDEX = 1000;
|
||||
|
||||
@@ -52,20 +51,11 @@ export class SheetsFilterRenderController extends RxDisposable implements IRende
|
||||
@Inject(SheetsFilterService) private readonly _sheetsFilterService: SheetsFilterService,
|
||||
@Inject(ThemeService) private readonly _themeService: ThemeService,
|
||||
@Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService,
|
||||
@Inject(SheetsRenderService) private _sheetsRenderService: SheetsRenderService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService,
|
||||
@ISheetSelectionRenderService private readonly _selectionRenderService: ISheetSelectionRenderService
|
||||
) {
|
||||
super();
|
||||
|
||||
[
|
||||
SetSheetsFilterRangeMutation,
|
||||
SetSheetsFilterCriteriaMutation,
|
||||
RemoveSheetsFilterMutation,
|
||||
ReCalcSheetsFilterMutation,
|
||||
].forEach((m) => this.disposeWithMe(this._sheetsRenderService.registerSkeletonChangingMutations(m.id)));
|
||||
|
||||
this._initRenderer();
|
||||
}
|
||||
|
||||
@@ -100,24 +90,17 @@ export class SheetsFilterRenderController extends RxDisposable implements IRende
|
||||
takeUntil(this.dispose$)
|
||||
).subscribe((renderParams) => {
|
||||
this._disposeRendering();
|
||||
|
||||
// If there's no filter range, we don't need to render anything.
|
||||
if (!renderParams || !renderParams.range) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderRange(renderParams.unitId, renderParams.range, renderParams.skeleton);
|
||||
this._renderRange(renderParams.range, renderParams.skeleton);
|
||||
this._renderButtons(renderParams as Required<ISheetsFilterRenderParams>);
|
||||
});
|
||||
}
|
||||
|
||||
private _renderRange(unitId: string, range: IRange, skeleton: SpreadsheetSkeleton): void {
|
||||
const renderer = this._renderManagerService.getRenderById(unitId);
|
||||
if (!renderer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { scene } = renderer;
|
||||
private _renderRange(range: IRange, skeleton: SpreadsheetSkeleton): void {
|
||||
const { scene } = this._context;
|
||||
const { rangeWithCoord, style } = this._selectionRenderService.attachSelectionWithCoord({
|
||||
range,
|
||||
primary: null,
|
||||
@@ -138,15 +121,10 @@ export class SheetsFilterRenderController extends RxDisposable implements IRende
|
||||
|
||||
private _renderButtons(params: Required<ISheetsFilterRenderParams>): void {
|
||||
const { range, filterModel, unitId, skeleton, worksheetId } = params;
|
||||
const currentRenderer = this._renderManagerService.getRenderById(unitId);
|
||||
if (!currentRenderer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { scene } = currentRenderer;
|
||||
const { scene } = this._context;
|
||||
|
||||
// Push cell contents to leave space for the filter buttons.
|
||||
this._interceptCellContent(params.range);
|
||||
this._interceptCellContent(unitId, worksheetId, params.range);
|
||||
|
||||
// Create filter button shapes.
|
||||
const { startColumn, endColumn, startRow } = range;
|
||||
@@ -185,12 +163,18 @@ export class SheetsFilterRenderController extends RxDisposable implements IRende
|
||||
scene.makeDirty();
|
||||
}
|
||||
|
||||
private _interceptCellContent(range: IRange): void {
|
||||
private _interceptCellContent(workbookId: string, worksheetId: string, range: IRange): void {
|
||||
const { startRow, startColumn, endColumn } = range;
|
||||
this._buttonRenderDisposable = this._sheetInterceptorService.intercept(INTERCEPTOR_POINT.CELL_CONTENT, {
|
||||
handler: (cell, pos, next) => {
|
||||
const { row, col } = pos;
|
||||
if (row !== startRow || col < startColumn || col > endColumn) {
|
||||
const { row, col, unitId, subUnitId } = pos;
|
||||
if (
|
||||
unitId !== workbookId ||
|
||||
subUnitId !== worksheetId ||
|
||||
row !== startRow ||
|
||||
col < startColumn ||
|
||||
col > endColumn
|
||||
) {
|
||||
return next(cell);
|
||||
}
|
||||
|
||||
@@ -691,7 +691,7 @@ export class SheetsFilterController extends Disposable {
|
||||
};
|
||||
}
|
||||
|
||||
private _commandExecutedListener() {
|
||||
private _commandExecutedListener(): void {
|
||||
this.disposeWithMe(this._commandService.onCommandExecuted((command: ICommandInfo, options) => {
|
||||
const { unitId, subUnitId } = command.params as unknown as ISheetCommandSharedParams || {};
|
||||
|
||||
|
||||
@@ -118,11 +118,11 @@ export class SheetsFilterService extends Disposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
setFilterErrorMsg(content: string) {
|
||||
setFilterErrorMsg(content: string): void {
|
||||
this._errorMsg$.next(content);
|
||||
}
|
||||
|
||||
private _updateActiveFilterModel() {
|
||||
private _updateActiveFilterModel(): void {
|
||||
let workbook: Nullable<Workbook>;
|
||||
try {
|
||||
workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET);
|
||||
@@ -147,7 +147,7 @@ export class SheetsFilterService extends Disposable {
|
||||
this._activeFilterModel$.next(filterModel);
|
||||
}
|
||||
|
||||
private _initActiveFilterModel() {
|
||||
private _initActiveFilterModel(): void {
|
||||
this.disposeWithMe(
|
||||
merge(
|
||||
// source1: executing filter related mutations
|
||||
@@ -174,7 +174,7 @@ export class SheetsFilterService extends Disposable {
|
||||
return JSON.stringify(json);
|
||||
}
|
||||
|
||||
private _deserializeAutoFiltersForUnit(unitId: string, json: ISheetsFilterResource) {
|
||||
private _deserializeAutoFiltersForUnit(unitId: string, json: ISheetsFilterResource): void {
|
||||
const workbook = this._univerInstanceService.getUniverSheetInstance(unitId)!;
|
||||
Object.keys(json).forEach((worksheetId: WorksheetID) => {
|
||||
const autoFilter = json[worksheetId]!;
|
||||
@@ -183,10 +183,10 @@ export class SheetsFilterService extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private _initModel() {
|
||||
private _initModel(): void {
|
||||
this._resourcesManagerService.registerPluginResource<ISheetsFilterResource>({
|
||||
pluginName: SHEET_FILTER_SNAPSHOT_ID,
|
||||
businesses: [2],
|
||||
businesses: [UniverInstanceType.UNIVER_SHEET],
|
||||
toJson: (id) => this._serializeAutoFiltersForUnit(id),
|
||||
parseJson: (json) => JSON.parse(json),
|
||||
onLoad: (unitId, value) => {
|
||||
@@ -204,7 +204,7 @@ export class SheetsFilterService extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private _cacheFilterModel(unitId: string, subUnitId: string, filterModel: FilterModel) {
|
||||
private _cacheFilterModel(unitId: string, subUnitId: string, filterModel: FilterModel): void {
|
||||
if (!this._filterModels.has(unitId)) {
|
||||
this._filterModels.set(unitId, new Map());
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ const TEST_WORKBOOK_DATA_DEMO: () => IWorkbookData = () => ({
|
||||
sheetOrder: [],
|
||||
styles: {},
|
||||
});
|
||||
|
||||
export const createTestBed = (dependencies?: Dependency[]) => {
|
||||
const univer = new Univer();
|
||||
const injector = univer.__getInjector();
|
||||
@@ -67,7 +68,10 @@ export const createTestBed = (dependencies?: Dependency[]) => {
|
||||
injector.add([SheetInterceptorService]);
|
||||
injector.add([SheetSkeletonManagerService]);
|
||||
injector.add([LexerTreeBuilder]);
|
||||
|
||||
dependencies?.forEach((d) => injector.add(d));
|
||||
|
||||
injector.get(SheetInterceptorService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -29,11 +29,13 @@ import {
|
||||
} from '../set-frozen.command';
|
||||
import { ExpandSelectionCommand, MoveSelectionCommand, SelectAllCommand } from '../set-selection.command';
|
||||
import { SheetSkeletonManagerService } from '../../../services/sheet-skeleton-manager.service';
|
||||
import { SelectAllService } from '../../../services/select-all/select-all.service';
|
||||
import { createCommandTestBed } from './create-command-test-bed';
|
||||
|
||||
export function createSelectionCommandTestBed(workbookData?: IWorkbookData) {
|
||||
const { univer, get, sheet } = createCommandTestBed(workbookData || SIMPLE_SELECTION_WORKBOOK_DATA, [
|
||||
[ShortcutExperienceService],
|
||||
[SelectAllService],
|
||||
]);
|
||||
|
||||
const commandService = get(ICommandService);
|
||||
|
||||
@@ -171,7 +171,7 @@ describe('Test commands used for change selections', () => {
|
||||
univer = null;
|
||||
}
|
||||
|
||||
function prepareTestBed(snapshot?: IWorkbookData) {
|
||||
function prepareSelectionsTestBed(snapshot?: IWorkbookData) {
|
||||
const testBed = createSelectionCommandTestBed(snapshot);
|
||||
univer = testBed.univer;
|
||||
get = testBed.get;
|
||||
@@ -183,7 +183,7 @@ describe('Test commands used for change selections', () => {
|
||||
afterEach(disposeTestBed);
|
||||
|
||||
describe('Simple movement to next cell', () => {
|
||||
beforeEach(() => prepareTestBed());
|
||||
beforeEach(() => prepareSelectionsTestBed());
|
||||
|
||||
it('Should move selection with command', async () => {
|
||||
selectTopLeft();
|
||||
@@ -258,7 +258,7 @@ describe('Test commands used for change selections', () => {
|
||||
});
|
||||
|
||||
describe('Move cell to/through merged cells', () => {
|
||||
beforeEach(() => prepareTestBed(SELECTION_WITH_MERGED_CELLS_DATA));
|
||||
beforeEach(() => prepareSelectionsTestBed(SELECTION_WITH_MERGED_CELLS_DATA));
|
||||
|
||||
/**
|
||||
* A1 | B1 | C1
|
||||
@@ -303,7 +303,7 @@ describe('Test commands used for change selections', () => {
|
||||
});
|
||||
|
||||
describe('Move to next cell that has value (skip cell)', () => {
|
||||
beforeEach(() => prepareTestBed(SELECTION_WITH_EMPTY_CELLS_DATA));
|
||||
beforeEach(() => prepareSelectionsTestBed(SELECTION_WITH_EMPTY_CELLS_DATA));
|
||||
|
||||
it('Works on move', async () => {
|
||||
selectTopLeft();
|
||||
@@ -362,7 +362,7 @@ describe('Test commands used for change selections', () => {
|
||||
});
|
||||
|
||||
describe('Expand to next selection or shrink to previous selection', () => {
|
||||
beforeEach(() => prepareTestBed(SELECTION_WITH_EMPTY_CELLS_DATA));
|
||||
beforeEach(() => prepareSelectionsTestBed(SELECTION_WITH_EMPTY_CELLS_DATA));
|
||||
|
||||
it('Works on expand', async () => {
|
||||
selectTopLeft();
|
||||
@@ -440,7 +440,7 @@ describe('Test commands used for change selections', () => {
|
||||
* When A1:C1 is selected and B2 is the primary cell, shrink should only shrink to one side.
|
||||
*/
|
||||
describe('Shrink edge case', () => {
|
||||
beforeEach(() => prepareTestBed(SELECTION_WITH_MERGED_CELLS_DATA));
|
||||
beforeEach(() => prepareSelectionsTestBed(SELECTION_WITH_MERGED_CELLS_DATA));
|
||||
|
||||
it('Should shrink on side when primary is in the middle of selections', async () => {
|
||||
select(0, 0, 1, 2, 1, 1, true, false);
|
||||
@@ -458,7 +458,7 @@ describe('Test commands used for change selections', () => {
|
||||
});
|
||||
|
||||
describe('Expand to next gap position or shrink to previous gap', () => {
|
||||
beforeEach(() => prepareTestBed(SELECTION_WITH_EMPTY_CELLS_DATA));
|
||||
beforeEach(() => prepareSelectionsTestBed(SELECTION_WITH_EMPTY_CELLS_DATA));
|
||||
|
||||
it('Works on gap expand', async () => {
|
||||
selectTopLeft();
|
||||
@@ -506,7 +506,7 @@ describe('Test commands used for change selections', () => {
|
||||
});
|
||||
|
||||
describe('Select all', () => {
|
||||
beforeEach(() => prepareTestBed());
|
||||
beforeEach(() => prepareSelectionsTestBed());
|
||||
|
||||
it('Should first select all neighbor cells, and then the whole sheet', async () => {
|
||||
selectTopLeft();
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import { KeyCode } from '@univerjs/ui';
|
||||
|
||||
import { ShortcutExperienceService } from '../../services/shortcut-experience.service';
|
||||
import { SelectAllService } from '../../services/select-all/select-all.service';
|
||||
import {
|
||||
checkIfShrink,
|
||||
expandToNextCell,
|
||||
@@ -330,35 +331,25 @@ export interface ISelectAllCommandParams {
|
||||
loop?: boolean;
|
||||
}
|
||||
|
||||
let RANGES_STACK: IRange[] = [];
|
||||
|
||||
let SELECTED_RANGE_WORKSHEET = '';
|
||||
|
||||
/**
|
||||
* This command expand selection to all neighbor ranges. If there are no neighbor ranges. Select the whole sheet.
|
||||
*/
|
||||
export const SelectAllCommand: ICommand<ISelectAllCommandParams> = {
|
||||
id: 'sheet.command.select-all',
|
||||
type: CommandType.COMMAND,
|
||||
onDispose() {
|
||||
RANGES_STACK = [];
|
||||
SELECTED_RANGE_WORKSHEET = '';
|
||||
},
|
||||
handler: async (accessor, params = { expandToGapFirst: true, loop: false }) => {
|
||||
const selection = getSelectionsService(accessor).getCurrentLastSelection();
|
||||
const target = getSheetCommandTarget(accessor.get(IUniverInstanceService));
|
||||
if (!target) return false;
|
||||
const selection = getSelectionsService(accessor).getCurrentLastSelection();
|
||||
if (!selection) return false;
|
||||
|
||||
const selectAllService = accessor.get(SelectAllService);
|
||||
|
||||
const { worksheet, unitId, subUnitId } = target;
|
||||
|
||||
if (!selection || !worksheet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const id = `${unitId}|${subUnitId}`;
|
||||
if (id !== SELECTED_RANGE_WORKSHEET) {
|
||||
RANGES_STACK = [];
|
||||
SELECTED_RANGE_WORKSHEET = id;
|
||||
if (id !== selectAllService.selectedRangeWorksheet) {
|
||||
selectAllService.rangesStack = [];
|
||||
selectAllService.selectedRangeWorksheet = id;
|
||||
}
|
||||
|
||||
const maxRow = worksheet.getMaxRows();
|
||||
@@ -371,9 +362,9 @@ export const SelectAllCommand: ICommand<ISelectAllCommandParams> = {
|
||||
range.startRow === 0 &&
|
||||
range.startColumn === 0;
|
||||
|
||||
if (!RANGES_STACK.some((s) => Rectangle.equals(s, range))) {
|
||||
RANGES_STACK = [];
|
||||
RANGES_STACK.push(range);
|
||||
if (!selectAllService.rangesStack.some((s) => Rectangle.equals(s, range))) {
|
||||
selectAllService.rangesStack = [];
|
||||
selectAllService.rangesStack.push(range);
|
||||
}
|
||||
|
||||
let destRange: IRange;
|
||||
@@ -381,12 +372,12 @@ export const SelectAllCommand: ICommand<ISelectAllCommandParams> = {
|
||||
// determined what kind of adjustment it should get
|
||||
if (isWholeSheetSelected) {
|
||||
if (loop) {
|
||||
const currentSelectionIndex = RANGES_STACK.findIndex((s) => Rectangle.equals(s, range));
|
||||
if (currentSelectionIndex !== RANGES_STACK.length - 1) {
|
||||
const currentSelectionIndex = selectAllService.rangesStack.findIndex((s) => Rectangle.equals(s, range));
|
||||
if (currentSelectionIndex !== selectAllService.rangesStack.length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
destRange = RANGES_STACK[0];
|
||||
destRange = selectAllService.rangesStack[0];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -400,8 +391,8 @@ export const SelectAllCommand: ICommand<ISelectAllCommandParams> = {
|
||||
destRange = expandToWholeSheet(worksheet);
|
||||
}
|
||||
|
||||
if (!RANGES_STACK.some((s) => Rectangle.equals(s, destRange))) {
|
||||
RANGES_STACK.push(destRange);
|
||||
if (!selectAllService.rangesStack.some((s) => Rectangle.equals(s, destRange))) {
|
||||
selectAllService.rangesStack.push(destRange);
|
||||
}
|
||||
|
||||
return accessor.get(ICommandService).executeCommand(SetSelectionsOperation.id, {
|
||||
|
||||
+7
-15
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Disposable, Inject, Injector, IPermissionService, LifecycleStages, OnLifecycle } from '@univerjs/core';
|
||||
import { Disposable, Inject, IPermissionService } from '@univerjs/core';
|
||||
import type { MenuConfig } from '@univerjs/ui';
|
||||
import { ComponentManager, IMenuService } from '@univerjs/ui';
|
||||
import { ComponentManager } from '@univerjs/ui';
|
||||
import { CheckMarkSingle, DeleteSingle, LockSingle, ProtectSingle, WriteSingle } from '@univerjs/icons';
|
||||
import { RangeProtectionRuleModel } from '@univerjs/sheets';
|
||||
import type { IRenderContext, IRenderModule, Spreadsheet } from '@univerjs/engine-render';
|
||||
@@ -32,25 +32,17 @@ export interface IUniverSheetsPermissionMenuConfig {
|
||||
menu: MenuConfig;
|
||||
}
|
||||
|
||||
export const DefaultSheetPermissionMenuConfig = {};
|
||||
|
||||
@OnLifecycle(LifecycleStages.Rendered, SheetPermissionRenderManagerController)
|
||||
export class SheetPermissionRenderManagerController extends Disposable {
|
||||
constructor(
|
||||
private readonly _config: Partial<IUniverSheetsPermissionMenuConfig>,
|
||||
@IMenuService private _menuService: IMenuService,
|
||||
@Inject(ComponentManager) private _componentManager: ComponentManager,
|
||||
@Inject(Injector) private readonly _injector: Injector
|
||||
) {
|
||||
constructor(@Inject(ComponentManager) private _componentManager: ComponentManager) {
|
||||
super();
|
||||
this._init();
|
||||
}
|
||||
|
||||
private _init() {
|
||||
private _init(): void {
|
||||
this._initComponents();
|
||||
}
|
||||
|
||||
private _initComponents() {
|
||||
private _initComponents(): void {
|
||||
([
|
||||
[permissionMenuIconKey, ProtectSingle],
|
||||
[permissionDeleteIconKey, DeleteSingle],
|
||||
@@ -96,7 +88,7 @@ export class SheetPermissionRenderController extends Disposable implements IRend
|
||||
});
|
||||
}
|
||||
|
||||
private _initRender() {
|
||||
private _initRender(): void {
|
||||
const spreadsheetRender = this._context.mainComponent as Spreadsheet;
|
||||
if (spreadsheetRender) {
|
||||
if (!spreadsheetRender.getExtensionByKey(RANGE_PROTECTION_CAN_VIEW_RENDER_EXTENSION_KEY)) {
|
||||
@@ -108,7 +100,7 @@ export class SheetPermissionRenderController extends Disposable implements IRend
|
||||
}
|
||||
}
|
||||
|
||||
private _initSkeleton() {
|
||||
private _initSkeleton(): void {
|
||||
const markDirtySkeleton = () => {
|
||||
this._sheetSkeletonManagerService.reCalculate();
|
||||
this._context.mainComponent?.makeDirty();
|
||||
|
||||
@@ -231,7 +231,7 @@ import { sheetPermissionAddProtectContextMenuFactory, sheetPermissionChangeSheet
|
||||
|
||||
export interface IUniverSheetsUIConfig {
|
||||
menu: MenuConfig;
|
||||
|
||||
disableAutoFocus?: true;
|
||||
override?: DependencyOverride;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ import { SheetContextMenuMobileRenderController } from './controllers/render-con
|
||||
import { SheetRenderController } from './controllers/render-controllers/sheet.render-controller';
|
||||
import { MobileSheetsSelectionRenderService } from './services/selection/mobile-selection-render.service';
|
||||
import { ISheetSelectionRenderService } from './services/selection/base-selection-render.service';
|
||||
import { SelectAllService } from './services/select-all/select-all.service';
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
@@ -92,16 +93,12 @@ export class UniverSheetsMobileUIPlugin extends Plugin {
|
||||
override onStarting(): void {
|
||||
(
|
||||
[
|
||||
// services
|
||||
[ShortcutExperienceService],
|
||||
[ISheetClipboardService, { useClass: SheetClipboardService }],
|
||||
[ISheetBarService, { useClass: SheetBarService }],
|
||||
[IFormatPainterService, { useClass: FormatPainterService }],
|
||||
[IAutoFillService, { useClass: AutoFillService }],
|
||||
[SheetPrintInterceptorService],
|
||||
|
||||
// This would be removed from global injector and moved into RenderUnit provider.
|
||||
// [SheetSkeletonManagerService],
|
||||
[ISheetSelectionRenderService, { useClass: MobileSheetsSelectionRenderService }],
|
||||
[IStatusBarService, { useClass: StatusBarService }],
|
||||
[IMarkSelectionService, { useClass: MarkSelectionService }],
|
||||
@@ -109,21 +106,16 @@ export class UniverSheetsMobileUIPlugin extends Plugin {
|
||||
[DragManagerService],
|
||||
[SheetCanvasPopManagerService],
|
||||
[CellAlertManagerService],
|
||||
[SelectAllService],
|
||||
|
||||
// controllers
|
||||
[ActiveWorksheetController],
|
||||
[AutoHeightController],
|
||||
[SheetClipboardController],
|
||||
[SheetsRenderService],
|
||||
[
|
||||
SheetUIMobileController,
|
||||
{
|
||||
useFactory: () => this._injector.createInstance(SheetUIMobileController, this._config),
|
||||
},
|
||||
],
|
||||
[SheetUIMobileController, {
|
||||
useFactory: (): SheetUIMobileController => this._injector.createInstance(SheetUIMobileController, this._config),
|
||||
}],
|
||||
[StatusBarController],
|
||||
// [AutoFillController],
|
||||
// [FormatPainterController],
|
||||
|
||||
// permission
|
||||
[SheetPermissionPanelModel],
|
||||
@@ -132,18 +124,9 @@ export class UniverSheetsMobileUIPlugin extends Plugin {
|
||||
[SheetPermissionInterceptorClipboardController],
|
||||
[SheetPermissionInterceptorBaseController],
|
||||
[SheetPermissionInitController],
|
||||
[SheetPermissionRenderManagerController],
|
||||
] as Dependency[]
|
||||
).forEach((d) => this._injector.add(d));
|
||||
|
||||
this._injector.add(
|
||||
[
|
||||
SheetPermissionRenderManagerController,
|
||||
{
|
||||
useFactory: () => this._injector.createInstance(SheetPermissionRenderManagerController, this._config),
|
||||
},
|
||||
]
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
override onReady(): void {
|
||||
@@ -177,8 +160,7 @@ export class UniverSheetsMobileUIPlugin extends Plugin {
|
||||
[HeaderMoveRenderController],
|
||||
[HeaderFreezeRenderController],
|
||||
// Caution: ScrollRenderController should placed before ZoomRenderController
|
||||
// because ZoomRenderController would change scrollInfo in currentSkeletonBefore$
|
||||
// currentSkeletonBefore$ --> ZoomRenderController ---> viewport.resize --> setScrollInfo, but ScrollRenderController needs scrollInfo
|
||||
// because ZoomRenderController would change scrollInfo in currentSkeletonBefore$.
|
||||
[MobileSheetsScrollRenderController],
|
||||
[SheetsZoomRenderController],
|
||||
[FormatPainterRenderController],
|
||||
@@ -199,12 +181,12 @@ export class UniverSheetsMobileUIPlugin extends Plugin {
|
||||
});
|
||||
}
|
||||
|
||||
private _markSheetAsFocused() {
|
||||
private _markSheetAsFocused(): void {
|
||||
const univerInstanceService = this._univerInstanceService;
|
||||
univerInstanceService.getCurrentTypeOfUnit$<Workbook>(UniverInstanceType.UNIVER_SHEET)
|
||||
this.disposeWithMe(univerInstanceService.getCurrentTypeOfUnit$<Workbook>(UniverInstanceType.UNIVER_SHEET)
|
||||
.pipe(filter((v) => !!v))
|
||||
.subscribe((workbook) => {
|
||||
univerInstanceService.focusUnit(workbook!.getUnitId());
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 { IRange } from '@univerjs/core';
|
||||
import { Disposable } from '@univerjs/core';
|
||||
|
||||
export class SelectAllService extends Disposable {
|
||||
rangesStack: IRange[] = [];
|
||||
selectedRangeWorksheet: string = '';
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import type {
|
||||
IDisposable,
|
||||
IFreeze,
|
||||
IInterceptor,
|
||||
Injector,
|
||||
@@ -150,7 +151,6 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele
|
||||
readonly selectionMoveStart$ = this._selectionMoveStart$.asObservable();
|
||||
|
||||
private _selectionMoving = false;
|
||||
|
||||
get selectionMoving(): boolean {
|
||||
return this._selectionMoving;
|
||||
}
|
||||
@@ -159,6 +159,8 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele
|
||||
|
||||
readonly interceptor = new InterceptorManager({ RANGE_MOVE_PERMISSION_CHECK, RANGE_FILL_PERMISSION_CHECK });
|
||||
|
||||
private _escapeShortcutDisposable: Nullable<IDisposable> = null;
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _themeService: ThemeService,
|
||||
@@ -375,8 +377,10 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele
|
||||
endSelection(): void {
|
||||
this._clearUpdatingListeners();
|
||||
this._selectionMoveEnd$.next(this.getSelectionDataWithStyle());
|
||||
|
||||
// when selection mouse up, enable the short cut service
|
||||
this._shortcutService.setDisable(false);
|
||||
this._escapeShortcutDisposable?.dispose();
|
||||
this._escapeShortcutDisposable = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,11 +524,12 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele
|
||||
|
||||
this._setupPointerMoveListener(viewportMain, activeSelectionControl!, rangeType, scrollTimerType, viewportPosX, viewportPosY);
|
||||
|
||||
this._shortcutService.setDisable(true);
|
||||
this._escapeShortcutDisposable = this._shortcutService.forceEscape();
|
||||
this._scenePointerUpSub = scene.onPointerUp$.subscribeEvent(() => {
|
||||
this._clearUpdatingListeners();
|
||||
this._selectionMoveEnd$.next(this.getSelectionDataWithStyle());
|
||||
this._shortcutService.setDisable(false);
|
||||
this._escapeShortcutDisposable?.dispose();
|
||||
this._escapeShortcutDisposable = null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -505,12 +505,14 @@ export class MobileSheetsSelectionRenderService extends BaseSelectionRenderServi
|
||||
|
||||
scene.getTransformer()?.clearSelectedObjects();
|
||||
|
||||
//#region pointermove
|
||||
// #region pointermove
|
||||
const relativeCoords = scene.getRelativeToViewportCoord(Vector2.FromArray([evt.offsetX, evt.offsetY]));
|
||||
this._setupPointerMoveListener(viewportMain, activeSelectionControl!, rangeType, scrollTimerType, relativeCoords.x, relativeCoords.y);
|
||||
//#endregion
|
||||
// #endregion
|
||||
|
||||
//#region pointerup
|
||||
// #region pointerup
|
||||
// when selection mouse down, disable the short cut service
|
||||
const disposableShortcut = this._shortcutService.forceEscape();
|
||||
this._scenePointerUpSub = scene.onPointerUp$.subscribeEvent((_evt: IPointerEvent | IMouseEvent) => {
|
||||
this.endSelection();
|
||||
this._expandingSelection = false;
|
||||
@@ -518,12 +520,9 @@ export class MobileSheetsSelectionRenderService extends BaseSelectionRenderServi
|
||||
this._selectionMoveEnd$.next(this.getSelectionDataWithStyle());
|
||||
|
||||
// when selection mouse up, enable the short cut service
|
||||
this._shortcutService.setDisable(false);
|
||||
disposableShortcut.dispose();
|
||||
});
|
||||
//#endregion
|
||||
|
||||
// when selection mouse down, disable the short cut service
|
||||
this._shortcutService.setDisable(true);
|
||||
// #endregion
|
||||
}
|
||||
|
||||
private _changeCurrCellWhenControlPointerDown(): ISelectionCellWithMergeInfo {
|
||||
|
||||
@@ -82,12 +82,14 @@ import { SheetsDefinedNameController } from './controllers/defined-name/defined-
|
||||
import { MoveRangeRenderController } from './controllers/move-range.controller';
|
||||
import { ISheetSelectionRenderService } from './services/selection/base-selection-render.service';
|
||||
import { SheetScrollManagerService } from './services/scroll-manager.service';
|
||||
import { SelectAllService } from './services/select-all/select-all.service';
|
||||
|
||||
@DependentOn(UniverSheetsPlugin)
|
||||
export class UniverSheetsUIPlugin extends Plugin {
|
||||
static override pluginName = 'SHEET_UI_PLUGIN';
|
||||
static override type = UniverInstanceType.UNIVER_SHEET;
|
||||
|
||||
/** @ignore */
|
||||
constructor(
|
||||
private readonly _config: Partial<IUniverSheetsUIConfig> = {},
|
||||
@Inject(Injector) override readonly _injector: Injector,
|
||||
@@ -101,7 +103,6 @@ export class UniverSheetsUIPlugin extends Plugin {
|
||||
|
||||
override onStarting(): void {
|
||||
mergeOverrideWithDependencies([
|
||||
// services
|
||||
[ShortcutExperienceService],
|
||||
[IEditorBridgeService, { useClass: EditorBridgeService }],
|
||||
[ISheetClipboardService, { useClass: SheetClipboardService }],
|
||||
@@ -111,15 +112,13 @@ export class UniverSheetsUIPlugin extends Plugin {
|
||||
[IFormulaEditorManagerService, { useClass: FormulaEditorManagerService }],
|
||||
[IAutoFillService, { useClass: AutoFillService }],
|
||||
[SheetPrintInterceptorService],
|
||||
|
||||
// This would be removed from global injector and moved into RenderUnit provider.
|
||||
// [SheetSkeletonManagerService],
|
||||
[IStatusBarService, { useClass: StatusBarService }],
|
||||
[IMarkSelectionService, { useClass: MarkSelectionService }],
|
||||
[HoverManagerService],
|
||||
[DragManagerService],
|
||||
[SheetCanvasPopManagerService],
|
||||
[CellAlertManagerService],
|
||||
[SelectAllService],
|
||||
|
||||
// controllers
|
||||
[ActiveWorksheetController],
|
||||
@@ -127,12 +126,9 @@ export class UniverSheetsUIPlugin extends Plugin {
|
||||
[FormulaEditorController],
|
||||
[SheetClipboardController],
|
||||
[SheetsRenderService],
|
||||
[
|
||||
SheetUIController,
|
||||
{
|
||||
useFactory: () => this._injector.createInstance(SheetUIController, this._config),
|
||||
},
|
||||
],
|
||||
[SheetUIController, {
|
||||
useFactory: (): SheetUIController => this._injector.createInstance(SheetUIController, this._config),
|
||||
}],
|
||||
[StatusBarController],
|
||||
[AutoFillController],
|
||||
[FormatPainterController],
|
||||
@@ -145,27 +141,22 @@ export class UniverSheetsUIPlugin extends Plugin {
|
||||
[SheetPermissionInterceptorClipboardController],
|
||||
[SheetPermissionInterceptorBaseController],
|
||||
[SheetPermissionInitController],
|
||||
// [MoveRangeController],
|
||||
[SheetPermissionRenderManagerController],
|
||||
] as Dependency[], this._config.override).forEach((d) => this._injector.add(d));
|
||||
|
||||
this._injector.add(
|
||||
[
|
||||
SheetPermissionRenderManagerController,
|
||||
{
|
||||
useFactory: () => this._injector.createInstance(SheetPermissionRenderManagerController, this._config),
|
||||
},
|
||||
]
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
override onReady(): void {
|
||||
this._markSheetAsFocused();
|
||||
if (!this._config.disableAutoFocus) {
|
||||
this._markSheetAsFocused();
|
||||
}
|
||||
|
||||
this._registerRenderBasics();
|
||||
}
|
||||
|
||||
override onRendered(): void {
|
||||
this._registerRenderModules();
|
||||
|
||||
this._injector.get(SheetPermissionRenderManagerController);
|
||||
}
|
||||
|
||||
private _registerRenderBasics(): void {
|
||||
@@ -185,8 +176,7 @@ export class UniverSheetsUIPlugin extends Plugin {
|
||||
[HeaderMoveRenderController],
|
||||
[HeaderUnhideRenderController],
|
||||
[HeaderResizeRenderController],
|
||||
// Caution: ScrollRenderController should placed before ZoomRenderController
|
||||
// because ZoomRenderController ---> viewport.resize --> setScrollInfo, but ScrollRenderController needs scrollInfo
|
||||
// Caution: ScrollRenderController should placed before ZoomRenderController.
|
||||
[SheetScrollManagerService],
|
||||
[SheetsScrollRenderController],
|
||||
[HeaderFreezeRenderController],
|
||||
@@ -217,10 +207,10 @@ export class UniverSheetsUIPlugin extends Plugin {
|
||||
});
|
||||
}
|
||||
|
||||
private _markSheetAsFocused() {
|
||||
private _markSheetAsFocused(): void {
|
||||
const univerInstanceService = this._univerInstanceService;
|
||||
univerInstanceService.getCurrentTypeOfUnit$<Workbook>(UniverInstanceType.UNIVER_SHEET)
|
||||
this.disposeWithMe(univerInstanceService.getCurrentTypeOfUnit$<Workbook>(UniverInstanceType.UNIVER_SHEET)
|
||||
.pipe(filter((v) => !!v))
|
||||
.subscribe((workbook) => univerInstanceService.focusUnit(workbook!.getUnitId()));
|
||||
.subscribe((workbook) => univerInstanceService.focusUnit(workbook!.getUnitId())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import { RangeProtectionRuleModel } from '../../../model/range-protection-rule.m
|
||||
import { RangeProtectionRenderModel } from '../../../model/range-protection-render.model';
|
||||
import type { ISetRangeProtectionMutationParams } from '../../../commands/mutations/set-range-protection.mutation';
|
||||
import { SetRangeProtectionMutation } from '../../../commands/mutations/set-range-protection.mutation';
|
||||
|
||||
import { InsertColMutation, InsertRowMutation } from '../../../commands/mutations/insert-row-col.mutation';
|
||||
import { RemoveColMutation, RemoveRowMutation } from '../../../commands/mutations/remove-row-col.mutation';
|
||||
import { type IMoveRowsMutationParams, MoveColsMutation, MoveRowsMutation } from '../../../commands/mutations/move-rows-cols.mutation';
|
||||
@@ -32,7 +31,6 @@ import type { IInsertColCommandParams, IInsertRowCommandParams } from '../../../
|
||||
import { InsertColCommand, InsertRowCommand } from '../../../commands/commands/insert-row-col.command';
|
||||
import type { IRemoveRowColCommandParams } from '../../../commands/commands/remove-row-col.command';
|
||||
import type { EffectRefRangeParams } from '../../../services/ref-range/type';
|
||||
|
||||
import type {
|
||||
IMoveColsCommandParams,
|
||||
IMoveRowsCommandParams,
|
||||
|
||||
+2
-3
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Disposable, Inject, IPermissionService, IResourceManagerService, LifecycleStages, OnLifecycle } from '@univerjs/core';
|
||||
import { Disposable, Inject, IPermissionService, IResourceManagerService } from '@univerjs/core';
|
||||
|
||||
import { UnitAction, UnitObject, UniverType } from '@univerjs/protocol';
|
||||
import type { IObjectModel } from '../../../model/range-protection-rule.model';
|
||||
@@ -24,7 +24,6 @@ import { getAllRangePermissionPoint } from './util';
|
||||
|
||||
const PLUGIN_NAME = 'SHEET_RANGE_PROTECTION_PLUGIN';
|
||||
|
||||
@OnLifecycle(LifecycleStages.Starting, RangeProtectionService)
|
||||
export class RangeProtectionService extends Disposable {
|
||||
constructor(
|
||||
@Inject(RangeProtectionRuleModel) private _selectionProtectionRuleModel: RangeProtectionRuleModel,
|
||||
@@ -37,7 +36,7 @@ export class RangeProtectionService extends Disposable {
|
||||
this._initRuleChange();
|
||||
}
|
||||
|
||||
private _initRuleChange() {
|
||||
private _initRuleChange(): void {
|
||||
this.disposeWithMe(
|
||||
this._selectionProtectionRuleModel.ruleChange$.subscribe((info) => {
|
||||
switch (info.type) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import type { Dependency, IWorkbookData } from '@univerjs/core';
|
||||
import { ILogService, Inject, Injector, IUniverInstanceService, LocaleType, LogLevel, Plugin, Univer, UniverInstanceType } from '@univerjs/core';
|
||||
import { SheetInterceptorService } from '../sheet-interceptor.service';
|
||||
|
||||
const TEST_WORKBOOK_DATA: IWorkbookData = {
|
||||
id: 'test',
|
||||
@@ -41,7 +42,7 @@ const TEST_WORKBOOK_DATA: IWorkbookData = {
|
||||
styles: {},
|
||||
};
|
||||
|
||||
export function createCoreTestBed(workbookData?: IWorkbookData, dependencies?: Dependency[]) {
|
||||
export function createSheetTestBed(workbookData?: IWorkbookData, dependencies?: Dependency[]) {
|
||||
const univer = new Univer();
|
||||
const injector = univer.__getInjector();
|
||||
const get = injector.get.bind(injector);
|
||||
@@ -59,6 +60,8 @@ export function createCoreTestBed(workbookData?: IWorkbookData, dependencies?: D
|
||||
|
||||
override onStarting(): void {
|
||||
dependencies?.forEach((d) => this._injector.add(d));
|
||||
|
||||
this._injector.get(SheetInterceptorService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
import { INTERCEPTOR_POINT } from '../interceptor-const';
|
||||
import { SheetInterceptorService } from '../sheet-interceptor.service';
|
||||
import type { ISheetLocation } from '../utils/interceptor';
|
||||
import { createCoreTestBed } from './create-core-test-bed';
|
||||
import { createSheetTestBed } from './create-core-test-bed';
|
||||
|
||||
describe('Test SheetInterceptorService', () => {
|
||||
let univer: Univer;
|
||||
@@ -30,7 +30,7 @@ describe('Test SheetInterceptorService', () => {
|
||||
const numberIntercept = createInterceptorKey<number, { step: number }>('numberIntercept');
|
||||
|
||||
beforeEach(() => {
|
||||
const testBed = createCoreTestBed(undefined, [[SheetInterceptorService]]);
|
||||
const testBed = createSheetTestBed(undefined, [[SheetInterceptorService]]);
|
||||
univer = testBed.univer;
|
||||
get = testBed.get;
|
||||
});
|
||||
|
||||
@@ -30,8 +30,6 @@ import {
|
||||
Disposable,
|
||||
DisposableCollection,
|
||||
IUniverInstanceService,
|
||||
LifecycleStages,
|
||||
OnLifecycle,
|
||||
remove,
|
||||
toDisposable,
|
||||
UniverInstanceType,
|
||||
@@ -62,10 +60,7 @@ export interface IRangeInterceptors {
|
||||
|
||||
/**
|
||||
* This class expose methods for sheet features to inject code to sheet underlying logic.
|
||||
*
|
||||
* It would inject Workbook & Worksheet.
|
||||
*/
|
||||
@OnLifecycle(LifecycleStages.Starting, SheetInterceptorService)
|
||||
export class SheetInterceptorService extends Disposable {
|
||||
private _interceptorsByName: Map<string, Array<IInterceptor<unknown, unknown>>> = new Map();
|
||||
private _commandInterceptors: ICommandInterceptor[] = [];
|
||||
@@ -76,6 +71,7 @@ export class SheetInterceptorService extends Disposable {
|
||||
private readonly _workbookDisposables = new Map<string, IDisposable>();
|
||||
private readonly _worksheetDisposables = new Map<string, IDisposable>();
|
||||
|
||||
/** @ignore */
|
||||
constructor(@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService) {
|
||||
super();
|
||||
|
||||
@@ -188,7 +184,7 @@ export class SheetInterceptorService extends Disposable {
|
||||
};
|
||||
}
|
||||
|
||||
intercept<T extends IInterceptor<any, any>>(name: T, interceptor: T) {
|
||||
intercept<T extends IInterceptor<any, any>>(name: T, interceptor: T): IDisposable {
|
||||
const key = name as unknown as string;
|
||||
if (!this._interceptorsByName.has(key)) {
|
||||
this._interceptorsByName.set(key, []);
|
||||
@@ -258,12 +254,12 @@ export class SheetInterceptorService extends Disposable {
|
||||
// We should intercept all instantiated worksheet and should subscribe to
|
||||
// worksheet creation event to intercept newly created worksheet.
|
||||
workbook.getSheets().forEach((worksheet) => interceptViewModel(worksheet));
|
||||
disposables.add(toDisposable(workbook.sheetCreated$.subscribe((worksheet) => interceptViewModel(worksheet))));
|
||||
disposables.add(workbook.sheetCreated$.subscribe((worksheet) => interceptViewModel(worksheet)));
|
||||
|
||||
// Dispose all underlying interceptors when workbook is disposed.
|
||||
disposables.add(toDisposable(() => workbook.getSheets().forEach((worksheet) => this._disposeSheetInterceptor(unitId, worksheet))));
|
||||
// Dispose interceptor when a worksheet is destroyed.
|
||||
disposables.add(toDisposable(workbook.sheetDisposed$.subscribe((worksheet) => this._disposeSheetInterceptor(unitId, worksheet))));
|
||||
disposables.add(workbook.sheetDisposed$.subscribe((worksheet) => this._disposeSheetInterceptor(unitId, worksheet)));
|
||||
|
||||
this._workbookDisposables.set(unitId, disposables);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import type { Dependency, DependencyOverride } from '@univerjs/core';
|
||||
import { DependentOn, ICommandService, IConfigService, Inject, Injector, LocaleService, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core';
|
||||
import { DependentOn, IConfigService, Inject, Injector, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core';
|
||||
|
||||
import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula';
|
||||
import { BasicWorksheetController } from './controllers/basic-worksheet.controller';
|
||||
@@ -52,9 +52,6 @@ export interface IUniverSheetsConfig {
|
||||
onlyRegisterFormulaRelatedMutations?: true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main sheet base, construct the sheet container and layout, mount the rendering engine
|
||||
*/
|
||||
@DependentOn(UniverFormulaEnginePlugin)
|
||||
export class UniverSheetsPlugin extends Plugin {
|
||||
static override pluginName = PLUGIN_NAME;
|
||||
@@ -62,9 +59,7 @@ export class UniverSheetsPlugin extends Plugin {
|
||||
|
||||
constructor(
|
||||
private _config: IUniverSheetsConfig | undefined,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IConfigService private readonly _configService: IConfigService,
|
||||
@Inject(LocaleService) private readonly _localeService: LocaleService,
|
||||
@Inject(Injector) override readonly _injector: Injector
|
||||
) {
|
||||
super();
|
||||
@@ -82,7 +77,7 @@ export class UniverSheetsPlugin extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
private _initDependencies(sheetInjector: Injector) {
|
||||
private _initDependencies(sheetInjector: Injector): void {
|
||||
const dependencies: Dependency[] = [
|
||||
// services
|
||||
[BorderStyleManagerService],
|
||||
@@ -111,14 +106,14 @@ export class UniverSheetsPlugin extends Plugin {
|
||||
];
|
||||
|
||||
if (!this._config?.notExecuteFormula) {
|
||||
// Should execute formula.
|
||||
dependencies.push(
|
||||
[CalculateResultApplyController]
|
||||
);
|
||||
dependencies.push([CalculateResultApplyController]);
|
||||
}
|
||||
|
||||
mergeOverrideWithDependencies(dependencies, this._config?.override).forEach((d) => {
|
||||
sheetInjector.add(d);
|
||||
});
|
||||
|
||||
this._injector.get(SheetInterceptorService);
|
||||
this._injector.get(RangeProtectionService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,49 +25,110 @@ import { IPlatformService } from '../platform/platform.service';
|
||||
import type { KeyCode } from './keycode';
|
||||
import { KeyCodeToChar, MetaKeys } from './keycode';
|
||||
|
||||
/**
|
||||
* A shortcut item that could be registered to the {@link IShortcutService}.
|
||||
*/
|
||||
export interface IShortcutItem<P extends object = object> {
|
||||
/** This should reuse the corresponding command's id. */
|
||||
/** Id of the shortcut item. It should reuse the corresponding {@link ICommand}'s id. */
|
||||
id: string;
|
||||
|
||||
/** Description of the shortcut. */
|
||||
description?: string;
|
||||
|
||||
/** If two shortcuts have the same binding, the one with higher priority would be check first. */
|
||||
priority?: number;
|
||||
/** A callback that will be triggered to examine if the shortcut should be invoked. */
|
||||
|
||||
/**
|
||||
* A callback that will be triggered to examine if the shortcut should be invoked. The `{@link IContextService}`
|
||||
* would be passed to the callback.
|
||||
*/
|
||||
preconditions?: (contextService: IContextService) => boolean;
|
||||
|
||||
/** A command can be bound to several bindings, with different static parameters perhaps. */
|
||||
/**
|
||||
* The binding of the shortcut. It should be a combination of {@link KeyCode} and {@link MetaKeys}.
|
||||
*
|
||||
* A command can be bound to several bindings, with different static parameters perhaps.
|
||||
*
|
||||
* @example { binding: KeyCode.ENTER | MetaKeys.ALT }
|
||||
*/
|
||||
binding: KeyCode | number;
|
||||
/**
|
||||
* The binding of the shortcut for macOS. If the property is not specified, the default binding would be used.
|
||||
*/
|
||||
mac?: number;
|
||||
/**
|
||||
* The binding of the shortcut for Windows. If the property is not specified, the default binding would be used.
|
||||
*/
|
||||
win?: number;
|
||||
/**
|
||||
* The binding of the shortcut for Linux. If the property is not specified, the default binding would be used.
|
||||
*/
|
||||
linux?: number;
|
||||
|
||||
/**
|
||||
* The group of the menu item should belong to. The shortcut item would be rendered in the
|
||||
* panel if this is set.
|
||||
*
|
||||
* @example { group: '10_global-shortcut' }
|
||||
*/
|
||||
group?: string;
|
||||
|
||||
/** Static parameters of this shortcut. Would be send to `CommandService.executeCommand`. */
|
||||
/**
|
||||
* Static parameters of this shortcut. Would be send to {@link ICommandService.executeCommand} as the second
|
||||
* parameter when the corresponding command is executed.
|
||||
*
|
||||
* You can define multi shortcuts with the same command id but different static parameters.
|
||||
*/
|
||||
staticParameters?: P;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dependency injection identifier of the {@link IShortcutService}.
|
||||
*/
|
||||
export const IShortcutService = createIdentifier<IShortcutService>('ui.shortcut.service');
|
||||
/**
|
||||
* The interface of the shortcut service.
|
||||
*/
|
||||
export interface IShortcutService {
|
||||
/**
|
||||
* An observable that emits when the shortcuts are changed.
|
||||
*/
|
||||
shortcutChanged$: Observable<void>;
|
||||
|
||||
/**
|
||||
* Make the shortcut service ignore all keyboard events.
|
||||
* @returns {IDisposable} a disposable that could be used to cancel the force escaping.
|
||||
*/
|
||||
forceEscape(): IDisposable;
|
||||
// registerCaptureSelector(selector: string): IDisposable;
|
||||
// registerEscapeSelector(selector: string): IDisposable;
|
||||
|
||||
/**
|
||||
* Register a shortcut item to the shortcut service.
|
||||
* @param {IShortcutItem} shortcut - the shortcut item to be registered.
|
||||
* @returns {IDisposable} a disposable that could be used to unregister the shortcut.
|
||||
*/
|
||||
registerShortcut(shortcut: IShortcutItem): IDisposable;
|
||||
/**
|
||||
* Get the display string of the shortcut item.
|
||||
* @param shortcut - the shortcut item to get the display string.
|
||||
* @returns {string} the display string of the shortcut. For example `Ctrl+Enter`.
|
||||
*/
|
||||
getShortcutDisplay(shortcut: IShortcutItem): string;
|
||||
/**
|
||||
* Get the display string of the shortcut of the command.
|
||||
* @param id the id of the command to get the shortcut display.
|
||||
* @returns {string | null} the display string of the shortcut. For example `Ctrl+Enter`.
|
||||
*/
|
||||
getShortcutDisplayOfCommand(id: string): string | null;
|
||||
/**
|
||||
* Get all the shortcuts registered in the shortcut service.
|
||||
* @returns {IShortcutItem[]} all the shortcuts registered in the shortcut service.
|
||||
*/
|
||||
getAllShortcuts(): IShortcutItem[];
|
||||
setDisable(disable: boolean): void;
|
||||
}
|
||||
|
||||
export const IShortcutService = createIdentifier<IShortcutService>('univer.shortcut');
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export class ShortcutService extends Disposable implements IShortcutService {
|
||||
private readonly _shortCutMapping = new Map<number, Set<IShortcutItem>>();
|
||||
private readonly _commandIDMapping = new Map<string, Set<IShortcutItem>>();
|
||||
@@ -77,8 +138,6 @@ export class ShortcutService extends Disposable implements IShortcutService {
|
||||
|
||||
private _forceEscaped = false;
|
||||
|
||||
private _disable = false;
|
||||
|
||||
constructor(
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IPlatformService private readonly _platformService: IPlatformService,
|
||||
@@ -97,10 +156,6 @@ export class ShortcutService extends Disposable implements IShortcutService {
|
||||
);
|
||||
}
|
||||
|
||||
setDisable(disable: boolean): void {
|
||||
this._disable = disable;
|
||||
}
|
||||
|
||||
getAllShortcuts(): IShortcutItem[] {
|
||||
return Array.from(this._shortCutMapping.values())
|
||||
.map((v) => Array.from(v.values()))
|
||||
@@ -179,14 +234,8 @@ export class ShortcutService extends Disposable implements IShortcutService {
|
||||
// Should get the container element of the Univer instance and see if
|
||||
// the event target is a descendant of the container element.
|
||||
// Also we should check through escape list and force catching list.
|
||||
// if the target is not focused on the univer instance we should ingore the keyboard event
|
||||
if (this._forceEscaped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._disable) {
|
||||
return;
|
||||
}
|
||||
// if the target is not focused on the univer instance we should ignore the keyboard event
|
||||
if (this._forceEscaped) return;
|
||||
|
||||
if (
|
||||
this._layoutService &&
|
||||
@@ -201,7 +250,7 @@ export class ShortcutService extends Disposable implements IShortcutService {
|
||||
}
|
||||
}
|
||||
|
||||
private _dispatch(e: KeyboardEvent) {
|
||||
private _dispatch(e: KeyboardEvent): boolean {
|
||||
const binding = this._deriveBindingFromEvent(e);
|
||||
if (binding === null) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user