Menu kontekstowe zawiera listę działań, które użytkownik może wykonać na komponencie, takim jak obszar roboczy, blok lub komentarz do obszaru roboczego. Menu kontekstowe jest wyświetlane w odpowiedzi na kliknięcie prawym przyciskiem myszy lub przytrzymanie na urządzeniu dotykowym. Jeśli używasz @blockly/keyboard-navigation
wtyczki, jest ona również wyświetlana ze skrótem klawiszowym, który domyślnie to Ctrl+Enter
w systemie Windows lub Command+Enter
na komputerze Mac.
Menu kontekstowe to dobre miejsce na dodanie działań, które użytkownik wykonuje rzadko, np. pobieranie zrzutu ekranu. Jeśli uważasz, że akcja będzie częściej używana, możesz utworzyć łatwiejszy sposób jej wywoływania.
Menu kontekstowe są obsługiwane przez obszary robocze, bloki, komentarze do obszaru roboczego, dymki i połączenia. Możesz też wdrożyć je we własnych komponentach niestandardowych. Blockly udostępnia standardowe menu kontekstowe, które możesz dostosować. Możesz też dostosowywać menu kontekstowe w obszarach roboczych i blokach w przypadku poszczególnych obszarów roboczych lub bloków.
Jak działają menu kontekstowe
Blockly ma rejestr, który zawiera szablony wszystkich możliwych elementów menu. Każdy szablon opisuje, jak utworzyć pojedynczy element w menu kontekstowym. Gdy użytkownik wywoła menu kontekstowe komponentu, komponent:
Prosi rejestr o utworzenie tablicy pozycji menu, które mają zastosowanie do komponentu. Rejestr pyta każdy szablon, czy ma zastosowanie do komponentu, a jeśli tak, dodaje odpowiednią pozycję menu do tablicy.
Jeśli komponentem jest obszar roboczy lub blok, sprawdza, czy dany obszar roboczy lub blok, w którym wywołano menu, ma funkcję dostosowywania menu kontekstowego. Jeśli tak, przekazuje tablicę do funkcji, która może dodawać, usuwać lub modyfikować elementy tablicy.
Wyświetla menu kontekstowe przy użyciu (prawdopodobnie zmodyfikowanej) tablicy elementów menu kontekstowego.
Blockly definiuje standardowy zestaw szablonów menu kontekstowych obszarów roboczych, bloków i komentarzy do obszaru roboczego. Wstępnie wczytuje szablony obszarów roboczych i bloków do rejestru. Jeśli chcesz używać szablonów do komentarzy w obszarze roboczym, musisz samodzielnie załadować je do rejestru.
Informacje o tym, jak dodawać, usuwać i modyfikować szablony w rejestrze, znajdziesz w artykule Dostosowywanie rejestru.
Zakres
Menu kontekstowe są implementowane przez różne typy komponentów, w tym obszary robocze, komentarze do obszarów roboczych, połączenia, bloki, dymki i własne komponenty niestandardowe. Menu kontekstowe poszczególnych typów komponentów mogą zawierać różne elementy, a elementy mogą zachowywać się inaczej w zależności od typu komponentu. Dlatego system menu kontekstowego musi wiedzieć, na którym komponencie zostało ono wywołane.
W tym celu rejestr używa obiektu Scope
. Komponent, w którym wywołano menu kontekstowe, jest przechowywany we właściwości focusedNode
jako obiekt implementujący interfejs IFocusableNode
. (IFocusableNode
jest implementowany przez wszystkie komponenty, na których użytkownicy mogą się skupić, w tym te, które implementują menu kontekstowe).
Obiekt Scope
jest przekazywany do kilku funkcji w szablonie. W dowolnej funkcji, która otrzymuje obiekt Scope
, możesz zdecydować, co zrobić na podstawie typu obiektu we właściwości focusedNode
. Możesz na przykład sprawdzić, czy komponent jest blokiem, za pomocą tego kodu:
if (scope.focusedNode instanceof Blockly.BlockSvg) {
// do something with the block
}
Obiekt Scope
ma inne właściwości opcjonalne, których nie zalecamy już używać, ale nadal można je ustawić:
block
jest ustawiony tylko wtedy, gdy komponent, którego menu jest wyświetlane, jest elementemBlockSvg
.workspace
jest ustawiony tylko wtedy, gdy komponent jest elementemWorkspaceSvg
.comment
jest ustawiony tylko wtedy, gdy komponent jest elementemRenderedWorkspaceComment
.
Te właściwości nie obejmują wszystkich typów komponentów, które mogą mieć menu kontekstowe, dlatego lepiej używać właściwości focusedNode
.
Typ RegistryItem
Szablony mają typ ContextMenuRegistry.RegistryItem
, który zawiera te właściwości: Właściwości preconditionFn
, displayText
i callback
wykluczają się wzajemnie z właściwością separator
.
Identyfikator
Właściwość id
powinna być unikalnym ciągiem znaków, który wskazuje, co robi element menu kontekstowego.
const collapseTemplate = {
id: 'collapseBlock',
// ...
};
Funkcja warunku wstępnego
Za pomocą właściwości preconditionFn
możesz ograniczyć, kiedy i w jaki sposób ma być wyświetlana pozycja menu kontekstowego.
Powinna zwracać jeden z tych ciągów znaków: 'enabled'
, 'disabled'
lub 'hidden'
.
Wartość | Opis | Obraz |
---|---|---|
włączone | Wskazuje, że element jest aktywny. | ![]() |
wyłączono | Wskazuje, że produkt jest nieaktywny. | ![]() |
ukryta | Ukrywa element. |
Do funkcji preconditionFn
przekazywany jest też obiekt Scope
, którego możesz użyć do określenia typu komponentu, w którym zostało otwarte menu, oraz stanu tego komponentu.
Możesz na przykład chcieć, aby element pojawiał się tylko w przypadku bloków i tylko wtedy, gdy te bloki są w określonym stanie:
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';
},
// ...
}
Tekst wyświetlany
Znak displayText
powinien być wyświetlany użytkownikowi jako część pozycji menu.
Tekst wyświetlany może być ciągiem znaków, kodem HTML lub funkcją, która zwraca ciąg znaków lub kod HTML.
const collapseTemplate = {
// ...
displayText: 'Collapse block',
// ...
};
Jeśli chcesz wyświetlić tłumaczenie z Blockly.Msg
, musisz użyć funkcji. Jeśli spróbujesz przypisać wartość bezpośrednio, wiadomości mogą się nie załadować i zamiast nich otrzymasz wartość undefined
.
const collapseTemplate = {
// ...
displayText: () => Blockly.Msg['MY_COLLAPSE_BLOCK_TEXT'],
// ...
};
Jeśli używasz funkcji, przekazywana jest do niej również wartość Scope
. Możesz użyć tego parametru, aby dodać do tekstu wyświetlanego informacje o elemencie.
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 '';
},
// ...
}
Waga
weight
określa kolejność wyświetlania elementów menu kontekstowego.
Bardziej pozytywne wartości są wyświetlane niżej na liście niż mniej pozytywne.
(Możesz sobie wyobrazić, że elementy o większej wadze są „cięższe”, więc opadają na dno).
const collapseTemplate = {
// ...
weight: 10,
// ...
}
Wagi wbudowanych elementów menu kontekstowego są podawane w kolejności rosnącej, zaczynając od 1 i zwiększając się o 1.
Wywołanie zwrotne
Właściwość callback
to funkcja, która wykonuje działanie elementu menu kontekstowego. Przekazywanych jest do niej kilka parametrów:
scope
: obiektScope
, który zawiera odniesienie do komponentu, którego menu jest otwarte.menuOpenEvent
:Event
, który spowodował otwarcie menu kontekstowego. Może to byćPointerEvent
lubKeyboardEvent
, w zależności od tego, jak użytkownik otworzył menu.menuSelectEvent
:Event
, który wybrał ten konkretny element menu kontekstowego. Może to być ikonaPointerEvent
lubKeyboardEvent
, w zależności od tego, jak użytkownik wybrał produkt.location
:Coordinate
w współrzędnych pikseli, w których otwarto menu. Dzięki temu możesz na przykład utworzyć nowy blok w miejscu kliknięcia.
const collapseTemplate = {
// ...
callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
scope.focusedNode.collapse();
}
},
}
Za pomocą symbolu scope
możesz projektować szablony, które działają inaczej w zależności od komponentu, w którym zostały otwarte:
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);
}
}
}
Separator
Właściwość separator
rysuje linię w menu kontekstowym.
Szablony z właściwością separator
nie mogą mieć właściwości preconditionFn
, displayText
ani callback
i mogą być ograniczone tylko za pomocą właściwości scopeType
. To drugie ograniczenie oznacza, że można ich używać tylko w menu kontekstowych obszarów roboczych, bloków i komentarzy do obszarów roboczych.
const separatorAfterCollapseBlockTemplate = {
id: 'separatorAfterCollapseBlock',
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
weight: 11, // Between the weights of the two items you want to separate.
separator: true,
};
Dla każdego separatora w menu kontekstowym potrzebujesz innego szablonu. Użyj właściwości weight
, aby umieścić każdy separator.
Typ zakresu
Właściwość scopeType
została wycofana. Wcześniej służyło do określania, czy element menu powinien być wyświetlany w menu kontekstowym bloku, komentarza w obszarze roboczym lub obszaru roboczego. Menu kontekstowe można otwierać w innych komponentach, więc właściwość scopeType
jest zbyt restrykcyjna. Zamiast tego użyj elementu preconditionFn
, aby wyświetlić lub ukryć opcję dla odpowiednich komponentów.
Jeśli masz szablony menu kontekstowego, które używają scopeType
, Blockly będzie nadal wyświetlać element tylko w odpowiednim komponencie.
const collapseTemplate = {
// ...
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
// ...
};
Dostosowywanie rejestru
W rejestrze możesz dodawać, usuwać i modyfikować szablony. Domyślne szablony znajdziesz w regionie contextmenu_items.ts
.
Dodawanie szablonu
Możesz dodać szablon do rejestru, rejestrując go. Należy to zrobić raz podczas wczytywania strony. Może to nastąpić przed wstrzyknięciem obszaru roboczego lub po nim.
const collapseTemplate = { /* properties from above */ };
Blockly.ContextMenuRegistry.registry.register(collapseTemplate);
Usuwanie szablonu
Możesz usunąć szablon z rejestru, wyrejestrowując go według identyfikatora.
Blockly.ContextMenuRegistry.registry.unregister('someID');
Modyfikowanie szablonu
Możesz zmodyfikować istniejący szablon, pobierając go z rejestru, a następnie wprowadzając zmiany w miejscu jego przechowywania.
const template = Blockly.ContextMenuRegistry.registry.getItem('someID');
template?.displayText = 'some other display text';
Wyłącz blokowanie menu kontekstowych
Domyślnie bloki mają menu kontekstowe, które umożliwia użytkownikom wykonywanie takich czynności jak dodawanie komentarzy do bloków czy ich duplikowanie.
Aby wyłączyć menu kontekstowe poszczególnych bloków:
block.contextMenu = false;
W definicji JSON typu bloku użyj klucza enableContextMenu
:
{
// ...,
"enableContextMenu": false,
}
Dostosowywanie menu kontekstowych według typu bloku lub obszaru roboczego
Gdy Blockly wygeneruje tablicę elementów menu kontekstowego, możesz ją dostosować do poszczególnych bloków lub obszarów roboczych. Aby to zrobić, ustaw BlockSvg.customContextMenu
lub WorkspaceSvg.configureContextMenu
na funkcję, która modyfikuje tablicę w miejscu.
Obiekty w tablicy przekazywanej do bloków mają typ ContextMenuOption
lub implementują interfejs LegacyContextMenuOption
. Obiekty przekazywane do obszarów roboczych mają typ ContextMenuOption
. Blockly używa tych właściwości z tych obiektów:
text
: tekst wyświetlany.enabled
: Jeślifalse
, wyświetl element z szarym tekstem.callback
: funkcja, która ma zostać wywołana po kliknięciu elementu.separator
: element jest separatorem. Wzajemnie wykluczające się z pozostałymi 3 właściwościami.
Informacje o typach właściwości i sygnaturach funkcji znajdziesz w dokumentacji.
Oto na przykład funkcja, która dodaje element Hello, World!
do menu kontekstowego obszaru roboczego:
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);
}
Wyświetlanie menu kontekstowego w przypadku obiektu niestandardowego
Aby menu kontekstowe pojawiało się w przypadku komponentów niestandardowych, wykonaj te czynności:
- Wdróż
IFocusableNode
. Ten interfejs jest używany w systemie menu kontekstowego do identyfikowania komponentu. Umożliwia też użytkownikom przechodzenie do komponentu za pomocą wtyczki do nawigacji klawiaturą. Zaimplementuj
IContextMenu
, który zawiera funkcjęshowContextMenu
. Ta funkcja pobiera elementy menu kontekstowego z rejestru, oblicza miejsce na ekranie, w którym ma się wyświetlić menu, i w końcu wyświetla menu, jeśli są w nim jakieś elementy.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); } }
Dodaj procedurę obsługi zdarzeń, która wywołuje funkcję
showContextMenu
, gdy użytkownik kliknie komponent prawym przyciskiem myszy. Pamiętaj, że wtyczka do nawigacji za pomocą klawiatury udostępnia procedurę obsługi zdarzeń, która wywołuje funkcjęshowContextMenu
, gdy użytkownik naciśnie klawiszCtrl+Enter
(Windows) lubCommand+Enter
(Mac).Dodaj szablony do rejestru dla elementów menu kontekstowego.