From fbba688de98a85506c9176a152e55ec8ef2e04e0 Mon Sep 17 00:00:00 2001 From: SIHAN LI <1015813038@qq.com> Date: Fri, 14 Feb 2025 20:31:00 -0500 Subject: [PATCH] [Fix] improve context menu destruction logic on selection change --- .../slashCommandExtension.ts | 55 +++++++++++++++---- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/editor/contrib/slashCommandExtension/slashCommandExtension.ts b/src/editor/contrib/slashCommandExtension/slashCommandExtension.ts index ef2d9e2e4..6b5f8cfb9 100644 --- a/src/editor/contrib/slashCommandExtension/slashCommandExtension.ts +++ b/src/editor/contrib/slashCommandExtension/slashCommandExtension.ts @@ -39,7 +39,7 @@ export class EditorSlashCommandExtension extends EditorExtension implements IEdi @II18nService i18nService: II18nService, ) { super(editorWidget); - this._keyboardController = this.__register(new SlashKeyboardController(this, editorWidget, contextMenuService)); + this._keyboardController = this.__register(new SlashKeyboardController(this, contextMenuService)); this._menuController = new SlashMenuController(editorWidget); this._menuRenderer = this.__register(new SlashMenuRenderer(editorWidget, contextMenuService, i18nService)); @@ -96,15 +96,23 @@ class SlashKeyboardController implements IDisposable { private _ongoing?: IDisposable; + private _triggeredNode?: { + readonly pos: number; + readonly depth: number; + readonly nodeType: string; + }; + constructor( private readonly extension: EditorSlashCommandExtension, - private readonly editorWidget: IEditorWidget, private readonly contextMenuService: IContextMenuService, - ) {} + ) { + this._triggeredNode = undefined; + } public dispose(): void { this._ongoing?.dispose(); this._ongoing = undefined; + this._triggeredNode = undefined; } public unlisten(): void { @@ -115,6 +123,8 @@ class SlashKeyboardController implements IDisposable { * Invoked whenever a menu is rendererd, we handle the keyboard logic here. */ public listen(view: ProseEditorView): void { + this.__trackCurrentNode(view); + this._ongoing?.dispose(); const bucket = (this._ongoing = new DisposableBucket()); @@ -195,17 +205,42 @@ class SlashKeyboardController implements IDisposable { } })); - // TODO: destroy contextMenu whenever the selection changes to other blocks. - /** - * Whenever clicks happens, destory contextMenu. Unless the user is - * clicking the current text block. + * Destroy slash command whenever the selection changes to other blocks. */ - bucket.register(this.extension.onDidClick(e => { - // TODO: check if clicking the current text block - this.contextMenuService.contextMenu.destroy(); + bucket.register(this.extension.onDidSelectionChange(e => { + const menu = this.contextMenuService.contextMenu; + const triggeredNode = this._triggeredNode; + if (!triggeredNode) { + return; + } + + // obtain current selection's node info + const currSelection = e.transaction.selection; + const $current = currSelection.$from; + const mappedPos = e.transaction.mapping.map(triggeredNode.pos); + + const isSameNode = ( + $current.parent.type.name === triggeredNode.nodeType && + $current.before() === mappedPos && + $current.depth === triggeredNode.depth + ); + + if (!isSameNode) { + menu.destroy(); + } })); } + + private __trackCurrentNode(view: ProseEditorView): void { + const { state } = view; + const $pos = state.selection.$from; + this._triggeredNode = { + pos: $pos.before(), + depth: $pos.depth, + nodeType: $pos.parent.type.name, + }; + } } // region - SlashMenuRenderer