A context menu contains a list of actions you can take related to some element in the workspace. A context menu is shown on right clicks and long presses.
You may want to create a custom context menu option if you want to add a new kind of action the user can perform. For example, organizing all of the blocks in the workspace or downloading an image of the blocks. If you think the action will be used infrequently, the context menu is a great place to put it. Otherwise, you might want to create a more discoverable way to access the action.
Implement a new option
To implement a new context menu option, you need to fulfill the
RegistryItem
interface.
ID
The id
property should be a unique string that indicates what your context
menu option does.
const deleteOption = {
id: 'deleteElement',
};
Scope
The scopeType
property tells Blockly what context the menu option might be
shown in and what information to pass to its displayText
, preconditionFn
,
and callback
. Context menus can be scoped to blocks, workspace comments, and
workspaces.
const deleteOption = {
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
};
If you want your context menu to work in multiple scopes, you should duplicate the context menu option and redefine the scope parameter for each scope.
const otherDeleteOption = {...deleteOption};
otherDeleteOption.scopeType = Blockly.ContextMenuRegistry.ScopeType.COMMENT;
Display text
The displayText
is what should be shown to the user as part of the menu
option. The display text can be a string, or HTML, or a function that returns
either a string or HTML.
const deleteOption = {
displayText: 'Delete block',
};
If you want to display a translation from Blockly.Msg
you need to use a
function. If you try to assign the value directly, the messages may not be
loaded and you'll get a value of undefined
instead.
const deleteOption = {
displayText: () => Blockly.Msg['MY_DELETE_OPTION_TEXT'],
};
If you use a function, it is also passed a Scope
value which gives
you access to the element the context menu is associated with (e.g. the block or
workspace). You can use this to add information about the element to your
display text.
const deleteOption = {
displayText: (scope) => `Delete ${scope.block.type} block`,
}
Weight
The weight
determines the order in which context menu items are displayed.
More positive values are displayed lower in the list than less positive values.
(You can imagine that options with higher weights are "heavier" so they sink to
the bottom.)
const deleteOption = {
weight: 10;
}
Weights for the built-in context menu options go in increasing order starting at 1 and increasing by 1.
Precondition
In addition to the scopeType
, you can use the preconditionFn
to restrict
when and how a context menu option should be displayed.
It should return one of a set of strings: 'enabled'
, 'disabled'
, or
'hidden'
.
Value | Description | Image |
---|---|---|
enabled | Shows that the option is active. | |
disabled | Shows that the option is not active. | |
hidden | Hides the option. |
The preconditionFn
is also passed a Scope
which you can use to determine the
state of your option.
const deleteOption = {
preconditionFn: (scope) => {
if (scope.block.isDeletable()) {
return 'enabled';
}
return 'disabled';
}
}
Callback
The callback
property performs the action of your context menu item. It is
passed a Scope
and a PointerEvent
. The PointerEvent
is the original event
that triggered opening the context menu, not the one that selected an option.
You can use the event to figure out where the click happened. This lets you, for
example, create a new block at the click location.
const deleteOption = {
callback: (scope, e) => {
scope.block.dispose();
}
}
Registration
To use your context menu option, you need to register it. You should do this once on page load. It can happen before or after you inject your workspace.
const deleteOption = { /* implementations from above */ };
Blockly.ContextMenuRegistry.registry.register(deleteOption);
Modify options per-block-type
Blocks have an additional way to modify context menus which is to use overwrite
their customContextMenu
property. This method takes in an
array of ContextMenuOption
objects (which are collated
from the registered menu items) and then modifies that array in-place to
determine the final set of displayed options.
For more information see Define blocks, custom context menus.
Workspaces also have a configureContextMenu
method
which works similarly.
Remove an option
You can remove an option from the context menu by unregistering it by ID.
Blockly.ContextMenuRegistry.registry.unregister('someID');
The IDs for the default options are in contextmenu_items.ts.
Modify an option
You can modify an existing option by getting the item from the registry and then modifying it in-place.
const option = Blockly.ContextMenuRegistry.registry.getItem('someID');
option?.displayText = 'some other display text';