mirror of
https://github.com/dream-num/univer.git
synced 2026-10-02 04:24:34 +08:00
fix(docs-hyper-link-ui): respect host editor hyperlink ownership (#7754)
This commit is contained in:
+2
-2
@@ -24,7 +24,7 @@ import {
|
||||
Inject,
|
||||
} from '@univerjs/core';
|
||||
import { DocSelectionManagerService, DocSkeletonManagerService } from '@univerjs/docs';
|
||||
import { DocEventManagerService } from '@univerjs/docs-ui';
|
||||
import { DocEventManagerService, getEditorRuntimeConfig } from '@univerjs/docs-ui';
|
||||
import {
|
||||
ClickDocHyperLinkOperation,
|
||||
ToggleDocHyperLinkInfoPopupOperation,
|
||||
@@ -46,7 +46,7 @@ export class DocHyperLinkEventRenderController extends Disposable implements IRe
|
||||
) {
|
||||
super();
|
||||
|
||||
if (this._context.unitId === DOCS_NORMAL_EDITOR_UNIT_ID_KEY) {
|
||||
if (this._context.unitId === DOCS_NORMAL_EDITOR_UNIT_ID_KEY || getEditorRuntimeConfig(this._context.unit)?.customHyperLinkUI) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+144
-87
@@ -14,79 +14,126 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** @vitest-environment jsdom */
|
||||
|
||||
import type { DocumentDataModel, IDocumentData } from '@univerjs/core';
|
||||
import type { RenderUnit } from '@univerjs/engine-render';
|
||||
import { IPermissionService, LocaleService, LocaleType, Univer, UniverInstanceType } from '@univerjs/core';
|
||||
import {
|
||||
IPermissionService,
|
||||
toDisposable,
|
||||
Univer,
|
||||
UniverInstanceType,
|
||||
} from '@univerjs/core';
|
||||
import { DocSelectionManagerService, setDocumentPermissionValue } from '@univerjs/docs';
|
||||
import { DocCanvasPopManagerService } from '@univerjs/docs-ui';
|
||||
import { IRenderManagerService, RenderManagerService } from '@univerjs/engine-render';
|
||||
DocLayoutExecutorService,
|
||||
DocSelectionManagerService,
|
||||
DocSkeletonManagerService,
|
||||
setDocumentPermissionValue,
|
||||
} from '@univerjs/docs';
|
||||
import { DocCanvasPopManagerService, registerEditorRuntimeConfig } from '@univerjs/docs-ui';
|
||||
import { Documents, FontCache, IRenderManagerService, UniverRenderEnginePlugin } from '@univerjs/engine-render';
|
||||
import { UnitAction } from '@univerjs/protocol';
|
||||
import { IDialogService } from '@univerjs/ui';
|
||||
import { of } from 'rxjs';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
CanvasPopupService,
|
||||
DesktopDialogService,
|
||||
ICanvasPopupService,
|
||||
IDialogService,
|
||||
IUIPartsService,
|
||||
UIPartsService,
|
||||
} from '@univerjs/ui';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import enUS from '../../locale/en-US';
|
||||
import { DocHyperLinkPopupService } from '../hyper-link-popup.service';
|
||||
|
||||
class CapturingDocCanvasPopManagerService {
|
||||
readonly attached: unknown[] = [];
|
||||
readonly disposed: number[] = [];
|
||||
|
||||
attachPopupToRange(range: unknown, popup: unknown, unitId: string) {
|
||||
this.attached.push({ range, popup, unitId });
|
||||
const order = this.attached.length;
|
||||
return { dispose: () => this.disposed.push(order) };
|
||||
const instances = new Set<Univer>();
|
||||
afterEach(() => {
|
||||
for (const univer of instances) {
|
||||
univer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
const CapturingDocCanvasPopManagerServiceCtor = CapturingDocCanvasPopManagerService as unknown as typeof DocCanvasPopManagerService;
|
||||
instances.clear();
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
function createService() {
|
||||
// Canvas is the unavailable platform boundary; document and popup services stay real.
|
||||
const context = new Proxy({ webkitBackingStorePixelRatio: 1, measureText: (text: string) => ({ width: text.length * 8, actualBoundingBoxAscent: 10, actualBoundingBoxDescent: 2, fontBoundingBoxAscent: 10, fontBoundingBoxDescent: 2 }) }, {
|
||||
get: (target, key) => key in target ? Reflect.get(target, key) : () => {},
|
||||
});
|
||||
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(context as never);
|
||||
Reflect.set(FontCache, '_context', null);
|
||||
FontCache.invalidateMetrics(() => true);
|
||||
const univer = new Univer();
|
||||
instances.add(univer);
|
||||
univer.registerPlugin(UniverRenderEnginePlugin);
|
||||
const injector = univer.__getInjector();
|
||||
injector.add([IDialogService, {
|
||||
useValue: {
|
||||
close: () => {},
|
||||
closeAll: () => {},
|
||||
getDialogs$: () => of([]),
|
||||
open: () => toDisposable(() => {}),
|
||||
},
|
||||
}]);
|
||||
injector.add([DocCanvasPopManagerService, { useClass: CapturingDocCanvasPopManagerServiceCtor }]);
|
||||
injector.add([IRenderManagerService, { useClass: RenderManagerService }]);
|
||||
injector.add([IUIPartsService, { useClass: UIPartsService }]);
|
||||
injector.add([IDialogService, { useClass: DesktopDialogService }]);
|
||||
injector.add([ICanvasPopupService, { useClass: CanvasPopupService }]);
|
||||
injector.add([DocCanvasPopManagerService]);
|
||||
injector.add([DocLayoutExecutorService]);
|
||||
injector.add([DocSelectionManagerService]);
|
||||
injector.add([DocHyperLinkPopupService]);
|
||||
univer.createUnit(UniverInstanceType.UNIVER_DOC, { id: 'doc-1' });
|
||||
const locale = injector.get(LocaleService);
|
||||
locale.load({ [LocaleType.EN_US]: enUS });
|
||||
locale.setLocale(LocaleType.EN_US);
|
||||
locale.setDirection('ltr');
|
||||
const model = univer.createUnit<IDocumentData, DocumentDataModel>(UniverInstanceType.UNIVER_DOC, {
|
||||
id: 'doc-1',
|
||||
body: { dataStream: 'first link and second link\r\n', paragraphs: [{ startIndex: 26, paragraphId: 'paragraph' }], sectionBreaks: [{ startIndex: 27, sectionId: 'section' }] },
|
||||
documentStyle: { pageSize: { width: 400, height: 300 } },
|
||||
});
|
||||
univer.createUnit(UniverInstanceType.UNIVER_DOC, { id: 'doc-2' });
|
||||
const manager = injector.get(IRenderManagerService);
|
||||
const render = manager.createRender('doc-1') as RenderUnit;
|
||||
render.deactivate();
|
||||
render.engine.resizeBySize(500, 500);
|
||||
vi.spyOn(render.engine.getCanvasElement(), 'getBoundingClientRect').mockReturnValue(new DOMRect(0, 0, 500, 500));
|
||||
render.addRenderDependencies([[DocSkeletonManagerService]]);
|
||||
const documents = new Documents('doc-1', render.with(DocSkeletonManagerService).getSkeleton());
|
||||
render.mainComponent = documents;
|
||||
render.scene.addObject(documents);
|
||||
manager.createRender('doc-2').deactivate();
|
||||
const selectionManager = injector.get(DocSelectionManagerService);
|
||||
selectionManager.__TEST_ONLY_setCurrentSelection({ unitId: 'doc-1', subUnitId: 'doc-1' });
|
||||
const popupManager = injector.get(DocCanvasPopManagerService) as unknown as CapturingDocCanvasPopManagerService;
|
||||
const permissionService = injector.get(IPermissionService);
|
||||
const renderManagerService = injector.get(IRenderManagerService);
|
||||
|
||||
const attach = vi.spyOn(injector.get(DocCanvasPopManagerService), 'attachPopupToRange');
|
||||
const canvasPopup = injector.get(ICanvasPopupService);
|
||||
const add = vi.spyOn(canvasPopup, 'addPopup');
|
||||
const remove = vi.spyOn(canvasPopup, 'removePopup');
|
||||
return {
|
||||
service: injector.get(DocHyperLinkPopupService),
|
||||
injector,
|
||||
registerCustomHyperLinkUI: () => registerEditorRuntimeConfig(model, { customHyperLinkUI: true }),
|
||||
dispose: () => univer.dispose(),
|
||||
selectionManager,
|
||||
attached: popupManager.attached,
|
||||
disposed: popupManager.disposed,
|
||||
disposeRender: (unitId: string) => {
|
||||
renderManagerService.addRender(unitId, {
|
||||
unitId,
|
||||
type: UniverInstanceType.UNIVER_DOC,
|
||||
components: new Map(),
|
||||
engine: { dispose: () => {} },
|
||||
scene: { dispose: () => {} },
|
||||
dispose: () => {},
|
||||
} as never);
|
||||
renderManagerService.removeRender(unitId);
|
||||
},
|
||||
permissionService,
|
||||
attached: () => attach.mock.calls.map(([range, popup, unitId]) => ({ range, popup, unitId })),
|
||||
disposed: () => remove.mock.calls.map(([id]) => add.mock.results.findIndex((result) => result.value === id) + 1),
|
||||
disposeRender: (unitId: string) => manager.removeRender(unitId),
|
||||
permissionService: injector.get(IPermissionService),
|
||||
};
|
||||
}
|
||||
|
||||
describe('DocHyperLinkPopupService', () => {
|
||||
it('leaves hyperlink menus to the host editor and restores default behavior after unregistering', () => {
|
||||
const { injector, attached, registerCustomHyperLinkUI, dispose } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const ownership = registerCustomHyperLinkUI();
|
||||
const link = { unitId: 'doc-1', linkId: 'link-1', startIndex: 0, endIndex: 3 };
|
||||
try {
|
||||
service.showInfoPopup(link);
|
||||
service.showInfoPopupFromHover(link);
|
||||
service.showInfoPopup(link, { pinned: true });
|
||||
service.showEditPopup('doc-1', link);
|
||||
expect(attached()).toHaveLength(0);
|
||||
expect(service.showing).toBeNull();
|
||||
expect(service.editing).toBeNull();
|
||||
ownership.dispose();
|
||||
service.showInfoPopup(link);
|
||||
expect(attached()).toHaveLength(1);
|
||||
expect(service.showing?.linkId).toBe('link-1');
|
||||
} finally {
|
||||
ownership.dispose();
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
||||
it('closes link popups only when their owning Render is disposed', () => {
|
||||
const { service, disposed, disposeRender } = createService();
|
||||
const { injector, disposed, disposeRender } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const link = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -97,14 +144,15 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.showEditPopup('doc-1', link);
|
||||
service.showInfoPopup(link);
|
||||
disposeRender('doc-2');
|
||||
expect(disposed).toEqual([]);
|
||||
expect(disposed()).toEqual([]);
|
||||
|
||||
disposeRender('doc-1');
|
||||
expect(disposed).toEqual([1, 2]);
|
||||
expect(disposed()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('releases owned link popups when the service is disposed', () => {
|
||||
const { service, disposed } = createService();
|
||||
const { injector, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const link = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -116,11 +164,12 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.showInfoPopup(link);
|
||||
service.dispose();
|
||||
|
||||
expect(disposed).toEqual([1, 2]);
|
||||
expect(disposed()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('opens edit and info popups around the selected document link and disposes previous popups', () => {
|
||||
const { service, selectionManager, attached, disposed } = createService();
|
||||
const { injector, selectionManager, attached, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const refreshes: unknown[] = [];
|
||||
const refreshSub = selectionManager.refreshSelection$.subscribe((value) => refreshes.push(value));
|
||||
const link = {
|
||||
@@ -133,7 +182,7 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.showEditPopup('doc-1', link);
|
||||
expect(service.editing).toEqual(link);
|
||||
expect(refreshes.at(-1)).toMatchObject({ docRanges: [{ startOffset: 4, endOffset: 9 }] });
|
||||
expect(attached).toMatchObject([{
|
||||
expect(attached()).toMatchObject([{
|
||||
range: { startOffset: 4, endOffset: 9, collapsed: false },
|
||||
popup: { offset: [0, 10] },
|
||||
unitId: 'doc-1',
|
||||
@@ -141,7 +190,7 @@ describe('DocHyperLinkPopupService', () => {
|
||||
|
||||
service.showInfoPopup(link);
|
||||
expect(service.showing).toEqual(link);
|
||||
expect(attached.at(-1)).toMatchObject({
|
||||
expect(attached().at(-1)).toMatchObject({
|
||||
range: { startOffset: 4, endOffset: 9, collapsed: false },
|
||||
popup: { offset: [0, 10] },
|
||||
unitId: 'doc-1',
|
||||
@@ -151,13 +200,14 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.hideInfoPopup();
|
||||
expect(service.editing).toBeNull();
|
||||
expect(service.showing).toBeNull();
|
||||
expect(disposed).toEqual([1, 2]);
|
||||
expect(disposed()).toEqual([1, 2]);
|
||||
|
||||
refreshSub.unsubscribe();
|
||||
});
|
||||
|
||||
it('opens the edit popup from the current text selection when creating a new hyperlink', () => {
|
||||
const { service, selectionManager, attached, disposed } = createService();
|
||||
const { injector, selectionManager, attached, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
selectionManager.__TEST_ONLY_add([{
|
||||
startOffset: 1,
|
||||
endOffset: 5,
|
||||
@@ -172,15 +222,16 @@ describe('DocHyperLinkPopupService', () => {
|
||||
expect(firstPopup).not.toBeNull();
|
||||
expect(secondPopup).not.toBeNull();
|
||||
expect(service.editing).toBeNull();
|
||||
expect(attached).toMatchObject([
|
||||
expect(attached()).toMatchObject([
|
||||
{ range: { startOffset: 1, endOffset: 5, collapsed: false }, unitId: 'doc-1' },
|
||||
{ range: { startOffset: 1, endOffset: 5, collapsed: false }, unitId: 'doc-1' },
|
||||
]);
|
||||
expect(disposed).toEqual([1]);
|
||||
expect(disposed()).toEqual([1]);
|
||||
});
|
||||
|
||||
it('reuses an already visible link popup and replaces it only when the hovered link changes', () => {
|
||||
const { service, attached, disposed } = createService();
|
||||
const { injector, attached, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const firstLink = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -201,13 +252,14 @@ describe('DocHyperLinkPopupService', () => {
|
||||
expect(firstPopup).not.toBeNull();
|
||||
expect(duplicatePopup).toBeUndefined();
|
||||
expect(secondPopup).not.toBeNull();
|
||||
expect(attached).toHaveLength(2);
|
||||
expect(attached()).toHaveLength(2);
|
||||
expect(service.showing).toEqual(secondLink);
|
||||
expect(disposed).toEqual([1]);
|
||||
expect(disposed()).toEqual([1]);
|
||||
});
|
||||
|
||||
it('keeps a click-pinned popup pinned until another link replaces it or it closes', () => {
|
||||
const { service } = createService();
|
||||
const { injector } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const firstLink = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -237,7 +289,8 @@ describe('DocHyperLinkPopupService', () => {
|
||||
|
||||
it('keeps a hovered popup visible while the pointer crosses to it and closes after the handoff delay', () => {
|
||||
vi.useFakeTimers();
|
||||
const { service, disposed } = createService();
|
||||
const { injector, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const link = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -258,7 +311,7 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.scheduleHideInfoPopup();
|
||||
vi.advanceTimersByTime(150);
|
||||
expect(service.showing).toBeNull();
|
||||
expect(disposed).toEqual([1]);
|
||||
expect(disposed()).toEqual([1]);
|
||||
} finally {
|
||||
service.dispose();
|
||||
vi.useRealTimers();
|
||||
@@ -266,7 +319,8 @@ describe('DocHyperLinkPopupService', () => {
|
||||
});
|
||||
|
||||
it('keeps the current popup while the pointer crosses adjacent links', () => {
|
||||
const { service, attached, disposed } = createService();
|
||||
const { injector, attached, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const firstLink = { unitId: 'doc-1', linkId: 'link-1', startIndex: 4, endIndex: 8 };
|
||||
const secondLink = { unitId: 'doc-1', linkId: 'link-2', startIndex: 9, endIndex: 13 };
|
||||
|
||||
@@ -274,20 +328,21 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.showInfoPopupFromHover(secondLink);
|
||||
|
||||
expect(service.showing).toEqual(firstLink);
|
||||
expect(attached).toHaveLength(1);
|
||||
expect(disposed).toEqual([]);
|
||||
expect(attached()).toHaveLength(1);
|
||||
expect(disposed()).toEqual([]);
|
||||
|
||||
service.hideInfoPopup();
|
||||
service.showInfoPopupFromHover(secondLink);
|
||||
expect(service.showing).toEqual(secondLink);
|
||||
expect(attached).toHaveLength(2);
|
||||
expect(disposed).toEqual([1]);
|
||||
expect(attached()).toHaveLength(2);
|
||||
expect(disposed()).toEqual([1]);
|
||||
|
||||
service.dispose();
|
||||
});
|
||||
|
||||
it('does not show link information when the target document is not loaded', () => {
|
||||
const { service, attached } = createService();
|
||||
const { injector, attached } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
|
||||
const popup = service.showInfoPopup({
|
||||
unitId: 'missing-doc',
|
||||
@@ -298,11 +353,12 @@ describe('DocHyperLinkPopupService', () => {
|
||||
|
||||
expect(popup).toBeUndefined();
|
||||
expect(service.showing).toBeNull();
|
||||
expect(attached).toEqual([]);
|
||||
expect(attached()).toEqual([]);
|
||||
});
|
||||
|
||||
it('hides the link information popup when the user clicks outside it', () => {
|
||||
const { service, attached, disposed } = createService();
|
||||
const { injector, attached, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const link = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -311,15 +367,15 @@ describe('DocHyperLinkPopupService', () => {
|
||||
};
|
||||
|
||||
service.showInfoPopup(link);
|
||||
const popupConfig = (attached[0] as { popup: { onClickOutside: () => void } }).popup;
|
||||
popupConfig.onClickOutside();
|
||||
attached()[0].popup.onClickOutside?.(new MouseEvent('click'));
|
||||
|
||||
expect(service.showing).toBeNull();
|
||||
expect(disposed).toEqual([1]);
|
||||
expect(disposed()).toEqual([1]);
|
||||
});
|
||||
|
||||
it('prevents a stale selection refresh from restoring a popup closed on pointer down', async () => {
|
||||
const { service, attached, disposed } = createService();
|
||||
const { injector, attached, disposed } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
const link = {
|
||||
unitId: 'doc-1',
|
||||
linkId: 'link-1',
|
||||
@@ -332,18 +388,19 @@ describe('DocHyperLinkPopupService', () => {
|
||||
service.showInfoPopup(link);
|
||||
|
||||
expect(service.showing).toBeNull();
|
||||
expect(attached).toHaveLength(1);
|
||||
expect(disposed).toEqual([1]);
|
||||
expect(attached()).toHaveLength(1);
|
||||
expect(disposed()).toEqual([1]);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
service.showInfoPopup(link);
|
||||
|
||||
expect(service.showing).toEqual(link);
|
||||
expect(attached).toHaveLength(2);
|
||||
expect(attached()).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('does not open an edit popup without document edit permission', () => {
|
||||
const { service, attached, permissionService } = createService();
|
||||
const { injector, attached, permissionService } = createService();
|
||||
const service = injector.get(DocHyperLinkPopupService);
|
||||
setDocumentPermissionValue(
|
||||
permissionService,
|
||||
'doc-1',
|
||||
@@ -353,6 +410,6 @@ describe('DocHyperLinkPopupService', () => {
|
||||
);
|
||||
|
||||
expect(service.showEditPopup('doc-1', null)).toBeNull();
|
||||
expect(attached).toEqual([]);
|
||||
expect(attached()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,8 +25,13 @@ import {
|
||||
LocaleService,
|
||||
UniverInstanceType,
|
||||
} from '@univerjs/core';
|
||||
import { canEditDocumentTargets, DocSelectionManagerService, getDocumentEntityParentPermissionObjectIds, getDocumentEntityPermissionObjectId } from '@univerjs/docs';
|
||||
import { DocCanvasPopManagerService } from '@univerjs/docs-ui';
|
||||
import {
|
||||
canEditDocumentTargets,
|
||||
DocSelectionManagerService,
|
||||
getDocumentEntityParentPermissionObjectIds,
|
||||
getDocumentEntityPermissionObjectId,
|
||||
} from '@univerjs/docs';
|
||||
import { DocCanvasPopManagerService, getEditorRuntimeConfig } from '@univerjs/docs-ui';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { IDialogService } from '@univerjs/ui';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
@@ -128,6 +133,10 @@ export class DocHyperLinkPopupService extends Disposable {
|
||||
}
|
||||
|
||||
showEditPopup(unitId: string, linkInfo: ILinkInfo | null): IDisposable | null {
|
||||
const doc = this._univerInstanceService.getUnit<DocumentDataModel>(unitId, UniverInstanceType.UNIVER_DOC);
|
||||
if (doc && getEditorRuntimeConfig(doc)?.customHyperLinkUI) {
|
||||
return null;
|
||||
}
|
||||
if (!this.canEditLink(unitId, linkInfo)) {
|
||||
return null;
|
||||
}
|
||||
@@ -174,6 +183,10 @@ export class DocHyperLinkPopupService extends Disposable {
|
||||
}
|
||||
|
||||
showInfoPopup(info: ILinkInfo, options?: { pinned?: boolean }): IDisposable | null | undefined {
|
||||
const doc = this._univerInstanceService.getUnit(info.unitId, UniverInstanceType.UNIVER_DOC);
|
||||
if (!(doc instanceof DocumentDataModel) || getEditorRuntimeConfig(doc)?.customHyperLinkUI) {
|
||||
return;
|
||||
}
|
||||
this.cancelScheduledHideInfoPopup();
|
||||
if (this._infoPopupSuppressed) {
|
||||
return;
|
||||
@@ -192,10 +205,6 @@ export class DocHyperLinkPopupService extends Disposable {
|
||||
this._infoPopup.dispose();
|
||||
this._infoPopup = null;
|
||||
}
|
||||
const doc = this._univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_DOC);
|
||||
if (!(doc instanceof DocumentDataModel)) {
|
||||
return;
|
||||
}
|
||||
this._infoPopupPinned = options?.pinned ?? false;
|
||||
this._showingLink$.next({ unitId, linkId, segmentId, segmentPage, startIndex, endIndex });
|
||||
|
||||
|
||||
@@ -266,6 +266,7 @@ export { DocsRenderService } from './services/docs-render.service';
|
||||
export { Editor } from './services/editor/editor';
|
||||
export { EditorService, IEditorService } from './services/editor/editor-manager.service';
|
||||
export type { IEditorRuntimeConfig } from './services/editor/editor-runtime-config';
|
||||
export { getEditorRuntimeConfig, registerEditorRuntimeConfig } from './services/editor/editor-runtime-config';
|
||||
export { DocFloatMenuService } from './services/float-menu.service';
|
||||
export {
|
||||
isInSameTableCell,
|
||||
|
||||
@@ -23,6 +23,8 @@ export interface IEditorRuntimeConfig {
|
||||
layout?: IDocumentLayoutPresentation;
|
||||
inheritParagraphStartStyle?: boolean;
|
||||
disableSelectionAutoScroll?: boolean;
|
||||
/** The host editor provides its own hyperlink menus and pointer interaction. */
|
||||
customHyperLinkUI?: boolean;
|
||||
}
|
||||
|
||||
const configs = new WeakMap<DocumentDataModel, { config: IEditorRuntimeConfig }>();
|
||||
|
||||
Reference in New Issue
Block a user