From de9e2be265bf5d800f37a8267b140ffb62f3b674 Mon Sep 17 00:00:00 2001 From: Christopher Willis-Ford Date: Tue, 27 Mar 2018 14:35:04 -0700 Subject: [PATCH] Add EVENT extension block type An EVENT block is like a HAT block but it has no implementation function. Its stack runs when the VM emits the corresponding event. --- src/engine/runtime.js | 21 ++++++++++++++------ src/extension-support/block-type.js | 6 ++++++ src/extension-support/extension-manager.js | 22 ++++----------------- src/extension-support/extension-metadata.js | 13 +++++++----- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 86881d166..2e14ab1dd 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -562,10 +562,14 @@ class Runtime extends EventEmitter { const convertedBlock = this._convertForScratchBlocks(blockInfo, categoryInfo); const opcode = convertedBlock.json.type; categoryInfo.blocks.push(convertedBlock); - this._primitives[opcode] = convertedBlock.info.func; - if (blockInfo.blockType === BlockType.HAT) { - this._hats[opcode] = {edgeActivated: true}; - /** @TODO let extension specify this */ + if (blockInfo.blockType !== BlockType.EVENT) { + this._primitives[opcode] = convertedBlock.info.func; + } + if (blockInfo.blockType === BlockType.EVENT || blockInfo.blockType === BlockType.HAT) { + this._hats[opcode] = { + edgeActivated: blockInfo.isEdgeActivated, + restartExistingThreads: blockInfo.shouldRestartExistingThreads + }; } } catch (e) { log.error('Error parsing block: ', {block: blockInfo, error: e}); @@ -620,8 +624,8 @@ class Runtime extends EventEmitter { } /** - * Convert BlockInfo into scratch-blocks JSON & XML, and generate a proxy function. - * @param {BlockInfo} blockInfo - the block to convert + * Convert ExtensionBlockMetadata into scratch-blocks JSON & XML, and generate a proxy function. + * @param {ExtensionBlockMetadata} blockInfo - the block to convert * @param {CategoryInfo} categoryInfo - the category for this block * @returns {ConvertedBlockInfo} - the converted & original block information * @private @@ -685,6 +689,11 @@ class Runtime extends EventEmitter { blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_HEXAGONAL; break; case BlockType.HAT: + case BlockType.EVENT: + if (!blockInfo.hasOwnProperty('isEdgeActivated')) { + // if absent, this property defaults to true + blockInfo.isEdgeActivated = true; + } blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; blockJSON.nextStatement = null; // null = available connection; undefined = terminal break; diff --git a/src/extension-support/block-type.js b/src/extension-support/block-type.js index 4db5e5d52..3b38c0511 100644 --- a/src/extension-support/block-type.js +++ b/src/extension-support/block-type.js @@ -19,6 +19,12 @@ const BlockType = { */ CONDITIONAL: 'conditional', + /** + * Specialized hat block with no implementation function + * This stack only runs if the corresponding event is emitted by other code. + */ + EVENT: 'event', + /** * Hat block which conditionally starts a block stack */ diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index ba3ac6a9b..c6b846f35 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -21,23 +21,9 @@ const builtinExtensions = { * @property {*|undefined} default - the default value of this argument (default: blank) */ -/** - * @typedef {object} BlockInfo - Information about an extension block - * @property {string} opcode - the block opcode - * @property {string|object} text - the human-readable text on this block - * @property {BlockType|undefined} blockType - the type of block (default: BlockType.COMMAND) - * @property {int|undefined} branchCount - the number of branches this block controls, if conditional (default: 0) - * @property {Boolean|undefined} isTerminal - true if this block ends a stack (default: false) - * @property {Boolean|undefined} blockAllThreads - true if all threads must wait for this block to run (default: false) - * @property {object.|undefined} arguments - information about this block's arguments, if any - * @property {string|Function|undefined} func - the method for this block on the extension service (default: opcode) - * @property {Array.|undefined} filter - the list of targets for which this block should appear (default: all) - * @property {Boolean|undefined} hideFromPalette - true if should not be appear in the palette. (default false) - */ - /** * @typedef {object} ConvertedBlockInfo - Raw extension block data paired with processed data ready for scratch-blocks - * @property {BlockInfo} info - the raw block info + * @property {ExtensionBlockMetadata} info - the raw block info * @property {object} json - the scratch-blocks JSON definition for this block * @property {string} xml - the scratch-blocks XML definition for this block */ @@ -250,7 +236,7 @@ class ExtensionManager { case '---': // separator result = '---'; break; - default: // a BlockInfo object + default: // an ExtensionBlockMetadata object result = this._prepareBlockInfo(serviceName, blockInfo); break; } @@ -316,8 +302,8 @@ class ExtensionManager { /** * Apply defaults for optional block fields. * @param {string} serviceName - the name of the service hosting this extension block - * @param {BlockInfo} blockInfo - the block info from the extension - * @returns {BlockInfo} - a new block info object which has values for all relevant optional fields. + * @param {ExtensionBlockMetadata} blockInfo - the block info from the extension + * @returns {ExtensionBlockMetadata} - a new block info object which has values for all relevant optional fields. * @private */ _prepareBlockInfo (serviceName, blockInfo) { diff --git a/src/extension-support/extension-metadata.js b/src/extension-support/extension-metadata.js index 515c853ba..6e2396471 100644 --- a/src/extension-support/extension-metadata.js +++ b/src/extension-support/extension-metadata.js @@ -14,13 +14,16 @@ * @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 {string} [func] - the name of the function implementing this block. Can be shared by other blocks/opcodes. * @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.} arguments - map of argument placeholder to metadata about each arg. + * @property {Boolean} [hideFromPalette] - true if this block should not appear in the block palette. + * @property {Boolean} [isTerminal] - true if the block ends a stack - no blocks can be connected after it. + * @property {ReporterScope} [reporterScope] - if this block is a reporter, this is the scope/context for its value. + * @property {Boolean} [isEdgeActivated] - sets whether a hat block is edge-activated. + * @property {Boolean} [shouldRestartExistingThreads] - sets whether a hat/event block should restart existing threads. + * @property {int} [branchCount] - for flow control blocks, the number of branches/substacks for this block. + * @property {Object.} [arguments] - map of argument placeholder to metadata about each arg. */ /**