From acca9ea83fdd399f95880aabc01da6d9546956cc Mon Sep 17 00:00:00 2001 From: Maribeth Moffatt Date: Tue, 15 Apr 2025 11:24:01 -0700 Subject: [PATCH] feat!: deprecate scopeType and include focusedNode in context menu options (#8882) * feat!: deprecate scopeType and include focusedNode in context menu options * chore: add issue to todo --- core/block_svg.ts | 3 +- core/comments/rendered_workspace_comment.ts | 3 +- core/contextmenu_registry.ts | 90 +++++++++++---------- core/workspace_svg.ts | 3 +- 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/core/block_svg.ts b/core/block_svg.ts index b2f6c1c9c..b8712b019 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -588,8 +588,7 @@ export class BlockSvg return null; } const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( - ContextMenuRegistry.ScopeType.BLOCK, - {block: this}, + {block: this, focusedNode: this}, e, ); diff --git a/core/comments/rendered_workspace_comment.ts b/core/comments/rendered_workspace_comment.ts index 8a592a78b..bcb650b26 100644 --- a/core/comments/rendered_workspace_comment.ts +++ b/core/comments/rendered_workspace_comment.ts @@ -286,8 +286,7 @@ export class RenderedWorkspaceComment /** Show a context menu for this comment. */ showContextMenu(e: Event): void { const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( - ContextMenuRegistry.ScopeType.COMMENT, - {comment: this}, + {comment: this, focusedNode: this}, e, ); diff --git a/core/contextmenu_registry.ts b/core/contextmenu_registry.ts index 06b60801a..fc7a94dcb 100644 --- a/core/contextmenu_registry.ts +++ b/core/contextmenu_registry.ts @@ -13,6 +13,7 @@ import type {BlockSvg} from './block_svg.js'; import {RenderedWorkspaceComment} from './comments/rendered_workspace_comment.js'; +import type {IFocusableNode} from './interfaces/i_focusable_node.js'; import {Coordinate} from './utils/coordinate.js'; import type {WorkspaceSvg} from './workspace_svg.js'; @@ -71,56 +72,60 @@ export class ContextMenuRegistry { } /** - * Gets the valid context menu options for the given scope type (e.g. block or - * workspace) and scope. Blocks are only shown if the preconditionFn shows + * Gets the valid context menu options for the given scope. + * Options are only included if the preconditionFn shows * they should not be hidden. * - * @param scopeType Type of scope where menu should be shown (e.g. on a block - * or on a workspace) * @param scope Current scope of context menu (i.e., the exact workspace or - * block being clicked on) + * block being clicked on). + * @param menuOpenEvent Event that caused the menu to open. * @returns the list of ContextMenuOptions */ getContextMenuOptions( - scopeType: ScopeType, scope: Scope, menuOpenEvent: Event, ): ContextMenuOption[] { const menuOptions: ContextMenuOption[] = []; for (const item of this.registeredItems.values()) { - if (scopeType === item.scopeType) { - let menuOption: - | ContextMenuRegistry.CoreContextMenuOption - | ContextMenuRegistry.SeparatorContextMenuOption - | ContextMenuRegistry.ActionContextMenuOption; - menuOption = { - scope, - weight: item.weight, - }; - - if (item.separator) { - menuOption = { - ...menuOption, - separator: true, - }; - } else { - const precondition = item.preconditionFn(scope, menuOpenEvent); - if (precondition === 'hidden') continue; - - const displayText = - typeof item.displayText === 'function' - ? item.displayText(scope) - : item.displayText; - menuOption = { - ...menuOption, - text: displayText, - callback: item.callback, - enabled: precondition === 'enabled', - }; - } - - menuOptions.push(menuOption); + if (item.scopeType) { + // If the scopeType is present, check to make sure + // that the option is compatible with the current scope + if (item.scopeType === ScopeType.BLOCK && !scope.block) continue; + if (item.scopeType === ScopeType.COMMENT && !scope.comment) continue; + if (item.scopeType === ScopeType.WORKSPACE && !scope.workspace) + continue; } + let menuOption: + | ContextMenuRegistry.CoreContextMenuOption + | ContextMenuRegistry.SeparatorContextMenuOption + | ContextMenuRegistry.ActionContextMenuOption; + menuOption = { + scope, + weight: item.weight, + }; + + if (item.separator) { + menuOption = { + ...menuOption, + separator: true, + }; + } else { + const precondition = item.preconditionFn(scope, menuOpenEvent); + if (precondition === 'hidden') continue; + + const displayText = + typeof item.displayText === 'function' + ? item.displayText(scope) + : item.displayText; + menuOption = { + ...menuOption, + text: displayText, + callback: item.callback, + enabled: precondition === 'enabled', + }; + } + + menuOptions.push(menuOption); } menuOptions.sort(function (a, b) { return a.weight - b.weight; @@ -142,20 +147,23 @@ export namespace ContextMenuRegistry { } /** - * The actual workspace/block where the menu is being rendered. This is passed - * to callback and displayText functions that depend on this information. + * The actual workspace/block/focused object where the menu is being + * rendered. This is passed to callback and displayText functions + * that depend on this information. */ export interface Scope { block?: BlockSvg; workspace?: WorkspaceSvg; comment?: RenderedWorkspaceComment; + // TODO(#8839): Remove any once Block, etc. implement IFocusableNode + focusedNode?: IFocusableNode | any; } /** * Fields common to all context menu registry items. */ interface CoreRegistryItem { - scopeType: ScopeType; + scopeType?: ScopeType; weight: number; id: string; } diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index e9414dcde..91668b744 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -1711,8 +1711,7 @@ export class WorkspaceSvg return; } const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( - ContextMenuRegistry.ScopeType.WORKSPACE, - {workspace: this}, + {workspace: this, focusedNode: this}, e, );