From 9048a9b9e78f25fef129fc1663912a244729cb1d Mon Sep 17 00:00:00 2001 From: DD Date: Mon, 13 Nov 2017 16:28:50 -0500 Subject: [PATCH 1/6] Pipe through whether a monitor is sprite-specific --- src/engine/blocks.js | 14 +++++++++++--- src/engine/execute.js | 2 ++ src/engine/monitor-record.js | 2 ++ src/engine/runtime.js | 9 +++++---- src/util/uid.js | 3 ++- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 92a2d58e7..7564d3ca9 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -226,7 +226,8 @@ class Blocks { id: e.blockId, element: e.element, name: e.name, - value: e.newValue + value: e.newValue, + isSpriteSpecific: e.isSpriteSpecific }, optRuntime); break; case 'move': @@ -326,12 +327,14 @@ class Blocks { break; case 'checkbox': block.isMonitored = args.value; + block.targetId = args.isSpriteSpecific ? this._getTargetIdFromBlockId(block.id) : null; if (optRuntime && wasMonitored && !block.isMonitored) { optRuntime.requestRemoveMonitor(block.id); } else if (optRuntime && !wasMonitored && block.isMonitored) { optRuntime.requestAddMonitor(MonitorRecord({ // @todo(vm#564) this will collide if multiple sprites use same block id: block.id, + spriteName: block.targetId ? optRuntime.getTargetById(block.targetId).getName() : null, opcode: block.opcode, params: this._getBlockParams(block), // @todo(vm#565) for numerical values with decimals, some countries use comma @@ -406,12 +409,17 @@ class Blocks { runAllMonitored (runtime) { Object.keys(this._blocks).forEach(blockId => { if (this.getBlock(blockId).isMonitored) { - // @todo handle specific targets (e.g. apple x position) - runtime.addMonitorScript(blockId); + const targetId = this.getBlock(blockId).targetId; + runtime.addMonitorScript(blockId, targetId ? runtime.getTargetById(targetId) : null); } }); } + _getTargetIdFromBlockId (blockId) { + // First word of block ID. See makeToolboxXML in scratch-gui + return blockId.split('_')[0]; + } + /** * Block management: delete blocks and their associated scripts. * @param {!object} e Blockly delete event to be processed. diff --git a/src/engine/execute.js b/src/engine/execute.js index df9b5964b..fe1688e6a 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -68,8 +68,10 @@ const handleReport = function ( sequencer.runtime.visualReport(currentBlockId, resolvedValue); } if (thread.updateMonitor) { + const targetId = sequencer.runtime.monitorBlocks.getBlock(currentBlockId).targetId; sequencer.runtime.requestUpdateMonitor(Map({ id: currentBlockId, + spriteName: targetId ? sequencer.runtime.getTargetById(targetId).getName() : null, value: String(resolvedValue) })); } diff --git a/src/engine/monitor-record.js b/src/engine/monitor-record.js index 76ed08489..40e67c5e7 100644 --- a/src/engine/monitor-record.js +++ b/src/engine/monitor-record.js @@ -2,6 +2,8 @@ const {Record} = require('immutable'); const MonitorRecord = Record({ id: null, + /** Present only if the monitor is sprite-specific, such as x position */ + spriteName: null, opcode: null, value: null, params: null diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 56fceadfc..06d068bcd 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -838,7 +838,7 @@ class Runtime extends EventEmitter { /** * Enqueue a script that when finished will update the monitor for the block. * @param {!string} topBlockId ID of block that starts the script. - * @param {?string} optTarget target ID for target to run script on. If not supplied, uses editing target. + * @param {?string} optTarget target Target to run script on. If not supplied, uses editing target. */ addMonitorScript (topBlockId, optTarget) { if (!optTarget) optTarget = this._editingTarget; @@ -1260,7 +1260,7 @@ class Runtime extends EventEmitter { * @param {!MonitorRecord} monitor Monitor to add. */ requestAddMonitor (monitor) { - this._monitorState = this._monitorState.set(monitor.id, monitor); + this._monitorState = this._monitorState.set(monitor.get('id'), monitor); } /** @@ -1271,9 +1271,10 @@ class Runtime extends EventEmitter { * the old monitor will keep its old value. */ requestUpdateMonitor (monitor) { - if (this._monitorState.has(monitor.get('id'))) { + const id = monitor.get('id'); + if (this._monitorState.has(id)) { this._monitorState = - this._monitorState.set(monitor.get('id'), this._monitorState.get(monitor.get('id')).merge(monitor)); + this._monitorState.set(id, this._monitorState.get(id).merge(monitor)); } } diff --git a/src/util/uid.js b/src/util/uid.js index fd4c41e87..34e8eaf58 100644 --- a/src/util/uid.js +++ b/src/util/uid.js @@ -6,9 +6,10 @@ * Legal characters for the unique ID. * Should be all on a US keyboard. No XML special characters or control codes. * Removed $ due to issue 251. + * Removed _ which denotes word separation in XML. * @private */ -const soup_ = '!#%()*+,-./:;=?@[]^_`{|}~' + +const soup_ = '!#%()*+,-./:;=?@[]^`{|}~' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; /** From 757dccd565ecc3367e5f637910b4e48e91aae24b Mon Sep 17 00:00:00 2001 From: DD Date: Tue, 14 Nov 2017 18:25:54 -0500 Subject: [PATCH 2/6] Move is sprite specific verification into VM in a temporary way. Remove monitors when their sprites are deleted. --- src/engine/blocks.js | 1 + src/engine/execute.js | 4 ++++ src/engine/monitor-record.js | 2 ++ src/engine/runtime.js | 9 +++++++++ src/virtual-machine.js | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 7564d3ca9..155a2e5e8 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -334,6 +334,7 @@ class Blocks { optRuntime.requestAddMonitor(MonitorRecord({ // @todo(vm#564) this will collide if multiple sprites use same block id: block.id, + targetId: block.targetId, spriteName: block.targetId ? optRuntime.getTargetById(block.targetId).getName() : null, opcode: block.opcode, params: this._getBlockParams(block), diff --git a/src/engine/execute.js b/src/engine/execute.js index fe1688e6a..bbacca951 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -69,6 +69,10 @@ const handleReport = function ( } if (thread.updateMonitor) { const targetId = sequencer.runtime.monitorBlocks.getBlock(currentBlockId).targetId; + if (targetId && !sequencer.runtime.getTargetById(targetId)) { + // Target no longer exists + return; + } sequencer.runtime.requestUpdateMonitor(Map({ id: currentBlockId, spriteName: targetId ? sequencer.runtime.getTargetById(targetId).getName() : null, diff --git a/src/engine/monitor-record.js b/src/engine/monitor-record.js index 40e67c5e7..d42b878f5 100644 --- a/src/engine/monitor-record.js +++ b/src/engine/monitor-record.js @@ -4,6 +4,8 @@ const MonitorRecord = Record({ id: null, /** Present only if the monitor is sprite-specific, such as x position */ spriteName: null, + /** Present only if the monitor is sprite-specific, such as x position */ + targetId: null, opcode: null, value: null, params: null diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 06d068bcd..6d650668e 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -1287,6 +1287,15 @@ class Runtime extends EventEmitter { this._monitorState = this._monitorState.delete(monitorId); } + /** + * Removes all monitors with the given target ID from the state. Does nothing if + * the monitor already does not exist in the state. + * @param {!string} targetId Remove all monitors with given target ID. + */ + requestRemoveMonitorByTargetId (targetId) { + this._monitorState = this._monitorState.filterNot(value => value.targetId === targetId); + } + /** * Get a target by its id. * @param {string} targetId Id of target to find. diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 6dfc7acad..175b5fd20 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -484,6 +484,7 @@ class VirtualMachine extends EventEmitter { if (!sprite) { throw new Error('No sprite associated with this target.'); } + this.runtime.requestRemoveMonitorByTargetId(targetId); const currentEditingTarget = this.editingTarget; for (let i = 0; i < sprite.clones.length; i++) { const clone = sprite.clones[i]; @@ -574,9 +575,44 @@ class VirtualMachine extends EventEmitter { * @param {!Blockly.Event} e Any Blockly event. */ monitorBlockListener (e) { + const tempMonitoredBlocks = [ + 'volume', + 'tempo', + 'answer', + 'loudness', + 'videoon', + 'timer', + 'of', + 'current', + 'username', + 'xposition', + 'yposition', + 'direction', + 'size', + 'backdropname', + 'costumeorder', + 'backdroporder' + ]; + const tempMonitoredPerSpriteBlocks = [ + 'xposition', + 'yposition', + 'direction', + 'size', + 'costumeorder' + ]; // Filter events by type, since monitor blocks only need to listen to these events. // Monitor blocks shouldn't be destroyed when flyout blocks are deleted. if (['create', 'change'].indexOf(e.type) !== -1) { + // TEMPORARY ---- + let blockType = e.blockId.split('_'); + blockType = blockType[blockType.length - 1]; + if (tempMonitoredBlocks.indexOf(blockType) === -1) { + return; + } + if (tempMonitoredPerSpriteBlocks.indexOf(blockType) !== -1) { + e.isSpriteSpecific = true; + } + // ----- this.runtime.monitorBlocks.blocklyListen(e, this.runtime); } } From 0958db2618705512dfe9172fc206a5fee6e6edd2 Mon Sep 17 00:00:00 2001 From: DD Date: Wed, 15 Nov 2017 17:53:43 -0500 Subject: [PATCH 3/6] Move data to blocks files --- src/blocks/scratch3_looks.js | 9 +++++++++ src/blocks/scratch3_motion.js | 8 ++++++++ src/blocks/scratch3_sensing.js | 10 ++++++++++ src/blocks/scratch3_sound.js | 6 ++++++ src/engine/runtime.js | 26 ++++++++++++++++++++++++++ src/virtual-machine.js | 32 +++----------------------------- 6 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index 70238a786..a64f095b0 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -242,6 +242,15 @@ class Scratch3LooksBlocks { }; } + getMonitored () { + return { + size: {isSpriteSpecific: true}, + costumeorder: {isSpriteSpecific: true}, + backdroporder: {}, + backdropname: {} + }; + } + say (args, util) { // @TODO in 2.0 calling say/think resets the right/left bias of the bubble this._updateBubble(util.target, 'say', String(args.MESSAGE)); diff --git a/src/blocks/scratch3_motion.js b/src/blocks/scratch3_motion.js index d040337c8..b30138d3e 100644 --- a/src/blocks/scratch3_motion.js +++ b/src/blocks/scratch3_motion.js @@ -38,6 +38,14 @@ class Scratch3MotionBlocks { }; } + getMonitored () { + return { + xposition: {isSpriteSpecific: true}, + yposition: {isSpriteSpecific: true}, + direction: {isSpriteSpecific: true} + }; + } + moveSteps (args, util) { const steps = Cast.toNumber(args.STEPS); const radians = MathUtil.degToRad(90 - util.target.direction); diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index 17dc87e9d..d51dd5d3b 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -49,6 +49,16 @@ class Scratch3SensingBlocks { }; } + getMonitored () { + return { + answer: {}, + loudness: {}, + timer: {}, + of: {}, + current: {} + }; + } + _onAnswer (answer) { this._answer = answer; const questionObj = this._questionList.shift(); diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index 6f5fed972..d3f3f92ac 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -103,6 +103,12 @@ class Scratch3SoundBlocks { }; } + getMonitored () { + return { + volume: {} + }; + } + playSound (args, util) { const index = this._getSoundIndex(args.SOUND_MENU, util); if (index >= 0) { diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 6d650668e..d8fa88358 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -176,6 +176,13 @@ class Runtime extends EventEmitter { */ this._refreshTargets = false; + /** + * Map to look up all monitor block information by opcode. + * @type {object} + * @private + */ + this.monitorBlockInfo = {}; + /** * Ordered map of all monitors, which are MonitorReporter objects. */ @@ -225,6 +232,9 @@ class Runtime extends EventEmitter { // Register all given block packages. this._registerBlockPackages(); + // Populate monitorBlockInfo + this._registerMonitorInfo(); + // Register and initialize "IO devices", containers for processing // I/O related data. /** @type {Object.} */ @@ -451,6 +461,22 @@ class Runtime extends EventEmitter { this.emit(Runtime.EXTENSION_ADDED, categoryInfo.blocks.concat(categoryInfo.menus)); } + /** + * Populate this.monitorBlockInfo + */ + _registerMonitorInfo () { + for (const packageName in defaultBlockPackages) { + if (defaultBlockPackages.hasOwnProperty(packageName)) { + // @todo pass a different runtime depending on package privilege? + const packageObject = new (defaultBlockPackages[packageName])(this); + // Collect monitored from package. + if (packageObject.getMonitored) { + this.monitorBlockInfo = Object.assign({}, this.monitorBlockInfo, packageObject.getMonitored()); + } + } + } + } + /** * Build the scratch-blocks JSON for a menu. Note that scratch-blocks treats menus as a special kind of block. * @param {string} menuName - the name of the menu diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 175b5fd20..5c5361bae 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -575,44 +575,18 @@ class VirtualMachine extends EventEmitter { * @param {!Blockly.Event} e Any Blockly event. */ monitorBlockListener (e) { - const tempMonitoredBlocks = [ - 'volume', - 'tempo', - 'answer', - 'loudness', - 'videoon', - 'timer', - 'of', - 'current', - 'username', - 'xposition', - 'yposition', - 'direction', - 'size', - 'backdropname', - 'costumeorder', - 'backdroporder' - ]; - const tempMonitoredPerSpriteBlocks = [ - 'xposition', - 'yposition', - 'direction', - 'size', - 'costumeorder' - ]; // Filter events by type, since monitor blocks only need to listen to these events. // Monitor blocks shouldn't be destroyed when flyout blocks are deleted. if (['create', 'change'].indexOf(e.type) !== -1) { - // TEMPORARY ---- let blockType = e.blockId.split('_'); blockType = blockType[blockType.length - 1]; - if (tempMonitoredBlocks.indexOf(blockType) === -1) { + if (!this.runtime.monitorBlockInfo.hasOwnProperty(blockType)) { return; } - if (tempMonitoredPerSpriteBlocks.indexOf(blockType) !== -1) { + if (!this.runtime.monitorBlockInfo.hasOwnProperty(blockType) || + this.runtime.monitorBlockInfo[blockType].isSpriteSpecific) { e.isSpriteSpecific = true; } - // ----- this.runtime.monitorBlocks.blocklyListen(e, this.runtime); } } From 255e160ebb00c123e373a5199b66e18b1e0ca629 Mon Sep 17 00:00:00 2001 From: DD Date: Thu, 16 Nov 2017 17:19:51 -0500 Subject: [PATCH 4/6] Change it so we dont have to do string manipulation on IDs to get data out of events --- src/blocks/scratch3_looks.js | 8 ++++---- src/blocks/scratch3_motion.js | 6 +++--- src/blocks/scratch3_sensing.js | 10 +++++----- src/blocks/scratch3_sound.js | 2 +- src/engine/blocks.js | 11 +++++------ src/virtual-machine.js | 9 --------- 6 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index a64f095b0..6c8f4fe3b 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -244,10 +244,10 @@ class Scratch3LooksBlocks { getMonitored () { return { - size: {isSpriteSpecific: true}, - costumeorder: {isSpriteSpecific: true}, - backdroporder: {}, - backdropname: {} + looks_size: {isSpriteSpecific: true}, + looks_costumeorder: {isSpriteSpecific: true}, + looks_backdroporder: {}, + looks_backdropname: {} }; } diff --git a/src/blocks/scratch3_motion.js b/src/blocks/scratch3_motion.js index b30138d3e..0b206975b 100644 --- a/src/blocks/scratch3_motion.js +++ b/src/blocks/scratch3_motion.js @@ -40,9 +40,9 @@ class Scratch3MotionBlocks { getMonitored () { return { - xposition: {isSpriteSpecific: true}, - yposition: {isSpriteSpecific: true}, - direction: {isSpriteSpecific: true} + motion_xposition: {isSpriteSpecific: true}, + motion_yposition: {isSpriteSpecific: true}, + motion_direction: {isSpriteSpecific: true} }; } diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index d51dd5d3b..fa129f6c0 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -51,11 +51,11 @@ class Scratch3SensingBlocks { getMonitored () { return { - answer: {}, - loudness: {}, - timer: {}, - of: {}, - current: {} + sensing_answer: {}, + sensing_loudness: {}, + sensing_timer: {}, + sensing_of: {}, + sensing_current: {} }; } diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index d3f3f92ac..be78ec7e2 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -105,7 +105,7 @@ class Scratch3SoundBlocks { getMonitored () { return { - volume: {} + sound_volume: {} }; } diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 155a2e5e8..a5b6ad45c 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -327,7 +327,11 @@ class Blocks { break; case 'checkbox': block.isMonitored = args.value; - block.targetId = args.isSpriteSpecific ? this._getTargetIdFromBlockId(block.id) : null; + if (optRuntime) { + const isSpriteSpecific = optRuntime.monitorBlockInfo.hasOwnProperty(block.opcode) && + optRuntime.monitorBlockInfo[block.opcode].isSpriteSpecific; + block.targetId = isSpriteSpecific ? optRuntime.getEditingTarget().id : null; + } if (optRuntime && wasMonitored && !block.isMonitored) { optRuntime.requestRemoveMonitor(block.id); } else if (optRuntime && !wasMonitored && block.isMonitored) { @@ -416,11 +420,6 @@ class Blocks { }); } - _getTargetIdFromBlockId (blockId) { - // First word of block ID. See makeToolboxXML in scratch-gui - return blockId.split('_')[0]; - } - /** * Block management: delete blocks and their associated scripts. * @param {!object} e Blockly delete event to be processed. diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 5c5361bae..994de9860 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -578,15 +578,6 @@ class VirtualMachine extends EventEmitter { // Filter events by type, since monitor blocks only need to listen to these events. // Monitor blocks shouldn't be destroyed when flyout blocks are deleted. if (['create', 'change'].indexOf(e.type) !== -1) { - let blockType = e.blockId.split('_'); - blockType = blockType[blockType.length - 1]; - if (!this.runtime.monitorBlockInfo.hasOwnProperty(blockType)) { - return; - } - if (!this.runtime.monitorBlockInfo.hasOwnProperty(blockType) || - this.runtime.monitorBlockInfo[blockType].isSpriteSpecific) { - e.isSpriteSpecific = true; - } this.runtime.monitorBlocks.blocklyListen(e, this.runtime); } } From 6d260231049040d38c40181275a8f20e4c7ff1ee Mon Sep 17 00:00:00 2001 From: DD Date: Mon, 20 Nov 2017 13:00:37 -0500 Subject: [PATCH 5/6] revert unnecessary changes' : --- src/engine/blocks.js | 3 +-- src/util/uid.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index a5b6ad45c..89d7a63ce 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -226,8 +226,7 @@ class Blocks { id: e.blockId, element: e.element, name: e.name, - value: e.newValue, - isSpriteSpecific: e.isSpriteSpecific + value: e.newValue }, optRuntime); break; case 'move': diff --git a/src/util/uid.js b/src/util/uid.js index 34e8eaf58..fd4c41e87 100644 --- a/src/util/uid.js +++ b/src/util/uid.js @@ -6,10 +6,9 @@ * Legal characters for the unique ID. * Should be all on a US keyboard. No XML special characters or control codes. * Removed $ due to issue 251. - * Removed _ which denotes word separation in XML. * @private */ -const soup_ = '!#%()*+,-./:;=?@[]^`{|}~' + +const soup_ = '!#%()*+,-./:;=?@[]^_`{|}~' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; /** From ec9d8094bd9e41a87856c45defbe37ec5287aa03 Mon Sep 17 00:00:00 2001 From: DD Date: Mon, 20 Nov 2017 17:23:59 -0500 Subject: [PATCH 6/6] fix review comments --- src/engine/runtime.js | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/engine/runtime.js b/src/engine/runtime.js index d8fa88358..63aec3bb6 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -232,9 +232,6 @@ class Runtime extends EventEmitter { // Register all given block packages. this._registerBlockPackages(); - // Populate monitorBlockInfo - this._registerMonitorInfo(); - // Register and initialize "IO devices", containers for processing // I/O related data. /** @type {Object.} */ @@ -407,6 +404,10 @@ class Runtime extends EventEmitter { } } } + // Collect monitored from package. + if (packageObject.getMonitored) { + this.monitorBlockInfo = Object.assign({}, this.monitorBlockInfo, packageObject.getMonitored()); + } } } } @@ -461,22 +462,6 @@ class Runtime extends EventEmitter { this.emit(Runtime.EXTENSION_ADDED, categoryInfo.blocks.concat(categoryInfo.menus)); } - /** - * Populate this.monitorBlockInfo - */ - _registerMonitorInfo () { - for (const packageName in defaultBlockPackages) { - if (defaultBlockPackages.hasOwnProperty(packageName)) { - // @todo pass a different runtime depending on package privilege? - const packageObject = new (defaultBlockPackages[packageName])(this); - // Collect monitored from package. - if (packageObject.getMonitored) { - this.monitorBlockInfo = Object.assign({}, this.monitorBlockInfo, packageObject.getMonitored()); - } - } - } - } - /** * Build the scratch-blocks JSON for a menu. Note that scratch-blocks treats menus as a special kind of block. * @param {string} menuName - the name of the menu @@ -864,7 +849,7 @@ class Runtime extends EventEmitter { /** * Enqueue a script that when finished will update the monitor for the block. * @param {!string} topBlockId ID of block that starts the script. - * @param {?string} optTarget target Target to run script on. If not supplied, uses editing target. + * @param {?Target} optTarget target Target to run script on. If not supplied, uses editing target. */ addMonitorScript (topBlockId, optTarget) { if (!optTarget) optTarget = this._editingTarget;