Ein Kontextmenü enthält eine Liste von Aktionen, die ein Nutzer für eine Komponente wie einen Arbeitsbereich, einen Block oder einen Arbeitsbereichskommentar ausführen kann. Das Kontextmenü wird als Reaktion auf einen Rechtsklick oder ein langes Drücken auf einem Touchgerät angezeigt. Wenn Sie das @blockly/keyboard-navigation
-Plug-in verwenden, wird es auch mit einer Tastenkombination angezeigt, die standardmäßig Ctrl+Enter
unter Windows oder Command+Enter
unter Mac ist.
Kontextmenüs eignen sich gut, um Aktionen hinzuzufügen, die der Nutzer nur selten ausführt, z. B. das Herunterladen eines Screenshots. Wenn Sie davon ausgehen, dass eine Aktion häufiger verwendet wird, sollten Sie sie leichter aufrufen können.
Kontextmenüs werden von Arbeitsbereichen, Blöcken, Arbeitsbereichskommentaren, Sprechblasen und Verbindungen unterstützt. Sie können sie auch in Ihren eigenen benutzerdefinierten Komponenten implementieren. Blockly bietet Standardkontextmenüs, die Sie anpassen können. Sie können Kontextmenüs in Arbeitsbereichen und Blöcken auch pro Arbeitsbereich oder pro Block anpassen.
Funktionsweise von Kontextmenüs
Blockly hat eine Registrierung, die Vorlagen für alle möglichen Menüelemente enthält. Jede Vorlage beschreibt, wie ein einzelnes Element in einem Kontextmenü erstellt wird. Wenn der Nutzer ein Kontextmenü für eine Komponente aufruft, passiert Folgendes:
Fordert die Registrierung auf, ein Array von Menüelementen zu erstellen, die für die Komponente gelten. Die Registrierung fragt jede Vorlage, ob sie auf die Komponente angewendet werden kann. Wenn ja, wird dem Array ein entsprechendes Menüelement hinzugefügt.
Wenn die Komponente ein Arbeitsbereich oder Block ist, wird geprüft, ob der Arbeitsbereich oder Block, in dem das Menü aufgerufen wurde, eine Funktion zum Anpassen des Kontextmenüs hat. Wenn ja, wird das Array an die Funktion übergeben, die Elemente des Arrays hinzufügen, löschen oder ändern kann.
Zeigt das Kontextmenü mit dem (möglicherweise geänderten) Array von Kontextmenüelementen an.
Blockly definiert einen Standardsatz von Vorlagen für die Kontextmenüs für Arbeitsbereiche, Blöcke und Arbeitsbereichskommentare. Sie lädt die Vorlagen für Arbeitsbereiche und Blöcke in die Registrierung vor. Wenn Sie die Vorlagen für Arbeitsbereichskommentare verwenden möchten, müssen Sie sie selbst in die Registrierung laden.
Informationen zum Hinzufügen, Löschen und Ändern von Vorlagen in der Registrierung finden Sie unter Registrierung anpassen.
Umfang
Kontextmenüs werden von verschiedenen Arten von Komponenten implementiert, darunter Arbeitsbereiche, Arbeitsbereichskommentare, Verbindungen, Blöcke, Sprechblasen und Ihre eigenen benutzerdefinierten Komponenten. Die Kontextmenüs für die einzelnen Komponententypen können unterschiedliche Elemente enthalten und Elemente können sich je nach Komponententyp unterschiedlich verhalten. Daher muss das Kontextmenüsystem wissen, für welche Komponente es aufgerufen wurde.
Dazu verwendet die Registrierung ein Scope
-Objekt. Die Komponente, für die das Kontextmenü aufgerufen wurde, wird in der Eigenschaft focusedNode
als Objekt gespeichert, das IFocusableNode
implementiert. IFocusableNode
wird von allen Komponenten implementiert, auf die sich Nutzer konzentrieren können, einschließlich derer, die Kontextmenüs implementieren. Weitere Informationen finden Sie unter Fokussystem.)
Das Scope
-Objekt wird an mehrere Funktionen in einer Vorlage übergeben. In jeder Funktion, die ein Scope
-Objekt erhält, können Sie anhand des Typs des Objekts in der focusedNode
-Eigenschaft entscheiden, was zu tun ist. Sie können beispielsweise prüfen, ob die Komponente ein Block ist:
if (scope.focusedNode instanceof Blockly.BlockSvg) {
// do something with the block
}
Das Scope
-Objekt hat weitere optionale Eigenschaften, deren Verwendung nicht mehr empfohlen wird, die aber weiterhin festgelegt werden können:
block
wird nur festgelegt, wenn die Komponente, deren Menü angezeigt wird, einBlockSvg
ist.workspace
wird nur festgelegt, wenn die Komponente einWorkspaceSvg
ist.comment
wird nur festgelegt, wenn die Komponente einRenderedWorkspaceComment
ist.
Diese Attribute decken nicht alle Arten von Komponenten ab, die ein Kontextmenü haben können. Verwenden Sie daher vorzugsweise das Attribut focusedNode
.
Der Typ „RegistryItem“
Vorlagen haben den Typ ContextMenuRegistry.RegistryItem
, der die folgenden Attribute enthält. Die Attribute preconditionFn
, displayText
und callback
schließen sich gegenseitig mit dem Attribut separator
aus.
ID
Die Property id
sollte ein eindeutiger String sein, der angibt, was Ihr Kontextmenüelement bewirkt.
const collapseTemplate = {
id: 'collapseBlock',
// ...
};
Voraussetzungsfunktion
Mit preconditionFn
können Sie einschränken, wann und wie ein Kontextmenüelement angezeigt werden soll.
Es sollte einer der folgenden Strings zurückgegeben werden: 'enabled'
, 'disabled'
oder 'hidden'
.
Wert | Beschreibung | Bild |
---|---|---|
'enabled' |
Zeigt an, dass das Element aktiv ist. | ![]() |
'disabled' |
Gibt an, dass das Element nicht aktiv ist. | ![]() |
'hidden' |
Blendet das Element aus. |
An preconditionFn
wird auch ein Scope
übergeben, mit dem Sie ermitteln können, auf welcher Art von Komponente das Menü geöffnet wurde und in welchem Zustand sich diese Komponente befindet.
Sie möchten beispielsweise, dass ein Element nur für Blöcke und nur dann angezeigt wird, wenn sich diese Blöcke in einem bestimmten Zustand befinden:
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';
},
// ...
}
Anzeigetext
displayText
ist das, was dem Nutzer als Teil des Menüelements angezeigt werden sollte.
Der Anzeigetext kann ein String, HTML oder eine Funktion sein, die entweder einen String oder HTML zurückgibt.
const collapseTemplate = {
// ...
displayText: 'Collapse block',
// ...
};
Wenn Sie eine Übersetzung von Blockly.Msg
anzeigen möchten, müssen Sie eine Funktion verwenden. Wenn Sie versuchen, den Wert direkt zuzuweisen, werden die Nachrichten möglicherweise nicht geladen und Sie erhalten stattdessen den Wert undefined
.
const collapseTemplate = {
// ...
displayText: () => Blockly.Msg['MY_COLLAPSE_BLOCK_TEXT'],
// ...
};
Wenn Sie eine Funktion verwenden, wird ihr auch ein Scope
-Wert übergeben. Damit können Sie dem Anzeigetext Informationen zum Element hinzufügen.
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 '';
},
// ...
}
Gewicht
Die weight
bestimmt die Reihenfolge, in der Kontextmenüelemente angezeigt werden.
Positivere Werte werden in der Liste weiter unten angezeigt als weniger positive Werte.
Sie können sich vorstellen, dass Elemente mit höheren Gewichten „schwerer“ sind und daher nach unten sinken.
const collapseTemplate = {
// ...
weight: 10,
// ...
}
Die Gewichte für die integrierten Kontextmenüelemente werden in aufsteigender Reihenfolge ab 1 und jeweils um 1 erhöht.
Callback-Funktion
Die callback
-Eigenschaft ist eine Funktion, die die Aktion des Kontextmenüelements ausführt. Es werden mehrere Parameter übergeben:
scope
: EinScope
-Objekt, das einen Verweis auf die Komponente enthält, deren Menü geöffnet ist.menuOpenEvent
: DasEvent
, das das Öffnen des Kontextmenüs ausgelöst hat. Das kann einPointerEvent
oderKeyboardEvent
sein, je nachdem, wie der Nutzer das Menü geöffnet hat.menuSelectEvent
: DieEvent
, mit der dieses bestimmte Kontextmenüelement im Menü ausgewählt wurde. Dies kann einPointerEvent
oder einKeyboardEvent
sein, je nachdem, wie der Nutzer das Element ausgewählt hat.location
: DieCoordinate
in Pixelkoordinaten, in der das Menü geöffnet wurde. So können Sie beispielsweise einen neuen Block an der Klickposition erstellen.
const collapseTemplate = {
// ...
callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
scope.focusedNode.collapse();
}
},
}
Mit scope
können Sie Vorlagen entwerfen, die je nach Komponente, in der sie geöffnet wurden, unterschiedlich funktionieren:
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);
}
}
}
Trennzeichen
Mit der Property separator
wird eine Linie im Kontextmenü gezeichnet.
Vorlagen mit dem Attribut separator
dürfen nicht die Attribute preconditionFn
, displayText
oder callback
haben und können nur mit dem Attribut scopeType
eingegrenzt werden. Aufgrund dieser Einschränkung können sie nur in Kontextmenüs für Arbeitsbereiche, Blöcke und Arbeitsbereichskommentare verwendet werden.
const separatorAfterCollapseBlockTemplate = {
id: 'separatorAfterCollapseBlock',
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
weight: 11, // Between the weights of the two items you want to separate.
separator: true,
};
Für jedes Trennzeichen im Kontextmenü benötigen Sie eine andere Vorlage. Verwenden Sie das Attribut weight
, um die einzelnen Trennzeichen zu positionieren.
Bereichstyp
Das Attribut „scopeType
“ wird nicht mehr unterstützt. Bisher wurde damit bestimmt, ob ein Menüelement in einem Kontextmenü für einen Block, einen Arbeitsbereichskommentar oder einen Arbeitsbereich angezeigt werden soll. Da Kontextmenüs für andere Komponenten geöffnet werden können, ist das Attribut scopeType
zu restriktiv. Verwenden Sie stattdessen preconditionFn
, um die Option für die entsprechenden Komponenten ein- oder auszublenden.
Wenn Sie vorhandene Kontextmenüvorlagen haben, in denen scopeType
verwendet wird, wird das Element in Blockly weiterhin nur für die entsprechende Komponente angezeigt.
const collapseTemplate = {
// ...
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
// ...
};
Registry anpassen
Sie können Vorlagen in der Registrierung hinzufügen, löschen oder ändern. Die Standardvorlagen finden Sie unter contextmenu_items.ts
.
Vorlage hinzufügen
Sie können der Registry eine Vorlage hinzufügen, indem Sie sie registrieren. Dies sollte einmal beim Laden der Seite erfolgen. Das kann vor oder nach dem Einfügen des Arbeitsbereichs passieren.
const collapseTemplate = { /* properties from above */ };
Blockly.ContextMenuRegistry.registry.register(collapseTemplate);
Vorlage löschen
Sie können eine Vorlage aus der Registrierung entfernen, indem Sie die Registrierung anhand der ID aufheben.
Blockly.ContextMenuRegistry.registry.unregister('someID');
Vorlage ändern
Sie können eine vorhandene Vorlage ändern, indem Sie sie aus der Registry abrufen und dann direkt bearbeiten.
const template = Blockly.ContextMenuRegistry.registry.getItem('someID');
template?.displayText = 'some other display text';
Kontextmenüs für Blöcke deaktivieren
Standardmäßig haben Blöcke ein Kontextmenü, in dem Nutzer beispielsweise Blockkommentare hinzufügen oder Blöcke duplizieren können.
Sie können das Kontextmenü eines einzelnen Blocks so deaktivieren:
block.contextMenu = false;
Verwenden Sie in der JSON-Definition eines Blocktyps den Schlüssel enableContextMenu
:
{
// ...,
"enableContextMenu": false,
}
Kontextmenüs nach Blocktyp oder Arbeitsbereich anpassen
Nachdem Blockly ein Array von Kontextmenüelementen generiert hat, können Sie es für einzelne Blöcke oder Arbeitsbereiche anpassen. Setzen Sie dazu BlockSvg.customContextMenu
oder WorkspaceSvg.configureContextMenu
auf eine Funktion, die das Array direkt ändert.
Objekte im Array, das an Blöcke übergeben wird, haben den Typ ContextMenuOption
oder implementieren die Schnittstelle LegacyContextMenuOption
. Objekte, die an Arbeitsbereiche übergeben werden, haben den Typ ContextMenuOption
. Blockly verwendet die folgenden Eigenschaften dieser Objekte:
text
: Der Anzeigetext.enabled
: Wennfalse
, wird das Element mit grauem Text angezeigt.callback
: Die Funktion, die aufgerufen werden soll, wenn auf das Element geklickt wird.separator
: Das Element ist ein Trennzeichen. Schließt sich mit den anderen drei Attributen gegenseitig aus.
Referenzdokumentation zu Property-Typen und Funktionssignaturen
Hier ist beispielsweise eine Funktion, die dem Kontextmenü eines Arbeitsbereichs ein Hello, World!
-Element hinzufügt:
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);
}
Kontextmenü für ein benutzerdefiniertes Objekt anzeigen
So lassen Sie Kontextmenüs für benutzerdefinierte Komponenten einblenden:
- Implementieren Sie
IFocusableNode
oder erweitern Sie eine Klasse, dieIFocusableNode
implementiert. Diese Schnittstelle wird im Kontextmenüsystem verwendet, um Ihre Komponente zu identifizieren. Außerdem können Nutzer mit dem Tastaturnavigations-Plug-in zu Ihrer Komponente navigieren. Implementieren Sie
IContextMenu
, das die FunktionshowContextMenu
enthält. Diese Funktion ruft die Kontextmenüelemente aus der Registrierung ab, berechnet die Position auf dem Bildschirm, an der das Menü angezeigt werden soll, und zeigt das Menü schließlich an, wenn Elemente angezeigt werden sollen.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); } }
Fügen Sie einen Event-Handler hinzu, der
showContextMenu
aufruft, wenn der Nutzer mit der rechten Maustaste auf Ihre Komponente klickt. Das Tastaturnavigations-Plug-in bietet einen Ereignishandler, dershowContextMenu
aufruft, wenn der NutzerCtrl+Enter
(Windows) oderCommand+Enter
(Mac) drückt.Fügen Sie der Registry Vorlagen für Ihre Kontextmenüelemente hinzu.