mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-06-05 01:54:52 -04:00
switch from rejectReporters
flag to acceptReporters
Also add more extensive documentation around extension menu definitions, including some considerations to think about before making a menu accept reporters.
This commit is contained in:
parent
e7bf49c8df
commit
3fbed88a95
2 changed files with 127 additions and 10 deletions
|
@ -120,6 +120,123 @@ class SomeBlocks {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Defining a Menu
|
||||||
|
|
||||||
|
To display a drop-down menu for a block argument, specify the `menu` property of that argument and a matching item in
|
||||||
|
the `menus` section of your extension's definition:
|
||||||
|
|
||||||
|
```js
|
||||||
|
return {
|
||||||
|
// ...
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
arguments: {
|
||||||
|
FOO: {
|
||||||
|
type: ArgumentType.NUMBER,
|
||||||
|
menu: 'fooMenu'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
menus: {
|
||||||
|
fooMenu: {
|
||||||
|
items: ['a', 'b', 'c']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The items in a menu may be specified with an array or with the name of a function which returns an array. The two
|
||||||
|
simplest forms for menu definitions are:
|
||||||
|
|
||||||
|
```js
|
||||||
|
getInfo () {
|
||||||
|
return {
|
||||||
|
menus: {
|
||||||
|
staticMenu: ['static 1', 'static 2', 'static 3'],
|
||||||
|
dynamicMenu: 'getDynamicMenuItems'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// this member function will be called each time the menu opens
|
||||||
|
getDynamicMenuItems () {
|
||||||
|
return ['dynamic 1', 'dynamic 2', 'dynamic 3'];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The examples above are shorthand for these equivalent definitions:
|
||||||
|
|
||||||
|
```js
|
||||||
|
getInfo () {
|
||||||
|
return {
|
||||||
|
menus: {
|
||||||
|
staticMenu: {
|
||||||
|
items: ['static 1', 'static 2', 'static 3']
|
||||||
|
},
|
||||||
|
dynamicMenu: {
|
||||||
|
items: 'getDynamicMenuItems'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// this member function will be called each time the menu opens
|
||||||
|
getDynamicMenuItems () {
|
||||||
|
return ['dynamic 1', 'dynamic 2', 'dynamic 3'];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a menu item needs a label that doesn't match its value -- for example, if the label needs to be displayed in the
|
||||||
|
user's language but the value needs to stay constant -- the menu item may be an object instead of a string. This works
|
||||||
|
for both static and dynamic menu items:
|
||||||
|
|
||||||
|
```js
|
||||||
|
menus: {
|
||||||
|
staticMenu: [
|
||||||
|
{
|
||||||
|
text: formatMessage(/* ... */),
|
||||||
|
value: 42
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Accepting reporters ("droppable" menus)
|
||||||
|
|
||||||
|
By default it is not possible to specify the value of a dropdown menu by inserting a reporter block. While we
|
||||||
|
encourage extension authors to make their menus accept reporters when possible, doing so requires careful
|
||||||
|
consideration to avoid confusion and frustration on the part of those using the extension.
|
||||||
|
|
||||||
|
A few of these considerations include:
|
||||||
|
|
||||||
|
* The valid values for the menu should not change when the user changes the Scratch language setting.
|
||||||
|
* In particular, changing languages should never break a working project.
|
||||||
|
* The average Scratch user should be able to figure out the valid values for this input without referring to extension
|
||||||
|
documentation.
|
||||||
|
* One way to ensure this is to make an item's text match or include the item's value.
|
||||||
|
* The block should accept any value as input, even "invalid" values.
|
||||||
|
* Scratch has no concept of a runtime error!
|
||||||
|
* For a command block, sometimes the best option is to do nothing.
|
||||||
|
* For a reporter, returning zero or the empty string might make sense.
|
||||||
|
* The block should be forgiving in its interpretation of inputs.
|
||||||
|
* For example, if the block expects a string and receives a number it may make sense to interpret the number as a
|
||||||
|
string instead of treating it as invalid input.
|
||||||
|
|
||||||
|
The `acceptReporters` flag indicates that the user can drop a reporter onto the menu input:
|
||||||
|
|
||||||
|
```js
|
||||||
|
menus: {
|
||||||
|
staticMenu: {
|
||||||
|
acceptReporters: true,
|
||||||
|
items: [/*...*/]
|
||||||
|
},
|
||||||
|
dynamicMenu: {
|
||||||
|
acceptReporters: true,
|
||||||
|
items: 'getDynamicMenuItems'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Annotated Example
|
## Annotated Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -315,8 +432,8 @@ class SomeBlocks {
|
||||||
|
|
||||||
// The examples above are shorthand for setting only the `items` property in this full form:
|
// The examples above are shorthand for setting only the `items` property in this full form:
|
||||||
menuC: {
|
menuC: {
|
||||||
// This flag makes a "non-droppable" menu: the menu will not accept reporters.
|
// This flag makes a "droppable" menu: the menu will allow dropping a reporter in for the input.
|
||||||
rejectReporters: true,
|
acceptReporters: true,
|
||||||
|
|
||||||
// The `item` property may be an array or function name as in previous menu examples.
|
// The `item` property may be an array or function name as in previous menu examples.
|
||||||
items: [/*...*/] || 'getItemsForMenuC'
|
items: [/*...*/] || 'getItemsForMenuC'
|
||||||
|
|
|
@ -894,7 +894,7 @@ class Runtime extends EventEmitter {
|
||||||
* @param {string} menuName - the name of the menu
|
* @param {string} menuName - the name of the menu
|
||||||
* @param {object} menuInfo - a description of this menu and its items
|
* @param {object} menuInfo - a description of this menu and its items
|
||||||
* @property {*} items - an array of menu items or a function to retrieve such an array
|
* @property {*} items - an array of menu items or a function to retrieve such an array
|
||||||
* @property {boolean} [rejectReporters] - if true, prevent dropping reporters onto this menu
|
* @property {boolean} [acceptReporters] - if true, allow dropping reporters onto this menu
|
||||||
* @param {CategoryInfo} categoryInfo - the category for this block
|
* @param {CategoryInfo} categoryInfo - the category for this block
|
||||||
* @returns {object} - a JSON-esque object ready for scratch-blocks' consumption
|
* @returns {object} - a JSON-esque object ready for scratch-blocks' consumption
|
||||||
* @private
|
* @private
|
||||||
|
@ -927,8 +927,8 @@ class Runtime extends EventEmitter {
|
||||||
colour: categoryInfo.color1,
|
colour: categoryInfo.color1,
|
||||||
colourSecondary: categoryInfo.color2,
|
colourSecondary: categoryInfo.color2,
|
||||||
colourTertiary: categoryInfo.color3,
|
colourTertiary: categoryInfo.color3,
|
||||||
outputShape: menuInfo.rejectReporters ?
|
outputShape: menuInfo.acceptReporters ?
|
||||||
ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE : ScratchBlocksConstants.OUTPUT_SHAPE_ROUND,
|
ScratchBlocksConstants.OUTPUT_SHAPE_ROUND : ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE,
|
||||||
args0: [
|
args0: [
|
||||||
{
|
{
|
||||||
type: 'field_dropdown',
|
type: 'field_dropdown',
|
||||||
|
@ -1235,16 +1235,16 @@ class Runtime extends EventEmitter {
|
||||||
let fieldName;
|
let fieldName;
|
||||||
if (argInfo.menu) {
|
if (argInfo.menu) {
|
||||||
const menuInfo = argInfo.menu && context.categoryInfo.menuInfo[argInfo.menu];
|
const menuInfo = argInfo.menu && context.categoryInfo.menuInfo[argInfo.menu];
|
||||||
if (menuInfo.rejectReporters) {
|
if (menuInfo.acceptReporters) {
|
||||||
|
valueName = placeholder;
|
||||||
|
shadowType = this._makeExtensionMenuId(argInfo.menu, context.categoryInfo.id);
|
||||||
|
fieldName = argInfo.menu;
|
||||||
|
} else {
|
||||||
argJSON.type = 'field_dropdown';
|
argJSON.type = 'field_dropdown';
|
||||||
argJSON.options = menuInfo.items;
|
argJSON.options = menuInfo.items;
|
||||||
valueName = null;
|
valueName = null;
|
||||||
shadowType = null;
|
shadowType = null;
|
||||||
fieldName = placeholder;
|
fieldName = placeholder;
|
||||||
} else {
|
|
||||||
valueName = placeholder;
|
|
||||||
shadowType = this._makeExtensionMenuId(argInfo.menu, context.categoryInfo.id);
|
|
||||||
fieldName = argInfo.menu;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
valueName = placeholder;
|
valueName = placeholder;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue