@@ -10,7 +10,6 @@ import {
1010 ContextMenu ,
1111 ContextMenuRegistry ,
1212 ShortcutRegistry ,
13- comments ,
1413 utils as BlocklyUtils ,
1514 WidgetDiv ,
1615} from 'blockly' ;
@@ -23,10 +22,7 @@ const createSerializedKey = ShortcutRegistry.registry.createSerializedKey.bind(
2322 ShortcutRegistry . registry ,
2423) ;
2524
26- export interface Scope {
27- block ?: BlockSvg ;
28- workspace ?: WorkspaceSvg ;
29- comment ?: comments . RenderedWorkspaceComment ;
25+ export interface ScopeWithConnection extends ContextMenuRegistry . Scope {
3026 connection ?: Connection ;
3127}
3228
@@ -100,6 +96,8 @@ export class ActionMenu {
10096 * Returns true if it is possible to open the action menu in the
10197 * current location, even if the menu was not opened due there being
10298 * no applicable menu items.
99+ *
100+ * @param workspace The workspace.
103101 */
104102 private openActionMenu ( workspace : WorkspaceSvg ) : boolean {
105103 let menuOptions : Array <
@@ -114,7 +112,7 @@ export class ActionMenu {
114112 if ( ! node ) return false ;
115113 const nodeType = node . getType ( ) ;
116114 switch ( nodeType ) {
117- case ASTNode . types . BLOCK :
115+ case ASTNode . types . BLOCK : {
118116 const block = node . getLocation ( ) as BlockSvg ;
119117 rtl = block . RTL ;
120118 // Reimplement BlockSvg.prototype.generateContextMenu as that
@@ -130,11 +128,12 @@ export class ActionMenu {
130128 }
131129 // End reimplement.
132130 break ;
131+ }
133132
134133 // case Blockly.ASTNode.types.INPUT:
135134 case ASTNode . types . NEXT :
136135 case ASTNode . types . PREVIOUS :
137- case ASTNode . types . INPUT :
136+ case ASTNode . types . INPUT : {
138137 const connection = node . getLocation ( ) as Connection ;
139138 rtl = connection . getSourceBlock ( ) . RTL ;
140139
@@ -143,6 +142,7 @@ export class ActionMenu {
143142 // a possible kind of scope.
144143 this . addConnectionItems ( connection , menuOptions ) ;
145144 break ;
145+ }
146146
147147 default :
148148 console . info ( `No action menu for ASTNode of type ${ nodeType } ` ) ;
@@ -177,24 +177,21 @@ export class ActionMenu {
177177 */
178178 private addConnectionItems (
179179 connection : Connection ,
180- menuOptions : (
180+ menuOptions : Array <
181181 | ContextMenuRegistry . ContextMenuOption
182182 | ContextMenuRegistry . LegacyContextMenuOption
183- ) [ ] ,
183+ > ,
184184 ) {
185- const insertAction = ContextMenuRegistry . registry . getItem ( 'insert' ) ;
186- if ( ! insertAction ) throw new Error ( "can't find insert action" ) ;
187-
188- const pasteAction = ContextMenuRegistry . registry . getItem (
189- 'blockPasteFromContextMenu' ,
190- ) ;
191- if ( ! pasteAction ) throw new Error ( "can't find paste action" ) ;
192- const possibleOptions = [ insertAction , pasteAction /* etc.*/ ] ;
185+ const possibleOptions = [
186+ this . getContextMenuAction ( 'insert' ) ,
187+ this . getContextMenuAction ( 'blockPasteFromContextMenu' ) ,
188+ ] ;
193189
194190 // Check preconditions and get menu texts.
195191 const scope = {
196192 connection,
197193 } as unknown as ContextMenuRegistry . Scope ;
194+
198195 for ( const option of possibleOptions ) {
199196 const precondition = option . preconditionFn ?.( scope ) ;
200197 if ( precondition === 'hidden' ) continue ;
@@ -205,14 +202,33 @@ export class ActionMenu {
205202 menuOptions . push ( {
206203 text : displayText ,
207204 enabled : precondition === 'enabled' ,
208- callback : option . callback ! ,
205+ callback : option . callback ,
209206 scope,
210207 weight : option . weight ,
211208 } ) ;
212209 }
213210 return menuOptions ;
214211 }
215212
213+ /**
214+ * Find a context menu action, throwing an `Error` if it is not present or
215+ * not an action. This usefully narrows the type to `ActionRegistryItem`
216+ * which is not exported from Blockly.
217+ *
218+ * @param id The id of the action.
219+ * @returns the action.
220+ */
221+ private getContextMenuAction ( id : string ) {
222+ const item = ContextMenuRegistry . registry . getItem ( id ) ;
223+ if ( ! item ) {
224+ throw new Error ( `can't find context menu item ${ id } ` ) ;
225+ }
226+ if ( ! item ?. callback ) {
227+ throw new Error ( `context menu item unexpectedly not action ${ id } ` ) ;
228+ }
229+ return item ;
230+ }
231+
216232 /**
217233 * Create a fake PointerEvent for opening the action menu for the
218234 * given ASTNode.
0 commit comments