mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-23 14:32:59 -05:00
Merge pull request #994 from cwillisf/looks-extension-support
Looks extension support
This commit is contained in:
commit
9dc3df1fda
5 changed files with 156 additions and 4 deletions
|
@ -1,8 +1,31 @@
|
|||
/**
|
||||
* Block argument types
|
||||
* @enum {string}
|
||||
*/
|
||||
const ArgumentType = {
|
||||
/**
|
||||
* Numeric value with angle picker
|
||||
*/
|
||||
ANGLE: 'angle',
|
||||
|
||||
/**
|
||||
* Boolean value with hexagonal placeholder
|
||||
*/
|
||||
BOOLEAN: 'Boolean',
|
||||
|
||||
/**
|
||||
* Numeric value with color picker
|
||||
*/
|
||||
COLOR: 'color',
|
||||
|
||||
/**
|
||||
* Numeric value with text field
|
||||
*/
|
||||
NUMBER: 'number',
|
||||
|
||||
/**
|
||||
* String value with text field
|
||||
*/
|
||||
STRING: 'string'
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,31 @@
|
|||
/**
|
||||
* Types of block
|
||||
* @enum {string}
|
||||
*/
|
||||
const BlockType = {
|
||||
/**
|
||||
* Boolean reporter with hexagonal shape
|
||||
*/
|
||||
BOOLEAN: 'Boolean',
|
||||
|
||||
/**
|
||||
* Command block
|
||||
*/
|
||||
COMMAND: 'command',
|
||||
|
||||
/**
|
||||
* Specialized command block which may or may not run a child branch
|
||||
*/
|
||||
CONDITIONAL: 'conditional',
|
||||
|
||||
/**
|
||||
* Hat block which conditionally starts a block stack
|
||||
*/
|
||||
HAT: 'hat',
|
||||
|
||||
/**
|
||||
* General reporter with numeric or string value
|
||||
*/
|
||||
REPORTER: 'reporter'
|
||||
};
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ class ExtensionManager {
|
|||
extensionInfo.menus = this._prepareMenuInfo(serviceName, extensionInfo.menus);
|
||||
return extensionInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare extension menus. e.g. setup binding for dynamic menu functions.
|
||||
* @param {string} serviceName - the name of the service hosting this extension block
|
||||
|
@ -264,13 +264,36 @@ class ExtensionManager {
|
|||
// we can use it later when converting the menu for Scratch Blocks.
|
||||
if (typeof menus[item] === 'string') {
|
||||
const serviceObject = dispatch.services[serviceName];
|
||||
// TODO: Fix this to use dispatch.call when extensions are running in workers.
|
||||
menus[item] = serviceObject[menus[item]].bind(serviceObject);
|
||||
const menuName = menus[item];
|
||||
menus[item] = this._getExtensionMenuItems.bind(this, serviceObject, menuName);
|
||||
}
|
||||
}
|
||||
return menus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the items for a particular extension menu, providing the target ID for context.
|
||||
* @param {object} extensionObject - the extension object providing the menu.
|
||||
* @param {string} menuName - the name of the menu function to call.
|
||||
* @returns {Array} menu items ready for scratch-blocks.
|
||||
* @private
|
||||
*/
|
||||
_getExtensionMenuItems (extensionObject, menuName) {
|
||||
// Fetch the items appropriate for the target currently being edited. This assumes that menus only
|
||||
// collect items when opened by the user while editing a particular target.
|
||||
const editingTarget = this.runtime.getEditingTarget();
|
||||
const editingTargetID = editingTarget ? editingTarget.id : null;
|
||||
|
||||
// TODO: Fix this to use dispatch.call when extensions are running in workers.
|
||||
const menuFunc = extensionObject[menuName];
|
||||
const menuItems = menuFunc.call(extensionObject, editingTargetID);
|
||||
|
||||
if (!menuItems || menuItems.length < 1) {
|
||||
throw new Error(`Extension menu returned no items: ${menuName}`);
|
||||
}
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply defaults for optional block fields.
|
||||
* @param {string} serviceName - the name of the service hosting this extension block
|
||||
|
@ -297,7 +320,12 @@ class ExtensionManager {
|
|||
blockInfo.func = dispatch.call.bind(dispatch, serviceName, blockInfo.func);
|
||||
} else {
|
||||
const serviceObject = dispatch.services[serviceName];
|
||||
blockInfo.func = serviceObject[blockInfo.func].bind(serviceObject);
|
||||
const func = serviceObject[blockInfo.func];
|
||||
if (func) {
|
||||
blockInfo.func = func.bind(serviceObject);
|
||||
} else {
|
||||
throw new Error(`Could not find extension block function called ${blockInfo.func}`);
|
||||
}
|
||||
}
|
||||
return blockInfo;
|
||||
}
|
||||
|
|
60
src/extension-support/extension-metadata.js
Normal file
60
src/extension-support/extension-metadata.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @typedef {object} ExtensionMetadata
|
||||
* All the metadata needed to register an extension.
|
||||
* @property {string} id - a unique alphanumeric identifier for this extension. No special characters allowed.
|
||||
* @property {string} name - the human-readable name of this extension.
|
||||
* @property {string} blockIconURI - URI for an image to be placed on each block in this extension. Data URI ok.
|
||||
* @property {string} menuIconURI - URI for an image to be placed on this extension's category menu entry. Data URI ok.
|
||||
* @property {string} docsURI - link to documentation content for this extension.
|
||||
* @property {Array.<ExtensionBlockMetadata|string>} - the blocks provided by this extension, with optional separators.
|
||||
* @property {Object.<ExtensionMenuMetadata>} - map of menu name to metadata about each of this extension's menus.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} ExtensionBlockMetadata
|
||||
* All the metadata needed to register an extension block.
|
||||
* @property {string} opcode - a unique alphanumeric identifier for this block. No special characters allowed.
|
||||
* @property {BlockType} blockType - the type of block (command, reporter, etc.) being described.
|
||||
* @property {string} func - the name of the function implementing this block. Can be shared with other blocks/opcodes.
|
||||
* @property {Boolean} hideFromPalette - true if this block should not appear in the block palette.
|
||||
* @property {ReporterScope} reporterScope - if this block is a reporter, this is the scope/context for its value.
|
||||
* @property {Boolean} terminal - true if the block ends a stack - no blocks can be connected after it.
|
||||
* @property {string} text - the text on the block, with [PLACEHOLDERS] for arguments.
|
||||
* @property {Object.<ExtensionArgumentMetadata>} arguments - map of argument placeholder to metadata about each arg.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} ExtensionArgumentMetadata
|
||||
* All the metadata needed to register an argument for an extension block.
|
||||
* @property {ArgumentType} type - the type of the argument (number, string, etc.)
|
||||
* @property {*} defaultValue - the default value of this argument.
|
||||
* @property {string} menu - the name of the menu to use for this argument, if any.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {ExtensionDynamicMenu|ExtensionMenuItems} ExtensionMenuMetadata
|
||||
* All the metadata needed to register an extension drop-down menu.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {string} ExtensionDynamicMenu
|
||||
* The string name of a function which returns menu items.
|
||||
* @see {ExtensionMenuItems} - the type of data expected to be returned by the specified function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Array.<ExtensionMenuItemSimple|ExtensionMenuItemComplex>} ExtensionMenuItems
|
||||
* Items in an extension menu.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {string} ExtensionMenuItemSimple
|
||||
* A menu item for which the label and value are identical strings.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} ExtensionMenuItemComplex
|
||||
* A menu item for which the label and value can differ.
|
||||
* @property {*} value - the value of the block argument when this menu item is selected.
|
||||
* @property {string} text - the human-readable label of this menu item in the menu.
|
||||
*/
|
18
src/extension-support/reporter-scope.js
Normal file
18
src/extension-support/reporter-scope.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Indicate the scope for a reporter's value.
|
||||
* @enum {string}
|
||||
*/
|
||||
const ReporterScope = {
|
||||
/**
|
||||
* This reporter's value is global and does not depend on context.
|
||||
*/
|
||||
GLOBAL: 'global',
|
||||
|
||||
/**
|
||||
* This reporter's value is specific to a particular target/sprite.
|
||||
* Another target may have a different value or may not even have a value.
|
||||
*/
|
||||
TARGET: 'target'
|
||||
};
|
||||
|
||||
module.exports = ReporterScope;
|
Loading…
Reference in a new issue