From 2c1d7475caaa46aa8570160a806cd1a170362d82 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 3 Mar 2022 19:48:08 +0000 Subject: [PATCH 1/6] fix: run conversion script on workspace --- core/workspace.js | 1323 +++++++++++++++++++++++---------------------- 1 file changed, 664 insertions(+), 659 deletions(-) diff --git a/core/workspace.js b/core/workspace.js index 51995a75784..9d91a89ebe7 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -53,764 +53,769 @@ const WorkspaceDB_ = Object.create(null); /** * Class for a workspace. This is a data structure that contains blocks. * There is no UI, and can be created headlessly. - * @param {!Options=} opt_options Dictionary of options. - * @constructor - * @implements {IASTNodeLocation} - * @alias Blockly.Workspace */ -const Workspace = function(opt_options) { - /** @type {string} */ - this.id = idGenerator.genUid(); - WorkspaceDB_[this.id] = this; - /** @type {!Options} */ - this.options = - opt_options || new Options(/** @type {!BlocklyOptions} */ ({})); - /** @type {boolean} */ - this.RTL = !!this.options.RTL; - /** @type {boolean} */ - this.horizontalLayout = !!this.options.horizontalLayout; - /** @type {toolbox.Position} */ - this.toolboxPosition = this.options.toolboxPosition; - - /** - * Returns `true` if the workspace is visible and `false` if it's headless. - * @type {boolean} - */ - this.rendered = false; - - /** - * Returns `true` if the workspace is currently in the process of a bulk - * clear. - * @type {boolean} - * @package - */ - this.isClearing = false; - +var Workspace = class { /** - * Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets - * it to unlimited. - * @type {number} + * @param {!Options=} opt_options Dictionary of options. + * @implements {IASTNodeLocation} + * @alias Blockly.Workspace */ - this.MAX_UNDO = 1024; + constructor(opt_options) { + /** @type {string} */ + this.id = idGenerator.genUid(); + WorkspaceDB_[this.id] = this; + /** @type {!Options} */ + this.options = + opt_options || new Options(/** @type {!BlocklyOptions} */ ({})); + /** @type {boolean} */ + this.RTL = !!this.options.RTL; + /** @type {boolean} */ + this.horizontalLayout = !!this.options.horizontalLayout; + /** @type {toolbox.Position} */ + this.toolboxPosition = this.options.toolboxPosition; + + /** + * Returns `true` if the workspace is visible and `false` if it's headless. + * @type {boolean} + */ + this.rendered = false; + + /** + * Returns `true` if the workspace is currently in the process of a bulk + * clear. + * @type {boolean} + * @package + */ + this.isClearing = false; - /** - * Set of databases for rapid lookup of connection locations. - * @type {Array} - */ - this.connectionDBList = null; + /** + * Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets + * it to unlimited. + * @type {number} + */ + this.MAX_UNDO = 1024; + + /** + * Set of databases for rapid lookup of connection locations. + * @type {Array} + */ + this.connectionDBList = null; + + const connectionCheckerClass = registry.getClassFromOptions( + registry.Type.CONNECTION_CHECKER, this.options, true); + /** + * An object that encapsulates logic for safety, type, and dragging checks. + * @type {!IConnectionChecker} + */ + this.connectionChecker = new connectionCheckerClass(this); + + /** + * @type {!Array} + * @private + */ + this.topBlocks_ = []; + /** + * @type {!Array} + * @private + */ + this.topComments_ = []; + /** + * @type {!Object} + * @private + */ + this.commentDB_ = Object.create(null); + /** + * @type {!Array} + * @private + */ + this.listeners_ = []; + /** + * @type {!Array} + * @protected + */ + this.undoStack_ = []; + /** + * @type {!Array} + * @protected + */ + this.redoStack_ = []; + /** + * @type {!Object} + * @private + */ + this.blockDB_ = Object.create(null); + /** + * @type {!Object} + * @private + */ + this.typedBlocksDB_ = Object.create(null); + + /** + * A map from variable type to list of variable names. The lists contain all + * of the named variables in the workspace, including variables + * that are not currently in use. + * @type {!VariableMap} + * @private + */ + this.variableMap_ = new VariableMap(this); + + /** + * Blocks in the flyout can refer to variables that don't exist in the main + * workspace. For instance, the "get item in list" block refers to an "item" + * variable regardless of whether the variable has been created yet. + * A FieldVariable must always refer to a VariableModel. We reconcile + * these by tracking "potential" variables in the flyout. These variables + * become real when references to them are dragged into the main workspace. + * @type {?VariableMap} + * @private + */ + this.potentialVariableMap_ = null; + } - const connectionCheckerClass = registry.getClassFromOptions( - registry.Type.CONNECTION_CHECKER, this.options, true); /** - * An object that encapsulates logic for safety, type, and dragging checks. - * @type {!IConnectionChecker} + * Dispose of this workspace. + * Unlink from all DOM elements to prevent memory leaks. + * @suppress {checkTypes} */ - this.connectionChecker = new connectionCheckerClass(this); + dispose() { + this.listeners_.length = 0; + this.clear(); + // Remove from workspace database. + delete WorkspaceDB_[this.id]; + } /** - * @type {!Array} + * Compare function for sorting objects (blocks, comments, etc) by position; + * top to bottom (with slight LTR or RTL bias). + * @param {!Block | !WorkspaceComment} a The first object to + * compare. + * @param {!Block | !WorkspaceComment} b The second object to + * compare. + * @return {number} The comparison value. This tells Array.sort() how to change + * object a's index. * @private */ - this.topBlocks_ = []; + sortObjects_(a, b) { + const aXY = a.getRelativeToSurfaceXY(); + const bXY = b.getRelativeToSurfaceXY(); + return (aXY.y + Workspace.prototype.sortObjects_.offset * aXY.x) - + (bXY.y + Workspace.prototype.sortObjects_.offset * bXY.x); + } + /** - * @type {!Array} - * @private + * Adds a block to the list of top blocks. + * @param {!Block} block Block to add. */ - this.topComments_ = []; + addTopBlock(block) { + this.topBlocks_.push(block); + } + /** - * @type {!Object} - * @private + * Removes a block from the list of top blocks. + * @param {!Block} block Block to remove. */ - this.commentDB_ = Object.create(null); + removeTopBlock(block) { + if (!arrayUtils.removeElem(this.topBlocks_, block)) { + throw Error('Block not present in workspace\'s list of top-most blocks.'); + } + } + /** - * @type {!Array} - * @private + * Finds the top-level blocks and returns them. Blocks are optionally sorted + * by position; top to bottom (with slight LTR or RTL bias). + * @param {boolean} ordered Sort the list if true. + * @return {!Array} The top-level block objects. */ - this.listeners_ = []; + getTopBlocks(ordered) { + // Copy the topBlocks_ list. + const blocks = [].concat(this.topBlocks_); + if (ordered && blocks.length > 1) { + this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); + if (this.RTL) { + this.sortObjects_.offset *= -1; + } + blocks.sort(this.sortObjects_); + } + return blocks; + } + /** - * @type {!Array} - * @protected + * Add a block to the list of blocks keyed by type. + * @param {!Block} block Block to add. */ - this.undoStack_ = []; + addTypedBlock(block) { + if (!this.typedBlocksDB_[block.type]) { + this.typedBlocksDB_[block.type] = []; + } + this.typedBlocksDB_[block.type].push(block); + } + /** - * @type {!Array} - * @protected + * Remove a block from the list of blocks keyed by type. + * @param {!Block} block Block to remove. */ - this.redoStack_ = []; + removeTypedBlock(block) { + arrayUtils.removeElem(this.typedBlocksDB_[block.type], block); + if (!this.typedBlocksDB_[block.type].length) { + delete this.typedBlocksDB_[block.type]; + } + } + /** - * @type {!Object} - * @private + * Finds the blocks with the associated type and returns them. Blocks are + * optionally sorted by position; top to bottom (with slight LTR or RTL bias). + * @param {string} type The type of block to search for. + * @param {boolean} ordered Sort the list if true. + * @return {!Array} The blocks of the given type. */ - this.blockDB_ = Object.create(null); + getBlocksByType(type, ordered) { + if (!this.typedBlocksDB_[type]) { + return []; + } + const blocks = this.typedBlocksDB_[type].slice(0); + if (ordered && blocks.length > 1) { + this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); + if (this.RTL) { + this.sortObjects_.offset *= -1; + } + blocks.sort(this.sortObjects_); + } + + return blocks.filter(function(block) { + return !block.isInsertionMarker(); + }); + } + /** - * @type {!Object} - * @private + * Adds a comment to the list of top comments. + * @param {!WorkspaceComment} comment comment to add. + * @package */ - this.typedBlocksDB_ = Object.create(null); + addTopComment(comment) { + this.topComments_.push(comment); + + // Note: If the comment database starts to hold block comments, this may need + // to move to a separate function. + if (this.commentDB_[comment.id]) { + console.warn( + 'Overriding an existing comment on this workspace, with id "' + + comment.id + '"'); + } + this.commentDB_[comment.id] = comment; + } /** - * A map from variable type to list of variable names. The lists contain all - * of the named variables in the workspace, including variables - * that are not currently in use. - * @type {!VariableMap} - * @private + * Removes a comment from the list of top comments. + * @param {!WorkspaceComment} comment comment to remove. + * @package */ - this.variableMap_ = new VariableMap(this); + removeTopComment(comment) { + if (!arrayUtils.removeElem(this.topComments_, comment)) { + throw Error( + 'Comment not present in workspace\'s list of top-most ' + + 'comments.'); + } + // Note: If the comment database starts to hold block comments, this may need + // to move to a separate function. + delete this.commentDB_[comment.id]; + } /** - * Blocks in the flyout can refer to variables that don't exist in the main - * workspace. For instance, the "get item in list" block refers to an "item" - * variable regardless of whether the variable has been created yet. - * A FieldVariable must always refer to a VariableModel. We reconcile - * these by tracking "potential" variables in the flyout. These variables - * become real when references to them are dragged into the main workspace. - * @type {?VariableMap} - * @private + * Finds the top-level comments and returns them. Comments are optionally + * sorted by position; top to bottom (with slight LTR or RTL bias). + * @param {boolean} ordered Sort the list if true. + * @return {!Array} The top-level comment objects. + * @package */ - this.potentialVariableMap_ = null; -}; - -/** - * Dispose of this workspace. - * Unlink from all DOM elements to prevent memory leaks. - * @suppress {checkTypes} - */ -Workspace.prototype.dispose = function() { - this.listeners_.length = 0; - this.clear(); - // Remove from workspace database. - delete WorkspaceDB_[this.id]; -}; - -/** - * Angle away from the horizontal to sweep for blocks. Order of execution is - * generally top to bottom, but a small angle changes the scan to give a bit of - * a left to right bias (reversed in RTL). Units are in degrees. - * See: https://tvtropes.org/pmwiki/pmwiki.php/Main/DiagonalBilling - */ -Workspace.SCAN_ANGLE = 3; - -/** - * Compare function for sorting objects (blocks, comments, etc) by position; - * top to bottom (with slight LTR or RTL bias). - * @param {!Block | !WorkspaceComment} a The first object to - * compare. - * @param {!Block | !WorkspaceComment} b The second object to - * compare. - * @return {number} The comparison value. This tells Array.sort() how to change - * object a's index. - * @private - */ -Workspace.prototype.sortObjects_ = function(a, b) { - const aXY = a.getRelativeToSurfaceXY(); - const bXY = b.getRelativeToSurfaceXY(); - return (aXY.y + Workspace.prototype.sortObjects_.offset * aXY.x) - - (bXY.y + Workspace.prototype.sortObjects_.offset * bXY.x); -}; - -/** - * Adds a block to the list of top blocks. - * @param {!Block} block Block to add. - */ -Workspace.prototype.addTopBlock = function(block) { - this.topBlocks_.push(block); -}; - -/** - * Removes a block from the list of top blocks. - * @param {!Block} block Block to remove. - */ -Workspace.prototype.removeTopBlock = function(block) { - if (!arrayUtils.removeElem(this.topBlocks_, block)) { - throw Error('Block not present in workspace\'s list of top-most blocks.'); + getTopComments(ordered) { + // Copy the topComments_ list. + const comments = [].concat(this.topComments_); + if (ordered && comments.length > 1) { + this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); + if (this.RTL) { + this.sortObjects_.offset *= -1; + } + comments.sort(this.sortObjects_); + } + return comments; } -}; -/** - * Finds the top-level blocks and returns them. Blocks are optionally sorted - * by position; top to bottom (with slight LTR or RTL bias). - * @param {boolean} ordered Sort the list if true. - * @return {!Array} The top-level block objects. - */ -Workspace.prototype.getTopBlocks = function(ordered) { - // Copy the topBlocks_ list. - const blocks = [].concat(this.topBlocks_); - if (ordered && blocks.length > 1) { - this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); - if (this.RTL) { - this.sortObjects_.offset *= -1; + /** + * Find all blocks in workspace. Blocks are optionally sorted + * by position; top to bottom (with slight LTR or RTL bias). + * @param {boolean} ordered Sort the list if true. + * @return {!Array} Array of blocks. + */ + getAllBlocks(ordered) { + let blocks; + if (ordered) { + // Slow, but ordered. + const topBlocks = this.getTopBlocks(true); + blocks = []; + for (let i = 0; i < topBlocks.length; i++) { + blocks.push.apply(blocks, topBlocks[i].getDescendants(true)); + } + } else { + // Fast, but in no particular order. + blocks = this.getTopBlocks(false); + for (let i = 0; i < blocks.length; i++) { + blocks.push.apply(blocks, blocks[i].getChildren(false)); + } } - blocks.sort(this.sortObjects_); - } - return blocks; -}; -/** - * Add a block to the list of blocks keyed by type. - * @param {!Block} block Block to add. - */ -Workspace.prototype.addTypedBlock = function(block) { - if (!this.typedBlocksDB_[block.type]) { - this.typedBlocksDB_[block.type] = []; - } - this.typedBlocksDB_[block.type].push(block); -}; + // Insertion markers exist on the workspace for rendering reasons, but aren't + // "real" blocks from a developer perspective. + const filtered = blocks.filter(function(block) { + return !block.isInsertionMarker(); + }); -/** - * Remove a block from the list of blocks keyed by type. - * @param {!Block} block Block to remove. - */ -Workspace.prototype.removeTypedBlock = function(block) { - arrayUtils.removeElem(this.typedBlocksDB_[block.type], block); - if (!this.typedBlocksDB_[block.type].length) { - delete this.typedBlocksDB_[block.type]; + return filtered; } -}; -/** - * Finds the blocks with the associated type and returns them. Blocks are - * optionally sorted by position; top to bottom (with slight LTR or RTL bias). - * @param {string} type The type of block to search for. - * @param {boolean} ordered Sort the list if true. - * @return {!Array} The blocks of the given type. - */ -Workspace.prototype.getBlocksByType = function(type, ordered) { - if (!this.typedBlocksDB_[type]) { - return []; - } - const blocks = this.typedBlocksDB_[type].slice(0); - if (ordered && blocks.length > 1) { - this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); - if (this.RTL) { - this.sortObjects_.offset *= -1; + /** + * Dispose of all blocks and comments in workspace. + */ + clear() { + this.isClearing = true; + try { + const existingGroup = eventUtils.getGroup(); + if (!existingGroup) { + eventUtils.setGroup(true); + } + while (this.topBlocks_.length) { + this.topBlocks_[0].dispose(false); + } + while (this.topComments_.length) { + this.topComments_[this.topComments_.length - 1].dispose(); + } + if (!existingGroup) { + eventUtils.setGroup(false); + } + this.variableMap_.clear(); + if (this.potentialVariableMap_) { + this.potentialVariableMap_.clear(); + } + } finally { + this.isClearing = false; } - blocks.sort(this.sortObjects_); } - return blocks.filter(function(block) { - return !block.isInsertionMarker(); - }); -}; - -/** - * Adds a comment to the list of top comments. - * @param {!WorkspaceComment} comment comment to add. - * @package - */ -Workspace.prototype.addTopComment = function(comment) { - this.topComments_.push(comment); + /* Begin functions that are just pass-throughs to the variable map. */ - // Note: If the comment database starts to hold block comments, this may need - // to move to a separate function. - if (this.commentDB_[comment.id]) { - console.warn( - 'Overriding an existing comment on this workspace, with id "' + - comment.id + '"'); + /** + * Rename a variable by updating its name in the variable map. Identify the + * variable to rename with the given ID. + * @param {string} id ID of the variable to rename. + * @param {string} newName New variable name. + */ + renameVariableById(id, newName) { + this.variableMap_.renameVariableById(id, newName); } - this.commentDB_[comment.id] = comment; -}; - -/** - * Removes a comment from the list of top comments. - * @param {!WorkspaceComment} comment comment to remove. - * @package - */ -Workspace.prototype.removeTopComment = function(comment) { - if (!arrayUtils.removeElem(this.topComments_, comment)) { - throw Error( - 'Comment not present in workspace\'s list of top-most ' + - 'comments.'); - } - // Note: If the comment database starts to hold block comments, this may need - // to move to a separate function. - delete this.commentDB_[comment.id]; -}; -/** - * Finds the top-level comments and returns them. Comments are optionally - * sorted by position; top to bottom (with slight LTR or RTL bias). - * @param {boolean} ordered Sort the list if true. - * @return {!Array} The top-level comment objects. - * @package - */ -Workspace.prototype.getTopComments = function(ordered) { - // Copy the topComments_ list. - const comments = [].concat(this.topComments_); - if (ordered && comments.length > 1) { - this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); - if (this.RTL) { - this.sortObjects_.offset *= -1; - } - comments.sort(this.sortObjects_); + /** + * Create a variable with a given name, optional type, and optional ID. + * @param {string} name The name of the variable. This must be unique across + * variables and procedures. + * @param {?string=} opt_type The type of the variable like 'int' or 'string'. + * Does not need to be unique. Field_variable can filter variables based on + * their type. This will default to '' which is a specific type. + * @param {?string=} opt_id The unique ID of the variable. This will default to + * a UUID. + * @return {!VariableModel} The newly created variable. + */ + createVariable(name, opt_type, opt_id) { + return this.variableMap_.createVariable(name, opt_type, opt_id); } - return comments; -}; -/** - * Find all blocks in workspace. Blocks are optionally sorted - * by position; top to bottom (with slight LTR or RTL bias). - * @param {boolean} ordered Sort the list if true. - * @return {!Array} Array of blocks. - */ -Workspace.prototype.getAllBlocks = function(ordered) { - let blocks; - if (ordered) { - // Slow, but ordered. - const topBlocks = this.getTopBlocks(true); - blocks = []; - for (let i = 0; i < topBlocks.length; i++) { - blocks.push.apply(blocks, topBlocks[i].getDescendants(true)); - } - } else { - // Fast, but in no particular order. - blocks = this.getTopBlocks(false); - for (let i = 0; i < blocks.length; i++) { - blocks.push.apply(blocks, blocks[i].getChildren(false)); - } + /** + * Find all the uses of the given variable, which is identified by ID. + * @param {string} id ID of the variable to find. + * @return {!Array} Array of block usages. + */ + getVariableUsesById(id) { + return this.variableMap_.getVariableUsesById(id); } - // Insertion markers exist on the workspace for rendering reasons, but aren't - // "real" blocks from a developer perspective. - const filtered = blocks.filter(function(block) { - return !block.isInsertionMarker(); - }); - - return filtered; -}; - -/** - * Dispose of all blocks and comments in workspace. - */ -Workspace.prototype.clear = function() { - this.isClearing = true; - try { - const existingGroup = eventUtils.getGroup(); - if (!existingGroup) { - eventUtils.setGroup(true); - } - while (this.topBlocks_.length) { - this.topBlocks_[0].dispose(false); - } - while (this.topComments_.length) { - this.topComments_[this.topComments_.length - 1].dispose(); - } - if (!existingGroup) { - eventUtils.setGroup(false); - } - this.variableMap_.clear(); - if (this.potentialVariableMap_) { - this.potentialVariableMap_.clear(); - } - } finally { - this.isClearing = false; + /** + * Delete a variables by the passed in ID and all of its uses from this + * workspace. May prompt the user for confirmation. + * @param {string} id ID of variable to delete. + */ + deleteVariableById(id) { + this.variableMap_.deleteVariableById(id); } -}; - -/* Begin functions that are just pass-throughs to the variable map. */ -/** - * Rename a variable by updating its name in the variable map. Identify the - * variable to rename with the given ID. - * @param {string} id ID of the variable to rename. - * @param {string} newName New variable name. - */ -Workspace.prototype.renameVariableById = function(id, newName) { - this.variableMap_.renameVariableById(id, newName); -}; - -/** - * Create a variable with a given name, optional type, and optional ID. - * @param {string} name The name of the variable. This must be unique across - * variables and procedures. - * @param {?string=} opt_type The type of the variable like 'int' or 'string'. - * Does not need to be unique. Field_variable can filter variables based on - * their type. This will default to '' which is a specific type. - * @param {?string=} opt_id The unique ID of the variable. This will default to - * a UUID. - * @return {!VariableModel} The newly created variable. - */ -Workspace.prototype.createVariable = function(name, opt_type, opt_id) { - return this.variableMap_.createVariable(name, opt_type, opt_id); -}; - -/** - * Find all the uses of the given variable, which is identified by ID. - * @param {string} id ID of the variable to find. - * @return {!Array} Array of block usages. - */ -Workspace.prototype.getVariableUsesById = function(id) { - return this.variableMap_.getVariableUsesById(id); -}; - -/** - * Delete a variables by the passed in ID and all of its uses from this - * workspace. May prompt the user for confirmation. - * @param {string} id ID of variable to delete. - */ -Workspace.prototype.deleteVariableById = function(id) { - this.variableMap_.deleteVariableById(id); -}; -/** - * Find the variable by the given name and return it. Return null if not found. - * @param {string} name The name to check for. - * @param {string=} opt_type The type of the variable. If not provided it - * defaults to the empty string, which is a specific type. - * @return {?VariableModel} The variable with the given name. - */ -// TODO (#1559): Possibly delete this function after resolving #1559. -Workspace.prototype.getVariable = function(name, opt_type) { - return this.variableMap_.getVariable(name, opt_type); -}; + /** + * Find the variable by the given name and return it. Return null if not found. + * @param {string} name The name to check for. + * @param {string=} opt_type The type of the variable. If not provided it + * defaults to the empty string, which is a specific type. + * @return {?VariableModel} The variable with the given name. + */ -/** - * Find the variable by the given ID and return it. Return null if not found. - * @param {string} id The ID to check for. - * @return {?VariableModel} The variable with the given ID. - */ -Workspace.prototype.getVariableById = function(id) { - return this.variableMap_.getVariableById(id); -}; + // TODO (#1559): Possibly delete this function after resolving #1559. + getVariable(name, opt_type) { + return this.variableMap_.getVariable(name, opt_type); + } -/** - * Find the variable with the specified type. If type is null, return list of - * variables with empty string type. - * @param {?string} type Type of the variables to find. - * @return {!Array} The sought after variables of the - * passed in type. An empty array if none are found. - */ -Workspace.prototype.getVariablesOfType = function(type) { - return this.variableMap_.getVariablesOfType(type); -}; + /** + * Find the variable by the given ID and return it. Return null if not found. + * @param {string} id The ID to check for. + * @return {?VariableModel} The variable with the given ID. + */ + getVariableById(id) { + return this.variableMap_.getVariableById(id); + } -/** - * Return all variable types. - * @return {!Array} List of variable types. - * @package - */ -Workspace.prototype.getVariableTypes = function() { - return this.variableMap_.getVariableTypes(this); -}; + /** + * Find the variable with the specified type. If type is null, return list of + * variables with empty string type. + * @param {?string} type Type of the variables to find. + * @return {!Array} The sought after variables of the + * passed in type. An empty array if none are found. + */ + getVariablesOfType(type) { + return this.variableMap_.getVariablesOfType(type); + } -/** - * Return all variables of all types. - * @return {!Array} List of variable models. - */ -Workspace.prototype.getAllVariables = function() { - return this.variableMap_.getAllVariables(); -}; + /** + * Return all variable types. + * @return {!Array} List of variable types. + * @package + */ + getVariableTypes() { + return this.variableMap_.getVariableTypes(this); + } -/** - * Returns all variable names of all types. - * @return {!Array} List of all variable names of all types. - */ -Workspace.prototype.getAllVariableNames = function() { - return this.variableMap_.getAllVariableNames(); -}; + /** + * Return all variables of all types. + * @return {!Array} List of variable models. + */ + getAllVariables() { + return this.variableMap_.getAllVariables(); + } -/* End functions that are just pass-throughs to the variable map. */ + /** + * Returns all variable names of all types. + * @return {!Array} List of all variable names of all types. + */ + getAllVariableNames() { + return this.variableMap_.getAllVariableNames(); + } -/** - * Returns the horizontal offset of the workspace. - * Intended for LTR/RTL compatibility in XML. - * Not relevant for a headless workspace. - * @return {number} Width. - */ -Workspace.prototype.getWidth = function() { - return 0; -}; + /* End functions that are just pass-throughs to the variable map. */ -/** - * Obtain a newly created block. - * @param {!string} prototypeName Name of the language object containing - * type-specific functions for this block. - * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise - * create a new ID. - * @return {!Block} The created block. - */ -Workspace.prototype.newBlock = function(prototypeName, opt_id) { - const {Block} = goog.module.get('Blockly.Block'); - return new Block(this, prototypeName, opt_id); -}; + /** + * Returns the horizontal offset of the workspace. + * Intended for LTR/RTL compatibility in XML. + * Not relevant for a headless workspace. + * @return {number} Width. + */ + getWidth() { + return 0; + } -/** - * The number of blocks that may be added to the workspace before reaching - * the maxBlocks. - * @return {number} Number of blocks left. - */ -Workspace.prototype.remainingCapacity = function() { - if (isNaN(this.options.maxBlocks)) { - return Infinity; + /** + * Obtain a newly created block. + * @param {!string} prototypeName Name of the language object containing + * type-specific functions for this block. + * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise + * create a new ID. + * @return {!Block} The created block. + */ + newBlock(prototypeName, opt_id) { + const {Block} = goog.module.get('Blockly.Block'); + return new Block(this, prototypeName, opt_id); } - return this.options.maxBlocks - this.getAllBlocks(false).length; -}; + /** + * The number of blocks that may be added to the workspace before reaching + * the maxBlocks. + * @return {number} Number of blocks left. + */ + remainingCapacity() { + if (isNaN(this.options.maxBlocks)) { + return Infinity; + } -/** - * The number of blocks of the given type that may be added to the workspace - * before reaching the maxInstances allowed for that type. - * @param {string} type Type of block to return capacity for. - * @return {number} Number of blocks of type left. - */ -Workspace.prototype.remainingCapacityOfType = function(type) { - if (!this.options.maxInstances) { - return Infinity; + return this.options.maxBlocks - this.getAllBlocks(false).length; } - const maxInstanceOfType = (this.options.maxInstances[type] !== undefined) ? - this.options.maxInstances[type] : - Infinity; + /** + * The number of blocks of the given type that may be added to the workspace + * before reaching the maxInstances allowed for that type. + * @param {string} type Type of block to return capacity for. + * @return {number} Number of blocks of type left. + */ + remainingCapacityOfType(type) { + if (!this.options.maxInstances) { + return Infinity; + } - return maxInstanceOfType - this.getBlocksByType(type, false).length; -}; + const maxInstanceOfType = (this.options.maxInstances[type] !== undefined) ? + this.options.maxInstances[type] : + Infinity; -/** - * Check if there is remaining capacity for blocks of the given counts to be - * created. If the total number of blocks represented by the map is more than - * the total remaining capacity, it returns false. If a type count is more - * than the remaining capacity for that type, it returns false. - * @param {!Object} typeCountsMap A map of types to counts (usually representing - * blocks to be created). - * @return {boolean} True if there is capacity for the given map, - * false otherwise. - */ -Workspace.prototype.isCapacityAvailable = function(typeCountsMap) { - if (!this.hasBlockLimits()) { - return true; + return maxInstanceOfType - this.getBlocksByType(type, false).length; } - let copyableBlocksCount = 0; - for (const type in typeCountsMap) { - if (typeCountsMap[type] > this.remainingCapacityOfType(type)) { + + /** + * Check if there is remaining capacity for blocks of the given counts to be + * created. If the total number of blocks represented by the map is more than + * the total remaining capacity, it returns false. If a type count is more + * than the remaining capacity for that type, it returns false. + * @param {!Object} typeCountsMap A map of types to counts (usually representing + * blocks to be created). + * @return {boolean} True if there is capacity for the given map, + * false otherwise. + */ + isCapacityAvailable(typeCountsMap) { + if (!this.hasBlockLimits()) { + return true; + } + let copyableBlocksCount = 0; + for (const type in typeCountsMap) { + if (typeCountsMap[type] > this.remainingCapacityOfType(type)) { + return false; + } + copyableBlocksCount += typeCountsMap[type]; + } + if (copyableBlocksCount > this.remainingCapacity()) { return false; } - copyableBlocksCount += typeCountsMap[type]; - } - if (copyableBlocksCount > this.remainingCapacity()) { - return false; + return true; } - return true; -}; -/** - * Checks if the workspace has any limits on the maximum number of blocks, - * or the maximum number of blocks of specific types. - * @return {boolean} True if it has block limits, false otherwise. - */ -Workspace.prototype.hasBlockLimits = function() { - return this.options.maxBlocks !== Infinity || !!this.options.maxInstances; -}; + /** + * Checks if the workspace has any limits on the maximum number of blocks, + * or the maximum number of blocks of specific types. + * @return {boolean} True if it has block limits, false otherwise. + */ + hasBlockLimits() { + return this.options.maxBlocks !== Infinity || !!this.options.maxInstances; + } -/** - * Gets the undo stack for workplace. - * @return {!Array} undo stack - * @package - */ -Workspace.prototype.getUndoStack = function() { - return this.undoStack_; -}; + /** + * Gets the undo stack for workplace. + * @return {!Array} undo stack + * @package + */ + getUndoStack() { + return this.undoStack_; + } -/** - * Gets the redo stack for workplace. - * @return {!Array} redo stack - * @package - */ -Workspace.prototype.getRedoStack = function() { - return this.redoStack_; -}; + /** + * Gets the redo stack for workplace. + * @return {!Array} redo stack + * @package + */ + getRedoStack() { + return this.redoStack_; + } -/** - * Undo or redo the previous action. - * @param {boolean} redo False if undo, true if redo. - */ -Workspace.prototype.undo = function(redo) { - const inputStack = redo ? this.redoStack_ : this.undoStack_; - const outputStack = redo ? this.undoStack_ : this.redoStack_; - const inputEvent = inputStack.pop(); - if (!inputEvent) { - return; - } - let events = [inputEvent]; - // Do another undo/redo if the next one is of the same group. - while (inputStack.length && inputEvent.group && - inputEvent.group === inputStack[inputStack.length - 1].group) { - events.push(inputStack.pop()); - } - // Push these popped events on the opposite stack. - for (let i = 0; i < events.length; i++) { - const event = events[i]; - outputStack.push(event); - } - events = eventUtils.filter(events, redo); - eventUtils.setRecordUndo(false); - try { + /** + * Undo or redo the previous action. + * @param {boolean} redo False if undo, true if redo. + */ + undo(redo) { + const inputStack = redo ? this.redoStack_ : this.undoStack_; + const outputStack = redo ? this.undoStack_ : this.redoStack_; + const inputEvent = inputStack.pop(); + if (!inputEvent) { + return; + } + let events = [inputEvent]; + // Do another undo/redo if the next one is of the same group. + while (inputStack.length && inputEvent.group && + inputEvent.group === inputStack[inputStack.length - 1].group) { + events.push(inputStack.pop()); + } + // Push these popped events on the opposite stack. for (let i = 0; i < events.length; i++) { const event = events[i]; - event.run(redo); + outputStack.push(event); + } + events = eventUtils.filter(events, redo); + eventUtils.setRecordUndo(false); + try { + for (let i = 0; i < events.length; i++) { + const event = events[i]; + event.run(redo); + } + } finally { + eventUtils.setRecordUndo(true); } - } finally { - eventUtils.setRecordUndo(true); } -}; -/** - * Clear the undo/redo stacks. - */ -Workspace.prototype.clearUndo = function() { - this.undoStack_.length = 0; - this.redoStack_.length = 0; - // Stop any events already in the firing queue from being undoable. - eventUtils.clearPendingUndo(); -}; + /** + * Clear the undo/redo stacks. + */ + clearUndo() { + this.undoStack_.length = 0; + this.redoStack_.length = 0; + // Stop any events already in the firing queue from being undoable. + eventUtils.clearPendingUndo(); + } -/** - * When something in this workspace changes, call a function. - * Note that there may be a few recent events already on the stack. Thus the - * new change listener might be called with events that occurred a few - * milliseconds before the change listener was added. - * @param {!Function} func Function to call. - * @return {!Function} Obsolete return value, ignore. - */ -Workspace.prototype.addChangeListener = function(func) { - this.listeners_.push(func); - return func; -}; + /** + * When something in this workspace changes, call a function. + * Note that there may be a few recent events already on the stack. Thus the + * new change listener might be called with events that occurred a few + * milliseconds before the change listener was added. + * @param {!Function} func Function to call. + * @return {!Function} Obsolete return value, ignore. + */ + addChangeListener(func) { + this.listeners_.push(func); + return func; + } -/** - * Stop listening for this workspace's changes. - * @param {!Function} func Function to stop calling. - */ -Workspace.prototype.removeChangeListener = function(func) { - arrayUtils.removeElem(this.listeners_, func); -}; + /** + * Stop listening for this workspace's changes. + * @param {!Function} func Function to stop calling. + */ + removeChangeListener(func) { + arrayUtils.removeElem(this.listeners_, func); + } -/** - * Fire a change event. - * @param {!Abstract} event Event to fire. - */ -Workspace.prototype.fireChangeListener = function(event) { - if (event.recordUndo) { - this.undoStack_.push(event); - this.redoStack_.length = 0; - while (this.undoStack_.length > this.MAX_UNDO && this.MAX_UNDO >= 0) { - this.undoStack_.shift(); + /** + * Fire a change event. + * @param {!Abstract} event Event to fire. + */ + fireChangeListener(event) { + if (event.recordUndo) { + this.undoStack_.push(event); + this.redoStack_.length = 0; + while (this.undoStack_.length > this.MAX_UNDO && this.MAX_UNDO >= 0) { + this.undoStack_.shift(); + } + } + for (let i = 0; i < this.listeners_.length; i++) { + const func = this.listeners_[i]; + func(event); } } - for (let i = 0; i < this.listeners_.length; i++) { - const func = this.listeners_[i]; - func(event); - } -}; -/** - * Find the block on this workspace with the specified ID. - * @param {string} id ID of block to find. - * @return {?Block} The sought after block, or null if not found. - */ -Workspace.prototype.getBlockById = function(id) { - return this.blockDB_[id] || null; -}; + /** + * Find the block on this workspace with the specified ID. + * @param {string} id ID of block to find. + * @return {?Block} The sought after block, or null if not found. + */ + getBlockById(id) { + return this.blockDB_[id] || null; + } -/** - * Set a block on this workspace with the specified ID. - * @param {string} id ID of block to set. - * @param {Block} block The block to set. - * @package - */ -Workspace.prototype.setBlockById = function(id, block) { - this.blockDB_[id] = block; -}; + /** + * Set a block on this workspace with the specified ID. + * @param {string} id ID of block to set. + * @param {Block} block The block to set. + * @package + */ + setBlockById(id, block) { + this.blockDB_[id] = block; + } -/** - * Delete a block off this workspace with the specified ID. - * @param {string} id ID of block to delete. - * @package - */ -Workspace.prototype.removeBlockById = function(id) { - delete this.blockDB_[id]; -}; + /** + * Delete a block off this workspace with the specified ID. + * @param {string} id ID of block to delete. + * @package + */ + removeBlockById(id) { + delete this.blockDB_[id]; + } -/** - * Find the comment on this workspace with the specified ID. - * @param {string} id ID of comment to find. - * @return {?WorkspaceComment} The sought after comment, or null if not - * found. - * @package - */ -Workspace.prototype.getCommentById = function(id) { - return this.commentDB_[id] || null; -}; + /** + * Find the comment on this workspace with the specified ID. + * @param {string} id ID of comment to find. + * @return {?WorkspaceComment} The sought after comment, or null if not + * found. + * @package + */ + getCommentById(id) { + return this.commentDB_[id] || null; + } -/** - * Checks whether all value and statement inputs in the workspace are filled - * with blocks. - * @param {boolean=} opt_shadowBlocksAreFilled An optional argument controlling - * whether shadow blocks are counted as filled. Defaults to true. - * @return {boolean} True if all inputs are filled, false otherwise. - */ -Workspace.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { - const blocks = this.getTopBlocks(false); - for (let i = 0; i < blocks.length; i++) { - const block = blocks[i]; - if (!block.allInputsFilled(opt_shadowBlocksAreFilled)) { - return false; + /** + * Checks whether all value and statement inputs in the workspace are filled + * with blocks. + * @param {boolean=} opt_shadowBlocksAreFilled An optional argument controlling + * whether shadow blocks are counted as filled. Defaults to true. + * @return {boolean} True if all inputs are filled, false otherwise. + */ + allInputsFilled(opt_shadowBlocksAreFilled) { + const blocks = this.getTopBlocks(false); + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i]; + if (!block.allInputsFilled(opt_shadowBlocksAreFilled)) { + return false; + } } + return true; } - return true; -}; -/** - * Return the variable map that contains "potential" variables. - * These exist in the flyout but not in the workspace. - * @return {?VariableMap} The potential variable map. - * @package - */ -Workspace.prototype.getPotentialVariableMap = function() { - return this.potentialVariableMap_; -}; + /** + * Return the variable map that contains "potential" variables. + * These exist in the flyout but not in the workspace. + * @return {?VariableMap} The potential variable map. + * @package + */ + getPotentialVariableMap() { + return this.potentialVariableMap_; + } -/** - * Create and store the potential variable map for this workspace. - * @package - */ -Workspace.prototype.createPotentialVariableMap = function() { - this.potentialVariableMap_ = new VariableMap(this); -}; + /** + * Create and store the potential variable map for this workspace. + * @package + */ + createPotentialVariableMap() { + this.potentialVariableMap_ = new VariableMap(this); + } -/** - * Return the map of all variables on the workspace. - * @return {!VariableMap} The variable map. - */ -Workspace.prototype.getVariableMap = function() { - return this.variableMap_; -}; + /** + * Return the map of all variables on the workspace. + * @return {!VariableMap} The variable map. + */ + getVariableMap() { + return this.variableMap_; + } -/** - * Set the map of all variables on the workspace. - * @param {!VariableMap} variableMap The variable map. - * @package - */ -Workspace.prototype.setVariableMap = function(variableMap) { - this.variableMap_ = variableMap; -}; + /** + * Set the map of all variables on the workspace. + * @param {!VariableMap} variableMap The variable map. + * @package + */ + setVariableMap(variableMap) { + this.variableMap_ = variableMap; + } -/** - * Find the workspace with the specified ID. - * @param {string} id ID of workspace to find. - * @return {?Workspace} The sought after workspace or null if not found. - */ -Workspace.getById = function(id) { - return WorkspaceDB_[id] || null; + /** + * Find the workspace with the specified ID. + * @param {string} id ID of workspace to find. + * @return {?Workspace} The sought after workspace or null if not found. + */ + static getById(id) { + return WorkspaceDB_[id] || null; + } + + /** + * Find all workspaces. + * @return {!Array} Array of workspaces. + */ + static getAll() { + const workspaces = []; + for (const workspaceId in WorkspaceDB_) { + workspaces.push(WorkspaceDB_[workspaceId]); + } + return workspaces; + } }; /** - * Find all workspaces. - * @return {!Array} Array of workspaces. + * Angle away from the horizontal to sweep for blocks. Order of execution is + * generally top to bottom, but a small angle changes the scan to give a bit of + * a left to right bias (reversed in RTL). Units are in degrees. + * See: https://tvtropes.org/pmwiki/pmwiki.php/Main/DiagonalBilling */ -Workspace.getAll = function() { - const workspaces = []; - for (const workspaceId in WorkspaceDB_) { - workspaces.push(WorkspaceDB_[workspaceId]); - } - return workspaces; -}; +Workspace.SCAN_ANGLE = 3; exports.Workspace = Workspace; From dab85b823c7134924d5339a58723ba8a28089e5e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 3 Mar 2022 19:50:49 +0000 Subject: [PATCH 2/6] fix: cleanup from conversion script --- core/workspace.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/workspace.js b/core/workspace.js index 9d91a89ebe7..928e8056a67 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -53,11 +53,11 @@ const WorkspaceDB_ = Object.create(null); /** * Class for a workspace. This is a data structure that contains blocks. * There is no UI, and can be created headlessly. + * @implements {IASTNodeLocation} */ -var Workspace = class { +class Workspace { /** * @param {!Options=} opt_options Dictionary of options. - * @implements {IASTNodeLocation} * @alias Blockly.Workspace */ constructor(opt_options) { @@ -452,9 +452,8 @@ var Workspace = class { * defaults to the empty string, which is a specific type. * @return {?VariableModel} The variable with the given name. */ - - // TODO (#1559): Possibly delete this function after resolving #1559. getVariable(name, opt_type) { + // TODO (#1559): Possibly delete this function after resolving #1559. return this.variableMap_.getVariable(name, opt_type); } @@ -808,7 +807,7 @@ var Workspace = class { } return workspaces; } -}; +} /** * Angle away from the horizontal to sweep for blocks. Order of execution is From 22ee39788144a853289d7058a8f57145696279f8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 3 Mar 2022 22:06:48 +0000 Subject: [PATCH 3/6] fix: make debug build happy --- core/blockly.js | 3 ++- core/events/utils.js | 5 ++++- core/field.js | 9 ++++++--- core/gesture.js | 5 ++++- core/inject.js | 4 ++-- core/mutator.js | 6 ++---- core/procedures.js | 4 ++-- core/serialization/workspaces.js | 5 +++-- core/theme_manager.js | 4 ++-- core/toolbox/toolbox.js | 4 ++-- core/variables.js | 11 ++++++++--- core/variables_dynamic.js | 4 +++- core/workspace.js | 13 +++++++++++++ core/workspace_svg.js | 23 +++++------------------ core/xml.js | 23 +++++++++++++---------- tests/deps.js | 2 +- 16 files changed, 72 insertions(+), 53 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index e393ebc4686..121dd1e5413 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -307,7 +307,8 @@ exports.svgResize = common.svgResize; * @alias Blockly.hideChaff */ const hideChaff = function(opt_onlyClosePopups) { - common.getMainWorkspace().hideChaff(opt_onlyClosePopups); + /** @type {!WorkspaceSvg} */(common.getMainWorkspace()) + .hideChaff(opt_onlyClosePopups); }; exports.hideChaff = hideChaff; diff --git a/core/events/utils.js b/core/events/utils.js index cf76736234a..d69dc50fbcf 100644 --- a/core/events/utils.js +++ b/core/events/utils.js @@ -37,6 +37,8 @@ const {CommentMove} = goog.requireType('Blockly.Events.CommentMove'); const {ViewportChange} = goog.requireType('Blockly.Events.ViewportChange'); /* eslint-disable-next-line no-unused-vars */ const {Workspace} = goog.requireType('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ +const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg'); /** @@ -561,7 +563,8 @@ const disableOrphans = function(event) { return; } const {Workspace} = goog.module.get('Blockly.Workspace'); - const eventWorkspace = Workspace.getById(blockEvent.workspaceId); + const eventWorkspace = + /** @type {!WorkspaceSvg} */(Workspace.getById(blockEvent.workspaceId)); let block = eventWorkspace.getBlockById(blockEvent.blockId); if (block) { // Changing blocks as part of this event shouldn't be undoable. diff --git a/core/field.js b/core/field.js index 7b8daf0dea0..7b6d5d75ee8 100644 --- a/core/field.js +++ b/core/field.js @@ -309,7 +309,8 @@ class Field { if (!this.constants_ && this.sourceBlock_ && this.sourceBlock_.workspace && this.sourceBlock_.workspace.rendered) { this.constants_ = - this.sourceBlock_.workspace.getRenderer().getConstants(); + /** @type {!WorkspaceSvg} */(this.sourceBlock_.workspace) + .getRenderer().getConstants(); } return this.constants_; } @@ -834,7 +835,8 @@ class Field { // - Webkit / Blink: fill-box / object bounding box // - Gecko / Triden / EdgeHTML: stroke-box const bBox = this.sourceBlock_.getHeightWidth(); - const scale = this.sourceBlock_.workspace.scale; + const scale = + /** @type {!WorkspaceSvg} */(this.sourceBlock_.workspace).scale; xy = this.getAbsoluteXY_(); scaledWidth = bBox.width * scale; scaledHeight = bBox.height * scale; @@ -1072,7 +1074,8 @@ class Field { if (!this.sourceBlock_ || !this.sourceBlock_.workspace) { return; } - const gesture = this.sourceBlock_.workspace.getGesture(e); + const gesture = + /** @type {!WorkspaceSvg} */(this.sourceBlock_.workspace).getGesture(e); if (gesture) { gesture.setStartField(this); } diff --git a/core/gesture.js b/core/gesture.js index 63e27b16ae8..5a9f52275d5 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -1012,7 +1012,10 @@ class Gesture { static inProgress() { const workspaces = Workspace.getAll(); for (let i = 0, workspace; (workspace = workspaces[i]); i++) { - if (workspace.currentGesture_) { + // Not actually necessarily a WorkspaceSvg, but it doesn't matter b/c + // we're just checking if the property exists. Theoretically we would + // want to use instanceof, but that causes a circular dependency. + if (/** @type {!WorkspaceSvg} */(workspace).currentGesture_) { return true; } } diff --git a/core/inject.js b/core/inject.js index ef6c0ed88b0..6a03391fe27 100644 --- a/core/inject.js +++ b/core/inject.js @@ -274,7 +274,7 @@ const init = function(mainWorkspace) { // TODO (https://github.com/google/blockly/issues/1998) handle cases where there // are multiple workspaces and non-main workspaces are able to accept input. const onKeyDown = function(e) { - const mainWorkspace = common.getMainWorkspace(); + const mainWorkspace = /** @type {!WorkspaceSvg} */(common.getMainWorkspace()); if (!mainWorkspace) { return; } @@ -337,7 +337,7 @@ const bindDocumentEvents = function() { /** * Load sounds for the given workspace. * @param {string} pathToMedia The path to the media directory. - * @param {!Workspace} workspace The workspace to load sounds for. + * @param {!WorkspaceSvg} workspace The workspace to load sounds for. */ const loadSounds = function(pathToMedia, workspace) { const audioMgr = workspace.getAudioManager(); diff --git a/core/mutator.js b/core/mutator.js index 9b6b2c80613..ef6af18ea2a 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -40,8 +40,6 @@ const {Icon} = goog.require('Blockly.Icon'); const {Options} = goog.require('Blockly.Options'); const {Svg} = goog.require('Blockly.utils.Svg'); const {WorkspaceSvg} = goog.require('Blockly.WorkspaceSvg'); -/* eslint-disable-next-line no-unused-vars */ -const {Workspace} = goog.requireType('Blockly.Workspace'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BubbleOpen'); @@ -550,8 +548,8 @@ class Mutator extends Icon { /** * Get the parent workspace of a workspace that is inside a mutator, taking * into account whether it is a flyout. - * @param {Workspace} workspace The workspace that is inside a mutator. - * @return {?Workspace} The mutator's parent workspace or null. + * @param {WorkspaceSvg} workspace The workspace that is inside a mutator. + * @return {?WorkspaceSvg} The mutator's parent workspace or null. * @public */ static findParentWs(workspace) { diff --git a/core/procedures.js b/core/procedures.js index d7041f46db1..f15a72b013d 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -210,7 +210,7 @@ exports.rename = rename; /** * Construct the blocks required by the flyout for the procedure category. - * @param {!Workspace} workspace The workspace containing procedures. + * @param {!WorkspaceSvg} workspace The workspace containing procedures. * @return {!Array} Array of XML block elements. * @alias Blockly.Procedures.flyoutCategory */ @@ -297,7 +297,7 @@ exports.flyoutCategory = flyoutCategory; /** * Updates the procedure mutator's flyout so that the arg block is not a * duplicate of another arg. - * @param {!Workspace} workspace The procedure mutator's workspace. This + * @param {!WorkspaceSvg} workspace The procedure mutator's workspace. This * workspace's flyout is what is being updated. */ const updateMutatorFlyout = function(workspace) { diff --git a/core/serialization/workspaces.js b/core/serialization/workspaces.js index d3e1c08d915..c0ca5d75740 100644 --- a/core/serialization/workspaces.js +++ b/core/serialization/workspaces.js @@ -22,6 +22,7 @@ const eventUtils = goog.require('Blockly.Events.utils'); const registry = goog.require('Blockly.registry'); // eslint-disable-next-line no-unused-vars const {Workspace} = goog.require('Blockly.Workspace'); +const {WorkspaceSvg} = goog.require('Blockly.WorkspaceSvg'); /** @@ -70,7 +71,7 @@ const load = function(state, workspace, {recordUndo = false} = {}) { } dom.startTextWidthCache(); - if (workspace.setResizesEnabled) { + if (workspace instanceof WorkspaceSvg) { workspace.setResizesEnabled(false); } @@ -89,7 +90,7 @@ const load = function(state, workspace, {recordUndo = false} = {}) { } } - if (workspace.setResizesEnabled) { + if (workspace instanceof WorkspaceSvg) { workspace.setResizesEnabled(true); } dom.stopTextWidthCache(); diff --git a/core/theme_manager.js b/core/theme_manager.js index 8042648cf69..fefbba9d5cb 100644 --- a/core/theme_manager.js +++ b/core/theme_manager.js @@ -97,7 +97,7 @@ class ThemeManager { // Refresh all subscribed workspaces. for (let i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) { - workspace.refreshTheme(); + /** @type {!WorkspaceSvg} */(workspace).refreshTheme(); } // Refresh all registered Blockly UI components. @@ -112,7 +112,7 @@ class ThemeManager { } for (const workspace of this.subscribedWorkspaces_) { - workspace.hideChaff(); + /** @type {!WorkspaceSvg} */ (workspace).hideChaff(); } } diff --git a/core/toolbox/toolbox.js b/core/toolbox/toolbox.js index 8219099f40c..1765976836d 100644 --- a/core/toolbox/toolbox.js +++ b/core/toolbox/toolbox.js @@ -318,7 +318,7 @@ class Toolbox extends DeleteArea { onClick_(e) { if (browserEvents.isRightButton(e) || e.target === this.HtmlDiv) { // Close flyout. - common.getMainWorkspace().hideChaff(false); + /** @type {!WorkspaceSvg} */(common.getMainWorkspace()).hideChaff(false); } else { const targetElement = e.target; const itemId = targetElement.getAttribute('id'); @@ -330,7 +330,7 @@ class Toolbox extends DeleteArea { } } // Just close popups. - common.getMainWorkspace().hideChaff(true); + /** @type {!WorkspaceSvg} */(common.getMainWorkspace()).hideChaff(true); } Touch.clearTouchIdentifier(); // Don't block future drags. } diff --git a/core/variables.js b/core/variables.js index c3bb62f6f19..33018e5f3fc 100644 --- a/core/variables.js +++ b/core/variables.js @@ -23,6 +23,8 @@ const {Msg} = goog.require('Blockly.Msg'); const {VariableModel} = goog.require('Blockly.VariableModel'); /* eslint-disable-next-line no-unused-vars */ const {Workspace} = goog.requireType('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ +const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg'); /** * String for use in the "custom" attribute of a category in toolbox XML. @@ -118,7 +120,7 @@ exports.allDeveloperVariables = allDeveloperVariables; /** * Construct the elements (blocks and button) required by the flyout for the * variable category. - * @param {!Workspace} workspace The workspace containing variables. + * @param {!WorkspaceSvg} workspace The workspace containing variables. * @return {!Array} Array of XML elements. * @alias Blockly.Variables.flyoutCategory */ @@ -526,8 +528,11 @@ const createVariable = function(workspace, id, opt_name, opt_type) { const potentialVariableMap = workspace.getPotentialVariableMap(); // Variables without names get uniquely named for this workspace. if (!opt_name) { - const ws = workspace.isFlyout ? workspace.targetWorkspace : workspace; - opt_name = exports.generateUniqueName(ws); + const ws = + /** @type {!Workspace} */ (workspace.isFlyout ? + /** @type {!WorkspaceSvg} */(workspace).targetWorkspace : + workspace); + opt_name = generateUniqueName(ws); } // Create a potential variable if in the flyout. diff --git a/core/variables_dynamic.js b/core/variables_dynamic.js index b84f4c8c91b..9006ad5b325 100644 --- a/core/variables_dynamic.js +++ b/core/variables_dynamic.js @@ -24,6 +24,8 @@ const {Msg} = goog.require('Blockly.Msg'); const {VariableModel} = goog.require('Blockly.VariableModel'); /* eslint-disable-next-line no-unused-vars */ const {Workspace} = goog.requireType('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ +const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg'); /** @@ -59,7 +61,7 @@ exports.onCreateVariableButtonClick_Colour = colourButtonClickHandler; /** * Construct the elements (blocks and button) required by the flyout for the * variable category. - * @param {!Workspace} workspace The workspace containing variables. + * @param {!WorkspaceSvg} workspace The workspace containing variables. * @return {!Array} Array of XML elements. * @alias Blockly.VariablesDynamic.flyoutCategory */ diff --git a/core/workspace.js b/core/workspace.js index 928e8056a67..b8675b1ada8 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -80,6 +80,19 @@ class Workspace { */ this.rendered = false; + /** + * Is this workspace the surface for a flyout? + * @type {boolean} + */ + this.isFlyout = false; + + /** + * Is this workspace the surface for a mutator? + * @type {boolean} + * @package + */ + this.isMutator = false; + /** * Returns `true` if the workspace is currently in the process of a bulk * clear. diff --git a/core/workspace_svg.js b/core/workspace_svg.js index f95e61eb3b6..61687144b3e 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -156,19 +156,6 @@ class WorkspaceSvg extends Workspace { */ this.isVisible_ = true; - /** - * Is this workspace the surface for a flyout? - * @type {boolean} - */ - this.isFlyout = false; - - /** - * Is this workspace the surface for a mutator? - * @type {boolean} - * @package - */ - this.isMutator = false; - /** * Whether this workspace has resizes enabled. * Disable during batch operations for a performance improvement. @@ -321,7 +308,7 @@ class WorkspaceSvg extends Workspace { /** * The current gesture in progress on this workspace, if any. * @type {TouchGesture} - * @private + * @package */ this.currentGesture_ = null; @@ -484,7 +471,7 @@ class WorkspaceSvg extends Workspace { /** * Map from function names to callbacks, for deciding what to do when a * custom toolbox category is opened. - * @type {!Object} * @private */ @@ -2578,8 +2565,8 @@ class WorkspaceSvg extends Workspace { * custom toolbox categories in this workspace. See the variable and * procedure categories as an example. * @param {string} key The name to use to look up this function. - * @param {function(!Workspace): !toolbox.FlyoutDefinition} func The function - * to call when the given toolbox category is opened. + * @param {function(!WorkspaceSvg): !toolbox.FlyoutDefinition} func The + * function to call when the given toolbox category is opened. */ registerToolboxCategoryCallback(key, func) { if (typeof func !== 'function') { @@ -2592,7 +2579,7 @@ class WorkspaceSvg extends Workspace { * Get the callback function associated with a given key, for populating * custom toolbox categories in this workspace. * @param {string} key The name to use to look up the function. - * @return {?function(!Workspace): !toolbox.FlyoutDefinition} The function + * @return {?function(!WorkspaceSvg): !toolbox.FlyoutDefinition} The function * corresponding to the given key for this workspace, or null if no * function is registered. */ diff --git a/core/xml.js b/core/xml.js index 217b910f03c..eee7c68f61d 100644 --- a/core/xml.js +++ b/core/xml.js @@ -398,7 +398,7 @@ exports.textToDom = textToDom; * Clear the given workspace then decode an XML DOM and * create blocks on the workspace. * @param {!Element} xml XML DOM. - * @param {!Workspace} workspace The workspace. + * @param {!WorkspaceSvg} workspace The workspace. * @return {!Array} An array containing new block IDs. * @alias Blockly.Xml.clearWorkspaceAndLoadFromXml */ @@ -445,8 +445,9 @@ const domToWorkspace = function(xml, workspace) { } // Disable workspace resizes as an optimization. - if (workspace.setResizesEnabled) { - workspace.setResizesEnabled(false); + // Assume it is rendered so we can check. + if (/** @type {!WorkspaceSvg} */(workspace).setResizesEnabled) { + /** @type {!WorkspaceSvg} */(workspace).setResizesEnabled(false); } let variablesFirst = true; try { @@ -515,8 +516,8 @@ const domToWorkspace = function(xml, workspace) { dom.stopTextWidthCache(); } // Re-enable workspace resizing. - if (workspace.setResizesEnabled) { - workspace.setResizesEnabled(true); + if (/** @type {!WorkspaceSvg} */(workspace).setResizesEnabled) { + /** @type {!WorkspaceSvg} */(workspace).setResizesEnabled(true); } eventUtils.fire(new (eventUtils.get(eventUtils.FINISHED_LOADING))(workspace)); return newBlockIds; @@ -532,12 +533,14 @@ exports.domToWorkspace = domToWorkspace; * @alias Blockly.Xml.appendDomToWorkspace */ const appendDomToWorkspace = function(xml, workspace) { - let bbox; // Bounding box of the current blocks. - // First check if we have a workspaceSvg, otherwise the blocks have no shape + // First check if we have a WorkspaceSvg, otherwise the blocks have no shape // and the position does not matter. - if (Object.prototype.hasOwnProperty.call(workspace, 'scale')) { - bbox = workspace.getBlocksBoundingBox(); + // Assume it is rendered so we can check. + if (!/** @type {!WorkspaceSvg} */(workspace).getBlocksBoundingBox) { + return domToWorkspace(xml, workspace); } + + const bbox = /** @type {!WorkspaceSvg} */(workspace).getBlocksBoundingBox(); // Load the new blocks into the workspace and get the IDs of the new blocks. const newBlockIds = domToWorkspace(xml, workspace); if (bbox && bbox.top !== bbox.bottom) { // check if any previous block @@ -622,7 +625,7 @@ const domToBlock = function(xmlBlock, workspace) { topBlockSvg.updateDisabled(); // Allow the scrollbars to resize and move based on the new contents. // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing. - workspace.resizeContents(); + /** @type {!WorkspaceSvg} */(workspace).resizeContents(); } else { const blocks = topBlock.getDescendants(false); for (let i = blocks.length - 1; i >= 0; i--) { diff --git a/tests/deps.js b/tests/deps.js index ef4b6e87f34..c1ab24e8260 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -209,7 +209,7 @@ goog.addDependency('../../core/serialization/exceptions.js', ['Blockly.serializa goog.addDependency('../../core/serialization/priorities.js', ['Blockly.serialization.priorities'], [], {'module': 'goog'}); goog.addDependency('../../core/serialization/registry.js', ['Blockly.serialization.registry'], ['Blockly.registry'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/serialization/variables.js', ['Blockly.serialization.variables'], ['Blockly.serialization.ISerializer', 'Blockly.serialization.priorities', 'Blockly.serialization.registry'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/serialization/workspaces.js', ['Blockly.serialization.workspaces'], ['Blockly.Events.utils', 'Blockly.Workspace', 'Blockly.registry', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/serialization/workspaces.js', ['Blockly.serialization.workspaces'], ['Blockly.Events.utils', 'Blockly.Workspace', 'Blockly.WorkspaceSvg', 'Blockly.registry', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly.Gesture', 'Blockly.ShortcutRegistry', 'Blockly.clipboard', 'Blockly.common', 'Blockly.utils.KeyCodes'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/shortcut_registry.js', ['Blockly.ShortcutRegistry'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/sprites.js', ['Blockly.sprite'], [], {'lang': 'es6', 'module': 'goog'}); From 6327672c54e7ff115ab152555200248fb6c11e76 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 3 Mar 2022 22:15:13 +0000 Subject: [PATCH 4/6] fix: tests --- core/variables.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/variables.js b/core/variables.js index 33018e5f3fc..03fdbdc6778 100644 --- a/core/variables.js +++ b/core/variables.js @@ -532,7 +532,8 @@ const createVariable = function(workspace, id, opt_name, opt_type) { /** @type {!Workspace} */ (workspace.isFlyout ? /** @type {!WorkspaceSvg} */(workspace).targetWorkspace : workspace); - opt_name = generateUniqueName(ws); + // Must call version on exports to allow for mocking in tests. See #5321 + opt_name = exports.generateUniqueName(ws); } // Create a potential variable if in the flyout. From 1791e35c40186c3876d50038374e9526dad642db Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 3 Mar 2022 22:28:35 +0000 Subject: [PATCH 5/6] fix: format --- core/blockly.js | 2 +- core/events/utils.js | 3 ++- core/field.js | 10 +++++--- core/gesture.js | 2 +- core/inject.js | 3 ++- core/theme_manager.js | 2 +- core/toolbox/toolbox.js | 4 +-- core/variables.js | 5 ++-- core/workspace.js | 54 ++++++++++++++++++++++------------------- core/xml.js | 14 +++++------ 10 files changed, 54 insertions(+), 45 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index 121dd1e5413..001a5cb79ec 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -307,7 +307,7 @@ exports.svgResize = common.svgResize; * @alias Blockly.hideChaff */ const hideChaff = function(opt_onlyClosePopups) { - /** @type {!WorkspaceSvg} */(common.getMainWorkspace()) + /** @type {!WorkspaceSvg} */ (common.getMainWorkspace()) .hideChaff(opt_onlyClosePopups); }; exports.hideChaff = hideChaff; diff --git a/core/events/utils.js b/core/events/utils.js index d69dc50fbcf..dfd2d4f06d7 100644 --- a/core/events/utils.js +++ b/core/events/utils.js @@ -564,7 +564,8 @@ const disableOrphans = function(event) { } const {Workspace} = goog.module.get('Blockly.Workspace'); const eventWorkspace = - /** @type {!WorkspaceSvg} */(Workspace.getById(blockEvent.workspaceId)); + /** @type {!WorkspaceSvg} */ ( + Workspace.getById(blockEvent.workspaceId)); let block = eventWorkspace.getBlockById(blockEvent.blockId); if (block) { // Changing blocks as part of this event shouldn't be undoable. diff --git a/core/field.js b/core/field.js index 7b6d5d75ee8..90c28a9d5f8 100644 --- a/core/field.js +++ b/core/field.js @@ -309,8 +309,9 @@ class Field { if (!this.constants_ && this.sourceBlock_ && this.sourceBlock_.workspace && this.sourceBlock_.workspace.rendered) { this.constants_ = - /** @type {!WorkspaceSvg} */(this.sourceBlock_.workspace) - .getRenderer().getConstants(); + /** @type {!WorkspaceSvg} */ (this.sourceBlock_.workspace) + .getRenderer() + .getConstants(); } return this.constants_; } @@ -836,7 +837,7 @@ class Field { // - Gecko / Triden / EdgeHTML: stroke-box const bBox = this.sourceBlock_.getHeightWidth(); const scale = - /** @type {!WorkspaceSvg} */(this.sourceBlock_.workspace).scale; + /** @type {!WorkspaceSvg} */ (this.sourceBlock_.workspace).scale; xy = this.getAbsoluteXY_(); scaledWidth = bBox.width * scale; scaledHeight = bBox.height * scale; @@ -1075,7 +1076,8 @@ class Field { return; } const gesture = - /** @type {!WorkspaceSvg} */(this.sourceBlock_.workspace).getGesture(e); + /** @type {!WorkspaceSvg} */ (this.sourceBlock_.workspace) + .getGesture(e); if (gesture) { gesture.setStartField(this); } diff --git a/core/gesture.js b/core/gesture.js index 5a9f52275d5..f310c0ba160 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -1015,7 +1015,7 @@ class Gesture { // Not actually necessarily a WorkspaceSvg, but it doesn't matter b/c // we're just checking if the property exists. Theoretically we would // want to use instanceof, but that causes a circular dependency. - if (/** @type {!WorkspaceSvg} */(workspace).currentGesture_) { + if (/** @type {!WorkspaceSvg} */ (workspace).currentGesture_) { return true; } } diff --git a/core/inject.js b/core/inject.js index 6a03391fe27..6a30824b2ed 100644 --- a/core/inject.js +++ b/core/inject.js @@ -274,7 +274,8 @@ const init = function(mainWorkspace) { // TODO (https://github.com/google/blockly/issues/1998) handle cases where there // are multiple workspaces and non-main workspaces are able to accept input. const onKeyDown = function(e) { - const mainWorkspace = /** @type {!WorkspaceSvg} */(common.getMainWorkspace()); + const mainWorkspace = + /** @type {!WorkspaceSvg} */ (common.getMainWorkspace()); if (!mainWorkspace) { return; } diff --git a/core/theme_manager.js b/core/theme_manager.js index fefbba9d5cb..01bc86f3894 100644 --- a/core/theme_manager.js +++ b/core/theme_manager.js @@ -97,7 +97,7 @@ class ThemeManager { // Refresh all subscribed workspaces. for (let i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) { - /** @type {!WorkspaceSvg} */(workspace).refreshTheme(); + /** @type {!WorkspaceSvg} */ (workspace).refreshTheme(); } // Refresh all registered Blockly UI components. diff --git a/core/toolbox/toolbox.js b/core/toolbox/toolbox.js index 1765976836d..9e10c927340 100644 --- a/core/toolbox/toolbox.js +++ b/core/toolbox/toolbox.js @@ -318,7 +318,7 @@ class Toolbox extends DeleteArea { onClick_(e) { if (browserEvents.isRightButton(e) || e.target === this.HtmlDiv) { // Close flyout. - /** @type {!WorkspaceSvg} */(common.getMainWorkspace()).hideChaff(false); + /** @type {!WorkspaceSvg} */ (common.getMainWorkspace()).hideChaff(false); } else { const targetElement = e.target; const itemId = targetElement.getAttribute('id'); @@ -330,7 +330,7 @@ class Toolbox extends DeleteArea { } } // Just close popups. - /** @type {!WorkspaceSvg} */(common.getMainWorkspace()).hideChaff(true); + /** @type {!WorkspaceSvg} */ (common.getMainWorkspace()).hideChaff(true); } Touch.clearTouchIdentifier(); // Don't block future drags. } diff --git a/core/variables.js b/core/variables.js index 03fdbdc6778..68b7007a144 100644 --- a/core/variables.js +++ b/core/variables.js @@ -529,8 +529,9 @@ const createVariable = function(workspace, id, opt_name, opt_type) { // Variables without names get uniquely named for this workspace. if (!opt_name) { const ws = - /** @type {!Workspace} */ (workspace.isFlyout ? - /** @type {!WorkspaceSvg} */(workspace).targetWorkspace : + /** @type {!Workspace} */ ( + workspace.isFlyout ? + /** @type {!WorkspaceSvg} */ (workspace).targetWorkspace : workspace); // Must call version on exports to allow for mocking in tests. See #5321 opt_name = exports.generateUniqueName(ws); diff --git a/core/workspace.js b/core/workspace.js index b8675b1ada8..7c05f0097cd 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -102,8 +102,8 @@ class Workspace { this.isClearing = false; /** - * Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets - * it to unlimited. + * Maximum number of undo events in stack. `0` turns off undo, `Infinity` + * sets it to unlimited. * @type {number} */ this.MAX_UNDO = 1024; @@ -164,9 +164,9 @@ class Workspace { this.typedBlocksDB_ = Object.create(null); /** - * A map from variable type to list of variable names. The lists contain all - * of the named variables in the workspace, including variables - * that are not currently in use. + * A map from variable type to list of variable names. The lists contain + * all of the named variables in the workspace, including variables that are + * not currently in use. * @type {!VariableMap} * @private */ @@ -174,8 +174,8 @@ class Workspace { /** * Blocks in the flyout can refer to variables that don't exist in the main - * workspace. For instance, the "get item in list" block refers to an "item" - * variable regardless of whether the variable has been created yet. + * workspace. For instance, the "get item in list" block refers to an + * "item" variable regardless of whether the variable has been created yet. * A FieldVariable must always refer to a VariableModel. We reconcile * these by tracking "potential" variables in the flyout. These variables * become real when references to them are dragged into the main workspace. @@ -204,7 +204,8 @@ class Workspace { * compare. * @param {!Block | !WorkspaceComment} b The second object to * compare. - * @return {number} The comparison value. This tells Array.sort() how to change + * @return {number} The comparison value. This tells Array.sort() how to + * change * object a's index. * @private */ @@ -307,8 +308,8 @@ class Workspace { addTopComment(comment) { this.topComments_.push(comment); - // Note: If the comment database starts to hold block comments, this may need - // to move to a separate function. + // Note: If the comment database starts to hold block comments, this may + // need to move to a separate function. if (this.commentDB_[comment.id]) { console.warn( 'Overriding an existing comment on this workspace, with id "' + @@ -328,8 +329,8 @@ class Workspace { 'Comment not present in workspace\'s list of top-most ' + 'comments.'); } - // Note: If the comment database starts to hold block comments, this may need - // to move to a separate function. + // Note: If the comment database starts to hold block comments, this may + // need to move to a separate function. delete this.commentDB_[comment.id]; } @@ -376,8 +377,8 @@ class Workspace { } } - // Insertion markers exist on the workspace for rendering reasons, but aren't - // "real" blocks from a developer perspective. + // Insertion markers exist on the workspace for rendering reasons, but + // aren't "real" blocks from a developer perspective. const filtered = blocks.filter(function(block) { return !block.isInsertionMarker(); }); @@ -430,10 +431,10 @@ class Workspace { * @param {string} name The name of the variable. This must be unique across * variables and procedures. * @param {?string=} opt_type The type of the variable like 'int' or 'string'. - * Does not need to be unique. Field_variable can filter variables based on - * their type. This will default to '' which is a specific type. - * @param {?string=} opt_id The unique ID of the variable. This will default to - * a UUID. + * Does not need to be unique. Field_variable can filter variables based + * on their type. This will default to '' which is a specific type. + * @param {?string=} opt_id The unique ID of the variable. This will default + * to a UUID. * @return {!VariableModel} The newly created variable. */ createVariable(name, opt_type, opt_id) { @@ -459,7 +460,8 @@ class Workspace { } /** - * Find the variable by the given name and return it. Return null if not found. + * Find the variable by the given name and return it. Return null if not + * found. * @param {string} name The name to check for. * @param {string=} opt_type The type of the variable. If not provided it * defaults to the empty string, which is a specific type. @@ -573,10 +575,11 @@ class Workspace { /** * Check if there is remaining capacity for blocks of the given counts to be - * created. If the total number of blocks represented by the map is more than - * the total remaining capacity, it returns false. If a type count is more - * than the remaining capacity for that type, it returns false. - * @param {!Object} typeCountsMap A map of types to counts (usually representing + * created. If the total number of blocks represented by the map is more + * than the total remaining capacity, it returns false. If a type count is + * more than the remaining capacity for that type, it returns false. + * @param {!Object} typeCountsMap A map of types to counts (usually + * representing * blocks to be created). * @return {boolean} True if there is capacity for the given map, * false otherwise. @@ -750,8 +753,9 @@ class Workspace { /** * Checks whether all value and statement inputs in the workspace are filled * with blocks. - * @param {boolean=} opt_shadowBlocksAreFilled An optional argument controlling - * whether shadow blocks are counted as filled. Defaults to true. + * @param {boolean=} opt_shadowBlocksAreFilled An optional argument + * controlling whether shadow blocks are counted as filled. Defaults to + * true. * @return {boolean} True if all inputs are filled, false otherwise. */ allInputsFilled(opt_shadowBlocksAreFilled) { diff --git a/core/xml.js b/core/xml.js index eee7c68f61d..17c61eeed83 100644 --- a/core/xml.js +++ b/core/xml.js @@ -446,8 +446,8 @@ const domToWorkspace = function(xml, workspace) { // Disable workspace resizes as an optimization. // Assume it is rendered so we can check. - if (/** @type {!WorkspaceSvg} */(workspace).setResizesEnabled) { - /** @type {!WorkspaceSvg} */(workspace).setResizesEnabled(false); + if (/** @type {!WorkspaceSvg} */ (workspace).setResizesEnabled) { + /** @type {!WorkspaceSvg} */ (workspace).setResizesEnabled(false); } let variablesFirst = true; try { @@ -516,8 +516,8 @@ const domToWorkspace = function(xml, workspace) { dom.stopTextWidthCache(); } // Re-enable workspace resizing. - if (/** @type {!WorkspaceSvg} */(workspace).setResizesEnabled) { - /** @type {!WorkspaceSvg} */(workspace).setResizesEnabled(true); + if (/** @type {!WorkspaceSvg} */ (workspace).setResizesEnabled) { + /** @type {!WorkspaceSvg} */ (workspace).setResizesEnabled(true); } eventUtils.fire(new (eventUtils.get(eventUtils.FINISHED_LOADING))(workspace)); return newBlockIds; @@ -536,11 +536,11 @@ const appendDomToWorkspace = function(xml, workspace) { // First check if we have a WorkspaceSvg, otherwise the blocks have no shape // and the position does not matter. // Assume it is rendered so we can check. - if (!/** @type {!WorkspaceSvg} */(workspace).getBlocksBoundingBox) { + if (!/** @type {!WorkspaceSvg} */ (workspace).getBlocksBoundingBox) { return domToWorkspace(xml, workspace); } - const bbox = /** @type {!WorkspaceSvg} */(workspace).getBlocksBoundingBox(); + const bbox = /** @type {!WorkspaceSvg} */ (workspace).getBlocksBoundingBox(); // Load the new blocks into the workspace and get the IDs of the new blocks. const newBlockIds = domToWorkspace(xml, workspace); if (bbox && bbox.top !== bbox.bottom) { // check if any previous block @@ -625,7 +625,7 @@ const domToBlock = function(xmlBlock, workspace) { topBlockSvg.updateDisabled(); // Allow the scrollbars to resize and move based on the new contents. // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing. - /** @type {!WorkspaceSvg} */(workspace).resizeContents(); + /** @type {!WorkspaceSvg} */ (workspace).resizeContents(); } else { const blocks = topBlock.getDescendants(false); for (let i = blocks.length - 1; i >= 0; i--) { From 4fc3fdeee044612ccdaf19f9cedf93ff8362f4ce Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 16 Mar 2022 20:18:00 +0000 Subject: [PATCH 6/6] fix: format --- core/workspace.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/workspace.js b/core/workspace.js index 7c05f0097cd..236cadbe912 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -205,8 +205,7 @@ class Workspace { * @param {!Block | !WorkspaceComment} b The second object to * compare. * @return {number} The comparison value. This tells Array.sort() how to - * change - * object a's index. + * change object a's index. * @private */ sortObjects_(a, b) {