snapshot of https://github.com/dream-num/univer.git (dev, 2026-09-16; blobs > 131072B omitted)
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DeleteDirection, Direction } from '@univerjs/core';
|
||||
import { DeleteTextCommand, InsertTextCommand, RichTextEditingMutation } from '@univerjs/docs';
|
||||
import { DeleteLeftCommand, IMEInputCommand, MoveCursorOperation } from '@univerjs/docs-ui';
|
||||
import { KeyCode } from '@univerjs/ui';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { CloseQuickInsertPopupOperation, ShowQuickInsertPopupOperation } from '../../commands/operations/quick-insert-popup.operation';
|
||||
import { numberedListMenu, textMenu } from '../../menu/menu';
|
||||
import { DocQuickInsertTriggerController } from '../doc-quick-insert-trigger.controller';
|
||||
|
||||
function createCommandService() {
|
||||
const listeners = new Set<(commandInfo: { id: string; params?: unknown }) => void>();
|
||||
|
||||
return {
|
||||
executeCommand: vi.fn(() => true),
|
||||
onCommandExecuted: vi.fn((callback: (commandInfo: { id: string; params?: unknown }) => void) => {
|
||||
listeners.add(callback);
|
||||
return {
|
||||
dispose: () => listeners.delete(callback),
|
||||
};
|
||||
}),
|
||||
emit(commandInfo: { id: string; params?: unknown }) {
|
||||
listeners.forEach((listener) => listener(commandInfo));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createPopupService() {
|
||||
let menuSelectedHandler: ((menu: { id: string }) => void) | null = null;
|
||||
let editPopup: { anchor: number } | null = null;
|
||||
let isComposing = false;
|
||||
let inputOffset = { start: 0, end: 0 };
|
||||
|
||||
return {
|
||||
get editPopup() {
|
||||
return editPopup;
|
||||
},
|
||||
setEditPopup(value: { anchor: number } | null) {
|
||||
editPopup = value;
|
||||
},
|
||||
get isComposing() {
|
||||
return isComposing;
|
||||
},
|
||||
get inputOffset() {
|
||||
return inputOffset;
|
||||
},
|
||||
setInputOffset: vi.fn((value: { start: number; end: number }) => {
|
||||
inputOffset = value;
|
||||
}),
|
||||
resolvePopup: vi.fn(),
|
||||
setIsComposing: vi.fn((value: boolean) => {
|
||||
isComposing = value;
|
||||
}),
|
||||
onMenuSelected: vi.fn((handler: (menu: { id: string }) => void) => {
|
||||
menuSelectedHandler = handler;
|
||||
return () => {
|
||||
menuSelectedHandler = null;
|
||||
};
|
||||
}),
|
||||
triggerMenuSelected(menu: { id: string }) {
|
||||
menuSelectedHandler?.(menu);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('DocQuickInsertTriggerController', () => {
|
||||
it('reacts to insert, edit, cursor, delete and IME events like a real quick-insert session', () => {
|
||||
vi.useFakeTimers();
|
||||
|
||||
const commandService = createCommandService();
|
||||
const popupService = createPopupService();
|
||||
const shortcutService = {
|
||||
registerShortcut: vi.fn(() => ({ dispose: vi.fn() })),
|
||||
};
|
||||
const selectionManagerService = {
|
||||
getActiveTextRange: vi.fn(() => ({ startOffset: 5, endOffset: 5 })),
|
||||
};
|
||||
const popup = {
|
||||
keyword: '/',
|
||||
menus$: { subscribe: vi.fn() },
|
||||
preconditions: vi.fn(() => true),
|
||||
};
|
||||
popupService.resolvePopup.mockReturnValue(popup);
|
||||
|
||||
const controller = new DocQuickInsertTriggerController(
|
||||
commandService as never,
|
||||
selectionManagerService as never,
|
||||
popupService as never,
|
||||
shortcutService as never,
|
||||
{
|
||||
getCurrentUnitOfType: vi.fn(() => ({ getDisabled: () => false })),
|
||||
} as never
|
||||
);
|
||||
|
||||
expect(shortcutService.registerShortcut).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: CloseQuickInsertPopupOperation.id,
|
||||
binding: KeyCode.ESC,
|
||||
priority: 1000,
|
||||
}));
|
||||
|
||||
commandService.emit({
|
||||
id: InsertTextCommand.id,
|
||||
params: {
|
||||
body: { dataStream: '/' },
|
||||
range: { endOffset: 5 },
|
||||
unitId: 'doc-1',
|
||||
},
|
||||
});
|
||||
|
||||
expect(popupService.setInputOffset).toHaveBeenCalledWith({ start: 4, end: 5 });
|
||||
expect(commandService.executeCommand).not.toHaveBeenCalledWith(ShowQuickInsertPopupOperation.id, expect.anything());
|
||||
|
||||
vi.advanceTimersByTime(100);
|
||||
expect(commandService.executeCommand).toHaveBeenCalledWith(ShowQuickInsertPopupOperation.id, {
|
||||
index: 4,
|
||||
unitId: 'doc-1',
|
||||
popup,
|
||||
});
|
||||
|
||||
popupService.setEditPopup({ anchor: 4 });
|
||||
commandService.emit({
|
||||
id: InsertTextCommand.id,
|
||||
params: {
|
||||
body: { dataStream: 'a' },
|
||||
range: { endOffset: 7 },
|
||||
unitId: 'doc-1',
|
||||
},
|
||||
});
|
||||
expect(popupService.setInputOffset).toHaveBeenLastCalledWith({ start: 4, end: 8 });
|
||||
|
||||
commandService.emit({
|
||||
id: IMEInputCommand.id,
|
||||
params: { isCompositionStart: true, isCompositionEnd: false },
|
||||
});
|
||||
commandService.emit({
|
||||
id: IMEInputCommand.id,
|
||||
params: { isCompositionStart: false, isCompositionEnd: true },
|
||||
});
|
||||
expect(popupService.setIsComposing).toHaveBeenNthCalledWith(1, true);
|
||||
expect(popupService.setIsComposing).toHaveBeenNthCalledWith(2, false);
|
||||
|
||||
commandService.emit({
|
||||
id: RichTextEditingMutation.id,
|
||||
params: {
|
||||
isCompositionEnd: true,
|
||||
textRanges: [{ endOffset: 9 }],
|
||||
},
|
||||
});
|
||||
expect(popupService.setInputOffset).toHaveBeenLastCalledWith({ start: 4, end: 9 });
|
||||
|
||||
commandService.emit({
|
||||
id: DeleteTextCommand.id,
|
||||
params: {
|
||||
direction: DeleteDirection.LEFT,
|
||||
len: 2,
|
||||
range: { endOffset: 10 },
|
||||
},
|
||||
});
|
||||
expect(popupService.setInputOffset).toHaveBeenLastCalledWith({ start: 4, end: 8 });
|
||||
|
||||
commandService.emit({
|
||||
id: MoveCursorOperation.id,
|
||||
params: { direction: Direction.LEFT },
|
||||
});
|
||||
expect(commandService.executeCommand).toHaveBeenCalledWith(CloseQuickInsertPopupOperation.id);
|
||||
|
||||
selectionManagerService.getActiveTextRange.mockReturnValue({ startOffset: 4, endOffset: 4 });
|
||||
commandService.emit({ id: DeleteLeftCommand.id });
|
||||
expect(commandService.executeCommand).toHaveBeenCalledWith(CloseQuickInsertPopupOperation.id);
|
||||
|
||||
controller.dispose();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('executes built-in menu commands but skips plain text selection', () => {
|
||||
const commandService = createCommandService();
|
||||
const popupService = createPopupService();
|
||||
|
||||
const controller = new DocQuickInsertTriggerController(
|
||||
commandService as never,
|
||||
{ getActiveTextRange: vi.fn() } as never,
|
||||
popupService as never,
|
||||
{ registerShortcut: vi.fn(() => ({ dispose: vi.fn() })) } as never,
|
||||
{
|
||||
getCurrentUnitOfType: vi.fn(() => ({ getDisabled: () => false })),
|
||||
} as never
|
||||
);
|
||||
|
||||
popupService.triggerMenuSelected(textMenu);
|
||||
popupService.triggerMenuSelected(numberedListMenu);
|
||||
|
||||
expect(commandService.executeCommand).not.toHaveBeenCalledWith(textMenu.id);
|
||||
expect(commandService.executeCommand).toHaveBeenCalledWith(numberedListMenu.id);
|
||||
|
||||
controller.dispose();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Disposable, Inject } from '@univerjs/core';
|
||||
import { DividerIcon, TextIcon } from '@univerjs/icons';
|
||||
import { ComponentManager, IconManager } from '@univerjs/ui';
|
||||
import { KeywordInputPlaceholder } from '../views/KeywordInputPlaceholder';
|
||||
import { QuickInsertButton } from '../views/QuickInsertButton';
|
||||
import { QuickInsertPlaceholder } from '../views/QuickInsertPlaceholder';
|
||||
import { QuickInsertPopup } from '../views/QuickInsertPopup';
|
||||
|
||||
export class ComponentsController extends Disposable {
|
||||
constructor(
|
||||
@Inject(ComponentManager) protected readonly _componentManager: ComponentManager,
|
||||
@Inject(IconManager) private readonly _iconManager: IconManager
|
||||
) {
|
||||
super();
|
||||
|
||||
this._registerIcons();
|
||||
this._registerComponents();
|
||||
}
|
||||
|
||||
private _registerIcons(): void {
|
||||
this.disposeWithMe(this._iconManager.register({
|
||||
DividerIcon,
|
||||
TextIcon,
|
||||
}));
|
||||
}
|
||||
|
||||
protected _registerComponents(): void {
|
||||
this._registerPopup();
|
||||
([
|
||||
[KeywordInputPlaceholder.componentKey, KeywordInputPlaceholder],
|
||||
[QuickInsertPlaceholder.componentKey, QuickInsertPlaceholder],
|
||||
[QuickInsertButton.componentKey, QuickInsertButton],
|
||||
] as const).forEach(([key, comp]) => {
|
||||
if (key) {
|
||||
this.disposeWithMe(this._componentManager.register(key, comp));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected _registerPopup(): void {
|
||||
this.disposeWithMe(this._componentManager.register(QuickInsertPopup.componentKey, QuickInsertPopup));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { DocumentDataModel } from '@univerjs/core';
|
||||
import type {
|
||||
IDeleteTextCommandParams,
|
||||
IInsertTextCommandParams,
|
||||
IRichTextEditingMutationParams,
|
||||
} from '@univerjs/docs';
|
||||
import type { IIMEInputCommandParams, IMoveCursorOperationParams } from '@univerjs/docs-ui';
|
||||
import {
|
||||
DeleteDirection,
|
||||
Direction,
|
||||
Disposable,
|
||||
ICommandService,
|
||||
Inject,
|
||||
IUniverInstanceService,
|
||||
UniverInstanceType,
|
||||
} from '@univerjs/core';
|
||||
import {
|
||||
DeleteTextCommand,
|
||||
DocSelectionManagerService,
|
||||
InsertTextCommand,
|
||||
RichTextEditingMutation,
|
||||
} from '@univerjs/docs';
|
||||
import { DeleteLeftCommand, IMEInputCommand, MoveCursorOperation } from '@univerjs/docs-ui';
|
||||
import { IShortcutService, KeyCode } from '@univerjs/ui';
|
||||
import {
|
||||
CloseQuickInsertPopupOperation,
|
||||
ShowQuickInsertPopupOperation,
|
||||
} from '../commands/operations/quick-insert-popup.operation';
|
||||
import { builtInMenuCommandIds, textMenu } from '../menu/menu';
|
||||
import { DocQuickInsertPopupService } from '../services/doc-quick-insert-popup.service';
|
||||
|
||||
export class DocQuickInsertTriggerController extends Disposable {
|
||||
constructor(
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@Inject(DocSelectionManagerService) private readonly _textSelectionManagerService: DocSelectionManagerService,
|
||||
@Inject(DocQuickInsertPopupService) private readonly _docQuickInsertPopupService: DocQuickInsertPopupService,
|
||||
@Inject(IShortcutService) private readonly _shortcutService: IShortcutService,
|
||||
@Inject(IUniverInstanceService) private readonly _univerInstanceService: IUniverInstanceService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.disposeWithMe(this._shortcutService.registerShortcut({
|
||||
id: CloseQuickInsertPopupOperation.id,
|
||||
binding: KeyCode.ESC,
|
||||
preconditions: () => Boolean(this._docQuickInsertPopupService.editPopup),
|
||||
priority: 1000,
|
||||
}));
|
||||
|
||||
this._initTrigger();
|
||||
this._initMenuHandler();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
private _initTrigger() {
|
||||
this.disposeWithMe(
|
||||
// eslint-disable-next-line complexity, max-lines-per-function
|
||||
this._commandService.onCommandExecuted((commandInfo) => {
|
||||
const { _docQuickInsertPopupService, _textSelectionManagerService, _commandService } = this;
|
||||
const documentDataModel = this._univerInstanceService.getCurrentUnitOfType<DocumentDataModel>(UniverInstanceType.UNIVER_DOC);
|
||||
if (documentDataModel?.getDisabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (commandInfo.id === InsertTextCommand.id) {
|
||||
const params = commandInfo.params as IInsertTextCommandParams;
|
||||
if (_docQuickInsertPopupService.editPopup) {
|
||||
_docQuickInsertPopupService.setInputOffset({
|
||||
start: _docQuickInsertPopupService.inputOffset.start,
|
||||
end: params.range.endOffset + 1,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const activeRange = _textSelectionManagerService.getActiveTextRange();
|
||||
if (!activeRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
const popup = _docQuickInsertPopupService.resolvePopup(params.body.dataStream);
|
||||
if (!popup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const available = popup.preconditions ? popup.preconditions(params) : true;
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
_docQuickInsertPopupService.setInputOffset({ start: activeRange.startOffset - 1, end: activeRange.startOffset });
|
||||
|
||||
setTimeout(() => {
|
||||
_commandService.executeCommand(ShowQuickInsertPopupOperation.id, {
|
||||
index: activeRange.startOffset - 1,
|
||||
unitId: params.unitId,
|
||||
popup,
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
if (commandInfo.id === IMEInputCommand.id) {
|
||||
const params = commandInfo.params as IIMEInputCommandParams;
|
||||
if (!_docQuickInsertPopupService.isComposing && params.isCompositionStart) {
|
||||
_docQuickInsertPopupService.setIsComposing(true);
|
||||
}
|
||||
|
||||
if (_docQuickInsertPopupService.isComposing && params.isCompositionEnd) {
|
||||
_docQuickInsertPopupService.setIsComposing(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (commandInfo.id === RichTextEditingMutation.id) {
|
||||
const params = commandInfo.params as IRichTextEditingMutationParams;
|
||||
if (params.isCompositionEnd) {
|
||||
const endOffset = params.textRanges?.[0]?.endOffset;
|
||||
if (endOffset) {
|
||||
_docQuickInsertPopupService.setInputOffset({ start: _docQuickInsertPopupService.inputOffset.start, end: endOffset });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (commandInfo.id === DeleteTextCommand.id) {
|
||||
const params = commandInfo.params as IDeleteTextCommandParams;
|
||||
if (_docQuickInsertPopupService.editPopup && params.direction === DeleteDirection.LEFT) {
|
||||
const len = params.len ?? 0;
|
||||
_docQuickInsertPopupService.setInputOffset({ start: _docQuickInsertPopupService.inputOffset.start, end: params.range.endOffset - len });
|
||||
}
|
||||
}
|
||||
|
||||
if (commandInfo.id === MoveCursorOperation.id) {
|
||||
const params = commandInfo.params as IMoveCursorOperationParams;
|
||||
|
||||
if (params.direction === Direction.LEFT || params.direction === Direction.RIGHT) {
|
||||
_docQuickInsertPopupService.editPopup && _commandService.executeCommand(CloseQuickInsertPopupOperation.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (commandInfo.id === DeleteLeftCommand.id) {
|
||||
const activeRange = _textSelectionManagerService.getActiveTextRange();
|
||||
if (!_docQuickInsertPopupService.editPopup || !activeRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeRange.endOffset <= _docQuickInsertPopupService.editPopup.anchor) {
|
||||
_commandService.executeCommand(CloseQuickInsertPopupOperation.id);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _initMenuHandler() {
|
||||
this.disposeWithMe(this._docQuickInsertPopupService.onMenuSelected((menu) => {
|
||||
if (menu.id === textMenu.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (builtInMenuCommandIds.has(menu.id)) {
|
||||
this._commandService.executeCommand(menu.id);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Disposable, Inject } from '@univerjs/core';
|
||||
import { DividerIcon, TextIcon } from '@univerjs/icons';
|
||||
import { ComponentManager, IconManager } from '@univerjs/ui';
|
||||
import { KeywordInputPlaceholder } from '../../views/KeywordInputPlaceholder';
|
||||
import { MobileQuickInsertPopup } from '../../views/mobile/MobileQuickInsertPopup';
|
||||
import { QuickInsertButton } from '../../views/QuickInsertButton';
|
||||
import { QuickInsertPlaceholder } from '../../views/QuickInsertPlaceholder';
|
||||
import { QuickInsertPopup } from '../../views/QuickInsertPopup';
|
||||
|
||||
export class MobileComponentsController extends Disposable {
|
||||
constructor(
|
||||
@Inject(ComponentManager) protected readonly _componentManager: ComponentManager,
|
||||
@Inject(IconManager) private readonly _iconManager: IconManager
|
||||
) {
|
||||
super();
|
||||
|
||||
this._registerIcons();
|
||||
this._registerComponents();
|
||||
}
|
||||
|
||||
private _registerIcons(): void {
|
||||
this.disposeWithMe(this._iconManager.register({
|
||||
DividerIcon,
|
||||
TextIcon,
|
||||
}));
|
||||
}
|
||||
|
||||
protected _registerComponents(): void {
|
||||
this._registerPopup();
|
||||
([
|
||||
[KeywordInputPlaceholder.componentKey, KeywordInputPlaceholder],
|
||||
[QuickInsertPlaceholder.componentKey, QuickInsertPlaceholder],
|
||||
[QuickInsertButton.componentKey, QuickInsertButton],
|
||||
] as const).forEach(([key, comp]) => {
|
||||
if (key) {
|
||||
this.disposeWithMe(this._componentManager.register(key, comp));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected _registerPopup(): void {
|
||||
this.disposeWithMe(this._componentManager.register(QuickInsertPopup.componentKey, MobileQuickInsertPopup));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { ITextRangeWithStyle } from '@univerjs/engine-render';
|
||||
import type { IDocPopup } from '../services/doc-quick-insert-popup.service';
|
||||
import { Disposable, ICommandService, Inject } from '@univerjs/core';
|
||||
import { of } from 'rxjs';
|
||||
import { DeleteSearchKeyCommand } from '../commands/commands/doc-quick-insert.command';
|
||||
import { CloseQuickInsertPopupOperation, ShowQuickInsertPopupOperation } from '../commands/operations/quick-insert-popup.operation';
|
||||
import { builtInMenus } from '../menu/menu';
|
||||
import { DocQuickInsertPopupService } from '../services/doc-quick-insert-popup.service';
|
||||
|
||||
export class DocQuickInsertUIController extends Disposable {
|
||||
constructor(
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@Inject(DocQuickInsertPopupService) private readonly _docQuickInsertPopupService: DocQuickInsertPopupService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._initCommands();
|
||||
this._initComponents();
|
||||
this._initMenus();
|
||||
}
|
||||
|
||||
private _initCommands() {
|
||||
[
|
||||
DeleteSearchKeyCommand,
|
||||
ShowQuickInsertPopupOperation,
|
||||
CloseQuickInsertPopupOperation,
|
||||
].forEach((operation) => {
|
||||
this.disposeWithMe(this._commandService.registerCommand(operation));
|
||||
});
|
||||
}
|
||||
|
||||
private _initComponents() {
|
||||
const popups: IDocPopup[] = [
|
||||
{
|
||||
keyword: '/',
|
||||
menus$: of(builtInMenus),
|
||||
// only show when the cursor is at the beginning of a line
|
||||
preconditions: (params) => (params.range as ITextRangeWithStyle).startNodePosition?.glyph === 0,
|
||||
},
|
||||
];
|
||||
|
||||
popups.forEach((popup) => {
|
||||
this.disposeWithMe(this._docQuickInsertPopupService.registerPopup(popup));
|
||||
});
|
||||
}
|
||||
|
||||
private _initMenus() {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user