Un menu contextuel contient une liste d'actions qu'un utilisateur peut effectuer sur un composant, tel qu'un espace de travail, un bloc ou un commentaire d'espace de travail. Le menu contextuel s'affiche en réponse à un clic droit ou à un appui prolongé sur un appareil tactile. Si vous utilisez le plug-in @blockly/keyboard-navigation
, il est également affiché avec un raccourci clavier, qui est défini par défaut sur Ctrl+Enter
sous Windows ou Command+Enter
sous Mac.
Les menus contextuels sont un bon endroit pour ajouter des actions que l'utilisateur effectue rarement, comme le téléchargement d'une capture d'écran. Si vous pensez qu'une action sera utilisée plus fréquemment, vous pouvez créer un moyen plus facile à découvrir pour l'invoquer.
Les menus contextuels sont compatibles avec les espaces de travail, les blocs, les commentaires d'espace de travail, les bulles et les connexions. Vous pouvez également les implémenter sur vos propres composants personnalisés. Blockly fournit des menus contextuels standards que vous pouvez personnaliser. Vous pouvez également personnaliser les menus contextuels des espaces de travail et des blocs, individuellement pour chaque espace de travail ou chaque bloc.
Fonctionnement des menus contextuels
Blockly dispose d'un registre contenant des modèles pour tous les éléments de menu possibles. Chaque modèle décrit comment construire un seul élément dans un menu contextuel. Lorsque l'utilisateur appelle un menu contextuel sur un composant, le composant :
Demande au registre de construire un tableau d'éléments de menu qui s'appliquent au composant. Le registre demande à chaque modèle s'il s'applique au composant et, le cas échéant, ajoute un élément de menu correspondant au tableau.
Si le composant est un espace de travail ou un bloc, vérifie si l'espace de travail ou le bloc spécifique sur lequel le menu a été appelé dispose d'une fonction de personnalisation du menu contextuel. Si c'est le cas, il transmet le tableau à la fonction, qui peut ajouter, supprimer ou modifier des éléments du tableau.
Affiche le menu contextuel à l'aide du tableau (éventuellement modifié) des éléments du menu contextuel.
Blockly définit un ensemble standard de modèles pour les menus contextuels des espaces de travail, des blocs et des commentaires d'espace de travail. Il précharge les modèles pour les espaces de travail et les blocs dans le registre. Si vous souhaitez utiliser les modèles pour les commentaires dans l'espace de travail, vous devez les charger vous-même dans le registre.
Pour savoir comment ajouter, supprimer et modifier des modèles dans le registre, consultez Personnaliser le registre.
Champ d'application
Les menus contextuels sont implémentés par différents types de composants, y compris les espaces de travail, les commentaires d'espace de travail, les connexions, les blocs, les bulles et vos propres composants personnalisés. Les menus contextuels de chacun de ces types de composants peuvent contenir différents éléments, et les éléments peuvent se comporter différemment selon le type de composant. Le système de menu contextuel doit donc savoir sur quel composant il a été appelé.
Pour résoudre ce problème, le registre utilise un objet Scope
. Le composant sur lequel le menu contextuel a été appelé est stocké dans la propriété focusedNode
en tant qu'objet qui implémente IFocusableNode
. (IFocusableNode
est implémenté par tous les composants sur lesquels les utilisateurs peuvent se concentrer, y compris ceux qui implémentent des menus contextuels. Pour en savoir plus, consultez Système de focus.)
L'objet Scope
est transmis à plusieurs fonctions d'un modèle. Dans n'importe quelle fonction qui obtient un objet Scope
, vous pouvez décider quoi faire en fonction du type d'objet dans la propriété focusedNode
. Par exemple, vous pouvez vérifier si le composant est un bloc avec :
if (scope.focusedNode instanceof Blockly.BlockSvg) {
// do something with the block
}
L'objet Scope
possède d'autres propriétés facultatives dont l'utilisation n'est plus recommandée, mais qui peuvent toujours être définies :
block
n'est défini que si le composant dont le menu est affiché est unBlockSvg
.workspace
n'est défini que si le composant est unWorkspaceSvg
.comment
n'est défini que si le composant est unRenderedWorkspaceComment
.
Ces propriétés ne couvrent pas tous les types de composants pouvant comporter un menu contextuel. Il est donc préférable d'utiliser la propriété focusedNode
.
Type RegistryItem
Les modèles sont de type ContextMenuRegistry.RegistryItem
et contiennent les propriétés suivantes. Notez que les propriétés preconditionFn
, displayText
et callback
s'excluent mutuellement avec la propriété separator
.
ID
La propriété id
doit être une chaîne unique qui indique ce que fait votre élément de menu contextuel.
const collapseTemplate = {
id: 'collapseBlock',
// ...
};
Fonction de préconditionnement
Vous pouvez utiliser preconditionFn
pour limiter le moment et la manière dont un élément de menu contextuel doit être affiché.
Il doit renvoyer l'une des chaînes suivantes : 'enabled'
, 'disabled'
ou 'hidden'
.
Valeur | Description | Image |
---|---|---|
'enabled'
|
Indique que l'élément est actif. | ![]() |
'disabled'
|
Indique que l'élément n'est pas actif. | ![]() |
'hidden' |
Masque l'élément. |
preconditionFn
reçoit également un Scope
que vous pouvez utiliser pour déterminer le type de composant sur lequel le menu a été ouvert et l'état de ce composant.
Par exemple, vous pouvez souhaiter qu'un élément n'apparaisse que pour les blocs et uniquement lorsque ces blocs sont dans un état particulier :
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';
},
// ...
}
Texte à afficher
displayText
est ce qui doit être affiché à l'utilisateur dans l'élément de menu.
Le texte à afficher peut être une chaîne, du code HTML ou une fonction qui renvoie une chaîne ou du code HTML.
const collapseTemplate = {
// ...
displayText: 'Collapse block',
// ...
};
Si vous souhaitez afficher une traduction à partir de Blockly.Msg
, vous devez utiliser une fonction. Si vous essayez d'attribuer la valeur directement, il est possible que les messages ne soient pas chargés et que vous obteniez une valeur de undefined
à la place.
const collapseTemplate = {
// ...
displayText: () => Blockly.Msg['MY_COLLAPSE_BLOCK_TEXT'],
// ...
};
Si vous utilisez une fonction, une valeur Scope
lui est également transmise. Vous pouvez l'utiliser pour ajouter des informations sur l'élément à votre texte à afficher.
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 '';
},
// ...
}
Poids
weight
détermine l'ordre dans lequel les éléments du menu contextuel sont affichés.
Les valeurs les plus positives sont affichées plus bas dans la liste que les valeurs moins positives.
(Vous pouvez imaginer que les éléments avec des pondérations plus élevées sont "plus lourds" et qu'ils coulent au fond.)
const collapseTemplate = {
// ...
weight: 10,
// ...
}
Les pondérations des éléments de menu contextuel intégrés sont classées par ordre croissant, en commençant par 1 et en augmentant de 1.
Fonction de rappel
La propriété callback
est une fonction qui exécute l'action de votre élément de menu contextuel. Plusieurs paramètres lui sont transmis :
scope
: objetScope
qui fournit une référence au composant dont le menu est ouvert.menuOpenEvent
:Event
qui a déclenché l'ouverture du menu contextuel. Il peut s'agir d'unPointerEvent
ou d'unKeyboardEvent
, selon la façon dont l'utilisateur a ouvert le menu.menuSelectEvent
:Event
qui a sélectionné cet élément de menu contextuel spécifique dans le menu. Il peut s'agir d'unPointerEvent
ou d'unKeyboardEvent
, selon la façon dont l'utilisateur a sélectionné l'élément.location
:Coordinate
dans les coordonnées en pixels où le menu a été ouvert. Cela vous permet, par exemple, de créer un bloc à l'emplacement du clic.
const collapseTemplate = {
// ...
callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
scope.focusedNode.collapse();
}
},
}
Vous pouvez utiliser scope
pour concevoir des modèles qui fonctionnent différemment selon le composant dans lequel ils ont été ouverts :
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);
}
}
}
Séparateur
La propriété separator
dessine une ligne dans le menu contextuel.
Les modèles avec la propriété separator
ne peuvent pas avoir de propriétés preconditionFn
, displayText
ou callback
, et ne peuvent être définis que par la propriété scopeType
. Cette dernière restriction signifie qu'ils ne peuvent être utilisés que dans les menus contextuels des espaces de travail, des blocs et des commentaires d'espace de travail.
const separatorAfterCollapseBlockTemplate = {
id: 'separatorAfterCollapseBlock',
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
weight: 11, // Between the weights of the two items you want to separate.
separator: true,
};
Vous avez besoin d'un modèle différent pour chaque séparateur de votre menu contextuel. Utilisez la propriété weight
pour positionner chaque séparateur.
Type de champ d'application
La propriété scopeType
est obsolète. Auparavant, il était utilisé pour déterminer si un élément de menu devait être affiché dans un menu contextuel pour un bloc, un commentaire d'espace de travail ou un espace de travail. Étant donné que les menus contextuels peuvent être ouverts sur d'autres composants, la propriété scopeType
est trop restrictive. Vous devez plutôt utiliser preconditionFn
pour afficher ou masquer votre option pour les composants correspondants.
Si vous disposez de modèles de menu contextuel existants qui utilisent scopeType
, Blockly continuera à afficher l'élément uniquement pour le composant approprié.
const collapseTemplate = {
// ...
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
// ...
};
Personnaliser le registre
Vous pouvez ajouter, supprimer ou modifier des modèles dans le registre. Vous trouverez les modèles par défaut dans contextmenu_items.ts
.
Ajouter un modèle
Vous pouvez ajouter un modèle au registre en l'enregistrant. Vous devez le faire une seule fois au chargement de la page. Cela peut se produire avant ou après l'injection de votre espace de travail.
const collapseTemplate = { /* properties from above */ };
Blockly.ContextMenuRegistry.registry.register(collapseTemplate);
Supprimer un modèle
Vous pouvez supprimer un modèle du registre en le désenregistrant par ID.
Blockly.ContextMenuRegistry.registry.unregister('someID');
Modifier un modèle
Vous pouvez modifier un modèle existant en l'obtenant à partir du registre, puis en le modifiant sur place.
const template = Blockly.ContextMenuRegistry.registry.getItem('someID');
template?.displayText = 'some other display text';
Désactiver les menus contextuels de bloc
Par défaut, les blocs disposent d'un menu contextuel qui permet aux utilisateurs d'ajouter des commentaires ou de dupliquer des blocs, par exemple.
Vous pouvez désactiver le menu contextuel d'un bloc individuel en procédant comme suit :
block.contextMenu = false;
Dans la définition JSON d'un type de bloc, utilisez la clé enableContextMenu
:
{
// ...,
"enableContextMenu": false,
}
Personnaliser les menus contextuels par type de bloc ou par espace de travail
Une fois que Blockly a généré un tableau d'éléments de menu contextuel, vous pouvez le personnaliser pour des blocs ou des espaces de travail individuels. Pour ce faire, définissez BlockSvg.customContextMenu
ou WorkspaceSvg.configureContextMenu
sur une fonction qui modifie le tableau sur place.
Les objets du tableau transmis aux blocs sont de type ContextMenuOption
ou implémentent l'interface LegacyContextMenuOption
. Les objets transmis aux espaces de travail sont de type ContextMenuOption
. Blockly utilise les propriétés suivantes de ces objets :
text
: texte à afficher.enabled
: si la valeur estfalse
, affichez l'élément avec du texte gris.callback
: fonction à appeler lorsque l'utilisateur clique sur l'élément.separator
: l'élément est un séparateur. S'exclut mutuellement avec les trois autres propriétés.
Consultez la documentation de référence pour les types de propriétés et les signatures de fonctions.
Par exemple, voici une fonction qui ajoute un élément Hello, World!
au menu contextuel d'un espace de travail :
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);
}
Afficher un menu contextuel sur un objet personnalisé
Pour afficher des menus contextuels pour les composants personnalisés, procédez comme suit :
- Implémentez
IFocusableNode
ou étendez une classe qui implémenteIFocusableNode
. Cette interface est utilisée dans le système de menu contextuel pour identifier votre composant. Il permet également aux utilisateurs d'accéder à votre composant à l'aide du plug-in de navigation au clavier. Implémentez
IContextMenu
, qui contient la fonctionshowContextMenu
. Cette fonction récupère les éléments du menu contextuel à partir du registre, calcule l'emplacement à l'écran où afficher le menu et, enfin, affiche le menu s'il y a des éléments à afficher.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); } }
Ajoutez un gestionnaire d'événements qui appelle
showContextMenu
lorsque l'utilisateur effectue un clic droit sur votre composant. Notez que le plug-in de navigation au clavier fournit un gestionnaire d'événements qui appelleshowContextMenu
lorsque l'utilisateur appuie surCtrl+Enter
(Windows) ouCommand+Enter
(Mac).Ajoutez des modèles au registre pour les éléments de votre menu contextuel.