Um menu de contexto contém uma lista de ações que um usuário pode realizar em um componente, como um espaço de trabalho, um bloco ou um comentário do espaço de trabalho. O menu de contexto é mostrado em
resposta a um clique com o botão direito do mouse ou um toque longo em um dispositivo touchscreen. Se você usa o
plug-in @blockly/keyboard-navigation
, ele também
aparece com um atalho de teclado, que é Ctrl+Enter
no Windows ou
Command+Enter
no Mac.
Os menus contextuais são um bom lugar para adicionar ações que o usuário realiza com pouca frequência, como baixar uma captura de tela. Se você acha que uma ação será usada com mais frequência, crie uma maneira mais fácil de invocá-la.
Os menus de contexto são compatíveis com espaços de trabalho, blocos, comentários do espaço de trabalho, balões e conexões. Você também pode implementá-los nos seus próprios componentes personalizados. O Blockly oferece menus de contexto padrão que podem ser personalizados. Também é possível personalizar menus de contexto em espaços de trabalho e blocos por espaço de trabalho ou por bloco.
Como os menus de contexto funcionam
O Blockly tem um registro que contém modelos para todos os itens de menu possíveis. Cada modelo descreve como construir um único item em um menu de contexto. Quando o usuário invoca um menu de contexto em um componente, ele:
Pede ao registro para construir uma matriz de itens de menu que se aplicam ao componente. O registro pergunta a cada modelo se ele se aplica ao componente e, em caso afirmativo, adiciona um item de menu correspondente à matriz.
Se o componente for um espaço de trabalho ou bloco, verifique se o espaço de trabalho ou bloco específico em que o menu foi invocado tem uma função para personalizar o menu de contexto. Se for, ele transmite a matriz para a função, que pode adicionar, excluir ou modificar elementos da matriz.
Mostra o menu de contexto usando a matriz (possivelmente modificada) de itens do menu de contexto.
O Blockly define um conjunto padrão de modelos para os menus de contexto de espaços de trabalho, blocos e comentários do espaço de trabalho. Ele pré-carrega os modelos para espaços de trabalho e blocos no registro. Se quiser usar os modelos para comentários do espaço de trabalho, carregue-os no registro manualmente.
Para informações sobre como adicionar, excluir e modificar modelos no registro, consulte Personalizar o registro.
Escopo
Os menus de contexto são implementados por diferentes tipos de componentes, incluindo espaços de trabalho, comentários do espaço de trabalho, conexões, blocos, balões e seus próprios componentes personalizados. Os menus de contexto para cada um desses tipos de componentes podem conter itens diferentes, e os itens podem se comportar de maneira diferente com base no tipo de componente. Assim, o sistema de menu de contexto precisa saber em qual componente ele foi invocado.
Para resolver isso, o registro usa um objeto Scope
. O componente em que o
menu de contexto foi invocado é armazenado na propriedade focusedNode
como um objeto
que implementa IFocusableNode
. (IFocusableNode
é implementado por todos os componentes em que os usuários podem se concentrar, incluindo aqueles que implementam menus de contexto. Para mais informações, consulte Sistema de
foco.
O objeto Scope
é transmitido para várias funções em um modelo. Em qualquer
função que receba um objeto Scope
, você pode decidir o que fazer com base no tipo
do objeto na propriedade focusedNode
. Por exemplo, você pode verificar se o
componente é um bloco com:
if (scope.focusedNode instanceof Blockly.BlockSvg) {
// do something with the block
}
O objeto Scope
tem outras propriedades opcionais que não são mais recomendadas para uso, mas ainda podem ser definidas:
block
só é definido se o componente cujo menu é mostrado for umBlockSvg
.workspace
só é definido se o componente for umWorkspaceSvg
.comment
só é definido se o componente for umRenderedWorkspaceComment
.
Essas propriedades não abrangem todos os tipos de componentes que podem ter um menu
de contexto. Por isso, prefira usar a propriedade focusedNode
.
O tipo RegistryItem
Os modelos têm o tipo ContextMenuRegistry.RegistryItem
, que contém as seguintes propriedades. As propriedades preconditionFn
, displayText
e callback
são mutuamente exclusivas com a propriedade separator
.
ID
A propriedade id
precisa ser uma string exclusiva que indica o que o item do menu de contexto
faz.
const collapseTemplate = {
id: 'collapseBlock',
// ...
};
Função de pré-condição
Você pode usar o preconditionFn
para restringir quando e como um item de menu de contexto
deve ser exibido.
Ele precisa retornar uma das seguintes strings: 'enabled'
, 'disabled'
ou 'hidden'
.
Valor | Descrição | Imagem |
---|---|---|
'enabled'
|
Mostra que o item está ativo. | ![]() |
'disabled'
|
Mostra que o item não está ativo. | ![]() |
'hidden' |
Oculta o item. |
O preconditionFn
também recebe um Scope
que pode ser usado para
determinar em que tipo de componente o menu foi aberto e o estado desse
componente.
Por exemplo, você pode querer que um item apareça apenas para blocos e somente quando esses blocos estiverem em um estado específico:
const collapseTemplate = {
// ...
preconditionFn: (scope) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
if (!scope.focusedNode.isCollapsed()) {
// The component is a block and it is not already collapsed
return 'enabled';
} else {
// The block is already collapsed
return 'disabled';
}
}
// The component is not a block
return 'hidden';
},
// ...
}
Texto de exibição
O displayText
é o que deve ser mostrado ao usuário como parte do item de menu.
O texto de exibição pode ser uma string, HTML ou uma função que retorna uma string ou HTML.
const collapseTemplate = {
// ...
displayText: 'Collapse block',
// ...
};
Se você quiser mostrar uma tradução do Blockly.Msg
, use uma função. Se você tentar atribuir o valor diretamente, as mensagens poderão não ser
carregadas, e você vai receber um valor de undefined
.
const collapseTemplate = {
// ...
displayText: () => Blockly.Msg['MY_COLLAPSE_BLOCK_TEXT'],
// ...
};
Se você usar uma função, ela também vai receber um valor Scope
. Você pode usar isso para adicionar informações sobre o elemento ao texto de exibição.
const collapseTemplate = {
// ...
displayText: (scope) => {
if (scope.focusedNode instanceof Blockly.Block) {
return `Collapse ${scope.focusedNode.type} block`;
}
// Shouldn't be possible, as our preconditionFn only shows this item for blocks
return '';
},
// ...
}
Peso
O weight
determina a ordem em que os itens do menu de contexto são mostrados.
Valores mais positivos aparecem mais abaixo na lista do que valores menos positivos.
É possível imaginar que itens com pesos maiores são "mais pesados" e, portanto, afundam até o fundo.
const collapseTemplate = {
// ...
weight: 10,
// ...
}
Os pesos dos itens do menu de contexto integrado seguem uma ordem crescente, começando em 1 e aumentando em 1.
Função de callback
A propriedade callback
é uma função que realiza a ação do item do menu de contexto. Ele recebe vários parâmetros:
scope
: um objetoScope
que fornece uma referência ao componente com o menu aberto.menuOpenEvent
: oEvent
que acionou a abertura do menu de contexto. Isso pode ser umPointerEvent
ou umKeyboardEvent
, dependendo de como o usuário abriu o menu.menuSelectEvent
: oEvent
que selecionou este item específico do menu de contexto. Pode ser umPointerEvent
ouKeyboardEvent
, dependendo de como o usuário selecionou o item.location
: oCoordinate
em coordenadas de pixel em que o menu foi aberto. Isso permite, por exemplo, criar um novo bloco no local do clique.
const collapseTemplate = {
// ...
callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
scope.focusedNode.collapse();
}
},
}
É possível usar scope
para criar modelos que funcionam de maneira diferente dependendo do
componente em que foram abertos:
const collapseTemplate = {
// ...
callback: (scope) => {
if (scope.focusedNode instance of Blockly.BlockSvg) {
// On a block, collapse just the block.
const block = scope.focusedNode;
block.collapse();
} else if (scope.focusedNode instanceof Blockly.WorkspaceSvg) {
// On a workspace, collapse all the blocks.
let workspace = scope.focusedNode;
collapseAllBlocks(workspace);
}
}
}
Separador
A propriedade separator
desenha uma linha no menu de contexto.
Modelos com a propriedade separator
não podem ter propriedades preconditionFn
, displayText
ou callback
e só podem ser definidos com a propriedade scopeType
. A última restrição significa que eles só podem ser usados em
menus de contexto para espaços de trabalho, blocos e comentários do espaço de trabalho.
const separatorAfterCollapseBlockTemplate = {
id: 'separatorAfterCollapseBlock',
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
weight: 11, // Between the weights of the two items you want to separate.
separator: true,
};
Você precisa de um modelo diferente para cada separador no menu de contexto. Use a propriedade weight
para posicionar cada separador.
Tipo de escopo
A propriedade scopeType
foi descontinuada. Antes, ele era usado para determinar se um item de menu deveria ser mostrado em um menu de contexto para um bloco, um comentário do espaço de trabalho ou um espaço de trabalho. Como os menus de contexto podem ser abertos em outros componentes, a propriedade scopeType
é muito restritiva. Em vez disso, use o
preconditionFn
para mostrar ou ocultar sua opção nos componentes correspondentes.
Se você tiver modelos de menu de contexto que usam scopeType
, o Blockly
continuará mostrando o item apenas para o componente adequado.
const collapseTemplate = {
// ...
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
// ...
};
Personalizar o registro
É possível adicionar, excluir ou modificar modelos no registro. Os modelos padrão estão em contextmenu_items.ts
.
Adicionar um modelo
É possível adicionar um modelo ao registro ao registrá-lo. Faça isso uma vez no carregamento da página. Isso pode acontecer antes ou depois de você injetar seu espaço de trabalho.
const collapseTemplate = { /* properties from above */ };
Blockly.ContextMenuRegistry.registry.register(collapseTemplate);
Excluir um modelo
É possível remover um modelo do registro cancelando o registro dele por ID.
Blockly.ContextMenuRegistry.registry.unregister('someID');
Modificar um modelo
É possível modificar um modelo atual buscando-o no registro e fazendo as mudanças no local.
const template = Blockly.ContextMenuRegistry.registry.getItem('someID');
template?.displayText = 'some other display text';
Desativar menus de contexto de bloqueio
Por padrão, os blocos têm um menu de contexto que permite aos usuários adicionar comentários ou duplicar blocos.
Para desativar o menu de contexto de um bloco específico, faça o seguinte:
block.contextMenu = false;
Na definição JSON de um tipo de bloco, use a chave enableContextMenu
:
{
// ...,
"enableContextMenu": false,
}
Personalizar menus de contexto por tipo de bloco ou espaço de trabalho
Depois que o Blockly gerar uma matriz de itens do menu de contexto, você poderá personalizar para blocos ou espaços de trabalho individuais. Para fazer isso, defina BlockSvg.customContextMenu
ou
WorkspaceSvg.configureContextMenu
como uma função que
modifica a matriz no lugar.
Os objetos na matriz transmitida para blocos têm o tipo
ContextMenuOption
ou implementam a interface
LegacyContextMenuOption
. Os objetos transmitidos para
espaços de trabalho têm o tipo ContextMenuOption
. O Blockly usa as seguintes propriedades desses objetos:
text
: o texto de exibição.enabled
: sefalse
, mostre o item com texto cinza.callback
: a função a ser chamada quando o item é clicado.separator
: o item é um separador. Mutuamente exclusivo com as outras três propriedades.
Consulte a documentação de referência para tipos de propriedade e assinaturas de função.
Por exemplo, veja uma função que adiciona um item Hello, World!
ao menu de contexto de um
espaço de trabalho:
workspace.configureContextMenu = function (menuOptions, e) {
const item = {
text: 'Hello, World!',
enabled: true,
callback: function () {
alert('Hello, World!');
},
};
// Add the item to the end of the context menu.
menuOptions.push(item);
}
Mostrar um menu de contexto em um objeto personalizado
Para fazer com que os menus de contexto apareçam em componentes personalizados, siga estas etapas:
- Implemente
IFocusableNode
ou estenda uma classe que implementeIFocusableNode
. Essa interface é usada no sistema de menu de contexto para identificar seu componente. Ele também permite que os usuários naveguem até o componente usando o plug-in de navegação por teclado. Implemente
IContextMenu
, que contém a funçãoshowContextMenu
. Essa função recebe os itens do menu de contexto do registro, calcula o local na tela em que o menu será mostrado e, por fim, mostra o menu se houver itens para exibir.const MyBubble implements IFocusableNode, IContextMenu { ... showContextMenu(menuOpenEvent) { // Get the items from the context menu registry const scope = {focusedNode: this}; const items = Blockly.ContextMenuRegistry.registry.getContextMenuOptions(scope, menuOpenEvent); // Return early if there are no items available if (!items.length) return; // Show the menu at the same location on screen as this component // The location is in pixel coordinates, so translate from workspace coordinates const location = Blockly.utils.svgMath.wsToScreenCoordinates(new Coordinate(this.x, this.y)); // Show the context menu Blockly.ContextMenu.show(menuOpenEvent, items, this.workspace.RTL, this.workspace, location); } }
Adicione um manipulador de eventos que chame
showContextMenu
quando o usuário clicar com o botão direito do mouse no componente. O plug-in de navegação por teclado oferece um manipulador de eventos que chamashowContextMenu
quando o usuário pressionaCtrl+Enter
(Windows) ouCommand+Enter
(Mac).Adicione modelos ao registro dos itens do menu de contexto.