Skip to content

Commit b7269dd

Browse files
committed
chore(docs): add guides and codelabs
1 parent 6bdfac5 commit b7269dd

296 files changed

Lines changed: 69491 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
slug: /codelabs/context-menu-option/add-a-context-menu-item/index.html
3+
description: How to add a context menu item to the registry.
4+
---
5+
6+
import ClassBlock from '@site/src/components/ClassBlock';
7+
8+
# Customizing context menus
9+
10+
## 3. Add a context menu item
11+
12+
In this section you will create a very basic `Blockly.ContextMenuRegistry.RegistryItem`, then register it to display when you open a context menu on the workspace, a block, or a comment.
13+
14+
### The RegistryItem
15+
16+
A context menu consists of one or more menu options that a user can select. Blockly stores information about menu option as items in a registry. You can think of the _registry items_ as templates for constructing _menu options_. When the user opens a context menu, Blockly retrieves all of the registry items that apply to the current context and uses them to construct a list of menu options.
17+
18+
Each item in the registry has several properties:
19+
20+
- `displayText`: The text to show in the menu. Either a string, or HTML, or a function that returns either of the former.
21+
- `preconditionFn`: Function that returns one of `'enabled'`, `'disabled'`, or `'hidden'` to determine whether and how the menu option should be rendered.
22+
- `callback`: A function called when the menu option is selected.
23+
- `id`: A unique string id for the item.
24+
- `weight`: A number that determines the sort order of the option. Options with higher weights appear later in the context menu.
25+
26+
We will discuss these in detail in later sections of the codelab.
27+
28+
### Make a RegistryItem
29+
30+
Add a function to `index.js` named `registerHelloWorldItem`. Create a new registry item in your function:
31+
32+
```js
33+
function registerHelloWorldItem() {
34+
const helloWorldItem = {
35+
displayText: 'Hello World',
36+
preconditionFn: function(scope) {
37+
return 'enabled';
38+
},
39+
callback: function(scope) {
40+
},
41+
id: 'hello_world',
42+
weight: 100,
43+
};
44+
}
45+
```
46+
47+
Call your function from `start`:
48+
49+
```js
50+
function start() {
51+
registerHelloWorldItem();
52+
53+
Blockly.ContextMenuItems.registerCommentOptions();
54+
// Create main workspace.
55+
workspace = Blockly.inject('blocklyDiv',
56+
{
57+
toolbox: toolboxSimple,
58+
});
59+
}
60+
```
61+
62+
### Register it
63+
64+
Next, register your item with Blockly:
65+
66+
```js
67+
function registerHelloWorldItem() {
68+
const helloWorldItem = {
69+
// ...
70+
};
71+
Blockly.ContextMenuRegistry.registry.register(helloWorldItem);
72+
}
73+
```
74+
75+
:::note
76+
you will never need to make a new `ContextMenuRegistry`. Always use the singleton `Blockly.ContextMenuRegistry.registry`.
77+
:::
78+
79+
### Test it
80+
81+
Reload your web page and open a context menu on the workspace (right-click with a mouse, or press `Ctrl+Enter` (Windows) or `Command+Enter` (Mac) if you are navigating Blockly with the keyboard). You should see a new option labeled "Hello World" at the bottom of the context menu.
82+
83+
<ClassBlock className="codelabImages"> ![A context menu. The last option says "Hello World".](../../../static/images/codelabs/context-menu-option/hello_world.png) </ClassBlock>
84+
85+
Next, drag a block onto the workspace and open a context menu on the block. You'll see "Hello World" at the bottom of the block's context menu. Finally, open a context menu on the workspace and create a comment, then open a context menu on the comment's header. "Hello World" should be at the bottom of the context menu.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
slug: /codelabs/context-menu-option/callback/index.html
3+
description: How to add a callback to a context menu item.
4+
---
5+
6+
# Customizing context menus
7+
8+
## 7. Callback
9+
10+
The callback function determines what happens when you select the context menu option. Like the precondition, it can use the `scope` argument to access the Blockly component on which the context menu was invoked.
11+
12+
It is also passed a `PointerEvent` which is the original event that triggered opening the context menu (not the event that selected the current option). This lets you, for example, figure out where on the workspace the context menu was opened so you can create a new element there.
13+
14+
As an example, update the help item's `callback` to add a block to the workspace when selected:
15+
16+
```js
17+
callback: function(scope) {
18+
Blockly.serialization.blocks.append({
19+
'type': 'text',
20+
'fields': {
21+
'TEXT': 'Now there is a block'
22+
}
23+
}, scope.focusedNode);
24+
},
25+
```
26+
27+
### Test it
28+
29+
- Reload the page and open a context menu on the workspace.
30+
- Select the **Help** option.
31+
- A text block should appear in the top left of the workspace.
32+
33+
34+
![A text block containing the text "Now there is a block".](../../../static/images/codelabs/context-menu-option/there_is_a_block.png)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
pagination_prev: null
3+
slug: /codelabs/context-menu-option/codelab-overview/index.html
4+
description: Overview of the "Customizing context menus" codelab.
5+
---
6+
7+
# Customizing context menus
8+
9+
## 1. Codelab overview
10+
11+
### What you'll learn
12+
13+
In this codelab you will learn how to:
14+
- Add a context menu option to the workspace.
15+
- Add a context menu option to all blocks.
16+
- Use precondition functions to hide or disable context menu options.
17+
- Take an action when a menu option is selected.
18+
- Customize ordering and display text for context menu options.
19+
20+
### What you'll build
21+
A very simple Blockly workspace with a few new context menu options.
22+
23+
### What you'll need
24+
- A browser.
25+
- A text editor.
26+
- Basic knowledge of HTML, CSS, and JavaScript.
27+
28+
This codelab is focused on Blockly's context menus. Non-relevant concepts and code are glossed over and are provided for you to simply copy and paste.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Context Menu Codelab</title>
6+
<script src="https://unpkg.com/blockly/blockly.min.js"></script>
7+
<script src="https://unpkg.com/@blockly/dev-tools"></script>
8+
<script src="./index.js"></script>
9+
10+
<style>
11+
html,
12+
body {
13+
height: 100%;
14+
}
15+
16+
body {
17+
background-color: #fff;
18+
font-family: sans-serif;
19+
overflow: hidden;
20+
}
21+
22+
h1 {
23+
font-weight: normal;
24+
font-size: 140%;
25+
margin: 10px;
26+
}
27+
28+
#blocklyDiv {
29+
float: bottom;
30+
height: 90%;
31+
width: 100%;
32+
}
33+
</style>
34+
</head>
35+
36+
<body onload="start()">
37+
<h1>Context Menu Codelab</h1>
38+
<div id="blocklyDiv"></div>
39+
</body>
40+
</html>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
'use strict';
2+
3+
let workspace = null;
4+
5+
function start() {
6+
registerHelloWorldItem();
7+
registerHelpItem();
8+
registerDisplayItem();
9+
Blockly.ContextMenuRegistry.registry.unregister('workspaceDelete');
10+
registerSeparators();
11+
12+
Blockly.ContextMenuItems.registerCommentOptions();
13+
// Create main workspace.
14+
workspace = Blockly.inject('blocklyDiv', {
15+
toolbox: toolboxSimple,
16+
});
17+
}
18+
19+
function registerHelloWorldItem() {
20+
const helloWorldItem = {
21+
displayText: 'Hello World',
22+
preconditionFn: function (scope) {
23+
// Only display this option for workspaces and blocks.
24+
if (
25+
scope.focusedNode instanceof Blockly.WorkspaceSvg ||
26+
scope.focusedNode instanceof Blockly.BlockSvg
27+
) {
28+
// Enable for the first 30 seconds of every minute; disable for the next 30 seconds.
29+
const now = new Date(Date.now());
30+
if (now.getSeconds() < 30) {
31+
return 'enabled';
32+
}
33+
return 'disabled';
34+
}
35+
return 'hidden';
36+
},
37+
callback: function (scope) {},
38+
id: 'hello_world',
39+
weight: 100,
40+
};
41+
// Register.
42+
Blockly.ContextMenuRegistry.registry.register(helloWorldItem);
43+
}
44+
45+
function registerHelpItem() {
46+
const helpItem = {
47+
displayText: 'Help! There are no blocks',
48+
preconditionFn: function (scope) {
49+
// Only display this option on workspace context menus.
50+
if (!(scope.focusedNode instanceof Blockly.WorkspaceSvg)) return 'hidden';
51+
// Use the focused node, which is a WorkspaceSvg, to check for blocks on the workspace.
52+
if (!scope.focusedNode.getTopBlocks().length) {
53+
return 'enabled';
54+
}
55+
return 'hidden';
56+
},
57+
// Use the focused node in the callback function to add a block to the workspace.
58+
callback: function (scope) {
59+
Blockly.serialization.blocks.append(
60+
{
61+
type: 'text',
62+
fields: {
63+
TEXT: 'Now there is a block',
64+
},
65+
},
66+
scope.focusedNode,
67+
);
68+
},
69+
id: 'help_no_blocks',
70+
weight: 100,
71+
};
72+
Blockly.ContextMenuRegistry.registry.register(helpItem);
73+
}
74+
75+
function registerDisplayItem() {
76+
const displayItem = {
77+
// Use the focused node (a BlockSvg) to set display text dynamically based on the type of the block.
78+
displayText: function (scope) {
79+
if (scope.focusedNode.type.startsWith('text')) {
80+
return 'Text block';
81+
} else if (scope.focusedNode.type.startsWith('controls')) {
82+
return 'Controls block';
83+
} else {
84+
return 'Some other block';
85+
}
86+
},
87+
preconditionFn: function (scope) {
88+
return scope.focusedNode instanceof Blockly.BlockSvg
89+
? 'enabled'
90+
: 'hidden';
91+
},
92+
callback: function (scope) {},
93+
id: 'display_text_example',
94+
weight: 100,
95+
};
96+
Blockly.ContextMenuRegistry.registry.register(displayItem);
97+
}
98+
99+
function registerSeparators() {
100+
const workspaceSeparator = {
101+
id: 'workspace_separator',
102+
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
103+
weight: 99,
104+
separator: true,
105+
};
106+
Blockly.ContextMenuRegistry.registry.register(workspaceSeparator);
107+
108+
const blockSeparator = {
109+
id: 'block_separator',
110+
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
111+
weight: 99,
112+
separator: true,
113+
};
114+
Blockly.ContextMenuRegistry.registry.register(blockSeparator);
115+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
slug: /codelabs/context-menu-option/display-text/index.html
3+
description: How to set the display text of a context menu item.
4+
---
5+
6+
# Customizing context menus
7+
8+
## 8. Display text
9+
10+
So far the `displayText` has always been a simple string, but it can also be HTML, or a function that returns either of the former. Using a function can be useful when you want a context-dependent message.
11+
12+
When defined as a function `displayText` accepts a `scope` argument, just like `callback` and `preconditionFn`.
13+
14+
As an example, add this registry item. The display text depends on the block type.
15+
16+
```js
17+
function registerDisplayItem() {
18+
const displayItem = {
19+
displayText: function(scope) {
20+
if (scope.focusedNode.type.startsWith('text')) {
21+
return 'Text block';
22+
} else if (scope.focusedNode.type.startsWith('controls')) {
23+
return 'Controls block';
24+
} else {
25+
return 'Some other block';
26+
}
27+
},
28+
preconditionFn: function(scope) {
29+
return scope.focusedNode instanceof Blockly.BlockSvg
30+
? 'enabled'
31+
: 'hidden';
32+
},
33+
callback: function(scope) {
34+
},
35+
id: 'display_text_example',
36+
weight: 100,
37+
};
38+
Blockly.ContextMenuRegistry.registry.register(displayItem);
39+
}
40+
```
41+
42+
As usual, remember to call `registerDisplayItem()` from your `start` function.
43+
44+
### Test it
45+
46+
- Reload the workspace and open context menus on various blocks.
47+
- The last context menu option's text should vary based on the block type.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
slug: /codelabs/context-menu-option/precondition-blockly-state/index.html
3+
description: How to include a context menu item based on Blockly's state.
4+
---
5+
6+
# Customizing context menus
7+
8+
## 6. Precondition: Blockly state
9+
10+
Disabling your context menu options half of the time is not useful, but you may want to show or hide an option based on what the user is doing. For example, let's show a **Help** option in the context menu if the user doesn't have any blocks on the workspace. Add this code in `index.js`:
11+
12+
```js
13+
function registerHelpItem() {
14+
const helpItem = {
15+
displayText: 'Help! There are no blocks',
16+
preconditionFn: function(scope) {
17+
if (!(scope.focusedNode instanceof Blockly.WorkspaceSvg)) return 'hidden';
18+
if (!scope.focusedNode.getTopBlocks().length) {
19+
return 'enabled';
20+
}
21+
return 'hidden';
22+
},
23+
callback: function(scope) {
24+
},
25+
id: 'help_no_blocks',
26+
weight: 100,
27+
};
28+
Blockly.ContextMenuRegistry.registry.register(helpItem);
29+
}
30+
```
31+
32+
Don't forget to call `registerHelpItem` from your `start` function.
33+
34+
### Test it
35+
36+
- Reload your page and open a context menu on the workspace. You should see an option labeled "Help! There are no blocks".
37+
- Add a block to the workspace and open a context menu on the workspace again. The **Help** option should be gone.

0 commit comments

Comments
 (0)