diff --git a/.github/workflows/tag_module_cleanup.yml b/.github/workflows/tag_module_cleanup.yml index 94e7ec692..0265070af 100644 --- a/.github/workflows/tag_module_cleanup.yml +++ b/.github/workflows/tag_module_cleanup.yml @@ -19,17 +19,20 @@ jobs: - uses: actions/github-script@a3e7071a34d7e1f219a8a4de9a5e0a34d1ee1293 with: script: | - // 2021 q3 release milestone. - // https://github.com/google/blockly/milestone/18 - const milestoneNumber = 18; - // Note that pull requests are accessed through the issues API. - const issuesUpdateParams = { - owner: context.repo.owner, - repo: context.repo.repo, - // Adds the milestone - milestone: milestoneNumber, + // Note that pull requests are considered issues and "shared" + // actions for both features, like manipulating labels and + // milestones are provided within the issues API. + await github.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + // 2021 q3 release milestone. + // https://github.com/google/blockly/milestone/18 + milestone: 18 + }) + await github.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, issue_number: context.issue.number, - // Sets the labels labels: ['type: cleanup'] - } - await github.issues.update(issuesUpdateParams) + }) diff --git a/core/block.js b/core/block.js index cfeaddebd..0f610c2e7 100644 --- a/core/block.js +++ b/core/block.js @@ -10,15 +10,40 @@ */ 'use strict'; -goog.provide('Blockly.Block'); +goog.module('Blockly.Block'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.ASTNode'); -goog.require('Blockly.Blocks'); -goog.require('Blockly.Connection'); -goog.require('Blockly.connectionTypes'); -/** @suppress {extraRequire} */ -goog.require('Blockly.constants'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Abstract = goog.requireType('Blockly.Events.Abstract'); +const ASTNode = goog.require('Blockly.ASTNode'); +const Blocks = goog.require('Blockly.Blocks'); +/* eslint-disable-next-line no-unused-vars */ +const Comment = goog.requireType('Blockly.Comment'); +const Connection = goog.require('Blockly.Connection'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +const Extensions = goog.require('Blockly.Extensions'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation'); +/* eslint-disable-next-line no-unused-vars */ +const IDeletable = goog.requireType('Blockly.IDeletable'); +const Input = goog.require('Blockly.Input'); +/* eslint-disable-next-line no-unused-vars */ +const Mutator = goog.requireType('Blockly.Mutator'); +const Size = goog.require('Blockly.utils.Size'); +const Tooltip = goog.require('Blockly.Tooltip'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const constants = goog.require('Blockly.constants'); +const fieldRegistry = goog.require('Blockly.fieldRegistry'); +const inputTypes = goog.require('Blockly.inputTypes'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); /** @suppress {extraRequire} */ @@ -27,59 +52,41 @@ goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.BlockDelete'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockMove'); -goog.require('Blockly.Extensions'); -goog.require('Blockly.fieldRegistry'); -goog.require('Blockly.IASTNodeLocation'); -goog.require('Blockly.IDeletable'); -goog.require('Blockly.Input'); -goog.require('Blockly.inputTypes'); -goog.require('Blockly.Tooltip'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Size'); -goog.require('Blockly.Workspace'); - -goog.requireType('Blockly.Comment'); -goog.requireType('Blockly.Events.Abstract'); -goog.requireType('Blockly.Field'); -goog.requireType('Blockly.Mutator'); -goog.requireType('Blockly.utils.Size'); -goog.requireType('Blockly.VariableModel'); /** * Class for one block. * Not normally called directly, workspace.newBlock() is preferred. - * @param {!Blockly.Workspace} workspace The block's workspace. + * @param {!Workspace} workspace The block's workspace. * @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. * @constructor - * @implements {Blockly.IASTNodeLocation} - * @implements {Blockly.IDeletable} + * @implements {IASTNodeLocation} + * @implements {IDeletable} * @throws When the prototypeName is not valid or not allowed. */ -Blockly.Block = function(workspace, prototypeName, opt_id) { - if (Blockly.Generator && - typeof Blockly.Generator.prototype[prototypeName] != 'undefined') { +const Block = function(workspace, prototypeName, opt_id) { + const Generator = goog.module.get('Blockly.Generator'); + if (Generator && typeof Generator.prototype[prototypeName] != 'undefined') { // Occluding Generator class members is not allowed. - throw Error('Block prototypeName "' + prototypeName + + throw Error( + 'Block prototypeName "' + prototypeName + '" conflicts with Blockly.Generator members.'); } /** @type {string} */ - this.id = (opt_id && !workspace.getBlockById(opt_id)) ? - opt_id : Blockly.utils.genUid(); + this.id = + (opt_id && !workspace.getBlockById(opt_id)) ? opt_id : utils.genUid(); workspace.setBlockById(this.id, this); - /** @type {Blockly.Connection} */ + /** @type {Connection} */ this.outputConnection = null; - /** @type {Blockly.Connection} */ + /** @type {Connection} */ this.nextConnection = null; - /** @type {Blockly.Connection} */ + /** @type {Connection} */ this.previousConnection = null; - /** @type {!Array} */ + /** @type {!Array} */ this.inputList = []; /** @type {boolean|undefined} */ this.inputsInline = undefined; @@ -88,19 +95,19 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { * @private */ this.disabled = false; - /** @type {!Blockly.Tooltip.TipInfo} */ + /** @type {!Tooltip.TipInfo} */ this.tooltip = ''; /** @type {boolean} */ this.contextMenu = true; /** - * @type {Blockly.Block} + * @type {Block} * @protected */ this.parentBlock_ = null; /** - * @type {!Array} + * @type {!Array} * @protected */ this.childBlocks_ = []; @@ -143,31 +150,27 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { /** * A string representing the comment attached to this block. - * @type {string|Blockly.Comment} + * @type {string|Comment} * @deprecated August 2019. Use getCommentText instead. */ this.comment = null; /** * A model of the comment attached to this block. - * @type {!Blockly.Block.CommentModel} + * @type {!Block.CommentModel} * @package */ - this.commentModel = { - text: null, - pinned: false, - size: new Blockly.utils.Size(160, 80) - }; + this.commentModel = {text: null, pinned: false, size: new Size(160, 80)}; /** * The block's position in workspace units. (0, 0) is at the workspace's * origin; scale does not change this value. - * @type {!Blockly.utils.Coordinate} + * @type {!Coordinate} * @private */ - this.xy_ = new Blockly.utils.Coordinate(0, 0); + this.xy_ = new Coordinate(0, 0); - /** @type {!Blockly.Workspace} */ + /** @type {!Workspace} */ this.workspace = workspace; /** @type {boolean} */ this.isInFlyout = workspace.isFlyout; @@ -204,11 +207,11 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { if (prototypeName) { /** @type {string} */ this.type = prototypeName; - var prototype = Blockly.Blocks[prototypeName]; + const prototype = Blocks[prototypeName]; if (!prototype || typeof prototype != 'object') { throw TypeError('Unknown block type: ' + prototypeName); } - Blockly.utils.object.mixin(this, prototype); + object.mixin(this, prototype); } workspace.addTopBlock(this); @@ -217,32 +220,31 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { // All events fired should be part of the same group. // Any events fired during init should not be undoable, // so that block creation is atomic. - var existingGroup = Blockly.Events.getGroup(); + const existingGroup = Events.getGroup(); if (!existingGroup) { - Blockly.Events.setGroup(true); + Events.setGroup(true); } - var initialUndoFlag = Blockly.Events.recordUndo; + const initialUndoFlag = Events.recordUndo; try { // Call an initialization function, if it exists. if (typeof this.init == 'function') { - Blockly.Events.recordUndo = false; + Events.recordUndo = false; this.init(); - Blockly.Events.recordUndo = initialUndoFlag; + Events.recordUndo = initialUndoFlag; } // Fire a create event. - if (Blockly.Events.isEnabled()) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))( - this)); + if (Events.isEnabled()) { + Events.fire(new (Events.get(Events.BLOCK_CREATE))(this)); } } finally { if (!existingGroup) { - Blockly.Events.setGroup(false); + Events.setGroup(false); } // In case init threw, recordUndo flag should still be reset. - Blockly.Events.recordUndo = initialUndoFlag; + Events.recordUndo = initialUndoFlag; } // Record initial inline state. @@ -259,36 +261,36 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { * @typedef {{ * text:?string, * pinned:boolean, - * size:Blockly.utils.Size + * size:Size * }} */ -Blockly.Block.CommentModel; +Block.CommentModel; /** * The language-neutral ID given to the collapsed input. * @const {string} */ -Blockly.Block.COLLAPSED_INPUT_NAME = Blockly.constants.COLLAPSED_INPUT_NAME; +Block.COLLAPSED_INPUT_NAME = constants.COLLAPSED_INPUT_NAME; /** * The language-neutral ID given to the collapsed field. * @const {string} */ -Blockly.Block.COLLAPSED_FIELD_NAME = Blockly.constants.COLLAPSED_FIELD_NAME; +Block.COLLAPSED_FIELD_NAME = constants.COLLAPSED_FIELD_NAME; /** * Optional text data that round-trips between blocks and XML. * Has no effect. May be used by 3rd parties for meta information. * @type {?string} */ -Blockly.Block.prototype.data = null; +Block.prototype.data = null; /** * Has this block been disposed of? * @type {boolean} * @package */ -Blockly.Block.prototype.disposed = false; +Block.prototype.disposed = false; /** * Colour of the block as HSV hue value (0-360) @@ -296,56 +298,56 @@ Blockly.Block.prototype.disposed = false; * @type {?number} * @private */ -Blockly.Block.prototype.hue_ = null; +Block.prototype.hue_ = null; /** * Colour of the block in '#RRGGBB' format. * @type {string} * @protected */ -Blockly.Block.prototype.colour_ = '#000000'; +Block.prototype.colour_ = '#000000'; /** * Name of the block style. * @type {string} * @protected */ -Blockly.Block.prototype.styleName_ = ''; +Block.prototype.styleName_ = ''; /** * An optional method called during initialization. * @type {?function()} */ -Blockly.Block.prototype.init; +Block.prototype.init; /** * An optional callback method to use whenever the block's parent workspace * changes. This is usually only called from the constructor, the block type * initializer function, or an extension initializer function. - * @type {?function(Blockly.Events.Abstract)} + * @type {?function(Abstract)} */ -Blockly.Block.prototype.onchange; +Block.prototype.onchange; /** * An optional serialization method for defining how to serialize the * mutation state. This must be coupled with defining `domToMutation`. * @type {?function(...):!Element} */ -Blockly.Block.prototype.mutationToDom; +Block.prototype.mutationToDom; /** * An optional deserialization method for defining how to deserialize the * mutation state. This must be coupled with defining `mutationToDom`. * @type {?function(!Element)} */ -Blockly.Block.prototype.domToMutation; +Block.prototype.domToMutation; /** * An optional property for suppressing adding STATEMENT_PREFIX and * STATEMENT_SUFFIX to generated code. * @type {?boolean} */ -Blockly.Block.prototype.suppressPrefixSuffix; +Block.prototype.suppressPrefixSuffix; /** * An optional property for declaring developer variables. Return a list of @@ -353,7 +355,7 @@ Blockly.Block.prototype.suppressPrefixSuffix; * the user, but are declared as global variables in the generated code. * @type {?function():!Array} */ -Blockly.Block.prototype.getDeveloperVariables; +Block.prototype.getDeveloperVariables; /** * Dispose of this block. @@ -362,7 +364,7 @@ Blockly.Block.prototype.getDeveloperVariables; * all children of this block. * @suppress {checkTypes} */ -Blockly.Block.prototype.dispose = function(healStack) { +Block.prototype.dispose = function(healStack) { if (!this.workspace) { // Already deleted. return; @@ -373,11 +375,10 @@ Blockly.Block.prototype.dispose = function(healStack) { } this.unplug(healStack); - if (Blockly.Events.isEnabled()) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_DELETE))( - this)); + if (Events.isEnabled()) { + Events.fire(new (Events.get(Events.BLOCK_DELETE))(this)); } - Blockly.Events.disable(); + Events.disable(); try { // This block is now at the top of the workspace. @@ -399,22 +400,22 @@ Blockly.Block.prototype.dispose = function(healStack) { } // First, dispose of all my children. - for (var i = this.childBlocks_.length - 1; i >= 0; i--) { + for (let i = this.childBlocks_.length - 1; i >= 0; i--) { this.childBlocks_[i].dispose(false); } // Then dispose of myself. // Dispose of all inputs and their fields. - for (var i = 0, input; (input = this.inputList[i]); i++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { input.dispose(); } this.inputList.length = 0; // Dispose of any remaining connections (next/previous/output). - var connections = this.getConnections_(true); - for (var i = 0, connection; (connection = connections[i]); i++) { + const connections = this.getConnections_(true); + for (let i = 0, connection; (connection = connections[i]); i++) { connection.dispose(); } } finally { - Blockly.Events.enable(); + Events.enable(); this.disposed = true; } }; @@ -428,9 +429,9 @@ Blockly.Block.prototype.dispose = function(healStack) { * change). * @public */ -Blockly.Block.prototype.initModel = function() { - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { +Block.prototype.initModel = function() { + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { if (field.initModel) { field.initModel(); } @@ -444,7 +445,7 @@ Blockly.Block.prototype.initModel = function() { * @param {boolean=} opt_healStack Disconnect child statement and reconnect * stack. Defaults to false. */ -Blockly.Block.prototype.unplug = function(opt_healStack) { +Block.prototype.unplug = function(opt_healStack) { if (this.outputConnection) { this.unplugFromRow_(opt_healStack); } else if (this.previousConnection) { @@ -459,8 +460,8 @@ Blockly.Block.prototype.unplug = function(opt_healStack) { * left-side block. Defaults to false. * @private */ -Blockly.Block.prototype.unplugFromRow_ = function(opt_healStack) { - var parentConnection = null; +Block.prototype.unplugFromRow_ = function(opt_healStack) { + let parentConnection = null; if (this.outputConnection.isConnected()) { parentConnection = this.outputConnection.targetConnection; // Disconnect from any superior block. @@ -472,21 +473,20 @@ Blockly.Block.prototype.unplugFromRow_ = function(opt_healStack) { return; } - var thisConnection = this.getOnlyValueConnection_(); - if (!thisConnection || - !thisConnection.isConnected() || + const thisConnection = this.getOnlyValueConnection_(); + if (!thisConnection || !thisConnection.isConnected() || thisConnection.targetBlock().isShadow()) { // Too many or too few possible connections on this block, or there's // nothing on the other side of this connection. return; } - var childConnection = thisConnection.targetConnection; + const childConnection = thisConnection.targetConnection; // Disconnect the child block. childConnection.disconnect(); // Connect child to the parent if possible, otherwise bump away. if (this.workspace.connectionChecker.canConnect( - childConnection, parentConnection, false)) { + childConnection, parentConnection, false)) { parentConnection.connect(childConnection); } else { childConnection.onFailedConnect(parentConnection); @@ -500,15 +500,14 @@ Blockly.Block.prototype.unplugFromRow_ = function(opt_healStack) { * Since only one block can be displaced and attached to the insertion marker * this should only ever return one connection. * - * @return {?Blockly.Connection} The connection on the value input, or null. + * @return {?Connection} The connection on the value input, or null. * @private */ -Blockly.Block.prototype.getOnlyValueConnection_ = function() { - var connection = null; - for (var i = 0; i < this.inputList.length; i++) { - var thisConnection = this.inputList[i].connection; - if (thisConnection && - thisConnection.type == Blockly.connectionTypes.INPUT_VALUE && +Block.prototype.getOnlyValueConnection_ = function() { + let connection = null; + for (let i = 0; i < this.inputList.length; i++) { + const thisConnection = this.inputList[i].connection; + if (thisConnection && thisConnection.type == connectionTypes.INPUT_VALUE && thisConnection.targetConnection) { if (connection) { return null; // More than one value input found. @@ -526,18 +525,18 @@ Blockly.Block.prototype.getOnlyValueConnection_ = function() { * stack. Defaults to false. * @private */ -Blockly.Block.prototype.unplugFromStack_ = function(opt_healStack) { - var previousTarget = null; +Block.prototype.unplugFromStack_ = function(opt_healStack) { + let previousTarget = null; if (this.previousConnection.isConnected()) { // Remember the connection that any next statements need to connect to. previousTarget = this.previousConnection.targetConnection; // Detach this block from the parent's tree. this.previousConnection.disconnect(); } - var nextBlock = this.getNextBlock(); + const nextBlock = this.getNextBlock(); if (opt_healStack && nextBlock && !nextBlock.isShadow()) { // Disconnect the next statement. - var nextTarget = this.nextConnection.targetConnection; + const nextTarget = this.nextConnection.targetConnection; nextTarget.disconnect(); if (previousTarget && this.workspace.connectionChecker.canConnect( @@ -551,11 +550,11 @@ Blockly.Block.prototype.unplugFromStack_ = function(opt_healStack) { /** * Returns all connections originating from this block. * @param {boolean} _all If true, return all connections even hidden ones. - * @return {!Array} Array of connections. + * @return {!Array} Array of connections. * @package */ -Blockly.Block.prototype.getConnections_ = function(_all) { - var myConnections = []; +Block.prototype.getConnections_ = function(_all) { + const myConnections = []; if (this.outputConnection) { myConnections.push(this.outputConnection); } @@ -565,7 +564,7 @@ Blockly.Block.prototype.getConnections_ = function(_all) { if (this.nextConnection) { myConnections.push(this.nextConnection); } - for (var i = 0, input; (input = this.inputList[i]); i++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.connection) { myConnections.push(input.connection); } @@ -578,13 +577,13 @@ Blockly.Block.prototype.getConnections_ = function(_all) { * @param {boolean} ignoreShadows If true,the last connection on a non-shadow * block will be returned. If false, this will follow shadows to find the * last connection. - * @return {?Blockly.Connection} The last next connection on the stack, or null. + * @return {?Connection} The last next connection on the stack, or null. * @package */ -Blockly.Block.prototype.lastConnectionInStack = function(ignoreShadows) { - var nextConnection = this.nextConnection; +Block.prototype.lastConnectionInStack = function(ignoreShadows) { + let nextConnection = this.nextConnection; while (nextConnection) { - var nextBlock = nextConnection.targetBlock(); + const nextBlock = nextConnection.targetBlock(); if (!nextBlock || (ignoreShadows && nextBlock.isShadow())) { return nextConnection; } @@ -597,28 +596,29 @@ Blockly.Block.prototype.lastConnectionInStack = function(ignoreShadows) { * Bump unconnected blocks out of alignment. Two blocks which aren't actually * connected should not coincidentally line up on screen. */ -Blockly.Block.prototype.bumpNeighbours = function() { +Block.prototype.bumpNeighbours = function() { // noop. }; /** * Return the parent block or null if this block is at the top level. The parent - * block is either the block connected to the previous connection (for a statement - * block) or the block connected to the output connection (for a value block). - * @return {?Blockly.Block} The block (if any) that holds the current block. + * block is either the block connected to the previous connection (for a + * statement block) or the block connected to the output connection (for a value + * block). + * @return {?Block} The block (if any) that holds the current block. */ -Blockly.Block.prototype.getParent = function() { +Block.prototype.getParent = function() { return this.parentBlock_; }; /** * Return the input that connects to the specified block. - * @param {!Blockly.Block} block A block connected to an input on this block. - * @return {?Blockly.Input} The input (if any) that connects to the specified + * @param {!Block} block A block connected to an input on this block. + * @return {?Input} The input (if any) that connects to the specified * block. */ -Blockly.Block.prototype.getInputWithBlock = function(block) { - for (var i = 0, input; (input = this.inputList[i]); i++) { +Block.prototype.getInputWithBlock = function(block) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.connection && input.connection.targetBlock() == block) { return input; } @@ -630,12 +630,13 @@ Blockly.Block.prototype.getInputWithBlock = function(block) { * Return the parent block that surrounds the current block, or null if this * block has no surrounding block. A parent block might just be the previous * statement, whereas the surrounding block is an if statement, while loop, etc. - * @return {?Blockly.Block} The block (if any) that surrounds the current block. + * @return {?Block} The block (if any) that surrounds the current block. */ -Blockly.Block.prototype.getSurroundParent = function() { - var block = this; +Block.prototype.getSurroundParent = function() { + let block = this; + let prevBlock; do { - var prevBlock = block; + prevBlock = block; block = block.getParent(); if (!block) { // Ran off the top. @@ -648,30 +649,30 @@ Blockly.Block.prototype.getSurroundParent = function() { /** * Return the next statement block directly connected to this block. - * @return {?Blockly.Block} The next statement block or null. + * @return {?Block} The next statement block or null. */ -Blockly.Block.prototype.getNextBlock = function() { +Block.prototype.getNextBlock = function() { return this.nextConnection && this.nextConnection.targetBlock(); }; /** * Returns the block connected to the previous connection. - * @return {?Blockly.Block} The previous statement block or null. + * @return {?Block} The previous statement block or null. */ -Blockly.Block.prototype.getPreviousBlock = function() { +Block.prototype.getPreviousBlock = function() { return this.previousConnection && this.previousConnection.targetBlock(); }; /** * Return the connection on the first statement input on this block, or null if * there are none. - * @return {?Blockly.Connection} The first statement connection or null. + * @return {?Connection} The first statement connection or null. * @package */ -Blockly.Block.prototype.getFirstStatementConnection = function() { - for (var i = 0, input; (input = this.inputList[i]); i++) { +Block.prototype.getFirstStatementConnection = function() { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.connection && - input.connection.type == Blockly.connectionTypes.NEXT_STATEMENT) { + input.connection.type == connectionTypes.NEXT_STATEMENT) { return input.connection; } } @@ -681,11 +682,11 @@ Blockly.Block.prototype.getFirstStatementConnection = function() { /** * Return the top-most block in this block's tree. * This will return itself if this block is at the top level. - * @return {!Blockly.Block} The root block. + * @return {!Block} The root block. */ -Blockly.Block.prototype.getRootBlock = function() { - var rootBlock; - var block = this; +Block.prototype.getRootBlock = function() { + let rootBlock; + let block = this; do { rootBlock = block; block = rootBlock.parentBlock_; @@ -697,13 +698,14 @@ Blockly.Block.prototype.getRootBlock = function() { * Walk up from the given block up through the stack of blocks to find * the top block of the sub stack. If we are nested in a statement input only * find the top-most nested block. Do not go all the way to the root block. - * @return {!Blockly.Block} The top block in a stack. + * @return {!Block} The top block in a stack. * @package */ -Blockly.Block.prototype.getTopStackBlock = function() { - var block = this; +Block.prototype.getTopStackBlock = function() { + let block = this; + let previous; do { - var previous = block.getPreviousBlock(); + previous = block.getPreviousBlock(); } while (previous && previous.getNextBlock() == block && (block = previous)); return block; }; @@ -714,22 +716,22 @@ Blockly.Block.prototype.getTopStackBlock = function() { * Excludes any connection on an output tab or any preceding statement. * Blocks are optionally sorted by position; top to bottom. * @param {boolean} ordered Sort the list if true. - * @return {!Array} Array of blocks. + * @return {!Array} Array of blocks. */ -Blockly.Block.prototype.getChildren = function(ordered) { +Block.prototype.getChildren = function(ordered) { if (!ordered) { return this.childBlocks_; } - var blocks = []; - for (var i = 0, input; (input = this.inputList[i]); i++) { + const blocks = []; + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.connection) { - var child = input.connection.targetBlock(); + const child = input.connection.targetBlock(); if (child) { blocks.push(child); } } } - var next = this.getNextBlock(); + const next = this.getNextBlock(); if (next) { blocks.push(next); } @@ -738,31 +740,32 @@ Blockly.Block.prototype.getChildren = function(ordered) { /** * Set parent of this block to be a new block or null. - * @param {Blockly.Block} newParent New parent block. + * @param {Block} newParent New parent block. * @package */ -Blockly.Block.prototype.setParent = function(newParent) { +Block.prototype.setParent = function(newParent) { if (newParent === this.parentBlock_) { return; } // Check that block is connected to new parent if new parent is not null and // that block is not connected to superior one if new parent is null. - var connection = this.previousConnection || this.outputConnection; - var isConnected = !!(connection && connection.targetBlock()); + const connection = this.previousConnection || this.outputConnection; + const isConnected = !!(connection && connection.targetBlock()); if (isConnected && newParent && connection.targetBlock() !== newParent) { throw Error('Block connected to superior one that is not new parent.'); } else if (!isConnected && newParent) { throw Error('Block not connected to new parent.'); } else if (isConnected && !newParent) { - throw Error('Cannot set parent to null while block is still connected to' + + throw Error( + 'Cannot set parent to null while block is still connected to' + ' superior block.'); } if (this.parentBlock_) { // Remove this block from the old parent's child list. - Blockly.utils.arrayRemove(this.parentBlock_.childBlocks_, this); + utils.arrayRemove(this.parentBlock_.childBlocks_, this); // This block hasn't actually moved on-screen, so there's no need to update // its connection locations. @@ -788,12 +791,12 @@ Blockly.Block.prototype.setParent = function(newParent) { * Excludes any connection on an output tab or any preceding statements. * Blocks are optionally sorted by position; top to bottom. * @param {boolean} ordered Sort the list if true. - * @return {!Array} Flattened array of blocks. + * @return {!Array} Flattened array of blocks. */ -Blockly.Block.prototype.getDescendants = function(ordered) { - var blocks = [this]; - var childBlocks = this.getChildren(ordered); - for (var child, i = 0; (child = childBlocks[i]); i++) { +Block.prototype.getDescendants = function(ordered) { + const blocks = [this]; + const childBlocks = this.getChildren(ordered); + for (let child, i = 0; (child = childBlocks[i]); i++) { blocks.push.apply(blocks, child.getDescendants(ordered)); } return blocks; @@ -803,7 +806,7 @@ Blockly.Block.prototype.getDescendants = function(ordered) { * Get whether this block is deletable or not. * @return {boolean} True if deletable. */ -Blockly.Block.prototype.isDeletable = function() { +Block.prototype.isDeletable = function() { return this.deletable_ && !this.isShadow_ && !(this.workspace && this.workspace.options.readOnly); }; @@ -812,7 +815,7 @@ Blockly.Block.prototype.isDeletable = function() { * Set whether this block is deletable or not. * @param {boolean} deletable True if deletable. */ -Blockly.Block.prototype.setDeletable = function(deletable) { +Block.prototype.setDeletable = function(deletable) { this.deletable_ = deletable; }; @@ -820,7 +823,7 @@ Blockly.Block.prototype.setDeletable = function(deletable) { * Get whether this block is movable or not. * @return {boolean} True if movable. */ -Blockly.Block.prototype.isMovable = function() { +Block.prototype.isMovable = function() { return this.movable_ && !this.isShadow_ && !(this.workspace && this.workspace.options.readOnly); }; @@ -829,7 +832,7 @@ Blockly.Block.prototype.isMovable = function() { * Set whether this block is movable or not. * @param {boolean} movable True if movable. */ -Blockly.Block.prototype.setMovable = function(movable) { +Block.prototype.setMovable = function(movable) { this.movable_ = movable; }; @@ -840,19 +843,19 @@ Blockly.Block.prototype.setMovable = function(movable) { * type over their maxInstances this block is not duplicatable. * @return {boolean} True if duplicatable. */ -Blockly.Block.prototype.isDuplicatable = function() { +Block.prototype.isDuplicatable = function() { if (!this.workspace.hasBlockLimits()) { return true; } return this.workspace.isCapacityAvailable( - Blockly.utils.getBlockTypeCounts(this, true)); + utils.getBlockTypeCounts(this, true)); }; /** * Get whether this block is a shadow block or not. * @return {boolean} True if a shadow. */ -Blockly.Block.prototype.isShadow = function() { +Block.prototype.isShadow = function() { return this.isShadow_; }; @@ -861,7 +864,7 @@ Blockly.Block.prototype.isShadow = function() { * @param {boolean} shadow True if a shadow. * @package */ -Blockly.Block.prototype.setShadow = function(shadow) { +Block.prototype.setShadow = function(shadow) { this.isShadow_ = shadow; }; @@ -869,7 +872,7 @@ Blockly.Block.prototype.setShadow = function(shadow) { * Get whether this block is an insertion marker block or not. * @return {boolean} True if an insertion marker. */ -Blockly.Block.prototype.isInsertionMarker = function() { +Block.prototype.isInsertionMarker = function() { return this.isInsertionMarker_; }; @@ -879,7 +882,7 @@ Blockly.Block.prototype.isInsertionMarker = function() { * @param {boolean} insertionMarker True if an insertion marker. * @package */ -Blockly.Block.prototype.setInsertionMarker = function(insertionMarker) { +Block.prototype.setInsertionMarker = function(insertionMarker) { this.isInsertionMarker_ = insertionMarker; }; @@ -887,7 +890,7 @@ Blockly.Block.prototype.setInsertionMarker = function(insertionMarker) { * Get whether this block is editable or not. * @return {boolean} True if editable. */ -Blockly.Block.prototype.isEditable = function() { +Block.prototype.isEditable = function() { return this.editable_ && !(this.workspace && this.workspace.options.readOnly); }; @@ -895,10 +898,10 @@ Blockly.Block.prototype.isEditable = function() { * Set whether this block is editable or not. * @param {boolean} editable True if editable. */ -Blockly.Block.prototype.setEditable = function(editable) { +Block.prototype.setEditable = function(editable) { this.editable_ = editable; - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { field.updateEditable(); } } @@ -908,7 +911,7 @@ Blockly.Block.prototype.setEditable = function(editable) { * Returns if this block has been disposed of / deleted. * @return {boolean} True if this block has been disposed of / deleted. */ -Blockly.Block.prototype.isDisposed = function() { +Block.prototype.isDisposed = function() { return this.disposed; }; @@ -916,18 +919,18 @@ Blockly.Block.prototype.isDisposed = function() { * Find the connection on this block that corresponds to the given connection * on the other block. * Used to match connections between a block and its insertion marker. - * @param {!Blockly.Block} otherBlock The other block to match against. - * @param {!Blockly.Connection} conn The other connection to match. - * @return {?Blockly.Connection} The matching connection on this block, or null. + * @param {!Block} otherBlock The other block to match against. + * @param {!Connection} conn The other connection to match. + * @return {?Connection} The matching connection on this block, or null. * @package */ -Blockly.Block.prototype.getMatchingConnection = function(otherBlock, conn) { - var connections = this.getConnections_(true); - var otherConnections = otherBlock.getConnections_(true); +Block.prototype.getMatchingConnection = function(otherBlock, conn) { + const connections = this.getConnections_(true); + const otherConnections = otherBlock.getConnections_(true); if (connections.length != otherConnections.length) { - throw Error("Connection lists did not match in length."); + throw Error('Connection lists did not match in length.'); } - for (var i = 0; i < otherConnections.length; i++) { + for (let i = 0; i < otherConnections.length; i++) { if (otherConnections[i] == conn) { return connections[i]; } @@ -940,17 +943,17 @@ Blockly.Block.prototype.getMatchingConnection = function(otherBlock, conn) { * @param {string|Function} url URL string for block help, or function that * returns a URL. Null for no help. */ -Blockly.Block.prototype.setHelpUrl = function(url) { +Block.prototype.setHelpUrl = function(url) { this.helpUrl = url; }; /** * Sets the tooltip for this block. - * @param {!Blockly.Tooltip.TipInfo} newTip The text for the tooltip, a function + * @param {!Tooltip.TipInfo} newTip The text for the tooltip, a function * that returns the text for the tooltip, or a parent object whose tooltip * will be used. To not display a tooltip pass the empty string. */ -Blockly.Block.prototype.setTooltip = function(newTip) { +Block.prototype.setTooltip = function(newTip) { this.tooltip = newTip; }; @@ -958,15 +961,15 @@ Blockly.Block.prototype.setTooltip = function(newTip) { * Returns the tooltip text for this block. * @return {!string} The tooltip text for this block. */ -Blockly.Block.prototype.getTooltip = function() { - return Blockly.Tooltip.getTooltipOfObject(this); +Block.prototype.getTooltip = function() { + return Tooltip.getTooltipOfObject(this); }; /** * Get the colour of a block. * @return {string} #RRGGBB string. */ -Blockly.Block.prototype.getColour = function() { +Block.prototype.getColour = function() { return this.colour_; }; @@ -974,7 +977,7 @@ Blockly.Block.prototype.getColour = function() { * Get the name of the block style. * @return {string} Name of the block style. */ -Blockly.Block.prototype.getStyleName = function() { +Block.prototype.getStyleName = function() { return this.styleName_; }; @@ -982,7 +985,7 @@ Blockly.Block.prototype.getStyleName = function() { * Get the HSV hue value of a block. Null if hue not set. * @return {?number} Hue value (0-360). */ -Blockly.Block.prototype.getHue = function() { +Block.prototype.getHue = function() { return this.hue_; }; @@ -991,8 +994,8 @@ Blockly.Block.prototype.getHue = function() { * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, * or a message reference string pointing to one of those two values. */ -Blockly.Block.prototype.setColour = function(colour) { - var parsed = Blockly.utils.parseBlockColour(colour); +Block.prototype.setColour = function(colour) { + const parsed = utils.parseBlockColour(colour); this.hue_ = parsed.hue; this.colour_ = parsed.hex; }; @@ -1001,7 +1004,7 @@ Blockly.Block.prototype.setColour = function(colour) { * Set the style and colour values of a block. * @param {string} blockStyleName Name of the block style. */ -Blockly.Block.prototype.setStyle = function(blockStyleName) { +Block.prototype.setStyle = function(blockStyleName) { this.styleName_ = blockStyleName; }; @@ -1010,11 +1013,11 @@ Blockly.Block.prototype.setStyle = function(blockStyleName) { * changes, replacing any prior onchange handler. This is usually only called * from the constructor, the block type initializer function, or an extension * initializer function. - * @param {function(Blockly.Events.Abstract)} onchangeFn The callback to call + * @param {function(Abstract)} onchangeFn The callback to call * when the block's workspace changes. * @throws {Error} if onchangeFn is not falsey and not a function. */ -Blockly.Block.prototype.setOnChange = function(onchangeFn) { +Block.prototype.setOnChange = function(onchangeFn) { if (onchangeFn && typeof onchangeFn != 'function') { throw Error('onchange must be a function.'); } @@ -1031,17 +1034,18 @@ Blockly.Block.prototype.setOnChange = function(onchangeFn) { /** * Returns the named field from a block. * @param {string} name The name of the field. - * @return {?Blockly.Field} Named field, or null if field does not exist. + * @return {?Field} Named field, or null if field does not exist. */ -Blockly.Block.prototype.getField = function(name) { +Block.prototype.getField = function(name) { if (typeof name !== 'string') { - throw TypeError('Blockly.Block.prototype.getField expects a string ' + - 'with the field name but received ' + - (name === undefined ? 'nothing' : name + ' of type ' + typeof name) + - ' instead'); + throw TypeError( + 'Block.prototype.getField expects a string ' + + 'with the field name but received ' + + (name === undefined ? 'nothing' : name + ' of type ' + typeof name) + + ' instead'); } - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { if (field.name === name) { return field; } @@ -1054,10 +1058,10 @@ Blockly.Block.prototype.getField = function(name) { * Return all variables referenced by this block. * @return {!Array} List of variable names. */ -Blockly.Block.prototype.getVars = function() { - var vars = []; - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { +Block.prototype.getVars = function() { + const vars = []; + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { if (field.referencesVariables()) { vars.push(field.getValue()); } @@ -1068,15 +1072,15 @@ Blockly.Block.prototype.getVars = function() { /** * Return all variables referenced by this block. - * @return {!Array} List of variable models. + * @return {!Array} List of variable models. * @package */ -Blockly.Block.prototype.getVarModels = function() { - var vars = []; - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { +Block.prototype.getVarModels = function() { + const vars = []; + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { if (field.referencesVariables()) { - var model = this.workspace.getVariableById( + const model = this.workspace.getVariableById( /** @type {string} */ (field.getValue())); // Check if the variable actually exists (and isn't just a potential // variable). @@ -1092,14 +1096,13 @@ Blockly.Block.prototype.getVarModels = function() { /** * Notification that a variable is renaming but keeping the same ID. If the * variable is in use on this block, rerender to show the new name. - * @param {!Blockly.VariableModel} variable The variable being renamed. + * @param {!VariableModel} variable The variable being renamed. * @package */ -Blockly.Block.prototype.updateVarName = function(variable) { - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { - if (field.referencesVariables() && - variable.getId() == field.getValue()) { +Block.prototype.updateVarName = function(variable) { + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { + if (field.referencesVariables() && variable.getId() == field.getValue()) { field.refreshVariableName(); } } @@ -1113,11 +1116,10 @@ Blockly.Block.prototype.updateVarName = function(variable) { * @param {string} newId ID of new variable. May be the same as oldId, but with * an updated name. */ -Blockly.Block.prototype.renameVarById = function(oldId, newId) { - for (var i = 0, input; (input = this.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { - if (field.referencesVariables() && - oldId == field.getValue()) { +Block.prototype.renameVarById = function(oldId, newId) { + for (let i = 0, input; (input = this.inputList[i]); i++) { + for (let j = 0, field; (field = input.fieldRow[j]); j++) { + if (field.referencesVariables() && oldId == field.getValue()) { field.setValue(newId); } } @@ -1129,8 +1131,8 @@ Blockly.Block.prototype.renameVarById = function(oldId, newId) { * @param {string} name The name of the field. * @return {*} Value of the field or null if field does not exist. */ -Blockly.Block.prototype.getFieldValue = function(name) { - var field = this.getField(name); +Block.prototype.getFieldValue = function(name) { + const field = this.getField(name); if (field) { return field.getValue(); } @@ -1142,8 +1144,8 @@ Blockly.Block.prototype.getFieldValue = function(name) { * @param {*} newValue The value to set. * @param {string} name The name of the field to set the value of. */ -Blockly.Block.prototype.setFieldValue = function(newValue, name) { - var field = this.getField(name); +Block.prototype.setFieldValue = function(newValue, name) { + const field = this.getField(name); if (!field) { throw Error('Field "' + name + '" not found.'); } @@ -1156,24 +1158,26 @@ Blockly.Block.prototype.setFieldValue = function(newValue, name) { * @param {(string|Array|null)=} opt_check Statement type or * list of statement types. Null/undefined if any type could be connected. */ -Blockly.Block.prototype.setPreviousStatement = function(newBoolean, opt_check) { +Block.prototype.setPreviousStatement = function(newBoolean, opt_check) { if (newBoolean) { if (opt_check === undefined) { opt_check = null; } if (!this.previousConnection) { if (this.outputConnection) { - throw Error('Remove output connection prior to adding previous ' + + throw Error( + 'Remove output connection prior to adding previous ' + 'connection.'); } this.previousConnection = - this.makeConnection_(Blockly.connectionTypes.PREVIOUS_STATEMENT); + this.makeConnection_(connectionTypes.PREVIOUS_STATEMENT); } this.previousConnection.setCheck(opt_check); } else { if (this.previousConnection) { if (this.previousConnection.isConnected()) { - throw Error('Must disconnect previous statement before removing ' + + throw Error( + 'Must disconnect previous statement before removing ' + 'connection.'); } this.previousConnection.dispose(); @@ -1188,20 +1192,21 @@ Blockly.Block.prototype.setPreviousStatement = function(newBoolean, opt_check) { * @param {(string|Array|null)=} opt_check Statement type or * list of statement types. Null/undefined if any type could be connected. */ -Blockly.Block.prototype.setNextStatement = function(newBoolean, opt_check) { +Block.prototype.setNextStatement = function(newBoolean, opt_check) { if (newBoolean) { if (opt_check === undefined) { opt_check = null; } if (!this.nextConnection) { this.nextConnection = - this.makeConnection_(Blockly.connectionTypes.NEXT_STATEMENT); + this.makeConnection_(connectionTypes.NEXT_STATEMENT); } this.nextConnection.setCheck(opt_check); } else { if (this.nextConnection) { if (this.nextConnection.isConnected()) { - throw Error('Must disconnect next statement before removing ' + + throw Error( + 'Must disconnect next statement before removing ' + 'connection.'); } this.nextConnection.dispose(); @@ -1217,18 +1222,19 @@ Blockly.Block.prototype.setNextStatement = function(newBoolean, opt_check) { * of returned types. Null or undefined if any type could be returned * (e.g. variable get). */ -Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) { +Block.prototype.setOutput = function(newBoolean, opt_check) { if (newBoolean) { if (opt_check === undefined) { opt_check = null; } if (!this.outputConnection) { if (this.previousConnection) { - throw Error('Remove previous connection prior to adding output ' + + throw Error( + 'Remove previous connection prior to adding output ' + 'connection.'); } this.outputConnection = - this.makeConnection_(Blockly.connectionTypes.OUTPUT_VALUE); + this.makeConnection_(connectionTypes.OUTPUT_VALUE); } this.outputConnection.setCheck(opt_check); } else { @@ -1246,9 +1252,9 @@ Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) { * Set whether value inputs are arranged horizontally or vertically. * @param {boolean} newBoolean True if inputs are horizontal. */ -Blockly.Block.prototype.setInputsInline = function(newBoolean) { +Block.prototype.setInputsInline = function(newBoolean) { if (this.inputsInline != newBoolean) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( this, 'inline', null, this.inputsInline, newBoolean)); this.inputsInline = newBoolean; } @@ -1258,22 +1264,22 @@ Blockly.Block.prototype.setInputsInline = function(newBoolean) { * Get whether value inputs are arranged horizontally or vertically. * @return {boolean} True if inputs are horizontal. */ -Blockly.Block.prototype.getInputsInline = function() { +Block.prototype.getInputsInline = function() { if (this.inputsInline != undefined) { // Set explicitly. return this.inputsInline; } // Not defined explicitly. Figure out what would look best. - for (var i = 1; i < this.inputList.length; i++) { - if (this.inputList[i - 1].type == Blockly.inputTypes.DUMMY && - this.inputList[i].type == Blockly.inputTypes.DUMMY) { + for (let i = 1; i < this.inputList.length; i++) { + if (this.inputList[i - 1].type == inputTypes.DUMMY && + this.inputList[i].type == inputTypes.DUMMY) { // Two dummy inputs in a row. Don't inline them. return false; } } - for (var i = 1; i < this.inputList.length; i++) { - if (this.inputList[i - 1].type == Blockly.inputTypes.VALUE && - this.inputList[i].type == Blockly.inputTypes.DUMMY) { + for (let i = 1; i < this.inputList.length; i++) { + if (this.inputList[i - 1].type == inputTypes.VALUE && + this.inputList[i].type == inputTypes.DUMMY) { // Dummy input after a value input. Inline them. return true; } @@ -1285,7 +1291,7 @@ Blockly.Block.prototype.getInputsInline = function() { * Set the block's output shape. * @param {?number} outputShape Value representing an output shape. */ -Blockly.Block.prototype.setOutputShape = function(outputShape) { +Block.prototype.setOutputShape = function(outputShape) { this.outputShape_ = outputShape; }; @@ -1293,7 +1299,7 @@ Blockly.Block.prototype.setOutputShape = function(outputShape) { * Get the block's output shape. * @return {?number} Value representing output shape if one exists. */ -Blockly.Block.prototype.getOutputShape = function() { +Block.prototype.getOutputShape = function() { return this.outputShape_; }; @@ -1301,7 +1307,7 @@ Blockly.Block.prototype.getOutputShape = function() { * Get whether this block is enabled or not. * @return {boolean} True if enabled. */ -Blockly.Block.prototype.isEnabled = function() { +Block.prototype.isEnabled = function() { return !this.disabled; }; @@ -1309,9 +1315,9 @@ Blockly.Block.prototype.isEnabled = function() { * Set whether the block is enabled or not. * @param {boolean} enabled True if enabled. */ -Blockly.Block.prototype.setEnabled = function(enabled) { +Block.prototype.setEnabled = function(enabled) { if (this.isEnabled() != enabled) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( this, 'disabled', null, this.disabled, !enabled)); this.disabled = !enabled; } @@ -1322,8 +1328,8 @@ Blockly.Block.prototype.setEnabled = function(enabled) { * The block's own disabled property is not considered. * @return {boolean} True if disabled. */ -Blockly.Block.prototype.getInheritedDisabled = function() { - var ancestor = this.getSurroundParent(); +Block.prototype.getInheritedDisabled = function() { + let ancestor = this.getSurroundParent(); while (ancestor) { if (ancestor.disabled) { return true; @@ -1338,7 +1344,7 @@ Blockly.Block.prototype.getInheritedDisabled = function() { * Get whether the block is collapsed or not. * @return {boolean} True if collapsed. */ -Blockly.Block.prototype.isCollapsed = function() { +Block.prototype.isCollapsed = function() { return this.collapsed_; }; @@ -1346,9 +1352,9 @@ Blockly.Block.prototype.isCollapsed = function() { * Set whether the block is collapsed or not. * @param {boolean} collapsed True if collapsed. */ -Blockly.Block.prototype.setCollapsed = function(collapsed) { +Block.prototype.setCollapsed = function(collapsed) { if (this.collapsed_ != collapsed) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( this, 'collapsed', null, this.collapsed_, collapsed)); this.collapsed_ = collapsed; } @@ -1361,29 +1367,29 @@ Blockly.Block.prototype.setCollapsed = function(collapsed) { * empty field. If not specified, '?' is used. * @return {string} Text of block. */ -Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { - var text = []; - var emptyFieldPlaceholder = opt_emptyToken || '?'; +Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { + let text = []; + const emptyFieldPlaceholder = opt_emptyToken || '?'; // Temporarily set flag to navigate to all fields. - var prevNavigateFields = Blockly.ASTNode.NAVIGATE_ALL_FIELDS; - Blockly.ASTNode.NAVIGATE_ALL_FIELDS = true; + const prevNavigateFields = ASTNode.NAVIGATE_ALL_FIELDS; + ASTNode.NAVIGATE_ALL_FIELDS = true; - var node = Blockly.ASTNode.createBlockNode(this); - var rootNode = node; + let node = ASTNode.createBlockNode(this); + const rootNode = node; /** * Whether or not to add parentheses around an input. - * @param {!Blockly.Connection} connection The connection. + * @param {!Connection} connection The connection. * @return {boolean} True if we should add parentheses around the input. */ function shouldAddParentheses(connection) { - var checks = connection.getCheck(); + let checks = connection.getCheck(); if (!checks && connection.targetConnection) { checks = connection.targetConnection.getCheck(); } - return !!checks && (checks.indexOf('Boolean') != -1 || - checks.indexOf('Number') != -1); + return !!checks && + (checks.indexOf('Boolean') != -1 || checks.indexOf('Number') != -1); } /** @@ -1399,23 +1405,25 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { // Traverse the AST building up our text string. while (node) { switch (node.getType()) { - case Blockly.ASTNode.types.INPUT: - var connection = /** @type {!Blockly.Connection} */ (node.getLocation()); + case ASTNode.types.INPUT: { + const connection = /** @type {!Connection} */ (node.getLocation()); if (!node.in()) { text.push(emptyFieldPlaceholder); } else if (shouldAddParentheses(connection)) { text.push('('); } break; - case Blockly.ASTNode.types.FIELD: - var field = /** @type {Blockly.Field} */ (node.getLocation()); - if (field.name != Blockly.constants.COLLAPSED_FIELD_NAME) { + } + case ASTNode.types.FIELD: { + const field = /** @type {Field} */ (node.getLocation()); + if (field.name != constants.COLLAPSED_FIELD_NAME) { text.push(field.getText()); } break; + } } - var current = node; + const current = node; node = current.in() || current.next(); if (!node) { // Can't go in or next, keep going out until we can go next. @@ -1425,9 +1433,9 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { node = node.out(); checkRoot(); // If we hit an input on the way up, possibly close out parentheses. - if (node && node.getType() == Blockly.ASTNode.types.INPUT && + if (node && node.getType() == ASTNode.types.INPUT && shouldAddParentheses( - /** @type {!Blockly.Connection} */ (node.getLocation()))) { + /** @type {!Connection} */ (node.getLocation()))) { text.push(')'); } } @@ -1438,12 +1446,12 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { } // Restore state of NAVIGATE_ALL_FIELDS. - Blockly.ASTNode.NAVIGATE_ALL_FIELDS = prevNavigateFields; + ASTNode.NAVIGATE_ALL_FIELDS = prevNavigateFields; // Run through our text array and simplify expression to remove parentheses // around single field blocks. // E.g. ['repeat', '(', '10', ')', 'times', 'do', '?'] - for (var i = 2; i < text.length; i++) { + for (let i = 2; i < text.length; i++) { if (text[i - 2] == '(' && text[i] == ')') { text[i - 2] = text[i - 1]; text.splice(i - 1, 2); @@ -1470,30 +1478,30 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { * Shortcut for appending a value input row. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. - * @return {!Blockly.Input} The input object created. + * @return {!Input} The input object created. */ -Blockly.Block.prototype.appendValueInput = function(name) { - return this.appendInput_(Blockly.inputTypes.VALUE, name); +Block.prototype.appendValueInput = function(name) { + return this.appendInput_(inputTypes.VALUE, name); }; /** * Shortcut for appending a statement input row. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. - * @return {!Blockly.Input} The input object created. + * @return {!Input} The input object created. */ -Blockly.Block.prototype.appendStatementInput = function(name) { - return this.appendInput_(Blockly.inputTypes.STATEMENT, name); +Block.prototype.appendStatementInput = function(name) { + return this.appendInput_(inputTypes.STATEMENT, name); }; /** * Shortcut for appending a dummy input row. * @param {string=} opt_name Language-neutral identifier which may used to find * this input again. Should be unique to this block. - * @return {!Blockly.Input} The input object created. + * @return {!Input} The input object created. */ -Blockly.Block.prototype.appendDummyInput = function(opt_name) { - return this.appendInput_(Blockly.inputTypes.DUMMY, opt_name || ''); +Block.prototype.appendDummyInput = function(opt_name) { + return this.appendInput_(inputTypes.DUMMY, opt_name || ''); }; /** @@ -1501,12 +1509,13 @@ Blockly.Block.prototype.appendDummyInput = function(opt_name) { * JSON description. * @param {!Object} json Structured data describing the block. */ -Blockly.Block.prototype.jsonInit = function(json) { - var warningPrefix = json['type'] ? 'Block "' + json['type'] + '": ' : ''; +Block.prototype.jsonInit = function(json) { + const warningPrefix = json['type'] ? 'Block "' + json['type'] + '": ' : ''; // Validate inputs. if (json['output'] && json['previousStatement']) { - throw Error(warningPrefix + + throw Error( + warningPrefix + 'Must not have both an output and a previousStatement.'); } @@ -1527,10 +1536,11 @@ Blockly.Block.prototype.jsonInit = function(json) { } // Interpolate the message blocks. - var i = 0; + let i = 0; while (json['message' + i] !== undefined) { - this.interpolate_(json['message' + i], json['args' + i] || [], - json['lastDummyAlign' + i], warningPrefix); + this.interpolate_( + json['message' + i], json['args' + i] || [], json['lastDummyAlign' + i], + warningPrefix); i++; } @@ -1551,17 +1561,17 @@ Blockly.Block.prototype.jsonInit = function(json) { this.setNextStatement(true, json['nextStatement']); } if (json['tooltip'] !== undefined) { - var rawValue = json['tooltip']; - var localizedText = Blockly.utils.replaceMessageReferences(rawValue); + const rawValue = json['tooltip']; + const localizedText = utils.replaceMessageReferences(rawValue); this.setTooltip(localizedText); } if (json['enableContextMenu'] !== undefined) { - var rawValue = json['enableContextMenu']; + const rawValue = json['enableContextMenu']; this.contextMenu = !!rawValue; } if (json['helpUrl'] !== undefined) { - var rawValue = json['helpUrl']; - var localizedValue = Blockly.utils.replaceMessageReferences(rawValue); + const rawValue = json['helpUrl']; + const localizedValue = utils.replaceMessageReferences(rawValue); this.setHelpUrl(localizedValue); } if (typeof json['extensions'] == 'string') { @@ -1574,13 +1584,13 @@ Blockly.Block.prototype.jsonInit = function(json) { // Add the mutator to the block. if (json['mutator'] !== undefined) { - Blockly.Extensions.apply(json['mutator'], this, true); + Extensions.apply(json['mutator'], this, true); } - var extensionNames = json['extensions']; + const extensionNames = json['extensions']; if (Array.isArray(extensionNames)) { - for (var j = 0; j < extensionNames.length; ++j) { - Blockly.Extensions.apply(extensionNames[j], this, false); + for (let j = 0; j < extensionNames.length; ++j) { + Extensions.apply(extensionNames[j], this, false); } } }; @@ -1591,12 +1601,12 @@ Blockly.Block.prototype.jsonInit = function(json) { * @param {string} warningPrefix Warning prefix string identifying block. * @private */ -Blockly.Block.prototype.jsonInitColour_ = function(json, warningPrefix) { +Block.prototype.jsonInitColour_ = function(json, warningPrefix) { if ('colour' in json) { if (json['colour'] === undefined) { console.warn(warningPrefix + 'Undefined colour value.'); } else { - var rawValue = json['colour']; + const rawValue = json['colour']; try { this.setColour(rawValue); } catch (e) { @@ -1612,8 +1622,8 @@ Blockly.Block.prototype.jsonInitColour_ = function(json, warningPrefix) { * @param {string} warningPrefix Warning prefix string identifying block. * @private */ -Blockly.Block.prototype.jsonInitStyle_ = function(json, warningPrefix) { - var blockStyleName = json['style']; +Block.prototype.jsonInitStyle_ = function(json, warningPrefix) { + const blockStyleName = json['style']; try { this.setStyle(blockStyleName); } catch (styleError) { @@ -1630,23 +1640,23 @@ Blockly.Block.prototype.jsonInitStyle_ = function(json, warningPrefix) { * @param {!Object} mixinObj The key/values pairs to add to this block object. * @param {boolean=} opt_disableCheck Option flag to disable overwrite checks. */ -Blockly.Block.prototype.mixin = function(mixinObj, opt_disableCheck) { +Block.prototype.mixin = function(mixinObj, opt_disableCheck) { if (opt_disableCheck !== undefined && typeof opt_disableCheck != 'boolean') { throw Error('opt_disableCheck must be a boolean if provided'); } if (!opt_disableCheck) { - var overwrites = []; - for (var key in mixinObj) { + const overwrites = []; + for (let key in mixinObj) { if (this[key] !== undefined) { overwrites.push(key); } } if (overwrites.length) { - throw Error('Mixin will overwrite block members: ' + - JSON.stringify(overwrites)); + throw Error( + 'Mixin will overwrite block members: ' + JSON.stringify(overwrites)); } } - Blockly.utils.object.mixin(this, mixinObj); + object.mixin(this, mixinObj); }; /** @@ -1659,27 +1669,27 @@ Blockly.Block.prototype.mixin = function(mixinObj, opt_disableCheck) { * @param {string} warningPrefix Warning prefix string identifying block. * @private */ -Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign, - warningPrefix) { - var tokens = Blockly.utils.tokenizeInterpolation(message); +Block.prototype.interpolate_ = function( + message, args, lastDummyAlign, warningPrefix) { + const tokens = utils.tokenizeInterpolation(message); this.validateTokens_(tokens, args.length); - var elements = this.interpolateArguments_(tokens, args, lastDummyAlign); + const elements = this.interpolateArguments_(tokens, args, lastDummyAlign); // An array of [field, fieldName] tuples. - var fieldStack = []; - for (var i = 0, element; (element = elements[i]); i++) { + const fieldStack = []; + for (let i = 0, element; (element = elements[i]); i++) { if (this.isInputKeyword_(element['type'])) { - var input = this.inputFromJson_(element, warningPrefix); + const input = this.inputFromJson_(element, warningPrefix); // Should never be null, but just in case. if (input) { - for (var j = 0, tuple; (tuple = fieldStack[j]); j++) { + for (let j = 0, tuple; (tuple = fieldStack[j]); j++) { input.appendField(tuple[0], tuple[1]); } fieldStack.length = 0; } } else { // All other types, including ones starting with 'input_' get routed here. - var field = this.fieldFromJson_(element); + const field = this.fieldFromJson_(element); if (field) { fieldStack.push([field, element['name']]); } @@ -1695,27 +1705,30 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign, * @param {number} argsCount The number of args that need to be referred to. * @private */ -Blockly.Block.prototype.validateTokens_ = function(tokens, argsCount) { - var visitedArgsHash = []; - var visitedArgsCount = 0; - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i]; +Block.prototype.validateTokens_ = function(tokens, argsCount) { + const visitedArgsHash = []; + let visitedArgsCount = 0; + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; if (typeof token != 'number') { continue; } if (token < 1 || token > argsCount) { - throw Error('Block "' + this.type + '": ' + + throw Error( + 'Block "' + this.type + '": ' + 'Message index %' + token + ' out of range.'); } if (visitedArgsHash[token]) { - throw Error('Block "' + this.type + '": ' + + throw Error( + 'Block "' + this.type + '": ' + 'Message index %' + token + ' duplicated.'); } visitedArgsHash[token] = true; visitedArgsCount++; } if (visitedArgsCount != argsCount) { - throw Error('Block "' + this.type + '": ' + + throw Error( + 'Block "' + this.type + '": ' + 'Message does not reference all ' + argsCount + ' arg(s).'); } }; @@ -1732,35 +1745,34 @@ Blockly.Block.prototype.validateTokens_ = function(tokens, argsCount) { * to the block. * @private */ -Blockly.Block.prototype.interpolateArguments_ = - function(tokens, args, lastDummyAlign) { - var elements = []; - for (var i = 0; i < tokens.length; i++) { - var element = tokens[i]; - if (typeof element == 'number') { - element = args[element - 1]; - } - // Args can be strings, which is why this isn't elseif. - if (typeof element == 'string') { - element = this.stringToFieldJson_(element); - if (!element) { - continue; - } - } - elements.push(element); +Block.prototype.interpolateArguments_ = function(tokens, args, lastDummyAlign) { + const elements = []; + for (let i = 0; i < tokens.length; i++) { + let element = tokens[i]; + if (typeof element == 'number') { + element = args[element - 1]; + } + // Args can be strings, which is why this isn't elseif. + if (typeof element == 'string') { + element = this.stringToFieldJson_(element); + if (!element) { + continue; } + } + elements.push(element); + } - var length = elements.length; - if (length && !this.isInputKeyword_(elements[length - 1]['type'])) { - var dummyInput = {'type': 'input_dummy'}; - if (lastDummyAlign) { - dummyInput['align'] = lastDummyAlign; - } - elements.push(dummyInput); - } + const length = elements.length; + if (length && !this.isInputKeyword_(elements[length - 1]['type'])) { + const dummyInput = {'type': 'input_dummy'}; + if (lastDummyAlign) { + dummyInput['align'] = lastDummyAlign; + } + elements.push(dummyInput); + } - return elements; - }; + return elements; +}; /** * Creates a field from the JSON definition of a field. If a field with the @@ -1768,15 +1780,15 @@ Blockly.Block.prototype.interpolateArguments_ = * the 'alt' property of the JSON definition (if it exists). * @param {{alt:(string|undefined)}} element The element to try to turn into a * field. - * @return {?Blockly.Field} The field defined by the JSON, or null if one + * @return {?Field} The field defined by the JSON, or null if one * couldn't be created. * @private */ -Blockly.Block.prototype.fieldFromJson_ = function(element) { - var field = Blockly.fieldRegistry.fromJson(element); +Block.prototype.fieldFromJson_ = function(element) { + const field = fieldRegistry.fromJson(element); if (!field && element['alt']) { if (typeof element['alt'] == 'string') { - var json = this.stringToFieldJson_(element['alt']); + const json = this.stringToFieldJson_(element['alt']); return json ? this.fieldFromJson_(json) : null; } return this.fieldFromJson_(element['alt']); @@ -1790,19 +1802,19 @@ Blockly.Block.prototype.fieldFromJson_ = function(element) { * @param {!Object} element The JSON to turn into an input. * @param {string} warningPrefix The prefix to add to warnings to help the * developer debug. - * @return {?Blockly.Input} The input that has been created, or null if one + * @return {?Input} The input that has been created, or null if one * could not be created for some reason (should never happen). * @private */ -Blockly.Block.prototype.inputFromJson_ = function(element, warningPrefix) { - var alignmentLookup = { - 'LEFT': Blockly.constants.ALIGN.LEFT, - 'RIGHT': Blockly.constants.ALIGN.RIGHT, - 'CENTRE': Blockly.constants.ALIGN.CENTRE, - 'CENTER': Blockly.constants.ALIGN.CENTRE +Block.prototype.inputFromJson_ = function(element, warningPrefix) { + const alignmentLookup = { + 'LEFT': constants.ALIGN.LEFT, + 'RIGHT': constants.ALIGN.RIGHT, + 'CENTRE': constants.ALIGN.CENTRE, + 'CENTER': constants.ALIGN.CENTRE }; - var input = null; + let input = null; switch (element['type']) { case 'input_value': input = this.appendValueInput(element['name']); @@ -1823,10 +1835,9 @@ Blockly.Block.prototype.inputFromJson_ = function(element, warningPrefix) { input.setCheck(element['check']); } if (element['align']) { - var alignment = alignmentLookup[element['align'].toUpperCase()]; + const alignment = alignmentLookup[element['align'].toUpperCase()]; if (alignment === undefined) { - console.warn(warningPrefix + 'Illegal align value: ', - element['align']); + console.warn(warningPrefix + 'Illegal align value: ', element['align']); } else { input.setAlign(alignment); } @@ -1841,9 +1852,8 @@ Blockly.Block.prototype.inputFromJson_ = function(element, warningPrefix) { * false otherwise. * @private */ -Blockly.Block.prototype.isInputKeyword_ = function(str) { - return str == 'input_value' || - str == 'input_statement' || +Block.prototype.isInputKeyword_ = function(str) { + return str == 'input_value' || str == 'input_statement' || str == 'input_dummy'; }; @@ -1854,7 +1864,7 @@ Blockly.Block.prototype.isInputKeyword_ = function(str) { * @return {?{text: string, type: string}} The JSON definition or null. * @private */ -Blockly.Block.prototype.stringToFieldJson_ = function(str) { +Block.prototype.stringToFieldJson_ = function(str) { str = str.trim(); if (str) { return { @@ -1870,19 +1880,18 @@ Blockly.Block.prototype.stringToFieldJson_ = function(str) { * @param {number} type One of Blockly.inputTypes. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. - * @return {!Blockly.Input} The input object created. + * @return {!Input} The input object created. * @protected */ -Blockly.Block.prototype.appendInput_ = function(type, name) { - var connection = null; - if (type == Blockly.inputTypes.VALUE || - type == Blockly.inputTypes.STATEMENT) { +Block.prototype.appendInput_ = function(type, name) { + let connection = null; + if (type == inputTypes.VALUE || type == inputTypes.STATEMENT) { connection = this.makeConnection_(type); } - if (type == Blockly.inputTypes.STATEMENT) { + if (type == inputTypes.STATEMENT) { this.statementInputCount++; } - var input = new Blockly.Input(type, name, this, connection); + const input = new Input(type, name, this, connection); // Append input to list. this.inputList.push(input); return input; @@ -1894,14 +1903,14 @@ Blockly.Block.prototype.appendInput_ = function(type, name) { * @param {?string} refName Name of input that should be after the moved input, * or null to be the input at the end. */ -Blockly.Block.prototype.moveInputBefore = function(name, refName) { +Block.prototype.moveInputBefore = function(name, refName) { if (name == refName) { return; } // Find both inputs. - var inputIndex = -1; - var refIndex = refName ? -1 : this.inputList.length; - for (var i = 0, input; (input = this.inputList[i]); i++) { + let inputIndex = -1; + let refIndex = refName ? -1 : this.inputList.length; + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.name == name) { inputIndex = i; if (refIndex != -1) { @@ -1928,8 +1937,7 @@ Blockly.Block.prototype.moveInputBefore = function(name, refName) { * @param {number} inputIndex Index of the input to move. * @param {number} refIndex Index of input that should be after the moved input. */ -Blockly.Block.prototype.moveNumberedInputBefore = function( - inputIndex, refIndex) { +Block.prototype.moveNumberedInputBefore = function(inputIndex, refIndex) { // Validate arguments. if (inputIndex == refIndex) { throw Error('Can\'t move input to itself.'); @@ -1941,7 +1949,7 @@ Blockly.Block.prototype.moveNumberedInputBefore = function( throw RangeError('Reference input ' + refIndex + ' out of bounds.'); } // Remove input. - var input = this.inputList[inputIndex]; + const input = this.inputList[inputIndex]; this.inputList.splice(inputIndex, 1); if (inputIndex < refIndex) { refIndex--; @@ -1954,13 +1962,14 @@ Blockly.Block.prototype.moveNumberedInputBefore = function( * Remove an input from this block. * @param {string} name The name of the input. * @param {boolean=} opt_quiet True to prevent an error if input is not present. - * @return {boolean} True if operation succeeds, false if input is not present and opt_quiet is true + * @return {boolean} True if operation succeeds, false if input is not present + * and opt_quiet is true. * @throws {Error} if the input is not present and opt_quiet is not true. */ -Blockly.Block.prototype.removeInput = function(name, opt_quiet) { - for (var i = 0, input; (input = this.inputList[i]); i++) { +Block.prototype.removeInput = function(name, opt_quiet) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.name == name) { - if (input.type == Blockly.inputTypes.STATEMENT) { + if (input.type == inputTypes.STATEMENT) { this.statementInputCount--; } input.dispose(); @@ -1977,10 +1986,10 @@ Blockly.Block.prototype.removeInput = function(name, opt_quiet) { /** * Fetches the named input object. * @param {string} name The name of the input. - * @return {?Blockly.Input} The input object, or null if input does not exist. + * @return {?Input} The input object, or null if input does not exist. */ -Blockly.Block.prototype.getInput = function(name) { - for (var i = 0, input; (input = this.inputList[i]); i++) { +Block.prototype.getInput = function(name) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.name == name) { return input; } @@ -1992,11 +2001,11 @@ Blockly.Block.prototype.getInput = function(name) { /** * Fetches the block attached to the named input. * @param {string} name The name of the input. - * @return {?Blockly.Block} The attached value block, or null if the input is + * @return {?Block} The attached value block, or null if the input is * either disconnected or if the input does not exist. */ -Blockly.Block.prototype.getInputTargetBlock = function(name) { - var input = this.getInput(name); +Block.prototype.getInputTargetBlock = function(name) { + const input = this.getInput(name); return input && input.connection && input.connection.targetBlock(); }; @@ -2004,7 +2013,7 @@ Blockly.Block.prototype.getInputTargetBlock = function(name) { * Returns the comment on this block (or null if there is no comment). * @return {?string} Block's comment. */ -Blockly.Block.prototype.getCommentText = function() { +Block.prototype.getCommentText = function() { return this.commentModel.text; }; @@ -2012,11 +2021,11 @@ Blockly.Block.prototype.getCommentText = function() { * Set this block's comment text. * @param {?string} text The text, or null to delete. */ -Blockly.Block.prototype.setCommentText = function(text) { +Block.prototype.setCommentText = function(text) { if (this.commentModel.text == text) { return; } - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( this, 'comment', null, this.commentModel.text, text)); this.commentModel.text = text; this.comment = text; // For backwards compatibility. @@ -2028,25 +2037,25 @@ Blockly.Block.prototype.setCommentText = function(text) { * @param {string=} _opt_id An optional ID for the warning text to be able to * maintain multiple warnings. */ -Blockly.Block.prototype.setWarningText = function(_text, _opt_id) { +Block.prototype.setWarningText = function(_text, _opt_id) { // NOP. }; /** * Give this block a mutator dialog. - * @param {Blockly.Mutator} _mutator A mutator dialog instance or null to + * @param {Mutator} _mutator A mutator dialog instance or null to * remove. */ -Blockly.Block.prototype.setMutator = function(_mutator) { +Block.prototype.setMutator = function(_mutator) { // NOP. }; /** * Return the coordinates of the top-left corner of this block relative to the * drawing surface's origin (0,0), in workspace units. - * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. + * @return {!Coordinate} Object with .x and .y properties. */ -Blockly.Block.prototype.getRelativeToSurfaceXY = function() { +Block.prototype.getRelativeToSurfaceXY = function() { return this.xy_; }; @@ -2055,24 +2064,24 @@ Blockly.Block.prototype.getRelativeToSurfaceXY = function() { * @param {number} dx Horizontal offset, in workspace units. * @param {number} dy Vertical offset, in workspace units. */ -Blockly.Block.prototype.moveBy = function(dx, dy) { +Block.prototype.moveBy = function(dx, dy) { if (this.parentBlock_) { throw Error('Block has parent.'); } - var event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this); + const event = new (Events.get(Events.BLOCK_MOVE))(this); this.xy_.translate(dx, dy); event.recordNew(); - Blockly.Events.fire(event); + Events.fire(event); }; /** * Create a connection of the specified type. * @param {number} type The type of the connection to create. - * @return {!Blockly.Connection} A new connection of the specified type. + * @return {!Connection} A new connection of the specified type. * @protected */ -Blockly.Block.prototype.makeConnection_ = function(type) { - return new Blockly.Connection(this, type); +Block.prototype.makeConnection_ = function(type) { + return new Connection(this, type); }; /** @@ -2082,7 +2091,7 @@ Blockly.Block.prototype.makeConnection_ = function(type) { * whether shadow blocks are counted as filled. Defaults to true. * @return {boolean} True if all inputs are filled, false otherwise. */ -Blockly.Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { +Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { // Account for the shadow block filledness toggle. if (opt_shadowBlocksAreFilled === undefined) { opt_shadowBlocksAreFilled = true; @@ -2092,18 +2101,18 @@ Blockly.Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { } // Recursively check each input block of the current block. - for (var i = 0, input; (input = this.inputList[i]); i++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (!input.connection) { continue; } - var target = input.connection.targetBlock(); + const target = input.connection.targetBlock(); if (!target || !target.allInputsFilled(opt_shadowBlocksAreFilled)) { return false; } } // Recursively check the next block after the current block. - var next = this.getNextBlock(); + const next = this.getNextBlock(); if (next) { return next.allInputsFilled(opt_shadowBlocksAreFilled); } @@ -2117,13 +2126,15 @@ Blockly.Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { * * Intended to on be used in console logs and errors. If you need a string that * uses the user's native language (including block text, field values, and - * child blocks), use [toString()]{@link Blockly.Block#toString}. + * child blocks), use [toString()]{@link Block#toString}. * @return {string} The description. */ -Blockly.Block.prototype.toDevString = function() { - var msg = this.type ? '"' + this.type + '" block' : 'Block'; +Block.prototype.toDevString = function() { + let msg = this.type ? '"' + this.type + '" block' : 'Block'; if (this.id) { msg += ' (id="' + this.id + '")'; } return msg; }; + +exports = Block; diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 2b911ef09..717713915 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -8,8 +8,9 @@ * @fileoverview A class that manages a surface for dragging blocks. When a * block drag is started, we move the block (and children) to a separate DOM * element that we move around using translate3d. At the end of the drag, the - * blocks are put back in into the SVG they came from. This helps performance by - * avoiding repainting the entire SVG on every mouse move while dragging blocks. + * blocks are put back in into the SVG they came from. This helps + * performance by avoiding repainting the entire SVG on every mouse move + * while dragging blocks. * @author picklesrus */ @@ -19,9 +20,9 @@ goog.module('Blockly.BlockDragSurfaceSvg'); goog.module.declareLegacyNamespace(); const Coordinate = goog.require('Blockly.utils.Coordinate'); -const {G, SVG} = goog.require('Blockly.utils.Svg'); -const {createSvgElement, HTML_NS, setCssTransform, SVG_NS, XLINK_NS} = goog.require('Blockly.utils.dom'); -const {getRelativeXY} = goog.require('Blockly.utils'); +const Svg = goog.require('Blockly.utils.Svg'); +const dom = goog.require('Blockly.utils.dom'); +const utils = goog.require('Blockly.utils'); /** @@ -94,16 +95,16 @@ BlockDragSurfaceSvg.prototype.createDom = function() { if (this.SVG_) { return; // Already created. } - this.SVG_ = createSvgElement( - SVG, { - 'xmlns': SVG_NS, - 'xmlns:html': HTML_NS, - 'xmlns:xlink': XLINK_NS, + this.SVG_ = dom.createSvgElement( + Svg.SVG, { + 'xmlns': dom.SVG_NS, + 'xmlns:html': dom.HTML_NS, + 'xmlns:xlink': dom.XLINK_NS, 'version': '1.1', 'class': 'blocklyBlockDragSurface' }, this.container_); - this.dragGroup_ = createSvgElement(G, {}, this.SVG_); + this.dragGroup_ = dom.createSvgElement(Svg.G, {}, this.SVG_); }; /** @@ -157,7 +158,7 @@ BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() { y = y.toFixed(0); this.SVG_.style.display = 'block'; - setCssTransform(this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0)'); + dom.setCssTransform(this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0)'); }; /** @@ -191,7 +192,7 @@ BlockDragSurfaceSvg.prototype.translateSurface = function(x, y) { * @return {!Coordinate} Current translation of the surface. */ BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() { - const xy = getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); + const xy = utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); return new Coordinate(xy.x / this.scale_, xy.y / this.scale_); }; diff --git a/core/block_dragger.js b/core/block_dragger.js index b7c11e8a3..32a6f4922 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -17,13 +17,14 @@ goog.module.declareLegacyNamespace(); const BlockSvg = goog.requireType('Blockly.BlockSvg'); const Coordinate = goog.require('Blockly.utils.Coordinate'); /* eslint-disable-next-line no-unused-vars */ -const IBlockDragger = goog.require('Blockly.IBlockDragger'); +const IBlockDragger = goog.requireType('Blockly.IBlockDragger'); /* eslint-disable-next-line no-unused-vars */ const IDragTarget = goog.requireType('Blockly.IDragTarget'); const InsertionMarkerManager = goog.require('Blockly.InsertionMarkerManager'); /* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); const blockAnimation = goog.require('Blockly.blockAnimations'); +const common = goog.require('Blockly.common'); const dom = goog.require('Blockly.utils.dom'); const events = goog.require('Blockly.Events'); const registry = goog.require('Blockly.registry'); @@ -332,7 +333,7 @@ BlockDragger.prototype.maybeDeleteBlock_ = function() { // Fire a move event, so we know where to go back to for an undo. this.fireMoveEvent_(); this.draggingBlock_.dispose(false, true); - Blockly.draggingConnections = []; + common.draggingConnections.length = 0; return true; } return false; diff --git a/core/block_svg.js b/core/block_svg.js index fd5be3212..4c2545eb1 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -10,92 +10,110 @@ */ 'use strict'; -goog.provide('Blockly.BlockSvg'); +goog.module('Blockly.BlockSvg'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.ASTNode'); -goog.require('Blockly.Block'); -goog.require('Blockly.blockAnimations'); -goog.require('Blockly.blockRendering.IPathObject'); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.constants'); -goog.require('Blockly.ContextMenu'); -goog.require('Blockly.ContextMenuRegistry'); -goog.require('Blockly.Events'); +const ASTNode = goog.require('Blockly.ASTNode'); +const Block = goog.require('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlockRenderingDebug = goog.requireType('Blockly.blockRendering.Debug'); +/* eslint-disable-next-line no-unused-vars */ +const Comment = goog.requireType('Blockly.Comment'); +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +const ContextMenu = goog.require('Blockly.ContextMenu'); +const ContextMenuRegistry = goog.require('Blockly.ContextMenuRegistry'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +const FieldLabel = goog.require('Blockly.FieldLabel'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocationSvg = goog.requireType('Blockly.IASTNodeLocationSvg'); +/* eslint-disable-next-line no-unused-vars */ +const IBoundedElement = goog.requireType('Blockly.IBoundedElement'); +/* eslint-disable-next-line no-unused-vars */ +const ICopyable = goog.requireType('Blockly.ICopyable'); +/* eslint-disable-next-line no-unused-vars */ +const IDraggable = goog.requireType('Blockly.IDraggable'); +/* eslint-disable-next-line no-unused-vars */ +const IPathObject = goog.requireType('Blockly.blockRendering.IPathObject'); +/* eslint-disable-next-line no-unused-vars */ +const Icon = goog.requireType('Blockly.Icon'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const MarkerManager = goog.require('Blockly.MarkerManager'); +const Msg = goog.require('Blockly.Msg'); +/* eslint-disable-next-line no-unused-vars */ +const Mutator = goog.requireType('Blockly.Mutator'); +const Rect = goog.require('Blockly.utils.Rect'); +const RenderedConnection = goog.require('Blockly.RenderedConnection'); +const Svg = goog.require('Blockly.utils.Svg'); +const TabNavigateCursor = goog.require('Blockly.TabNavigateCursor'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +const Tooltip = goog.require('Blockly.Tooltip'); +/* eslint-disable-next-line no-unused-vars */ +const Warning = goog.requireType('Blockly.Warning'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const Xml = goog.require('Blockly.Xml'); +const blockAnimations = goog.require('Blockly.blockAnimations'); +const browserEvents = goog.require('Blockly.browserEvents'); +const common = goog.require('Blockly.common'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const constants = goog.require('Blockly.constants'); +const deprecation = goog.require('Blockly.utils.deprecation'); +const dom = goog.require('Blockly.utils.dom'); +const internalConstants = goog.require('Blockly.internalConstants'); +const object = goog.require('Blockly.utils.object'); +const userAgent = goog.require('Blockly.utils.userAgent'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockMove'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.Selected'); -goog.require('Blockly.IASTNodeLocationSvg'); -goog.require('Blockly.IBoundedElement'); -goog.require('Blockly.ICopyable'); -goog.require('Blockly.IDraggable'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.Msg'); -goog.require('Blockly.RenderedConnection'); -goog.require('Blockly.TabNavigateCursor'); -goog.require('Blockly.Tooltip'); /** @suppress {extraRequire} */ goog.require('Blockly.Touch'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.deprecation'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.utils.userAgent'); -goog.require('Blockly.Xml'); - -goog.requireType('Blockly.blockRendering.Debug'); -goog.requireType('Blockly.Comment'); -goog.requireType('Blockly.Connection'); -goog.requireType('Blockly.Field'); -goog.requireType('Blockly.Input'); -goog.requireType('Blockly.Mutator'); -goog.requireType('Blockly.Theme'); -goog.requireType('Blockly.Warning'); -goog.requireType('Blockly.WorkspaceSvg'); /** * Class for a block's SVG representation. * Not normally called directly, workspace.newBlock() is preferred. - * @param {!Blockly.WorkspaceSvg} workspace The block's workspace. + * @param {!WorkspaceSvg} workspace The block's workspace. * @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. - * @extends {Blockly.Block} - * @implements {Blockly.IASTNodeLocationSvg} - * @implements {Blockly.IBoundedElement} - * @implements {Blockly.ICopyable} - * @implements {Blockly.IDraggable} + * @extends {Block} + * @implements {IASTNodeLocationSvg} + * @implements {IBoundedElement} + * @implements {ICopyable} + * @implements {IDraggable} * @constructor */ -Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { +const BlockSvg = function(workspace, prototypeName, opt_id) { // Create core elements for the block. /** * @type {!SVGGElement} * @private */ - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, {}, null); + this.svgGroup_ = dom.createSvgElement(Svg.G, {}, null); this.svgGroup_.translate_ = ''; /** * A block style object. - * @type {!Blockly.Theme.BlockStyle} + * @type {!Theme.BlockStyle} */ this.style = workspace.getRenderer().getConstants().getBlockStyle(null); /** * The renderer's path object. - * @type {Blockly.blockRendering.IPathObject} + * @type {IPathObject} * @package */ - this.pathObject = workspace.getRenderer().makePathObject( - this.svgGroup_, this.style); + this.pathObject = + workspace.getRenderer().makePathObject(this.svgGroup_, this.style); /** @type {boolean} */ this.rendered = false; @@ -108,14 +126,14 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { this.renderIsInProgress_ = false; - /** @type {!Blockly.WorkspaceSvg} */ + /** @type {!WorkspaceSvg} */ this.workspace = workspace; - /** @type {Blockly.RenderedConnection} */ + /** @type {RenderedConnection} */ this.outputConnection = null; - /** @type {Blockly.RenderedConnection} */ + /** @type {RenderedConnection} */ this.nextConnection = null; - /** @type {Blockly.RenderedConnection} */ + /** @type {RenderedConnection} */ this.previousConnection = null; /** @@ -125,36 +143,35 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @private */ this.useDragSurface_ = - Blockly.utils.is3dSupported() && !!workspace.getBlockDragSurface(); + utils.is3dSupported() && !!workspace.getBlockDragSurface(); - var svgPath = this.pathObject.svgPath; + const svgPath = this.pathObject.svgPath; svgPath.tooltip = this; - Blockly.Tooltip.bindMouseEvents(svgPath); - Blockly.BlockSvg.superClass_.constructor.call(this, - workspace, prototypeName, opt_id); + Tooltip.bindMouseEvents(svgPath); + BlockSvg.superClass_.constructor.call(this, workspace, prototypeName, opt_id); // Expose this block's ID on its top-level SVG group. if (this.svgGroup_.dataset) { this.svgGroup_.dataset['id'] = this.id; - } else if (Blockly.utils.userAgent.IE) { + } else if (userAgent.IE) { // SVGElement.dataset is not available on IE11, but data-* properties // can be set with setAttribute(). this.svgGroup_.setAttribute('data-id', this.id); } }; -Blockly.utils.object.inherits(Blockly.BlockSvg, Blockly.Block); +object.inherits(BlockSvg, Block); /** * Height of this block, not including any statement blocks above or below. * Height is in workspace units. */ -Blockly.BlockSvg.prototype.height = 0; +BlockSvg.prototype.height = 0; /** * Width of this block, including any connected value blocks. * Width is in workspace units. */ -Blockly.BlockSvg.prototype.width = 0; +BlockSvg.prototype.width = 0; /** * Map from IDs for warnings text to PIDs of functions to apply them. @@ -162,14 +179,14 @@ Blockly.BlockSvg.prototype.width = 0; * @type {Object} * @private */ -Blockly.BlockSvg.prototype.warningTextDb_ = null; +BlockSvg.prototype.warningTextDb_ = null; /** * Constant for identifying rows that are to be rendered inline. * Don't collide with Blockly.inputTypes. * @const */ -Blockly.BlockSvg.INLINE = -1; +BlockSvg.INLINE = -1; /** * ID to give the "collapsed warnings" warning. Allows us to remove the @@ -178,7 +195,7 @@ Blockly.BlockSvg.INLINE = -1; * @type {string} * @const */ -Blockly.BlockSvg.COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_'; +BlockSvg.COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_'; /** * An optional method called when a mutator dialog is first opened. @@ -187,53 +204,52 @@ Blockly.BlockSvg.COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_'; * block with any sub-blocks which are appropriate. This method must also be * coupled with defining a `compose` method for the default mutation dialog * button and UI to appear. - * @type {?function(Blockly.WorkspaceSvg):!Blockly.BlockSvg} + * @type {?function(WorkspaceSvg):!BlockSvg} */ -Blockly.BlockSvg.prototype.decompose; +BlockSvg.prototype.decompose; /** * An optional method called when a mutator dialog saves its content. * This function is called to modify the original block according to new * settings. This method must also be coupled with defining a `decompose` * method for the default mutation dialog button and UI to appear. - * @type {?function(!Blockly.BlockSvg)} + * @type {?function(!BlockSvg)} */ -Blockly.BlockSvg.prototype.compose; +BlockSvg.prototype.compose; /** * An optional method for defining custom block context menu items. * @type {?function(!Array)} */ -Blockly.BlockSvg.prototype.customContextMenu; +BlockSvg.prototype.customContextMenu; /** * An property used internally to reference the block's rendering debugger. - * @type {?Blockly.blockRendering.Debug} + * @type {?BlockRenderingDebug} * @package */ -Blockly.BlockSvg.prototype.renderingDebugger; +BlockSvg.prototype.renderingDebugger; /** * Create and initialize the SVG representation of the block. * May be called more than once. */ -Blockly.BlockSvg.prototype.initSvg = function() { +BlockSvg.prototype.initSvg = function() { if (!this.workspace.rendered) { throw TypeError('Workspace is headless.'); } - for (var i = 0, input; (input = this.inputList[i]); i++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { input.init(); } - var icons = this.getIcons(); - for (var i = 0; i < icons.length; i++) { + const icons = this.getIcons(); + for (let i = 0; i < icons.length; i++) { icons[i].createIcon(); } this.applyColour(); this.pathObject.updateMovable(this.isMovable()); - var svg = this.getSvgRoot(); + const svg = this.getSvgRoot(); if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) { - Blockly.browserEvents.conditionalBind( - svg, 'mousedown', this, this.onMouseDown_); + browserEvents.conditionalBind(svg, 'mousedown', this, this.onMouseDown_); } this.eventsInit_ = true; @@ -246,7 +262,7 @@ Blockly.BlockSvg.prototype.initSvg = function() { * Get the secondary colour of a block. * @return {?string} #RRGGBB string. */ -Blockly.BlockSvg.prototype.getColourSecondary = function() { +BlockSvg.prototype.getColourSecondary = function() { return this.style.colourSecondary; }; @@ -254,7 +270,7 @@ Blockly.BlockSvg.prototype.getColourSecondary = function() { * Get the tertiary colour of a block. * @return {?string} #RRGGBB string. */ -Blockly.BlockSvg.prototype.getColourTertiary = function() { +BlockSvg.prototype.getColourTertiary = function() { return this.style.colourTertiary; }; @@ -263,11 +279,9 @@ Blockly.BlockSvg.prototype.getColourTertiary = function() { * @return {?string} #RRGGBB string. * @deprecated Use style.colourSecondary. (2020 January 21) */ -Blockly.BlockSvg.prototype.getColourShadow = function() { - Blockly.utils.deprecation.warn( - 'BlockSvg.prototype.getColourShadow', - 'January 2020', - 'January 2021', +BlockSvg.prototype.getColourShadow = function() { + deprecation.warn( + 'BlockSvg.prototype.getColourShadow', 'January 2020', 'January 2021', 'style.colourSecondary'); return this.getColourSecondary(); }; @@ -281,25 +295,19 @@ Blockly.BlockSvg.prototype.getColourShadow = function() { * attributes will be defined (#RRGGBB strings). * @deprecated Use style.colourTertiary. (2020 January 21) */ -Blockly.BlockSvg.prototype.getColourBorder = function() { - Blockly.utils.deprecation.warn( - 'BlockSvg.prototype.getColourBorder', - 'January 2020', - 'January 2021', +BlockSvg.prototype.getColourBorder = function() { + deprecation.warn( + 'BlockSvg.prototype.getColourBorder', 'January 2020', 'January 2021', 'style.colourTertiary'); - var colourTertiary = this.getColourTertiary(); - return { - colourBorder: colourTertiary, - colourLight: null, - colourDark: null - }; + const colourTertiary = this.getColourTertiary(); + return {colourBorder: colourTertiary, colourLight: null, colourDark: null}; }; /** * Selects this block. Highlights the block visually and fires a select event * if the block is not already selected. */ -Blockly.BlockSvg.prototype.select = function() { +BlockSvg.prototype.select = function() { if (this.isShadow() && this.getParent()) { // Shadow blocks should not be selected. this.getParent().select(); @@ -308,20 +316,20 @@ Blockly.BlockSvg.prototype.select = function() { if (Blockly.selected == this) { return; } - var oldId = null; + let oldId = null; if (Blockly.selected) { oldId = Blockly.selected.id; // Unselect any previously selected block. - Blockly.Events.disable(); + Events.disable(); try { Blockly.selected.unselect(); } finally { - Blockly.Events.enable(); + Events.enable(); } } - var event = new (Blockly.Events.get(Blockly.Events.SELECTED))(oldId, this.id, - this.workspace.id); - Blockly.Events.fire(event); + const event = + new (Events.get(Events.SELECTED))(oldId, this.id, this.workspace.id); + Events.fire(event); Blockly.selected = this; this.addSelect(); }; @@ -330,50 +338,50 @@ Blockly.BlockSvg.prototype.select = function() { * Unselects this block. Unhighlights the block and fires a select (false) event * if the block is currently selected. */ -Blockly.BlockSvg.prototype.unselect = function() { +BlockSvg.prototype.unselect = function() { if (Blockly.selected != this) { return; } - var event = new (Blockly.Events.get(Blockly.Events.SELECTED))(this.id, null, - this.workspace.id); + const event = + new (Events.get(Events.SELECTED))(this.id, null, this.workspace.id); event.workspaceId = this.workspace.id; - Blockly.Events.fire(event); + Events.fire(event); Blockly.selected = null; this.removeSelect(); }; /** * Block's mutator icon (if any). - * @type {?Blockly.Mutator} + * @type {?Mutator} */ -Blockly.BlockSvg.prototype.mutator = null; +BlockSvg.prototype.mutator = null; /** * Block's comment icon (if any). - * @type {?Blockly.Comment} + * @type {?Comment} * @deprecated August 2019. Use getCommentIcon instead. */ -Blockly.BlockSvg.prototype.comment = null; +BlockSvg.prototype.comment = null; /** * Block's comment icon (if any). - * @type {?Blockly.Comment} + * @type {?Comment} * @private */ -Blockly.BlockSvg.prototype.commentIcon_ = null; +BlockSvg.prototype.commentIcon_ = null; /** * Block's warning icon (if any). - * @type {?Blockly.Warning} + * @type {?Warning} */ -Blockly.BlockSvg.prototype.warning = null; +BlockSvg.prototype.warning = null; /** * Returns a list of mutator, comment, and warning icons. - * @return {!Array} List of icons. + * @return {!Array} List of icons. */ -Blockly.BlockSvg.prototype.getIcons = function() { - var icons = []; +BlockSvg.prototype.getIcons = function() { + const icons = []; if (this.mutator) { icons.push(this.mutator); } @@ -388,21 +396,21 @@ Blockly.BlockSvg.prototype.getIcons = function() { /** * Sets the parent of this block to be a new block or null. - * @param {?Blockly.Block} newParent New parent block. + * @param {?Block} newParent New parent block. * @package * @override */ -Blockly.BlockSvg.prototype.setParent = function(newParent) { - var oldParent = this.parentBlock_; +BlockSvg.prototype.setParent = function(newParent) { + const oldParent = this.parentBlock_; if (newParent == oldParent) { return; } - Blockly.utils.dom.startTextWidthCache(); - Blockly.BlockSvg.superClass_.setParent.call(this, newParent); - Blockly.utils.dom.stopTextWidthCache(); + dom.startTextWidthCache(); + BlockSvg.superClass_.setParent.call(this, newParent); + dom.stopTextWidthCache(); - var svgRoot = this.getSvgRoot(); + const svgRoot = this.getSvgRoot(); // Bail early if workspace is clearing, or we aren't rendered. // We won't need to reattach ourselves anywhere. @@ -410,10 +418,10 @@ Blockly.BlockSvg.prototype.setParent = function(newParent) { return; } - var oldXY = this.getRelativeToSurfaceXY(); + const oldXY = this.getRelativeToSurfaceXY(); if (newParent) { newParent.getSvgRoot().appendChild(svgRoot); - var newXY = this.getRelativeToSurfaceXY(); + const newXY = this.getRelativeToSurfaceXY(); // Move the connections to match the child's new position. this.moveConnections(newXY.x - oldXY.x, newXY.y - oldXY.y); } @@ -433,37 +441,38 @@ Blockly.BlockSvg.prototype.setParent = function(newParent) { * If the block is on the workspace, (0, 0) is the origin of the workspace * coordinate system. * This does not change with workspace scale. - * @return {!Blockly.utils.Coordinate} Object with .x and .y properties in + * @return {!Coordinate} Object with .x and .y properties in * workspace coordinates. */ -Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { - var x = 0; - var y = 0; +BlockSvg.prototype.getRelativeToSurfaceXY = function() { + let x = 0; + let y = 0; - var dragSurfaceGroup = this.useDragSurface_ ? - this.workspace.getBlockDragSurface().getGroup() : null; + const dragSurfaceGroup = this.useDragSurface_ ? + this.workspace.getBlockDragSurface().getGroup() : + null; - var element = this.getSvgRoot(); + let element = this.getSvgRoot(); if (element) { do { // Loop through this block and every parent. - var xy = Blockly.utils.getRelativeXY(element); + const xy = utils.getRelativeXY(element); x += xy.x; y += xy.y; // If this element is the current element on the drag surface, include // the translation of the drag surface itself. if (this.useDragSurface_ && this.workspace.getBlockDragSurface().getCurrentBlock() == element) { - var surfaceTranslation = + const surfaceTranslation = this.workspace.getBlockDragSurface().getSurfaceTranslation(); x += surfaceTranslation.x; y += surfaceTranslation.y; } element = /** @type {!SVGElement} */ (element.parentNode); } while (element && element != this.workspace.getCanvas() && - element != dragSurfaceGroup); + element != dragSurfaceGroup); } - return new Blockly.utils.Coordinate(x, y); + return new Coordinate(x, y); }; /** @@ -471,20 +480,21 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { * @param {number} dx Horizontal offset in workspace units. * @param {number} dy Vertical offset in workspace units. */ -Blockly.BlockSvg.prototype.moveBy = function(dx, dy) { +BlockSvg.prototype.moveBy = function(dx, dy) { if (this.parentBlock_) { throw Error('Block has parent.'); } - var eventsEnabled = Blockly.Events.isEnabled(); + const eventsEnabled = Events.isEnabled(); + let event; if (eventsEnabled) { - var event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this); + event = new (Events.get(Events.BLOCK_MOVE))(this); } - var xy = this.getRelativeToSurfaceXY(); + const xy = this.getRelativeToSurfaceXY(); this.translate(xy.x + dx, xy.y + dy); this.moveConnections(dx, dy); if (eventsEnabled) { event.recordNew(); - Blockly.Events.fire(event); + Events.fire(event); } this.workspace.resizeContents(); }; @@ -495,9 +505,8 @@ Blockly.BlockSvg.prototype.moveBy = function(dx, dy) { * @param {number} x The x coordinate of the translation in workspace units. * @param {number} y The y coordinate of the translation in workspace units. */ -Blockly.BlockSvg.prototype.translate = function(x, y) { - this.getSvgRoot().setAttribute('transform', - 'translate(' + x + ',' + y + ')'); +BlockSvg.prototype.translate = function(x, y) { + this.getSvgRoot().setAttribute('transform', 'translate(' + x + ',' + y + ')'); }; /** @@ -506,7 +515,7 @@ Blockly.BlockSvg.prototype.translate = function(x, y) { * Does nothing if useDragSurface_ is false. * @package */ -Blockly.BlockSvg.prototype.moveToDragSurface = function() { +BlockSvg.prototype.moveToDragSurface = function() { if (!this.useDragSurface_) { return; } @@ -514,11 +523,11 @@ Blockly.BlockSvg.prototype.moveToDragSurface = function() { // is equal to the current relative-to-surface position, // to keep the position in sync as it move on/off the surface. // This is in workspace coordinates. - var xy = this.getRelativeToSurfaceXY(); + const xy = this.getRelativeToSurfaceXY(); this.clearTransformAttributes_(); this.workspace.getBlockDragSurface().translateSurface(xy.x, xy.y); // Execute the move on the top-level SVG component - var svg = this.getSvgRoot(); + const svg = this.getSvgRoot(); if (svg) { this.workspace.getBlockDragSurface().setBlocksAndShow(svg); } @@ -526,10 +535,10 @@ Blockly.BlockSvg.prototype.moveToDragSurface = function() { /** * Move a block to a position. - * @param {Blockly.utils.Coordinate} xy The position to move to in workspace units. + * @param {Coordinate} xy The position to move to in workspace units. */ -Blockly.BlockSvg.prototype.moveTo = function(xy) { - var curXY = this.getRelativeToSurfaceXY(); +BlockSvg.prototype.moveTo = function(xy) { + const curXY = this.getRelativeToSurfaceXY(); this.moveBy(xy.x - curXY.x, xy.y - curXY.y); }; @@ -537,11 +546,11 @@ Blockly.BlockSvg.prototype.moveTo = function(xy) { * Move this block back to the workspace block canvas. * Generally should be called at the same time as setDragging_(false). * Does nothing if useDragSurface_ is false. - * @param {!Blockly.utils.Coordinate} newXY The position the block should take on + * @param {!Coordinate} newXY The position the block should take on * on the workspace canvas, in workspace coordinates. * @package */ -Blockly.BlockSvg.prototype.moveOffDragSurface = function(newXY) { +BlockSvg.prototype.moveOffDragSurface = function(newXY) { if (!this.useDragSurface_) { return; } @@ -554,17 +563,17 @@ Blockly.BlockSvg.prototype.moveOffDragSurface = function(newXY) { * Move this block during a drag, taking into account whether we are using a * drag surface to translate blocks. * This block must be a top-level block. - * @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in + * @param {!Coordinate} newLoc The location to translate to, in * workspace coordinates. * @package */ -Blockly.BlockSvg.prototype.moveDuringDrag = function(newLoc) { +BlockSvg.prototype.moveDuringDrag = function(newLoc) { if (this.useDragSurface_) { this.workspace.getBlockDragSurface().translateSurface(newLoc.x, newLoc.y); } else { this.svgGroup_.translate_ = 'translate(' + newLoc.x + ',' + newLoc.y + ')'; - this.svgGroup_.setAttribute('transform', - this.svgGroup_.translate_ + this.svgGroup_.skew_); + this.svgGroup_.setAttribute( + 'transform', this.svgGroup_.translate_ + this.svgGroup_.skew_); } }; @@ -573,14 +582,14 @@ Blockly.BlockSvg.prototype.moveDuringDrag = function(newLoc) { * Used when the block is switching from 3d to 2d transform or vice versa. * @private */ -Blockly.BlockSvg.prototype.clearTransformAttributes_ = function() { +BlockSvg.prototype.clearTransformAttributes_ = function() { this.getSvgRoot().removeAttribute('transform'); }; /** * Snap this block to the nearest grid point. */ -Blockly.BlockSvg.prototype.snapToGrid = function() { +BlockSvg.prototype.snapToGrid = function() { if (!this.workspace) { return; // Deleted block. } @@ -593,18 +602,18 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { if (this.isInFlyout) { return; // Don't move blocks around in a flyout. } - var grid = this.workspace.getGrid(); + const grid = this.workspace.getGrid(); if (!grid || !grid.shouldSnap()) { return; // Config says no snapping. } - var spacing = grid.getSpacing(); - var half = spacing / 2; - var xy = this.getRelativeToSurfaceXY(); - var dx = Math.round((xy.x - half) / spacing) * spacing + half - xy.x; - var dy = Math.round((xy.y - half) / spacing) * spacing + half - xy.y; - dx = Math.round(dx); - dy = Math.round(dy); - if (dx != 0 || dy != 0) { + const spacing = grid.getSpacing(); + const half = spacing / 2; + const xy = this.getRelativeToSurfaceXY(); + const dx = + Math.round(Math.round((xy.x - half) / spacing) * spacing + half - xy.x); + const dy = + Math.round(Math.round((xy.y - half) / spacing) * spacing + half - xy.y); + if (dx || dy) { this.moveBy(dx, dy); } }; @@ -613,12 +622,13 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { * Returns the coordinates of a bounding box describing the dimensions of this * block and any blocks stacked below it. * Coordinate system: workspace coordinates. - * @return {!Blockly.utils.Rect} Object with coordinates of the bounding box. + * @return {!Rect} Object with coordinates of the bounding box. */ -Blockly.BlockSvg.prototype.getBoundingRectangle = function() { - var blockXY = this.getRelativeToSurfaceXY(); - var blockBounds = this.getHeightWidth(); - var left, right; +BlockSvg.prototype.getBoundingRectangle = function() { + const blockXY = this.getRelativeToSurfaceXY(); + const blockBounds = this.getHeightWidth(); + let left; + let right; if (this.RTL) { left = blockXY.x - blockBounds.width; right = blockXY.x; @@ -626,19 +636,18 @@ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { left = blockXY.x; right = blockXY.x + blockBounds.width; } - return new Blockly.utils.Rect( - blockXY.y, blockXY.y + blockBounds.height, left, right); + return new Rect(blockXY.y, blockXY.y + blockBounds.height, left, right); }; /** * Notify every input on this block to mark its fields as dirty. * A dirty field is a field that needs to be re-rendered. */ -Blockly.BlockSvg.prototype.markDirty = function() { - this.pathObject.constants = - (/** @type {!Blockly.WorkspaceSvg} */ (this.workspace)) - .getRenderer().getConstants(); - for (var i = 0, input; (input = this.inputList[i]); i++) { +BlockSvg.prototype.markDirty = function() { + this.pathObject.constants = (/** @type {!WorkspaceSvg} */ (this.workspace)) + .getRenderer() + .getConstants(); + for (let i = 0, input; (input = this.inputList[i]); i++) { input.markDirty(); } }; @@ -647,11 +656,11 @@ Blockly.BlockSvg.prototype.markDirty = function() { * Set whether the block is collapsed or not. * @param {boolean} collapsed True if collapsed. */ -Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { +BlockSvg.prototype.setCollapsed = function(collapsed) { if (this.collapsed_ == collapsed) { return; } - Blockly.BlockSvg.superClass_.setCollapsed.call(this, collapsed); + BlockSvg.superClass_.setCollapsed.call(this, collapsed); if (!collapsed) { this.updateCollapsed_(); } else if (this.rendered) { @@ -666,12 +675,12 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { * for that state. * @private */ -Blockly.BlockSvg.prototype.updateCollapsed_ = function() { - var collapsed = this.isCollapsed(); - var collapsedInputName = Blockly.constants.COLLAPSED_INPUT_NAME; - var collapsedFieldName = Blockly.constants.COLLAPSED_FIELD_NAME; +BlockSvg.prototype.updateCollapsed_ = function() { + const collapsed = this.isCollapsed(); + const collapsedInputName = constants.COLLAPSED_INPUT_NAME; + const collapsedFieldName = constants.COLLAPSED_FIELD_NAME; - for (var i = 0, input; (input = this.inputList[i]); i++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.name != collapsedInputName) { input.setVisible(!collapsed); } @@ -683,31 +692,31 @@ Blockly.BlockSvg.prototype.updateCollapsed_ = function() { return; } - var icons = this.getIcons(); - for (var i = 0, icon; (icon = icons[i]); i++) { + const icons = this.getIcons(); + for (let i = 0, icon; (icon = icons[i]); i++) { icon.setVisible(false); } - var text = this.toString(Blockly.internalConstants.COLLAPSE_CHARS); - var field = this.getField(collapsedFieldName); + const text = this.toString(internalConstants.COLLAPSE_CHARS); + const field = this.getField(collapsedFieldName); if (field) { field.setValue(text); return; } - var input = this.getInput(collapsedInputName) || + const input = this.getInput(collapsedInputName) || this.appendDummyInput(collapsedInputName); - input.appendField(new Blockly.FieldLabel(text), collapsedFieldName); + input.appendField(new FieldLabel(text), collapsedFieldName); }; /** * Open the next (or previous) FieldTextInput. - * @param {!Blockly.Field} start Current field. + * @param {!Field} start Current field. * @param {boolean} forward If true go forward, otherwise backward. */ -Blockly.BlockSvg.prototype.tab = function(start, forward) { - var tabCursor = new Blockly.TabNavigateCursor(); - tabCursor.setCurNode(Blockly.ASTNode.createFieldNode(start)); - var currentNode = tabCursor.getCurNode(); +BlockSvg.prototype.tab = function(start, forward) { + const tabCursor = new TabNavigateCursor(); + tabCursor.setCurNode(ASTNode.createFieldNode(start)); + const currentNode = tabCursor.getCurNode(); if (forward) { tabCursor.next(); @@ -715,9 +724,9 @@ Blockly.BlockSvg.prototype.tab = function(start, forward) { tabCursor.prev(); } - var nextNode = tabCursor.getCurNode(); + const nextNode = tabCursor.getCurNode(); if (nextNode && nextNode !== currentNode) { - var nextField = /** @type {!Blockly.Field} */ (nextNode.getLocation()); + const nextField = /** @type {!Field} */ (nextNode.getLocation()); nextField.showEditor(); // Also move the cursor if we're in keyboard nav mode. @@ -732,8 +741,8 @@ Blockly.BlockSvg.prototype.tab = function(start, forward) { * @param {!Event} e Mouse down event or touch start event. * @private */ -Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { - var gesture = this.workspace && this.workspace.getGesture(e); +BlockSvg.prototype.onMouseDown_ = function(e) { + const gesture = this.workspace && this.workspace.getGesture(e); if (gesture) { gesture.handleBlockStart(e, this); } @@ -743,8 +752,9 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { * Load the block's help page in a new window. * @package */ -Blockly.BlockSvg.prototype.showHelp = function() { - var url = (typeof this.helpUrl == 'function') ? this.helpUrl() : this.helpUrl; +BlockSvg.prototype.showHelp = function() { + const url = + (typeof this.helpUrl == 'function') ? this.helpUrl() : this.helpUrl; if (url) { window.open(url); } @@ -755,12 +765,12 @@ Blockly.BlockSvg.prototype.showHelp = function() { * @return {?Array} Context menu options or null if no menu. * @protected */ -Blockly.BlockSvg.prototype.generateContextMenu = function() { +BlockSvg.prototype.generateContextMenu = function() { if (this.workspace.options.readOnly || !this.contextMenu) { return null; } - var menuOptions = Blockly.ContextMenuRegistry.registry.getContextMenuOptions( - Blockly.ContextMenuRegistry.ScopeType.BLOCK, {block: this}); + const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( + ContextMenuRegistry.ScopeType.BLOCK, {block: this}); // Allow the block to add or modify menuOptions. if (this.customContextMenu) { @@ -775,12 +785,12 @@ Blockly.BlockSvg.prototype.generateContextMenu = function() { * @param {!Event} e Mouse event. * @package */ -Blockly.BlockSvg.prototype.showContextMenu = function(e) { - var menuOptions = this.generateContextMenu(); +BlockSvg.prototype.showContextMenu = function(e) { + const menuOptions = this.generateContextMenu(); if (menuOptions && menuOptions.length) { - Blockly.ContextMenu.show(e, menuOptions, this.RTL); - Blockly.ContextMenu.currentBlock = this; + ContextMenu.show(e, menuOptions, this.RTL); + ContextMenu.setCurrentBlock(this); } }; @@ -793,23 +803,23 @@ Blockly.BlockSvg.prototype.showContextMenu = function(e) { * units. * @package */ -Blockly.BlockSvg.prototype.moveConnections = function(dx, dy) { +BlockSvg.prototype.moveConnections = function(dx, dy) { if (!this.rendered) { // Rendering is required to lay out the blocks. // This is probably an invisible block attached to a collapsed block. return; } - var myConnections = this.getConnections_(false); - for (var i = 0; i < myConnections.length; i++) { + const myConnections = this.getConnections_(false); + for (let i = 0; i < myConnections.length; i++) { myConnections[i].moveBy(dx, dy); } - var icons = this.getIcons(); - for (var i = 0; i < icons.length; i++) { + const icons = this.getIcons(); + for (let i = 0; i < icons.length; i++) { icons[i].computeIconLocation(); } // Recurse through all blocks attached under this one. - for (var i = 0; i < this.childBlocks_.length; i++) { + for (let i = 0; i < this.childBlocks_.length; i++) { this.childBlocks_[i].moveConnections(dx, dy); } }; @@ -819,22 +829,21 @@ Blockly.BlockSvg.prototype.moveConnections = function(dx, dy) { * @param {boolean} adding True if adding, false if removing. * @package */ -Blockly.BlockSvg.prototype.setDragging = function(adding) { +BlockSvg.prototype.setDragging = function(adding) { if (adding) { - var group = this.getSvgRoot(); + const group = this.getSvgRoot(); group.translate_ = ''; group.skew_ = ''; - Blockly.draggingConnections = - Blockly.draggingConnections.concat(this.getConnections_(true)); - Blockly.utils.dom.addClass( + common.draggingConnections.push(...this.getConnections_(true)); + dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } else { - Blockly.draggingConnections = []; - Blockly.utils.dom.removeClass( + common.draggingConnections.length = 0; + dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } // Recurse through all blocks attached under this one. - for (var i = 0; i < this.childBlocks_.length; i++) { + for (let i = 0; i < this.childBlocks_.length; i++) { this.childBlocks_[i].setDragging(adding); } }; @@ -843,8 +852,8 @@ Blockly.BlockSvg.prototype.setDragging = function(adding) { * Set whether this block is movable or not. * @param {boolean} movable True if movable. */ -Blockly.BlockSvg.prototype.setMovable = function(movable) { - Blockly.BlockSvg.superClass_.setMovable.call(this, movable); +BlockSvg.prototype.setMovable = function(movable) { + BlockSvg.superClass_.setMovable.call(this, movable); this.pathObject.updateMovable(movable); }; @@ -852,10 +861,10 @@ Blockly.BlockSvg.prototype.setMovable = function(movable) { * Set whether this block is editable or not. * @param {boolean} editable True if editable. */ -Blockly.BlockSvg.prototype.setEditable = function(editable) { - Blockly.BlockSvg.superClass_.setEditable.call(this, editable); - var icons = this.getIcons(); - for (var i = 0; i < icons.length; i++) { +BlockSvg.prototype.setEditable = function(editable) { + BlockSvg.superClass_.setEditable.call(this, editable); + const icons = this.getIcons(); + for (let i = 0; i < icons.length; i++) { icons[i].updateEditable(); } }; @@ -865,8 +874,8 @@ Blockly.BlockSvg.prototype.setEditable = function(editable) { * @param {boolean} shadow True if a shadow. * @package */ -Blockly.BlockSvg.prototype.setShadow = function(shadow) { - Blockly.BlockSvg.superClass_.setShadow.call(this, shadow); +BlockSvg.prototype.setShadow = function(shadow) { + BlockSvg.superClass_.setShadow.call(this, shadow); this.applyColour(); }; @@ -876,14 +885,14 @@ Blockly.BlockSvg.prototype.setShadow = function(shadow) { * @param {boolean} insertionMarker True if an insertion marker. * @package */ -Blockly.BlockSvg.prototype.setInsertionMarker = function(insertionMarker) { +BlockSvg.prototype.setInsertionMarker = function(insertionMarker) { if (this.isInsertionMarker_ == insertionMarker) { return; // No change. } this.isInsertionMarker_ = insertionMarker; if (this.isInsertionMarker_) { - this.setColour(this.workspace.getRenderer().getConstants(). - INSERTION_MARKER_COLOUR); + this.setColour( + this.workspace.getRenderer().getConstants().INSERTION_MARKER_COLOUR); this.pathObject.updateInsertionMarker(true); } }; @@ -892,7 +901,7 @@ Blockly.BlockSvg.prototype.setInsertionMarker = function(insertionMarker) { * Return the root node of the SVG or null if none exists. * @return {!SVGGElement} The root SVG node (probably a group). */ -Blockly.BlockSvg.prototype.getSvgRoot = function() { +BlockSvg.prototype.getSvgRoot = function() { return this.svgGroup_; }; @@ -904,76 +913,76 @@ Blockly.BlockSvg.prototype.getSvgRoot = function() { * @param {boolean=} animate If true, show a disposal animation and sound. * @suppress {checkTypes} */ -Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { +BlockSvg.prototype.dispose = function(healStack, animate) { if (!this.workspace) { // The block has already been deleted. return; } - Blockly.Tooltip.dispose(); - Blockly.Tooltip.unbindMouseEvents(this.pathObject.svgPath); - Blockly.utils.dom.startTextWidthCache(); + Tooltip.dispose(); + Tooltip.unbindMouseEvents(this.pathObject.svgPath); + dom.startTextWidthCache(); // Save the block's workspace temporarily so we can resize the // contents once the block is disposed. - var blockWorkspace = this.workspace; + const blockWorkspace = this.workspace; // If this block is being dragged, unlink the mouse events. if (Blockly.selected == this) { this.unselect(); this.workspace.cancelCurrentGesture(); } // If this block has a context menu open, close it. - if (Blockly.ContextMenu.currentBlock == this) { - Blockly.ContextMenu.hide(); + if (ContextMenu.getCurrentBlock() == this) { + ContextMenu.hide(); } if (animate && this.rendered) { this.unplug(healStack); - Blockly.blockAnimations.disposeUiEffect(this); + blockAnimations.disposeUiEffect(this); } // Stop rerendering. this.rendered = false; // Clear pending warnings. if (this.warningTextDb_) { - for (var n in this.warningTextDb_) { + for (const n in this.warningTextDb_) { clearTimeout(this.warningTextDb_[n]); } this.warningTextDb_ = null; } - var icons = this.getIcons(); - for (var i = 0; i < icons.length; i++) { + const icons = this.getIcons(); + for (let i = 0; i < icons.length; i++) { icons[i].dispose(); } - Blockly.BlockSvg.superClass_.dispose.call(this, !!healStack); + BlockSvg.superClass_.dispose.call(this, !!healStack); - Blockly.utils.dom.removeNode(this.svgGroup_); + dom.removeNode(this.svgGroup_); blockWorkspace.resizeContents(); // Sever JavaScript to DOM connections. this.svgGroup_ = null; - Blockly.utils.dom.stopTextWidthCache(); + dom.stopTextWidthCache(); }; /** * Encode a block for copying. - * @return {?Blockly.ICopyable.CopyData} Copy metadata, or null if the block is + * @return {?ICopyable.CopyData} Copy metadata, or null if the block is * an insertion marker. * @package */ -Blockly.BlockSvg.prototype.toCopyData = function() { +BlockSvg.prototype.toCopyData = function() { if (this.isInsertionMarker_) { return null; } - var xml = /** @type {!Element} */ (Blockly.Xml.blockToDom(this, true)); + const xml = /** @type {!Element} */ (Xml.blockToDom(this, true)); // Copy only the selected block and internal blocks. - Blockly.Xml.deleteNext(xml); + Xml.deleteNext(xml); // Encode start position in XML. - var xy = this.getRelativeToSurfaceXY(); + const xy = this.getRelativeToSurfaceXY(); xml.setAttribute('x', this.RTL ? -xy.x : xy.x); xml.setAttribute('y', xy.y); return { xml: xml, source: this.workspace, - typeCounts: Blockly.utils.getBlockTypeCounts(this, true) + typeCounts: utils.getBlockTypeCounts(this, true) }; }; @@ -981,16 +990,16 @@ Blockly.BlockSvg.prototype.toCopyData = function() { * Updates the colour of the block to match the block's state. * @package */ -Blockly.BlockSvg.prototype.applyColour = function() { +BlockSvg.prototype.applyColour = function() { this.pathObject.applyColour(this); - var icons = this.getIcons(); - for (var i = 0; i < icons.length; i++) { + const icons = this.getIcons(); + for (let i = 0; i < icons.length; i++) { icons[i].applyColour(); } - for (var x = 0, input; (input = this.inputList[x]); x++) { - for (var y = 0, field; (field = input.fieldRow[y]); y++) { + for (let x = 0, input; (input = this.inputList[x]); x++) { + for (let y = 0, field; (field = input.fieldRow[y]); y++) { field.applyColour(); } } @@ -1001,13 +1010,13 @@ Blockly.BlockSvg.prototype.applyColour = function() { * state. * @package */ -Blockly.BlockSvg.prototype.updateDisabled = function() { - var children = this.getChildren(false); +BlockSvg.prototype.updateDisabled = function() { + const children = this.getChildren(false); this.applyColour(); if (this.isCollapsed()) { return; } - for (var i = 0, child; (child = children[i]); i++) { + for (let i = 0, child; (child = children[i]); i++) { if (child.rendered) { child.updateDisabled(); } @@ -1017,9 +1026,9 @@ Blockly.BlockSvg.prototype.updateDisabled = function() { /** * Get the comment icon attached to this block, or null if the block has no * comment. - * @return {?Blockly.Comment} The comment icon attached to this block, or null. + * @return {?Comment} The comment icon attached to this block, or null. */ -Blockly.BlockSvg.prototype.getCommentIcon = function() { +BlockSvg.prototype.getCommentIcon = function() { return this.commentIcon_; }; @@ -1027,16 +1036,17 @@ Blockly.BlockSvg.prototype.getCommentIcon = function() { * Set this block's comment text. * @param {?string} text The text, or null to delete. */ -Blockly.BlockSvg.prototype.setCommentText = function(text) { - if (!Blockly.Comment) { +BlockSvg.prototype.setCommentText = function(text) { + const Comment = goog.module.get('Blockly.Comment'); + if (!Comment) { throw Error('Missing require for Blockly.Comment'); } if (this.commentModel.text == text) { return; } - Blockly.BlockSvg.superClass_.setCommentText.call(this, text); + BlockSvg.superClass_.setCommentText.call(this, text); - var shouldHaveComment = text != null; + const shouldHaveComment = text != null; if (!!this.commentIcon_ == shouldHaveComment) { // If the comment's state of existence is correct, but the text is new // that means we're just updating a comment. @@ -1044,7 +1054,7 @@ Blockly.BlockSvg.prototype.setCommentText = function(text) { return; } if (shouldHaveComment) { - this.commentIcon_ = new Blockly.Comment(this); + this.commentIcon_ = new Comment(this); this.comment = this.commentIcon_; // For backwards compatibility. } else { this.commentIcon_.dispose(); @@ -1064,8 +1074,9 @@ Blockly.BlockSvg.prototype.setCommentText = function(text) { * @param {string=} opt_id An optional ID for the warning text to be able to * maintain multiple warnings. */ -Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { - if (!Blockly.Warning) { +BlockSvg.prototype.setWarningText = function(text, opt_id) { + const Warning = goog.module.get('Blockly.Warning'); + if (!Warning) { throw Error('Missing require for Blockly.Warning'); } if (!this.warningTextDb_) { @@ -1073,10 +1084,10 @@ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { // Only runs once per block (and only those with warnings). this.warningTextDb_ = Object.create(null); } - var id = opt_id || ''; + const id = opt_id || ''; if (!id) { // Kill all previous pending processes, this edit supersedes them all. - for (var n in this.warningTextDb_) { + for (const n of Object.keys(this.warningTextDb_)) { clearTimeout(this.warningTextDb_[n]); delete this.warningTextDb_[n]; } @@ -1088,7 +1099,7 @@ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { if (this.workspace.isDragging()) { // Don't change the warning text during a drag. // Wait until the drag finishes. - var thisBlock = this; + const thisBlock = this; this.warningTextDb_[id] = setTimeout(function() { if (thisBlock.workspace) { // Check block wasn't deleted. delete thisBlock.warningTextDb_[id]; @@ -1101,11 +1112,11 @@ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { text = null; } - var changedState = false; + let changedState = false; if (typeof text == 'string') { // Bubble up to add a warning on top-most collapsed block. - var parent = this.getSurroundParent(); - var collapsedParent = null; + let parent = this.getSurroundParent(); + let collapsedParent = null; while (parent) { if (parent.isCollapsed()) { collapsedParent = parent; @@ -1113,12 +1124,12 @@ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { parent = parent.getSurroundParent(); } if (collapsedParent) { - collapsedParent.setWarningText(Blockly.Msg['COLLAPSED_WARNINGS_WARNING'], - Blockly.BlockSvg.COLLAPSED_WARNING_ID); + collapsedParent.setWarningText( + Msg['COLLAPSED_WARNINGS_WARNING'], BlockSvg.COLLAPSED_WARNING_ID); } if (!this.warning) { - this.warning = new Blockly.Warning(this); + this.warning = new Warning(this); changedState = true; } this.warning.setText(/** @type {string} */ (text), id); @@ -1128,9 +1139,9 @@ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { this.warning.dispose(); changedState = true; } else if (this.warning) { - var oldText = this.warning.getText(); + const oldText = this.warning.getText(); this.warning.setText('', id); - var newText = this.warning.getText(); + const newText = this.warning.getText(); if (!newText) { this.warning.dispose(); } @@ -1146,9 +1157,9 @@ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { /** * Give this block a mutator dialog. - * @param {?Blockly.Mutator} mutator A mutator dialog instance or null to remove. + * @param {?Mutator} mutator A mutator dialog instance or null to remove. */ -Blockly.BlockSvg.prototype.setMutator = function(mutator) { +BlockSvg.prototype.setMutator = function(mutator) { if (this.mutator && this.mutator !== mutator) { this.mutator.dispose(); } @@ -1168,9 +1179,9 @@ Blockly.BlockSvg.prototype.setMutator = function(mutator) { * Set whether the block is enabled or not. * @param {boolean} enabled True if enabled. */ -Blockly.BlockSvg.prototype.setEnabled = function(enabled) { +BlockSvg.prototype.setEnabled = function(enabled) { if (this.isEnabled() != enabled) { - Blockly.BlockSvg.superClass_.setEnabled.call(this, enabled); + BlockSvg.superClass_.setEnabled.call(this, enabled); if (this.rendered && !this.getInheritedDisabled()) { this.updateDisabled(); } @@ -1182,7 +1193,7 @@ Blockly.BlockSvg.prototype.setEnabled = function(enabled) { * often used to visually mark blocks currently being executed. * @param {boolean} highlighted True if highlighted. */ -Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { +BlockSvg.prototype.setHighlighted = function(highlighted) { if (!this.rendered) { return; } @@ -1192,18 +1203,18 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { /** * Adds the visual "select" effect to the block, but does not actually select * it or fire an event. - * @see Blockly.BlockSvg#select + * @see BlockSvg#select */ -Blockly.BlockSvg.prototype.addSelect = function() { +BlockSvg.prototype.addSelect = function() { this.pathObject.updateSelected(true); }; /** * Removes the visual "select" effect from the block, but does not actually * unselect it or fire an event. - * @see Blockly.BlockSvg#unselect + * @see BlockSvg#unselect */ -Blockly.BlockSvg.prototype.removeSelect = function() { +BlockSvg.prototype.removeSelect = function() { this.pathObject.updateSelected(false); }; @@ -1213,7 +1224,7 @@ Blockly.BlockSvg.prototype.removeSelect = function() { * otherwise. * @package */ -Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { +BlockSvg.prototype.setDeleteStyle = function(enable) { this.pathObject.updateDraggingDelete(enable); }; @@ -1224,7 +1235,7 @@ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { * Get the colour of a block. * @return {string} #RRGGBB string. */ -Blockly.BlockSvg.prototype.getColour = function() { +BlockSvg.prototype.getColour = function() { return this.style.colourPrimary; }; @@ -1232,10 +1243,11 @@ Blockly.BlockSvg.prototype.getColour = function() { * Change the colour of a block. * @param {number|string} colour HSV hue value, or #RRGGBB string. */ -Blockly.BlockSvg.prototype.setColour = function(colour) { - Blockly.BlockSvg.superClass_.setColour.call(this, colour); - var styleObj = this.workspace.getRenderer().getConstants() - .getBlockStyleForColour(this.colour_); +BlockSvg.prototype.setColour = function(colour) { + BlockSvg.superClass_.setColour.call(this, colour); + const styleObj = + this.workspace.getRenderer().getConstants().getBlockStyleForColour( + this.colour_); this.pathObject.setStyle(styleObj.style); this.style = styleObj.style; @@ -1249,9 +1261,9 @@ Blockly.BlockSvg.prototype.setColour = function(colour) { * @param {string} blockStyleName Name of the block style. * @throws {Error} if the block style does not exist. */ -Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) { - var blockStyle = this.workspace.getRenderer() - .getConstants().getBlockStyle(blockStyleName); +BlockSvg.prototype.setStyle = function(blockStyleName) { + const blockStyle = + this.workspace.getRenderer().getConstants().getBlockStyle(blockStyleName); this.styleName_ = blockStyleName; if (blockStyle) { @@ -1274,12 +1286,12 @@ Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) { * block group's , it will render on top of any other blocks. * @package */ -Blockly.BlockSvg.prototype.bringToFront = function() { - var block = this; +BlockSvg.prototype.bringToFront = function() { + let block = this; do { - var root = block.getSvgRoot(); - var parent = root.parentNode; - var childNodes = parent.childNodes; + const root = block.getSvgRoot(); + const parent = root.parentNode; + const childNodes = parent.childNodes; // Avoid moving the block if it's already at the bottom. if (childNodes[childNodes.length - 1] !== root) { parent.appendChild(root); @@ -1294,10 +1306,8 @@ Blockly.BlockSvg.prototype.bringToFront = function() { * @param {(string|Array|null)=} opt_check Statement type or * list of statement types. Null/undefined if any type could be connected. */ -Blockly.BlockSvg.prototype.setPreviousStatement = function(newBoolean, - opt_check) { - Blockly.BlockSvg.superClass_.setPreviousStatement.call(this, newBoolean, - opt_check); +BlockSvg.prototype.setPreviousStatement = function(newBoolean, opt_check) { + BlockSvg.superClass_.setPreviousStatement.call(this, newBoolean, opt_check); if (this.rendered) { this.render(); @@ -1311,9 +1321,8 @@ Blockly.BlockSvg.prototype.setPreviousStatement = function(newBoolean, * @param {(string|Array|null)=} opt_check Statement type or * list of statement types. Null/undefined if any type could be connected. */ -Blockly.BlockSvg.prototype.setNextStatement = function(newBoolean, opt_check) { - Blockly.BlockSvg.superClass_.setNextStatement.call(this, newBoolean, - opt_check); +BlockSvg.prototype.setNextStatement = function(newBoolean, opt_check) { + BlockSvg.superClass_.setNextStatement.call(this, newBoolean, opt_check); if (this.rendered) { this.render(); @@ -1328,8 +1337,8 @@ Blockly.BlockSvg.prototype.setNextStatement = function(newBoolean, opt_check) { * of returned types. Null or undefined if any type could be returned * (e.g. variable get). */ -Blockly.BlockSvg.prototype.setOutput = function(newBoolean, opt_check) { - Blockly.BlockSvg.superClass_.setOutput.call(this, newBoolean, opt_check); +BlockSvg.prototype.setOutput = function(newBoolean, opt_check) { + BlockSvg.superClass_.setOutput.call(this, newBoolean, opt_check); if (this.rendered) { this.render(); @@ -1341,8 +1350,8 @@ Blockly.BlockSvg.prototype.setOutput = function(newBoolean, opt_check) { * Set whether value inputs are arranged horizontally or vertically. * @param {boolean} newBoolean True if inputs are horizontal. */ -Blockly.BlockSvg.prototype.setInputsInline = function(newBoolean) { - Blockly.BlockSvg.superClass_.setInputsInline.call(this, newBoolean); +BlockSvg.prototype.setInputsInline = function(newBoolean) { + BlockSvg.superClass_.setInputsInline.call(this, newBoolean); if (this.rendered) { this.render(); @@ -1354,12 +1363,12 @@ Blockly.BlockSvg.prototype.setInputsInline = function(newBoolean) { * Remove an input from this block. * @param {string} name The name of the input. * @param {boolean=} opt_quiet True to prevent error if input is not present. - * @return {boolean} True if operation succeeds, false if input is not present and opt_quiet is true - * @throws {Error} if the input is not present and - * opt_quiet is not true. + * @return {boolean} True if operation succeeds, false if input is not present + * and opt_quiet is true + * @throws {Error} if the input is not present and opt_quiet is not true. */ -Blockly.BlockSvg.prototype.removeInput = function(name, opt_quiet) { - var removed = Blockly.BlockSvg.superClass_.removeInput.call(this, name, opt_quiet); +BlockSvg.prototype.removeInput = function(name, opt_quiet) { + const removed = BlockSvg.superClass_.removeInput.call(this, name, opt_quiet); if (this.rendered) { this.render(); @@ -1375,10 +1384,8 @@ Blockly.BlockSvg.prototype.removeInput = function(name, opt_quiet) { * @param {number} inputIndex Index of the input to move. * @param {number} refIndex Index of input that should be after the moved input. */ -Blockly.BlockSvg.prototype.moveNumberedInputBefore = function( - inputIndex, refIndex) { - Blockly.BlockSvg.superClass_.moveNumberedInputBefore.call(this, inputIndex, - refIndex); +BlockSvg.prototype.moveNumberedInputBefore = function(inputIndex, refIndex) { + BlockSvg.superClass_.moveNumberedInputBefore.call(this, inputIndex, refIndex); if (this.rendered) { this.render(); @@ -1392,12 +1399,12 @@ Blockly.BlockSvg.prototype.moveNumberedInputBefore = function( * @param {number} type One of Blockly.inputTypes. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. - * @return {!Blockly.Input} The input object created. + * @return {!Input} The input object created. * @protected * @override */ -Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { - var input = Blockly.BlockSvg.superClass_.appendInput_.call(this, type, name); +BlockSvg.prototype.appendInput_ = function(type, name) { + const input = BlockSvg.superClass_.appendInput_.call(this, type, name); if (this.rendered) { this.render(); @@ -1416,7 +1423,7 @@ Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { * @param {boolean} track If true, start tracking. If false, stop tracking. * @package */ -Blockly.BlockSvg.prototype.setConnectionTracking = function(track) { +BlockSvg.prototype.setConnectionTracking = function(track) { if (this.previousConnection) { this.previousConnection.setTracking(track); } @@ -1425,7 +1432,7 @@ Blockly.BlockSvg.prototype.setConnectionTracking = function(track) { } if (this.nextConnection) { this.nextConnection.setTracking(track); - var child = this.nextConnection.targetBlock(); + const child = this.nextConnection.targetBlock(); if (child) { child.setConnectionTracking(track); } @@ -1438,13 +1445,13 @@ Blockly.BlockSvg.prototype.setConnectionTracking = function(track) { return; } - for (var i = 0; i < this.inputList.length; i++) { - var conn = this.inputList[i].connection; + for (let i = 0; i < this.inputList.length; i++) { + const conn = this.inputList[i].connection; if (conn) { conn.setTracking(track); // Pass tracking on down the chain. - var block = conn.targetBlock(); + const block = conn.targetBlock(); if (block) { block.setConnectionTracking(track); } @@ -1457,11 +1464,11 @@ Blockly.BlockSvg.prototype.setConnectionTracking = function(track) { * @param {boolean} all If true, return all connections even hidden ones. * Otherwise, for a non-rendered block return an empty list, and for a * collapsed block don't return inputs connections. - * @return {!Array} Array of connections. + * @return {!Array} Array of connections. * @package */ -Blockly.BlockSvg.prototype.getConnections_ = function(all) { - var myConnections = []; +BlockSvg.prototype.getConnections_ = function(all) { + const myConnections = []; if (all || this.rendered) { if (this.outputConnection) { myConnections.push(this.outputConnection); @@ -1473,7 +1480,7 @@ Blockly.BlockSvg.prototype.getConnections_ = function(all) { myConnections.push(this.nextConnection); } if (all || !this.collapsed_) { - for (var i = 0, input; (input = this.inputList[i]); i++) { + for (let i = 0, input; (input = this.inputList[i]); i++) { if (input.connection) { myConnections.push(input.connection); } @@ -1488,78 +1495,72 @@ Blockly.BlockSvg.prototype.getConnections_ = function(all) { * @param {boolean} ignoreShadows If true,the last connection on a non-shadow * block will be returned. If false, this will follow shadows to find the * last connection. - * @return {?Blockly.RenderedConnection} The last next connection on the stack, + * @return {?RenderedConnection} The last next connection on the stack, * or null. * @package * @override */ -Blockly.BlockSvg.prototype.lastConnectionInStack = function(ignoreShadows) { - return /** @type {Blockly.RenderedConnection} */ ( - Blockly.BlockSvg.superClass_ - .lastConnectionInStack.call(this, ignoreShadows)); +BlockSvg.prototype.lastConnectionInStack = function(ignoreShadows) { + return /** @type {RenderedConnection} */ ( + BlockSvg.superClass_.lastConnectionInStack.call(this, ignoreShadows)); }; /** * Find the connection on this block that corresponds to the given connection * on the other block. * Used to match connections between a block and its insertion marker. - * @param {!Blockly.Block} otherBlock The other block to match against. - * @param {!Blockly.Connection} conn The other connection to match. - * @return {?Blockly.RenderedConnection} The matching connection on this block, + * @param {!Block} otherBlock The other block to match against. + * @param {!Connection} conn The other connection to match. + * @return {?RenderedConnection} The matching connection on this block, * or null. * @package * @override */ -Blockly.BlockSvg.prototype.getMatchingConnection = function(otherBlock, conn) { - return /** @type {Blockly.RenderedConnection} */ ( - Blockly.BlockSvg.superClass_.getMatchingConnection.call(this, - otherBlock, conn)); +BlockSvg.prototype.getMatchingConnection = function(otherBlock, conn) { + return /** @type {RenderedConnection} */ ( + BlockSvg.superClass_.getMatchingConnection.call(this, otherBlock, conn)); }; /** * Create a connection of the specified type. * @param {number} type The type of the connection to create. - * @return {!Blockly.RenderedConnection} A new connection of the specified type. + * @return {!RenderedConnection} A new connection of the specified type. * @protected */ -Blockly.BlockSvg.prototype.makeConnection_ = function(type) { - return new Blockly.RenderedConnection(this, type); +BlockSvg.prototype.makeConnection_ = function(type) { + return new RenderedConnection(this, type); }; /** * Bump unconnected blocks out of alignment. Two blocks which aren't actually * connected should not coincidentally line up on screen. */ -Blockly.BlockSvg.prototype.bumpNeighbours = function() { +BlockSvg.prototype.bumpNeighbours = function() { if (!this.workspace) { return; // Deleted block. } if (this.workspace.isDragging()) { return; // Don't bump blocks during a drag. } - var rootBlock = this.getRootBlock(); + const rootBlock = this.getRootBlock(); if (rootBlock.isInFlyout) { return; // Don't move blocks around in a flyout. } // Loop through every connection on this block. - var myConnections = this.getConnections_(false); - for (var i = 0, connection; (connection = myConnections[i]); i++) { - + const myConnections = this.getConnections_(false); + for (let i = 0, connection; (connection = myConnections[i]); i++) { // Spider down from this block bumping all sub-blocks. if (connection.isConnected() && connection.isSuperior()) { connection.targetBlock().bumpNeighbours(); } - var neighbours = - connection.neighbours(Blockly.internalConstants.SNAP_RADIUS); - for (var j = 0, otherConnection; (otherConnection = neighbours[j]); j++) { - + const neighbours = connection.neighbours(internalConstants.SNAP_RADIUS); + for (let j = 0, otherConnection; (otherConnection = neighbours[j]); j++) { // If both connections are connected, that's probably fine. But if // either one of them is unconnected, then there could be confusion. if (!connection.isConnected() || !otherConnection.isConnected()) { // Only bump blocks if they are from different tree structures. if (otherConnection.getSourceBlock().getRootBlock() != rootBlock) { - // Always bump the inferior block. if (connection.isSuperior()) { otherConnection.bumpAwayFrom(connection); @@ -1577,42 +1578,42 @@ Blockly.BlockSvg.prototype.bumpNeighbours = function() { * delay. * @package */ -Blockly.BlockSvg.prototype.scheduleSnapAndBump = function() { - var block = this; +BlockSvg.prototype.scheduleSnapAndBump = function() { + const block = this; // Ensure that any snap and bump are part of this move's event group. - var group = Blockly.Events.getGroup(); + const group = Events.getGroup(); setTimeout(function() { - Blockly.Events.setGroup(group); + Events.setGroup(group); block.snapToGrid(); - Blockly.Events.setGroup(false); - }, Blockly.internalConstants.BUMP_DELAY / 2); + Events.setGroup(false); + }, internalConstants.BUMP_DELAY / 2); setTimeout(function() { - Blockly.Events.setGroup(group); + Events.setGroup(group); block.bumpNeighbours(); - Blockly.Events.setGroup(false); - }, Blockly.internalConstants.BUMP_DELAY); + Events.setGroup(false); + }, internalConstants.BUMP_DELAY); }; /** * Position a block so that it doesn't move the target block when connected. * The block to position is usually either the first block in a dragged stack or * an insertion marker. - * @param {!Blockly.RenderedConnection} sourceConnection The connection on the + * @param {!RenderedConnection} sourceConnection The connection on the * moving block's stack. - * @param {!Blockly.RenderedConnection} targetConnection The connection that + * @param {!RenderedConnection} targetConnection The connection that * should stay stationary as this block is positioned. * @package */ -Blockly.BlockSvg.prototype.positionNearConnection = function(sourceConnection, - targetConnection) { +BlockSvg.prototype.positionNearConnection = function( + sourceConnection, targetConnection) { // We only need to position the new block if it's before the existing one, // otherwise its position is set by the previous block. - if (sourceConnection.type == Blockly.connectionTypes.NEXT_STATEMENT || - sourceConnection.type == Blockly.connectionTypes.INPUT_VALUE) { - var dx = targetConnection.x - sourceConnection.x; - var dy = targetConnection.y - sourceConnection.y; + if (sourceConnection.type == connectionTypes.NEXT_STATEMENT || + sourceConnection.type == connectionTypes.INPUT_VALUE) { + const dx = targetConnection.x - sourceConnection.x; + const dy = targetConnection.y - sourceConnection.y; this.moveBy(dx, dy); } @@ -1620,23 +1621,22 @@ Blockly.BlockSvg.prototype.positionNearConnection = function(sourceConnection, /** * Return the parent block or null if this block is at the top level. - * @return {?Blockly.BlockSvg} The block (if any) that holds the current block. + * @return {?BlockSvg} The block (if any) that holds the current block. * @override */ -Blockly.BlockSvg.prototype.getParent = function() { - return /** @type {!Blockly.BlockSvg} */ ( - Blockly.BlockSvg.superClass_.getParent.call(this)); +BlockSvg.prototype.getParent = function() { + return /** @type {!BlockSvg} */ (BlockSvg.superClass_.getParent.call(this)); }; /** * Return the top-most block in this block's tree. * This will return itself if this block is at the top level. - * @return {!Blockly.BlockSvg} The root block. + * @return {!BlockSvg} The root block. * @override */ -Blockly.BlockSvg.prototype.getRootBlock = function() { - return /** @type {!Blockly.BlockSvg} */ ( - Blockly.BlockSvg.superClass_.getRootBlock.call(this)); +BlockSvg.prototype.getRootBlock = function() { + return /** @type {!BlockSvg} */ ( + BlockSvg.superClass_.getRootBlock.call(this)); }; /** @@ -1644,14 +1644,14 @@ Blockly.BlockSvg.prototype.getRootBlock = function() { * @param {boolean=} opt_bubble If false, just render this block. * If true, also render block's parent, grandparent, etc. Defaults to true. */ -Blockly.BlockSvg.prototype.render = function(opt_bubble) { +BlockSvg.prototype.render = function(opt_bubble) { if (this.renderIsInProgress_) { return; // Don't allow recursive renders. } this.renderIsInProgress_ = true; try { this.rendered = true; - Blockly.utils.dom.startTextWidthCache(); + dom.startTextWidthCache(); if (this.isCollapsed()) { this.updateCollapsed_(); @@ -1660,7 +1660,7 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { this.updateConnectionLocations_(); if (opt_bubble !== false) { - var parentBlock = this.getParent(); + const parentBlock = this.getParent(); if (parentBlock) { parentBlock.render(true); } else { @@ -1669,7 +1669,7 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { } } - Blockly.utils.dom.stopTextWidthCache(); + dom.stopTextWidthCache(); this.updateMarkers_(); } finally { this.renderIsInProgress_ = false; @@ -1680,13 +1680,13 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { * Redraw any attached marker or cursor svgs if needed. * @protected */ -Blockly.BlockSvg.prototype.updateMarkers_ = function() { +BlockSvg.prototype.updateMarkers_ = function() { if (this.workspace.keyboardAccessibilityMode && this.pathObject.cursorSvg) { this.workspace.getCursor().draw(); } if (this.workspace.keyboardAccessibilityMode && this.pathObject.markerSvg) { // TODO(#4592): Update all markers on the block. - this.workspace.getMarker(Blockly.MarkerManager.LOCAL_MARKER).draw(); + this.workspace.getMarker(MarkerManager.LOCAL_MARKER).draw(); } }; @@ -1696,8 +1696,8 @@ Blockly.BlockSvg.prototype.updateMarkers_ = function() { * connection locations. * @private */ -Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() { - var blockTL = this.getRelativeToSurfaceXY(); +BlockSvg.prototype.updateConnectionLocations_ = function() { + const blockTL = this.getRelativeToSurfaceXY(); // Don't tighten previous or output connections because they are inferior // connections. if (this.previousConnection) { @@ -1707,8 +1707,8 @@ Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() { this.outputConnection.moveToOffset(blockTL); } - for (var i = 0; i < this.inputList.length; i++) { - var conn = this.inputList[i].connection; + for (let i = 0; i < this.inputList.length; i++) { + const conn = this.inputList[i].connection; if (conn) { conn.moveToOffset(blockTL); if (conn.isConnected()) { @@ -1731,7 +1731,7 @@ Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() { * block SVG group. * @package */ -Blockly.BlockSvg.prototype.setCursorSvg = function(cursorSvg) { +BlockSvg.prototype.setCursorSvg = function(cursorSvg) { this.pathObject.setCursorSvg(cursorSvg); }; @@ -1741,7 +1741,7 @@ Blockly.BlockSvg.prototype.setCursorSvg = function(cursorSvg) { * block SVG group. * @package */ -Blockly.BlockSvg.prototype.setMarkerSvg = function(markerSvg) { +BlockSvg.prototype.setMarkerSvg = function(markerSvg) { this.pathObject.setMarkerSvg(markerSvg); }; @@ -1752,15 +1752,15 @@ Blockly.BlockSvg.prototype.setMarkerSvg = function(markerSvg) { * properties in workspace units. * @package */ -Blockly.BlockSvg.prototype.getHeightWidth = function() { - var height = this.height; - var width = this.width; +BlockSvg.prototype.getHeightWidth = function() { + let height = this.height; + let width = this.width; // Recursively add size of subsequent blocks. - var nextBlock = this.getNextBlock(); + const nextBlock = this.getNextBlock(); if (nextBlock) { - var nextHeightWidth = nextBlock.getHeightWidth(); - var workspace = /** @type {!Blockly.WorkspaceSvg} */ (this.workspace); - var tabHeight = workspace.getRenderer().getConstants().NOTCH_HEIGHT; + const nextHeightWidth = nextBlock.getHeightWidth(); + const workspace = /** @type {!WorkspaceSvg} */ (this.workspace); + const tabHeight = workspace.getRenderer().getConstants().NOTCH_HEIGHT; height += nextHeightWidth.height - tabHeight; width = Math.max(width, nextHeightWidth.width); } @@ -1773,17 +1773,19 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { * @param {boolean} add True if highlighting should be added. * @package */ -Blockly.BlockSvg.prototype.fadeForReplacement = function(add) { +BlockSvg.prototype.fadeForReplacement = function(add) { this.pathObject.updateReplacementFade(add); }; /** * Visual effect to show that if the dragging block is dropped it will connect * to this input. - * @param {Blockly.Connection} conn The connection on the input to highlight. + * @param {Connection} conn The connection on the input to highlight. * @param {boolean} add True if highlighting should be added. * @package */ -Blockly.BlockSvg.prototype.highlightShapeForInput = function(conn, add) { +BlockSvg.prototype.highlightShapeForInput = function(conn, add) { this.pathObject.updateShapeForInputHighlight(conn, add); }; + +exports = BlockSvg; diff --git a/core/blockly.js b/core/blockly.js index 94f485c99..1f8cfa55a 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -17,6 +17,8 @@ goog.provide('Blockly'); goog.require('Blockly.browserEvents'); +goog.require('Blockly.clipboard'); +goog.require('Blockly.common'); goog.require('Blockly.ComponentManager'); goog.require('Blockly.connectionTypes'); goog.require('Blockly.constants'); @@ -55,7 +57,6 @@ goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.Xml'); goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.Connection'); goog.requireType('Blockly.ICopyable'); goog.requireType('Blockly.Workspace'); @@ -71,12 +72,20 @@ goog.requireType('Blockly.Workspace'); */ Blockly.VERSION = 'uncompiled'; -/** - * The main workspace most recently used. - * Set by Blockly.WorkspaceSvg.prototype.markFocused - * @type {Blockly.Workspace} - */ -Blockly.mainWorkspace = null; +// Add a getter and setter pair for Blockly.mainWorkspace, for legacy reasons. +Object.defineProperty(Blockly, 'mainWorkspace', { + set: function(x) { + Blockly.utils.deprecation.warn( + 'Blockly.mainWorkspace', 'September 2021', 'September 2022'); + Blockly.common.setMainWorkspace(x); + }, + get: function() { + Blockly.utils.deprecation.warn( + 'Blockly.mainWorkspace', 'September 2021', 'September 2022', + 'Blockly.getMainWorkspace()'); + return Blockly.common.getMainWorkspace(); + } +}); /** * Currently selected block. @@ -84,48 +93,6 @@ Blockly.mainWorkspace = null; */ Blockly.selected = null; -/** - * All of the connections on blocks that are currently being dragged. - * @type {!Array} - * @package - */ -Blockly.draggingConnections = []; - -/** - * Contents of the local clipboard. - * @type {Element} - * @private - */ -Blockly.clipboardXml_ = null; - -/** - * Source of the local clipboard. - * @type {Blockly.WorkspaceSvg} - * @private - */ -Blockly.clipboardSource_ = null; - -/** - * Map of types to type counts for the clipboard object and descendants. - * @type {Object} - * @private - */ -Blockly.clipboardTypeCounts_ = null; - -/** - * Cached value for whether 3D is supported. - * @type {?boolean} - * @private - */ -Blockly.cache3dSupported_ = null; - -/** - * Container element to render the WidgetDiv, DropDownDiv and Tooltip. - * @type {?Element} - * @package - */ -Blockly.parentContainer = null; - /** * Returns the dimensions of the specified SVG image. * @param {!SVGElement} svg SVG image. @@ -136,9 +103,7 @@ Blockly.svgSize = function(svg) { // When removing this function, remove svg.cachedWidth_ and svg.cachedHeight_ // from setCachedParentSvgSize. Blockly.utils.deprecation.warn( - 'Blockly.svgSize', - 'March 2021', - 'March 2022', + 'Blockly.svgSize', 'March 2021', 'March 2022', 'workspace.getCachedParentSvgSize'); svg = /** @type {?} */ (svg); return new Blockly.utils.Size(svg.cachedWidth_, svg.cachedHeight_); @@ -195,7 +160,7 @@ Blockly.svgResize = function(workspace) { // TODO (https://github.com/google/blockly/issues/1998) handle cases where there // are multiple workspaces and non-main workspaces are able to accept input. Blockly.onKeyDown = function(e) { - var mainWorkspace = Blockly.mainWorkspace; + var mainWorkspace = Blockly.common.getMainWorkspace(); if (!mainWorkspace) { return; } @@ -220,7 +185,8 @@ Blockly.deleteBlock = function(selected) { Blockly.Events.setGroup(true); Blockly.hideChaff(); if (selected.outputConnection) { - // Do not attempt to heal rows (https://github.com/google/blockly/issues/4832) + // Do not attempt to heal rows + // (https://github.com/google/blockly/issues/4832) selected.dispose(false, true); } else { selected.dispose(/* heal */ true, true); @@ -234,39 +200,14 @@ Blockly.deleteBlock = function(selected) { * @param {!Blockly.ICopyable} toCopy Block or Workspace Comment to be copied. * @package */ -Blockly.copy = function(toCopy) { - var data = toCopy.toCopyData(); - if (data) { - Blockly.clipboardXml_ = data.xml; - Blockly.clipboardSource_ = data.source; - Blockly.clipboardTypeCounts_ = data.typeCounts; - } -}; +Blockly.copy = Blockly.clipboard.copy; /** * Paste a block or workspace comment on to the main workspace. * @return {boolean} True if the paste was successful, false otherwise. * @package */ -Blockly.paste = function() { - if (!Blockly.clipboardXml_) { - return false; - } - // Pasting always pastes to the main workspace, even if the copy - // started in a flyout workspace. - var workspace = Blockly.clipboardSource_; - if (workspace.isFlyout) { - workspace = workspace.targetWorkspace; - } - if (Blockly.clipboardTypeCounts_ && - workspace.isCapacityAvailable(Blockly.clipboardTypeCounts_)) { - Blockly.Events.setGroup(true); - workspace.paste(Blockly.clipboardXml_); - Blockly.Events.setGroup(false); - return true; - } - return false; -}; +Blockly.paste = Blockly.clipboard.paste; /** * Duplicate this block and its children, or a workspace comment. @@ -274,19 +215,7 @@ Blockly.paste = function() { * copied. * @package */ -Blockly.duplicate = function(toDuplicate) { - // Save the clipboard. - var clipboardXml = Blockly.clipboardXml_; - var clipboardSource = Blockly.clipboardSource_; - - // Create a duplicate via a copy/paste operation. - Blockly.copy(toDuplicate); - toDuplicate.workspace.paste(Blockly.clipboardXml_); - - // Restore the clipboard. - Blockly.clipboardXml_ = clipboardXml; - Blockly.clipboardSource_ = clipboardSource; -}; +Blockly.duplicate = Blockly.clipboard.duplicate; /** * Cancel the native context menu, unless the focus is on an HTML input widget. @@ -310,7 +239,7 @@ Blockly.hideChaff = function(opt_onlyClosePopups) { Blockly.DropDownDiv.hideWithoutAnimation(); var onlyClosePopups = !!opt_onlyClosePopups; - var workspace = Blockly.getMainWorkspace(); + var workspace = Blockly.common.getMainWorkspace(); var autoHideables = workspace.getComponentManager().getComponents( Blockly.ComponentManager.Capability.AUTOHIDEABLE, true); autoHideables.forEach(function(autoHideable) { @@ -324,9 +253,7 @@ Blockly.hideChaff = function(opt_onlyClosePopups) { * Blockly instances on a page. * @return {!Blockly.Workspace} The main workspace. */ -Blockly.getMainWorkspace = function() { - return /** @type {!Blockly.Workspace} */ (Blockly.mainWorkspace); -}; +Blockly.getMainWorkspace = Blockly.common.getMainWorkspace; /** * Wrapper to window.alert() that app developers may override to @@ -402,9 +329,7 @@ Blockly.defineBlocksWithJsonArray = function(jsonArray) { 'Block definition #' + i + ' in JSON array' + ' overwrites prior definition of "' + typename + '".'); } - Blockly.Blocks[typename] = { - init: Blockly.jsonInitFactory_(elem) - }; + Blockly.Blocks[typename] = {init: Blockly.jsonInitFactory_(elem)}; } } } @@ -430,78 +355,6 @@ Blockly.hueToHex = function(hue) { Blockly.internalConstants.HSV_VALUE * 255); }; -/** - * Checks old colour constants are not overwritten by the host application. - * If a constant is overwritten, it prints a console warning directing the - * developer to use the equivalent Msg constant. - * @package - */ -Blockly.checkBlockColourConstants = function() { - Blockly.checkBlockColourConstant_( - 'LOGIC_HUE', ['Blocks', 'logic', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'LOGIC_HUE', ['Constants', 'Logic', 'HUE'], 210); - Blockly.checkBlockColourConstant_( - 'LOOPS_HUE', ['Blocks', 'loops', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'LOOPS_HUE', ['Constants', 'Loops', 'HUE'], 120); - Blockly.checkBlockColourConstant_( - 'MATH_HUE', ['Blocks', 'math', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'MATH_HUE', ['Constants', 'Math', 'HUE'], 230); - Blockly.checkBlockColourConstant_( - 'TEXTS_HUE', ['Blocks', 'texts', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'TEXTS_HUE', ['Constants', 'Text', 'HUE'], 160); - Blockly.checkBlockColourConstant_( - 'LISTS_HUE', ['Blocks', 'lists', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'LISTS_HUE', ['Constants', 'Lists', 'HUE'], 260); - Blockly.checkBlockColourConstant_( - 'COLOUR_HUE', ['Blocks', 'colour', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'COLOUR_HUE', ['Constants', 'Colour', 'HUE'], 20); - Blockly.checkBlockColourConstant_( - 'VARIABLES_HUE', ['Blocks', 'variables', 'HUE'], undefined); - Blockly.checkBlockColourConstant_( - 'VARIABLES_HUE', ['Constants', 'Variables', 'HUE'], 330); - // Blockly.Blocks.variables_dynamic.HUE never existed. - Blockly.checkBlockColourConstant_( - 'VARIABLES_DYNAMIC_HUE', ['Constants', 'VariablesDynamic', 'HUE'], 310); - Blockly.checkBlockColourConstant_( - 'PROCEDURES_HUE', ['Blocks', 'procedures', 'HUE'], undefined); - // Blockly.Constants.Procedures.HUE never existed. -}; - -/** - * Checks for a constant in the Blockly namespace, verifying it is undefined or - * has the old/original value. Prints a warning if this is not true. - * @param {string} msgName The Msg constant identifier. - * @param {!Array} blocklyNamePath The name parts of the tested - * constant. - * @param {number|undefined} expectedValue The expected value of the constant. - * @private - */ -Blockly.checkBlockColourConstant_ = function( - msgName, blocklyNamePath, expectedValue) { - var namePath = 'Blockly'; - var value = Blockly; - for (var i = 0; i < blocklyNamePath.length; ++i) { - namePath += '.' + blocklyNamePath[i]; - if (value) { - value = value[blocklyNamePath[i]]; - } - } - - if (value && value !== expectedValue) { - var warningPattern = (expectedValue === undefined) ? - '%1 has been removed. Use Blockly.Msg["%2"].' : - '%1 is deprecated and unused. Override Blockly.Msg["%2"].'; - var warning = warningPattern.replace('%1', namePath).replace('%2', msgName); - console.warn(warning); - } -}; - /** * Set the parent container. This is the container element that the WidgetDiv, * DropDownDiv, and Tooltip are rendered into the first time `Blockly.inject` @@ -509,9 +362,7 @@ Blockly.checkBlockColourConstant_ = function( * This method is a NOP if called after the first ``Blockly.inject``. * @param {!Element} container The container element. */ -Blockly.setParentContainer = function(container) { - Blockly.parentContainer = container; -}; +Blockly.setParentContainer = Blockly.common.setParentContainer; /** Aliases. */ diff --git a/core/blockly_options.js b/core/blockly_options.js new file mode 100644 index 000000000..c9c7b62f9 --- /dev/null +++ b/core/blockly_options.js @@ -0,0 +1,25 @@ +/** + * @license + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Object that defines user-specified options for the workspace. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.BlocklyOptions'); +goog.module.declareLegacyNamespace(); + + +/** + * Blockly options. + * This interface is further described in + * `typings/parts/blockly-interfaces.d.ts`. + * @interface + */ +const BlocklyOptions = function() {}; + +exports = BlocklyOptions; diff --git a/core/browser_events.js b/core/browser_events.js index 3a251637b..b7ce3a61e 100644 --- a/core/browser_events.js +++ b/core/browser_events.js @@ -10,19 +10,20 @@ */ 'use strict'; -goog.provide('Blockly.browserEvents'); +goog.module('Blockly.browserEvents'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Touch'); -goog.require('Blockly.utils.global'); +const Touch = goog.require('Blockly.Touch'); +const global = goog.require('Blockly.utils.global'); /** * Blockly opaque event data used to unbind events when using - * `Blockly.browserEvents.bind` and - * `Blockly.browserEvents.conditionalBind`. + * `bind` and `conditionalBind`. * @typedef {!Array} */ -Blockly.browserEvents.Data; +let Data; +exports.Data = Data; /** * Bind an event handler that can be ignored if it is not part of the active @@ -40,24 +41,24 @@ Blockly.browserEvents.Data; * should prevent the default handler. False by default. If * opt_noPreventDefault is provided, opt_noCaptureIdentifier must also be * provided. - * @return {!Blockly.browserEvents.Data} Opaque data that can be passed to + * @return {!Data} Opaque data that can be passed to * unbindEvent_. - * @public */ -Blockly.browserEvents.conditionalBind = function( +const conditionalBind = function( node, name, thisObject, func, opt_noCaptureIdentifier, opt_noPreventDefault) { - var handled = false; - var wrapFunc = function(e) { - var captureIdentifier = !opt_noCaptureIdentifier; + let handled = false; + const wrapFunc = function(e) { + const captureIdentifier = !opt_noCaptureIdentifier; // Handle each touch point separately. If the event was a mouse event, this // will hand back an array with one element, which we're fine handling. - var events = Blockly.Touch.splitEventByTouches(e); - for (var i = 0, event; (event = events[i]); i++) { - if (captureIdentifier && !Blockly.Touch.shouldHandleEvent(event)) { + const events = Touch.splitEventByTouches(e); + for (let i = 0; i < events.length; i++) { + const event = events[i]; + if (captureIdentifier && !Touch.shouldHandleEvent(event)) { continue; } - Blockly.Touch.setClientFromTouch(event); + Touch.setClientFromTouch(event); if (thisObject) { func.call(thisObject, event); } else { @@ -67,10 +68,10 @@ Blockly.browserEvents.conditionalBind = function( } }; - var bindData = []; - if (Blockly.utils.global['PointerEvent'] && - (name in Blockly.Touch.TOUCH_MAP)) { - for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { + const bindData = []; + if (global['PointerEvent'] && (name in Touch.TOUCH_MAP)) { + for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { + const type = Touch.TOUCH_MAP[name][i]; node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); } @@ -79,17 +80,18 @@ Blockly.browserEvents.conditionalBind = function( bindData.push([node, name, wrapFunc]); // Add equivalent touch event. - if (name in Blockly.Touch.TOUCH_MAP) { - var touchWrapFunc = function(e) { + if (name in Touch.TOUCH_MAP) { + const touchWrapFunc = function(e) { wrapFunc(e); // Calling preventDefault stops the browser from scrolling/zooming the // page. - var preventDef = !opt_noPreventDefault; + const preventDef = !opt_noPreventDefault; if (handled && preventDef) { e.preventDefault(); } }; - for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { + for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { + const type = Touch.TOUCH_MAP[name][i]; node.addEventListener(type, touchWrapFunc, false); bindData.push([node, type, touchWrapFunc]); } @@ -97,6 +99,7 @@ Blockly.browserEvents.conditionalBind = function( } return bindData; }; +exports.conditionalBind = conditionalBind; /** @@ -108,12 +111,11 @@ Blockly.browserEvents.conditionalBind = function( * @param {string} name Event name to listen to (e.g. 'mousedown'). * @param {?Object} thisObject The value of 'this' in the function. * @param {!Function} func Function to call when event is triggered. - * @return {!Blockly.browserEvents.Data} Opaque data that can be passed to + * @return {!Data} Opaque data that can be passed to * unbindEvent_. - * @public */ -Blockly.browserEvents.bind = function(node, name, thisObject, func) { - var wrapFunc = function(e) { +const bind = function(node, name, thisObject, func) { + const wrapFunc = function(e) { if (thisObject) { func.call(thisObject, e); } else { @@ -121,10 +123,10 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) { } }; - var bindData = []; - if (Blockly.utils.global['PointerEvent'] && - (name in Blockly.Touch.TOUCH_MAP)) { - for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { + const bindData = []; + if (global['PointerEvent'] && (name in Touch.TOUCH_MAP)) { + for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { + const type = Touch.TOUCH_MAP[name][i]; node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); } @@ -133,12 +135,12 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) { bindData.push([node, name, wrapFunc]); // Add equivalent touch event. - if (name in Blockly.Touch.TOUCH_MAP) { - var touchWrapFunc = function(e) { + if (name in Touch.TOUCH_MAP) { + const touchWrapFunc = function(e) { // Punt on multitouch events. if (e.changedTouches && e.changedTouches.length == 1) { // Map the touch event's properties to the event. - var touchPoint = e.changedTouches[0]; + const touchPoint = e.changedTouches[0]; e.clientX = touchPoint.clientX; e.clientY = touchPoint.clientY; } @@ -147,7 +149,8 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) { // Stop the browser from scrolling/zooming the page. e.preventDefault(); }; - for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { + for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { + const type = Touch.TOUCH_MAP[name][i]; node.addEventListener(type, touchWrapFunc, false); bindData.push([node, type, touchWrapFunc]); } @@ -155,21 +158,23 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) { } return bindData; }; +exports.bind = bind; /** * Unbind one or more events event from a function call. - * @param {!Blockly.browserEvents.Data} bindData Opaque data from bindEvent_. + * @param {!Data} bindData Opaque data from bindEvent_. * This list is emptied during the course of calling this function. * @return {!Function} The function call. - * @public */ -Blockly.browserEvents.unbind = function(bindData) { +const unbind = function(bindData) { + let func; while (bindData.length) { - var bindDatum = bindData.pop(); - var node = bindDatum[0]; - var name = bindDatum[1]; - var func = bindDatum[2]; + const bindDatum = bindData.pop(); + const node = bindDatum[0]; + const name = bindDatum[1]; + func = bindDatum[2]; node.removeEventListener(name, func, false); } return func; }; +exports.unbind = unbind; diff --git a/core/bubble.js b/core/bubble.js index 161b2fb29..dbe10cd1b 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -10,42 +10,49 @@ */ 'use strict'; -goog.provide('Blockly.Bubble'); +goog.module('Blockly.Bubble'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.IBubble'); -goog.require('Blockly.Scrollbar'); -goog.require('Blockly.Touch'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.math'); -goog.require('Blockly.utils.Size'); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.utils.userAgent'); +// TODO(#5073): Fix Blockly requires for Blockly.hideChaff() +// const Blockly = goog.require('Blockly'); +/* eslint-disable-next-line no-unused-vars */ +const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +/* eslint-disable-next-line no-unused-vars */ +const IBubble = goog.requireType('Blockly.IBubble'); +/* eslint-disable-next-line no-unused-vars */ +const MetricsManager = goog.requireType('Blockly.MetricsManager'); +const Scrollbar = goog.require('Blockly.Scrollbar'); +const Size = goog.require('Blockly.utils.Size'); +const Svg = goog.require('Blockly.utils.Svg'); +const Touch = goog.require('Blockly.Touch'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const math = goog.require('Blockly.utils.math'); +const userAgent = goog.require('Blockly.utils.userAgent'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Workspace'); -goog.requireType('Blockly.BlockDragSurfaceSvg'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.MetricsManager'); -goog.requireType('Blockly.WorkspaceSvg'); - /** * Class for UI bubble. - * @param {!Blockly.WorkspaceSvg} workspace The workspace on which to draw the + * @param {!WorkspaceSvg} workspace The workspace on which to draw the * bubble. * @param {!Element} content SVG content for the bubble. * @param {!Element} shape SVG element to avoid eclipsing. - * @param {!Blockly.utils.Coordinate} anchorXY Absolute position of bubble's + * @param {!Coordinate} anchorXY Absolute position of bubble's * anchor point. * @param {?number} bubbleWidth Width of bubble, or null if not resizable. * @param {?number} bubbleHeight Height of bubble, or null if not resizable. - * @implements {Blockly.IBubble} + * @implements {IBubble} * @constructor */ -Blockly.Bubble = function( +const Bubble = function( workspace, content, shape, anchorXY, bubbleWidth, bubbleHeight) { this.workspace_ = workspace; this.content_ = content; @@ -67,14 +74,14 @@ Blockly.Bubble = function( /** * Mouse down on bubbleBack_ event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ this.onMouseDownBubbleWrapper_ = null; /** * Mouse down on resizeGroup_ event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ this.onMouseDownResizeWrapper_ = null; @@ -87,20 +94,20 @@ Blockly.Bubble = function( */ this.disposed = false; - var angle = Blockly.Bubble.ARROW_ANGLE; + let angle = Bubble.ARROW_ANGLE; if (this.workspace_.RTL) { angle = -angle; } - this.arrow_radians_ = Blockly.utils.math.toRadians(angle); + this.arrow_radians_ = math.toRadians(angle); - var canvas = workspace.getBubbleCanvas(); + const canvas = workspace.getBubbleCanvas(); canvas.appendChild(this.createDom_(content, !!(bubbleWidth && bubbleHeight))); this.setAnchorLocation(anchorXY); if (!bubbleWidth || !bubbleHeight) { - var bBox = /** @type {SVGLocatable} */ (this.content_).getBBox(); - bubbleWidth = bBox.width + 2 * Blockly.Bubble.BORDER_WIDTH; - bubbleHeight = bBox.height + 2 * Blockly.Bubble.BORDER_WIDTH; + const bBox = /** @type {SVGLocatable} */ (this.content_).getBBox(); + bubbleWidth = bBox.width + 2 * Bubble.BORDER_WIDTH; + bubbleHeight = bBox.height + 2 * Bubble.BORDER_WIDTH; } this.setBubbleSize(bubbleWidth, bubbleHeight); @@ -113,55 +120,55 @@ Blockly.Bubble = function( /** * Width of the border around the bubble. */ -Blockly.Bubble.BORDER_WIDTH = 6; +Bubble.BORDER_WIDTH = 6; /** * Determines the thickness of the base of the arrow in relation to the size * of the bubble. Higher numbers result in thinner arrows. */ -Blockly.Bubble.ARROW_THICKNESS = 5; +Bubble.ARROW_THICKNESS = 5; /** * The number of degrees that the arrow bends counter-clockwise. */ -Blockly.Bubble.ARROW_ANGLE = 20; +Bubble.ARROW_ANGLE = 20; /** * The sharpness of the arrow's bend. Higher numbers result in smoother arrows. */ -Blockly.Bubble.ARROW_BEND = 4; +Bubble.ARROW_BEND = 4; /** * Distance between arrow point and anchor point. */ -Blockly.Bubble.ANCHOR_RADIUS = 8; +Bubble.ANCHOR_RADIUS = 8; /** * Mouse up event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ -Blockly.Bubble.onMouseUpWrapper_ = null; +Bubble.onMouseUpWrapper_ = null; /** * Mouse move event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ -Blockly.Bubble.onMouseMoveWrapper_ = null; +Bubble.onMouseMoveWrapper_ = null; /** * Stop binding to the global mouseup and mousemove events. * @private */ -Blockly.Bubble.unbindDragEvents_ = function() { - if (Blockly.Bubble.onMouseUpWrapper_) { - Blockly.browserEvents.unbind(Blockly.Bubble.onMouseUpWrapper_); - Blockly.Bubble.onMouseUpWrapper_ = null; +Bubble.unbindDragEvents_ = function() { + if (Bubble.onMouseUpWrapper_) { + browserEvents.unbind(Bubble.onMouseUpWrapper_); + Bubble.onMouseUpWrapper_ = null; } - if (Blockly.Bubble.onMouseMoveWrapper_) { - Blockly.browserEvents.unbind(Blockly.Bubble.onMouseMoveWrapper_); - Blockly.Bubble.onMouseMoveWrapper_ = null; + if (Bubble.onMouseMoveWrapper_) { + browserEvents.unbind(Bubble.onMouseMoveWrapper_); + Bubble.onMouseMoveWrapper_ = null; } }; @@ -170,23 +177,23 @@ Blockly.Bubble.unbindDragEvents_ = function() { * @param {!Event} _e Mouse up event. * @private */ -Blockly.Bubble.bubbleMouseUp_ = function(_e) { - Blockly.Touch.clearTouchIdentifier(); - Blockly.Bubble.unbindDragEvents_(); +Bubble.bubbleMouseUp_ = function(_e) { + Touch.clearTouchIdentifier(); + Bubble.unbindDragEvents_(); }; /** * Flag to stop incremental rendering during construction. * @private */ -Blockly.Bubble.prototype.rendered_ = false; +Bubble.prototype.rendered_ = false; /** * Absolute coordinate of anchor point, in workspace coordinates. - * @type {Blockly.utils.Coordinate} + * @type {Coordinate} * @private */ -Blockly.Bubble.prototype.anchorXY_ = null; +Bubble.prototype.anchorXY_ = null; /** * Relative X coordinate of bubble with respect to the anchor's centre, @@ -194,32 +201,32 @@ Blockly.Bubble.prototype.anchorXY_ = null; * In RTL mode the initial value is negated. * @private */ -Blockly.Bubble.prototype.relativeLeft_ = 0; +Bubble.prototype.relativeLeft_ = 0; /** * Relative Y coordinate of bubble with respect to the anchor's centre, in * workspace units. * @private */ -Blockly.Bubble.prototype.relativeTop_ = 0; +Bubble.prototype.relativeTop_ = 0; /** * Width of bubble, in workspace units. * @private */ -Blockly.Bubble.prototype.width_ = 0; +Bubble.prototype.width_ = 0; /** * Height of bubble, in workspace units. * @private */ -Blockly.Bubble.prototype.height_ = 0; +Bubble.prototype.height_ = 0; /** * Automatically position and reposition the bubble. * @private */ -Blockly.Bubble.prototype.autoLayout_ = true; +Bubble.prototype.autoLayout_ = true; /** * Create the bubble's DOM. @@ -228,7 +235,7 @@ Blockly.Bubble.prototype.autoLayout_ = true; * @return {!SVGElement} The bubble's SVG group. * @private */ -Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { +Bubble.prototype.createDom_ = function(content, hasResize) { /* Create the bubble. Here's the markup that will be generated: @@ -243,42 +250,39 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { [...content goes here...] */ - this.bubbleGroup_ = - Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.G, {}, null); - var filter = { + this.bubbleGroup_ = dom.createSvgElement(Svg.G, {}, null); + let filter = { 'filter': 'url(#' + this.workspace_.getRenderer().getConstants().embossFilterId + ')' }; - if (Blockly.utils.userAgent.JAVA_FX) { + if (userAgent.JAVA_FX) { // Multiple reports that JavaFX can't handle filters. // https://github.com/google/blockly/issues/99 filter = {}; } - var bubbleEmboss = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, filter, this.bubbleGroup_); - this.bubbleArrow_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, {}, bubbleEmboss); - this.bubbleBack_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, { + const bubbleEmboss = dom.createSvgElement(Svg.G, filter, this.bubbleGroup_); + this.bubbleArrow_ = dom.createSvgElement(Svg.PATH, {}, bubbleEmboss); + this.bubbleBack_ = dom.createSvgElement( + Svg.RECT, { 'class': 'blocklyDraggable', 'x': 0, 'y': 0, - 'rx': Blockly.Bubble.BORDER_WIDTH, - 'ry': Blockly.Bubble.BORDER_WIDTH + 'rx': Bubble.BORDER_WIDTH, + 'ry': Bubble.BORDER_WIDTH }, bubbleEmboss); if (hasResize) { - this.resizeGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, + this.resizeGroup_ = dom.createSvgElement( + Svg.G, {'class': this.workspace_.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, this.bubbleGroup_); - var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.POLYGON, + const resizeSize = 2 * Bubble.BORDER_WIDTH; + dom.createSvgElement( + Svg.POLYGON, {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, this.resizeGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, { + dom.createSvgElement( + Svg.LINE, { 'class': 'blocklyResizeLine', 'x1': resizeSize / 3, 'y1': resizeSize - 1, @@ -286,8 +290,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { 'y2': resizeSize / 3 }, this.resizeGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, { + dom.createSvgElement( + Svg.LINE, { 'class': 'blocklyResizeLine', 'x1': resizeSize * 2 / 3, 'y1': resizeSize - 1, @@ -300,10 +304,10 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { } if (!this.workspace_.options.readOnly) { - this.onMouseDownBubbleWrapper_ = Blockly.browserEvents.conditionalBind( + this.onMouseDownBubbleWrapper_ = browserEvents.conditionalBind( this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_); if (this.resizeGroup_) { - this.onMouseDownResizeWrapper_ = Blockly.browserEvents.conditionalBind( + this.onMouseDownResizeWrapper_ = browserEvents.conditionalBind( this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); } } @@ -315,7 +319,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { * Return the root node of the bubble's SVG group. * @return {!SVGElement} The root SVG node of the bubble's group. */ -Blockly.Bubble.prototype.getSvgRoot = function() { +Bubble.prototype.getSvgRoot = function() { return this.bubbleGroup_; }; @@ -323,7 +327,7 @@ Blockly.Bubble.prototype.getSvgRoot = function() { * Expose the block's ID on the bubble's top-level SVG group. * @param {string} id ID of block. */ -Blockly.Bubble.prototype.setSvgId = function(id) { +Bubble.prototype.setSvgId = function(id) { if (this.bubbleGroup_.dataset) { this.bubbleGroup_.dataset['blockId'] = id; } @@ -334,8 +338,8 @@ Blockly.Bubble.prototype.setSvgId = function(id) { * @param {!Event} e Mouse down event. * @private */ -Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { - var gesture = this.workspace_.getGesture(e); +Bubble.prototype.bubbleMouseDown_ = function(e) { + const gesture = this.workspace_.getGesture(e); if (gesture) { gesture.handleBubbleStart(e, this); } @@ -346,7 +350,7 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { * @param {!Event} _e Mouse event. * @package */ -Blockly.Bubble.prototype.showContextMenu = function(_e) { +Bubble.prototype.showContextMenu = function(_e) { // NOP on bubbles, but used by the bubble dragger to pass events to // workspace comments. }; @@ -356,7 +360,7 @@ Blockly.Bubble.prototype.showContextMenu = function(_e) { * @return {boolean} True if deletable. * @package */ -Blockly.Bubble.prototype.isDeletable = function() { +Bubble.prototype.isDeletable = function() { return false; }; @@ -365,7 +369,7 @@ Blockly.Bubble.prototype.isDeletable = function() { * @param {boolean} _enable True if the bubble is about to be deleted, false * otherwise. */ -Blockly.Bubble.prototype.setDeleteStyle = function(_enable) { +Bubble.prototype.setDeleteStyle = function(_enable) { // NOP if bubble is not deletable. }; @@ -374,10 +378,10 @@ Blockly.Bubble.prototype.setDeleteStyle = function(_enable) { * @param {!Event} e Mouse down event. * @private */ -Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { +Bubble.prototype.resizeMouseDown_ = function(e) { this.promote(); - Blockly.Bubble.unbindDragEvents_(); - if (Blockly.utils.isRightButton(e)) { + Bubble.unbindDragEvents_(); + if (utils.isRightButton(e)) { // No right-click. e.stopPropagation(); return; @@ -385,12 +389,12 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { // Left-click (or middle click) this.workspace_.startDrag( e, - new Blockly.utils.Coordinate( + new Coordinate( this.workspace_.RTL ? -this.width_ : this.width_, this.height_)); - Blockly.Bubble.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind( - document, 'mouseup', this, Blockly.Bubble.bubbleMouseUp_); - Blockly.Bubble.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind( + Bubble.onMouseUpWrapper_ = browserEvents.conditionalBind( + document, 'mouseup', this, Bubble.bubbleMouseUp_); + Bubble.onMouseMoveWrapper_ = browserEvents.conditionalBind( document, 'mousemove', this, this.resizeMouseMove_); Blockly.hideChaff(); // This event has been handled. No need to bubble up to the document. @@ -402,9 +406,9 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { * @param {!Event} e Mouse move event. * @private */ -Blockly.Bubble.prototype.resizeMouseMove_ = function(e) { +Bubble.prototype.resizeMouseMove_ = function(e) { this.autoLayout_ = false; - var newXY = this.workspace_.moveDrag(e); + const newXY = this.workspace_.moveDrag(e); this.setBubbleSize(this.workspace_.RTL ? -newXY.x : newXY.x, newXY.y); if (this.workspace_.RTL) { // RTL requires the bubble to move its left edge. @@ -416,7 +420,7 @@ Blockly.Bubble.prototype.resizeMouseMove_ = function(e) { * Register a function as a callback event for when the bubble is resized. * @param {!Function} callback The function to call on resize. */ -Blockly.Bubble.prototype.registerResizeEvent = function(callback) { +Bubble.prototype.registerResizeEvent = function(callback) { this.resizeCallback_ = callback; }; @@ -424,7 +428,7 @@ Blockly.Bubble.prototype.registerResizeEvent = function(callback) { * Register a function as a callback event for when the bubble is moved. * @param {!Function} callback The function to call on move. */ -Blockly.Bubble.prototype.registerMoveEvent = function(callback) { +Bubble.prototype.registerMoveEvent = function(callback) { this.moveCallback_ = callback; }; @@ -433,8 +437,8 @@ Blockly.Bubble.prototype.registerMoveEvent = function(callback) { * @return {boolean} Whether or not the bubble has been moved. * @package */ -Blockly.Bubble.prototype.promote = function() { - var svgGroup = this.bubbleGroup_.parentNode; +Bubble.prototype.promote = function() { + const svgGroup = this.bubbleGroup_.parentNode; if (svgGroup.lastChild !== this.bubbleGroup_) { svgGroup.appendChild(this.bubbleGroup_); return true; @@ -445,9 +449,9 @@ Blockly.Bubble.prototype.promote = function() { /** * Notification that the anchor has moved. * Update the arrow and bubble accordingly. - * @param {!Blockly.utils.Coordinate} xy Absolute location. + * @param {!Coordinate} xy Absolute location. */ -Blockly.Bubble.prototype.setAnchorLocation = function(xy) { +Bubble.prototype.setAnchorLocation = function(xy) { this.anchorXY_ = xy; if (this.rendered_) { this.positionBubble_(); @@ -458,34 +462,36 @@ Blockly.Bubble.prototype.setAnchorLocation = function(xy) { * Position the bubble so that it does not fall off-screen. * @private */ -Blockly.Bubble.prototype.layoutBubble_ = function() { +Bubble.prototype.layoutBubble_ = function() { // Get the metrics in workspace units. - var viewMetrics = this.workspace_.getMetricsManager().getViewMetrics(true); + const viewMetrics = this.workspace_.getMetricsManager().getViewMetrics(true); - var optimalLeft = this.getOptimalRelativeLeft_(viewMetrics); - var optimalTop = this.getOptimalRelativeTop_(viewMetrics); - var bbox = this.shape_.getBBox(); + const optimalLeft = this.getOptimalRelativeLeft_(viewMetrics); + const optimalTop = this.getOptimalRelativeTop_(viewMetrics); + const bbox = this.shape_.getBBox(); - var topPosition = { + const topPosition = { x: optimalLeft, y: -this.height_ - this.workspace_.getRenderer().getConstants().MIN_BLOCK_HEIGHT }; - var startPosition = {x: -this.width_ - 30, y: optimalTop}; - var endPosition = {x: bbox.width, y: optimalTop}; - var bottomPosition = {x: optimalLeft, y: bbox.height}; + const startPosition = {x: -this.width_ - 30, y: optimalTop}; + const endPosition = {x: bbox.width, y: optimalTop}; + const bottomPosition = {x: optimalLeft, y: bbox.height}; - var closerPosition = bbox.width < bbox.height ? endPosition : bottomPosition; - var fartherPosition = bbox.width < bbox.height ? bottomPosition : endPosition; + const closerPosition = + bbox.width < bbox.height ? endPosition : bottomPosition; + const fartherPosition = + bbox.width < bbox.height ? bottomPosition : endPosition; - var topPositionOverlap = this.getOverlap_(topPosition, viewMetrics); - var startPositionOverlap = this.getOverlap_(startPosition, viewMetrics); - var closerPositionOverlap = this.getOverlap_(closerPosition, viewMetrics); - var fartherPositionOverlap = this.getOverlap_(fartherPosition, viewMetrics); + const topPositionOverlap = this.getOverlap_(topPosition, viewMetrics); + const startPositionOverlap = this.getOverlap_(startPosition, viewMetrics); + const closerPositionOverlap = this.getOverlap_(closerPosition, viewMetrics); + const fartherPositionOverlap = this.getOverlap_(fartherPosition, viewMetrics); // Set the position to whichever position shows the most of the bubble, // with tiebreaks going in the order: top > start > close > far. - var mostOverlap = Math.max( + const mostOverlap = Math.max( topPositionOverlap, startPositionOverlap, closerPositionOverlap, fartherPositionOverlap); if (topPositionOverlap == mostOverlap) { @@ -515,20 +521,23 @@ Blockly.Bubble.prototype.layoutBubble_ = function() { * workspace (what percentage of the bubble is visible). * @param {!{x: number, y: number}} relativeMin The position of the top-left * corner of the bubble relative to the anchor point. - * @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics + * @param {!MetricsManager.ContainerRegion} viewMetrics The view metrics * of the workspace the bubble will appear in. * @return {number} The percentage of the bubble that is visible. * @private */ -Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) { +Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) { // The position of the top-left corner of the bubble in workspace units. - var bubbleMin = { + const bubbleMin = { x: this.workspace_.RTL ? (this.anchorXY_.x - relativeMin.x - this.width_) : (relativeMin.x + this.anchorXY_.x), y: relativeMin.y + this.anchorXY_.y }; // The position of the bottom-right corner of the bubble in workspace units. - var bubbleMax = {x: bubbleMin.x + this.width_, y: bubbleMin.y + this.height_}; + const bubbleMax = { + x: bubbleMin.x + this.width_, + y: bubbleMin.y + this.height_ + }; // We could adjust these values to account for the scrollbars, but the // bubbles should have been adjusted to not collide with them anyway, so @@ -536,16 +545,16 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) { // calculation. // The position of the top-left corner of the workspace. - var workspaceMin = {x: viewMetrics.left, y: viewMetrics.top}; + const workspaceMin = {x: viewMetrics.left, y: viewMetrics.top}; // The position of the bottom-right corner of the workspace. - var workspaceMax = { + const workspaceMax = { x: viewMetrics.left + viewMetrics.width, y: viewMetrics.top + viewMetrics.height }; - var overlapWidth = Math.min(bubbleMax.x, workspaceMax.x) - + const overlapWidth = Math.min(bubbleMax.x, workspaceMax.x) - Math.max(bubbleMin.x, workspaceMin.x); - var overlapHeight = Math.min(bubbleMax.y, workspaceMax.y) - + const overlapHeight = Math.min(bubbleMax.y, workspaceMax.y) - Math.max(bubbleMin.y, workspaceMin.y); return Math.max( 0, @@ -557,14 +566,14 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) { * Calculate what the optimal horizontal position of the top-left corner of the * bubble is (relative to the anchor point) so that the most area of the * bubble is shown. - * @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics + * @param {!MetricsManager.ContainerRegion} viewMetrics The view metrics * of the workspace the bubble will appear in. * @return {number} The optimal horizontal position of the top-left corner * of the bubble. * @private */ -Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) { - var relativeLeft = -this.width_ / 4; +Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) { + let relativeLeft = -this.width_ / 4; // No amount of sliding left or right will give us a better overlap. if (this.width_ > viewMetrics.width) { @@ -573,24 +582,14 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) { if (this.workspace_.RTL) { // Bubble coordinates are flipped in RTL. - var bubbleRight = this.anchorXY_.x - relativeLeft; - var bubbleLeft = bubbleRight - this.width_; + const bubbleRight = this.anchorXY_.x - relativeLeft; + const bubbleLeft = bubbleRight - this.width_; - var workspaceRight = viewMetrics.left + viewMetrics.width; - var workspaceLeft = viewMetrics.left + + const workspaceRight = viewMetrics.left + viewMetrics.width; + const workspaceLeft = viewMetrics.left + // Thickness in workspace units. - (Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale); - } else { - var bubbleLeft = relativeLeft + this.anchorXY_.x; - var bubbleRight = bubbleLeft + this.width_; + (Scrollbar.scrollbarThickness / this.workspace_.scale); - var workspaceLeft = viewMetrics.left; - var workspaceRight = viewMetrics.left + viewMetrics.width - - // Thickness in workspace units. - (Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale); - } - - if (this.workspace_.RTL) { if (bubbleLeft < workspaceLeft) { // Slide the bubble right until it is onscreen. relativeLeft = -(workspaceLeft - this.anchorXY_.x + this.width_); @@ -599,6 +598,14 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) { relativeLeft = -(workspaceRight - this.anchorXY_.x); } } else { + const bubbleLeft = relativeLeft + this.anchorXY_.x; + const bubbleRight = bubbleLeft + this.width_; + + const workspaceLeft = viewMetrics.left; + const workspaceRight = viewMetrics.left + viewMetrics.width - + // Thickness in workspace units. + (Scrollbar.scrollbarThickness / this.workspace_.scale); + if (bubbleLeft < workspaceLeft) { // Slide the bubble right until it is onscreen. relativeLeft = workspaceLeft - this.anchorXY_.x; @@ -615,28 +622,28 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) { * Calculate what the optimal vertical position of the top-left corner of * the bubble is (relative to the anchor point) so that the most area of the * bubble is shown. - * @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics + * @param {!MetricsManager.ContainerRegion} viewMetrics The view metrics * of the workspace the bubble will appear in. * @return {number} The optimal vertical position of the top-left corner * of the bubble. * @private */ -Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) { - var relativeTop = -this.height_ / 4; +Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) { + let relativeTop = -this.height_ / 4; // No amount of sliding up or down will give us a better overlap. if (this.height_ > viewMetrics.height) { return relativeTop; } - var bubbleTop = this.anchorXY_.y + relativeTop; - var bubbleBottom = bubbleTop + this.height_; - var workspaceTop = viewMetrics.top; - var workspaceBottom = viewMetrics.top + viewMetrics.height - + const bubbleTop = this.anchorXY_.y + relativeTop; + const bubbleBottom = bubbleTop + this.height_; + const workspaceTop = viewMetrics.top; + const workspaceBottom = viewMetrics.top + viewMetrics.height - // Thickness in workspace units. - (Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale); + (Scrollbar.scrollbarThickness / this.workspace_.scale); - var anchorY = this.anchorXY_.y; + const anchorY = this.anchorXY_.y; if (bubbleTop < workspaceTop) { // Slide the bubble down until it is onscreen. relativeTop = workspaceTop - anchorY; @@ -652,14 +659,14 @@ Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) { * Move the bubble to a location relative to the anchor's centre. * @private */ -Blockly.Bubble.prototype.positionBubble_ = function() { - var left = this.anchorXY_.x; +Bubble.prototype.positionBubble_ = function() { + let left = this.anchorXY_.x; if (this.workspace_.RTL) { left -= this.relativeLeft_ + this.width_; } else { left += this.relativeLeft_; } - var top = this.relativeTop_ + this.anchorXY_.y; + const top = this.relativeTop_ + this.anchorXY_.y; this.moveTo(left, top); }; @@ -669,7 +676,7 @@ Blockly.Bubble.prototype.positionBubble_ = function() { * @param {number} y The y position to move to. * @package */ -Blockly.Bubble.prototype.moveTo = function(x, y) { +Bubble.prototype.moveTo = function(x, y) { this.bubbleGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')'); }; @@ -678,7 +685,7 @@ Blockly.Bubble.prototype.moveTo = function(x, y) { * @param {boolean} adding True if adding, false if removing. * @package */ -Blockly.Bubble.prototype.setDragging = function(adding) { +Bubble.prototype.setDragging = function(adding) { if (!adding && this.moveCallback_) { this.moveCallback_(); } @@ -686,10 +693,10 @@ Blockly.Bubble.prototype.setDragging = function(adding) { /** * Get the dimensions of this bubble. - * @return {!Blockly.utils.Size} The height and width of the bubble. + * @return {!Size} The height and width of the bubble. */ -Blockly.Bubble.prototype.getBubbleSize = function() { - return new Blockly.utils.Size(this.width_, this.height_); +Bubble.prototype.getBubbleSize = function() { + return new Size(this.width_, this.height_); }; /** @@ -697,8 +704,8 @@ Blockly.Bubble.prototype.getBubbleSize = function() { * @param {number} width Width of the bubble. * @param {number} height Height of the bubble. */ -Blockly.Bubble.prototype.setBubbleSize = function(width, height) { - var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH; +Bubble.prototype.setBubbleSize = function(width, height) { + const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH; // Minimum size of a bubble. width = Math.max(width, doubleBorderWidth + 45); height = Math.max(height, doubleBorderWidth + 20); @@ -709,7 +716,7 @@ Blockly.Bubble.prototype.setBubbleSize = function(width, height) { if (this.resizeGroup_) { if (this.workspace_.RTL) { // Mirror the resize group. - var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; + const resizeSize = 2 * Bubble.BORDER_WIDTH; this.resizeGroup_.setAttribute( 'transform', 'translate(' + resizeSize + ',' + (height - doubleBorderWidth) + @@ -737,64 +744,62 @@ Blockly.Bubble.prototype.setBubbleSize = function(width, height) { * Draw the arrow between the bubble and the origin. * @private */ -Blockly.Bubble.prototype.renderArrow_ = function() { - var steps = []; +Bubble.prototype.renderArrow_ = function() { + const steps = []; // Find the relative coordinates of the center of the bubble. - var relBubbleX = this.width_ / 2; - var relBubbleY = this.height_ / 2; + const relBubbleX = this.width_ / 2; + const relBubbleY = this.height_ / 2; // Find the relative coordinates of the center of the anchor. - var relAnchorX = -this.relativeLeft_; - var relAnchorY = -this.relativeTop_; + let relAnchorX = -this.relativeLeft_; + let relAnchorY = -this.relativeTop_; if (relBubbleX == relAnchorX && relBubbleY == relAnchorY) { // Null case. Bubble is directly on top of the anchor. // Short circuit this rather than wade through divide by zeros. steps.push('M ' + relBubbleX + ',' + relBubbleY); } else { // Compute the angle of the arrow's line. - var rise = relAnchorY - relBubbleY; - var run = relAnchorX - relBubbleX; + const rise = relAnchorY - relBubbleY; + let run = relAnchorX - relBubbleX; if (this.workspace_.RTL) { run *= -1; } - var hypotenuse = Math.sqrt(rise * rise + run * run); - var angle = Math.acos(run / hypotenuse); + const hypotenuse = Math.sqrt(rise * rise + run * run); + let angle = Math.acos(run / hypotenuse); if (rise < 0) { angle = 2 * Math.PI - angle; } // Compute a line perpendicular to the arrow. - var rightAngle = angle + Math.PI / 2; + let rightAngle = angle + Math.PI / 2; if (rightAngle > Math.PI * 2) { rightAngle -= Math.PI * 2; } - var rightRise = Math.sin(rightAngle); - var rightRun = Math.cos(rightAngle); + const rightRise = Math.sin(rightAngle); + const rightRun = Math.cos(rightAngle); // Calculate the thickness of the base of the arrow. - var bubbleSize = this.getBubbleSize(); - var thickness = - (bubbleSize.width + bubbleSize.height) / Blockly.Bubble.ARROW_THICKNESS; + const bubbleSize = this.getBubbleSize(); + let thickness = + (bubbleSize.width + bubbleSize.height) / Bubble.ARROW_THICKNESS; thickness = Math.min(thickness, bubbleSize.width, bubbleSize.height) / 4; // Back the tip of the arrow off of the anchor. - var backoffRatio = 1 - Blockly.Bubble.ANCHOR_RADIUS / hypotenuse; + const backoffRatio = 1 - Bubble.ANCHOR_RADIUS / hypotenuse; relAnchorX = relBubbleX + backoffRatio * run; relAnchorY = relBubbleY + backoffRatio * rise; // Coordinates for the base of the arrow. - var baseX1 = relBubbleX + thickness * rightRun; - var baseY1 = relBubbleY + thickness * rightRise; - var baseX2 = relBubbleX - thickness * rightRun; - var baseY2 = relBubbleY - thickness * rightRise; + const baseX1 = relBubbleX + thickness * rightRun; + const baseY1 = relBubbleY + thickness * rightRise; + const baseX2 = relBubbleX - thickness * rightRun; + const baseY2 = relBubbleY - thickness * rightRise; // Distortion to curve the arrow. - var swirlAngle = angle + this.arrow_radians_; + let swirlAngle = angle + this.arrow_radians_; if (swirlAngle > Math.PI * 2) { swirlAngle -= Math.PI * 2; } - var swirlRise = - Math.sin(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND; - var swirlRun = - Math.cos(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND; + const swirlRise = Math.sin(swirlAngle) * hypotenuse / Bubble.ARROW_BEND; + const swirlRun = Math.cos(swirlAngle) * hypotenuse / Bubble.ARROW_BEND; steps.push('M' + baseX1 + ',' + baseY1); steps.push( @@ -812,7 +817,7 @@ Blockly.Bubble.prototype.renderArrow_ = function() { * Change the colour of a bubble. * @param {string} hexColour Hex code of colour. */ -Blockly.Bubble.prototype.setColour = function(hexColour) { +Bubble.prototype.setColour = function(hexColour) { this.bubbleBack_.setAttribute('fill', hexColour); this.bubbleArrow_.setAttribute('fill', hexColour); }; @@ -820,28 +825,28 @@ Blockly.Bubble.prototype.setColour = function(hexColour) { /** * Dispose of this bubble. */ -Blockly.Bubble.prototype.dispose = function() { +Bubble.prototype.dispose = function() { if (this.onMouseDownBubbleWrapper_) { - Blockly.browserEvents.unbind(this.onMouseDownBubbleWrapper_); + browserEvents.unbind(this.onMouseDownBubbleWrapper_); } if (this.onMouseDownResizeWrapper_) { - Blockly.browserEvents.unbind(this.onMouseDownResizeWrapper_); + browserEvents.unbind(this.onMouseDownResizeWrapper_); } - Blockly.Bubble.unbindDragEvents_(); - Blockly.utils.dom.removeNode(this.bubbleGroup_); + Bubble.unbindDragEvents_(); + dom.removeNode(this.bubbleGroup_); this.disposed = true; }; /** * Move this bubble during a drag, taking into account whether or not there is * a drag surface. - * @param {Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries + * @param {BlockDragSurfaceSvg} dragSurface The surface that carries * rendered items during a drag, or null if no drag surface is in use. - * @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in + * @param {!Coordinate} newLoc The location to translate to, in * workspace coordinates. * @package */ -Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) { +Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) { if (dragSurface) { dragSurface.translateSurface(newLoc.x, newLoc.y); } else { @@ -859,10 +864,10 @@ Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) { /** * Return the coordinates of the top-left corner of this bubble's body relative * to the drawing surface's origin (0,0), in workspace units. - * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. + * @return {!Coordinate} Object with .x and .y properties. */ -Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() { - return new Blockly.utils.Coordinate( +Bubble.prototype.getRelativeToSurfaceXY = function() { + return new Coordinate( this.workspace_.RTL ? -this.relativeLeft_ + this.anchorXY_.x - this.width_ : this.anchorXY_.x + this.relativeLeft_, @@ -877,7 +882,7 @@ Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() { * otherwise. * @package */ -Blockly.Bubble.prototype.setAutoLayout = function(enable) { +Bubble.prototype.setAutoLayout = function(enable) { this.autoLayout_ = enable; }; @@ -887,19 +892,18 @@ Blockly.Bubble.prototype.setAutoLayout = function(enable) { * @return {!SVGTextElement} The top-level node of the text. * @package */ -Blockly.Bubble.textToDom = function(text) { - var paragraph = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TEXT, { +Bubble.textToDom = function(text) { + const paragraph = dom.createSvgElement( + Svg.TEXT, { 'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents', - 'y': Blockly.Bubble.BORDER_WIDTH + 'y': Bubble.BORDER_WIDTH }, null); - var lines = text.split('\n'); - for (var i = 0; i < lines.length; i++) { - var tspanElement = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TSPAN, - {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); - var textNode = document.createTextNode(lines[i]); + const lines = text.split('\n'); + for (let i = 0; i < lines.length; i++) { + const tspanElement = dom.createSvgElement( + Svg.TSPAN, {'dy': '1em', 'x': Bubble.BORDER_WIDTH}, paragraph); + const textNode = document.createTextNode(lines[i]); tspanElement.appendChild(textNode); } return paragraph; @@ -909,28 +913,29 @@ Blockly.Bubble.textToDom = function(text) { * Creates a bubble that can not be edited. * @param {!SVGTextElement} paragraphElement The text element for the non * editable bubble. - * @param {!Blockly.BlockSvg} block The block that the bubble is attached to. - * @param {!Blockly.utils.Coordinate} iconXY The coordinate of the icon. - * @return {!Blockly.Bubble} The non editable bubble. + * @param {!BlockSvg} block The block that the bubble is attached to. + * @param {!Coordinate} iconXY The coordinate of the icon. + * @return {!Bubble} The non editable bubble. * @package */ -Blockly.Bubble.createNonEditableBubble = function( - paragraphElement, block, iconXY) { - var bubble = new Blockly.Bubble( - /** @type {!Blockly.WorkspaceSvg} */ (block.workspace), paragraphElement, +Bubble.createNonEditableBubble = function(paragraphElement, block, iconXY) { + const bubble = new Bubble( + /** @type {!WorkspaceSvg} */ (block.workspace), paragraphElement, block.pathObject.svgPath, - /** @type {!Blockly.utils.Coordinate} */ (iconXY), null, null); + /** @type {!Coordinate} */ (iconXY), null, null); // Expose this bubble's block's ID on its top-level SVG group. bubble.setSvgId(block.id); if (block.RTL) { // Right-align the paragraph. // This cannot be done until the bubble is rendered on screen. - var maxWidth = paragraphElement.getBBox().width; - for (var i = 0, textElement; (textElement = paragraphElement.childNodes[i]); - i++) { + const maxWidth = paragraphElement.getBBox().width; + for (let i = 0, textElement; (textElement = paragraphElement.childNodes[i]); + i++) { textElement.setAttribute('text-anchor', 'end'); - textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); + textElement.setAttribute('x', maxWidth + Bubble.BORDER_WIDTH); } } return bubble; }; + +exports = Bubble; diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index d06c2fdc0..d879e4748 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -25,6 +25,8 @@ const IDeleteArea = goog.requireType('Blockly.IDeleteArea'); /* eslint-disable-next-line no-unused-vars */ const IDragTarget = goog.requireType('Blockly.IDragTarget'); /* eslint-disable-next-line no-unused-vars */ +const WorkspaceCommentSvg = goog.requireType('Blockly.WorkspaceCommentSvg'); +/* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ @@ -236,7 +238,7 @@ BubbleDragger.prototype.fireMoveEvent_ = function() { if (this.draggingBubble_.isComment) { // TODO (adodson): Resolve build errors when requiring WorkspaceCommentSvg. const event = new (Events.get(Events.COMMENT_MOVE))( - /** @type {!Blockly.WorkspaceCommentSvg} */ (this.draggingBubble_)); + /** @type {!WorkspaceCommentSvg} */ (this.draggingBubble_)); event.setOldCoordinate(this.startXY_); event.recordNew(); Events.fire(event); diff --git a/core/clipboard.js b/core/clipboard.js new file mode 100644 index 000000000..9810836f9 --- /dev/null +++ b/core/clipboard.js @@ -0,0 +1,80 @@ +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Blockly's internal clipboard for managing copy-paste. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.clipboard'); +goog.module.declareLegacyNamespace(); + +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const ICopyable = goog.requireType('Blockly.ICopyable'); + +/** + * Metadata about the object that is currently on the clipboard. + * @type {?ICopyable.CopyData} + */ +let copyData = null; + +/** + * Copy a block or workspace comment onto the local clipboard. + * @param {!ICopyable} toCopy Block or Workspace Comment to be copied. + */ +const copy = function(toCopy) { + copyData = toCopy.toCopyData(); +}; +/** @package */ +exports.copy = copy; + +/** + * Paste a block or workspace comment on to the main workspace. + * @return {boolean} True if the paste was successful, false otherwise. + */ +const paste = function() { + if (!copyData.xml) { + return false; + } + // Pasting always pastes to the main workspace, even if the copy + // started in a flyout workspace. + var workspace = copyData.source; + if (workspace.isFlyout) { + workspace = workspace.targetWorkspace; + } + if (copyData.typeCounts && + workspace.isCapacityAvailable(copyData.typeCounts)) { + Events.setGroup(true); + workspace.paste(copyData.xml); + Events.setGroup(false); + return true; + } + return false; +}; +/** @package */ +exports.paste = paste; + +/** + * Duplicate this block and its children, or a workspace comment. + * @param {!ICopyable} toDuplicate Block or Workspace Comment to be + * duplicated. + */ +const duplicate = function(toDuplicate) { + // Save the clipboard. + const oldCopyData = copyData; + + // Create a duplicate via a copy/paste operation. + copy(toDuplicate); + // copy() replaced the value of copyData. + toDuplicate.workspace.paste(copyData.xml); + + // Restore the clipboard. + copyData = oldCopyData; +}; +/** @package */ +exports.duplicate = duplicate; diff --git a/core/comment.js b/core/comment.js index 99d81e89c..b126aaf57 100644 --- a/core/comment.js +++ b/core/comment.js @@ -20,6 +20,7 @@ const BlockSvg = goog.requireType('Blockly.BlockSvg'); const Bubble = goog.require('Blockly.Bubble'); /* eslint-disable-next-line no-unused-vars */ const Coordinate = goog.requireType('Blockly.utils.Coordinate'); +const Css = goog.require('Blockly.Css'); const Events = goog.require('Blockly.Events'); const Icon = goog.require('Blockly.Icon'); /* eslint-disable-next-line no-unused-vars */ @@ -27,12 +28,10 @@ const Size = goog.requireType('Blockly.utils.Size'); const Svg = goog.require('Blockly.utils.Svg'); /* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); const userAgent = goog.require('Blockly.utils.userAgent'); -/* eslint-disable-next-line no-unused-vars */ -const {conditionalBind, Data, unbind} = goog.require('Blockly.browserEvents'); -const {createSvgElement, HTML_NS} = goog.require('Blockly.utils.dom'); -const {inherits} = goog.require('Blockly.utils.object'); -const {register} = goog.require('Blockly.Css'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); /** @suppress {extraRequire} */ @@ -70,35 +69,35 @@ const Comment = function(block) { /** * Mouse up event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onMouseUpWrapper_ = null; /** * Wheel event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onWheelWrapper_ = null; /** * Change event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onChangeWrapper_ = null; /** * Input event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onInputWrapper_ = null; this.createIcon(); }; -inherits(Comment, Icon); +object.inherits(Comment, Icon); /** * Draw the comment icon. @@ -107,13 +106,13 @@ inherits(Comment, Icon); */ Comment.prototype.drawIcon_ = function(group) { // Circle. - createSvgElement( + dom.createSvgElement( Svg.CIRCLE, {'class': 'blocklyIconShape', 'r': '8', 'cx': '8', 'cy': '8'}, group); // Can't use a real '?' text character since different browsers and operating // systems render it differently. // Body of question mark. - createSvgElement( + dom.createSvgElement( Svg.PATH, { 'class': 'blocklyIconSymbol', 'd': 'm6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.405' + @@ -122,7 +121,7 @@ Comment.prototype.drawIcon_ = function(group) { }, group); // Dot of question mark. - createSvgElement( + dom.createSvgElement( Svg.RECT, { 'class': 'blocklyIconSymbol', 'x': '6.8', @@ -151,15 +150,15 @@ Comment.prototype.createEditor_ = function() { * For non-editable mode see Warning.textToDom_. */ - this.foreignObject_ = createSvgElement( + this.foreignObject_ = dom.createSvgElement( Svg.FOREIGNOBJECT, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null); - const body = document.createElementNS(HTML_NS, 'body'); - body.setAttribute('xmlns', HTML_NS); + const body = document.createElementNS(dom.HTML_NS, 'body'); + body.setAttribute('xmlns', dom.HTML_NS); body.className = 'blocklyMinimalBody'; - this.textarea_ = document.createElementNS(HTML_NS, 'textarea'); + this.textarea_ = document.createElementNS(dom.HTML_NS, 'textarea'); const textarea = this.textarea_; textarea.className = 'blocklyCommentTextarea'; textarea.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR'); @@ -172,23 +171,25 @@ Comment.prototype.createEditor_ = function() { // Ideally this would be hooked to the focus event for the comment. // However doing so in Firefox swallows the cursor for unknown reasons. // So this is hooked to mouseup instead. No big deal. - this.onMouseUpWrapper_ = - conditionalBind(textarea, 'mouseup', this, this.startEdit_, true, true); + this.onMouseUpWrapper_ = browserEvents.conditionalBind( + textarea, 'mouseup', this, this.startEdit_, true, true); // Don't zoom with mousewheel. - this.onWheelWrapper_ = conditionalBind(textarea, 'wheel', this, function(e) { - e.stopPropagation(); - }); + this.onWheelWrapper_ = + browserEvents.conditionalBind(textarea, 'wheel', this, function(e) { + e.stopPropagation(); + }); this.onChangeWrapper_ = - conditionalBind(textarea, 'change', this, function(_e) { + browserEvents.conditionalBind(textarea, 'change', this, function(_e) { if (this.cachedText_ != this.model_.text) { Events.fire(new (Events.get(Events.BLOCK_CHANGE))( this.block_, 'comment', null, this.cachedText_, this.model_.text)); } }); - this.onInputWrapper_ = conditionalBind(textarea, 'input', this, function(_e) { - this.model_.text = textarea.value; - }); + this.onInputWrapper_ = + browserEvents.conditionalBind(textarea, 'input', this, function(_e) { + this.model_.text = textarea.value; + }); setTimeout(textarea.focus.bind(textarea), 0); @@ -307,19 +308,19 @@ Comment.prototype.createNonEditableBubble_ = function() { */ Comment.prototype.disposeBubble_ = function() { if (this.onMouseUpWrapper_) { - unbind(this.onMouseUpWrapper_); + browserEvents.unbind(this.onMouseUpWrapper_); this.onMouseUpWrapper_ = null; } if (this.onWheelWrapper_) { - unbind(this.onWheelWrapper_); + browserEvents.unbind(this.onWheelWrapper_); this.onWheelWrapper_ = null; } if (this.onChangeWrapper_) { - unbind(this.onChangeWrapper_); + browserEvents.unbind(this.onChangeWrapper_); this.onChangeWrapper_ = null; } if (this.onInputWrapper_) { - unbind(this.onInputWrapper_); + browserEvents.unbind(this.onInputWrapper_); this.onInputWrapper_ = null; } this.bubble_.dispose(); @@ -397,7 +398,7 @@ Comment.prototype.dispose = function() { /** * CSS for block comment. See css.js for use. */ -register([ +Css.register([ /* eslint-disable indent */ '.blocklyCommentTextarea {', 'background-color: #fef49c;', 'border: 0;', 'outline: 0;', 'margin: 0;', 'padding: 3px;', 'resize: none;', diff --git a/core/common.js b/core/common.js new file mode 100644 index 000000000..b6d7ad369 --- /dev/null +++ b/core/common.js @@ -0,0 +1,82 @@ +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Common functions used both internally and externally, but which + * must not be at the top level to avoid circular dependencies. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.common'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); + + +/** + * The main workspace most recently used. + * Set by Blockly.WorkspaceSvg.prototype.markFocused + * @type {!Workspace} + */ +let mainWorkspace; + +/** + * Returns the last used top level workspace (based on focus). Try not to use + * this function, particularly if there are multiple Blockly instances on a + * page. + * @return {!Workspace} The main workspace. + */ +const getMainWorkspace = function() { + return mainWorkspace; +}; +exports.getMainWorkspace = getMainWorkspace; + +/** + * Sets last used main workspace. + * @param {!Workspace} workspace The most recently used top level workspace. + */ +const setMainWorkspace = function(workspace) { + mainWorkspace = workspace; +}; +exports.setMainWorkspace = setMainWorkspace; + +/** + * Container element in which to render the WidgetDiv, DropDownDiv and Tooltip. + * @type {?Element} + */ +let parentContainer; + +/** + * Get the container element in which to render the WidgetDiv, DropDownDiv and\ + * Tooltip. + * @return {?Element} The parent container. + */ +const getParentContainer = function() { + return parentContainer; +}; +exports.getParentContainer = getParentContainer; + +/** + * Set the parent container. This is the container element that the WidgetDiv, + * DropDownDiv, and Tooltip are rendered into the first time `Blockly.inject` + * is called. + * This method is a NOP if called after the first ``Blockly.inject``. + * @param {!Element} newParent The container element. + */ +const setParentContainer = function(newParent) { + parentContainer = newParent; +}; +exports.setParentContainer = setParentContainer; + +/** + * All of the connections on blocks that are currently being dragged. + * @type {!Array} + */ +exports.draggingConnections = []; diff --git a/core/connection.js b/core/connection.js index f272b59e0..ae7ad8051 100644 --- a/core/connection.js +++ b/core/connection.js @@ -17,7 +17,7 @@ goog.module.declareLegacyNamespace(); const Block = goog.requireType('Blockly.Block'); const Events = goog.require('Blockly.Events'); /* eslint-disable-next-line no-unused-vars */ -const IASTNodeLocationWithBlock = goog.require('Blockly.IASTNodeLocationWithBlock'); +const IASTNodeLocationWithBlock = goog.requireType('Blockly.IASTNodeLocationWithBlock'); /* eslint-disable-next-line no-unused-vars */ const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker'); /* eslint-disable-next-line no-unused-vars */ diff --git a/core/connection_checker.js b/core/connection_checker.js index 2ea27aa19..e3fbc1929 100644 --- a/core/connection_checker.js +++ b/core/connection_checker.js @@ -16,12 +16,13 @@ goog.module.declareLegacyNamespace(); const Connection = goog.require('Blockly.Connection'); /* eslint-disable-next-line no-unused-vars */ -const IConnectionChecker = goog.require('Blockly.IConnectionChecker'); +const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker'); /* eslint-disable-next-line no-unused-vars */ const RenderedConnection = goog.requireType('Blockly.RenderedConnection'); +const common = goog.require('Blockly.common'); const connectionTypes = goog.require('Blockly.connectionTypes'); +const internalConstants = goog.require('Blockly.internalConstants'); const registry = goog.require('Blockly.registry'); -const {OPPOSITE_TYPE} = goog.require('Blockly.internalConstants'); /** @@ -145,7 +146,7 @@ ConnectionChecker.prototype.doSafetyChecks = function(a, b) { } if (blockA == blockB) { return Connection.REASON_SELF_CONNECTION; - } else if (b.type != OPPOSITE_TYPE[a.type]) { + } else if (b.type != internalConstants.OPPOSITE_TYPE[a.type]) { return Connection.REASON_WRONG_TYPE; } else if (blockA.workspace !== blockB.workspace) { return Connection.REASON_DIFFERENT_WORKSPACES; @@ -239,7 +240,7 @@ ConnectionChecker.prototype.doDragChecks = function(a, b, distance) { } // Don't let blocks try to connect to themselves or ones they nest. - if (Blockly.draggingConnections.indexOf(b) != -1) { + if (common.draggingConnections.indexOf(b) != -1) { return false; } @@ -263,7 +264,7 @@ ConnectionChecker.prototype.canConnectToPrevious_ = function(a, b) { } // Don't let blocks try to connect to themselves or ones they nest. - if (Blockly.draggingConnections.indexOf(b) != -1) { + if (common.draggingConnections.indexOf(b) != -1) { return false; } diff --git a/core/connection_db.js b/core/connection_db.js index d3bc0507d..c0ee7f500 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -20,7 +20,7 @@ const Coordinate = goog.requireType('Blockly.utils.Coordinate'); /* eslint-disable-next-line no-unused-vars */ const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker'); /* eslint-disable-next-line no-unused-vars */ -const RenderedConnection = goog.require('Blockly.RenderedConnection'); +const RenderedConnection = goog.requireType('Blockly.RenderedConnection'); const connectionTypes = goog.require('Blockly.connectionTypes'); /** @suppress {extraRequire} */ goog.require('Blockly.constants'); diff --git a/core/contextmenu.js b/core/contextmenu.js index 3bfcda167..cc02adc25 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -10,45 +10,70 @@ */ 'use strict'; -/** - * @name Blockly.ContextMenu - * @namespace - */ -goog.provide('Blockly.ContextMenu'); +goog.module('Blockly.ContextMenu'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.Events'); +// TODO(#5073): Add Blockly require after fixing circular dependency. +// goog.require('Blockly'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +const Menu = goog.require('Blockly.Menu'); +const MenuItem = goog.require('Blockly.MenuItem'); +const Msg = goog.require('Blockly.Msg'); +const Rect = goog.require('Blockly.utils.Rect'); +const WidgetDiv = goog.require('Blockly.WidgetDiv'); +const Xml = goog.require('Blockly.Xml'); +const aria = goog.require('Blockly.utils.aria'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const internalConstants = goog.require('Blockly.internalConstants'); +const userAgent = goog.require('Blockly.utils.userAgent'); +const utils = goog.require('Blockly.utils'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceCommentSvg = goog.requireType('Blockly.WorkspaceCommentSvg'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockCreate'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.Menu'); -goog.require('Blockly.MenuItem'); -goog.require('Blockly.Msg'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.aria'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.userAgent'); -goog.require('Blockly.WidgetDiv'); -goog.require('Blockly.Xml'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.WorkspaceSvg'); /** * Which block is the context menu attached to? - * @type {Blockly.Block} + * @type {?Block} */ -Blockly.ContextMenu.currentBlock = null; +let currentBlock = null; + +/** + * Gets the block the context menu is currently attached to. + * @return {?Block} The block the context menu is attached to. + */ +const getCurrentBlock = function() { + return currentBlock; +}; +exports.getCurrentBlock = getCurrentBlock; + +/** + * Sets the block the context menu is currently attached to. + * @param {?Block} block The block the context menu is attached to. + */ +const setCurrentBlock = function(block) { + currentBlock = block; +}; +exports.setCurrentBlock = setCurrentBlock; + +// Ad JS accessors for backwards compatibility. +Object.defineProperty(exports, 'currentBlock', { + get: getCurrentBlock, + set: setCurrentBlock, +}); /** * Menu object. - * @type {Blockly.Menu} - * @private + * @type {Menu} */ -Blockly.ContextMenu.menu_ = null; +let menu_ = null; /** * Construct the menu based on the list of options and show the menu. @@ -56,47 +81,51 @@ Blockly.ContextMenu.menu_ = null; * @param {!Array} options Array of menu options. * @param {boolean} rtl True if RTL, false if LTR. */ -Blockly.ContextMenu.show = function(e, options, rtl) { - Blockly.WidgetDiv.show(Blockly.ContextMenu, rtl, Blockly.ContextMenu.dispose); +const show = function(e, options, rtl) { + WidgetDiv.show(exports, rtl, dispose); if (!options.length) { - Blockly.ContextMenu.hide(); + hide(); return; } - var menu = Blockly.ContextMenu.populate_(options, rtl); - Blockly.ContextMenu.menu_ = menu; + const menu = populate_(options, rtl); + menu_ = menu; - Blockly.ContextMenu.position_(menu, e, rtl); + position_(menu, e, rtl); // 1ms delay is required for focusing on context menus because some other // mouse event is still waiting in the queue and clears focus. - setTimeout(function() {menu.focus();}, 1); - Blockly.ContextMenu.currentBlock = null; // May be set by Blockly.Block. + setTimeout(function() { + menu.focus(); + }, 1); + currentBlock = null; // May be set by Blockly.Block. }; +exports.show = show; /** * Create the context menu object and populate it with the given options. * @param {!Array} options Array of menu options. * @param {boolean} rtl True if RTL, false if LTR. - * @return {!Blockly.Menu} The menu that will be shown on right click. + * @return {!Menu} The menu that will be shown on right click. * @private */ -Blockly.ContextMenu.populate_ = function(options, rtl) { +const populate_ = function(options, rtl) { /* Here's what one option object looks like: {text: 'Make It So', enabled: true, callback: Blockly.MakeItSo} */ - var menu = new Blockly.Menu(); - menu.setRole(Blockly.utils.aria.Role.MENU); - for (var i = 0, option; (option = options[i]); i++) { - var menuItem = new Blockly.MenuItem(option.text); + const menu = new Menu(); + menu.setRole(aria.Role.MENU); + for (let i = 0; i < options.length; i++) { + const option = options[i]; + const menuItem = new MenuItem(option.text); menuItem.setRightToLeft(rtl); - menuItem.setRole(Blockly.utils.aria.Role.MENUITEM); + menuItem.setRole(aria.Role.MENUITEM); menu.addChild(menuItem); menuItem.setEnabled(option.enabled); if (option.enabled) { - var actionHandler = function(_menuItem) { - var option = this; - Blockly.ContextMenu.hide(); + const actionHandler = function(_menuItem) { + const option = this; + hide(); option.callback(option.scope); }; menuItem.onAction(actionHandler, option); @@ -107,26 +136,23 @@ Blockly.ContextMenu.populate_ = function(options, rtl) { /** * Add the menu to the page and position it correctly. - * @param {!Blockly.Menu} menu The menu to add and position. + * @param {!Menu} menu The menu to add and position. * @param {!Event} e Mouse event for the right click that is making the context * menu appear. * @param {boolean} rtl True if RTL, false if LTR. * @private */ -Blockly.ContextMenu.position_ = function(menu, e, rtl) { +const position_ = function(menu, e, rtl) { // Record windowSize and scrollOffset before adding menu. - var viewportBBox = Blockly.utils.getViewportBBox(); + const viewportBBox = utils.getViewportBBox(); // This one is just a point, but we'll pretend that it's a rect so we can use // some helper functions. - var anchorBBox = new Blockly.utils.Rect( - e.clientY + viewportBBox.top, - e.clientY + viewportBBox.top, - e.clientX + viewportBBox.left, - e.clientX + viewportBBox.left - ); + const anchorBBox = new Rect( + e.clientY + viewportBBox.top, e.clientY + viewportBBox.top, + e.clientX + viewportBBox.left, e.clientX + viewportBBox.left); - Blockly.ContextMenu.createWidget_(menu); - var menuSize = menu.getSize(); + createWidget_(menu); + const menuSize = menu.getSize(); if (rtl) { anchorBBox.left += menuSize.width; @@ -135,7 +161,7 @@ Blockly.ContextMenu.position_ = function(menu, e, rtl) { viewportBBox.right += menuSize.width; } - Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, rtl); + WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, rtl); // Calling menuDom.focus() has to wait until after the menu has been placed // correctly. Otherwise it will cause a page scroll to get the misplaced menu // in view. See issue #1329. @@ -144,19 +170,19 @@ Blockly.ContextMenu.position_ = function(menu, e, rtl) { /** * Create and render the menu widget inside Blockly's widget div. - * @param {!Blockly.Menu} menu The menu to add to the widget div. + * @param {!Menu} menu The menu to add to the widget div. * @private */ -Blockly.ContextMenu.createWidget_ = function(menu) { - var div = Blockly.WidgetDiv.DIV; +const createWidget_ = function(menu) { + const div = WidgetDiv.DIV; menu.render(div); - var menuDom = menu.getElement(); - Blockly.utils.dom.addClass( + const menuDom = menu.getElement(); + dom.addClass( /** @type {!Element} */ (menuDom), 'blocklyContextMenu'); // Prevent system context menu when right-clicking a Blockly context menu. - Blockly.browserEvents.conditionalBind( + browserEvents.conditionalBind( /** @type {!EventTarget} */ (menuDom), 'contextmenu', null, - Blockly.utils.noEvent); + utils.noEvent); // Focus only after the initial render to avoid issue #1329. menu.focus(); }; @@ -164,85 +190,88 @@ Blockly.ContextMenu.createWidget_ = function(menu) { /** * Hide the context menu. */ -Blockly.ContextMenu.hide = function() { - Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu); - Blockly.ContextMenu.currentBlock = null; +const hide = function() { + WidgetDiv.hideIfOwner(exports); + currentBlock = null; }; +exports.hide = hide; /** * Dispose of the menu. */ -Blockly.ContextMenu.dispose = function() { - if (Blockly.ContextMenu.menu_) { - Blockly.ContextMenu.menu_.dispose(); - Blockly.ContextMenu.menu_ = null; +const dispose = function() { + if (menu_) { + menu_.dispose(); + menu_ = null; } }; +exports.dispose = dispose; /** * Create a callback function that creates and configures a block, * then places the new block next to the original. - * @param {!Blockly.Block} block Original block. + * @param {!Block} block Original block. * @param {!Element} xml XML representation of new block. * @return {!Function} Function that creates a block. */ -Blockly.ContextMenu.callbackFactory = function(block, xml) { +const callbackFactory = function(block, xml) { return function() { - Blockly.Events.disable(); + Events.disable(); + let newBlock; try { - var newBlock = Blockly.Xml.domToBlock(xml, block.workspace); + newBlock = Xml.domToBlock(xml, block.workspace); // Move the new block next to the old block. - var xy = block.getRelativeToSurfaceXY(); + const xy = block.getRelativeToSurfaceXY(); if (block.RTL) { - xy.x -= Blockly.internalConstants.SNAP_RADIUS; + xy.x -= internalConstants.SNAP_RADIUS; } else { - xy.x += Blockly.internalConstants.SNAP_RADIUS; + xy.x += internalConstants.SNAP_RADIUS; } - xy.y += Blockly.internalConstants.SNAP_RADIUS * 2; + xy.y += internalConstants.SNAP_RADIUS * 2; newBlock.moveBy(xy.x, xy.y); } finally { - Blockly.Events.enable(); + Events.enable(); } - if (Blockly.Events.isEnabled() && !newBlock.isShadow()) { - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock)); + if (Events.isEnabled() && !newBlock.isShadow()) { + Events.fire(new (Events.get(Events.BLOCK_CREATE))(newBlock)); } newBlock.select(); }; }; +exports.callbackFactory = callbackFactory; // Helper functions for creating context menu options. /** * Make a context menu option for deleting the current workspace comment. - * @param {!Blockly.WorkspaceCommentSvg} comment The workspace comment where the + * @param {!WorkspaceCommentSvg} comment The workspace comment where the * right-click originated. * @return {!Object} A menu option, containing text, enabled, and a callback. - * @package */ -Blockly.ContextMenu.commentDeleteOption = function(comment) { - var deleteOption = { - text: Blockly.Msg['REMOVE_COMMENT'], +const commentDeleteOption = function(comment) { + const deleteOption = { + text: Msg['REMOVE_COMMENT'], enabled: true, callback: function() { - Blockly.Events.setGroup(true); - comment.dispose(true, true); - Blockly.Events.setGroup(false); + Events.setGroup(true); + comment.dispose(); + Events.setGroup(false); } }; return deleteOption; }; +/** @package */ +exports.commentDeleteOption = commentDeleteOption; /** * Make a context menu option for duplicating the current workspace comment. - * @param {!Blockly.WorkspaceCommentSvg} comment The workspace comment where the + * @param {!WorkspaceCommentSvg} comment The workspace comment where the * right-click originated. * @return {!Object} A menu option, containing text, enabled, and a callback. - * @package */ -Blockly.ContextMenu.commentDuplicateOption = function(comment) { - var duplicateOption = { - text: Blockly.Msg['DUPLICATE_COMMENT'], +const commentDuplicateOption = function(comment) { + const duplicateOption = { + text: Msg['DUPLICATE_COMMENT'], enabled: true, callback: function() { Blockly.duplicate(comment); @@ -250,10 +279,12 @@ Blockly.ContextMenu.commentDuplicateOption = function(comment) { }; return duplicateOption; }; +/** @package */ +exports.commentDuplicateOption = commentDuplicateOption; /** * Make a context menu option for adding a comment on the workspace. - * @param {!Blockly.WorkspaceSvg} ws The workspace where the right-click + * @param {!WorkspaceSvg} ws The workspace where the right-click * originated. * @param {!Event} e The right-click mouse event. * @return {!Object} A menu option, containing text, enabled, and a callback. @@ -261,41 +292,42 @@ Blockly.ContextMenu.commentDuplicateOption = function(comment) { * @suppress {strictModuleDepCheck,checkTypes} Suppress checks while workspace * comments are not bundled in. */ -Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { - if (!Blockly.WorkspaceCommentSvg) { +const workspaceCommentOption = function(ws, e) { + const WorkspaceCommentSvg = goog.module.get('Blockly.WorkspaceCommentSvg'); + if (!WorkspaceCommentSvg) { throw Error('Missing require for Blockly.WorkspaceCommentSvg'); } // Helper function to create and position a comment correctly based on the // location of the mouse event. - var addWsComment = function() { - var comment = new Blockly.WorkspaceCommentSvg( - ws, Blockly.Msg['WORKSPACE_COMMENT_DEFAULT_TEXT'], - Blockly.WorkspaceCommentSvg.DEFAULT_SIZE, - Blockly.WorkspaceCommentSvg.DEFAULT_SIZE); + const addWsComment = function() { + const comment = new WorkspaceCommentSvg( + ws, Msg['WORKSPACE_COMMENT_DEFAULT_TEXT'], + WorkspaceCommentSvg.DEFAULT_SIZE, + WorkspaceCommentSvg.DEFAULT_SIZE); - var injectionDiv = ws.getInjectionDiv(); + const injectionDiv = ws.getInjectionDiv(); // Bounding rect coordinates are in client coordinates, meaning that they // are in pixels relative to the upper left corner of the visible browser // window. These coordinates change when you scroll the browser window. - var boundingRect = injectionDiv.getBoundingClientRect(); + const boundingRect = injectionDiv.getBoundingClientRect(); // The client coordinates offset by the injection div's upper left corner. - var clientOffsetPixels = new Blockly.utils.Coordinate( + const clientOffsetPixels = new Coordinate( e.clientX - boundingRect.left, e.clientY - boundingRect.top); // The offset in pixels between the main workspace's origin and the upper // left corner of the injection div. - var mainOffsetPixels = ws.getOriginOffsetInPixels(); + const mainOffsetPixels = ws.getOriginOffsetInPixels(); // The position of the new comment in pixels relative to the origin of the // main workspace. - var finalOffset = Blockly.utils.Coordinate.difference(clientOffsetPixels, - mainOffsetPixels); + const finalOffset = + Coordinate.difference(clientOffsetPixels, mainOffsetPixels); // The position of the new comment in main workspace coordinates. finalOffset.scale(1 / ws.scale); - var commentX = finalOffset.x; - var commentY = finalOffset.y; + const commentX = finalOffset.x; + const commentY = finalOffset.y; comment.moveBy(commentX, commentY); if (ws.rendered) { comment.initSvg(); @@ -304,14 +336,16 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { } }; - var wsCommentOption = { + const wsCommentOption = { // Foreign objects don't work in IE. Don't let the user create comments // that they won't be able to edit. - enabled: !Blockly.utils.userAgent.IE + enabled: !userAgent.IE }; - wsCommentOption.text = Blockly.Msg['ADD_COMMENT']; + wsCommentOption.text = Msg['ADD_COMMENT']; wsCommentOption.callback = function() { addWsComment(); }; return wsCommentOption; }; +/** @package */ +exports.workspaceCommentOption = workspaceCommentOption; diff --git a/core/contextmenu_items.js b/core/contextmenu_items.js index dffd4a83d..35cb5eddc 100644 --- a/core/contextmenu_items.js +++ b/core/contextmenu_items.js @@ -10,73 +10,84 @@ */ 'use strict'; -/** - * @name Blockly.ContextMenuItems - * @namespace - */ -goog.provide('Blockly.ContextMenuItems'); +goog.module('Blockly.ContextMenuItems'); +goog.module.declareLegacyNamespace(); -/** @suppress {extraRequire} */ -goog.require('Blockly.constants'); -goog.require('Blockly.ContextMenuRegistry'); -goog.require('Blockly.Events'); -goog.require('Blockly.inputTypes'); - -goog.requireType('Blockly.BlockSvg'); +const Blockly = goog.require('Blockly'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const ContextMenuRegistry = goog.require('Blockly.ContextMenuRegistry'); +const Events = goog.require('Blockly.Events'); +const Msg = goog.require('Blockly.Msg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const clipboard = goog.require('Blockly.clipboard'); +const inputTypes = goog.require('Blockly.inputTypes'); +const userAgent = goog.require('Blockly.utils.userAgent'); +const utils = goog.require('Blockly.utils'); /** Option to undo previous action. */ -Blockly.ContextMenuItems.registerUndo = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var undoOption = { +const registerUndo = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const undoOption = { displayText: function() { - return Blockly.Msg['UNDO']; + return Msg['UNDO']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.workspace.getUndoStack().length > 0) { return 'enabled'; } return 'disabled'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { scope.workspace.undo(false); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, + scopeType: ContextMenuRegistry.ScopeType.WORKSPACE, id: 'undoWorkspace', weight: 1, }; - Blockly.ContextMenuRegistry.registry.register(undoOption); + ContextMenuRegistry.registry.register(undoOption); }; +exports.registerUndo = registerUndo; /** Option to redo previous action. */ -Blockly.ContextMenuItems.registerRedo = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var redoOption = { - displayText: function() { return Blockly.Msg['REDO']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { +const registerRedo = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const redoOption = { + displayText: function() { + return Msg['REDO']; + }, + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.workspace.getRedoStack().length > 0) { return 'enabled'; } return 'disabled'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { scope.workspace.undo(true); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, + scopeType: ContextMenuRegistry.ScopeType.WORKSPACE, id: 'redoWorkspace', weight: 2, }; - Blockly.ContextMenuRegistry.registry.register(redoOption); + ContextMenuRegistry.registry.register(redoOption); }; +exports.registerRedo = registerRedo; /** Option to clean up blocks. */ -Blockly.ContextMenuItems.registerCleanup = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var cleanOption = { +const registerCleanup = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const cleanOption = { displayText: function() { - return Blockly.Msg['CLEAN_UP']; + return Msg['CLEAN_UP']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.workspace.isMovable()) { if (scope.workspace.getTopBlocks(false).length > 1) { return 'enabled'; @@ -85,27 +96,29 @@ Blockly.ContextMenuItems.registerCleanup = function() { } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { scope.workspace.cleanUp(); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, + scopeType: ContextMenuRegistry.ScopeType.WORKSPACE, id: 'cleanWorkspace', weight: 3, }; - Blockly.ContextMenuRegistry.registry.register(cleanOption); + ContextMenuRegistry.registry.register(cleanOption); }; +exports.registerCleanup = registerCleanup; /** * Creates a callback to collapse or expand top blocks. * @param {boolean} shouldCollapse Whether a block should collapse. - * @param {!Array} topBlocks Top blocks in the workspace. + * @param {!Array} topBlocks Top blocks in the workspace. * @private */ -Blockly.ContextMenuItems.toggleOption_ = function(shouldCollapse, topBlocks) { - var DELAY = 10; - var ms = 0; - for (var i = 0; i < topBlocks.length; i++) { - var block = topBlocks[i]; +const toggleOption_ = function(shouldCollapse, topBlocks) { + const DELAY = 10; + let ms = 0; + for (let i = 0; i < topBlocks.length; i++) { + let block = topBlocks[i]; while (block) { setTimeout(block.setCollapsed.bind(block, shouldCollapse), ms); block = block.getNextBlock(); @@ -115,17 +128,18 @@ Blockly.ContextMenuItems.toggleOption_ = function(shouldCollapse, topBlocks) { }; /** Option to collapse all blocks. */ -Blockly.ContextMenuItems.registerCollapse = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var collapseOption = { - displayText: function() { - return Blockly.Msg['COLLAPSE_ALL']; +const registerCollapse = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const collapseOption = { + displayText: function() { + return Msg['COLLAPSE_ALL']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.workspace.options.collapse) { - var topBlocks = scope.workspace.getTopBlocks(false); - for (var i = 0; i < topBlocks.length; i++) { - var block = topBlocks[i]; + const topBlocks = scope.workspace.getTopBlocks(false); + for (let i = 0; i < topBlocks.length; i++) { + let block = topBlocks[i]; while (block) { if (!block.isCollapsed()) { return 'enabled'; @@ -137,28 +151,31 @@ Blockly.ContextMenuItems.registerCollapse = function() { } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - Blockly.ContextMenuItems.toggleOption_(true, scope.workspace.getTopBlocks(true)); + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + toggleOption_(true, scope.workspace.getTopBlocks(true)); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, - id: 'collapseWorkspace', - weight: 4, + scopeType: ContextMenuRegistry.ScopeType.WORKSPACE, + id: 'collapseWorkspace', + weight: 4, }; - Blockly.ContextMenuRegistry.registry.register(collapseOption); + ContextMenuRegistry.registry.register(collapseOption); }; +exports.registerCollapse = registerCollapse; /** Option to expand all blocks. */ -Blockly.ContextMenuItems.registerExpand = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var expandOption = { +const registerExpand = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const expandOption = { displayText: function() { - return Blockly.Msg['EXPAND_ALL']; + return Msg['EXPAND_ALL']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.workspace.options.collapse) { - var topBlocks = scope.workspace.getTopBlocks(false); - for (var i = 0; i < topBlocks.length; i++) { - var block = topBlocks[i]; + const topBlocks = scope.workspace.getTopBlocks(false); + for (let i = 0; i < topBlocks.length; i++) { + let block = topBlocks[i]; while (block) { if (block.isCollapsed()) { return 'enabled'; @@ -170,142 +187,151 @@ Blockly.ContextMenuItems.registerExpand = function() { } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - Blockly.ContextMenuItems.toggleOption_(false, scope.workspace.getTopBlocks(true)); + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + toggleOption_(false, scope.workspace.getTopBlocks(true)); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, + scopeType: ContextMenuRegistry.ScopeType.WORKSPACE, id: 'expandWorkspace', weight: 5, }; - Blockly.ContextMenuRegistry.registry.register(expandOption); + ContextMenuRegistry.registry.register(expandOption); }; +exports.registerExpand = registerExpand; /** * Adds a block and its children to a list of deletable blocks. - * @param {!Blockly.BlockSvg} block to delete. - * @param {!Array} deleteList list of blocks that can be deleted. This will be + * @param {!BlockSvg} block to delete. + * @param {!Array} deleteList list of blocks that can be deleted. + * This will be * modifed in place with the given block and its descendants. * @private */ -Blockly.ContextMenuItems.addDeletableBlocks_ = function(block, deleteList) { +const addDeletableBlocks_ = function(block, deleteList) { if (block.isDeletable()) { Array.prototype.push.apply(deleteList, block.getDescendants(false)); } else { - var children = /* eslint-disable-next-line indent */ - /** @type {!Array} */ (block.getChildren(false)); - for (var i = 0; i < children.length; i++) { - Blockly.ContextMenuItems.addDeletableBlocks_(children[i], deleteList); + const children = /* eslint-disable-next-line indent */ + /** @type {!Array} */ (block.getChildren(false)); + for (let i = 0; i < children.length; i++) { + addDeletableBlocks_(children[i], deleteList); } } }; /** * Constructs a list of blocks that can be deleted in the given workspace. - * @param {!Blockly.WorkspaceSvg} workspace to delete all blocks from. - * @return {!Array} list of blocks to delete. + * @param {!WorkspaceSvg} workspace to delete all blocks from. + * @return {!Array} list of blocks to delete. * @private */ -Blockly.ContextMenuItems.getDeletableBlocks_ = function(workspace) { - var deleteList = []; - var topBlocks = workspace.getTopBlocks(true); - for (var i = 0; i < topBlocks.length; i++) { - Blockly.ContextMenuItems.addDeletableBlocks_(topBlocks[i], deleteList); +const getDeletableBlocks_ = function(workspace) { + const deleteList = []; + const topBlocks = workspace.getTopBlocks(true); + for (let i = 0; i < topBlocks.length; i++) { + addDeletableBlocks_(topBlocks[i], deleteList); } return deleteList; }; -/** Deletes the given blocks. Used to delete all blocks in the workspace. - * @param {!Array} deleteList list of blocks to delete. - * @param {string} eventGroup event group ID with which all delete events should be associated. +/** + * Deletes the given blocks. Used to delete all blocks in the workspace. + * @param {!Array} deleteList list of blocks to delete. + * @param {string} eventGroup event group ID with which all delete events should + * be associated. * @private */ -Blockly.ContextMenuItems.deleteNext_ = function(deleteList, eventGroup) { - var DELAY = 10; - Blockly.Events.setGroup(eventGroup); - var block = deleteList.shift(); +const deleteNext_ = function(deleteList, eventGroup) { + const DELAY = 10; + Events.setGroup(eventGroup); + const block = deleteList.shift(); if (block) { if (block.workspace) { block.dispose(false, true); - setTimeout(Blockly.ContextMenuItems.deleteNext_, DELAY, deleteList, eventGroup); + setTimeout(deleteNext_, DELAY, deleteList, eventGroup); } else { - Blockly.ContextMenuItems.deleteNext_(deleteList, eventGroup); + deleteNext_(deleteList, eventGroup); } } - Blockly.Events.setGroup(false); + Events.setGroup(false); }; /** Option to delete all blocks. */ -Blockly.ContextMenuItems.registerDeleteAll = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var deleteOption = { - displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { +const registerDeleteAll = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const deleteOption = { + displayText: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (!scope.workspace) { return; } - var deletableBlocksLength = - Blockly.ContextMenuItems.getDeletableBlocks_(scope.workspace).length; + const deletableBlocksLength = getDeletableBlocks_(scope.workspace).length; if (deletableBlocksLength == 1) { - return Blockly.Msg['DELETE_BLOCK']; + return Msg['DELETE_BLOCK']; } else { - return Blockly.Msg['DELETE_X_BLOCKS'].replace('%1', String(deletableBlocksLength)); + return Msg['DELETE_X_BLOCKS'].replace( + '%1', String(deletableBlocksLength)); } }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (!scope.workspace) { return; } - var deletableBlocksLength = - Blockly.ContextMenuItems.getDeletableBlocks_(scope.workspace).length; + const deletableBlocksLength = getDeletableBlocks_(scope.workspace).length; return deletableBlocksLength > 0 ? 'enabled' : 'disabled'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (!scope.workspace) { return; } scope.workspace.cancelCurrentGesture(); - var deletableBlocks = Blockly.ContextMenuItems.getDeletableBlocks_(scope.workspace); - var eventGroup = Blockly.utils.genUid(); + const deletableBlocks = getDeletableBlocks_(scope.workspace); + const eventGroup = utils.genUid(); if (deletableBlocks.length < 2) { - Blockly.ContextMenuItems.deleteNext_(deletableBlocks, eventGroup); + deleteNext_(deletableBlocks, eventGroup); } else { Blockly.confirm( - Blockly.Msg['DELETE_ALL_BLOCKS'].replace('%1', deletableBlocks.length), + Msg['DELETE_ALL_BLOCKS'].replace('%1', deletableBlocks.length), function(ok) { if (ok) { - Blockly.ContextMenuItems.deleteNext_(deletableBlocks, eventGroup); + deleteNext_(deletableBlocks, eventGroup); } }); } }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, + scopeType: ContextMenuRegistry.ScopeType.WORKSPACE, id: 'workspaceDelete', weight: 6, }; - Blockly.ContextMenuRegistry.registry.register(deleteOption); + ContextMenuRegistry.registry.register(deleteOption); }; +exports.registerDeleteAll = registerDeleteAll; /** * Registers all workspace-scoped context menu items. * @private */ -Blockly.ContextMenuItems.registerWorkspaceOptions_ = function() { - Blockly.ContextMenuItems.registerUndo(); - Blockly.ContextMenuItems.registerRedo(); - Blockly.ContextMenuItems.registerCleanup(); - Blockly.ContextMenuItems.registerCollapse(); - Blockly.ContextMenuItems.registerExpand(); - Blockly.ContextMenuItems.registerDeleteAll(); +const registerWorkspaceOptions_ = function() { + registerUndo(); + registerRedo(); + registerCleanup(); + registerCollapse(); + registerExpand(); + registerDeleteAll(); }; /** Option to duplicate a block. */ -Blockly.ContextMenuItems.registerDuplicate = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var duplicateOption = { +const registerDuplicate = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const duplicateOption = { displayText: function() { - return Blockly.Msg['DUPLICATE_BLOCK']; + return Msg['DUPLICATE_BLOCK']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; if (!block.isInFlyout && block.isDeletable() && block.isMovable()) { if (block.isDuplicatable()) { return 'enabled'; @@ -314,121 +340,141 @@ Blockly.ContextMenuItems.registerDuplicate = function() { } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.block) { - Blockly.duplicate(scope.block); + clipboard.duplicate(scope.block); } }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockDuplicate', weight: 1, }; - Blockly.ContextMenuRegistry.registry.register(duplicateOption); + ContextMenuRegistry.registry.register(duplicateOption); }; +exports.registerDuplicate = registerDuplicate; /** Option to add or remove block-level comment. */ -Blockly.ContextMenuItems.registerComment = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var commentOption = { - displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { +const registerComment = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const commentOption = { + displayText: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (scope.block.getCommentIcon()) { // If there's already a comment, option is to remove. - return Blockly.Msg['REMOVE_COMMENT']; + return Msg['REMOVE_COMMENT']; } // If there's no comment yet, option is to add. - return Blockly.Msg['ADD_COMMENT']; + return Msg['ADD_COMMENT']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; // IE doesn't support necessary features for comment editing. - if (!Blockly.utils.userAgent.IE && !block.isInFlyout && block.workspace.options.comments && - !block.isCollapsed() && block.isEditable()) { + if (!userAgent.IE && !block.isInFlyout && + block.workspace.options.comments && !block.isCollapsed() && + block.isEditable()) { return 'enabled'; } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; if (block.getCommentIcon()) { block.setCommentText(null); } else { block.setCommentText(''); } }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockComment', weight: 2, }; - Blockly.ContextMenuRegistry.registry.register(commentOption); + ContextMenuRegistry.registry.register(commentOption); }; +exports.registerComment = registerComment; /** Option to inline variables. */ -Blockly.ContextMenuItems.registerInline = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var inlineOption = { - displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - return (scope.block.getInputsInline()) ? - Blockly.Msg['EXTERNAL_INPUTS'] : Blockly.Msg['INLINE_INPUTS']; +const registerInline = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const inlineOption = { + displayText: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + return (scope.block.getInputsInline()) ? Msg['EXTERNAL_INPUTS'] : + Msg['INLINE_INPUTS']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; if (!block.isInFlyout && block.isMovable() && !block.isCollapsed()) { - for (var i = 1; i < block.inputList.length; i++) { - // Only display this option if there are two value or dummy inputs next to each other. - if (block.inputList[i - 1].type != Blockly.inputTypes.STATEMENT && - block.inputList[i].type != Blockly.inputTypes.STATEMENT) { + for (let i = 1; i < block.inputList.length; i++) { + // Only display this option if there are two value or dummy inputs + // next to each other. + if (block.inputList[i - 1].type != inputTypes.STATEMENT && + block.inputList[i].type != inputTypes.STATEMENT) { return 'enabled'; } } } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { scope.block.setInputsInline(!scope.block.getInputsInline()); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockInline', weight: 3, }; - Blockly.ContextMenuRegistry.registry.register(inlineOption); + ContextMenuRegistry.registry.register(inlineOption); }; +exports.registerInline = registerInline; /** Option to collapse or expand a block. */ -Blockly.ContextMenuItems.registerCollapseExpandBlock = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var collapseExpandOption = { - displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - return scope.block.isCollapsed() ? - Blockly.Msg['EXPAND_BLOCK'] : Blockly.Msg['COLLAPSE_BLOCK']; +const registerCollapseExpandBlock = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const collapseExpandOption = { + displayText: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + return scope.block.isCollapsed() ? Msg['EXPAND_BLOCK'] : + Msg['COLLAPSE_BLOCK']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; - if (!block.isInFlyout && block.isMovable() && block.workspace.options.collapse) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; + if (!block.isInFlyout && block.isMovable() && + block.workspace.options.collapse) { return 'enabled'; } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { scope.block.setCollapsed(!scope.block.isCollapsed()); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockCollapseExpand', weight: 4, }; - Blockly.ContextMenuRegistry.registry.register(collapseExpandOption); + ContextMenuRegistry.registry.register(collapseExpandOption); }; +exports.registerCollapseExpandBlock = registerCollapseExpandBlock; /** Option to disable or enable a block. */ -Blockly.ContextMenuItems.registerDisable = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var disableOption = { - displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - return (scope.block.isEnabled()) ? - Blockly.Msg['DISABLE_BLOCK'] : Blockly.Msg['ENABLE_BLOCK']; +const registerDisable = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const disableOption = { + displayText: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + return (scope.block.isEnabled()) ? Msg['DISABLE_BLOCK'] : + Msg['ENABLE_BLOCK']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; - if (!block.isInFlyout && block.workspace.options.disable && block.isEditable()) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; + if (!block.isInFlyout && block.workspace.options.disable && + block.isEditable()) { if (block.getInheritedDisabled()) { return 'disabled'; } @@ -436,108 +482,119 @@ Blockly.ContextMenuItems.registerDisable = function() { } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; - var group = Blockly.Events.getGroup(); + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; + const group = Events.getGroup(); if (!group) { - Blockly.Events.setGroup(true); + Events.setGroup(true); } block.setEnabled(!block.isEnabled()); if (!group) { - Blockly.Events.setGroup(false); + Events.setGroup(false); } }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockDisable', weight: 5, }; - Blockly.ContextMenuRegistry.registry.register(disableOption); + ContextMenuRegistry.registry.register(disableOption); }; +exports.registerDisable = registerDisable; /** Option to delete a block. */ -Blockly.ContextMenuItems.registerDelete = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var deleteOption = { - displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; +const registerDelete = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const deleteOption = { + displayText: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; // Count the number of blocks that are nested in this block. - var descendantCount = block.getDescendants(false).length; - var nextBlock = block.getNextBlock(); + let descendantCount = block.getDescendants(false).length; + const nextBlock = block.getNextBlock(); if (nextBlock) { // Blocks in the current stack would survive this block's deletion. descendantCount -= nextBlock.getDescendants(false).length; } - return (descendantCount == 1) ? Blockly.Msg['DELETE_BLOCK'] : - Blockly.Msg['DELETE_X_BLOCKS'].replace('%1', String(descendantCount)); + return (descendantCount == 1) ? + Msg['DELETE_BLOCK'] : + Msg['DELETE_X_BLOCKS'].replace('%1', String(descendantCount)); }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { if (!scope.block.isInFlyout && scope.block.isDeletable()) { return 'enabled'; } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - Blockly.Events.setGroup(true); + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + Events.setGroup(true); if (scope.block) { Blockly.deleteBlock(scope.block); } - Blockly.Events.setGroup(false); + Events.setGroup(false); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockDelete', weight: 6, }; - Blockly.ContextMenuRegistry.registry.register(deleteOption); + ContextMenuRegistry.registry.register(deleteOption); }; +exports.registerDelete = registerDelete; /** Option to open help for a block. */ -Blockly.ContextMenuItems.registerHelp = function() { - /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */ - var helpOption = { +const registerHelp = function() { + /** @type {!ContextMenuRegistry.RegistryItem} */ + const helpOption = { displayText: function() { - return Blockly.Msg['HELP']; + return Msg['HELP']; }, - preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { - var block = scope.block; - var url = (typeof block.helpUrl == 'function') ? - block.helpUrl() : block.helpUrl; + preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { + const block = scope.block; + const url = (typeof block.helpUrl == 'function') ? block.helpUrl() : + block.helpUrl; if (url) { return 'enabled'; } return 'hidden'; }, - callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) { + callback: function(/** @type {!ContextMenuRegistry.Scope} */ + scope) { scope.block.showHelp(); }, - scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, + scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockHelp', weight: 7, }; - Blockly.ContextMenuRegistry.registry.register(helpOption); + ContextMenuRegistry.registry.register(helpOption); }; +exports.registerHelp = registerHelp; /** * Registers all block-scoped context menu items. * @private */ -Blockly.ContextMenuItems.registerBlockOptions_ = function() { - Blockly.ContextMenuItems.registerDuplicate(); - Blockly.ContextMenuItems.registerComment(); - Blockly.ContextMenuItems.registerInline(); - Blockly.ContextMenuItems.registerCollapseExpandBlock(); - Blockly.ContextMenuItems.registerDisable(); - Blockly.ContextMenuItems.registerDelete(); - Blockly.ContextMenuItems.registerHelp(); +const registerBlockOptions_ = function() { + registerDuplicate(); + registerComment(); + registerInline(); + registerCollapseExpandBlock(); + registerDisable(); + registerDelete(); + registerHelp(); }; /** - * Registers all default context menu items. This should be called once per instance of - * ContextMenuRegistry. + * Registers all default context menu items. This should be called once per + * instance of ContextMenuRegistry. * @package */ -Blockly.ContextMenuItems.registerDefaultOptions = function() { - Blockly.ContextMenuItems.registerWorkspaceOptions_(); - Blockly.ContextMenuItems.registerBlockOptions_(); +const registerDefaultOptions = function() { + registerWorkspaceOptions_(); + registerBlockOptions_(); }; +exports.registerDefaultOptions = registerDefaultOptions; -Blockly.ContextMenuItems.registerDefaultOptions(); +registerDefaultOptions(); diff --git a/core/contextmenu_registry.js b/core/contextmenu_registry.js index 38cf08d3c..a97dc30f4 100644 --- a/core/contextmenu_registry.js +++ b/core/contextmenu_registry.js @@ -11,91 +11,97 @@ 'use strict'; /** - * @name Blockly.ContextMenuRegistry + * @name ContextMenuRegistry * @namespace */ -goog.provide('Blockly.ContextMenuRegistry'); +goog.module('Blockly.ContextMenuRegistry'); +goog.module.declareLegacyNamespace(); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); /** * Class for the registry of context menu items. This is intended to be a * singleton. You should not create a new instance, and only access this class - * from Blockly.ContextMenuRegistry.registry. + * from ContextMenuRegistry.registry. * @constructor + * @private */ -Blockly.ContextMenuRegistry = function() { +const ContextMenuRegistry = function() { // Singleton instance should be registered once. - Blockly.ContextMenuRegistry.registry = this; + ContextMenuRegistry.registry = this; /** * Registry of all registered RegistryItems, keyed by ID. - * @type {!Object} + * @type {!Object} * @private */ this.registry_ = Object.create(null); }; /** - * Where this menu item should be rendered. If the menu item should be rendered in multiple - * scopes, e.g. on both a block and a workspace, it should be registered for each scope. + * Where this menu item should be rendered. If the menu item should be rendered + * in multiple scopes, e.g. on both a block and a workspace, it should be + * registered for each scope. * @enum {string} */ -Blockly.ContextMenuRegistry.ScopeType = { +ContextMenuRegistry.ScopeType = { BLOCK: 'block', WORKSPACE: 'workspace', }; /** - * The actual workspace/block where the menu is being rendered. This is passed to callback and - * displayText functions that depend on this information. + * The actual workspace/block where the menu is being rendered. This is passed + * to callback and displayText functions that depend on this information. * @typedef {{ - * block: (Blockly.BlockSvg|undefined), - * workspace: (Blockly.WorkspaceSvg|undefined) + * block: (BlockSvg|undefined), + * workspace: (WorkspaceSvg|undefined) * }} */ -Blockly.ContextMenuRegistry.Scope; +ContextMenuRegistry.Scope; /** * A menu item as entered in the registry. * @typedef {{ - * callback: function(!Blockly.ContextMenuRegistry.Scope), - * scopeType: !Blockly.ContextMenuRegistry.ScopeType, - * displayText: ((function(!Blockly.ContextMenuRegistry.Scope):string)|string), - * preconditionFn: function(!Blockly.ContextMenuRegistry.Scope):string, + * callback: function(!ContextMenuRegistry.Scope), + * scopeType: !ContextMenuRegistry.ScopeType, + * displayText: ((function(!ContextMenuRegistry.Scope):string)|string), + * preconditionFn: function(!ContextMenuRegistry.Scope):string, * weight: number, * id: string * }} -*/ -Blockly.ContextMenuRegistry.RegistryItem; + */ +ContextMenuRegistry.RegistryItem; /** * A menu item as presented to contextmenu.js. * @typedef {{ * text: string, * enabled: boolean, - * callback: function(!Blockly.ContextMenuRegistry.Scope), - * scope: !Blockly.ContextMenuRegistry.Scope, + * callback: function(!ContextMenuRegistry.Scope), + * scope: !ContextMenuRegistry.Scope, * weight: number * }} */ -Blockly.ContextMenuRegistry.ContextMenuOption; +ContextMenuRegistry.ContextMenuOption; /** * Singleton instance of this class. All interactions with this class should be * done on this object. - * @type {?Blockly.ContextMenuRegistry} + * @type {?ContextMenuRegistry} */ -Blockly.ContextMenuRegistry.registry = null; +ContextMenuRegistry.registry = null; /** * Registers a RegistryItem. - * @param {!Blockly.ContextMenuRegistry.RegistryItem} item Context menu item to register. + * @param {!ContextMenuRegistry.RegistryItem} item Context menu item to + * register. * @throws {Error} if an item with the given ID already exists. */ -Blockly.ContextMenuRegistry.prototype.register = function(item) { +ContextMenuRegistry.prototype.register = function(item) { if (this.registry_[item.id]) { throw Error('Menu item with ID "' + item.id + '" is already registered.'); } @@ -107,7 +113,7 @@ Blockly.ContextMenuRegistry.prototype.register = function(item) { * @param {string} id The ID of the RegistryItem to remove. * @throws {Error} if an item with the given ID does not exist. */ -Blockly.ContextMenuRegistry.prototype.unregister = function(id) { +ContextMenuRegistry.prototype.unregister = function(id) { if (!this.registry_[id]) { throw new Error('Menu item with ID "' + id + '" not found.'); } @@ -116,33 +122,37 @@ Blockly.ContextMenuRegistry.prototype.unregister = function(id) { /** * @param {string} id The ID of the RegistryItem to get. - * @return {?Blockly.ContextMenuRegistry.RegistryItem} RegistryItem or null if not found + * @return {?ContextMenuRegistry.RegistryItem} RegistryItem or null if not found */ -Blockly.ContextMenuRegistry.prototype.getItem = function(id) { +ContextMenuRegistry.prototype.getItem = function(id) { return this.registry_[id] || null; }; /** - * Gets the valid context menu options for the given scope type (e.g. block or workspace) and scope. - * Blocks are only shown if the preconditionFn shows they should not be hidden. - * @param {!Blockly.ContextMenuRegistry.ScopeType} scopeType Type of scope where menu should be - * shown (e.g. on a block or on a workspace) - * @param {!Blockly.ContextMenuRegistry.Scope} scope Current scope of context menu + * Gets the valid context menu options for the given scope type (e.g. block or + * workspace) and scope. Blocks are only shown if the preconditionFn shows they + * should not be hidden. + * @param {!ContextMenuRegistry.ScopeType} scopeType Type of scope where menu + * should be shown (e.g. on a block or on a workspace) + * @param {!ContextMenuRegistry.Scope} scope Current scope of context menu * (i.e., the exact workspace or block being clicked on) - * @return {!Array} the list of ContextMenuOptions + * @return {!Array} the list of + * ContextMenuOptions */ -Blockly.ContextMenuRegistry.prototype.getContextMenuOptions = function(scopeType, scope) { - var menuOptions = []; - var registry = this.registry_; +ContextMenuRegistry.prototype.getContextMenuOptions = function( + scopeType, scope) { + const menuOptions = []; + const registry = this.registry_; Object.keys(registry).forEach(function(id) { - var item = registry[id]; + const item = registry[id]; if (scopeType == item.scopeType) { - var precondition = item.preconditionFn(scope); + const precondition = item.preconditionFn(scope); if (precondition != 'hidden') { - var displayText = typeof item.displayText == 'function' ? - item.displayText(scope) : item.displayText; - /** @type {!Blockly.ContextMenuRegistry.ContextMenuOption} */ - var menuOption = { + const displayText = typeof item.displayText == 'function' ? + item.displayText(scope) : + item.displayText; + /** @type {!ContextMenuRegistry.ContextMenuOption} */ + const menuOption = { text: displayText, enabled: (precondition == 'enabled'), callback: item.callback, @@ -160,4 +170,6 @@ Blockly.ContextMenuRegistry.prototype.getContextMenuOptions = function(scopeType }; // Creates and assigns the singleton instance. -new Blockly.ContextMenuRegistry(); +new ContextMenuRegistry(); + +exports = ContextMenuRegistry; diff --git a/core/delete_area.js b/core/delete_area.js index 55eb61a34..6dbe50db6 100644 --- a/core/delete_area.js +++ b/core/delete_area.js @@ -18,10 +18,10 @@ goog.module.declareLegacyNamespace(); const BlockSvg = goog.require('Blockly.BlockSvg'); const DragTarget = goog.require('Blockly.DragTarget'); /* eslint-disable-next-line no-unused-vars */ -const IDeleteArea = goog.require('Blockly.IDeleteArea'); +const IDeleteArea = goog.requireType('Blockly.IDeleteArea'); /* eslint-disable-next-line no-unused-vars */ const IDraggable = goog.requireType('Blockly.IDraggable'); -const {inherits} = goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); /** * Abstract class for a component that can delete a block or bubble that is @@ -42,7 +42,7 @@ const DeleteArea = function() { */ this.wouldDelete_ = false; }; -inherits(DeleteArea, DragTarget); +object.inherits(DeleteArea, DragTarget); /** * Returns whether the provided block or bubble would be deleted if dropped on diff --git a/core/drag_target.js b/core/drag_target.js index 18e29b40a..e5a0f578b 100644 --- a/core/drag_target.js +++ b/core/drag_target.js @@ -16,7 +16,7 @@ goog.module('Blockly.DragTarget'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IDragTarget = goog.require('Blockly.IDragTarget'); +const IDragTarget = goog.requireType('Blockly.IDragTarget'); /* eslint-disable-next-line no-unused-vars */ const IDraggable = goog.requireType('Blockly.IDraggable'); /* eslint-disable-next-line no-unused-vars */ diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 68698371e..5ebb22a5e 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -15,6 +15,7 @@ goog.provide('Blockly.DropDownDiv'); +goog.require('Blockly.common'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); goog.require('Blockly.utils.Rect'); @@ -162,7 +163,7 @@ Blockly.DropDownDiv.createDom = function() { } var div = document.createElement('div'); div.className = 'blocklyDropDownDiv'; - var container = Blockly.parentContainer || document.body; + var container = Blockly.common.getParentContainer() || document.body; container.appendChild(div); /** * The div element. @@ -381,7 +382,7 @@ Blockly.DropDownDiv.show = function(owner, rtl, primaryX, primaryY, div.style.direction = rtl ? 'rtl' : 'ltr'; var mainWorkspace = - /** @type {!Blockly.WorkspaceSvg} */ (Blockly.getMainWorkspace()); + /** @type {!Blockly.WorkspaceSvg} */ (Blockly.common.getMainWorkspace()); Blockly.DropDownDiv.rendererClassName_ = mainWorkspace.getRenderer().getClassName(); Blockly.DropDownDiv.themeClassName_ = mainWorkspace.getTheme().getClassName(); @@ -694,7 +695,7 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { Blockly.DropDownDiv.themeClassName_ = ''; } (/** @type {!Blockly.WorkspaceSvg} */ ( - Blockly.getMainWorkspace())).markFocused(); + Blockly.common.getMainWorkspace())).markFocused(); }; /** diff --git a/core/events/block_events.js b/core/events/block_events.js deleted file mode 100644 index 8be1dae30..000000000 --- a/core/events/block_events.js +++ /dev/null @@ -1,573 +0,0 @@ -/** - * @license - * Copyright 2018 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Classes for all types of block events. - * @author fenichel@google.com (Rachel Fenichel) - */ -'use strict'; - -goog.provide('Blockly.Events.BlockBase'); -goog.provide('Blockly.Events.BlockChange'); -goog.provide('Blockly.Events.BlockCreate'); -goog.provide('Blockly.Events.BlockDelete'); -goog.provide('Blockly.Events.BlockMove'); -goog.provide('Blockly.Events.Change'); // Deprecated. -goog.provide('Blockly.Events.Create'); // Deprecated. -goog.provide('Blockly.Events.Delete'); // Deprecated. -goog.provide('Blockly.Events.Move'); // Deprecated. - -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.Abstract'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.xml'); -goog.require('Blockly.Xml'); - -goog.requireType('Blockly.Block'); - - -/** - * Abstract class for a block event. - * @param {!Blockly.Block=} opt_block The block this event corresponds to. - * Undefined for a blank event. - * @extends {Blockly.Events.Abstract} - * @constructor - */ -Blockly.Events.BlockBase = function(opt_block) { - Blockly.Events.BlockBase.superClass_.constructor.call(this); - this.isBlank = typeof opt_block == 'undefined'; - - /** - * The block ID for the block this event pertains to - * @type {string} - */ - this.blockId = this.isBlank ? '' : opt_block.id; - - /** - * The workspace identifier for this event. - * @type {string} - */ - this.workspaceId = this.isBlank ? '' : opt_block.workspace.id; -}; -Blockly.utils.object.inherits(Blockly.Events.BlockBase, - Blockly.Events.Abstract); - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.BlockBase.prototype.toJson = function() { - var json = Blockly.Events.BlockBase.superClass_.toJson.call(this); - json['blockId'] = this.blockId; - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.BlockBase.prototype.fromJson = function(json) { - Blockly.Events.BlockBase.superClass_.fromJson.call(this, json); - this.blockId = json['blockId']; -}; - -/** - * Class for a block change event. - * @param {!Blockly.Block=} opt_block The changed block. Undefined for a blank - * event. - * @param {string=} opt_element One of 'field', 'comment', 'disabled', etc. - * @param {?string=} opt_name Name of input or field affected, or null. - * @param {*=} opt_oldValue Previous value of element. - * @param {*=} opt_newValue New value of element. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.BlockChange = function(opt_block, opt_element, opt_name, opt_oldValue, - opt_newValue) { - Blockly.Events.Change.superClass_.constructor.call(this, opt_block); - if (!opt_block) { - return; // Blank event to be populated by fromJson. - } - this.element = typeof opt_element == 'undefined' ? '' : opt_element; - this.name = typeof opt_name == 'undefined' ? '' : opt_name; - this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue; - this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue; -}; -Blockly.utils.object.inherits(Blockly.Events.BlockChange, Blockly.Events.BlockBase); - -/** - * Class for a block change event. - * @param {!Blockly.Block=} opt_block The changed block. Undefined for a blank - * event. - * @param {string=} opt_element One of 'field', 'comment', 'disabled', etc. - * @param {?string=} opt_name Name of input or field affected, or null. - * @param {*=} opt_oldValue Previous value of element. - * @param {*=} opt_newValue New value of element. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.Change = Blockly.Events.BlockChange; - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.BlockChange.prototype.type = Blockly.Events.CHANGE; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.BlockChange.prototype.toJson = function() { - var json = Blockly.Events.BlockChange.superClass_.toJson.call(this); - json['element'] = this.element; - if (this.name) { - json['name'] = this.name; - } - json['oldValue'] = this.oldValue; - json['newValue'] = this.newValue; - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.BlockChange.prototype.fromJson = function(json) { - Blockly.Events.BlockChange.superClass_.fromJson.call(this, json); - this.element = json['element']; - this.name = json['name']; - this.oldValue = json['oldValue']; - this.newValue = json['newValue']; -}; - -/** - * Does this event record any change of state? - * @return {boolean} False if something changed. - */ -Blockly.Events.BlockChange.prototype.isNull = function() { - return this.oldValue == this.newValue; -}; - -/** - * Run a change event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.BlockChange.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - var block = workspace.getBlockById(this.blockId); - if (!block) { - console.warn("Can't change non-existent block: " + this.blockId); - return; - } - if (block.mutator) { - // Close the mutator (if open) since we don't want to update it. - block.mutator.setVisible(false); - } - var value = forward ? this.newValue : this.oldValue; - switch (this.element) { - case 'field': - var field = block.getField(this.name); - if (field) { - field.setValue(value); - } else { - console.warn("Can't set non-existent field: " + this.name); - } - break; - case 'comment': - block.setCommentText(/** @type {string} */ (value) || null); - break; - case 'collapsed': - block.setCollapsed(!!value); - break; - case 'disabled': - block.setEnabled(!value); - break; - case 'inline': - block.setInputsInline(!!value); - break; - case 'mutation': - var oldMutation = ''; - if (block.mutationToDom) { - var oldMutationDom = block.mutationToDom(); - oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); - } - if (block.domToMutation) { - var dom = Blockly.Xml.textToDom(/** @type {string} */ (value) || ''); - block.domToMutation(dom); - } - Blockly.Events.fire(new Blockly.Events.BlockChange( - block, 'mutation', null, oldMutation, value)); - break; - default: - console.warn('Unknown change type: ' + this.element); - } -}; - -/** - * Class for a block creation event. - * @param {!Blockly.Block=} opt_block The created block. Undefined for a blank - * event. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.Create = function(opt_block) { - Blockly.Events.Create.superClass_.constructor.call(this, opt_block); - if (!opt_block) { - return; // Blank event to be populated by fromJson. - } - if (opt_block.isShadow()) { - // Moving shadow blocks is handled via disconnection. - this.recordUndo = false; - } - - if (opt_block.workspace.rendered) { - this.xml = Blockly.Xml.blockToDomWithXY(opt_block); - } else { - this.xml = Blockly.Xml.blockToDom(opt_block); - } - this.ids = Blockly.Events.getDescendantIds(opt_block); -}; -Blockly.utils.object.inherits(Blockly.Events.Create, Blockly.Events.BlockBase); - -/** - * Class for a block creation event. - * @param {!Blockly.Block=} block The created block. Undefined for a blank - * event. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.BlockCreate = Blockly.Events.Create; - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.Create.prototype.type = Blockly.Events.CREATE; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.Create.prototype.toJson = function() { - var json = Blockly.Events.Create.superClass_.toJson.call(this); - json['xml'] = Blockly.Xml.domToText(this.xml); - json['ids'] = this.ids; - if (!this.recordUndo) { - json['recordUndo'] = this.recordUndo; - } - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.Create.prototype.fromJson = function(json) { - Blockly.Events.Create.superClass_.fromJson.call(this, json); - this.xml = Blockly.Xml.textToDom(json['xml']); - this.ids = json['ids']; - if (json['recordUndo'] !== undefined) { - this.recordUndo = json['recordUndo']; - } -}; - -/** - * Run a creation event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.Create.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - if (forward) { - var xml = Blockly.utils.xml.createElement('xml'); - xml.appendChild(this.xml); - Blockly.Xml.domToWorkspace(xml, workspace); - } else { - for (var i = 0, id; (id = this.ids[i]); i++) { - var block = workspace.getBlockById(id); - if (block) { - block.dispose(false); - } else if (id == this.blockId) { - // Only complain about root-level block. - console.warn("Can't uncreate non-existent block: " + id); - } - } - } -}; - -/** - * Class for a block deletion event. - * @param {!Blockly.Block=} opt_block The deleted block. Undefined for a blank - * event. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.Delete = function(opt_block) { - Blockly.Events.Delete.superClass_.constructor.call(this, opt_block); - if (!opt_block) { - return; // Blank event to be populated by fromJson. - } - if (opt_block.getParent()) { - throw Error('Connected blocks cannot be deleted.'); - } - if (opt_block.isShadow()) { - // Respawning shadow blocks is handled via disconnection. - this.recordUndo = false; - } - - if (opt_block.workspace.rendered) { - this.oldXml = Blockly.Xml.blockToDomWithXY(opt_block); - } else { - this.oldXml = Blockly.Xml.blockToDom(opt_block); - } - this.ids = Blockly.Events.getDescendantIds(opt_block); -}; -Blockly.utils.object.inherits(Blockly.Events.Delete, Blockly.Events.BlockBase); - -/** - * Class for a block deletion event. - * @param {?Blockly.Block} block The deleted block. Null for a blank event. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.BlockDelete = Blockly.Events.Delete; - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.Delete.prototype.type = Blockly.Events.DELETE; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.Delete.prototype.toJson = function() { - var json = Blockly.Events.Delete.superClass_.toJson.call(this); - json['oldXml'] = Blockly.Xml.domToText(this.oldXml); - json['ids'] = this.ids; - if (!this.recordUndo) { - json['recordUndo'] = this.recordUndo; - } - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.Delete.prototype.fromJson = function(json) { - Blockly.Events.Delete.superClass_.fromJson.call(this, json); - this.oldXml = Blockly.Xml.textToDom(json['oldXml']); - this.ids = json['ids']; - if (json['recordUndo'] !== undefined) { - this.recordUndo = json['recordUndo']; - } -}; - -/** - * Run a deletion event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.Delete.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - if (forward) { - for (var i = 0, id; (id = this.ids[i]); i++) { - var block = workspace.getBlockById(id); - if (block) { - block.dispose(false); - } else if (id == this.blockId) { - // Only complain about root-level block. - console.warn("Can't delete non-existent block: " + id); - } - } - } else { - var xml = Blockly.utils.xml.createElement('xml'); - xml.appendChild(this.oldXml); - Blockly.Xml.domToWorkspace(xml, workspace); - } -}; - -/** - * Class for a block move event. Created before the move. - * @param {!Blockly.Block=} opt_block The moved block. Undefined for a blank - * event. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.Move = function(opt_block) { - Blockly.Events.Move.superClass_.constructor.call(this, opt_block); - if (!opt_block) { - return; // Blank event to be populated by fromJson. - } - if (opt_block.isShadow()) { - // Moving shadow blocks is handled via disconnection. - this.recordUndo = false; - } - - var location = this.currentLocation_(); - this.oldParentId = location.parentId; - this.oldInputName = location.inputName; - this.oldCoordinate = location.coordinate; -}; -Blockly.utils.object.inherits(Blockly.Events.Move, Blockly.Events.BlockBase); - -/** - * Class for a block move event. Created before the move. - * @param {?Blockly.Block} block The moved block. Null for a blank event. - * @extends {Blockly.Events.BlockBase} - * @constructor - */ -Blockly.Events.BlockMove = Blockly.Events.Move; - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.Move.prototype.type = Blockly.Events.MOVE; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.Move.prototype.toJson = function() { - var json = Blockly.Events.Move.superClass_.toJson.call(this); - if (this.newParentId) { - json['newParentId'] = this.newParentId; - } - if (this.newInputName) { - json['newInputName'] = this.newInputName; - } - if (this.newCoordinate) { - json['newCoordinate'] = Math.round(this.newCoordinate.x) + ',' + - Math.round(this.newCoordinate.y); - } - if (!this.recordUndo) { - json['recordUndo'] = this.recordUndo; - } - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.Move.prototype.fromJson = function(json) { - Blockly.Events.Move.superClass_.fromJson.call(this, json); - this.newParentId = json['newParentId']; - this.newInputName = json['newInputName']; - if (json['newCoordinate']) { - var xy = json['newCoordinate'].split(','); - this.newCoordinate = - new Blockly.utils.Coordinate(Number(xy[0]), Number(xy[1])); - } - if (json['recordUndo'] !== undefined) { - this.recordUndo = json['recordUndo']; - } -}; - -/** - * Record the block's new location. Called after the move. - */ -Blockly.Events.Move.prototype.recordNew = function() { - var location = this.currentLocation_(); - this.newParentId = location.parentId; - this.newInputName = location.inputName; - this.newCoordinate = location.coordinate; -}; - -/** - * Returns the parentId and input if the block is connected, - * or the XY location if disconnected. - * @return {!Object} Collection of location info. - * @private - */ -Blockly.Events.Move.prototype.currentLocation_ = function() { - var workspace = this.getEventWorkspace_(); - var block = workspace.getBlockById(this.blockId); - var location = {}; - var parent = block.getParent(); - if (parent) { - location.parentId = parent.id; - var input = parent.getInputWithBlock(block); - if (input) { - location.inputName = input.name; - } - } else { - location.coordinate = block.getRelativeToSurfaceXY(); - } - return location; -}; - -/** - * Does this event record any change of state? - * @return {boolean} False if something changed. - */ -Blockly.Events.Move.prototype.isNull = function() { - return this.oldParentId == this.newParentId && - this.oldInputName == this.newInputName && - Blockly.utils.Coordinate.equals(this.oldCoordinate, this.newCoordinate); -}; - -/** - * Run a move event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.Move.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - var block = workspace.getBlockById(this.blockId); - if (!block) { - console.warn("Can't move non-existent block: " + this.blockId); - return; - } - var parentId = forward ? this.newParentId : this.oldParentId; - var inputName = forward ? this.newInputName : this.oldInputName; - var coordinate = forward ? this.newCoordinate : this.oldCoordinate; - var parentBlock = null; - if (parentId) { - parentBlock = workspace.getBlockById(parentId); - if (!parentBlock) { - console.warn("Can't connect to non-existent block: " + parentId); - return; - } - } - if (block.getParent()) { - block.unplug(); - } - if (coordinate) { - var xy = block.getRelativeToSurfaceXY(); - block.moveBy(coordinate.x - xy.x, coordinate.y - xy.y); - } else { - var blockConnection = block.outputConnection || block.previousConnection; - var parentConnection; - var connectionType = blockConnection.type; - if (inputName) { - var input = parentBlock.getInput(inputName); - if (input) { - parentConnection = input.connection; - } - } else if (connectionType == Blockly.connectionTypes.PREVIOUS_STATEMENT) { - parentConnection = parentBlock.nextConnection; - } - if (parentConnection) { - blockConnection.connect(parentConnection); - } else { - console.warn("Can't connect to non-existent input: " + inputName); - } - } -}; - -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CREATE, - Blockly.Events.Create); -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.DELETE, - Blockly.Events.Delete); -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CHANGE, - Blockly.Events.BlockChange); -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.MOVE, - Blockly.Events.Move); diff --git a/core/events/events_abstract.js b/core/events/events_abstract.js index 719f6d937..9a14e82b2 100644 --- a/core/events/events_abstract.js +++ b/core/events/events_abstract.js @@ -11,19 +11,19 @@ */ 'use strict'; -goog.provide('Blockly.Events.Abstract'); +goog.module('Blockly.Events.Abstract'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); - -goog.requireType('Blockly.Workspace'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); /** * Abstract class for an event. * @constructor */ -Blockly.Events.Abstract = function() { - +const Abstract = function() { /** * Whether or not the event is blank (to be populated by fromJson). * @type {?boolean} @@ -42,29 +42,27 @@ Blockly.Events.Abstract = function() { * perspective, and should be undone together. * @type {string} */ - this.group = Blockly.Events.getGroup(); + this.group = Events.getGroup(); /** * Sets whether the event should be added to the undo stack. * @type {boolean} */ - this.recordUndo = Blockly.Events.recordUndo; + this.recordUndo = Events.recordUndo; }; /** * Whether or not the event is a UI event. * @type {boolean} */ -Blockly.Events.Abstract.prototype.isUiEvent = false; +Abstract.prototype.isUiEvent = false; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.Abstract.prototype.toJson = function() { - var json = { - 'type': this.type - }; +Abstract.prototype.toJson = function() { + const json = {'type': this.type}; if (this.group) { json['group'] = this.group; } @@ -75,7 +73,7 @@ Blockly.Events.Abstract.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.Abstract.prototype.fromJson = function(json) { +Abstract.prototype.fromJson = function(json) { this.isBlank = false; this.group = json['group']; }; @@ -84,7 +82,7 @@ Blockly.Events.Abstract.prototype.fromJson = function(json) { * Does this event record any change of state? * @return {boolean} True if null, false if something changed. */ -Blockly.Events.Abstract.prototype.isNull = function() { +Abstract.prototype.isNull = function() { return false; }; @@ -92,23 +90,27 @@ Blockly.Events.Abstract.prototype.isNull = function() { * Run an event. * @param {boolean} _forward True if run forward, false if run backward (undo). */ -Blockly.Events.Abstract.prototype.run = function(_forward) { +Abstract.prototype.run = function(_forward) { // Defined by subclasses. }; /** * Get workspace the event belongs to. - * @return {!Blockly.Workspace} The workspace the event belongs to. + * @return {!Workspace} The workspace the event belongs to. * @throws {Error} if workspace is null. * @protected */ -Blockly.Events.Abstract.prototype.getEventWorkspace_ = function() { +Abstract.prototype.getEventWorkspace_ = function() { + let workspace; if (this.workspaceId) { - var workspace = Blockly.Workspace.getById(this.workspaceId); + workspace = goog.module.get('Blockly.Workspace').getById(this.workspaceId); } if (!workspace) { - throw Error('Workspace is null. Event must have been generated from real' + + throw Error( + 'Workspace is null. Event must have been generated from real' + ' Blockly events.'); } return workspace; }; + +exports = Abstract; diff --git a/core/events/events_block_base.js b/core/events/events_block_base.js new file mode 100644 index 000000000..1f22a4ed8 --- /dev/null +++ b/core/events/events_block_base.js @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Base class for all types of block events. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.BlockBase'); +goog.module.declareLegacyNamespace(); + +const Abstract = goog.require('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const object = goog.require('Blockly.utils.object'); + + +/** + * Abstract class for a block event. + * @param {!Block=} opt_block The block this event corresponds to. + * Undefined for a blank event. + * @extends {Abstract} + * @constructor + */ +const BlockBase = function(opt_block) { + BlockBase.superClass_.constructor.call(this); + this.isBlank = typeof opt_block == 'undefined'; + + /** + * The block ID for the block this event pertains to + * @type {string} + */ + this.blockId = this.isBlank ? '' : opt_block.id; + + /** + * The workspace identifier for this event. + * @type {string} + */ + this.workspaceId = this.isBlank ? '' : opt_block.workspace.id; +}; +object.inherits(BlockBase, Abstract); + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +BlockBase.prototype.toJson = function() { + const json = BlockBase.superClass_.toJson.call(this); + json['blockId'] = this.blockId; + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +BlockBase.prototype.fromJson = function(json) { + BlockBase.superClass_.fromJson.call(this, json); + this.blockId = json['blockId']; +}; + +exports = BlockBase; diff --git a/core/events/events_block_change.js b/core/events/events_block_change.js new file mode 100644 index 000000000..3814a0d27 --- /dev/null +++ b/core/events/events_block_change.js @@ -0,0 +1,148 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class for a block change event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.BlockChange'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +const Xml = goog.require('Blockly.Xml'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); + + +/** + * Class for a block change event. + * @param {!Block=} opt_block The changed block. Undefined for a blank + * event. + * @param {string=} opt_element One of 'field', 'comment', 'disabled', etc. + * @param {?string=} opt_name Name of input or field affected, or null. + * @param {*=} opt_oldValue Previous value of element. + * @param {*=} opt_newValue New value of element. + * @extends {Events.BlockBase} + * @constructor + */ +const BlockChange = function( + opt_block, opt_element, opt_name, opt_oldValue, opt_newValue) { + BlockChange.superClass_.constructor.call(this, opt_block); + if (!opt_block) { + return; // Blank event to be populated by fromJson. + } + this.element = typeof opt_element == 'undefined' ? '' : opt_element; + this.name = typeof opt_name == 'undefined' ? '' : opt_name; + this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue; + this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue; +}; +object.inherits(BlockChange, Events.BlockBase); + +/** + * Type of this event. + * @type {string} + */ +BlockChange.prototype.type = Events.BLOCK_CHANGE; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +BlockChange.prototype.toJson = function() { + const json = BlockChange.superClass_.toJson.call(this); + json['element'] = this.element; + if (this.name) { + json['name'] = this.name; + } + json['oldValue'] = this.oldValue; + json['newValue'] = this.newValue; + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +BlockChange.prototype.fromJson = function(json) { + BlockChange.superClass_.fromJson.call(this, json); + this.element = json['element']; + this.name = json['name']; + this.oldValue = json['oldValue']; + this.newValue = json['newValue']; +}; + +/** + * Does this event record any change of state? + * @return {boolean} False if something changed. + */ +BlockChange.prototype.isNull = function() { + return this.oldValue == this.newValue; +}; + +/** + * Run a change event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +BlockChange.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + const block = workspace.getBlockById(this.blockId); + if (!block) { + console.warn('Can\'t change non-existent block: ' + this.blockId); + return; + } + if (block.mutator) { + // Close the mutator (if open) since we don't want to update it. + block.mutator.setVisible(false); + } + const value = forward ? this.newValue : this.oldValue; + switch (this.element) { + case 'field': { + const field = block.getField(this.name); + if (field) { + field.setValue(value); + } else { + console.warn('Can\'t set non-existent field: ' + this.name); + } + break; + } + case 'comment': + block.setCommentText(/** @type {string} */ (value) || null); + break; + case 'collapsed': + block.setCollapsed(!!value); + break; + case 'disabled': + block.setEnabled(!value); + break; + case 'inline': + block.setInputsInline(!!value); + break; + case 'mutation': { + let oldMutation = ''; + if (block.mutationToDom) { + const oldMutationDom = block.mutationToDom(); + oldMutation = oldMutationDom && Xml.domToText(oldMutationDom); + } + if (block.domToMutation) { + const dom = Xml.textToDom(/** @type {string} */ + (value) || ''); + block.domToMutation(dom); + } + Events.fire(new BlockChange(block, 'mutation', null, oldMutation, value)); + break; + } + default: + console.warn('Unknown change type: ' + this.element); + } +}; + +registry.register(registry.Type.EVENT, Events.CHANGE, BlockChange); + +exports = BlockChange; diff --git a/core/events/events_block_create.js b/core/events/events_block_create.js new file mode 100644 index 000000000..2a6afb003 --- /dev/null +++ b/core/events/events_block_create.js @@ -0,0 +1,111 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class for a block creation event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.BlockCreate'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const BlockBase = goog.require('Blockly.Events.BlockBase'); +const Events = goog.require('Blockly.Events'); +const Xml = goog.require('Blockly.Xml'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); +const xml = goog.require('Blockly.utils.xml'); + + +/** + * Class for a block creation event. + * @param {!Block=} opt_block The created block. Undefined for a blank + * event. + * @extends {BlockBase} + * @constructor + */ +const BlockCreate = function(opt_block) { + BlockCreate.superClass_.constructor.call(this, opt_block); + if (!opt_block) { + return; // Blank event to be populated by fromJson. + } + if (opt_block.isShadow()) { + // Moving shadow blocks is handled via disconnection. + this.recordUndo = false; + } + + if (opt_block.workspace.rendered) { + this.xml = Xml.blockToDomWithXY(opt_block); + } else { + this.xml = Xml.blockToDom(opt_block); + } + this.ids = Events.getDescendantIds(opt_block); +}; +object.inherits(BlockCreate, BlockBase); + +/** + * Type of this event. + * @type {string} + */ +BlockCreate.prototype.type = Events.BLOCK_CREATE; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +BlockCreate.prototype.toJson = function() { + const json = BlockCreate.superClass_.toJson.call(this); + json['xml'] = Xml.domToText(this.xml); + json['ids'] = this.ids; + if (!this.recordUndo) { + json['recordUndo'] = this.recordUndo; + } + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +BlockCreate.prototype.fromJson = function(json) { + BlockCreate.superClass_.fromJson.call(this, json); + this.xml = Xml.textToDom(json['xml']); + this.ids = json['ids']; + if (json['recordUndo'] !== undefined) { + this.recordUndo = json['recordUndo']; + } +}; + +/** + * Run a creation event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +BlockCreate.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + if (forward) { + const xmlEl = xml.createElement('xml'); + xmlEl.appendChild(this.xml); + Xml.domToWorkspace(xmlEl, workspace); + } else { + for (let i = 0; i < this.ids.length; i++) { + const id = this.ids[i]; + const block = workspace.getBlockById(id); + if (block) { + block.dispose(false); + } else if (id == this.blockId) { + // Only complain about root-level block. + console.warn('Can\'t uncreate non-existent block: ' + id); + } + } + } +}; + +registry.register(registry.Type.EVENT, Events.CREATE, BlockCreate); + +exports = BlockCreate; diff --git a/core/events/events_block_delete.js b/core/events/events_block_delete.js new file mode 100644 index 000000000..f44caa7f0 --- /dev/null +++ b/core/events/events_block_delete.js @@ -0,0 +1,114 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class for a block delete event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.BlockDelete'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const BlockBase = goog.require('Blockly.Events.BlockBase'); +const Events = goog.require('Blockly.Events'); +const Xml = goog.require('Blockly.Xml'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); +const xml = goog.require('Blockly.utils.xml'); + + +/** + * Class for a block deletion event. + * @param {!Block=} opt_block The deleted block. Undefined for a blank + * event. + * @extends {BlockBase} + * @constructor + */ +const BlockDelete = function(opt_block) { + BlockDelete.superClass_.constructor.call(this, opt_block); + if (!opt_block) { + return; // Blank event to be populated by fromJson. + } + if (opt_block.getParent()) { + throw Error('Connected blocks cannot be deleted.'); + } + if (opt_block.isShadow()) { + // Respawning shadow blocks is handled via disconnection. + this.recordUndo = false; + } + + if (opt_block.workspace.rendered) { + this.oldXml = Xml.blockToDomWithXY(opt_block); + } else { + this.oldXml = Xml.blockToDom(opt_block); + } + this.ids = Events.getDescendantIds(opt_block); +}; +object.inherits(BlockDelete, BlockBase); + +/** + * Type of this event. + * @type {string} + */ +BlockDelete.prototype.type = Events.BLOCK_DELETE; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +BlockDelete.prototype.toJson = function() { + const json = BlockDelete.superClass_.toJson.call(this); + json['oldXml'] = Xml.domToText(this.oldXml); + json['ids'] = this.ids; + if (!this.recordUndo) { + json['recordUndo'] = this.recordUndo; + } + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +BlockDelete.prototype.fromJson = function(json) { + BlockDelete.superClass_.fromJson.call(this, json); + this.oldXml = Xml.textToDom(json['oldXml']); + this.ids = json['ids']; + if (json['recordUndo'] !== undefined) { + this.recordUndo = json['recordUndo']; + } +}; + +/** + * Run a deletion event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +BlockDelete.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + if (forward) { + for (let i = 0; i < this.ids.length; i++) { + const id = this.ids[i]; + const block = workspace.getBlockById(id); + if (block) { + block.dispose(false); + } else if (id == this.blockId) { + // Only complain about root-level block. + console.warn('Can\'t delete non-existent block: ' + id); + } + } + } else { + const xmlEl = xml.createElement('xml'); + xmlEl.appendChild(this.oldXml); + Xml.domToWorkspace(xmlEl, workspace); + } +}; + +registry.register(registry.Type.EVENT, Events.DELETE, BlockDelete); + +exports = BlockDelete; diff --git a/core/events/events_block_drag.js b/core/events/events_block_drag.js index 9d256822a..6fd3f0a9f 100644 --- a/core/events/events_block_drag.js +++ b/core/events/events_block_drag.js @@ -10,30 +10,31 @@ */ 'use strict'; -goog.provide('Blockly.Events.BlockDrag'); +goog.module('Blockly.Events.BlockDrag'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** * Class for a block drag event. - * @param {!Blockly.Block=} opt_block The top block in the stack that is being + * @param {!Block=} opt_block The top block in the stack that is being * dragged. Undefined for a blank event. * @param {boolean=} opt_isStart Whether this is the start of a block drag. * Undefined for a blank event. - * @param {!Array=} opt_blocks The blocks affected by this + * @param {!Array=} opt_blocks The blocks affected by this * drag. Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.BlockDrag = function(opt_block, opt_isStart, opt_blocks) { - var workspaceId = opt_block ? opt_block.workspace.id : undefined; - Blockly.Events.BlockDrag.superClass_.constructor.call(this, workspaceId); +const BlockDrag = function(opt_block, opt_isStart, opt_blocks) { + const workspaceId = opt_block ? opt_block.workspace.id : undefined; + BlockDrag.superClass_.constructor.call(this, workspaceId); this.blockId = opt_block ? opt_block.id : null; /** @@ -44,24 +45,24 @@ Blockly.Events.BlockDrag = function(opt_block, opt_isStart, opt_blocks) { /** * The blocks affected by this drag event. - * @type {!Array|undefined} + * @type {!Array|undefined} */ this.blocks = opt_blocks; }; -Blockly.utils.object.inherits(Blockly.Events.BlockDrag, Blockly.Events.UiBase); +object.inherits(BlockDrag, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.BlockDrag.prototype.type = Blockly.Events.BLOCK_DRAG; +BlockDrag.prototype.type = Events.BLOCK_DRAG; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.BlockDrag.prototype.toJson = function() { - var json = Blockly.Events.BlockDrag.superClass_.toJson.call(this); +BlockDrag.prototype.toJson = function() { + const json = BlockDrag.superClass_.toJson.call(this); json['isStart'] = this.isStart; json['blockId'] = this.blockId; json['blocks'] = this.blocks; @@ -72,12 +73,13 @@ Blockly.Events.BlockDrag.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.BlockDrag.prototype.fromJson = function(json) { - Blockly.Events.BlockDrag.superClass_.fromJson.call(this, json); +BlockDrag.prototype.fromJson = function(json) { + BlockDrag.superClass_.fromJson.call(this, json); this.isStart = json['isStart']; this.blockId = json['blockId']; this.blocks = json['blocks']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.BLOCK_DRAG, Blockly.Events.BlockDrag); +registry.register(registry.Type.EVENT, Events.BLOCK_DRAG, BlockDrag); + +exports = BlockDrag; diff --git a/core/events/events_block_move.js b/core/events/events_block_move.js new file mode 100644 index 000000000..f026c080b --- /dev/null +++ b/core/events/events_block_move.js @@ -0,0 +1,188 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class for a block move event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.BlockMove'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const BlockBase = goog.require('Blockly.Events.BlockBase'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); + + +/** + * Class for a block move event. Created before the move. + * @param {!Block=} opt_block The moved block. Undefined for a blank + * event. + * @extends {BlockBase} + * @constructor + */ +const BlockMove = function(opt_block) { + BlockMove.superClass_.constructor.call(this, opt_block); + if (!opt_block) { + return; // Blank event to be populated by fromJson. + } + if (opt_block.isShadow()) { + // Moving shadow blocks is handled via disconnection. + this.recordUndo = false; + } + + const location = this.currentLocation_(); + this.oldParentId = location.parentId; + this.oldInputName = location.inputName; + this.oldCoordinate = location.coordinate; +}; +object.inherits(BlockMove, BlockBase); + +/** + * Type of this event. + * @type {string} + */ +BlockMove.prototype.type = Events.BLOCK_MOVE; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +BlockMove.prototype.toJson = function() { + const json = BlockMove.superClass_.toJson.call(this); + if (this.newParentId) { + json['newParentId'] = this.newParentId; + } + if (this.newInputName) { + json['newInputName'] = this.newInputName; + } + if (this.newCoordinate) { + json['newCoordinate'] = Math.round(this.newCoordinate.x) + ',' + + Math.round(this.newCoordinate.y); + } + if (!this.recordUndo) { + json['recordUndo'] = this.recordUndo; + } + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +BlockMove.prototype.fromJson = function(json) { + BlockMove.superClass_.fromJson.call(this, json); + this.newParentId = json['newParentId']; + this.newInputName = json['newInputName']; + if (json['newCoordinate']) { + const xy = json['newCoordinate'].split(','); + this.newCoordinate = new Coordinate(Number(xy[0]), Number(xy[1])); + } + if (json['recordUndo'] !== undefined) { + this.recordUndo = json['recordUndo']; + } +}; + +/** + * Record the block's new location. Called after the move. + */ +BlockMove.prototype.recordNew = function() { + const location = this.currentLocation_(); + this.newParentId = location.parentId; + this.newInputName = location.inputName; + this.newCoordinate = location.coordinate; +}; + +/** + * Returns the parentId and input if the block is connected, + * or the XY location if disconnected. + * @return {!Object} Collection of location info. + * @private + */ +BlockMove.prototype.currentLocation_ = function() { + const workspace = this.getEventWorkspace_(); + const block = workspace.getBlockById(this.blockId); + const location = {}; + const parent = block.getParent(); + if (parent) { + location.parentId = parent.id; + const input = parent.getInputWithBlock(block); + if (input) { + location.inputName = input.name; + } + } else { + location.coordinate = block.getRelativeToSurfaceXY(); + } + return location; +}; + +/** + * Does this event record any change of state? + * @return {boolean} False if something changed. + */ +BlockMove.prototype.isNull = function() { + return this.oldParentId == this.newParentId && + this.oldInputName == this.newInputName && + Coordinate.equals(this.oldCoordinate, this.newCoordinate); +}; + +/** + * Run a move event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +BlockMove.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + const block = workspace.getBlockById(this.blockId); + if (!block) { + console.warn('Can\'t move non-existent block: ' + this.blockId); + return; + } + const parentId = forward ? this.newParentId : this.oldParentId; + const inputName = forward ? this.newInputName : this.oldInputName; + const coordinate = forward ? this.newCoordinate : this.oldCoordinate; + let parentBlock; + if (parentId) { + parentBlock = workspace.getBlockById(parentId); + if (!parentBlock) { + console.warn('Can\'t connect to non-existent block: ' + parentId); + return; + } + } + if (block.getParent()) { + block.unplug(); + } + if (coordinate) { + const xy = block.getRelativeToSurfaceXY(); + block.moveBy(coordinate.x - xy.x, coordinate.y - xy.y); + } else { + const blockConnection = block.outputConnection || block.previousConnection; + let parentConnection; + const connectionType = blockConnection.type; + if (inputName) { + const input = parentBlock.getInput(inputName); + if (input) { + parentConnection = input.connection; + } + } else if (connectionType == connectionTypes.PREVIOUS_STATEMENT) { + parentConnection = parentBlock.nextConnection; + } + if (parentConnection) { + blockConnection.connect(parentConnection); + } else { + console.warn('Can\'t connect to non-existent input: ' + inputName); + } + } +}; + +registry.register(registry.Type.EVENT, Events.MOVE, BlockMove); + +exports = BlockMove; diff --git a/core/events/events_bubble_open.js b/core/events/events_bubble_open.js index 7d3fbff2d..1e177f33e 100644 --- a/core/events/events_bubble_open.js +++ b/core/events/events_bubble_open.js @@ -10,30 +10,32 @@ */ 'use strict'; -goog.provide('Blockly.Events.BubbleOpen'); +goog.module('Blockly.Events.BubbleOpen'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.BlockSvg'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** * Class for a bubble open event. - * @param {Blockly.BlockSvg} opt_block The associated block. Undefined for a + * @param {BlockSvg} opt_block The associated block. Undefined for a * blank event. * @param {boolean=} opt_isOpen Whether the bubble is opening (false if * closing). Undefined for a blank event. - * @param {string=} opt_bubbleType The type of bubble. One of 'mutator', 'comment' + * @param {string=} opt_bubbleType The type of bubble. One of 'mutator', + * 'comment' * or 'warning'. Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.BubbleOpen = function(opt_block, opt_isOpen, opt_bubbleType) { - var workspaceId = opt_block ? opt_block.workspace.id : undefined; - Blockly.Events.BubbleOpen.superClass_.constructor.call(this, workspaceId); +const BubbleOpen = function(opt_block, opt_isOpen, opt_bubbleType) { + const workspaceId = opt_block ? opt_block.workspace.id : undefined; + BubbleOpen.superClass_.constructor.call(this, workspaceId); this.blockId = opt_block ? opt_block.id : null; /** @@ -48,20 +50,20 @@ Blockly.Events.BubbleOpen = function(opt_block, opt_isOpen, opt_bubbleType) { */ this.bubbleType = opt_bubbleType; }; -Blockly.utils.object.inherits(Blockly.Events.BubbleOpen, Blockly.Events.UiBase); +object.inherits(BubbleOpen, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.BubbleOpen.prototype.type = Blockly.Events.BUBBLE_OPEN; +BubbleOpen.prototype.type = Events.BUBBLE_OPEN; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.BubbleOpen.prototype.toJson = function() { - var json = Blockly.Events.BubbleOpen.superClass_.toJson.call(this); +BubbleOpen.prototype.toJson = function() { + const json = BubbleOpen.superClass_.toJson.call(this); json['isOpen'] = this.isOpen; json['bubbleType'] = this.bubbleType; json['blockId'] = this.blockId; @@ -72,12 +74,13 @@ Blockly.Events.BubbleOpen.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.BubbleOpen.prototype.fromJson = function(json) { - Blockly.Events.BubbleOpen.superClass_.fromJson.call(this, json); +BubbleOpen.prototype.fromJson = function(json) { + BubbleOpen.superClass_.fromJson.call(this, json); this.isOpen = json['isOpen']; this.bubbleType = json['bubbleType']; this.blockId = json['blockId']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.BUBBLE_OPEN, Blockly.Events.BubbleOpen); +registry.register(registry.Type.EVENT, Events.BUBBLE_OPEN, BubbleOpen); + +exports = BubbleOpen; diff --git a/core/events/events_click.js b/core/events/events_click.js index ea46b0a76..521f87763 100644 --- a/core/events/events_click.js +++ b/core/events/events_click.js @@ -10,31 +10,31 @@ */ 'use strict'; -goog.provide('Blockly.Events.Click'); - -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.Block'); +goog.module('Blockly.Events.Click'); +goog.module.declareLegacyNamespace(); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** * Class for a click event. - * @param {?Blockly.Block=} opt_block The affected block. Null for click events + * @param {?Block=} opt_block The affected block. Null for click events * that do not have an associated block (i.e. workspace click). Undefined * for a blank event. * @param {?string=} opt_workspaceId The workspace identifier for this event. * Not used if block is passed. Undefined for a blank event. * @param {string=} opt_targetType The type of element targeted by this click * event. Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.Click = function(opt_block, opt_workspaceId, opt_targetType) { - var workspaceId = opt_block ? opt_block.workspace.id : opt_workspaceId; - Blockly.Events.Click.superClass_.constructor.call(this, workspaceId); +const Click = function(opt_block, opt_workspaceId, opt_targetType) { + const workspaceId = opt_block ? opt_block.workspace.id : opt_workspaceId; + Click.superClass_.constructor.call(this, workspaceId); this.blockId = opt_block ? opt_block.id : null; /** @@ -43,20 +43,20 @@ Blockly.Events.Click = function(opt_block, opt_workspaceId, opt_targetType) { */ this.targetType = opt_targetType; }; -Blockly.utils.object.inherits(Blockly.Events.Click, Blockly.Events.UiBase); +object.inherits(Click, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.Click.prototype.type = Blockly.Events.CLICK; +Click.prototype.type = Events.CLICK; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.Click.prototype.toJson = function() { - var json = Blockly.Events.Click.superClass_.toJson.call(this); +Click.prototype.toJson = function() { + const json = Click.superClass_.toJson.call(this); json['targetType'] = this.targetType; if (this.blockId) { json['blockId'] = this.blockId; @@ -68,11 +68,12 @@ Blockly.Events.Click.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.Click.prototype.fromJson = function(json) { - Blockly.Events.Click.superClass_.fromJson.call(this, json); +Click.prototype.fromJson = function(json) { + Click.superClass_.fromJson.call(this, json); this.targetType = json['targetType']; this.blockId = json['blockId']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CLICK, - Blockly.Events.Click); +registry.register(registry.Type.EVENT, Events.CLICK, Click); + +exports = Click; diff --git a/core/events/events_marker_move.js b/core/events/events_marker_move.js index ab839daff..2d0e0957b 100644 --- a/core/events/events_marker_move.js +++ b/core/events/events_marker_move.js @@ -10,39 +10,39 @@ */ 'use strict'; -goog.provide('Blockly.Events.MarkerMove'); +goog.module('Blockly.Events.MarkerMove'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.ASTNode'); -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.Workspace'); +const ASTNode = goog.require('Blockly.ASTNode'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** * Class for a marker move event. - * @param {?Blockly.Block=} opt_block The affected block. Null if current node + * @param {?Block=} opt_block The affected block. Null if current node * is of type workspace. Undefined for a blank event. * @param {boolean=} isCursor Whether this is a cursor event. Undefined for a * blank event. - * @param {?Blockly.ASTNode=} opt_oldNode The old node the marker used to be on. + * @param {?ASTNode=} opt_oldNode The old node the marker used to be on. * Undefined for a blank event. - * @param {!Blockly.ASTNode=} opt_newNode The new node the marker is now on. + * @param {!ASTNode=} opt_newNode The new node the marker is now on. * Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.MarkerMove = function(opt_block, isCursor, opt_oldNode, - opt_newNode) { - var workspaceId = opt_block ? opt_block.workspace.id : undefined; - if (opt_newNode && opt_newNode.getType() == Blockly.ASTNode.types.WORKSPACE) { - workspaceId = - (/** @type {!Blockly.Workspace} */ (opt_newNode.getLocation())).id; +const MarkerMove = function(opt_block, isCursor, opt_oldNode, opt_newNode) { + let workspaceId = opt_block ? opt_block.workspace.id : undefined; + if (opt_newNode && opt_newNode.getType() == ASTNode.types.WORKSPACE) { + workspaceId = (/** @type {!Workspace} */ (opt_newNode.getLocation())).id; } - Blockly.Events.MarkerMove.superClass_.constructor.call(this, workspaceId); + MarkerMove.superClass_.constructor.call(this, workspaceId); /** * The workspace identifier for this event. @@ -52,13 +52,13 @@ Blockly.Events.MarkerMove = function(opt_block, isCursor, opt_oldNode, /** * The old node the marker used to be on. - * @type {?Blockly.ASTNode|undefined} + * @type {?ASTNode|undefined} */ this.oldNode = opt_oldNode; /** * The new node the marker is now on. - * @type {Blockly.ASTNode|undefined} + * @type {ASTNode|undefined} */ this.newNode = opt_newNode; @@ -68,20 +68,20 @@ Blockly.Events.MarkerMove = function(opt_block, isCursor, opt_oldNode, */ this.isCursor = isCursor; }; -Blockly.utils.object.inherits(Blockly.Events.MarkerMove, Blockly.Events.UiBase); +object.inherits(MarkerMove, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.MarkerMove.prototype.type = Blockly.Events.MARKER_MOVE; +MarkerMove.prototype.type = Events.MARKER_MOVE; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.MarkerMove.prototype.toJson = function() { - var json = Blockly.Events.MarkerMove.superClass_.toJson.call(this); +MarkerMove.prototype.toJson = function() { + const json = MarkerMove.superClass_.toJson.call(this); json['isCursor'] = this.isCursor; json['blockId'] = this.blockId; json['oldNode'] = this.oldNode; @@ -93,13 +93,14 @@ Blockly.Events.MarkerMove.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.MarkerMove.prototype.fromJson = function(json) { - Blockly.Events.MarkerMove.superClass_.fromJson.call(this, json); +MarkerMove.prototype.fromJson = function(json) { + MarkerMove.superClass_.fromJson.call(this, json); this.isCursor = json['isCursor']; this.blockId = json['blockId']; this.oldNode = json['oldNode']; this.newNode = json['newNode']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.MARKER_MOVE, Blockly.Events.MarkerMove); +registry.register(registry.Type.EVENT, Events.MARKER_MOVE, MarkerMove); + +exports = MarkerMove; diff --git a/core/events/events_selected.js b/core/events/events_selected.js index cfb7c6573..47fcee5df 100644 --- a/core/events/events_selected.js +++ b/core/events/events_selected.js @@ -10,12 +10,13 @@ */ 'use strict'; -goog.provide('Blockly.Events.Selected'); +goog.module('Blockly.Events.Selected'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -26,12 +27,11 @@ goog.require('Blockly.utils.object'); * element currently selected (deselect). Undefined for a blank event. * @param {string=} opt_workspaceId The workspace identifier for this event. * Null if no element previously selected. Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.Selected = function(opt_oldElementId, opt_newElementId, - opt_workspaceId) { - Blockly.Events.Selected.superClass_.constructor.call(this, opt_workspaceId); +const Selected = function(opt_oldElementId, opt_newElementId, opt_workspaceId) { + Selected.superClass_.constructor.call(this, opt_workspaceId); /** * The id of the last selected element. @@ -45,20 +45,20 @@ Blockly.Events.Selected = function(opt_oldElementId, opt_newElementId, */ this.newElementId = opt_newElementId; }; -Blockly.utils.object.inherits(Blockly.Events.Selected, Blockly.Events.UiBase); +object.inherits(Selected, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.Selected.prototype.type = Blockly.Events.SELECTED; +Selected.prototype.type = Events.SELECTED; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.Selected.prototype.toJson = function() { - var json = Blockly.Events.Selected.superClass_.toJson.call(this); +Selected.prototype.toJson = function() { + const json = Selected.superClass_.toJson.call(this); json['oldElementId'] = this.oldElementId; json['newElementId'] = this.newElementId; return json; @@ -68,11 +68,12 @@ Blockly.Events.Selected.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.Selected.prototype.fromJson = function(json) { - Blockly.Events.Selected.superClass_.fromJson.call(this, json); +Selected.prototype.fromJson = function(json) { + Selected.superClass_.fromJson.call(this, json); this.oldElementId = json['oldElementId']; this.newElementId = json['newElementId']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.SELECTED, - Blockly.Events.Selected); +registry.register(registry.Type.EVENT, Events.SELECTED, Selected); + +exports = Selected; diff --git a/core/events/events_theme_change.js b/core/events/events_theme_change.js index c0ecd889f..c58d11158 100644 --- a/core/events/events_theme_change.js +++ b/core/events/events_theme_change.js @@ -10,12 +10,13 @@ */ 'use strict'; -goog.provide('Blockly.Events.ThemeChange'); +goog.module('Blockly.Events.ThemeChange'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -23,11 +24,11 @@ goog.require('Blockly.utils.object'); * @param {string=} opt_themeName The theme name. Undefined for a blank event. * @param {string=} opt_workspaceId The workspace identifier for this event. * event. Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.ThemeChange = function(opt_themeName, opt_workspaceId) { - Blockly.Events.ThemeChange.superClass_.constructor.call(this, opt_workspaceId); +const ThemeChange = function(opt_themeName, opt_workspaceId) { + ThemeChange.superClass_.constructor.call(this, opt_workspaceId); /** * The theme name. @@ -35,20 +36,20 @@ Blockly.Events.ThemeChange = function(opt_themeName, opt_workspaceId) { */ this.themeName = opt_themeName; }; -Blockly.utils.object.inherits(Blockly.Events.ThemeChange, Blockly.Events.UiBase); +object.inherits(ThemeChange, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.ThemeChange.prototype.type = Blockly.Events.THEME_CHANGE; +ThemeChange.prototype.type = Events.THEME_CHANGE; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.ThemeChange.prototype.toJson = function() { - var json = Blockly.Events.ThemeChange.superClass_.toJson.call(this); +ThemeChange.prototype.toJson = function() { + const json = ThemeChange.superClass_.toJson.call(this); json['themeName'] = this.themeName; return json; }; @@ -57,10 +58,11 @@ Blockly.Events.ThemeChange.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.ThemeChange.prototype.fromJson = function(json) { - Blockly.Events.ThemeChange.superClass_.fromJson.call(this, json); +ThemeChange.prototype.fromJson = function(json) { + ThemeChange.superClass_.fromJson.call(this, json); this.themeName = json['themeName']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.THEME_CHANGE, Blockly.Events.ThemeChange); +registry.register(registry.Type.EVENT, Events.THEME_CHANGE, ThemeChange); + +exports = ThemeChange; diff --git a/core/events/events_toolbox_item_select.js b/core/events/events_toolbox_item_select.js index a7dbb5305..0fddaf4e9 100644 --- a/core/events/events_toolbox_item_select.js +++ b/core/events/events_toolbox_item_select.js @@ -10,12 +10,13 @@ */ 'use strict'; -goog.provide('Blockly.Events.ToolboxItemSelect'); +goog.module('Blockly.Events.ToolboxItemSelect'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -26,13 +27,11 @@ goog.require('Blockly.utils.object'); * a blank event. * @param {string=} opt_workspaceId The workspace identifier for this event. * Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.ToolboxItemSelect = function(opt_oldItem, opt_newItem, - opt_workspaceId) { - Blockly.Events.ToolboxItemSelect.superClass_.constructor.call( - this, opt_workspaceId); +const ToolboxItemSelect = function(opt_oldItem, opt_newItem, opt_workspaceId) { + ToolboxItemSelect.superClass_.constructor.call(this, opt_workspaceId); /** * The previously selected toolbox item. @@ -46,20 +45,20 @@ Blockly.Events.ToolboxItemSelect = function(opt_oldItem, opt_newItem, */ this.newItem = opt_newItem; }; -Blockly.utils.object.inherits(Blockly.Events.ToolboxItemSelect, Blockly.Events.UiBase); +object.inherits(ToolboxItemSelect, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.ToolboxItemSelect.prototype.type = Blockly.Events.TOOLBOX_ITEM_SELECT; +ToolboxItemSelect.prototype.type = Events.TOOLBOX_ITEM_SELECT; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.ToolboxItemSelect.prototype.toJson = function() { - var json = Blockly.Events.ToolboxItemSelect.superClass_.toJson.call(this); +ToolboxItemSelect.prototype.toJson = function() { + const json = ToolboxItemSelect.superClass_.toJson.call(this); json['oldItem'] = this.oldItem; json['newItem'] = this.newItem; return json; @@ -69,11 +68,13 @@ Blockly.Events.ToolboxItemSelect.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.ToolboxItemSelect.prototype.fromJson = function(json) { - Blockly.Events.ToolboxItemSelect.superClass_.fromJson.call(this, json); +ToolboxItemSelect.prototype.fromJson = function(json) { + ToolboxItemSelect.superClass_.fromJson.call(this, json); this.oldItem = json['oldItem']; this.newItem = json['newItem']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.TOOLBOX_ITEM_SELECT, Blockly.Events.ToolboxItemSelect); +registry.register( + registry.Type.EVENT, Events.TOOLBOX_ITEM_SELECT, ToolboxItemSelect); + +exports = ToolboxItemSelect; diff --git a/core/events/events_trashcan_open.js b/core/events/events_trashcan_open.js index ab388d909..6f5318213 100644 --- a/core/events/events_trashcan_open.js +++ b/core/events/events_trashcan_open.js @@ -10,12 +10,13 @@ */ 'use strict'; -goog.provide('Blockly.Events.TrashcanOpen'); +goog.module('Blockly.Events.TrashcanOpen'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -24,11 +25,11 @@ goog.require('Blockly.utils.object'); * opening). Undefined for a blank event. * @param {string=} opt_workspaceId The workspace identifier for this event. * Undefined for a blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.TrashcanOpen = function(opt_isOpen, opt_workspaceId) { - Blockly.Events.TrashcanOpen.superClass_.constructor.call(this, opt_workspaceId); +const TrashcanOpen = function(opt_isOpen, opt_workspaceId) { + TrashcanOpen.superClass_.constructor.call(this, opt_workspaceId); /** * Whether the trashcan flyout is opening (false if closing). @@ -36,20 +37,20 @@ Blockly.Events.TrashcanOpen = function(opt_isOpen, opt_workspaceId) { */ this.isOpen = opt_isOpen; }; -Blockly.utils.object.inherits(Blockly.Events.TrashcanOpen, Blockly.Events.UiBase); +object.inherits(TrashcanOpen, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.TrashcanOpen.prototype.type = Blockly.Events.TRASHCAN_OPEN; +TrashcanOpen.prototype.type = Events.TRASHCAN_OPEN; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.TrashcanOpen.prototype.toJson = function() { - var json = Blockly.Events.TrashcanOpen.superClass_.toJson.call(this); +TrashcanOpen.prototype.toJson = function() { + const json = TrashcanOpen.superClass_.toJson.call(this); json['isOpen'] = this.isOpen; return json; }; @@ -58,10 +59,11 @@ Blockly.Events.TrashcanOpen.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.TrashcanOpen.prototype.fromJson = function(json) { - Blockly.Events.TrashcanOpen.superClass_.fromJson.call(this, json); +TrashcanOpen.prototype.fromJson = function(json) { + TrashcanOpen.superClass_.fromJson.call(this, json); this.isOpen = json['isOpen']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.TRASHCAN_OPEN, Blockly.Events.TrashcanOpen); +registry.register(registry.Type.EVENT, Events.TRASHCAN_OPEN, TrashcanOpen); + +exports = TrashcanOpen; diff --git a/core/events/events_ui.js b/core/events/events_ui.js new file mode 100644 index 000000000..5598f30a0 --- /dev/null +++ b/core/events/events_ui.js @@ -0,0 +1,83 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview (Deprecated) Events fired as a result of UI actions in + * Blockly's editor. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +goog.module('Blockly.Events.Ui'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); + + +/** + * Class for a UI event. + * @param {?Block=} opt_block The affected block. Null for UI events + * that do not have an associated block. Undefined for a blank event. + * @param {string=} opt_element One of 'selected', 'comment', 'mutatorOpen', + * etc. + * @param {*=} opt_oldValue Previous value of element. + * @param {*=} opt_newValue New value of element. + * @extends {UiBase} + * @deprecated December 2020. Instead use a more specific UI event. + * @constructor + */ +const Ui = function(opt_block, opt_element, opt_oldValue, opt_newValue) { + const workspaceId = opt_block ? opt_block.workspace.id : undefined; + Ui.superClass_.constructor.call(this, workspaceId); + + this.blockId = opt_block ? opt_block.id : null; + this.element = typeof opt_element == 'undefined' ? '' : opt_element; + this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue; + this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue; +}; +object.inherits(Ui, UiBase); + +/** + * Type of this event. + * @type {string} + */ +Ui.prototype.type = Events.UI; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +Ui.prototype.toJson = function() { + const json = Ui.superClass_.toJson.call(this); + json['element'] = this.element; + if (this.newValue !== undefined) { + json['newValue'] = this.newValue; + } + if (this.blockId) { + json['blockId'] = this.blockId; + } + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Ui.prototype.fromJson = function(json) { + Ui.superClass_.fromJson.call(this, json); + this.element = json['element']; + this.newValue = json['newValue']; + this.blockId = json['blockId']; +}; + +registry.register(registry.Type.EVENT, Events.UI, Ui); + +exports = Ui; diff --git a/core/events/events_ui_base.js b/core/events/events_ui_base.js new file mode 100644 index 000000000..5bcf7270c --- /dev/null +++ b/core/events/events_ui_base.js @@ -0,0 +1,58 @@ +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Base class for events fired as a result of UI actions in + * Blockly's editor. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +goog.module('Blockly.Events.UiBase'); +goog.module.declareLegacyNamespace(); + +const Abstract = goog.require('Blockly.Events.Abstract'); +const object = goog.require('Blockly.utils.object'); + + +/** + * Base class for a UI event. + * UI events are events that don't need to be sent over the wire for multi-user + * editing to work (e.g. scrolling the workspace, zooming, opening toolbox + * categories). + * UI events do not undo or redo. + * @param {string=} opt_workspaceId The workspace identifier for this event. + * Undefined for a blank event. + * @extends {Abstract} + * @constructor + */ +const UiBase = function(opt_workspaceId) { + UiBase.superClass_.constructor.call(this); + + /** + * Whether or not the event is blank (to be populated by fromJson). + * @type {boolean} + */ + this.isBlank = typeof opt_workspaceId == 'undefined'; + + /** + * The workspace identifier for this event. + * @type {string} + */ + this.workspaceId = opt_workspaceId ? opt_workspaceId : ''; + + // UI events do not undo or redo. + this.recordUndo = false; +}; +object.inherits(UiBase, Abstract); + +/** + * Whether or not the event is a UI event. + * @type {boolean} + */ +UiBase.prototype.isUiEvent = true; + +exports = UiBase; diff --git a/core/events/events_var_base.js b/core/events/events_var_base.js new file mode 100644 index 000000000..cedf349b7 --- /dev/null +++ b/core/events/events_var_base.js @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Abstract class for a variable event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.VarBase'); +goog.module.declareLegacyNamespace(); + +const Abstract = goog.require('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +const object = goog.require('Blockly.utils.object'); + + +/** + * Abstract class for a variable event. + * @param {!VariableModel=} opt_variable The variable this event + * corresponds to. Undefined for a blank event. + * @extends {Abstract} + * @constructor + */ +const VarBase = function(opt_variable) { + VarBase.superClass_.constructor.call(this); + this.isBlank = typeof opt_variable == 'undefined'; + + /** + * The variable id for the variable this event pertains to. + * @type {string} + */ + this.varId = this.isBlank ? '' : opt_variable.getId(); + + /** + * The workspace identifier for this event. + * @type {string} + */ + this.workspaceId = this.isBlank ? '' : opt_variable.workspace.id; +}; +object.inherits(VarBase, Abstract); + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +VarBase.prototype.toJson = function() { + const json = VarBase.superClass_.toJson.call(this); + json['varId'] = this.varId; + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +VarBase.prototype.fromJson = function(json) { + VarBase.superClass_.toJson.call(this); + this.varId = json['varId']; +}; + +exports = VarBase; diff --git a/core/events/events_var_create.js b/core/events/events_var_create.js new file mode 100644 index 000000000..8db58be74 --- /dev/null +++ b/core/events/events_var_create.js @@ -0,0 +1,84 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class for a variable creation event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.VarCreate'); +goog.module.declareLegacyNamespace(); + +const Events = goog.require('Blockly.Events'); +const VarBase = goog.require('Blockly.Events.VarBase'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); + + +/** + * Class for a variable creation event. + * @param {!VariableModel=} opt_variable The created variable. Undefined + * for a blank event. + * @extends {VarBase} + * @constructor + */ +const VarCreate = function(opt_variable) { + VarCreate.superClass_.constructor.call(this, opt_variable); + if (!opt_variable) { + return; // Blank event to be populated by fromJson. + } + + this.varType = opt_variable.type; + this.varName = opt_variable.name; +}; +object.inherits(VarCreate, VarBase); + +/** + * Type of this event. + * @type {string} + */ +VarCreate.prototype.type = Events.VAR_CREATE; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +VarCreate.prototype.toJson = function() { + const json = VarCreate.superClass_.toJson.call(this); + json['varType'] = this.varType; + json['varName'] = this.varName; + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +VarCreate.prototype.fromJson = function(json) { + VarCreate.superClass_.fromJson.call(this, json); + this.varType = json['varType']; + this.varName = json['varName']; +}; + +/** + * Run a variable creation event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +VarCreate.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + if (forward) { + workspace.createVariable(this.varName, this.varType, this.varId); + } else { + workspace.deleteVariableById(this.varId); + } +}; + +registry.register(registry.Type.EVENT, Events.VAR_CREATE, VarCreate); + +exports = VarCreate; diff --git a/core/events/events_var_delete.js b/core/events/events_var_delete.js new file mode 100644 index 000000000..48497bdd7 --- /dev/null +++ b/core/events/events_var_delete.js @@ -0,0 +1,84 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Classes for all types of variable events. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.VarDelete'); +goog.module.declareLegacyNamespace(); + +const Events = goog.require('Blockly.Events'); +const VarBase = goog.require('Blockly.Events.VarBase'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); + + +/** + * Class for a variable deletion event. + * @param {!VariableModel=} opt_variable The deleted variable. Undefined + * for a blank event. + * @extends {VarBase} + * @constructor + */ +const VarDelete = function(opt_variable) { + VarDelete.superClass_.constructor.call(this, opt_variable); + if (!opt_variable) { + return; // Blank event to be populated by fromJson. + } + + this.varType = opt_variable.type; + this.varName = opt_variable.name; +}; +object.inherits(VarDelete, VarBase); + +/** + * Type of this event. + * @type {string} + */ +VarDelete.prototype.type = Events.VAR_DELETE; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +VarDelete.prototype.toJson = function() { + const json = VarDelete.superClass_.toJson.call(this); + json['varType'] = this.varType; + json['varName'] = this.varName; + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +VarDelete.prototype.fromJson = function(json) { + VarDelete.superClass_.fromJson.call(this, json); + this.varType = json['varType']; + this.varName = json['varName']; +}; + +/** + * Run a variable deletion event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +VarDelete.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + if (forward) { + workspace.deleteVariableById(this.varId); + } else { + workspace.createVariable(this.varName, this.varType, this.varId); + } +}; + +registry.register(registry.Type.EVENT, Events.VAR_DELETE, VarDelete); + +exports = VarDelete; diff --git a/core/events/events_var_rename.js b/core/events/events_var_rename.js new file mode 100644 index 000000000..9fa5f7058 --- /dev/null +++ b/core/events/events_var_rename.js @@ -0,0 +1,85 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class for a variable rename event. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.module('Blockly.Events.VarRename'); +goog.module.declareLegacyNamespace(); + +const Events = goog.require('Blockly.Events'); +const VarBase = goog.require('Blockly.Events.VarBase'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); + + +/** + * Class for a variable rename event. + * @param {!VariableModel=} opt_variable The renamed variable. Undefined + * for a blank event. + * @param {string=} newName The new name the variable will be changed to. + * @extends {VarBase} + * @constructor + */ +const VarRename = function(opt_variable, newName) { + VarRename.superClass_.constructor.call(this, opt_variable); + if (!opt_variable) { + return; // Blank event to be populated by fromJson. + } + + this.oldName = opt_variable.name; + this.newName = typeof newName == 'undefined' ? '' : newName; +}; +object.inherits(VarRename, VarBase); + +/** + * Type of this event. + * @type {string} + */ +VarRename.prototype.type = Events.VAR_RENAME; + +/** + * Encode the event as JSON. + * @return {!Object} JSON representation. + */ +VarRename.prototype.toJson = function() { + const json = VarRename.superClass_.toJson.call(this); + json['oldName'] = this.oldName; + json['newName'] = this.newName; + return json; +}; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +VarRename.prototype.fromJson = function(json) { + VarRename.superClass_.fromJson.call(this, json); + this.oldName = json['oldName']; + this.newName = json['newName']; +}; + +/** + * Run a variable rename event. + * @param {boolean} forward True if run forward, false if run backward (undo). + */ +VarRename.prototype.run = function(forward) { + const workspace = this.getEventWorkspace_(); + if (forward) { + workspace.renameVariableById(this.varId, this.newName); + } else { + workspace.renameVariableById(this.varId, this.oldName); + } +}; + +registry.register(registry.Type.EVENT, Events.VAR_RENAME, VarRename); + +exports = VarRename; diff --git a/core/events/events_viewport.js b/core/events/events_viewport.js index 6d857cd67..2cfd94a7f 100644 --- a/core/events/events_viewport.js +++ b/core/events/events_viewport.js @@ -10,12 +10,13 @@ */ 'use strict'; -goog.provide('Blockly.Events.ViewportChange'); +goog.module('Blockly.Events.ViewportChange'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.UiBase'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); +const Events = goog.require('Blockly.Events'); +const UiBase = goog.require('Blockly.Events.UiBase'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -30,12 +31,12 @@ goog.require('Blockly.utils.object'); * Undefined for a blank event. * @param {number=} opt_oldScale The old scale of the workspace. Undefined for a * blank event. - * @extends {Blockly.Events.UiBase} + * @extends {UiBase} * @constructor */ -Blockly.Events.ViewportChange = function(opt_top, opt_left, opt_scale, - opt_workspaceId, opt_oldScale) { - Blockly.Events.ViewportChange.superClass_.constructor.call(this, opt_workspaceId); +const ViewportChange = function( + opt_top, opt_left, opt_scale, opt_workspaceId, opt_oldScale) { + ViewportChange.superClass_.constructor.call(this, opt_workspaceId); /** * Top-edge of the visible portion of the workspace, relative to the workspace @@ -63,21 +64,20 @@ Blockly.Events.ViewportChange = function(opt_top, opt_left, opt_scale, */ this.oldScale = opt_oldScale; }; -Blockly.utils.object.inherits(Blockly.Events.ViewportChange, - Blockly.Events.UiBase); +object.inherits(ViewportChange, UiBase); /** * Type of this event. * @type {string} */ -Blockly.Events.ViewportChange.prototype.type = Blockly.Events.VIEWPORT_CHANGE; +ViewportChange.prototype.type = Events.VIEWPORT_CHANGE; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.ViewportChange.prototype.toJson = function() { - var json = Blockly.Events.ViewportChange.superClass_.toJson.call(this); +ViewportChange.prototype.toJson = function() { + const json = ViewportChange.superClass_.toJson.call(this); json['viewTop'] = this.viewTop; json['viewLeft'] = this.viewLeft; json['scale'] = this.scale; @@ -89,13 +89,14 @@ Blockly.Events.ViewportChange.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.ViewportChange.prototype.fromJson = function(json) { - Blockly.Events.ViewportChange.superClass_.fromJson.call(this, json); +ViewportChange.prototype.fromJson = function(json) { + ViewportChange.superClass_.fromJson.call(this, json); this.viewTop = json['viewTop']; this.viewLeft = json['viewLeft']; this.scale = json['scale']; this.oldScale = json['oldScale']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.VIEWPORT_CHANGE, Blockly.Events.ViewportChange); +registry.register(registry.Type.EVENT, Events.VIEWPORT_CHANGE, ViewportChange); + +exports = ViewportChange; diff --git a/core/events/ui_events.js b/core/events/ui_events.js deleted file mode 100644 index 5d649a22f..000000000 --- a/core/events/ui_events.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @license - * Copyright 2018 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Events fired as a result of UI actions in Blockly's editor. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -goog.provide('Blockly.Events.Ui'); -goog.provide('Blockly.Events.UiBase'); - -goog.require('Blockly.Events'); -goog.require('Blockly.Events.Abstract'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.Block'); - - -/** - * Base class for a UI event. - * UI events are events that don't need to be sent over the wire for multi-user - * editing to work (e.g. scrolling the workspace, zooming, opening toolbox - * categories). - * UI events do not undo or redo. - * @param {string=} opt_workspaceId The workspace identifier for this event. - * Undefined for a blank event. - * @extends {Blockly.Events.Abstract} - * @constructor - */ -Blockly.Events.UiBase = function(opt_workspaceId) { - Blockly.Events.UiBase.superClass_.constructor.call(this); - - /** - * Whether or not the event is blank (to be populated by fromJson). - * @type {boolean} - */ - this.isBlank = typeof opt_workspaceId == 'undefined'; - - /** - * The workspace identifier for this event. - * @type {string} - */ - this.workspaceId = opt_workspaceId ? opt_workspaceId : ''; - - // UI events do not undo or redo. - this.recordUndo = false; -}; -Blockly.utils.object.inherits(Blockly.Events.UiBase, Blockly.Events.Abstract); - -/** - * Whether or not the event is a UI event. - * @type {boolean} - */ -Blockly.Events.UiBase.prototype.isUiEvent = true; - -/** - * Class for a UI event. - * @param {?Blockly.Block=} opt_block The affected block. Null for UI events - * that do not have an associated block. Undefined for a blank event. - * @param {string=} opt_element One of 'selected', 'comment', 'mutatorOpen', - * etc. - * @param {*=} opt_oldValue Previous value of element. - * @param {*=} opt_newValue New value of element. - * @extends {Blockly.Events.UiBase} - * @deprecated December 2020. Instead use a more specific UI event. - * @constructor - */ -Blockly.Events.Ui = function(opt_block, opt_element, opt_oldValue, - opt_newValue) { - var workspaceId = opt_block ? opt_block.workspace.id : undefined; - Blockly.Events.Ui.superClass_.constructor.call(this, workspaceId); - - this.blockId = opt_block ? opt_block.id : null; - this.element = typeof opt_element == 'undefined' ? '' : opt_element; - this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue; - this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue; -}; -Blockly.utils.object.inherits(Blockly.Events.Ui, Blockly.Events.UiBase); - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.Ui.prototype.type = Blockly.Events.UI; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.Ui.prototype.toJson = function() { - var json = Blockly.Events.Ui.superClass_.toJson.call(this); - json['element'] = this.element; - if (this.newValue !== undefined) { - json['newValue'] = this.newValue; - } - if (this.blockId) { - json['blockId'] = this.blockId; - } - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.Ui.prototype.fromJson = function(json) { - Blockly.Events.Ui.superClass_.fromJson.call(this, json); - this.element = json['element']; - this.newValue = json['newValue']; - this.blockId = json['blockId']; -}; - -Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.UI, - Blockly.Events.Ui); diff --git a/core/events/variable_events.js b/core/events/variable_events.js deleted file mode 100644 index 4f7af9258..000000000 --- a/core/events/variable_events.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * @license - * Copyright 2018 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Classes for all types of variable events. - * @author fenichel@google.com (Rachel Fenichel) - */ -'use strict'; - -goog.provide('Blockly.Events.VarBase'); -goog.provide('Blockly.Events.VarCreate'); -goog.provide('Blockly.Events.VarDelete'); -goog.provide('Blockly.Events.VarRename'); - -goog.require('Blockly.Events'); -goog.require('Blockly.Events.Abstract'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.VariableModel'); - - -/** - * Abstract class for a variable event. - * @param {!Blockly.VariableModel=} opt_variable The variable this event - * corresponds to. Undefined for a blank event. - * @extends {Blockly.Events.Abstract} - * @constructor - */ -Blockly.Events.VarBase = function(opt_variable) { - Blockly.Events.VarBase.superClass_.constructor.call(this); - this.isBlank = typeof opt_variable == 'undefined'; - - /** - * The variable id for the variable this event pertains to. - * @type {string} - */ - this.varId = this.isBlank ? '' : opt_variable.getId(); - - /** - * The workspace identifier for this event. - * @type {string} - */ - this.workspaceId = this.isBlank ? '' : opt_variable.workspace.id; -}; -Blockly.utils.object.inherits(Blockly.Events.VarBase, Blockly.Events.Abstract); - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.VarBase.prototype.toJson = function() { - var json = Blockly.Events.VarBase.superClass_.toJson.call(this); - json['varId'] = this.varId; - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.VarBase.prototype.fromJson = function(json) { - Blockly.Events.VarBase.superClass_.toJson.call(this); - this.varId = json['varId']; -}; - -/** - * Class for a variable creation event. - * @param {!Blockly.VariableModel=} opt_variable The created variable. Undefined - * for a blank event. - * @extends {Blockly.Events.VarBase} - * @constructor - */ -Blockly.Events.VarCreate = function(opt_variable) { - Blockly.Events.VarCreate.superClass_.constructor.call(this, opt_variable); - if (!opt_variable) { - return; // Blank event to be populated by fromJson. - } - - this.varType = opt_variable.type; - this.varName = opt_variable.name; -}; -Blockly.utils.object.inherits(Blockly.Events.VarCreate, Blockly.Events.VarBase); - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.VarCreate.prototype.type = Blockly.Events.VAR_CREATE; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.VarCreate.prototype.toJson = function() { - var json = Blockly.Events.VarCreate.superClass_.toJson.call(this); - json['varType'] = this.varType; - json['varName'] = this.varName; - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.VarCreate.prototype.fromJson = function(json) { - Blockly.Events.VarCreate.superClass_.fromJson.call(this, json); - this.varType = json['varType']; - this.varName = json['varName']; -}; - -/** - * Run a variable creation event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.VarCreate.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - if (forward) { - workspace.createVariable(this.varName, this.varType, this.varId); - } else { - workspace.deleteVariableById(this.varId); - } -}; - -/** - * Class for a variable deletion event. - * @param {!Blockly.VariableModel=} opt_variable The deleted variable. Undefined - * for a blank event. - * @extends {Blockly.Events.VarBase} - * @constructor - */ -Blockly.Events.VarDelete = function(opt_variable) { - Blockly.Events.VarDelete.superClass_.constructor.call(this, opt_variable); - if (!opt_variable) { - return; // Blank event to be populated by fromJson. - } - - this.varType = opt_variable.type; - this.varName = opt_variable.name; -}; -Blockly.utils.object.inherits(Blockly.Events.VarDelete, Blockly.Events.VarBase); - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.VarDelete.prototype.type = Blockly.Events.VAR_DELETE; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.VarDelete.prototype.toJson = function() { - var json = Blockly.Events.VarDelete.superClass_.toJson.call(this); - json['varType'] = this.varType; - json['varName'] = this.varName; - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.VarDelete.prototype.fromJson = function(json) { - Blockly.Events.VarDelete.superClass_.fromJson.call(this, json); - this.varType = json['varType']; - this.varName = json['varName']; -}; - -/** - * Run a variable deletion event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.VarDelete.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - if (forward) { - workspace.deleteVariableById(this.varId); - } else { - workspace.createVariable(this.varName, this.varType, this.varId); - } -}; - -/** - * Class for a variable rename event. - * @param {!Blockly.VariableModel=} opt_variable The renamed variable. Undefined - * for a blank event. - * @param {string=} newName The new name the variable will be changed to. - * @extends {Blockly.Events.VarBase} - * @constructor - */ -Blockly.Events.VarRename = function(opt_variable, newName) { - Blockly.Events.VarRename.superClass_.constructor.call(this, opt_variable); - if (!opt_variable) { - return; // Blank event to be populated by fromJson. - } - - this.oldName = opt_variable.name; - this.newName = typeof newName == 'undefined' ? '' : newName; -}; -Blockly.utils.object.inherits(Blockly.Events.VarRename, Blockly.Events.VarBase); - -/** - * Type of this event. - * @type {string} - */ -Blockly.Events.VarRename.prototype.type = Blockly.Events.VAR_RENAME; - -/** - * Encode the event as JSON. - * @return {!Object} JSON representation. - */ -Blockly.Events.VarRename.prototype.toJson = function() { - var json = Blockly.Events.VarRename.superClass_.toJson.call(this); - json['oldName'] = this.oldName; - json['newName'] = this.newName; - return json; -}; - -/** - * Decode the JSON event. - * @param {!Object} json JSON representation. - */ -Blockly.Events.VarRename.prototype.fromJson = function(json) { - Blockly.Events.VarRename.superClass_.fromJson.call(this, json); - this.oldName = json['oldName']; - this.newName = json['newName']; -}; - -/** - * Run a variable rename event. - * @param {boolean} forward True if run forward, false if run backward (undo). - */ -Blockly.Events.VarRename.prototype.run = function(forward) { - var workspace = this.getEventWorkspace_(); - if (forward) { - workspace.renameVariableById(this.varId, this.newName); - } else { - workspace.renameVariableById(this.varId, this.oldName); - } -}; - -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.VAR_CREATE, Blockly.Events.VarCreate); -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.VAR_DELETE, Blockly.Events.VarDelete); -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.VAR_RENAME, Blockly.Events.VarRename); diff --git a/core/events/workspace_events.js b/core/events/workspace_events.js index bb22097a0..df832602e 100644 --- a/core/events/workspace_events.js +++ b/core/events/workspace_events.js @@ -10,14 +10,15 @@ */ 'use strict'; -goog.provide('Blockly.Events.FinishedLoading'); +goog.module('Blockly.Events.FinishedLoading'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); -goog.require('Blockly.Events.Abstract'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.Workspace'); +const Events = goog.require('Blockly.Events'); +const EventsAbstract = goog.require('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -25,13 +26,12 @@ goog.requireType('Blockly.Workspace'); * Used to notify the developer when the workspace has finished loading (i.e * domToWorkspace). * Finished loading events do not record undo or redo. - * @param {!Blockly.Workspace=} opt_workspace The workspace that has finished + * @param {!Workspace=} opt_workspace The workspace that has finished * loading. Undefined for a blank event. - * @extends {Blockly.Events.Abstract} + * @extends {EventsAbstract} * @constructor */ -Blockly.Events.FinishedLoading = function(opt_workspace) { - +const FinishedLoading = function(opt_workspace) { /** * Whether or not the event is blank (to be populated by fromJson). * @type {boolean} @@ -50,26 +50,25 @@ Blockly.Events.FinishedLoading = function(opt_workspace) { * perspective, and should be undone together. * @type {string} */ - this.group = Blockly.Events.getGroup(); + this.group = Events.getGroup(); // Workspace events do not undo or redo. this.recordUndo = false; }; -Blockly.utils.object.inherits(Blockly.Events.FinishedLoading, - Blockly.Events.Abstract); +object.inherits(FinishedLoading, EventsAbstract); /** * Type of this event. * @type {string} */ -Blockly.Events.FinishedLoading.prototype.type = Blockly.Events.FINISHED_LOADING; +FinishedLoading.prototype.type = Events.FINISHED_LOADING; /** * Encode the event as JSON. * @return {!Object} JSON representation. */ -Blockly.Events.FinishedLoading.prototype.toJson = function() { - var json = { +FinishedLoading.prototype.toJson = function() { + const json = { 'type': this.type, }; if (this.group) { @@ -85,11 +84,13 @@ Blockly.Events.FinishedLoading.prototype.toJson = function() { * Decode the JSON event. * @param {!Object} json JSON representation. */ -Blockly.Events.FinishedLoading.prototype.fromJson = function(json) { +FinishedLoading.prototype.fromJson = function(json) { this.isBlank = false; this.workspaceId = json['workspaceId']; this.group = json['group']; }; -Blockly.registry.register(Blockly.registry.Type.EVENT, - Blockly.Events.FINISHED_LOADING, Blockly.Events.FinishedLoading); +registry.register( + registry.Type.EVENT, Events.FINISHED_LOADING, FinishedLoading); + +exports = FinishedLoading; diff --git a/core/events/ws_comment_events.js b/core/events/ws_comment_events.js index a77c36428..e54441ec7 100644 --- a/core/events/ws_comment_events.js +++ b/core/events/ws_comment_events.js @@ -24,6 +24,8 @@ goog.require('Blockly.utils.object'); goog.require('Blockly.utils.xml'); goog.require('Blockly.Xml'); +goog.requireType('Blockly.WorkspaceComment'); + /** * Abstract class for a comment event. @@ -232,7 +234,7 @@ Blockly.Events.CommentCreateDeleteHelper = function(event, create) { } else { var comment = workspace.getCommentById(event.commentId); if (comment) { - comment.dispose(false, false); + comment.dispose(); } else { // Only complain about root-level block. console.warn("Can't uncreate non-existent comment: " + event.commentId); diff --git a/core/extensions.js b/core/extensions.js index 3f20777aa..42dc9d9f6 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -22,7 +22,8 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const Block = goog.requireType('Blockly.Block'); -const {checkMessageReferences, replaceMessageReferences, runAfterPageLoad} = goog.require('Blockly.utils'); +const utils = goog.require('Blockly.utils'); +goog.requireType('Blockly.Mutator'); /** @@ -102,10 +103,11 @@ const registerMutator = function(name, mixinObj, opt_helperFn, opt_blockList) { // Sanity checks passed. register(name, function() { if (hasMutatorDialog) { - if (!Blockly.Mutator) { + const Mutator = goog.module.get('Blockly.Mutator'); + if (!Mutator) { throw Error(errorPrefix + 'Missing require for Blockly.Mutator'); } - this.setMutator(new Blockly.Mutator(opt_blockList || [])); + this.setMutator(new Mutator(opt_blockList || [])); } // Mixin the object. this.mixin(mixinObj); @@ -331,13 +333,13 @@ const buildTooltipForDropdown = function(dropdownName, lookupTable) { // Check the tooltip string messages for invalid references. // Wait for load, in case Blockly.Msg is not yet populated. - // runAfterPageLoad() does not run in a Node.js environment due to lack of - // document object, in which case skip the validation. + // utils.runAfterPageLoad() does not run in a Node.js environment due to lack + // of document object, in which case skip the validation. if (typeof document == 'object') { // Relies on document.readyState - runAfterPageLoad(function() { + utils.runAfterPageLoad(function() { for (let key in lookupTable) { // Will print warnings if reference is missing. - checkMessageReferences(lookupTable[key]); + utils.checkMessageReferences(lookupTable[key]); } }); } @@ -366,7 +368,7 @@ const buildTooltipForDropdown = function(dropdownName, lookupTable) { console.warn(warning + '.'); } } else { - tooltip = replaceMessageReferences(tooltip); + tooltip = utils.replaceMessageReferences(tooltip); } return tooltip; }.bind(this)); @@ -411,12 +413,12 @@ const checkDropdownOptionsInTable = function(block, dropdownName, lookupTable) { const buildTooltipWithFieldText = function(msgTemplate, fieldName) { // Check the tooltip string messages for invalid references. // Wait for load, in case Blockly.Msg is not yet populated. - // runAfterPageLoad() does not run in a Node.js environment due to lack of - // document object, in which case skip the validation. + // utils.runAfterPageLoad() does not run in a Node.js environment due to lack + // of document object, in which case skip the validation. if (typeof document == 'object') { // Relies on document.readyState - runAfterPageLoad(function() { + utils.runAfterPageLoad(function() { // Will print warnings if reference is missing. - checkMessageReferences(msgTemplate); + utils.checkMessageReferences(msgTemplate); }); } @@ -427,7 +429,7 @@ const buildTooltipWithFieldText = function(msgTemplate, fieldName) { const extensionFn = function() { this.setTooltip(function() { const field = this.getField(fieldName); - return replaceMessageReferences(msgTemplate) + return utils.replaceMessageReferences(msgTemplate) .replace('%1', field ? field.getText() : ''); }.bind(this)); }; diff --git a/core/field.js b/core/field.js index 926e62008..79496526e 100644 --- a/core/field.js +++ b/core/field.js @@ -26,15 +26,15 @@ const Coordinate = goog.requireType('Blockly.utils.Coordinate'); const DropDownDiv = goog.require('Blockly.DropDownDiv'); const Events = goog.require('Blockly.Events'); /* eslint-disable-next-line no-unused-vars */ -const IASTNodeLocationSvg = goog.require('Blockly.IASTNodeLocationSvg'); +const IASTNodeLocationSvg = goog.requireType('Blockly.IASTNodeLocationSvg'); /* eslint-disable-next-line no-unused-vars */ -const IASTNodeLocationWithBlock = goog.require('Blockly.IASTNodeLocationWithBlock'); +const IASTNodeLocationWithBlock = goog.requireType('Blockly.IASTNodeLocationWithBlock'); /* eslint-disable-next-line no-unused-vars */ -const IKeyboardAccessible = goog.require('Blockly.IKeyboardAccessible'); -/* eslint-disable-next-line no-unused-vars */ -const IRegistrable = goog.require('Blockly.IRegistrable'); +const IKeyboardAccessible = goog.requireType('Blockly.IKeyboardAccessible'); /* eslint-disable-next-line no-unused-vars */ const Input = goog.requireType('Blockly.Input'); +/* eslint-disable-next-line no-unused-vars */ +const IRegistrable = goog.requireType('Blockly.IRegistrable'); const MarkerManager = goog.require('Blockly.MarkerManager'); const Rect = goog.require('Blockly.utils.Rect'); /* eslint-disable-next-line no-unused-vars */ @@ -45,12 +45,11 @@ const Tooltip = goog.require('Blockly.Tooltip'); const WidgetDiv = goog.require('Blockly.WidgetDiv'); /* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const dom = goog.require('Blockly.utils.dom'); +const browserEvents = goog.require('Blockly.browserEvents'); +const style = goog.require('Blockly.utils.style'); const userAgent = goog.require('Blockly.utils.userAgent'); -const {addClass, createSvgElement, getFastTextWidth, removeClass, removeNode} = goog.require('Blockly.utils.dom'); -/* eslint-disable-next-line no-unused-vars */ -const {conditionalBind, unbind, Data} = goog.require('Blockly.browserEvents'); -const {getPageOffset} = goog.require('Blockly.utils.style'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); /** @suppress {extraRequire} */ @@ -150,7 +149,7 @@ const Field = function(value, opt_validator, opt_config) { /** * Mouse down event listener data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.mouseDownWrapper_ = null; @@ -281,7 +280,7 @@ Field.prototype.SERIALIZABLE = false; Field.prototype.configure_ = function(config) { let tooltip = config['tooltip']; if (typeof tooltip == 'string') { - tooltip = replaceMessageReferences(config['tooltip']); + tooltip = utils.replaceMessageReferences(config['tooltip']); } tooltip && this.setTooltip(tooltip); @@ -331,7 +330,7 @@ Field.prototype.init = function() { // Field has already been initialized once. return; } - this.fieldGroup_ = createSvgElement(Svg.G, {}, null); + this.fieldGroup_ = dom.createSvgElement(Svg.G, {}, null); if (!this.isVisible()) { this.fieldGroup_.style.display = 'none'; } @@ -367,7 +366,7 @@ Field.prototype.initModel = function() {}; * @protected */ Field.prototype.createBorderRect_ = function() { - this.borderRect_ = createSvgElement( + this.borderRect_ = dom.createSvgElement( Svg.RECT, { 'rx': this.getConstants().FIELD_BORDER_RECT_RADIUS, 'ry': this.getConstants().FIELD_BORDER_RECT_RADIUS, @@ -387,7 +386,7 @@ Field.prototype.createBorderRect_ = function() { * @protected */ Field.prototype.createTextElement_ = function() { - this.textElement_ = createSvgElement( + this.textElement_ = dom.createSvgElement( Svg.TEXT, { 'class': 'blocklyText', }, @@ -406,7 +405,7 @@ Field.prototype.createTextElement_ = function() { */ Field.prototype.bindEvents_ = function() { Tooltip.bindMouseEvents(this.getClickTarget_()); - this.mouseDownWrapper_ = conditionalBind( + this.mouseDownWrapper_ = browserEvents.conditionalBind( this.getClickTarget_(), 'mousedown', this, this.onMouseDown_); }; @@ -443,10 +442,10 @@ Field.prototype.dispose = function() { Tooltip.unbindMouseEvents(this.getClickTarget_()); if (this.mouseDownWrapper_) { - unbind(this.mouseDownWrapper_); + browserEvents.unbind(this.mouseDownWrapper_); } - removeNode(this.fieldGroup_); + dom.removeNode(this.fieldGroup_); this.disposed = true; }; @@ -460,12 +459,12 @@ Field.prototype.updateEditable = function() { return; } if (this.enabled_ && this.sourceBlock_.isEditable()) { - addClass(group, 'blocklyEditableText'); - removeClass(group, 'blocklyNonEditableText'); + dom.addClass(group, 'blocklyEditableText'); + dom.removeClass(group, 'blocklyNonEditableText'); group.style.cursor = this.CURSOR; } else { - addClass(group, 'blocklyNonEditableText'); - removeClass(group, 'blocklyEditableText'); + dom.addClass(group, 'blocklyNonEditableText'); + dom.removeClass(group, 'blocklyEditableText'); group.style.cursor = ''; } }; @@ -643,7 +642,7 @@ Field.prototype.updateSize_ = function(opt_margin) { let contentWidth = 0; if (this.textElement_) { - contentWidth = getFastTextWidth( + contentWidth = dom.getFastTextWidth( this.textElement_, constants.FIELD_TEXT_FONTSIZE, constants.FIELD_TEXT_FONTWEIGHT, constants.FIELD_TEXT_FONTFAMILY); totalWidth += contentWidth; @@ -760,7 +759,7 @@ Field.prototype.getScaledBBox = function() { } } else { const bBox = this.borderRect_.getBoundingClientRect(); - xy = getPageOffset(this.borderRect_); + xy = style.getPageOffset(this.borderRect_); scaledWidth = bBox.width; scaledHeight = bBox.height; } @@ -1020,7 +1019,7 @@ Field.prototype.getClickTarget_ = function() { * @protected */ Field.prototype.getAbsoluteXY_ = function() { - return getPageOffset( + return style.getPageOffset( /** @type {!SVGRectElement} */ (this.getClickTarget_())); }; diff --git a/core/field_checkbox.js b/core/field_checkbox.js index d2ce60eaa..67362fd63 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -16,7 +16,7 @@ goog.module.declareLegacyNamespace(); const Field = goog.require('Blockly.Field'); const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); -const {inherits} = goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); @@ -48,7 +48,7 @@ const FieldCheckbox = function(opt_value, opt_validator, opt_config) { FieldCheckbox.superClass_.constructor.call( this, opt_value, opt_validator, opt_config); }; -inherits(FieldCheckbox, Field); +object.inherits(FieldCheckbox, Field); /** * The default value for this field. diff --git a/core/field_colour.js b/core/field_colour.js index a3dc0bf72..b4f53967d 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -20,12 +20,11 @@ const IdGenerator = goog.require('Blockly.utils.IdGenerator'); const KeyCodes = goog.require('Blockly.utils.KeyCodes'); const Size = goog.require('Blockly.utils.Size'); const aria = goog.require('Blockly.utils.aria'); +const browserEvents = goog.require('Blockly.browserEvents'); const colour = goog.require('Blockly.utils.colour'); +const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); -const {addClass, removeClass} = goog.require('Blockly.utils.dom'); -/* eslint-disable-next-line no-unused-vars */ -const {conditionalBind, unbind, Data} = goog.require('Blockly.browserEvents'); -const {inherits} = goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); @@ -65,40 +64,40 @@ const FieldColour = function(opt_value, opt_validator, opt_config) { /** * Mouse click event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onClickWrapper_ = null; /** * Mouse move event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onMouseMoveWrapper_ = null; /** * Mouse enter event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onMouseEnterWrapper_ = null; /** * Mouse leave event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onMouseLeaveWrapper_ = null; /** * Key down event data. - * @type {?Data} + * @type {?browserEvents.Data} * @private */ this.onKeyDownWrapper_ = null; }; -inherits(FieldColour, Field); +object.inherits(FieldColour, Field); /** * Construct a FieldColour from a JSON arg object. @@ -472,7 +471,7 @@ FieldColour.prototype.onMouseLeave_ = function() { this.picker_.blur(); const highlighted = this.getHighlighted_(); if (highlighted) { - removeClass(highlighted, 'blocklyColourHighlighted'); + dom.removeClass(highlighted, 'blocklyColourHighlighted'); } }; @@ -503,10 +502,10 @@ FieldColour.prototype.setHighlightedCell_ = function(cell, index) { // Unhighlight the current item. const highlighted = this.getHighlighted_(); if (highlighted) { - removeClass(highlighted, 'blocklyColourHighlighted'); + dom.removeClass(highlighted, 'blocklyColourHighlighted'); } // Highlight new item. - addClass(cell, 'blocklyColourHighlighted'); + dom.addClass(cell, 'blocklyColourHighlighted'); // Set new highlighted index. this.highlightedIndex_ = index; @@ -560,15 +559,15 @@ FieldColour.prototype.dropdownCreate_ = function() { // Configure event handler on the table to listen for any event in a cell. this.onClickWrapper_ = - conditionalBind(table, 'click', this, this.onClick_, true); - this.onMouseMoveWrapper_ = - conditionalBind(table, 'mousemove', this, this.onMouseMove_, true); - this.onMouseEnterWrapper_ = - conditionalBind(table, 'mouseenter', this, this.onMouseEnter_, true); - this.onMouseLeaveWrapper_ = - conditionalBind(table, 'mouseleave', this, this.onMouseLeave_, true); + browserEvents.conditionalBind(table, 'click', this, this.onClick_, true); + this.onMouseMoveWrapper_ = browserEvents.conditionalBind( + table, 'mousemove', this, this.onMouseMove_, true); + this.onMouseEnterWrapper_ = browserEvents.conditionalBind( + table, 'mouseenter', this, this.onMouseEnter_, true); + this.onMouseLeaveWrapper_ = browserEvents.conditionalBind( + table, 'mouseleave', this, this.onMouseLeave_, true); this.onKeyDownWrapper_ = - conditionalBind(table, 'keydown', this, this.onKeyDown_); + browserEvents.conditionalBind(table, 'keydown', this, this.onKeyDown_); this.picker_ = table; }; @@ -579,23 +578,23 @@ FieldColour.prototype.dropdownCreate_ = function() { */ FieldColour.prototype.dropdownDispose_ = function() { if (this.onClickWrapper_) { - unbind(this.onClickWrapper_); + browserEvents.unbind(this.onClickWrapper_); this.onClickWrapper_ = null; } if (this.onMouseMoveWrapper_) { - unbind(this.onMouseMoveWrapper_); + browserEvents.unbind(this.onMouseMoveWrapper_); this.onMouseMoveWrapper_ = null; } if (this.onMouseEnterWrapper_) { - unbind(this.onMouseEnterWrapper_); + browserEvents.unbind(this.onMouseEnterWrapper_); this.onMouseEnterWrapper_ = null; } if (this.onMouseLeaveWrapper_) { - unbind(this.onMouseLeaveWrapper_); + browserEvents.unbind(this.onMouseLeaveWrapper_); this.onMouseLeaveWrapper_ = null; } if (this.onKeyDownWrapper_) { - unbind(this.onKeyDownWrapper_); + browserEvents.unbind(this.onKeyDownWrapper_); this.onKeyDownWrapper_ = null; } this.picker_ = null; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index ddb5a4e18..effd6a31d 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -24,10 +24,10 @@ const Svg = goog.require('Blockly.utils.Svg'); const aria = goog.require('Blockly.utils.aria'); const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); +const object = goog.require('Blockly.utils.object'); const userAgent = goog.require('Blockly.utils.userAgent'); -const {commonWordPrefix, commonWordSuffix, shortestStringLength} = goog.require('Blockly.utils.string'); -const {inherits} = goog.require('Blockly.utils.object'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const utils = goog.require('Blockly.utils'); +const utilsString = goog.require('Blockly.utils.string'); /** @@ -130,7 +130,7 @@ const FieldDropdown = function(menuGenerator, opt_validator, opt_config) { */ this.svgArrow_ = null; }; -inherits(FieldDropdown, Field); +object.inherits(FieldDropdown, Field); /** * Dropdown image properties. @@ -405,10 +405,10 @@ FieldDropdown.prototype.trimOptions_ = function() { for (let i = 0; i < options.length; i++) { const label = options[i][0]; if (typeof label == 'string') { - options[i][0] = replaceMessageReferences(label); + options[i][0] = utils.replaceMessageReferences(label); } else { if (label.alt != null) { - options[i][0].alt = replaceMessageReferences(label.alt); + options[i][0].alt = utils.replaceMessageReferences(label.alt); } hasImages = true; } @@ -420,9 +420,9 @@ FieldDropdown.prototype.trimOptions_ = function() { for (let i = 0; i < options.length; i++) { strings.push(options[i][0]); } - const shortest = shortestStringLength(strings); - const prefixLength = commonWordPrefix(strings, shortest); - const suffixLength = commonWordSuffix(strings, shortest); + const shortest = utilsString.shortestStringLength(strings); + const prefixLength = utilsString.commonWordPrefix(strings, shortest); + const suffixLength = utilsString.commonWordSuffix(strings, shortest); if (!prefixLength && !suffixLength) { return; } diff --git a/core/field_image.js b/core/field_image.js index 9edc92c56..ff4460867 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -16,10 +16,10 @@ goog.module.declareLegacyNamespace(); const Field = goog.require('Blockly.Field'); const Size = goog.require('Blockly.utils.Size'); const Svg = goog.require('Blockly.utils.Svg'); +const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); -const {createSvgElement, XLINK_NS} = goog.require('Blockly.utils.dom'); -const {inherits} = goog.require('Blockly.utils.object'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @@ -45,9 +45,9 @@ const FieldImage = function( if (!src) { throw Error('Src value of an image field is required'); } - src = replaceMessageReferences(src); - const imageHeight = Number(replaceMessageReferences(height)); - const imageWidth = Number(replaceMessageReferences(width)); + src = utils.replaceMessageReferences(src); + const imageHeight = Number(utils.replaceMessageReferences(height)); + const imageWidth = Number(utils.replaceMessageReferences(width)); if (isNaN(imageHeight) || isNaN(imageWidth)) { throw Error( 'Height and width values of an image field must cast to' + @@ -78,7 +78,7 @@ const FieldImage = function( if (!opt_config) { // If the config wasn't passed, do old configuration. this.flipRtl_ = !!opt_flipRtl; - this.altText_ = replaceMessageReferences(opt_alt) || ''; + this.altText_ = utils.replaceMessageReferences(opt_alt) || ''; } // Initialize other properties. @@ -115,7 +115,7 @@ const FieldImage = function( */ this.imageElement_ = null; }; -inherits(FieldImage, Field); +object.inherits(FieldImage, Field); /** * The default value for this field. @@ -174,7 +174,7 @@ FieldImage.prototype.isDirty_ = false; FieldImage.prototype.configure_ = function(config) { FieldImage.superClass_.configure_.call(this, config); this.flipRtl_ = !!config['flipRtl']; - this.altText_ = replaceMessageReferences(config['alt']) || ''; + this.altText_ = utils.replaceMessageReferences(config['alt']) || ''; }; /** @@ -182,7 +182,7 @@ FieldImage.prototype.configure_ = function(config) { * @package */ FieldImage.prototype.initView = function() { - this.imageElement_ = createSvgElement( + this.imageElement_ = dom.createSvgElement( Svg.IMAGE, { 'height': this.imageHeight_ + 'px', 'width': this.size_.width + 'px', @@ -190,7 +190,7 @@ FieldImage.prototype.initView = function() { }, this.fieldGroup_); this.imageElement_.setAttributeNS( - XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_)); + dom.XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_)); if (this.clickHandler_) { this.imageElement_.style.cursor = 'pointer'; @@ -227,7 +227,7 @@ FieldImage.prototype.doValueUpdate_ = function(newValue) { this.value_ = newValue; if (this.imageElement_) { this.imageElement_.setAttributeNS( - XLINK_NS, 'xlink:href', String(this.value_)); + dom.XLINK_NS, 'xlink:href', String(this.value_)); } }; diff --git a/core/field_label.js b/core/field_label.js index 822d476ab..1a7480543 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -17,8 +17,8 @@ goog.module.declareLegacyNamespace(); const Field = goog.require('Blockly.Field'); const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); -const {inherits} = goog.require('Blockly.utils.object'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @@ -47,7 +47,7 @@ const FieldLabel = function(opt_value, opt_class, opt_config) { this.class_ = opt_class || null; } }; -inherits(FieldLabel, Field); +object.inherits(FieldLabel, Field); /** * The default value for this field. @@ -65,7 +65,7 @@ FieldLabel.prototype.DEFAULT_VALUE = ''; * @nocollapse */ FieldLabel.fromJson = function(options) { - const text = replaceMessageReferences(options['text']); + const text = utils.replaceMessageReferences(options['text']); // `this` might be a subclass of FieldLabel if that class doesn't override // the static fromJson method. return new this(text, undefined, options); diff --git a/core/field_label_serializable.js b/core/field_label_serializable.js index daabaa59f..dee9da1ef 100644 --- a/core/field_label_serializable.js +++ b/core/field_label_serializable.js @@ -16,8 +16,8 @@ goog.module.declareLegacyNamespace(); const FieldLabel = goog.require('Blockly.FieldLabel'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); -const {inherits} = goog.require('Blockly.utils.object'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @@ -37,7 +37,7 @@ const FieldLabelSerializable = function(opt_value, opt_class, opt_config) { FieldLabelSerializable.superClass_.constructor.call( this, opt_value, opt_class, opt_config); }; -inherits(FieldLabelSerializable, FieldLabel); +object.inherits(FieldLabelSerializable, FieldLabel); /** * Construct a FieldLabelSerializable from a JSON arg object, @@ -48,7 +48,7 @@ inherits(FieldLabelSerializable, FieldLabel); * @nocollapse */ FieldLabelSerializable.fromJson = function(options) { - const text = replaceMessageReferences(options['text']); + const text = utils.replaceMessageReferences(options['text']); // `this` might be a subclass of FieldLabelSerializable if that class doesn't // override the static fromJson method. return new this(text, undefined, options); diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 4842429a5..eee4f58c4 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -24,9 +24,9 @@ const WidgetDiv = goog.require('Blockly.WidgetDiv'); const aria = goog.require('Blockly.utils.aria'); const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); +const object = goog.require('Blockly.utils.object'); const userAgent = goog.require('Blockly.utils.userAgent'); -const {inherits} = goog.require('Blockly.utils.object'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const utils = goog.require('Blockly.utils'); /** @@ -70,7 +70,7 @@ const FieldMultilineInput = function(opt_value, opt_validator, opt_config) { */ this.isOverflowedY_ = false; }; -inherits(FieldMultilineInput, FieldTextInput); +object.inherits(FieldMultilineInput, FieldTextInput); /** * @override @@ -89,7 +89,7 @@ FieldMultilineInput.prototype.configure_ = function(config) { * @nocollapse */ FieldMultilineInput.fromJson = function(options) { - const text = replaceMessageReferences(options['text']); + const text = utils.replaceMessageReferences(options['text']); // `this` might be a subclass of FieldMultilineInput if that class doesn't // override the static fromJson method. return new this(text, undefined, options); diff --git a/core/field_number.js b/core/field_number.js index 8389f477f..4ed5ac5aa 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -15,8 +15,8 @@ goog.module.declareLegacyNamespace(); const FieldTextInput = goog.require('Blockly.FieldTextInput'); const aria = goog.require('Blockly.utils.aria'); -const {inherits} = goog.require('Blockly.utils.object'); -const {register} = goog.require('Blockly.fieldRegistry'); +const fieldRegistry = goog.require('Blockly.fieldRegistry'); +const object = goog.require('Blockly.utils.object'); /** @@ -74,7 +74,7 @@ const FieldNumber = function( this.setConstraints(opt_min, opt_max, opt_precision); } }; -inherits(FieldNumber, FieldTextInput); +object.inherits(FieldNumber, FieldTextInput); /** * The default value for this field. @@ -313,6 +313,6 @@ FieldNumber.prototype.widgetCreate_ = function() { return htmlInput; }; -register('field_number', FieldNumber); +fieldRegistry.register('field_number', FieldNumber); exports = FieldNumber; diff --git a/core/field_textinput.js b/core/field_textinput.js index cfa891e34..4b80e411b 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -13,6 +13,7 @@ goog.module('Blockly.FieldTextInput'); goog.module.declareLegacyNamespace(); +const Blockly = goog.require('Blockly'); /* eslint-disable-next-line no-unused-vars */ const BlockSvg = goog.requireType('Blockly.BlockSvg'); const Coordinate = goog.require('Blockly.utils.Coordinate'); @@ -28,10 +29,9 @@ const aria = goog.require('Blockly.utils.aria'); const browserEvents = goog.require('Blockly.browserEvents'); const dom = goog.require('Blockly.utils.dom'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); +const object = goog.require('Blockly.utils.object'); const userAgent = goog.require('Blockly.utils.userAgent'); -const {inherits} = goog.require('Blockly.utils.object'); -const {prompt: blocklyPrompt} = goog.require('Blockly'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); @@ -95,7 +95,7 @@ const FieldTextInput = function(opt_value, opt_validator, opt_config) { */ this.workspace_ = null; }; -inherits(FieldTextInput, Field); +object.inherits(FieldTextInput, Field); /** * The default value for this field. @@ -113,7 +113,7 @@ FieldTextInput.prototype.DEFAULT_VALUE = ''; * @nocollapse */ FieldTextInput.fromJson = function(options) { - const text = replaceMessageReferences(options['text']); + const text = utils.replaceMessageReferences(options['text']); // `this` might be a subclass of FieldTextInput if that class doesn't override // the static fromJson method. return new this(text, undefined, options); @@ -312,7 +312,7 @@ FieldTextInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) { * @private */ FieldTextInput.prototype.showPromptEditor_ = function() { - blocklyPrompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) { + Blockly.prompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) { this.setValue(this.getValueFromEditorText_(text)); }.bind(this)); }; diff --git a/core/field_variable.js b/core/field_variable.js index f700d4a99..e98db6f86 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -13,9 +13,12 @@ goog.module('Blockly.FieldVariable'); goog.module.declareLegacyNamespace(); +/* eslint-disable-next-line no-unused-vars */ const Block = goog.requireType('Blockly.Block'); const FieldDropdown = goog.require('Blockly.FieldDropdown'); +/* eslint-disable-next-line no-unused-vars */ const Menu = goog.requireType('Blockly.Menu'); +/* eslint-disable-next-line no-unused-vars */ const MenuItem = goog.requireType('Blockly.MenuItem'); const Msg = goog.require('Blockly.Msg'); const Size = goog.require('Blockly.utils.Size'); @@ -24,8 +27,8 @@ const Variables = goog.require('Blockly.Variables'); const Xml = goog.require('Blockly.Xml'); const fieldRegistry = goog.require('Blockly.fieldRegistry'); const internalConstants = goog.require('Blockly.internalConstants'); -const {inherits} = goog.require('Blockly.utils.object'); -const {replaceMessageReferences} = goog.require('Blockly.utils'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); @@ -86,7 +89,7 @@ const FieldVariable = function( this.setTypes_(opt_variableTypes, opt_defaultType); } }; -inherits(FieldVariable, FieldDropdown); +object.inherits(FieldVariable, FieldDropdown); /** * Construct a FieldVariable from a JSON arg object, @@ -98,7 +101,7 @@ inherits(FieldVariable, FieldDropdown); * @nocollapse */ FieldVariable.fromJson = function(options) { - const varName = replaceMessageReferences(options['variable']); + const varName = utils.replaceMessageReferences(options['variable']); // `this` might be a subclass of FieldVariable if that class doesn't override // the static fromJson method. return new this(varName, undefined, undefined, undefined, options); diff --git a/core/flyout_base.js b/core/flyout_base.js index 594d83a9f..c37d2a1ef 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -14,17 +14,19 @@ goog.module('Blockly.Flyout'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const Block = goog.require('Blockly.Block'); +const Block = goog.requireType('Blockly.Block'); +const Blockly = goog.require('Blockly'); /* eslint-disable-next-line no-unused-vars */ const BlockSvg = goog.requireType('Blockly.BlockSvg'); const ComponentManager = goog.require('Blockly.ComponentManager'); const Coordinate = goog.require('Blockly.utils.Coordinate'); const DeleteArea = goog.require('Blockly.DeleteArea'); const Events = goog.require('Blockly.Events'); -const FlyoutButton = goog.require('Blockly.FlyoutButton'); +/* eslint-disable-next-line no-unused-vars */ +const FlyoutButton = goog.requireType('Blockly.FlyoutButton'); const FlyoutMetricsManager = goog.require('Blockly.FlyoutMetricsManager'); /* eslint-disable-next-line no-unused-vars */ -const IFlyout = goog.require('Blockly.IFlyout'); +const IFlyout = goog.requireType('Blockly.IFlyout'); /* eslint-disable-next-line no-unused-vars */ const Options = goog.requireType('Blockly.Options'); const ScrollbarPair = goog.require('Blockly.ScrollbarPair'); @@ -38,7 +40,6 @@ const dom = goog.require('Blockly.utils.dom'); const toolbox = goog.require('Blockly.utils.toolbox'); const utils = goog.require('Blockly.utils'); const utilsXml = goog.require('Blockly.utils.xml'); -const {hideChaff} = goog.require('Blockly'); /** @suppress {extraRequire} */ goog.require('Blockly.blockRendering'); /** @suppress {extraRequire} */ @@ -659,6 +660,7 @@ Flyout.prototype.getDynamicCategoryContents_ = function(categoryName) { * @private */ Flyout.prototype.createButton_ = function(btnInfo, isLabel) { + const FlyoutButton = goog.module.get('Blockly.FlyoutButton'); if (!FlyoutButton) { throw Error('Missing require for Blockly.FlyoutButton'); } @@ -854,7 +856,7 @@ Flyout.prototype.createBlock = function(originalBlock) { } // Close the flyout. - hideChaff(); + Blockly.hideChaff(); const newVariables = Variables.getAddedVariables( this.targetWorkspace, variablesBeforeCreation); diff --git a/core/flyout_button.js b/core/flyout_button.js index 643790d9f..7bb5a3e88 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -10,42 +10,44 @@ */ 'use strict'; -goog.provide('Blockly.FlyoutButton'); +goog.module('Blockly.FlyoutButton'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.Css'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.style'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.utils.toolbox'); -goog.requireType('Blockly.WorkspaceSvg'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Css = goog.require('Blockly.Css'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const style = goog.require('Blockly.utils.style'); +/* eslint-disable-next-line no-unused-vars */ +const toolbox = goog.requireType('Blockly.utils.toolbox'); +const utils = goog.require('Blockly.utils'); /** * Class for a button in the flyout. - * @param {!Blockly.WorkspaceSvg} workspace The workspace in which to place this + * @param {!WorkspaceSvg} workspace The workspace in which to place this * button. - * @param {!Blockly.WorkspaceSvg} targetWorkspace The flyout's target workspace. - * @param {!Blockly.utils.toolbox.ButtonOrLabelInfo} json + * @param {!WorkspaceSvg} targetWorkspace The flyout's target workspace. + * @param {!toolbox.ButtonOrLabelInfo} json * The JSON specifying the label/button. * @param {boolean} isLabel Whether this button should be styled as a label. * @constructor * @package */ -Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) { +const FlyoutButton = function(workspace, targetWorkspace, json, isLabel) { // Labels behave the same as buttons, but are styled differently. /** - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.workspace_ = workspace; /** - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.targetWorkspace_ = targetWorkspace; @@ -57,10 +59,10 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) { this.text_ = json['text']; /** - * @type {!Blockly.utils.Coordinate} + * @type {!Coordinate} * @private */ - this.position_ = new Blockly.utils.Coordinate(0, 0); + this.position_ = new Coordinate(0, 0); /** * Whether this button should be styled as a label. @@ -75,8 +77,8 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) { * @private */ this.callbackKey_ = json['callbackKey'] || - /* Check the lower case version too to satisfy IE */ - json['callbackkey']; + /* Check the lower case version too to satisfy IE */ + json['callbackkey']; /** * If specified, a CSS class to add to this button. @@ -87,14 +89,14 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) { /** * Mouse up event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ this.onMouseUpWrapper_ = null; /** * The JSON specifying the label / button. - * @type {!Blockly.utils.toolbox.ButtonOrLabelInfo} + * @type {!toolbox.ButtonOrLabelInfo} */ this.info = json; }; @@ -102,69 +104,70 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) { /** * The horizontal margin around the text in the button. */ -Blockly.FlyoutButton.MARGIN_X = 5; +FlyoutButton.MARGIN_X = 5; /** * The vertical margin around the text in the button. */ -Blockly.FlyoutButton.MARGIN_Y = 2; +FlyoutButton.MARGIN_Y = 2; /** * The width of the button's rect. * @type {number} */ -Blockly.FlyoutButton.prototype.width = 0; +FlyoutButton.prototype.width = 0; /** * The height of the button's rect. * @type {number} */ -Blockly.FlyoutButton.prototype.height = 0; +FlyoutButton.prototype.height = 0; /** * Create the button elements. * @return {!SVGElement} The button's SVG group. */ -Blockly.FlyoutButton.prototype.createDom = function() { - var cssClass = this.isLabel_ ? 'blocklyFlyoutLabel' : 'blocklyFlyoutButton'; +FlyoutButton.prototype.createDom = function() { + let cssClass = this.isLabel_ ? 'blocklyFlyoutLabel' : 'blocklyFlyoutButton'; if (this.cssClass_) { cssClass += ' ' + this.cssClass_; } - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, {'class': cssClass}, - this.workspace_.getCanvas()); + this.svgGroup_ = dom.createSvgElement( + Svg.G, {'class': cssClass}, this.workspace_.getCanvas()); + let shadow; if (!this.isLabel_) { // Shadow rectangle (light source does not mirror in RTL). - var shadow = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { + shadow = dom.createSvgElement( + Svg.RECT, { 'class': 'blocklyFlyoutButtonShadow', - 'rx': 4, 'ry': 4, 'x': 1, 'y': 1 + 'rx': 4, + 'ry': 4, + 'x': 1, + 'y': 1 }, this.svgGroup_); } // Background rectangle. - var rect = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - 'class': this.isLabel_ ? - 'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground', - 'rx': 4, 'ry': 4 + const rect = dom.createSvgElement( + Svg.RECT, { + 'class': this.isLabel_ ? 'blocklyFlyoutLabelBackground' : + 'blocklyFlyoutButtonBackground', + 'rx': 4, + 'ry': 4 }, this.svgGroup_); - var svgText = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TEXT, - { + const svgText = dom.createSvgElement( + Svg.TEXT, { 'class': this.isLabel_ ? 'blocklyFlyoutLabelText' : 'blocklyText', 'x': 0, 'y': 0, 'text-anchor': 'middle' }, this.svgGroup_); - var text = Blockly.utils.replaceMessageReferences(this.text_); + let text = utils.replaceMessageReferences(this.text_); if (this.workspace_.RTL) { // Force text to be RTL by adding an RLM. text += '\u200F'; @@ -172,22 +175,22 @@ Blockly.FlyoutButton.prototype.createDom = function() { svgText.textContent = text; if (this.isLabel_) { this.svgText_ = svgText; - this.workspace_.getThemeManager().subscribe(this.svgText_, - 'flyoutForegroundColour', 'fill'); + this.workspace_.getThemeManager().subscribe( + this.svgText_, 'flyoutForegroundColour', 'fill'); } - var fontSize = Blockly.utils.style.getComputedStyle(svgText, 'fontSize'); - var fontWeight = Blockly.utils.style.getComputedStyle(svgText, 'fontWeight'); - var fontFamily = Blockly.utils.style.getComputedStyle(svgText, 'fontFamily'); - this.width = Blockly.utils.dom.getFastTextWidthWithSizeString(svgText, - fontSize, fontWeight, fontFamily); - var fontMetrics = Blockly.utils.dom.measureFontMetrics(text, fontSize, - fontWeight, fontFamily); + const fontSize = style.getComputedStyle(svgText, 'fontSize'); + const fontWeight = style.getComputedStyle(svgText, 'fontWeight'); + const fontFamily = style.getComputedStyle(svgText, 'fontFamily'); + this.width = dom.getFastTextWidthWithSizeString( + svgText, fontSize, fontWeight, fontFamily); + const fontMetrics = + dom.measureFontMetrics(text, fontSize, fontWeight, fontFamily); this.height = fontMetrics.height; if (!this.isLabel_) { - this.width += 2 * Blockly.FlyoutButton.MARGIN_X; - this.height += 2 * Blockly.FlyoutButton.MARGIN_Y; + this.width += 2 * FlyoutButton.MARGIN_X; + this.height += 2 * FlyoutButton.MARGIN_Y; shadow.setAttribute('width', this.width); shadow.setAttribute('height', this.height); } @@ -195,12 +198,12 @@ Blockly.FlyoutButton.prototype.createDom = function() { rect.setAttribute('height', this.height); svgText.setAttribute('x', this.width / 2); - svgText.setAttribute('y', this.height / 2 - fontMetrics.height / 2 + - fontMetrics.baseline); + svgText.setAttribute( + 'y', this.height / 2 - fontMetrics.height / 2 + fontMetrics.baseline); this.updateTransform_(); - this.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind( + this.onMouseUpWrapper_ = browserEvents.conditionalBind( this.svgGroup_, 'mouseup', this, this.onMouseUp_); return this.svgGroup_; }; @@ -208,7 +211,7 @@ Blockly.FlyoutButton.prototype.createDom = function() { /** * Correctly position the flyout button and make it visible. */ -Blockly.FlyoutButton.prototype.show = function() { +FlyoutButton.prototype.show = function() { this.updateTransform_(); this.svgGroup_.setAttribute('display', 'block'); }; @@ -217,8 +220,9 @@ Blockly.FlyoutButton.prototype.show = function() { * Update SVG attributes to match internal state. * @private */ -Blockly.FlyoutButton.prototype.updateTransform_ = function() { - this.svgGroup_.setAttribute('transform', +FlyoutButton.prototype.updateTransform_ = function() { + this.svgGroup_.setAttribute( + 'transform', 'translate(' + this.position_.x + ',' + this.position_.y + ')'); }; @@ -227,7 +231,7 @@ Blockly.FlyoutButton.prototype.updateTransform_ = function() { * @param {number} x The new x coordinate. * @param {number} y The new y coordinate. */ -Blockly.FlyoutButton.prototype.moveTo = function(x, y) { +FlyoutButton.prototype.moveTo = function(x, y) { this.position_.x = x; this.position_.y = y; this.updateTransform_(); @@ -236,44 +240,44 @@ Blockly.FlyoutButton.prototype.moveTo = function(x, y) { /** * @return {boolean} Whether or not the button is a label. */ -Blockly.FlyoutButton.prototype.isLabel = function() { +FlyoutButton.prototype.isLabel = function() { return this.isLabel_; }; /** * Location of the button. - * @return {!Blockly.utils.Coordinate} x, y coordinates. + * @return {!Coordinate} x, y coordinates. * @package */ -Blockly.FlyoutButton.prototype.getPosition = function() { +FlyoutButton.prototype.getPosition = function() { return this.position_; }; /** * @return {string} Text of the button. */ -Blockly.FlyoutButton.prototype.getButtonText = function() { +FlyoutButton.prototype.getButtonText = function() { return this.text_; }; /** * Get the button's target workspace. - * @return {!Blockly.WorkspaceSvg} The target workspace of the flyout where this + * @return {!WorkspaceSvg} The target workspace of the flyout where this * button resides. */ -Blockly.FlyoutButton.prototype.getTargetWorkspace = function() { +FlyoutButton.prototype.getTargetWorkspace = function() { return this.targetWorkspace_; }; /** * Dispose of this button. */ -Blockly.FlyoutButton.prototype.dispose = function() { +FlyoutButton.prototype.dispose = function() { if (this.onMouseUpWrapper_) { - Blockly.browserEvents.unbind(this.onMouseUpWrapper_); + browserEvents.unbind(this.onMouseUpWrapper_); } if (this.svgGroup_) { - Blockly.utils.dom.removeNode(this.svgGroup_); + dom.removeNode(this.svgGroup_); } if (this.svgText_) { this.workspace_.getThemeManager().unsubscribe(this.svgText_); @@ -285,16 +289,18 @@ Blockly.FlyoutButton.prototype.dispose = function() { * @param {!Event} e Mouse up event. * @private */ -Blockly.FlyoutButton.prototype.onMouseUp_ = function(e) { - var gesture = this.targetWorkspace_.getGesture(e); +FlyoutButton.prototype.onMouseUp_ = function(e) { + const gesture = this.targetWorkspace_.getGesture(e); if (gesture) { gesture.cancel(); } if (this.isLabel_ && this.callbackKey_) { console.warn('Labels should not have callbacks. Label text: ' + this.text_); - } else if (!this.isLabel_ && !(this.callbackKey_ && - this.targetWorkspace_.getButtonCallback(this.callbackKey_))) { + } else if ( + !this.isLabel_ && + !(this.callbackKey_ && + this.targetWorkspace_.getButtonCallback(this.callbackKey_))) { console.warn('Buttons should have callbacks. Button text: ' + this.text_); } else if (!this.isLabel_) { this.targetWorkspace_.getButtonCallback(this.callbackKey_)(this); @@ -304,7 +310,7 @@ Blockly.FlyoutButton.prototype.onMouseUp_ = function(e) { /** * CSS for buttons and labels. See css.js for use. */ -Blockly.Css.register([ +Css.register([ /* eslint-disable indent */ '.blocklyFlyoutButton {', 'fill: #888;', @@ -328,3 +334,5 @@ Blockly.Css.register([ '}', /* eslint-enable indent */ ]); + +exports = FlyoutButton; diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index 7f1ad72fd..b1c611215 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -22,10 +22,10 @@ const Options = goog.requireType('Blockly.Options'); const Rect = goog.require('Blockly.utils.Rect'); const Scrollbar = goog.require('Blockly.Scrollbar'); const WidgetDiv = goog.require('Blockly.WidgetDiv'); +const object = goog.require('Blockly.utils.object'); const registry = goog.require('Blockly.registry'); -const {Position} = goog.require('Blockly.utils.toolbox'); -const {getScrollDeltaPixels} = goog.require('Blockly.utils'); -const {inherits} = goog.require('Blockly.utils.object'); +const toolbox = goog.require('Blockly.utils.toolbox'); +const utils = goog.require('Blockly.utils'); /** @@ -39,7 +39,7 @@ const HorizontalFlyout = function(workspaceOptions) { HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions); this.horizontalLayout = true; }; -inherits(HorizontalFlyout, Flyout); +object.inherits(HorizontalFlyout, Flyout); /** * Sets the translation of the flyout to match the scrollbars. @@ -92,7 +92,7 @@ HorizontalFlyout.prototype.getY = function() { const toolboxMetrics = metricsManager.getToolboxMetrics(); let y = 0; - const atTop = this.toolboxPosition_ == Position.TOP; + const atTop = this.toolboxPosition_ == toolbox.Position.TOP; // If this flyout is not the trashcan flyout (e.g. toolbox or mutator). if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) { // If there is a category toolbox. @@ -159,7 +159,7 @@ HorizontalFlyout.prototype.position = function() { * @private */ HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) { - const atTop = this.toolboxPosition_ == Position.TOP; + const atTop = this.toolboxPosition_ == toolbox.Position.TOP; // Start at top left. const path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)]; @@ -210,7 +210,7 @@ HorizontalFlyout.prototype.scrollToStart = function() { * @protected */ HorizontalFlyout.prototype.wheel_ = function(e) { - const scrollDelta = getScrollDeltaPixels(e); + const scrollDelta = utils.getScrollDeltaPixels(e); const delta = scrollDelta.x || scrollDelta.y; if (delta) { @@ -326,7 +326,7 @@ HorizontalFlyout.prototype.getClientRect = function() { const BIG_NUM = 1000000000; const top = flyoutRect.top; - if (this.toolboxPosition_ == Position.TOP) { + if (this.toolboxPosition_ == toolbox.Position.TOP) { const height = flyoutRect.height; return new Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM); } else { // Bottom. @@ -335,7 +335,7 @@ HorizontalFlyout.prototype.getClientRect = function() { }; /** - * Compute height of flyout. Position mat under each block. + * Compute height of flyout. toolbox.Position mat under each block. * For RTL: Lay out the blocks right-aligned. * @protected */ @@ -362,7 +362,7 @@ HorizontalFlyout.prototype.reflowInternal_ = function() { } if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ && - this.toolboxPosition_ == Position.TOP && + this.toolboxPosition_ == toolbox.Position.TOP && !this.targetWorkspace.getToolbox()) { // This flyout is a simple toolbox. Reposition the workspace so that (0,0) // is in the correct position relative to the new absolute edge (ie diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 2091d1321..5b396c061 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -22,10 +22,10 @@ const Options = goog.requireType('Blockly.Options'); const Rect = goog.require('Blockly.utils.Rect'); const Scrollbar = goog.require('Blockly.Scrollbar'); const WidgetDiv = goog.require('Blockly.WidgetDiv'); +const object = goog.require('Blockly.utils.object'); const registry = goog.require('Blockly.registry'); -const {Position} = goog.require('Blockly.utils.toolbox'); -const {getScrollDeltaPixels} = goog.require('Blockly.utils'); -const {inherits} = goog.require('Blockly.utils.object'); +const toolbox = goog.require('Blockly.utils.toolbox'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Block'); /** @suppress {extraRequire} */ @@ -42,7 +42,7 @@ goog.require('Blockly.constants'); const VerticalFlyout = function(workspaceOptions) { VerticalFlyout.superClass_.constructor.call(this, workspaceOptions); }; -inherits(VerticalFlyout, Flyout); +object.inherits(VerticalFlyout, Flyout); /** * The name of the vertical flyout in the registry. @@ -94,14 +94,14 @@ VerticalFlyout.prototype.getX = function() { if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) { // If there is a category toolbox. if (this.targetWorkspace.getToolbox()) { - if (this.toolboxPosition_ == Position.LEFT) { + if (this.toolboxPosition_ == toolbox.Position.LEFT) { x = toolboxMetrics.width; } else { x = viewMetrics.width - this.width_; } // Simple (flyout-only) toolbox. } else { - if (this.toolboxPosition_ == Position.LEFT) { + if (this.toolboxPosition_ == toolbox.Position.LEFT) { x = 0; } else { // The simple flyout does not cover the workspace. @@ -110,7 +110,7 @@ VerticalFlyout.prototype.getX = function() { } // Trashcan flyout is opposite the main flyout. } else { - if (this.toolboxPosition_ == Position.LEFT) { + if (this.toolboxPosition_ == toolbox.Position.LEFT) { x = 0; } else { // Because the anchor point of the flyout is on the left, but we want @@ -165,7 +165,7 @@ VerticalFlyout.prototype.position = function() { * @private */ VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) { - const atRight = this.toolboxPosition_ == Position.RIGHT; + const atRight = this.toolboxPosition_ == toolbox.Position.RIGHT; const totalWidth = width + this.CORNER_RADIUS; // Decide whether to start on the left or right. @@ -201,7 +201,7 @@ VerticalFlyout.prototype.scrollToStart = function() { * @protected */ VerticalFlyout.prototype.wheel_ = function(e) { - const scrollDelta = getScrollDeltaPixels(e); + const scrollDelta = utils.getScrollDeltaPixels(e); if (scrollDelta.y) { const metricsManager = this.workspace_.getMetricsManager(); @@ -306,7 +306,7 @@ VerticalFlyout.prototype.getClientRect = function() { const BIG_NUM = 1000000000; const left = flyoutRect.left; - if (this.toolboxPosition_ == Position.LEFT) { + if (this.toolboxPosition_ == toolbox.Position.LEFT) { const width = flyoutRect.width; return new Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width); } else { // Right @@ -315,7 +315,7 @@ VerticalFlyout.prototype.getClientRect = function() { }; /** - * Compute width of flyout. Position mat under each block. + * Compute width of flyout. toolbox.Position mat under each block. * For RTL: Lay out the blocks and buttons to be right-aligned. * @protected */ @@ -363,7 +363,7 @@ VerticalFlyout.prototype.reflowInternal_ = function() { } if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ && - this.toolboxPosition_ == Position.LEFT && + this.toolboxPosition_ == toolbox.Position.LEFT && !this.targetWorkspace.getToolbox()) { // This flyout is a simple toolbox. Reposition the workspace so that (0,0) // is in the correct position relative to the new absolute edge (ie diff --git a/core/generator.js b/core/generator.js index 112c2f8a1..9984f186f 100644 --- a/core/generator.js +++ b/core/generator.js @@ -20,9 +20,9 @@ const Block = goog.requireType('Blockly.Block'); const Names = goog.requireType('Blockly.Names'); /* eslint-disable-next-line no-unused-vars */ const Workspace = goog.requireType('Blockly.Workspace'); -const internalConstants = goog.require('Blockly.internalConstants'); +const common = goog.require('Blockly.common'); const deprecation = goog.require('Blockly.utils.deprecation'); -const {getMainWorkspace} = goog.require('Blockly'); +const internalConstants = goog.require('Blockly.internalConstants'); /** @@ -98,7 +98,7 @@ Generator.prototype.workspaceToCode = function(workspace) { if (!workspace) { // Backwards compatibility from before there could be multiple workspaces. console.warn('No workspace specified in workspaceToCode call. Guessing.'); - workspace = getMainWorkspace(); + workspace = common.getMainWorkspace(); } let code = []; this.init(workspace); diff --git a/core/gesture.js b/core/gesture.js index 933930e44..855dc76de 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -20,8 +20,8 @@ goog.module.declareLegacyNamespace(); const BlockSvg = goog.requireType('Blockly.BlockSvg'); const BubbleDragger = goog.require('Blockly.BubbleDragger'); const Coordinate = goog.require('Blockly.utils.Coordinate'); -/* eslint-disable-next-line no-unused-vars */ const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ const Field = goog.requireType('Blockly.Field'); /* eslint-disable-next-line no-unused-vars */ const IBlockDragger = goog.requireType('Blockly.IBlockDragger'); @@ -31,8 +31,8 @@ const IBubble = goog.requireType('Blockly.IBubble'); const IFlyout = goog.requireType('Blockly.IFlyout'); const Tooltip = goog.require('Blockly.Tooltip'); const Touch = goog.require('Blockly.Touch'); -/* eslint-disable-next-line no-unused-vars */ const Workspace = goog.require('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); const WorkspaceDragger = goog.require('Blockly.WorkspaceDragger'); const blockAnimations = goog.require('Blockly.blockAnimations'); @@ -113,7 +113,7 @@ const Gesture = function(e, creatorWorkspace) { /** * The workspace that the gesture started on. There may be multiple * workspaces on a page; this is more accurate than using - * Blockly.getMainWorkspace(). + * Blockly.common.getMainWorkspace(). * @type {WorkspaceSvg} * @protected */ diff --git a/core/icon.js b/core/icon.js index 69ff3ef37..cae1d8b6c 100644 --- a/core/icon.js +++ b/core/icon.js @@ -22,7 +22,7 @@ const Size = goog.require('Blockly.utils.Size'); const Svg = goog.require('Blockly.utils.Svg'); const browserEvents = goog.require('Blockly.browserEvents'); const dom = goog.require('Blockly.utils.dom'); -const {getRelativeXY, isRightButton} = goog.require('Blockly.utils'); +const utils = goog.require('Blockly.utils'); /** @@ -135,7 +135,7 @@ Icon.prototype.iconClick_ = function(e) { // Drag operation is concluding. Don't open the editor. return; } - if (!this.block_.isInFlyout && !isRightButton(e)) { + if (!this.block_.isInFlyout && !utils.isRightButton(e)) { this.setVisible(!this.isVisible()); } }; @@ -167,7 +167,7 @@ Icon.prototype.setIconLocation = function(xy) { Icon.prototype.computeIconLocation = function() { // Find coordinates for the centre of the icon and update the arrow. const blockXY = this.block_.getRelativeToSurfaceXY(); - const iconXY = getRelativeXY( + const iconXY = utils.getRelativeXY( /** @type {!SVGElement} */ (this.iconGroup_)); const newXY = new Coordinate( blockXY.x + iconXY.x + this.SIZE / 2, diff --git a/core/inject.js b/core/inject.js index 0b7590824..62be9633e 100644 --- a/core/inject.js +++ b/core/inject.js @@ -14,6 +14,7 @@ goog.provide('Blockly.inject'); goog.require('Blockly.BlockDragSurfaceSvg'); goog.require('Blockly.browserEvents'); +goog.require('Blockly.common'); goog.require('Blockly.Css'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Events'); @@ -33,7 +34,9 @@ goog.require('Blockly.WorkspaceDragSurfaceSvg'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.WidgetDiv'); +goog.requireType('Blockly.BlocklyOptions'); goog.requireType('Blockly.BlockSvg'); +goog.requireType('Blockly.WorkspaceCommentSvg'); /** @@ -44,8 +47,6 @@ goog.requireType('Blockly.BlockSvg'); * @return {!Blockly.WorkspaceSvg} Newly created main workspace. */ Blockly.inject = function(container, opt_options) { - Blockly.checkBlockColourConstants(); - if (typeof container == 'string') { container = document.getElementById(container) || document.querySelector(container); @@ -77,12 +78,12 @@ Blockly.inject = function(container, opt_options) { Blockly.init_(workspace); // Keep focus on the first workspace so entering keyboard navigation looks correct. - Blockly.mainWorkspace = workspace; + Blockly.common.setMainWorkspace(workspace); Blockly.svgResize(workspace); subContainer.addEventListener('focusin', function() { - Blockly.mainWorkspace = workspace; + Blockly.common.setMainWorkspace(workspace); }); return workspace; @@ -215,7 +216,9 @@ Blockly.extractObjectFromEvent_ = function(workspace, e) { break; case Blockly.Events.COMMENT_CREATE: case Blockly.Events.COMMENT_MOVE: - object = workspace.getCommentById(e.commentId); + object = ( + /** @type {?Blockly.WorkspaceCommentSvg} */ + (workspace.getCommentById(e.commentId))); break; } return object; @@ -439,7 +442,7 @@ Blockly.inject.bindDocumentEvents_ = function() { window, 'orientationchange', document, function() { // TODO (#397): Fix for multiple Blockly workspaces. Blockly.svgResize(/** @type {!Blockly.WorkspaceSvg} */ - (Blockly.getMainWorkspace())); + (Blockly.common.getMainWorkspace())); }); } } diff --git a/core/input.js b/core/input.js index afa7a3358..9eb3892f8 100644 --- a/core/input.js +++ b/core/input.js @@ -18,7 +18,7 @@ const Block = goog.requireType('Blockly.Block'); /* eslint-disable-next-line no-unused-vars */ const BlockSvg = goog.requireType('Blockly.BlockSvg'); /* eslint-disable-next-line no-unused-vars */ -const Connection = goog.require('Blockly.Connection'); +const Connection = goog.requireType('Blockly.Connection'); /* eslint-disable-next-line no-unused-vars */ const Field = goog.requireType('Blockly.Field'); /* eslint-disable-next-line no-unused-vars */ diff --git a/core/input_types.js b/core/input_types.js index a58706358..8bdc9e504 100644 --- a/core/input_types.js +++ b/core/input_types.js @@ -11,19 +11,22 @@ 'use strict'; -goog.provide('Blockly.inputTypes'); +goog.module('Blockly.inputTypes'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.connectionTypes'); +const connectionTypes = goog.require('Blockly.connectionTypes'); /** * Enum for the type of a connection or input. * @enum {number} */ -Blockly.inputTypes = { +const inputTypes = { // A right-facing value input. E.g. 'set item to' or 'return'. - VALUE: Blockly.connectionTypes.INPUT_VALUE, + VALUE: connectionTypes.INPUT_VALUE, // A down-facing block stack. E.g. 'if-do' or 'else'. - STATEMENT: Blockly.connectionTypes.NEXT_STATEMENT, + STATEMENT: connectionTypes.NEXT_STATEMENT, // A dummy input. Used to add field(s) with no input. DUMMY: 5 }; + +exports = inputTypes; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 614f7e70b..41be57fff 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -10,34 +10,45 @@ */ 'use strict'; -goog.provide('Blockly.InsertionMarkerManager'); +goog.module('Blockly.InsertionMarkerManager'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockAnimations'); -goog.require('Blockly.ComponentManager'); -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.Events'); -goog.require('Blockly.internalConstants'); - -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.RenderedConnection'); -goog.requireType('Blockly.utils.Coordinate'); -goog.requireType('Blockly.WorkspaceSvg'); +// TODO(#5073): Add Blockly require after fixing circular dependency. +// goog.require('Blockly'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const ComponentManager = goog.require('Blockly.ComponentManager'); +/* eslint-disable-next-line no-unused-vars */ +const Coordinate = goog.requireType('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const IDeleteArea = goog.requireType('Blockly.IDeleteArea'); +/* eslint-disable-next-line no-unused-vars */ +const IDragTarget = goog.requireType('Blockly.IDragTarget'); +/* eslint-disable-next-line no-unused-vars */ +const RenderedConnection = goog.requireType('Blockly.RenderedConnection'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const blockAnimations = goog.require('Blockly.blockAnimations'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const constants = goog.require('Blockly.constants'); +const internalConstants = goog.require('Blockly.internalConstants'); /** * Class that controls updates to connections during drags. It is primarily * responsible for finding the closest eligible connection and highlighting or * unhiglighting it as needed during a drag. - * @param {!Blockly.BlockSvg} block The top block in the stack being dragged. + * @param {!BlockSvg} block The top block in the stack being dragged. * @constructor */ -Blockly.InsertionMarkerManager = function(block) { +const InsertionMarkerManager = function(block) { Blockly.selected = block; /** * The top block in the stack being dragged. * Does not change during a drag. - * @type {!Blockly.BlockSvg} + * @type {!BlockSvg} * @private */ this.topBlock_ = block; @@ -45,7 +56,7 @@ Blockly.InsertionMarkerManager = function(block) { /** * The workspace on which these connections are being dragged. * Does not change during a drag. - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.workspace_ = block.workspace; @@ -54,7 +65,7 @@ Blockly.InsertionMarkerManager = function(block) { * The last connection on the stack, if it's not the last connection on the * first block. * Set in initAvailableConnections, if at all. - * @type {Blockly.RenderedConnection} + * @type {RenderedConnection} * @private */ this.lastOnStack_ = null; @@ -63,7 +74,7 @@ Blockly.InsertionMarkerManager = function(block) { * The insertion marker corresponding to the last block in the stack, if * that's not the same as the first block in the stack. * Set in initAvailableConnections, if at all - * @type {Blockly.BlockSvg} + * @type {BlockSvg} * @private */ this.lastMarker_ = null; @@ -71,7 +82,7 @@ Blockly.InsertionMarkerManager = function(block) { /** * The insertion marker that shows up between blocks to show where a block * would go if dropped immediately. - * @type {Blockly.BlockSvg} + * @type {BlockSvg} * @private */ this.firstMarker_ = this.createMarkerBlock_(this.topBlock_); @@ -80,7 +91,7 @@ Blockly.InsertionMarkerManager = function(block) { * The connection that this block would connect to if released immediately. * Updated on every mouse move. * This is not on any of the blocks that are being dragged. - * @type {Blockly.RenderedConnection} + * @type {RenderedConnection} * @private */ this.closestConnection_ = null; @@ -91,7 +102,7 @@ Blockly.InsertionMarkerManager = function(block) { * Updated on every mouse move. * This is on the top block that is being dragged or the last block in the * dragging stack. - * @type {Blockly.RenderedConnection} + * @type {RenderedConnection} * @private */ this.localConnection_ = null; @@ -107,21 +118,21 @@ Blockly.InsertionMarkerManager = function(block) { /** * Connection on the insertion marker block that corresponds to * this.localConnection_ on the currently dragged block. - * @type {Blockly.RenderedConnection} + * @type {RenderedConnection} * @private */ this.markerConnection_ = null; /** * The block that currently has an input being highlighted, or null. - * @type {Blockly.BlockSvg} + * @type {BlockSvg} * @private */ this.highlightedBlock_ = null; /** * The block being faded to indicate replacement, or null. - * @type {Blockly.BlockSvg} + * @type {BlockSvg} * @private */ this.fadedBlock_ = null; @@ -131,7 +142,7 @@ Blockly.InsertionMarkerManager = function(block) { * other blocks. This includes all open connections on the top block, as well * as the last connection on the block stack. * Does not change during a drag. - * @type {!Array} + * @type {!Array} * @private */ this.availableConnections_ = this.initAvailableConnections_(); @@ -142,7 +153,7 @@ Blockly.InsertionMarkerManager = function(block) { * could display. * @enum {number} */ -Blockly.InsertionMarkerManager.PREVIEW_TYPE = { +InsertionMarkerManager.PREVIEW_TYPE = { INSERTION_MARKER: 0, INPUT_OUTLINE: 1, REPLACEMENT_FADE: 2, @@ -154,7 +165,7 @@ Blockly.InsertionMarkerManager.PREVIEW_TYPE = { * @type {string} * @const */ -Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR = 'The insertion marker ' + +InsertionMarkerManager.DUPLICATE_BLOCK_ERROR = 'The insertion marker ' + 'manager tried to create a marker but the result is missing %1. If ' + 'you are using a mutator, make sure your domToMutation method is ' + 'properly defined.'; @@ -163,10 +174,10 @@ Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR = 'The insertion marker ' + * Sever all links from this object. * @package */ -Blockly.InsertionMarkerManager.prototype.dispose = function() { +InsertionMarkerManager.prototype.dispose = function() { this.availableConnections_.length = 0; - Blockly.Events.disable(); + Events.disable(); try { if (this.firstMarker_) { this.firstMarker_.dispose(); @@ -175,7 +186,7 @@ Blockly.InsertionMarkerManager.prototype.dispose = function() { this.lastMarker_.dispose(); } } finally { - Blockly.Events.enable(); + Events.enable(); } }; @@ -184,7 +195,7 @@ Blockly.InsertionMarkerManager.prototype.dispose = function() { * change if a block is unplugged and the stack is healed. * @package */ -Blockly.InsertionMarkerManager.prototype.updateAvailableConnections = function() { +InsertionMarkerManager.prototype.updateAvailableConnections = function() { this.availableConnections_ = this.initAvailableConnections_(); }; @@ -194,7 +205,7 @@ Blockly.InsertionMarkerManager.prototype.updateAvailableConnections = function() * @return {boolean} True if the block would be deleted if dropped immediately. * @package */ -Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock = function() { +InsertionMarkerManager.prototype.wouldDeleteBlock = function() { return this.wouldDeleteBlock_; }; @@ -205,7 +216,7 @@ Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock = function() { * immediately. * @package */ -Blockly.InsertionMarkerManager.prototype.wouldConnectBlock = function() { +InsertionMarkerManager.prototype.wouldConnectBlock = function() { return !!this.closestConnection_; }; @@ -214,23 +225,23 @@ Blockly.InsertionMarkerManager.prototype.wouldConnectBlock = function() { * This should be called at the end of a drag. * @package */ -Blockly.InsertionMarkerManager.prototype.applyConnections = function() { +InsertionMarkerManager.prototype.applyConnections = function() { if (this.closestConnection_) { // Don't fire events for insertion markers. - Blockly.Events.disable(); + Events.disable(); this.hidePreview_(); - Blockly.Events.enable(); + Events.enable(); // Connect two blocks together. this.localConnection_.connect(this.closestConnection_); if (this.topBlock_.rendered) { // Trigger a connection animation. // Determine which connection is inferior (lower in the source stack). - var inferiorConnection = this.localConnection_.isSuperior() ? - this.closestConnection_ : this.localConnection_; - Blockly.blockAnimations.connectionUiEffect( - inferiorConnection.getSourceBlock()); + const inferiorConnection = this.localConnection_.isSuperior() ? + this.closestConnection_ : + this.localConnection_; + blockAnimations.connectionUiEffect(inferiorConnection.getSourceBlock()); // Bring the just-edited stack to the front. - var rootBlock = this.topBlock_.getRootBlock(); + const rootBlock = this.topBlock_.getRootBlock(); rootBlock.bringToFront(); } } @@ -238,46 +249,47 @@ Blockly.InsertionMarkerManager.prototype.applyConnections = function() { /** * Update connections based on the most recent move location. - * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, + * @param {!Coordinate} dxy Position relative to drag start, * in workspace units. - * @param {?Blockly.IDragTarget} dragTarget The drag target that the block is + * @param {?IDragTarget} dragTarget The drag target that the block is * currently over. * @package */ -Blockly.InsertionMarkerManager.prototype.update = function(dxy, dragTarget) { - var candidate = this.getCandidate_(dxy); +InsertionMarkerManager.prototype.update = function(dxy, dragTarget) { + const candidate = this.getCandidate_(dxy); this.wouldDeleteBlock_ = this.shouldDelete_(candidate, dragTarget); - var shouldUpdate = this.wouldDeleteBlock_ || - this.shouldUpdatePreviews_(candidate, dxy); + const shouldUpdate = + this.wouldDeleteBlock_ || this.shouldUpdatePreviews_(candidate, dxy); if (shouldUpdate) { // Don't fire events for insertion marker creation or movement. - Blockly.Events.disable(); + Events.disable(); this.maybeHidePreview_(candidate); this.maybeShowPreview_(candidate); - Blockly.Events.enable(); + Events.enable(); } }; /** * Create an insertion marker that represents the given block. - * @param {!Blockly.BlockSvg} sourceBlock The block that the insertion marker + * @param {!BlockSvg} sourceBlock The block that the insertion marker * will represent. - * @return {!Blockly.BlockSvg} The insertion marker that represents the given + * @return {!BlockSvg} The insertion marker that represents the given * block. * @private */ -Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlock) { - var imType = sourceBlock.type; +InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlock) { + const imType = sourceBlock.type; - Blockly.Events.disable(); + Events.disable(); + let result; try { - var result = this.workspace_.newBlock(imType); + result = this.workspace_.newBlock(imType); result.setInsertionMarker(true); if (sourceBlock.mutationToDom) { - var oldMutationDom = sourceBlock.mutationToDom(); + const oldMutationDom = sourceBlock.mutationToDom(); if (oldMutationDom) { result.domToMutation(oldMutationDom); } @@ -285,22 +297,22 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo // Copy field values from the other block. These values may impact the // rendered size of the insertion marker. Note that we do not care about // child blocks here. - for (var i = 0; i < sourceBlock.inputList.length; i++) { - var sourceInput = sourceBlock.inputList[i]; - if (sourceInput.name == Blockly.constants.COLLAPSED_INPUT_NAME) { + for (let i = 0; i < sourceBlock.inputList.length; i++) { + const sourceInput = sourceBlock.inputList[i]; + if (sourceInput.name == constants.COLLAPSED_INPUT_NAME) { continue; // Ignore the collapsed input. } - var resultInput = result.inputList[i]; + const resultInput = result.inputList[i]; if (!resultInput) { - throw new Error(Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR - .replace('%1', 'an input')); + throw new Error(InsertionMarkerManager.DUPLICATE_BLOCK_ERROR.replace( + '%1', 'an input')); } - for (var j = 0; j < sourceInput.fieldRow.length; j++) { - var sourceField = sourceInput.fieldRow[j]; - var resultField = resultInput.fieldRow[j]; + for (let j = 0; j < sourceInput.fieldRow.length; j++) { + const sourceField = sourceInput.fieldRow[j]; + const resultField = resultInput.fieldRow[j]; if (!resultField) { - throw new Error(Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR - .replace('%1', 'a field')); + throw new Error(InsertionMarkerManager.DUPLICATE_BLOCK_ERROR.replace( + '%1', 'a field')); } resultField.setValue(sourceField.getValue()); } @@ -312,7 +324,7 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo result.initSvg(); result.getSvgRoot().setAttribute('visibility', 'hidden'); } finally { - Blockly.Events.enable(); + Events.enable(); } return result; @@ -323,23 +335,23 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo * only be called once, at the beginning of a drag. * If the stack has more than one block, this function will populate * lastOnStack_ and create the corresponding insertion marker. - * @return {!Array} A list of available + * @return {!Array} A list of available * connections. * @private */ -Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function() { - var available = this.topBlock_.getConnections_(false); +InsertionMarkerManager.prototype.initAvailableConnections_ = function() { + const available = this.topBlock_.getConnections_(false); // Also check the last connection on this stack - var lastOnStack = this.topBlock_.lastConnectionInStack(true); + const lastOnStack = this.topBlock_.lastConnectionInStack(true); if (lastOnStack && lastOnStack != this.topBlock_.nextConnection) { available.push(lastOnStack); this.lastOnStack_ = lastOnStack; if (this.lastMarker_) { - Blockly.Events.disable(); + Events.disable(); try { this.lastMarker_.dispose(); } finally { - Blockly.Events.enable(); + Events.enable(); } } this.lastMarker_ = this.createMarkerBlock_(lastOnStack.getSourceBlock()); @@ -352,16 +364,16 @@ Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function() * updated based on the closest candidate and the current drag distance. * @param {!Object} candidate An object containing a local connection, a closest * connection, and a radius. Returned by getCandidate_. - * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, + * @param {!Coordinate} dxy Position relative to drag start, * in workspace units. * @return {boolean} Whether the preview should be updated. * @private */ -Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function( +InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function( candidate, dxy) { - var candidateLocal = candidate.local; - var candidateClosest = candidate.closest; - var radius = candidate.radius; + const candidateLocal = candidate.local; + const candidateClosest = candidate.closest; + const radius = candidate.radius; // Found a connection! if (candidateLocal && candidateClosest) { @@ -373,57 +385,55 @@ Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function( this.localConnection_ == candidateLocal) { return false; } - var xDiff = this.localConnection_.x + dxy.x - this.closestConnection_.x; - var yDiff = this.localConnection_.y + dxy.y - this.closestConnection_.y; - var curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff); + const xDiff = this.localConnection_.x + dxy.x - this.closestConnection_.x; + const yDiff = this.localConnection_.y + dxy.y - this.closestConnection_.y; + const curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff); // Slightly prefer the existing preview over a new preview. return !( candidateClosest && - radius > curDistance - - Blockly.internalConstants.CURRENT_CONNECTION_PREFERENCE); + radius > + curDistance - internalConstants.CURRENT_CONNECTION_PREFERENCE); } else if (!this.localConnection_ && !this.closestConnection_) { - // We weren't showing a preview before, but we should now. + // We weren't showing a preview before, but we should now. return true; } else { - console.error('Only one of localConnection_ and closestConnection_ was set.'); + console.error( + 'Only one of localConnection_ and closestConnection_ was set.'); } } else { // No connection found. // Only need to update if we were showing a preview before. return !!(this.localConnection_ && this.closestConnection_); } - console.error('Returning true from shouldUpdatePreviews, but it\'s not clear why.'); + console.error( + 'Returning true from shouldUpdatePreviews, but it\'s not clear why.'); return true; }; /** * Find the nearest valid connection, which may be the same as the current * closest connection. - * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, + * @param {!Coordinate} dxy Position relative to drag start, * in workspace units. * @return {!Object} An object containing a local connection, a closest * connection, and a radius. * @private */ -Blockly.InsertionMarkerManager.prototype.getCandidate_ = function(dxy) { - var radius = this.getStartRadius_(); - var candidateClosest = null; - var candidateLocal = null; +InsertionMarkerManager.prototype.getCandidate_ = function(dxy) { + let radius = this.getStartRadius_(); + let candidateClosest = null; + let candidateLocal = null; - for (var i = 0; i < this.availableConnections_.length; i++) { - var myConnection = this.availableConnections_[i]; - var neighbour = myConnection.closest(radius, dxy); + for (let i = 0; i < this.availableConnections_.length; i++) { + const myConnection = this.availableConnections_[i]; + const neighbour = myConnection.closest(radius, dxy); if (neighbour.connection) { candidateClosest = neighbour.connection; candidateLocal = myConnection; radius = neighbour.radius; } } - return { - closest: candidateClosest, - local: candidateLocal, - radius: radius - }; + return {closest: candidateClosest, local: candidateLocal, radius: radius}; }; /** @@ -432,38 +442,38 @@ Blockly.InsertionMarkerManager.prototype.getCandidate_ = function(dxy) { * connection. * @private */ -Blockly.InsertionMarkerManager.prototype.getStartRadius_ = function() { +InsertionMarkerManager.prototype.getStartRadius_ = function() { // If there is already a connection highlighted, // increase the radius we check for making new connections. - // Why? When a connection is highlighted, blocks move around when the insertion - // marker is created, which could cause the connection became out of range. - // By increasing radiusConnection when a connection already exists, - // we never "lose" the connection from the offset. + // Why? When a connection is highlighted, blocks move around when the + // insertion marker is created, which could cause the connection became out of + // range. By increasing radiusConnection when a connection already exists, we + // never "lose" the connection from the offset. if (this.closestConnection_ && this.localConnection_) { - return Blockly.internalConstants.CONNECTING_SNAP_RADIUS; + return internalConstants.CONNECTING_SNAP_RADIUS; } - return Blockly.internalConstants.SNAP_RADIUS; + return internalConstants.SNAP_RADIUS; }; /** * Whether ending the drag would delete the block. * @param {!Object} candidate An object containing a local connection, a closest * connection, and a radius. - * @param {?Blockly.IDragTarget} dragTarget The drag target that the block is + * @param {?IDragTarget} dragTarget The drag target that the block is * currently over. * @return {boolean} Whether dropping the block immediately would delete the * block. * @private */ -Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function( +InsertionMarkerManager.prototype.shouldDelete_ = function( candidate, dragTarget) { if (dragTarget) { - var componentManager = this.workspace_.getComponentManager(); - var isDeleteArea = componentManager.hasCapability(dragTarget.id, - Blockly.ComponentManager.Capability.DELETE_AREA); + const componentManager = this.workspace_.getComponentManager(); + const isDeleteArea = componentManager.hasCapability( + dragTarget.id, ComponentManager.Capability.DELETE_AREA); if (isDeleteArea) { return ( - /** @type {!Blockly.IDeleteArea} */ (dragTarget)) + /** @type {!IDeleteArea} */ (dragTarget)) .wouldDelete(this.topBlock_, candidate && !!candidate.closest); } } @@ -479,13 +489,13 @@ Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function( * connection, and a radius. * @private */ -Blockly.InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) { +InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) { // Nope, don't add a marker. if (this.wouldDeleteBlock_) { return; } - var closest = candidate.closest; - var local = candidate.local; + const closest = candidate.closest; + const local = candidate.local; // Nothing to connect to. if (!closest) { @@ -509,22 +519,22 @@ Blockly.InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) * highlight or an insertion marker, and shows the appropriate one. * @private */ -Blockly.InsertionMarkerManager.prototype.showPreview_ = function() { - var closest = this.closestConnection_; - var renderer = this.workspace_.getRenderer(); - var method = renderer.getConnectionPreviewMethod( - /** @type {!Blockly.RenderedConnection} */ (closest), - /** @type {!Blockly.RenderedConnection} */ (this.localConnection_), +InsertionMarkerManager.prototype.showPreview_ = function() { + const closest = this.closestConnection_; + const renderer = this.workspace_.getRenderer(); + const method = renderer.getConnectionPreviewMethod( + /** @type {!RenderedConnection} */ (closest), + /** @type {!RenderedConnection} */ (this.localConnection_), this.topBlock_); switch (method) { - case Blockly.InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE: + case InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE: this.showInsertionInputOutline_(); break; - case Blockly.InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER: + case InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER: this.showInsertionMarker_(); break; - case Blockly.InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE: + case InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE: this.showReplacementFade_(); break; } @@ -544,7 +554,7 @@ Blockly.InsertionMarkerManager.prototype.showPreview_ = function() { * connection, and a radius. * @private */ -Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) { +InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) { // If there's no new preview, remove the old one but don't bother deleting it. // We might need it later, and this saves disposing of it and recreating it. if (!candidate.closest) { @@ -552,12 +562,14 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) } else { // If there's a new preview and there was an preview before, and either // connection has changed, remove the old preview. - var hadPreview = this.closestConnection_ && this.localConnection_; - var closestChanged = this.closestConnection_ != candidate.closest; - var localChanged = this.localConnection_ != candidate.local; + const hadPreview = this.closestConnection_ && this.localConnection_; + const closestChanged = this.closestConnection_ != candidate.closest; + const localChanged = this.localConnection_ != candidate.local; - // Also hide if we had a preview before but now we're going to delete instead. - if (hadPreview && (closestChanged || localChanged || this.wouldDeleteBlock_)) { + // Also hide if we had a preview before but now we're going to delete + // instead. + if (hadPreview && + (closestChanged || localChanged || this.wouldDeleteBlock_)) { this.hidePreview_(); } } @@ -573,10 +585,10 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) * highlight or an insertion marker, and hides the appropriate one. * @private */ -Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() { +InsertionMarkerManager.prototype.hidePreview_ = function() { if (this.closestConnection_ && this.closestConnection_.targetBlock() && - this.workspace_.getRenderer() - .shouldHighlightConnection(this.closestConnection_)) { + this.workspace_.getRenderer().shouldHighlightConnection( + this.closestConnection_)) { this.closestConnection_.unhighlight(); } if (this.fadedBlock_) { @@ -593,16 +605,17 @@ Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() { * manager state). * @private */ -Blockly.InsertionMarkerManager.prototype.showInsertionMarker_ = function() { - var local = this.localConnection_; - var closest = this.closestConnection_; +InsertionMarkerManager.prototype.showInsertionMarker_ = function() { + const local = this.localConnection_; + const closest = this.closestConnection_; - var isLastInStack = this.lastOnStack_ && local == this.lastOnStack_; - var imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_; - var imConn = imBlock.getMatchingConnection(local.getSourceBlock(), local); + const isLastInStack = this.lastOnStack_ && local == this.lastOnStack_; + const imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_; + const imConn = imBlock.getMatchingConnection(local.getSourceBlock(), local); if (imConn == this.markerConnection_) { - throw Error('Made it to showInsertionMarker_ even though the marker isn\'t ' + + throw Error( + 'Made it to showInsertionMarker_ even though the marker isn\'t ' + 'changing'); } @@ -629,23 +642,22 @@ Blockly.InsertionMarkerManager.prototype.showInsertionMarker_ = function() { * to their original state. * @private */ -Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() { +InsertionMarkerManager.prototype.hideInsertionMarker_ = function() { if (!this.markerConnection_) { console.log('No insertion marker connection to disconnect'); return; } - var imConn = this.markerConnection_; - var imBlock = imConn.getSourceBlock(); - var markerNext = imBlock.nextConnection; - var markerPrev = imBlock.previousConnection; - var markerOutput = imBlock.outputConnection; + const imConn = this.markerConnection_; + const imBlock = imConn.getSourceBlock(); + const markerNext = imBlock.nextConnection; + const markerPrev = imBlock.previousConnection; + const markerOutput = imBlock.outputConnection; - var isFirstInStatementStack = + const isFirstInStatementStack = (imConn == markerNext && !(markerPrev && markerPrev.targetConnection)); - var isFirstInOutputStack = - imConn.type == Blockly.connectionTypes.INPUT_VALUE && + const isFirstInOutputStack = imConn.type == connectionTypes.INPUT_VALUE && !(markerOutput && markerOutput.targetConnection); // The insertion marker is the first block in a stack. Unplug won't do // anything in that case. Instead, unplug the following block. @@ -653,12 +665,12 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() { imConn.targetBlock().unplug(false); } // Inside of a C-block, first statement connection. - else if (imConn.type == Blockly.connectionTypes.NEXT_STATEMENT && - imConn != markerNext) { - var innerConnection = imConn.targetConnection; + else if ( + imConn.type == connectionTypes.NEXT_STATEMENT && imConn != markerNext) { + const innerConnection = imConn.targetConnection; innerConnection.getSourceBlock().unplug(false); - var previousBlockNextConnection = + const previousBlockNextConnection = markerPrev ? markerPrev.targetConnection : null; imBlock.unplug(true); @@ -670,12 +682,13 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() { } if (imConn.targetConnection) { - throw Error('markerConnection_ still connected at the end of ' + + throw Error( + 'markerConnection_ still connected at the end of ' + 'disconnectInsertionMarker'); } this.markerConnection_ = null; - var svg = imBlock.getSvgRoot(); + const svg = imBlock.getSvgRoot(); if (svg) { svg.setAttribute('visibility', 'hidden'); } @@ -685,8 +698,8 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() { * Shows an outline around the input the closest connection belongs to. * @private */ -Blockly.InsertionMarkerManager.prototype.showInsertionInputOutline_ = function() { - var closest = this.closestConnection_; +InsertionMarkerManager.prototype.showInsertionInputOutline_ = function() { + const closest = this.closestConnection_; this.highlightedBlock_ = closest.getSourceBlock(); this.highlightedBlock_.highlightShapeForInput(closest, true); }; @@ -695,7 +708,7 @@ Blockly.InsertionMarkerManager.prototype.showInsertionInputOutline_ = function() * Hides any visible input outlines. * @private */ -Blockly.InsertionMarkerManager.prototype.hideInsertionInputOutline_ = function() { +InsertionMarkerManager.prototype.hideInsertionInputOutline_ = function() { this.highlightedBlock_.highlightShapeForInput(this.closestConnection_, false); this.highlightedBlock_ = null; }; @@ -705,7 +718,7 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionInputOutline_ = function() * (the block that is currently connected to it). * @private */ -Blockly.InsertionMarkerManager.prototype.showReplacementFade_ = function() { +InsertionMarkerManager.prototype.showReplacementFade_ = function() { this.fadedBlock_ = this.closestConnection_.targetBlock(); this.fadedBlock_.fadeForReplacement(true); }; @@ -714,7 +727,7 @@ Blockly.InsertionMarkerManager.prototype.showReplacementFade_ = function() { * Hides/Removes any visible fade affects. * @private */ -Blockly.InsertionMarkerManager.prototype.hideReplacementFade_ = function() { +InsertionMarkerManager.prototype.hideReplacementFade_ = function() { this.fadedBlock_.fadeForReplacement(false); this.fadedBlock_ = null; }; @@ -722,12 +735,12 @@ Blockly.InsertionMarkerManager.prototype.hideReplacementFade_ = function() { /** * Get a list of the insertion markers that currently exist. Drags have 0, 1, * or 2 insertion markers. - * @return {!Array} A possibly empty list of insertion + * @return {!Array} A possibly empty list of insertion * marker blocks. * @package */ -Blockly.InsertionMarkerManager.prototype.getInsertionMarkers = function() { - var result = []; +InsertionMarkerManager.prototype.getInsertionMarkers = function() { + const result = []; if (this.firstMarker_) { result.push(this.firstMarker_); } @@ -736,3 +749,5 @@ Blockly.InsertionMarkerManager.prototype.getInsertionMarkers = function() { } return result; }; + +exports = InsertionMarkerManager; diff --git a/core/interfaces/i_ast_node_location_svg.js b/core/interfaces/i_ast_node_location_svg.js index 526fbffa3..53d65a529 100644 --- a/core/interfaces/i_ast_node_location_svg.js +++ b/core/interfaces/i_ast_node_location_svg.js @@ -15,7 +15,7 @@ goog.module('Blockly.IASTNodeLocationSvg'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IASTNodeLocation = goog.require('Blockly.IASTNodeLocation'); +const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation'); /** diff --git a/core/interfaces/i_ast_node_location_with_block.js b/core/interfaces/i_ast_node_location_with_block.js index 002db0ad8..0bef06154 100644 --- a/core/interfaces/i_ast_node_location_with_block.js +++ b/core/interfaces/i_ast_node_location_with_block.js @@ -18,7 +18,7 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const Block = goog.requireType('Blockly.Block'); /* eslint-disable-next-line no-unused-vars */ -const IASTNodeLocation = goog.require('Blockly.IASTNodeLocation'); +const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation'); /** diff --git a/core/interfaces/i_autohideable.js b/core/interfaces/i_autohideable.js index 0ccbf310a..c3c7a8125 100644 --- a/core/interfaces/i_autohideable.js +++ b/core/interfaces/i_autohideable.js @@ -16,7 +16,7 @@ goog.module('Blockly.IAutoHideable'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IComponent = goog.require('Blockly.IComponent'); +const IComponent = goog.requireType('Blockly.IComponent'); /** diff --git a/core/interfaces/i_bubble.js b/core/interfaces/i_bubble.js index b6e9736d7..a7578fc09 100644 --- a/core/interfaces/i_bubble.js +++ b/core/interfaces/i_bubble.js @@ -19,9 +19,9 @@ const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg'); /* eslint-disable-next-line no-unused-vars */ const Coordinate = goog.requireType('Blockly.utils.Coordinate'); /* eslint-disable-next-line no-unused-vars */ -const IContextMenu = goog.require('Blockly.IContextMenu'); +const IContextMenu = goog.requireType('Blockly.IContextMenu'); /* eslint-disable-next-line no-unused-vars */ -const IDraggable = goog.require('Blockly.IDraggable'); +const IDraggable = goog.requireType('Blockly.IDraggable'); /** diff --git a/core/interfaces/i_collapsible_toolbox_item.js b/core/interfaces/i_collapsible_toolbox_item.js index 45bd3ae3e..5915a05b4 100644 --- a/core/interfaces/i_collapsible_toolbox_item.js +++ b/core/interfaces/i_collapsible_toolbox_item.js @@ -15,7 +15,7 @@ goog.module('Blockly.ICollapsibleToolboxItem'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const ISelectableToolboxItem = goog.require('Blockly.ISelectableToolboxItem'); +const ISelectableToolboxItem = goog.requireType('Blockly.ISelectableToolboxItem'); /* eslint-disable-next-line no-unused-vars */ const IToolboxItem = goog.requireType('Blockly.IToolboxItem'); diff --git a/core/interfaces/i_delete_area.js b/core/interfaces/i_delete_area.js index 845d7dddb..fbe54559a 100644 --- a/core/interfaces/i_delete_area.js +++ b/core/interfaces/i_delete_area.js @@ -18,7 +18,7 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const IDraggable = goog.requireType('Blockly.IDraggable'); /* eslint-disable-next-line no-unused-vars */ -const IDragTarget = goog.require('Blockly.IDragTarget'); +const IDragTarget = goog.requireType('Blockly.IDragTarget'); /** diff --git a/core/interfaces/i_drag_target.js b/core/interfaces/i_drag_target.js index 6b777781d..a47798841 100644 --- a/core/interfaces/i_drag_target.js +++ b/core/interfaces/i_drag_target.js @@ -16,7 +16,7 @@ goog.module('Blockly.IDragTarget'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IComponent = goog.require('Blockly.IComponent'); +const IComponent = goog.requireType('Blockly.IComponent'); /* eslint-disable-next-line no-unused-vars */ const IDraggable = goog.requireType('Blockly.IDraggable'); /* eslint-disable-next-line no-unused-vars */ diff --git a/core/interfaces/i_draggable.js b/core/interfaces/i_draggable.js index 5d7e17d53..5e6702a1c 100644 --- a/core/interfaces/i_draggable.js +++ b/core/interfaces/i_draggable.js @@ -15,7 +15,7 @@ goog.module('Blockly.IDraggable'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IDeletable = goog.require('Blockly.IDeletable'); +const IDeletable = goog.requireType('Blockly.IDeletable'); /** diff --git a/core/interfaces/i_flyout.js b/core/interfaces/i_flyout.js index 23c76dd0b..405f0e482 100644 --- a/core/interfaces/i_flyout.js +++ b/core/interfaces/i_flyout.js @@ -19,13 +19,13 @@ const BlockSvg = goog.requireType('Blockly.BlockSvg'); /* eslint-disable-next-line no-unused-vars */ const Coordinate = goog.requireType('Blockly.utils.Coordinate'); /* eslint-disable-next-line no-unused-vars */ -const IRegistrable = goog.require('Blockly.IRegistrable'); +const IRegistrable = goog.requireType('Blockly.IRegistrable'); /* eslint-disable-next-line no-unused-vars */ const Svg = goog.requireType('Blockly.utils.Svg'); /* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); /* eslint-disable-next-line no-unused-vars */ -const {FlyoutDefinition} = goog.requireType('Blockly.utils.toolbox'); +const toolbox = goog.requireType('Blockly.utils.toolbox'); /** @@ -142,7 +142,7 @@ IFlyout.prototype.hide; /** * Show and populate the flyout. - * @param {!FlyoutDefinition|string} flyoutDef Contents to + * @param {!toolbox.FlyoutDefinition|string} flyoutDef Contents to * display in the flyout. This is either an array of Nodes, a NodeList, a * toolbox definition, or a string with the name of the dynamic category. */ diff --git a/core/interfaces/i_metrics_manager.js b/core/interfaces/i_metrics_manager.js index db1f575c1..7dd8ef663 100644 --- a/core/interfaces/i_metrics_manager.js +++ b/core/interfaces/i_metrics_manager.js @@ -17,9 +17,9 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const Metrics = goog.requireType('Blockly.utils.Metrics'); /* eslint-disable-next-line no-unused-vars */ -const Size = goog.requireType('Blockly.utils.Size'); +const MetricsManager = goog.requireType('Blockly.MetricsManager'); /* eslint-disable-next-line no-unused-vars */ -const {AbsoluteMetrics, ContainerRegion, ToolboxMetrics} = goog.requireType('Blockly.MetricsManager'); +const Size = goog.requireType('Blockly.utils.Size'); /** @@ -39,13 +39,13 @@ IMetricsManager.prototype.hasFixedEdges; * Returns the metrics for the scroll area of the workspace. * @param {boolean=} opt_getWorkspaceCoordinates True to get the scroll metrics * in workspace coordinates, false to get them in pixel coordinates. - * @param {!ContainerRegion=} opt_viewMetrics The view + * @param {!MetricsManager.ContainerRegion=} opt_viewMetrics The view * metrics if they have been previously computed. Passing in null may cause * the view metrics to be computed again, if it is needed. - * @param {!ContainerRegion=} opt_contentMetrics The + * @param {!MetricsManager.ContainerRegion=} opt_contentMetrics The * content metrics if they have been previously computed. Passing in null * may cause the content metrics to be computed again, if it is needed. - * @return {!ContainerRegion} The metrics for the scroll + * @return {!MetricsManager.ContainerRegion} The metrics for the scroll * container */ IMetricsManager.prototype.getScrollMetrics; @@ -55,7 +55,7 @@ IMetricsManager.prototype.getScrollMetrics; * coordinates. Returns 0 for the width and height if the workspace has a * category toolbox instead of a simple toolbox. * @param {boolean=} opt_own Whether to only return the workspace's own flyout. - * @return {!ToolboxMetrics} The width and height of the + * @return {!MetricsManager.ToolboxMetrics} The width and height of the * flyout. * @public */ @@ -66,7 +66,7 @@ IMetricsManager.prototype.getFlyoutMetrics; * coordinates. Returns 0 for the width and height if the workspace has a simple * toolbox instead of a category toolbox. To get the width and height of a * simple toolbox @see {@link getFlyoutMetrics}. - * @return {!ToolboxMetrics} The object with the width, + * @return {!MetricsManager.ToolboxMetrics} The object with the width, * height and position of the toolbox. * @public */ @@ -84,7 +84,7 @@ IMetricsManager.prototype.getSvgMetrics; /** * Gets the absolute left and absolute top in pixel coordinates. * This is where the visible workspace starts in relation to the SVG container. - * @return {!AbsoluteMetrics} The absolute metrics for + * @return {!MetricsManager.AbsoluteMetrics} The absolute metrics for * the workspace. * @public */ @@ -95,7 +95,7 @@ IMetricsManager.prototype.getAbsoluteMetrics; * coordinates. The visible workspace does not include the toolbox or flyout. * @param {boolean=} opt_getWorkspaceCoordinates True to get the view metrics in * workspace coordinates, false to get them in pixel coordinates. - * @return {!ContainerRegion} The width, height, top and + * @return {!MetricsManager.ContainerRegion} The width, height, top and * left of the viewport in either workspace coordinates or pixel * coordinates. * @public @@ -108,7 +108,7 @@ IMetricsManager.prototype.getViewMetrics; * workspace (workspace comments and blocks). * @param {boolean=} opt_getWorkspaceCoordinates True to get the content metrics * in workspace coordinates, false to get them in pixel coordinates. - * @return {!ContainerRegion} The + * @return {!MetricsManager.ContainerRegion} The * metrics for the content container. * @public */ diff --git a/core/interfaces/i_positionable.js b/core/interfaces/i_positionable.js index 1fe773add..ba1a4d2b5 100644 --- a/core/interfaces/i_positionable.js +++ b/core/interfaces/i_positionable.js @@ -15,11 +15,11 @@ goog.module('Blockly.IPositionable'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IComponent = goog.require('Blockly.IComponent'); +const IComponent = goog.requireType('Blockly.IComponent'); +/* eslint-disable-next-line no-unused-vars */ +const MetricsManager = goog.requireType('Blockly.MetricsManager'); /* eslint-disable-next-line no-unused-vars */ const Rect = goog.requireType('Blockly.utils.Rect'); -/* eslint-disable-next-line no-unused-vars */ -const {UiMetrics} = goog.requireType('Blockly.MetricsManager'); /** @@ -31,7 +31,7 @@ const IPositionable = function() {}; /** * Positions the element. Called when the window is resized. - * @param {!UiMetrics} metrics The workspace metrics. + * @param {!MetricsManager.UiMetrics} metrics The workspace metrics. * @param {!Array} savedPositions List of rectangles that * are already on the workspace. */ diff --git a/core/interfaces/i_selectable_toolbox_item.js b/core/interfaces/i_selectable_toolbox_item.js index cefe35740..2e286889f 100644 --- a/core/interfaces/i_selectable_toolbox_item.js +++ b/core/interfaces/i_selectable_toolbox_item.js @@ -15,9 +15,9 @@ goog.module('Blockly.ISelectableToolboxItem'); goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ -const IToolboxItem = goog.require('Blockly.IToolboxItem'); +const IToolboxItem = goog.requireType('Blockly.IToolboxItem'); /* eslint-disable-next-line no-unused-vars */ -const {FlyoutItemInfoArray} = goog.requireType('Blockly.utils.toolbox'); +const toolbox = goog.requireType('Blockly.utils.toolbox'); /** @@ -37,7 +37,7 @@ ISelectableToolboxItem.prototype.getName; /** * Gets the contents of the toolbox item. These are items that are meant to be * displayed in the flyout. - * @return {!FlyoutItemInfoArray|string} The definition + * @return {!toolbox.FlyoutItemInfoArray|string} The definition * of items to be displayed in the flyout. * @public */ diff --git a/core/interfaces/i_toolbox.js b/core/interfaces/i_toolbox.js index 0c7e7deb3..ee645ba34 100644 --- a/core/interfaces/i_toolbox.js +++ b/core/interfaces/i_toolbox.js @@ -17,13 +17,13 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const IFlyout = goog.requireType('Blockly.IFlyout'); /* eslint-disable-next-line no-unused-vars */ -const IRegistrable = goog.require('Blockly.IRegistrable'); +const IRegistrable = goog.requireType('Blockly.IRegistrable'); /* eslint-disable-next-line no-unused-vars */ const IToolboxItem = goog.requireType('Blockly.IToolboxItem'); /* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); /* eslint-disable-next-line no-unused-vars */ -const {ToolboxInfo} = goog.requireType('Blockly.utils.toolbox'); +const toolbox = goog.requireType('Blockly.utils.toolbox'); /** @@ -41,7 +41,7 @@ IToolbox.prototype.init; /** * Fills the toolbox with new toolbox items and removes any old contents. - * @param {!ToolboxInfo} toolboxDef Object holding information + * @param {!toolbox.ToolboxInfo} toolboxDef Object holding information * for creating a toolbox. */ IToolbox.prototype.render; diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index d86a22a4c..b52ca1b18 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -10,18 +10,25 @@ */ 'use strict'; -goog.provide('Blockly.ASTNode'); +goog.module('Blockly.ASTNode'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.utils.Coordinate'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.Connection'); -goog.requireType('Blockly.Field'); -goog.requireType('Blockly.IASTNodeLocation'); -goog.requireType('Blockly.IASTNodeLocationWithBlock'); -goog.requireType('Blockly.Input'); -goog.requireType('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocationWithBlock = goog.requireType('Blockly.IASTNodeLocationWithBlock'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const connectionTypes = goog.require('Blockly.connectionTypes'); /** @@ -29,19 +36,19 @@ goog.requireType('Blockly.Workspace'); * It is recommended that you use one of the createNode methods instead of * creating a node directly. * @param {string} type The type of the location. - * Must be in Blockly.ASTNode.types. - * @param {!Blockly.IASTNodeLocation} location The position in the AST. - * @param {!Blockly.ASTNode.Params=} opt_params Optional dictionary of options. + * Must be in ASTNode.types. + * @param {!IASTNodeLocation} location The position in the AST. + * @param {!ASTNode.Params=} opt_params Optional dictionary of options. * @constructor */ -Blockly.ASTNode = function(type, location, opt_params) { +const ASTNode = function(type, location, opt_params) { if (!location) { throw Error('Cannot create a node without a location.'); } /** * The type of the location. - * One of Blockly.ASTNode.types + * One of ASTNode.types * @type {string} * @private */ @@ -52,18 +59,18 @@ Blockly.ASTNode = function(type, location, opt_params) { * @type {boolean} * @private */ - this.isConnection_ = Blockly.ASTNode.isConnectionType_(type); + this.isConnection_ = ASTNode.isConnectionType_(type); /** * The location of the AST node. - * @type {!Blockly.IASTNodeLocation} + * @type {!IASTNodeLocation} * @private */ this.location_ = location; /** * The coordinate on the workspace. - * @type {Blockly.utils.Coordinate} + * @type {Coordinate} * @private */ this.wsCoordinate_ = null; @@ -73,16 +80,16 @@ Blockly.ASTNode = function(type, location, opt_params) { /** * @typedef {{ - * wsCoordinate: Blockly.utils.Coordinate + * wsCoordinate: Coordinate * }} */ -Blockly.ASTNode.Params; +ASTNode.Params; /** * Object holding different types for an AST node. * @enum {string} */ -Blockly.ASTNode.types = { +ASTNode.types = { FIELD: 'field', BLOCK: 'block', INPUT: 'input', @@ -97,7 +104,7 @@ Blockly.ASTNode.types = { * True to navigate to all fields. False to only navigate to clickable fields. * @type {boolean} */ -Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false; +ASTNode.NAVIGATE_ALL_FIELDS = false; /** * The default y offset to use when moving the cursor from a stack to the @@ -105,20 +112,20 @@ Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false; * @type {number} * @private */ -Blockly.ASTNode.DEFAULT_OFFSET_Y = -20; +ASTNode.DEFAULT_OFFSET_Y = -20; /** * Whether an AST node of the given type points to a connection. - * @param {string} type The type to check. One of Blockly.ASTNode.types. + * @param {string} type The type to check. One of ASTNode.types. * @return {boolean} True if a node of the given type points to a connection. * @private */ -Blockly.ASTNode.isConnectionType_ = function(type) { +ASTNode.isConnectionType_ = function(type) { switch (type) { - case Blockly.ASTNode.types.PREVIOUS: - case Blockly.ASTNode.types.NEXT: - case Blockly.ASTNode.types.INPUT: - case Blockly.ASTNode.types.OUTPUT: + case ASTNode.types.PREVIOUS: + case ASTNode.types.NEXT: + case ASTNode.types.INPUT: + case ASTNode.types.OUTPUT: return true; } return false; @@ -126,39 +133,39 @@ Blockly.ASTNode.isConnectionType_ = function(type) { /** * Create an AST node pointing to a field. - * @param {Blockly.Field} field The location of the AST node. - * @return {Blockly.ASTNode} An AST node pointing to a field. + * @param {Field} field The location of the AST node. + * @return {ASTNode} An AST node pointing to a field. */ -Blockly.ASTNode.createFieldNode = function(field) { +ASTNode.createFieldNode = function(field) { if (!field) { return null; } - return new Blockly.ASTNode(Blockly.ASTNode.types.FIELD, field); + return new ASTNode(ASTNode.types.FIELD, field); }; /** * Creates an AST node pointing to a connection. If the connection has a parent * input then create an AST node of type input that will hold the connection. - * @param {Blockly.Connection} connection This is the connection the node will + * @param {Connection} connection This is the connection the node will * point to. - * @return {Blockly.ASTNode} An AST node pointing to a connection. + * @return {ASTNode} An AST node pointing to a connection. */ -Blockly.ASTNode.createConnectionNode = function(connection) { +ASTNode.createConnectionNode = function(connection) { if (!connection) { return null; } - var type = connection.type; - if (type == Blockly.connectionTypes.INPUT_VALUE) { - return Blockly.ASTNode.createInputNode(connection.getParentInput()); - } else if (type == Blockly.connectionTypes.NEXT_STATEMENT && - connection.getParentInput()) { - return Blockly.ASTNode.createInputNode(connection.getParentInput()); - } else if (type == Blockly.connectionTypes.NEXT_STATEMENT) { - return new Blockly.ASTNode(Blockly.ASTNode.types.NEXT, connection); - } else if (type == Blockly.connectionTypes.OUTPUT_VALUE) { - return new Blockly.ASTNode(Blockly.ASTNode.types.OUTPUT, connection); - } else if (type == Blockly.connectionTypes.PREVIOUS_STATEMENT) { - return new Blockly.ASTNode(Blockly.ASTNode.types.PREVIOUS, connection); + const type = connection.type; + if (type == connectionTypes.INPUT_VALUE) { + return ASTNode.createInputNode(connection.getParentInput()); + } else if ( + type == connectionTypes.NEXT_STATEMENT && connection.getParentInput()) { + return ASTNode.createInputNode(connection.getParentInput()); + } else if (type == connectionTypes.NEXT_STATEMENT) { + return new ASTNode(ASTNode.types.NEXT, connection); + } else if (type == connectionTypes.OUTPUT_VALUE) { + return new ASTNode(ASTNode.types.OUTPUT, connection); + } else if (type == connectionTypes.PREVIOUS_STATEMENT) { + return new ASTNode(ASTNode.types.PREVIOUS, connection); } return null; }; @@ -166,86 +173,83 @@ Blockly.ASTNode.createConnectionNode = function(connection) { /** * Creates an AST node pointing to an input. Stores the input connection as the * location. - * @param {Blockly.Input} input The input used to create an AST node. - * @return {Blockly.ASTNode} An AST node pointing to a input. + * @param {Input} input The input used to create an AST node. + * @return {ASTNode} An AST node pointing to a input. */ -Blockly.ASTNode.createInputNode = function(input) { +ASTNode.createInputNode = function(input) { if (!input || !input.connection) { return null; } - return new Blockly.ASTNode(Blockly.ASTNode.types.INPUT, input.connection); + return new ASTNode(ASTNode.types.INPUT, input.connection); }; /** * Creates an AST node pointing to a block. - * @param {Blockly.Block} block The block used to create an AST node. - * @return {Blockly.ASTNode} An AST node pointing to a block. + * @param {Block} block The block used to create an AST node. + * @return {ASTNode} An AST node pointing to a block. */ -Blockly.ASTNode.createBlockNode = function(block) { +ASTNode.createBlockNode = function(block) { if (!block) { return null; } - return new Blockly.ASTNode(Blockly.ASTNode.types.BLOCK, block); + return new ASTNode(ASTNode.types.BLOCK, block); }; /** * Create an AST node of type stack. A stack, represented by its top block, is * the set of all blocks connected to a top block, including the top block. - * @param {Blockly.Block} topBlock A top block has no parent and can be found + * @param {Block} topBlock A top block has no parent and can be found * in the list returned by workspace.getTopBlocks(). - * @return {Blockly.ASTNode} An AST node of type stack that points to the top + * @return {ASTNode} An AST node of type stack that points to the top * block on the stack. */ -Blockly.ASTNode.createStackNode = function(topBlock) { +ASTNode.createStackNode = function(topBlock) { if (!topBlock) { return null; } - return new Blockly.ASTNode(Blockly.ASTNode.types.STACK, topBlock); + return new ASTNode(ASTNode.types.STACK, topBlock); }; /** * Creates an AST node pointing to a workspace. - * @param {!Blockly.Workspace} workspace The workspace that we are on. - * @param {Blockly.utils.Coordinate} wsCoordinate The position on the workspace + * @param {!Workspace} workspace The workspace that we are on. + * @param {Coordinate} wsCoordinate The position on the workspace * for this node. - * @return {Blockly.ASTNode} An AST node pointing to a workspace and a position + * @return {ASTNode} An AST node pointing to a workspace and a position * on the workspace. */ -Blockly.ASTNode.createWorkspaceNode = function(workspace, wsCoordinate) { +ASTNode.createWorkspaceNode = function(workspace, wsCoordinate) { if (!wsCoordinate || !workspace) { return null; } - var params = { - wsCoordinate: wsCoordinate - }; - return new Blockly.ASTNode( - Blockly.ASTNode.types.WORKSPACE, workspace, params); + const params = {wsCoordinate: wsCoordinate}; + return new ASTNode(ASTNode.types.WORKSPACE, workspace, params); }; /** * Creates an AST node for the top position on a block. * This is either an output connection, previous connection, or block. - * @param {!Blockly.Block} block The block to find the top most AST node on. - * @return {Blockly.ASTNode} The AST node holding the top most position on the + * @param {!Block} block The block to find the top most AST node on. + * @return {ASTNode} The AST node holding the top most position on the * block. */ -Blockly.ASTNode.createTopNode = function(block) { - var astNode; - var topConnection = block.previousConnection || block.outputConnection; +ASTNode.createTopNode = function(block) { + let astNode; + const topConnection = block.previousConnection || block.outputConnection; if (topConnection) { - astNode = Blockly.ASTNode.createConnectionNode(topConnection); + astNode = ASTNode.createConnectionNode(topConnection); } else { - astNode = Blockly.ASTNode.createBlockNode(block); + astNode = ASTNode.createBlockNode(block); } return astNode; }; /** * Parse the optional parameters. - * @param {?Blockly.ASTNode.Params} params The user specified parameters. + * @param {?ASTNode.Params} params The user specified parameters. * @private */ -Blockly.ASTNode.prototype.processParams_ = function(params) { +ASTNode.prototype.processParams_ = function(params) { if (!params) { return; } @@ -258,28 +262,28 @@ Blockly.ASTNode.prototype.processParams_ = function(params) { * Gets the value pointed to by this node. * It is the callers responsibility to check the node type to figure out what * type of object they get back from this. - * @return {!Blockly.IASTNodeLocation} The current field, connection, workspace, or + * @return {!IASTNodeLocation} The current field, connection, workspace, or * block the cursor is on. */ -Blockly.ASTNode.prototype.getLocation = function() { +ASTNode.prototype.getLocation = function() { return this.location_; }; /** * The type of the current location. - * One of Blockly.ASTNode.types + * One of ASTNode.types * @return {string} The type of the location. */ -Blockly.ASTNode.prototype.getType = function() { +ASTNode.prototype.getType = function() { return this.type_; }; /** * The coordinate on the workspace. - * @return {Blockly.utils.Coordinate} The workspace coordinate or null if the + * @return {Coordinate} The workspace coordinate or null if the * location is not a workspace. */ -Blockly.ASTNode.prototype.getWsCoordinate = function() { +ASTNode.prototype.getWsCoordinate = function() { return this.wsCoordinate_; }; @@ -288,7 +292,7 @@ Blockly.ASTNode.prototype.getWsCoordinate = function() { * @return {boolean} [description] * @package */ -Blockly.ASTNode.prototype.isConnection = function() { +ASTNode.prototype.isConnection = function() { return this.isConnection_; }; @@ -296,25 +300,27 @@ Blockly.ASTNode.prototype.isConnection = function() { * Given an input find the next editable field or an input with a non null * connection in the same block. The current location must be an input * connection. - * @return {Blockly.ASTNode} The AST node holding the next field or connection + * @return {ASTNode} The AST node holding the next field or connection * or null if there is no editable field or input connection after the given * input. * @private */ -Blockly.ASTNode.prototype.findNextForInput_ = function() { - var location = /** @type {!Blockly.Connection} */ (this.location_); - var parentInput = location.getParentInput(); - var block = parentInput.getSourceBlock(); - var curIdx = block.inputList.indexOf(parentInput); - for (var i = curIdx + 1, input; (input = block.inputList[i]); i++) { - var fieldRow = input.fieldRow; - for (var j = 0, field; (field = fieldRow[j]); j++) { - if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { - return Blockly.ASTNode.createFieldNode(field); +ASTNode.prototype.findNextForInput_ = function() { + const location = /** @type {!Connection} */ (this.location_); + const parentInput = location.getParentInput(); + const block = parentInput.getSourceBlock(); + const curIdx = block.inputList.indexOf(parentInput); + for (let i = curIdx + 1; i < block.inputList.length; i++) { + const input = block.inputList[i]; + const fieldRow = input.fieldRow; + for (let j = 0; j < fieldRow.length; j++) { + const field = fieldRow[j]; + if (field.isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) { + return ASTNode.createFieldNode(field); } } if (input.connection) { - return Blockly.ASTNode.createInputNode(input); + return ASTNode.createInputNode(input); } } return null; @@ -323,28 +329,29 @@ Blockly.ASTNode.prototype.findNextForInput_ = function() { /** * Given a field find the next editable field or an input with a non null * connection in the same block. The current location must be a field. - * @return {Blockly.ASTNode} The AST node pointing to the next field or + * @return {ASTNode} The AST node pointing to the next field or * connection or null if there is no editable field or input connection * after the given input. * @private */ -Blockly.ASTNode.prototype.findNextForField_ = function() { - var location = /** @type {!Blockly.Field} */ (this.location_); - var input = location.getParentInput(); - var block = location.getSourceBlock(); - var curIdx = block.inputList.indexOf(/** @type {!Blockly.Input} */ (input)); - var fieldIdx = input.fieldRow.indexOf(location) + 1; - for (var i = curIdx, newInput; (newInput = block.inputList[i]); i++) { - var fieldRow = newInput.fieldRow; +ASTNode.prototype.findNextForField_ = function() { + const location = /** @type {!Field} */ (this.location_); + const input = location.getParentInput(); + const block = location.getSourceBlock(); + const curIdx = block.inputList.indexOf(/** @type {!Input} */ (input)); + let fieldIdx = input.fieldRow.indexOf(location) + 1; + for (let i = curIdx; i < block.inputList.length; i++) { + const newInput = block.inputList[i]; + const fieldRow = newInput.fieldRow; while (fieldIdx < fieldRow.length) { - if (fieldRow[fieldIdx].isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { - return Blockly.ASTNode.createFieldNode(fieldRow[fieldIdx]); + if (fieldRow[fieldIdx].isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) { + return ASTNode.createFieldNode(fieldRow[fieldIdx]); } fieldIdx++; } fieldIdx = 0; if (newInput.connection) { - return Blockly.ASTNode.createInputNode(newInput); + return ASTNode.createInputNode(newInput); } } return null; @@ -354,23 +361,25 @@ Blockly.ASTNode.prototype.findNextForField_ = function() { * Given an input find the previous editable field or an input with a non null * connection in the same block. The current location must be an input * connection. - * @return {Blockly.ASTNode} The AST node holding the previous field or + * @return {ASTNode} The AST node holding the previous field or * connection. * @private */ -Blockly.ASTNode.prototype.findPrevForInput_ = function() { - var location = /** @type {!Blockly.Connection} */ (this.location_); - var parentInput = location.getParentInput(); - var block = parentInput.getSourceBlock(); - var curIdx = block.inputList.indexOf(parentInput); - for (var i = curIdx, input; (input = block.inputList[i]); i--) { +ASTNode.prototype.findPrevForInput_ = function() { + const location = /** @type {!Connection} */ (this.location_); + const parentInput = location.getParentInput(); + const block = parentInput.getSourceBlock(); + const curIdx = block.inputList.indexOf(parentInput); + for (let i = curIdx; i >= 0; i--) { + const input = block.inputList[i]; if (input.connection && input !== parentInput) { - return Blockly.ASTNode.createInputNode(input); + return ASTNode.createInputNode(input); } - var fieldRow = input.fieldRow; - for (var j = fieldRow.length - 1, field; (field = fieldRow[j]); j--) { - if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { - return Blockly.ASTNode.createFieldNode(field); + const fieldRow = input.fieldRow; + for (let j = fieldRow.length - 1; j >= 0; j--) { + const field = fieldRow[j]; + if (field.isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) { + return ASTNode.createFieldNode(field); } } } @@ -380,24 +389,25 @@ Blockly.ASTNode.prototype.findPrevForInput_ = function() { /** * Given a field find the previous editable field or an input with a non null * connection in the same block. The current location must be a field. - * @return {Blockly.ASTNode} The AST node holding the previous input or field. + * @return {ASTNode} The AST node holding the previous input or field. * @private */ -Blockly.ASTNode.prototype.findPrevForField_ = function() { - var location = /** @type {!Blockly.Field} */ (this.location_); - var parentInput = location.getParentInput(); - var block = location.getSourceBlock(); - var curIdx = block.inputList.indexOf( - /** @type {!Blockly.Input} */ (parentInput)); - var fieldIdx = parentInput.fieldRow.indexOf(location) - 1; - for (var i = curIdx, input; (input = block.inputList[i]); i--) { +ASTNode.prototype.findPrevForField_ = function() { + const location = /** @type {!Field} */ (this.location_); + const parentInput = location.getParentInput(); + const block = location.getSourceBlock(); + const curIdx = block.inputList.indexOf( + /** @type {!Input} */ (parentInput)); + let fieldIdx = parentInput.fieldRow.indexOf(location) - 1; + for (let i = curIdx; i >= 0; i--) { + const input = block.inputList[i]; if (input.connection && input !== parentInput) { - return Blockly.ASTNode.createInputNode(input); + return ASTNode.createInputNode(input); } - var fieldRow = input.fieldRow; + const fieldRow = input.fieldRow; while (fieldIdx > -1) { - if (fieldRow[fieldIdx].isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { - return Blockly.ASTNode.createFieldNode(fieldRow[fieldIdx]); + if (fieldRow[fieldIdx].isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) { + return ASTNode.createFieldNode(fieldRow[fieldIdx]); } fieldIdx--; } @@ -412,29 +422,30 @@ Blockly.ASTNode.prototype.findPrevForField_ = function() { /** * Navigate between stacks of blocks on the workspace. * @param {boolean} forward True to go forward. False to go backwards. - * @return {Blockly.ASTNode} The first block of the next stack or null if there + * @return {ASTNode} The first block of the next stack or null if there * are no blocks on the workspace. * @private */ -Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) { +ASTNode.prototype.navigateBetweenStacks_ = function(forward) { var curLocation = this.getLocation(); if (curLocation.getSourceBlock) { - curLocation = /** @type {!Blockly.IASTNodeLocationWithBlock} */ ( - curLocation).getSourceBlock(); + curLocation = /** @type {!IASTNodeLocationWithBlock} */ (curLocation) + .getSourceBlock(); } if (!curLocation || !curLocation.workspace) { return null; } - var curRoot = curLocation.getRootBlock(); - var topBlocks = curRoot.workspace.getTopBlocks(true); - for (var i = 0, topBlock; (topBlock = topBlocks[i]); i++) { + const curRoot = curLocation.getRootBlock(); + const topBlocks = curRoot.workspace.getTopBlocks(true); + for (let i = 0; i < topBlocks.length; i++) { + const topBlock = topBlocks[i]; if (curRoot.id == topBlock.id) { - var offset = forward ? 1 : -1; - var resultIndex = i + offset; + const offset = forward ? 1 : -1; + const resultIndex = i + offset; if (resultIndex == -1 || resultIndex == topBlocks.length) { return null; } - return Blockly.ASTNode.createStackNode(topBlocks[resultIndex]); + return ASTNode.createStackNode(topBlocks[resultIndex]); } } throw Error('Couldn\'t find ' + (forward ? 'next' : 'previous') + ' stack?!'); @@ -444,69 +455,71 @@ Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) { * Finds the top most AST node for a given block. * This is either the previous connection, output connection or block depending * on what kind of connections the block has. - * @param {!Blockly.Block} block The block that we want to find the top + * @param {!Block} block The block that we want to find the top * connection on. - * @return {!Blockly.ASTNode} The AST node containing the top connection. + * @return {!ASTNode} The AST node containing the top connection. * @private */ -Blockly.ASTNode.prototype.findTopASTNodeForBlock_ = function(block) { - var topConnection = block.previousConnection || block.outputConnection; +ASTNode.prototype.findTopASTNodeForBlock_ = function(block) { + const topConnection = block.previousConnection || block.outputConnection; if (topConnection) { - return /** @type {!Blockly.ASTNode} */ (Blockly.ASTNode.createConnectionNode( - topConnection)); + return /** @type {!ASTNode} */ ( + ASTNode.createConnectionNode(topConnection)); } else { - return /** @type {!Blockly.ASTNode} */ (Blockly.ASTNode.createBlockNode( - block)); + return /** @type {!ASTNode} */ (ASTNode.createBlockNode(block)); } }; /** * Get the AST node pointing to the input that the block is nested under or if * the block is not nested then get the stack AST node. - * @param {Blockly.Block} block The source block of the current location. - * @return {Blockly.ASTNode} The AST node pointing to the input connection or + * @param {Block} block The source block of the current location. + * @return {ASTNode} The AST node pointing to the input connection or * the top block of the stack this block is in. * @private */ -Blockly.ASTNode.prototype.getOutAstNodeForBlock_ = function(block) { +ASTNode.prototype.getOutAstNodeForBlock_ = function(block) { if (!block) { return null; } - var topBlock; + let topBlock; // If the block doesn't have a previous connection then it is the top of the // substack. topBlock = block.getTopStackBlock(); - var topConnection = topBlock.previousConnection || topBlock.outputConnection; + const topConnection = + topBlock.previousConnection || topBlock.outputConnection; // If the top connection has a parentInput, create an AST node pointing to // that input. if (topConnection && topConnection.targetConnection && topConnection.targetConnection.getParentInput()) { - return Blockly.ASTNode.createInputNode( + return ASTNode.createInputNode( topConnection.targetConnection.getParentInput()); } else { // Go to stack level if you are not underneath an input. - return Blockly.ASTNode.createStackNode(topBlock); + return ASTNode.createStackNode(topBlock); } }; /** * Find the first editable field or input with a connection on a given block. - * @param {!Blockly.Block} block The source block of the current location. - * @return {Blockly.ASTNode} An AST node pointing to the first field or input. + * @param {!Block} block The source block of the current location. + * @return {ASTNode} An AST node pointing to the first field or input. * Null if there are no editable fields or inputs with connections on the block. * @private */ -Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) { - var inputs = block.inputList; - for (var i = 0, input; (input = inputs[i]); i++) { - var fieldRow = input.fieldRow; - for (var j = 0, field; (field = fieldRow[j]); j++) { - if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { - return Blockly.ASTNode.createFieldNode(field); +ASTNode.prototype.findFirstFieldOrInput_ = function(block) { + const inputs = block.inputList; + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i]; + const fieldRow = input.fieldRow; + for (let j = 0; j < fieldRow.length; j++) { + const field = fieldRow[j]; + if (field.isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) { + return ASTNode.createFieldNode(field); } } if (input.connection) { - return Blockly.ASTNode.createInputNode(input); + return ASTNode.createInputNode(input); } } return null; @@ -514,55 +527,56 @@ Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) { /** * Finds the source block of the location of this node. - * @return {Blockly.Block} The source block of the location, or null if the node + * @return {Block} The source block of the location, or null if the node * is of type workspace. */ -Blockly.ASTNode.prototype.getSourceBlock = function() { - if (this.getType() === Blockly.ASTNode.types.BLOCK) { - return /** @type {Blockly.Block} */ (this.getLocation()); - } else if (this.getType() === Blockly.ASTNode.types.STACK) { - return /** @type {Blockly.Block} */ (this.getLocation()); - } else if (this.getType() === Blockly.ASTNode.types.WORKSPACE) { +ASTNode.prototype.getSourceBlock = function() { + if (this.getType() === ASTNode.types.BLOCK) { + return /** @type {Block} */ (this.getLocation()); + } else if (this.getType() === ASTNode.types.STACK) { + return /** @type {Block} */ (this.getLocation()); + } else if (this.getType() === ASTNode.types.WORKSPACE) { return null; } else { - return /** @type {Blockly.IASTNodeLocationWithBlock} */ ( - this.getLocation()).getSourceBlock(); + return /** @type {IASTNodeLocationWithBlock} */ (this.getLocation()) + .getSourceBlock(); } }; /** * Find the element to the right of the current element in the AST. - * @return {Blockly.ASTNode} An AST node that wraps the next field, connection, + * @return {ASTNode} An AST node that wraps the next field, connection, * block, or workspace. Or null if there is no node to the right. */ -Blockly.ASTNode.prototype.next = function() { +ASTNode.prototype.next = function() { switch (this.type_) { - case Blockly.ASTNode.types.STACK: + case ASTNode.types.STACK: return this.navigateBetweenStacks_(true); - case Blockly.ASTNode.types.OUTPUT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - return Blockly.ASTNode.createBlockNode(connection.getSourceBlock()); - - case Blockly.ASTNode.types.FIELD: + case ASTNode.types.OUTPUT: { + const connection = /** @type {!Connection} */ (this.location_); + return ASTNode.createBlockNode(connection.getSourceBlock()); + } + case ASTNode.types.FIELD: return this.findNextForField_(); - case Blockly.ASTNode.types.INPUT: + case ASTNode.types.INPUT: return this.findNextForInput_(); - case Blockly.ASTNode.types.BLOCK: - var block = /** @type {!Blockly.Block} */ (this.location_); - var nextConnection = block.nextConnection; - return Blockly.ASTNode.createConnectionNode(nextConnection); - - case Blockly.ASTNode.types.PREVIOUS: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - return Blockly.ASTNode.createBlockNode(connection.getSourceBlock()); - - case Blockly.ASTNode.types.NEXT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - var targetConnection = connection.targetConnection; - return Blockly.ASTNode.createConnectionNode(targetConnection); + case ASTNode.types.BLOCK: { + const block = /** @type {!Block} */ (this.location_); + const nextConnection = block.nextConnection; + return ASTNode.createConnectionNode(nextConnection); + } + case ASTNode.types.PREVIOUS: { + const connection = /** @type {!Connection} */ (this.location_); + return ASTNode.createBlockNode(connection.getSourceBlock()); + } + case ASTNode.types.NEXT: { + const connection = /** @type {!Connection} */ (this.location_); + const targetConnection = connection.targetConnection; + return ASTNode.createConnectionNode(targetConnection); + } } return null; @@ -571,31 +585,32 @@ Blockly.ASTNode.prototype.next = function() { /** * Find the element one level below and all the way to the left of the current * location. - * @return {Blockly.ASTNode} An AST node that wraps the next field, connection, + * @return {ASTNode} An AST node that wraps the next field, connection, * workspace, or block. Or null if there is nothing below this node. */ -Blockly.ASTNode.prototype.in = function() { +ASTNode.prototype.in = function() { switch (this.type_) { - case Blockly.ASTNode.types.WORKSPACE: - var workspace = /** @type {!Blockly.Workspace} */ (this.location_); - var topBlocks = workspace.getTopBlocks(true); + case ASTNode.types.WORKSPACE: { + const workspace = /** @type {!Workspace} */ (this.location_); + const topBlocks = workspace.getTopBlocks(true); if (topBlocks.length > 0) { - return Blockly.ASTNode.createStackNode(topBlocks[0]); + return ASTNode.createStackNode(topBlocks[0]); } break; - - case Blockly.ASTNode.types.STACK: - var block = /** @type {!Blockly.Block} */ (this.location_); + } + case ASTNode.types.STACK: { + const block = /** @type {!Block} */ (this.location_); return this.findTopASTNodeForBlock_(block); - - case Blockly.ASTNode.types.BLOCK: - var block = /** @type {!Blockly.Block} */ (this.location_); + } + case ASTNode.types.BLOCK: { + const block = /** @type {!Block} */ (this.location_); return this.findFirstFieldOrInput_(block); - - case Blockly.ASTNode.types.INPUT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - var targetConnection = connection.targetConnection; - return Blockly.ASTNode.createConnectionNode(targetConnection); + } + case ASTNode.types.INPUT: { + const connection = /** @type {!Connection} */ (this.location_); + const targetConnection = connection.targetConnection; + return ASTNode.createConnectionNode(targetConnection); + } } return null; @@ -603,40 +618,41 @@ Blockly.ASTNode.prototype.in = function() { /** * Find the element to the left of the current element in the AST. - * @return {Blockly.ASTNode} An AST node that wraps the previous field, + * @return {ASTNode} An AST node that wraps the previous field, * connection, workspace or block. Or null if no node exists to the left. * null. */ -Blockly.ASTNode.prototype.prev = function() { +ASTNode.prototype.prev = function() { switch (this.type_) { - case Blockly.ASTNode.types.STACK: + case ASTNode.types.STACK: return this.navigateBetweenStacks_(false); - case Blockly.ASTNode.types.OUTPUT: + case ASTNode.types.OUTPUT: return null; - case Blockly.ASTNode.types.FIELD: + case ASTNode.types.FIELD: return this.findPrevForField_(); - case Blockly.ASTNode.types.INPUT: + case ASTNode.types.INPUT: return this.findPrevForInput_(); - case Blockly.ASTNode.types.BLOCK: - var block = /** @type {!Blockly.Block} */ (this.location_); - var topConnection = block.previousConnection || block.outputConnection; - return Blockly.ASTNode.createConnectionNode(topConnection); - - case Blockly.ASTNode.types.PREVIOUS: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - var targetConnection = connection.targetConnection; + case ASTNode.types.BLOCK: { + const block = /** @type {!Block} */ (this.location_); + const topConnection = block.previousConnection || block.outputConnection; + return ASTNode.createConnectionNode(topConnection); + } + case ASTNode.types.PREVIOUS: { + const connection = /** @type {!Connection} */ (this.location_); + const targetConnection = connection.targetConnection; if (targetConnection && !targetConnection.getParentInput()) { - return Blockly.ASTNode.createConnectionNode(targetConnection); + return ASTNode.createConnectionNode(targetConnection); } break; - - case Blockly.ASTNode.types.NEXT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - return Blockly.ASTNode.createBlockNode(connection.getSourceBlock()); + } + case ASTNode.types.NEXT: { + const connection = /** @type {!Connection} */ (this.location_); + return ASTNode.createBlockNode(connection.getSourceBlock()); + } } return null; @@ -645,47 +661,50 @@ Blockly.ASTNode.prototype.prev = function() { /** * Find the next element that is one position above and all the way to the left * of the current location. - * @return {Blockly.ASTNode} An AST node that wraps the next field, connection, + * @return {ASTNode} An AST node that wraps the next field, connection, * workspace or block. Or null if we are at the workspace level. */ -Blockly.ASTNode.prototype.out = function() { +ASTNode.prototype.out = function() { switch (this.type_) { - case Blockly.ASTNode.types.STACK: - var block = /** @type {!Blockly.Block} */ (this.location_); - var blockPos = block.getRelativeToSurfaceXY(); + case ASTNode.types.STACK: { + const block = /** @type {!Block} */ (this.location_); + const blockPos = block.getRelativeToSurfaceXY(); // TODO: Make sure this is in the bounds of the workspace. - var wsCoordinate = new Blockly.utils.Coordinate( - blockPos.x, blockPos.y + Blockly.ASTNode.DEFAULT_OFFSET_Y); - return Blockly.ASTNode.createWorkspaceNode(block.workspace, wsCoordinate); - - case Blockly.ASTNode.types.OUTPUT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - var target = connection.targetConnection; + const wsCoordinate = + new Coordinate(blockPos.x, blockPos.y + ASTNode.DEFAULT_OFFSET_Y); + return ASTNode.createWorkspaceNode(block.workspace, wsCoordinate); + } + case ASTNode.types.OUTPUT: { + const connection = /** @type {!Connection} */ (this.location_); + const target = connection.targetConnection; if (target) { - return Blockly.ASTNode.createConnectionNode(target); + return ASTNode.createConnectionNode(target); } - return Blockly.ASTNode.createStackNode(connection.getSourceBlock()); - - case Blockly.ASTNode.types.FIELD: - var field = /** @type {!Blockly.Field} */ (this.location_); - return Blockly.ASTNode.createBlockNode(field.getSourceBlock()); - - case Blockly.ASTNode.types.INPUT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); - return Blockly.ASTNode.createBlockNode(connection.getSourceBlock()); - - case Blockly.ASTNode.types.BLOCK: - var block = /** @type {!Blockly.Block} */ (this.location_); + return ASTNode.createStackNode(connection.getSourceBlock()); + } + case ASTNode.types.FIELD: { + const field = /** @type {!Field} */ (this.location_); + return ASTNode.createBlockNode(field.getSourceBlock()); + } + case ASTNode.types.INPUT: { + const connection = /** @type {!Connection} */ (this.location_); + return ASTNode.createBlockNode(connection.getSourceBlock()); + } + case ASTNode.types.BLOCK: { + const block = /** @type {!Block} */ (this.location_); return this.getOutAstNodeForBlock_(block); - - case Blockly.ASTNode.types.PREVIOUS: - var connection = /** @type {!Blockly.Connection} */ (this.location_); + } + case ASTNode.types.PREVIOUS: { + const connection = /** @type {!Connection} */ (this.location_); return this.getOutAstNodeForBlock_(connection.getSourceBlock()); - - case Blockly.ASTNode.types.NEXT: - var connection = /** @type {!Blockly.Connection} */ (this.location_); + } + case ASTNode.types.NEXT: { + const connection = /** @type {!Connection} */ (this.location_); return this.getOutAstNodeForBlock_(connection.getSourceBlock()); + } } return null; }; + +exports = ASTNode; diff --git a/core/keyboard_nav/basic_cursor.js b/core/keyboard_nav/basic_cursor.js index e9780e119..78ee3fe1b 100644 --- a/core/keyboard_nav/basic_cursor.js +++ b/core/keyboard_nav/basic_cursor.js @@ -16,8 +16,8 @@ goog.module.declareLegacyNamespace(); const ASTNode = goog.require('Blockly.ASTNode'); const Cursor = goog.require('Blockly.Cursor'); -const {register, Type} = goog.require('Blockly.registry'); -const {inherits} = goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -30,7 +30,7 @@ const {inherits} = goog.require('Blockly.utils.object'); const BasicCursor = function() { BasicCursor.superClass_.constructor.call(this); }; -inherits(BasicCursor, Cursor); +object.inherits(BasicCursor, Cursor); /** * Name used for registering a basic cursor. @@ -214,6 +214,7 @@ BasicCursor.prototype.getRightMostChild_ = function(node) { return this.getRightMostChild_(newNode); }; -register(Type.CURSOR, BasicCursor.registrationName, BasicCursor); +registry.register( + registry.Type.CURSOR, BasicCursor.registrationName, BasicCursor); exports = BasicCursor; diff --git a/core/keyboard_nav/cursor.js b/core/keyboard_nav/cursor.js index de3d97498..9bc9526e2 100644 --- a/core/keyboard_nav/cursor.js +++ b/core/keyboard_nav/cursor.js @@ -16,8 +16,8 @@ goog.module.declareLegacyNamespace(); const ASTNode = goog.require('Blockly.ASTNode'); const Marker = goog.require('Blockly.Marker'); -const {DEFAULT, register, Type} = goog.require('Blockly.registry'); -const {inherits} = goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** @@ -34,7 +34,7 @@ const Cursor = function() { */ this.type = 'cursor'; }; -inherits(Cursor, Marker); +object.inherits(Cursor, Marker); /** * Find the next connection, field, or block. @@ -134,6 +134,6 @@ Cursor.prototype.out = function() { return newNode; }; -register(Type.CURSOR, DEFAULT, Cursor); +registry.register(registry.Type.CURSOR, registry.DEFAULT, Cursor); exports = Cursor; diff --git a/core/keyboard_nav/marker.js b/core/keyboard_nav/marker.js index de31d6084..4b6f341bb 100644 --- a/core/keyboard_nav/marker.js +++ b/core/keyboard_nav/marker.js @@ -11,11 +11,13 @@ */ 'use strict'; -goog.provide('Blockly.Marker'); +goog.module('Blockly.Marker'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.ASTNode'); - -goog.requireType('Blockly.blockRendering.MarkerSvg'); +/* eslint-disable-next-line no-unused-vars */ +const ASTNode = goog.requireType('Blockly.ASTNode'); +/* eslint-disable-next-line no-unused-vars */ +const MarkerSvg = goog.requireType('Blockly.blockRendering.MarkerSvg'); /** @@ -23,7 +25,7 @@ goog.requireType('Blockly.blockRendering.MarkerSvg'); * This is used in keyboard navigation to save a location in the Blockly AST. * @constructor */ -Blockly.Marker = function() { +const Marker = function() { /** * The colour of the marker. * @type {?string} @@ -32,14 +34,15 @@ Blockly.Marker = function() { /** * The current location of the marker. - * @type {Blockly.ASTNode} + * @type {ASTNode} * @private */ this.curNode_ = null; /** - * The object in charge of drawing the visual representation of the current node. - * @type {Blockly.blockRendering.MarkerSvg} + * The object in charge of drawing the visual representation of the current + * node. + * @type {MarkerSvg} * @private */ this.drawer_ = null; @@ -53,28 +56,28 @@ Blockly.Marker = function() { /** * Sets the object in charge of drawing the marker. - * @param {Blockly.blockRendering.MarkerSvg} drawer The object in charge of + * @param {MarkerSvg} drawer The object in charge of * drawing the marker. */ -Blockly.Marker.prototype.setDrawer = function(drawer) { +Marker.prototype.setDrawer = function(drawer) { this.drawer_ = drawer; }; /** * Get the current drawer for the marker. - * @return {Blockly.blockRendering.MarkerSvg} The object in charge of drawing + * @return {MarkerSvg} The object in charge of drawing * the marker. */ -Blockly.Marker.prototype.getDrawer = function() { +Marker.prototype.getDrawer = function() { return this.drawer_; }; /** * Gets the current location of the marker. - * @return {Blockly.ASTNode} The current field, connection, or block the marker + * @return {ASTNode} The current field, connection, or block the marker * is on. */ -Blockly.Marker.prototype.getCurNode = function() { +Marker.prototype.getCurNode = function() { return this.curNode_; }; @@ -82,10 +85,10 @@ Blockly.Marker.prototype.getCurNode = function() { * Set the location of the marker and call the update method. * Setting isStack to true will only work if the newLocation is the top most * output or previous connection on a stack. - * @param {Blockly.ASTNode} newNode The new location of the marker. + * @param {ASTNode} newNode The new location of the marker. */ -Blockly.Marker.prototype.setCurNode = function(newNode) { - var oldNode = this.curNode_; +Marker.prototype.setCurNode = function(newNode) { + const oldNode = this.curNode_; this.curNode_ = newNode; if (this.drawer_) { this.drawer_.draw(oldNode, this.curNode_); @@ -96,7 +99,7 @@ Blockly.Marker.prototype.setCurNode = function(newNode) { * Redraw the current marker. * @package */ -Blockly.Marker.prototype.draw = function() { +Marker.prototype.draw = function() { if (this.drawer_) { this.drawer_.draw(this.curNode_, this.curNode_); } @@ -105,7 +108,7 @@ Blockly.Marker.prototype.draw = function() { /** * Hide the marker SVG. */ -Blockly.Marker.prototype.hide = function() { +Marker.prototype.hide = function() { if (this.drawer_) { this.drawer_.hide(); } @@ -114,8 +117,10 @@ Blockly.Marker.prototype.hide = function() { /** * Dispose of this marker. */ -Blockly.Marker.prototype.dispose = function() { +Marker.prototype.dispose = function() { if (this.getDrawer()) { this.getDrawer().dispose(); } }; + +exports = Marker; diff --git a/core/keyboard_nav/tab_navigate_cursor.js b/core/keyboard_nav/tab_navigate_cursor.js index 77fc5a2a2..3847b03a9 100644 --- a/core/keyboard_nav/tab_navigate_cursor.js +++ b/core/keyboard_nav/tab_navigate_cursor.js @@ -18,7 +18,7 @@ const ASTNode = goog.require('Blockly.ASTNode'); const BasicCursor = goog.require('Blockly.BasicCursor'); /* eslint-disable-next-line no-unused-vars */ const Field = goog.requireType('Blockly.Field'); -const {inherits} = goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); /** @@ -29,7 +29,7 @@ const {inherits} = goog.require('Blockly.utils.object'); const TabNavigateCursor = function() { TabNavigateCursor.superClass_.constructor.call(this); }; -inherits(TabNavigateCursor, BasicCursor); +object.inherits(TabNavigateCursor, BasicCursor); /** * Skip all nodes except for tab navigable fields. diff --git a/core/menuitem.js b/core/menuitem.js index 91e156742..9a8ea2c67 100644 --- a/core/menuitem.js +++ b/core/menuitem.js @@ -10,11 +10,12 @@ */ 'use strict'; -goog.provide('Blockly.MenuItem'); +goog.module('Blockly.MenuItem'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.utils.aria'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.IdGenerator'); +const aria = goog.require('Blockly.utils.aria'); +const dom = goog.require('Blockly.utils.dom'); +const idGenerator = goog.require('Blockly.utils.IdGenerator'); /** @@ -25,7 +26,7 @@ goog.require('Blockly.utils.IdGenerator'); * @param {string=} opt_value Data/model associated with the menu item. * @constructor */ -Blockly.MenuItem = function(content, opt_value) { +const MenuItem = function(content, opt_value) { /** * Human-readable text of this menu item, or the HTML element to display. * @type {string|!HTMLElement} @@ -63,7 +64,7 @@ Blockly.MenuItem = function(content, opt_value) { /** * ARIA name for this menu. - * @type {?Blockly.utils.aria.Role} + * @type {?aria.Role} * @private */ this.roleName_ = null; @@ -102,9 +103,9 @@ Blockly.MenuItem = function(content, opt_value) { * Creates the menuitem's DOM. * @return {!Element} Completed DOM. */ -Blockly.MenuItem.prototype.createDom = function() { - var element = document.createElement('div'); - element.id = Blockly.utils.IdGenerator.getNextUniqueId(); +MenuItem.prototype.createDom = function() { + const element = document.createElement('div'); + element.id = idGenerator.getNextUniqueId(); this.element_ = element; // Set class and style @@ -112,20 +113,20 @@ Blockly.MenuItem.prototype.createDom = function() { element.className = 'blocklyMenuItem goog-menuitem ' + (this.enabled_ ? '' : 'blocklyMenuItemDisabled goog-menuitem-disabled ') + (this.checked_ ? 'blocklyMenuItemSelected goog-option-selected ' : '') + - (this.highlight_ ? - 'blocklyMenuItemHighlight goog-menuitem-highlight ' : '') + + (this.highlight_ ? 'blocklyMenuItemHighlight goog-menuitem-highlight ' : + '') + (this.rightToLeft_ ? 'blocklyMenuItemRtl goog-menuitem-rtl ' : ''); - var content = document.createElement('div'); + const content = document.createElement('div'); content.className = 'blocklyMenuItemContent goog-menuitem-content'; // Add a checkbox for checkable menu items. if (this.checkable_) { - var checkbox = document.createElement('div'); + const checkbox = document.createElement('div'); checkbox.className = 'blocklyMenuItemCheckbox goog-menuitem-checkbox'; content.appendChild(checkbox); } - var contentDom = /** @type {!HTMLElement} */ (this.content_); + let contentDom = /** @type {!HTMLElement} */ (this.content_); if (typeof this.content_ == 'string') { contentDom = document.createTextNode(this.content_); } @@ -134,12 +135,12 @@ Blockly.MenuItem.prototype.createDom = function() { // Initialize ARIA role and state. if (this.roleName_) { - Blockly.utils.aria.setRole(element, this.roleName_); + aria.setRole(element, this.roleName_); } - Blockly.utils.aria.setState(element, Blockly.utils.aria.State.SELECTED, + aria.setState( + element, aria.State.SELECTED, (this.checkable_ && this.checked_) || false); - Blockly.utils.aria.setState(element, Blockly.utils.aria.State.DISABLED, - !this.enabled_); + aria.setState(element, aria.State.DISABLED, !this.enabled_); return element; }; @@ -147,7 +148,7 @@ Blockly.MenuItem.prototype.createDom = function() { /** * Dispose of this menu item. */ -Blockly.MenuItem.prototype.dispose = function() { +MenuItem.prototype.dispose = function() { this.element_ = null; }; @@ -156,7 +157,7 @@ Blockly.MenuItem.prototype.dispose = function() { * @return {?Element} The DOM element. * @package */ -Blockly.MenuItem.prototype.getElement = function() { +MenuItem.prototype.getElement = function() { return this.element_; }; @@ -165,7 +166,7 @@ Blockly.MenuItem.prototype.getElement = function() { * @return {string} Unique component ID. * @package */ -Blockly.MenuItem.prototype.getId = function() { +MenuItem.prototype.getId = function() { return this.element_.id; }; @@ -174,7 +175,7 @@ Blockly.MenuItem.prototype.getId = function() { * @return {*} value Value associated with the menu item. * @package */ -Blockly.MenuItem.prototype.getValue = function() { +MenuItem.prototype.getValue = function() { return this.value_; }; @@ -183,16 +184,16 @@ Blockly.MenuItem.prototype.getValue = function() { * @param {boolean} rtl True if RTL, false if LTR. * @package */ -Blockly.MenuItem.prototype.setRightToLeft = function(rtl) { +MenuItem.prototype.setRightToLeft = function(rtl) { this.rightToLeft_ = rtl; }; /** * Set the menu item's accessibility role. - * @param {!Blockly.utils.aria.Role} roleName Role name. + * @param {!aria.Role} roleName Role name. * @package */ -Blockly.MenuItem.prototype.setRole = function(roleName) { +MenuItem.prototype.setRole = function(roleName) { this.roleName_ = roleName; }; @@ -202,7 +203,7 @@ Blockly.MenuItem.prototype.setRole = function(roleName) { * @param {boolean} checkable Whether the menu item is checkable. * @package */ -Blockly.MenuItem.prototype.setCheckable = function(checkable) { +MenuItem.prototype.setCheckable = function(checkable) { this.checkable_ = checkable; }; @@ -211,7 +212,7 @@ Blockly.MenuItem.prototype.setCheckable = function(checkable) { * @param {boolean} checked Whether to check or uncheck the component. * @package */ -Blockly.MenuItem.prototype.setChecked = function(checked) { +MenuItem.prototype.setChecked = function(checked) { this.checked_ = checked; }; @@ -220,21 +221,21 @@ Blockly.MenuItem.prototype.setChecked = function(checked) { * @param {boolean} highlight Whether to highlight or unhighlight the component. * @package */ -Blockly.MenuItem.prototype.setHighlighted = function(highlight) { +MenuItem.prototype.setHighlighted = function(highlight) { this.highlight_ = highlight; - var el = this.getElement(); + const el = this.getElement(); if (el && this.isEnabled()) { // goog-menuitem-highlight is deprecated, use blocklyMenuItemHighlight. // May 2020. - var name = 'blocklyMenuItemHighlight'; - var nameDep = 'goog-menuitem-highlight'; + const name = 'blocklyMenuItemHighlight'; + const nameDep = 'goog-menuitem-highlight'; if (highlight) { - Blockly.utils.dom.addClass(el, name); - Blockly.utils.dom.addClass(el, nameDep); + dom.addClass(el, name); + dom.addClass(el, nameDep); } else { - Blockly.utils.dom.removeClass(el, name); - Blockly.utils.dom.removeClass(el, nameDep); + dom.removeClass(el, name); + dom.removeClass(el, nameDep); } } }; @@ -244,7 +245,7 @@ Blockly.MenuItem.prototype.setHighlighted = function(highlight) { * @return {boolean} Whether the menu item is enabled. * @package */ -Blockly.MenuItem.prototype.isEnabled = function() { +MenuItem.prototype.isEnabled = function() { return this.enabled_; }; @@ -253,7 +254,7 @@ Blockly.MenuItem.prototype.isEnabled = function() { * @param {boolean} enabled Whether to enable or disable the menu item. * @package */ -Blockly.MenuItem.prototype.setEnabled = function(enabled) { +MenuItem.prototype.setEnabled = function(enabled) { this.enabled_ = enabled; }; @@ -262,7 +263,7 @@ Blockly.MenuItem.prototype.setEnabled = function(enabled) { * by the user. * @package */ -Blockly.MenuItem.prototype.performAction = function() { +MenuItem.prototype.performAction = function() { if (this.isEnabled() && this.actionHandler_) { this.actionHandler_(this); } @@ -271,10 +272,12 @@ Blockly.MenuItem.prototype.performAction = function() { /** * Set the handler that's called when the menu item is activated by the user. * `obj` will be used as the 'this' object in the function when called. - * @param {function(!Blockly.MenuItem)} fn The handler. + * @param {function(!MenuItem)} fn The handler. * @param {!Object} obj Used as the 'this' object in fn when called. * @package */ -Blockly.MenuItem.prototype.onAction = function(fn, obj) { +MenuItem.prototype.onAction = function(fn, obj) { this.actionHandler_ = fn.bind(obj); }; + +exports = MenuItem; diff --git a/core/metrics_manager.js b/core/metrics_manager.js index 841114d14..1288588df 100644 --- a/core/metrics_manager.js +++ b/core/metrics_manager.js @@ -13,7 +13,7 @@ goog.provide('Blockly.FlyoutMetricsManager'); goog.provide('Blockly.MetricsManager'); -goog.require('Blockly.IMetricsManager'); +goog.requireType('Blockly.IMetricsManager'); goog.require('Blockly.registry'); goog.require('Blockly.utils.Size'); goog.require('Blockly.utils.toolbox'); diff --git a/core/mutator.js b/core/mutator.js index 2733964c7..5f7189fcd 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -11,81 +11,88 @@ */ 'use strict'; -goog.provide('Blockly.Mutator'); +goog.module('Blockly.Mutator'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Bubble'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Abstract = goog.requireType('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Bubble = goog.require('Blockly.Bubble'); +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const Coordinate = goog.requireType('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +const Icon = goog.require('Blockly.Icon'); +const Options = goog.require('Blockly.Options'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const WorkspaceSvg = goog.require('Blockly.WorkspaceSvg'); +const Xml = goog.require('Blockly.Xml'); +const dom = goog.require('Blockly.utils.dom'); +const internalConstants = goog.require('Blockly.internalConstants'); +const object = goog.require('Blockly.utils.object'); +const toolbox = goog.require('Blockly.utils.toolbox'); +const xml = goog.require('Blockly.utils.xml'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BubbleOpen'); -goog.require('Blockly.Icon'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.Options'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.utils.toolbox'); -goog.require('Blockly.utils.xml'); -goog.require('Blockly.WorkspaceSvg'); -goog.require('Blockly.Xml'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.Connection'); -goog.requireType('Blockly.Events.Abstract'); -goog.requireType('Blockly.utils.Coordinate'); -goog.requireType('Blockly.Workspace'); /** * Class for a mutator dialog. * @param {!Array} quarkNames List of names of sub-blocks for flyout. - * @extends {Blockly.Icon} + * @extends {Icon} * @constructor */ -Blockly.Mutator = function(quarkNames) { - Blockly.Mutator.superClass_.constructor.call(this, null); +const Mutator = function(quarkNames) { + Mutator.superClass_.constructor.call(this, null); this.quarkNames_ = quarkNames; }; -Blockly.utils.object.inherits(Blockly.Mutator, Blockly.Icon); +object.inherits(Mutator, Icon); /** * Workspace in the mutator's bubble. - * @type {?Blockly.WorkspaceSvg} + * @type {?WorkspaceSvg} * @private */ -Blockly.Mutator.prototype.workspace_ = null; +Mutator.prototype.workspace_ = null; /** * Width of workspace. * @private */ -Blockly.Mutator.prototype.workspaceWidth_ = 0; +Mutator.prototype.workspaceWidth_ = 0; /** * Height of workspace. * @private */ -Blockly.Mutator.prototype.workspaceHeight_ = 0; +Mutator.prototype.workspaceHeight_ = 0; /** * Set the block this mutator is associated with. - * @param {!Blockly.BlockSvg} block The block associated with this mutator. + * @param {!BlockSvg} block The block associated with this mutator. * @package */ -Blockly.Mutator.prototype.setBlock = function(block) { +Mutator.prototype.setBlock = function(block) { this.block_ = block; }; /** * Returns the workspace inside this mutator icon's bubble. - * @return {?Blockly.WorkspaceSvg} The workspace inside this mutator icon's + * @return {?WorkspaceSvg} The workspace inside this mutator icon's * bubble or null if the mutator isn't open. * @package */ -Blockly.Mutator.prototype.getWorkspace = function() { +Mutator.prototype.getWorkspace = function() { return this.workspace_; }; @@ -94,11 +101,10 @@ Blockly.Mutator.prototype.getWorkspace = function() { * @param {!Element} group The icon group. * @protected */ -Blockly.Mutator.prototype.drawIcon_ = function(group) { +Mutator.prototype.drawIcon_ = function(group) { // Square with rounded corners. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { + dom.createSvgElement( + Svg.RECT, { 'class': 'blocklyIconShape', 'rx': '4', 'ry': '4', @@ -107,29 +113,22 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) { }, group); // Gear teeth. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { + dom.createSvgElement( + Svg.PATH, { 'class': 'blocklyIconSymbol', 'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' + - '0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' + - '-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' + - '-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' + - '-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' + - '-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' + - '0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z' + '0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' + + '-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' + + '-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' + + '-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' + + '-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' + + '0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z' }, group); // Axle hole. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.CIRCLE, - { - 'class': 'blocklyIconShape', - 'r': '2.7', - 'cx': '8', - 'cy': '8' - }, - group); + dom.createSvgElement( + Svg.CIRCLE, + {'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, group); }; /** @@ -139,9 +138,9 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) { * @protected * @override */ -Blockly.Mutator.prototype.iconClick_ = function(e) { +Mutator.prototype.iconClick_ = function(e) { if (this.block_.isEditable()) { - Blockly.Icon.prototype.iconClick_.call(this, e); + Icon.prototype.iconClick_.call(this, e); } }; @@ -150,29 +149,28 @@ Blockly.Mutator.prototype.iconClick_ = function(e) { * @return {!SVGElement} The top-level node of the editor. * @private */ -Blockly.Mutator.prototype.createEditor_ = function() { +Mutator.prototype.createEditor_ = function() { /* Create the editor. Here's the markup that will be generated: [Workspace] */ - this.svgDialog_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.SVG, - {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, - null); + this.svgDialog_ = dom.createSvgElement( + Svg.SVG, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null); // Convert the list of names into a list of XML objects for the flyout. + let quarkXml; if (this.quarkNames_.length) { - var quarkXml = Blockly.utils.xml.createElement('xml'); - for (var i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) { - var element = Blockly.utils.xml.createElement('block'); + quarkXml = xml.createElement('xml'); + for (let i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) { + const element = xml.createElement('block'); element.setAttribute('type', quarkName); quarkXml.appendChild(element); } } else { - var quarkXml = null; + quarkXml = null; } - var workspaceOptions = new Blockly.Options( - /** @type {!Blockly.BlocklyOptions} */ + const workspaceOptions = new Options( + /** @type {!BlocklyOptions} */ ({ // If you want to enable disabling, also remove the // event filter from workspaceChanged_ . @@ -184,25 +182,22 @@ Blockly.Mutator.prototype.createEditor_ = function() { 'renderer': this.block_.workspace.options.renderer, 'rendererOverrides': this.block_.workspace.options.rendererOverrides })); - workspaceOptions.toolboxPosition = this.block_.RTL ? - Blockly.utils.toolbox.Position.RIGHT : - Blockly.utils.toolbox.Position.LEFT; - var hasFlyout = !!quarkXml; + workspaceOptions.toolboxPosition = + this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT; + const hasFlyout = !!quarkXml; if (hasFlyout) { - workspaceOptions.languageTree = - Blockly.utils.toolbox.convertToolboxDefToJson(quarkXml); + workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml); } - this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions); + this.workspace_ = new WorkspaceSvg(workspaceOptions); this.workspace_.isMutator = true; - this.workspace_.addChangeListener(Blockly.Events.disableOrphans); + this.workspace_.addChangeListener(Events.disableOrphans); // Mutator flyouts go inside the mutator workspace's rather than in // a top level SVG. Instead of handling scale themselves, mutators // inherit scale from the parent workspace. // To fix this, scale needs to be applied at a different level in the DOM. - var flyoutSvg = hasFlyout ? - this.workspace_.addFlyout(Blockly.utils.Svg.G) : null; - var background = this.workspace_.createDom('blocklyMutatorBackground'); + const flyoutSvg = hasFlyout ? this.workspace_.addFlyout(Svg.G) : null; + const background = this.workspace_.createDom('blocklyMutatorBackground'); if (flyoutSvg) { // Insert the flyout after the but before the block canvas so that @@ -218,12 +213,12 @@ Blockly.Mutator.prototype.createEditor_ = function() { /** * Add or remove the UI indicating if this icon may be clicked or not. */ -Blockly.Mutator.prototype.updateEditable = function() { - Blockly.Mutator.superClass_.updateEditable.call(this); +Mutator.prototype.updateEditable = function() { + Mutator.superClass_.updateEditable.call(this); if (!this.block_.isInFlyout) { if (this.block_.isEditable()) { if (this.iconGroup_) { - Blockly.utils.dom.removeClass( + dom.removeClass( /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly'); } @@ -231,7 +226,7 @@ Blockly.Mutator.prototype.updateEditable = function() { // Close any mutator bubble. Icon is not clickable. this.setVisible(false); if (this.iconGroup_) { - Blockly.utils.dom.addClass( + dom.addClass( /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly'); } @@ -243,15 +238,15 @@ Blockly.Mutator.prototype.updateEditable = function() { * Resize the bubble to match the size of the workspace. * @private */ -Blockly.Mutator.prototype.resizeBubble_ = function() { - var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH; - var workspaceSize = this.workspace_.getCanvas().getBBox(); - var width = workspaceSize.width + workspaceSize.x; - var height = workspaceSize.height + doubleBorderWidth * 3; - var flyout = this.workspace_.getFlyout(); +Mutator.prototype.resizeBubble_ = function() { + const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH; + const workspaceSize = this.workspace_.getCanvas().getBBox(); + let width = workspaceSize.width + workspaceSize.x; + let height = workspaceSize.height + doubleBorderWidth * 3; + const flyout = this.workspace_.getFlyout(); if (flyout) { - var flyoutScrollMetrics = flyout.getWorkspace().getMetricsManager() - .getScrollMetrics(); + const flyoutScrollMetrics = + flyout.getWorkspace().getMetricsManager().getScrollMetrics(); height = Math.max(height, flyoutScrollMetrics.height + 20); width += flyout.getWidth(); } @@ -276,7 +271,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { if (this.block_.RTL) { // Scroll the workspace to always left-align. - var translation = 'translate(' + this.workspaceWidth_ + ',0)'; + const translation = 'translate(' + this.workspaceWidth_ + ',0)'; this.workspace_.getCanvas().setAttribute('transform', translation); } this.workspace_.resize(); @@ -286,7 +281,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { * A method handler for when the bubble is moved. * @private */ -Blockly.Mutator.prototype.onBubbleMove_ = function() { +Mutator.prototype.onBubbleMove_ = function() { if (this.workspace_) { this.workspace_.recordDragTargets(); } @@ -296,43 +291,44 @@ Blockly.Mutator.prototype.onBubbleMove_ = function() { * Show or hide the mutator bubble. * @param {boolean} visible True if the bubble should be visible. */ -Blockly.Mutator.prototype.setVisible = function(visible) { +Mutator.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { // No change. return; } - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BUBBLE_OPEN))( - this.block_, visible, 'mutator')); + Events.fire( + new (Events.get(Events.BUBBLE_OPEN))(this.block_, visible, 'mutator')); if (visible) { // Create the bubble. - this.bubble_ = new Blockly.Bubble( - /** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace), + this.bubble_ = new Bubble( + /** @type {!WorkspaceSvg} */ (this.block_.workspace), this.createEditor_(), this.block_.pathObject.svgPath, - /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_), null, null); + /** @type {!Coordinate} */ (this.iconXY_), null, null); // Expose this mutator's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); this.bubble_.registerMoveEvent(this.onBubbleMove_.bind(this)); - var tree = this.workspace_.options.languageTree; - var flyout = this.workspace_.getFlyout(); + const tree = this.workspace_.options.languageTree; + const flyout = this.workspace_.getFlyout(); if (tree) { flyout.init(this.workspace_); flyout.show(tree); } this.rootBlock_ = this.block_.decompose(this.workspace_); - var blocks = this.rootBlock_.getDescendants(false); - for (var i = 0, child; (child = blocks[i]); i++) { + const blocks = this.rootBlock_.getDescendants(false); + for (let i = 0, child; (child = blocks[i]); i++) { child.render(); } // The root block should not be draggable or deletable. this.rootBlock_.setMovable(false); this.rootBlock_.setDeletable(false); + let margin, x; if (flyout) { - var margin = flyout.CORNER_RADIUS * 2; - var x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin; + margin = flyout.CORNER_RADIUS * 2; + x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin; } else { - var margin = 16; - var x = margin; + margin = 16; + x = margin; } if (this.block_.RTL) { x = -x; @@ -340,10 +336,9 @@ Blockly.Mutator.prototype.setVisible = function(visible) { this.rootBlock_.moveBy(x, margin); // Save the initial connections, then listen for further changes. if (this.block_.saveConnections) { - var thisMutator = this; - var mutatorBlock = - /** @type {{saveConnections: function(!Blockly.Block)}} */ ( - this.block_); + const thisMutator = this; + const mutatorBlock = + /** @type {{saveConnections: function(!Block)}} */ (this.block_); mutatorBlock.saveConnections(this.rootBlock_); this.sourceListener_ = function() { mutatorBlock.saveConnections(thisMutator.rootBlock_); @@ -375,21 +370,20 @@ Blockly.Mutator.prototype.setVisible = function(visible) { * Update the source block when the mutator's blocks are changed. * Bump down any block that's too high. * Fired whenever a change is made to the mutator's workspace. - * @param {!Blockly.Events.Abstract} e Custom data for event. + * @param {!Abstract} e Custom data for event. * @private */ -Blockly.Mutator.prototype.workspaceChanged_ = function(e) { - if (e.isUiEvent || - (e.type == Blockly.Events.CHANGE && e.element == 'disabled')) { +Mutator.prototype.workspaceChanged_ = function(e) { + if (e.isUiEvent || (e.type == Events.CHANGE && e.element == 'disabled')) { return; } if (!this.workspace_.isDragging()) { - var blocks = this.workspace_.getTopBlocks(false); - var MARGIN = 20; + const blocks = this.workspace_.getTopBlocks(false); + const MARGIN = 20; - for (var b = 0, block; (block = blocks[b]); b++) { - var blockXY = block.getRelativeToSurfaceXY(); + for (let b = 0, block; (block = blocks[b]); b++) { + const blockXY = block.getRelativeToSurfaceXY(); // Bump any block that's above the top back inside. if (blockXY.y < MARGIN) { @@ -397,8 +391,8 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) { } // Bump any block overlapping the flyout back inside. if (block.RTL) { - var right = -MARGIN; - var flyout = this.workspace_.getFlyout(); + let right = -MARGIN; + const flyout = this.workspace_.getFlyout(); if (flyout) { right -= flyout.getWidth(); } @@ -413,13 +407,13 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) { // When the mutator's workspace changes, update the source block. if (this.rootBlock_.workspace == this.workspace_) { - Blockly.Events.setGroup(true); - var block = this.block_; - var oldMutationDom = block.mutationToDom(); - var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); + Events.setGroup(true); + const block = this.block_; + const oldMutationDom = block.mutationToDom(); + const oldMutation = oldMutationDom && Xml.domToText(oldMutationDom); // Switch off rendering while the source block is rebuilt. - var savedRendered = block.rendered; + const savedRendered = block.rendered; // TODO(#4288): We should not be setting the rendered property to false. block.rendered = false; @@ -434,18 +428,18 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) { block.render(); } - var newMutationDom = block.mutationToDom(); - var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom); + const newMutationDom = block.mutationToDom(); + const newMutation = newMutationDom && Xml.domToText(newMutationDom); if (oldMutation != newMutation) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( block, 'mutation', null, oldMutation, newMutation)); // Ensure that any bump is part of this mutation's event group. - var group = Blockly.Events.getGroup(); + const group = Events.getGroup(); setTimeout(function() { - Blockly.Events.setGroup(group); + Events.setGroup(group); block.bumpNeighbours(); - Blockly.Events.setGroup(false); - }, Blockly.internalConstants.BUMP_DELAY); + Events.setGroup(false); + }, internalConstants.BUMP_DELAY); } // Don't update the bubble until the drag has ended, to avoid moving blocks @@ -453,35 +447,35 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) { if (!this.workspace_.isDragging()) { this.resizeBubble_(); } - Blockly.Events.setGroup(false); + Events.setGroup(false); } }; /** * Dispose of this mutator. */ -Blockly.Mutator.prototype.dispose = function() { +Mutator.prototype.dispose = function() { this.block_.mutator = null; - Blockly.Icon.prototype.dispose.call(this); + Icon.prototype.dispose.call(this); }; /** * Update the styles on all blocks in the mutator. * @public */ -Blockly.Mutator.prototype.updateBlockStyle = function() { - var ws = this.workspace_; +Mutator.prototype.updateBlockStyle = function() { + const ws = this.workspace_; if (ws && ws.getAllBlocks(false)) { - var workspaceBlocks = ws.getAllBlocks(false); - for (var i = 0, block; (block = workspaceBlocks[i]); i++) { + const workspaceBlocks = ws.getAllBlocks(false); + for (let i = 0, block; (block = workspaceBlocks[i]); i++) { block.setStyle(block.getStyleName()); } - var flyout = ws.getFlyout(); + const flyout = ws.getFlyout(); if (flyout) { - var flyoutBlocks = flyout.workspace_.getAllBlocks(false); - for (var i = 0, block; (block = flyoutBlocks[i]); i++) { + const flyoutBlocks = flyout.workspace_.getAllBlocks(false); + for (let i = 0, block; (block = flyoutBlocks[i]); i++) { block.setStyle(block.getStyleName()); } } @@ -490,17 +484,17 @@ Blockly.Mutator.prototype.updateBlockStyle = function() { /** * Reconnect an block to a mutated input. - * @param {Blockly.Connection} connectionChild Connection on child block. - * @param {!Blockly.Block} block Parent block. + * @param {Connection} connectionChild Connection on child block. + * @param {!Block} block Parent block. * @param {string} inputName Name of input on parent block. * @return {boolean} True iff a reconnection was made, false otherwise. */ -Blockly.Mutator.reconnect = function(connectionChild, block, inputName) { +Mutator.reconnect = function(connectionChild, block, inputName) { if (!connectionChild || !connectionChild.getSourceBlock().workspace) { return false; // No connection or block has been deleted. } - var connectionParent = block.getInput(inputName).connection; - var currentParent = connectionChild.targetBlock(); + const connectionParent = block.getInput(inputName).connection; + const currentParent = connectionChild.targetBlock(); if ((!currentParent || currentParent == block) && connectionParent.targetConnection != connectionChild) { if (connectionParent.isConnected()) { @@ -516,14 +510,14 @@ Blockly.Mutator.reconnect = function(connectionChild, block, inputName) { /** * Get the parent workspace of a workspace that is inside a mutator, taking into * account whether it is a flyout. - * @param {Blockly.Workspace} workspace The workspace that is inside a mutator. - * @return {?Blockly.Workspace} The mutator's parent workspace or null. + * @param {Workspace} workspace The workspace that is inside a mutator. + * @return {?Workspace} The mutator's parent workspace or null. * @public */ -Blockly.Mutator.findParentWs = function(workspace) { - var outerWs = null; +Mutator.findParentWs = function(workspace) { + let outerWs = null; if (workspace && workspace.options) { - var parent = workspace.options.parentWorkspace; + const parent = workspace.options.parentWorkspace; // If we were in a flyout in a mutator, need to go up two levels to find // the actual parent. if (workspace.isFlyout) { @@ -536,3 +530,5 @@ Blockly.Mutator.findParentWs = function(workspace) { } return outerWs; }; + +exports = Mutator; diff --git a/core/names.js b/core/names.js index a559321cf..b66da4c37 100644 --- a/core/names.js +++ b/core/names.js @@ -10,12 +10,18 @@ */ 'use strict'; -goog.provide('Blockly.Names'); +goog.module('Blockly.Names'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.Msg'); - -goog.requireType('Blockly.VariableMap'); +const Msg = goog.require('Blockly.Msg'); +/* eslint-disable-next-line no-unused-vars */ +const VariableMap = goog.requireType('Blockly.VariableMap'); +const Variables = goog.require('Blockly.Variables'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const internalConstants = goog.require('Blockly.internalConstants'); +/** @suppress {extraRequire} */ +goog.requireType('Blockly.Procedures'); /** @@ -26,12 +32,12 @@ goog.requireType('Blockly.VariableMap'); * before all variable names (but not procedure names). * @constructor */ -Blockly.Names = function(reservedWords, opt_variablePrefix) { +const Names = function(reservedWords, opt_variablePrefix) { this.variablePrefix_ = opt_variablePrefix || ''; this.reservedDict_ = Object.create(null); if (reservedWords) { - var splitWords = reservedWords.split(','); - for (var i = 0; i < splitWords.length; i++) { + const splitWords = reservedWords.split(','); + for (let i = 0; i < splitWords.length; i++) { this.reservedDict_[splitWords[i]] = true; } } @@ -45,7 +51,7 @@ Blockly.Names = function(reservedWords, opt_variablePrefix) { * will never be shown to the user in the workspace or stored in the variable * map. */ -Blockly.Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE'; +Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE'; /** * When JavaScript (or most other languages) is generated, variable 'foo' and @@ -59,7 +65,7 @@ Blockly.Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE'; /** * Empty the database and start from scratch. The reserved words are kept. */ -Blockly.Names.prototype.reset = function() { +Names.prototype.reset = function() { this.db_ = Object.create(null); this.dbReverse_ = Object.create(null); this.variableMap_ = null; @@ -67,31 +73,32 @@ Blockly.Names.prototype.reset = function() { /** * Set the variable map that maps from variable name to variable object. - * @param {!Blockly.VariableMap} map The map to track. + * @param {!VariableMap} map The map to track. */ -Blockly.Names.prototype.setVariableMap = function(map) { +Names.prototype.setVariableMap = function(map) { this.variableMap_ = map; }; /** * Get the name for a user-defined variable, based on its ID. * This should only be used for variables of realm - * Blockly.internalConstants.VARIABLE_CATEGORY_NAME. + * internalConstants.VARIABLE_CATEGORY_NAME. * @param {string} id The ID to look up in the variable map. * @return {?string} The name of the referenced variable, or null if there was * no variable map or the variable was not found in the map. * @private */ -Blockly.Names.prototype.getNameForUserVariable_ = function(id) { +Names.prototype.getNameForUserVariable_ = function(id) { if (!this.variableMap_) { - console.warn('Deprecated call to Blockly.Names.prototype.getName without ' + + console.warn( + 'Deprecated call to Names.prototype.getName without ' + 'defining a variable map. To fix, add the following code in your ' + 'generator\'s init() function:\n' + 'Blockly.YourGeneratorName.nameDB_.setVariableMap(' + 'workspace.getVariableMap());'); return null; } - var variable = this.variableMap_.getVariableById(id); + const variable = this.variableMap_.getVariableById(id); if (variable) { return variable.name; } @@ -100,27 +107,27 @@ Blockly.Names.prototype.getNameForUserVariable_ = function(id) { /** * Generate names for user variables, but only ones that are being used. - * @param {!Blockly.Workspace} workspace Workspace to generate variables from. + * @param {!Workspace} workspace Workspace to generate variables from. */ -Blockly.Names.prototype.populateVariables = function(workspace) { - var variables = Blockly.Variables.allUsedVarModels(workspace); - for (var i = 0; i < variables.length; i++) { +Names.prototype.populateVariables = function(workspace) { + const variables = Variables.allUsedVarModels(workspace); + for (let i = 0; i < variables.length; i++) { this.getName( - variables[i].getId(), Blockly.internalConstants.VARIABLE_CATEGORY_NAME); + variables[i].getId(), internalConstants.VARIABLE_CATEGORY_NAME); } }; /** * Generate names for procedures. - * @param {!Blockly.Workspace} workspace Workspace to generate procedures from. + * @param {!Workspace} workspace Workspace to generate procedures from. */ -Blockly.Names.prototype.populateProcedures = function(workspace) { - var procedures = Blockly.Procedures.allProcedures(workspace); +Names.prototype.populateProcedures = function(workspace) { + let procedures = + goog.module.get('Blockly.Procedures').allProcedures(workspace); // Flatten the return vs no-return procedure lists. procedures = procedures[0].concat(procedures[1]); - for (var i = 0; i < procedures.length; i++) { - this.getName( - procedures[i][0], Blockly.internalConstants.PROCEDURE_CATEGORY_NAME); + for (let i = 0; i < procedures.length; i++) { + this.getName(procedures[i][0], internalConstants.PROCEDURE_CATEGORY_NAME); } }; @@ -132,29 +139,29 @@ Blockly.Names.prototype.populateProcedures = function(workspace) { * ('VARIABLE', 'PROCEDURE', 'DEVELOPER_VARIABLE', etc...). * @return {string} An entity name that is legal in the exported language. */ -Blockly.Names.prototype.getName = function(nameOrId, realm) { - var name = nameOrId; - if (realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME) { - var varName = this.getNameForUserVariable_(nameOrId); +Names.prototype.getName = function(nameOrId, realm) { + let name = nameOrId; + if (realm == internalConstants.VARIABLE_CATEGORY_NAME) { + const varName = this.getNameForUserVariable_(nameOrId); if (varName) { // Successful ID lookup. name = varName; } } - var normalizedName = name.toLowerCase(); + const normalizedName = name.toLowerCase(); - var isVar = realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME || - realm == Blockly.Names.DEVELOPER_VARIABLE_TYPE; + const isVar = realm == internalConstants.VARIABLE_CATEGORY_NAME || + realm == Names.DEVELOPER_VARIABLE_TYPE; - var prefix = isVar ? this.variablePrefix_ : ''; + const prefix = isVar ? this.variablePrefix_ : ''; if (!(realm in this.db_)) { this.db_[realm] = Object.create(null); } - var realmDb = this.db_[realm]; + const realmDb = this.db_[realm]; if (normalizedName in realmDb) { return prefix + realmDb[normalizedName]; } - var safeName = this.getDistinctName(name, realm); + const safeName = this.getDistinctName(name, realm); realmDb[normalizedName] = safeName.substr(prefix.length); return safeName; }; @@ -165,8 +172,8 @@ Blockly.Names.prototype.getName = function(nameOrId, realm) { * ('VARIABLE', 'PROCEDURE', 'DEVELOPER_VARIABLE', etc...). * @return {!Array} A list of Blockly entity names (no constraints). */ -Blockly.Names.prototype.getUserNames = function(realm) { - var realmDb = this.db_[realm] || {}; +Names.prototype.getUserNames = function(realm) { + const realmDb = this.db_[realm] || {}; return Object.keys(realmDb); }; @@ -180,9 +187,9 @@ Blockly.Names.prototype.getUserNames = function(realm) { * ('VARIABLE', 'PROCEDURE', 'DEVELOPER_VARIABLE', etc...). * @return {string} An entity name that is legal in the exported language. */ -Blockly.Names.prototype.getDistinctName = function(name, realm) { - var safeName = this.safeName_(name); - var i = ''; +Names.prototype.getDistinctName = function(name, realm) { + let safeName = this.safeName_(name); + let i = ''; while (this.dbReverse_[safeName + i] || (safeName + i) in this.reservedDict_) { // Collision with existing name. Create a unique name. @@ -190,9 +197,9 @@ Blockly.Names.prototype.getDistinctName = function(name, realm) { } safeName += i; this.dbReverse_[safeName] = true; - var isVar = realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME || - realm == Blockly.Names.DEVELOPER_VARIABLE_TYPE; - var prefix = isVar ? this.variablePrefix_ : ''; + const isVar = realm == internalConstants.VARIABLE_CATEGORY_NAME || + realm == Names.DEVELOPER_VARIABLE_TYPE; + const prefix = isVar ? this.variablePrefix_ : ''; return prefix + safeName; }; @@ -204,9 +211,9 @@ Blockly.Names.prototype.getDistinctName = function(name, realm) { * @return {string} Safe entity name. * @private */ -Blockly.Names.prototype.safeName_ = function(name) { +Names.prototype.safeName_ = function(name) { if (!name) { - name = Blockly.Msg['UNNAMED_KEY'] || 'unnamed'; + name = Msg['UNNAMED_KEY'] || 'unnamed'; } else { // Unfortunately names in non-latin characters will look like // _E9_9F_B3_E4_B9_90 which is pretty meaningless. @@ -227,7 +234,9 @@ Blockly.Names.prototype.safeName_ = function(name) { * @param {string} name2 Second name. * @return {boolean} True if names are the same. */ -Blockly.Names.equals = function(name1, name2) { +Names.equals = function(name1, name2) { // name1.localeCompare(name2) is slower. return name1.toLowerCase() == name2.toLowerCase(); }; + +exports = Names; diff --git a/core/options.js b/core/options.js index 58c4e378a..0ed544bae 100644 --- a/core/options.js +++ b/core/options.js @@ -10,104 +10,111 @@ */ 'use strict'; -goog.provide('Blockly.Options'); +goog.module('Blockly.Options'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.registry'); -goog.require('Blockly.Theme'); -goog.require('Blockly.Themes.Classic'); -goog.require('Blockly.utils.IdGenerator'); -goog.require('Blockly.utils.Metrics'); -goog.require('Blockly.utils.toolbox'); - -goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions'); +const Classic = goog.require('Blockly.Themes.Classic'); +const IdGenerator = goog.require('Blockly.utils.IdGenerator'); +/* eslint-disable-next-line no-unused-vars */ +const Metrics = goog.requireType('Blockly.utils.Metrics'); +const Theme = goog.require('Blockly.Theme'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const deprecation = goog.require('Blockly.utils.deprecation'); +const registry = goog.require('Blockly.registry'); +const toolbox = goog.require('Blockly.utils.toolbox'); /** * Parse the user-specified options, using reasonable defaults where behaviour * is unspecified. - * @param {!Blockly.BlocklyOptions} options Dictionary of options. - * Specification: https://developers.google.com/blockly/guides/get-started/web#configuration + * @param {!BlocklyOptions} options Dictionary of options. + * Specification: + * https://developers.google.com/blockly/guides/get-started/web#configuration * @constructor */ -Blockly.Options = function(options) { - var readOnly = !!options['readOnly']; - if (readOnly) { - var toolboxJsonDef = null; - var hasCategories = false; - var hasTrashcan = false; - var hasCollapse = false; - var hasComments = false; - var hasDisable = false; - var hasSounds = false; - } else { - var toolboxJsonDef = Blockly.utils.toolbox.convertToolboxDefToJson(options['toolbox']); - var hasCategories = Blockly.utils.toolbox.hasCategories(toolboxJsonDef); - var hasTrashcan = options['trashcan']; +const Options = function(options) { + let toolboxJsonDef = null; + let hasCategories = false; + let hasTrashcan = false; + let hasCollapse = false; + let hasComments = false; + let hasDisable = false; + let hasSounds = false; + const readOnly = !!options['readOnly']; + if (!readOnly) { + toolboxJsonDef = toolbox.convertToolboxDefToJson(options['toolbox']); + hasCategories = toolbox.hasCategories(toolboxJsonDef); + hasTrashcan = options['trashcan']; if (hasTrashcan === undefined) { hasTrashcan = hasCategories; } - var maxTrashcanContents = options['maxTrashcanContents']; - if (hasTrashcan) { - if (maxTrashcanContents === undefined) { - maxTrashcanContents = 32; - } - } else { - maxTrashcanContents = 0; - } - var hasCollapse = options['collapse']; + hasCollapse = options['collapse']; if (hasCollapse === undefined) { hasCollapse = hasCategories; } - var hasComments = options['comments']; + hasComments = options['comments']; if (hasComments === undefined) { hasComments = hasCategories; } - var hasDisable = options['disable']; + hasDisable = options['disable']; if (hasDisable === undefined) { hasDisable = hasCategories; } - var hasSounds = options['sounds']; + hasSounds = options['sounds']; if (hasSounds === undefined) { hasSounds = true; } } - var rtl = !!options['rtl']; - var horizontalLayout = options['horizontalLayout']; + + let maxTrashcanContents = options['maxTrashcanContents']; + if (hasTrashcan) { + if (maxTrashcanContents === undefined) { + maxTrashcanContents = 32; + } + } else { + maxTrashcanContents = 0; + } + const rtl = !!options['rtl']; + let horizontalLayout = options['horizontalLayout']; if (horizontalLayout === undefined) { horizontalLayout = false; } - var toolboxAtStart = options['toolboxPosition']; + let toolboxAtStart = options['toolboxPosition']; toolboxAtStart = toolboxAtStart !== 'end'; - /** @type {!Blockly.utils.toolbox.Position} */ - var toolboxPosition; + /** @type {!toolbox.Position} */ + let toolboxPosition; if (horizontalLayout) { - toolboxPosition = toolboxAtStart ? - Blockly.utils.toolbox.Position.TOP : Blockly.utils.toolbox.Position.BOTTOM; + toolboxPosition = + toolboxAtStart ? toolbox.Position.TOP : toolbox.Position.BOTTOM; } else { - toolboxPosition = (toolboxAtStart == rtl) ? - Blockly.utils.toolbox.Position.RIGHT : Blockly.utils.toolbox.Position.LEFT; + toolboxPosition = (toolboxAtStart == rtl) ? toolbox.Position.RIGHT : + toolbox.Position.LEFT; } - var hasCss = options['css']; + let hasCss = options['css']; if (hasCss === undefined) { hasCss = true; } - var pathToMedia = 'https://blockly-demo.appspot.com/static/media/'; + let pathToMedia = 'https://blockly-demo.appspot.com/static/media/'; if (options['media']) { pathToMedia = options['media']; } else if (options['path']) { // 'path' is a deprecated option which has been replaced by 'media'. pathToMedia = options['path'] + 'media/'; } + let oneBasedIndex; if (options['oneBasedIndex'] === undefined) { - var oneBasedIndex = true; + oneBasedIndex = true; } else { - var oneBasedIndex = !!options['oneBasedIndex']; + oneBasedIndex = !!options['oneBasedIndex']; } - var renderer = options['renderer'] || 'geras'; + const renderer = options['renderer'] || 'geras'; - var plugins = options['plugins'] || {}; + const plugins = options['plugins'] || {}; /** @type {boolean} */ this.RTL = rtl; @@ -129,8 +136,8 @@ Blockly.Options = function(options) { this.pathToMedia = pathToMedia; /** @type {boolean} */ this.hasCategories = hasCategories; - /** @type {!Blockly.Options.MoveOptions} */ - this.moveOptions = Blockly.Options.parseMoveOptions_(options, hasCategories); + /** @type {!Options.MoveOptions} */ + this.moveOptions = Options.parseMoveOptions_(options, hasCategories); /** @deprecated January 2019 */ this.hasScrollbars = !!this.moveOptions.scrollbars; /** @type {boolean} */ @@ -143,16 +150,16 @@ Blockly.Options = function(options) { this.hasCss = hasCss; /** @type {boolean} */ this.horizontalLayout = horizontalLayout; - /** @type {?Blockly.utils.toolbox.ToolboxInfo} */ + /** @type {?toolbox.ToolboxInfo} */ this.languageTree = toolboxJsonDef; - /** @type {!Blockly.Options.GridOptions} */ - this.gridOptions = Blockly.Options.parseGridOptions_(options); - /** @type {!Blockly.Options.ZoomOptions} */ - this.zoomOptions = Blockly.Options.parseZoomOptions_(options); - /** @type {!Blockly.utils.toolbox.Position} */ + /** @type {!Options.GridOptions} */ + this.gridOptions = Options.parseGridOptions_(options); + /** @type {!Options.ZoomOptions} */ + this.zoomOptions = Options.parseZoomOptions_(options); + /** @type {!toolbox.Position} */ this.toolboxPosition = toolboxPosition; - /** @type {!Blockly.Theme} */ - this.theme = Blockly.Options.parseThemeOptions_(options); + /** @type {!Theme} */ + this.theme = Options.parseThemeOptions_(options); /** @type {string} */ this.renderer = renderer; /** @type {?Object} */ @@ -169,7 +176,7 @@ Blockly.Options = function(options) { * The parent of the current workspace, or null if there is no parent * workspace. We can assert that this is of type WorkspaceSvg as opposed to * Workspace as this is only used in a rendered workspace. - * @type {Blockly.WorkspaceSvg} + * @type {WorkspaceSvg} */ this.parentWorkspace = options['parentWorkspace']; @@ -180,14 +187,6 @@ Blockly.Options = function(options) { this.plugins = plugins; }; -/** - * Blockly options. - * This interface is further described in - * `typings/parts/blockly-interfaces.d.ts`. - * @interface - */ -Blockly.BlocklyOptions = function() {}; - /** * Grid Options. * @typedef {{ @@ -197,17 +196,17 @@ Blockly.BlocklyOptions = function() {}; * spacing: number * }} */ -Blockly.Options.GridOptions; +Options.GridOptions; /** * Move Options. * @typedef {{ * drag: boolean, - * scrollbars: (boolean | !Blockly.Options.ScrollbarOptions), + * scrollbars: (boolean | !Options.ScrollbarOptions), * wheel: boolean * }} */ -Blockly.Options.MoveOptions; +Options.MoveOptions; /** * Scrollbar Options. @@ -216,7 +215,7 @@ Blockly.Options.MoveOptions; * vertical: boolean * }} */ -Blockly.Options.ScrollbarOptions; +Options.ScrollbarOptions; /** * Zoom Options. @@ -230,7 +229,7 @@ Blockly.Options.ScrollbarOptions; * wheel: boolean * }} */ -Blockly.Options.ZoomOptions; +Options.ZoomOptions; /** * If set, sets the translation of the workspace to match the scrollbars. @@ -238,25 +237,25 @@ Blockly.Options.ZoomOptions; * is a float between 0 and 1 specifying the degree of scrolling. * @return {void} */ -Blockly.Options.prototype.setMetrics; +Options.prototype.setMetrics; /** * Return an object with the metrics required to size the workspace. - * @return {!Blockly.utils.Metrics} Contains size and position metrics. + * @return {!Metrics} Contains size and position metrics. */ -Blockly.Options.prototype.getMetrics; +Options.prototype.getMetrics; /** * Parse the user-specified move options, using reasonable defaults where * behaviour is unspecified. * @param {!Object} options Dictionary of options. * @param {boolean} hasCategories Whether the workspace has categories or not. - * @return {!Blockly.Options.MoveOptions} Normalized move options. + * @return {!Options.MoveOptions} Normalized move options. * @private */ -Blockly.Options.parseMoveOptions_ = function(options, hasCategories) { - var move = options['move'] || {}; - var moveOptions = {}; +Options.parseMoveOptions_ = function(options, hasCategories) { + const move = options['move'] || {}; + const moveOptions = {}; if (move['scrollbars'] === undefined && options['scrollbars'] === undefined) { moveOptions.scrollbars = hasCategories; } else if (typeof move['scrollbars'] == 'object') { @@ -268,7 +267,8 @@ Blockly.Options.parseMoveOptions_ = function(options, hasCategories) { // !!moveOptions.scrollbars. if (moveOptions.scrollbars.horizontal && moveOptions.scrollbars.vertical) { moveOptions.scrollbars = true; - } else if (!moveOptions.scrollbars.horizontal && + } else if ( + !moveOptions.scrollbars.horizontal && !moveOptions.scrollbars.vertical) { moveOptions.scrollbars = false; } @@ -298,12 +298,12 @@ Blockly.Options.parseMoveOptions_ = function(options, hasCategories) { * behaviour is unspecified. See zoom documentation: * https://developers.google.com/blockly/guides/configure/web/zoom * @param {!Object} options Dictionary of options. - * @return {!Blockly.Options.ZoomOptions} Normalized zoom options. + * @return {!Options.ZoomOptions} Normalized zoom options. * @private */ -Blockly.Options.parseZoomOptions_ = function(options) { - var zoom = options['zoom'] || {}; - var zoomOptions = {}; +Options.parseZoomOptions_ = function(options) { + const zoom = options['zoom'] || {}; + const zoomOptions = {}; if (zoom['controls'] === undefined) { zoomOptions.controls = false; } else { @@ -347,12 +347,12 @@ Blockly.Options.parseZoomOptions_ = function(options) { * behaviour is unspecified. See grid documentation: * https://developers.google.com/blockly/guides/configure/web/grid * @param {!Object} options Dictionary of options. - * @return {!Blockly.Options.GridOptions} Normalized grid options. + * @return {!Options.GridOptions} Normalized grid options. * @private */ -Blockly.Options.parseGridOptions_ = function(options) { - var grid = options['grid'] || {}; - var gridOptions = {}; +Options.parseGridOptions_ = function(options) { + const grid = options['grid'] || {}; + const gridOptions = {}; gridOptions.spacing = Number(grid['spacing']) || 0; gridOptions.colour = grid['colour'] || '#888'; gridOptions.length = @@ -365,19 +365,19 @@ Blockly.Options.parseGridOptions_ = function(options) { * Parse the user-specified theme options, using the classic theme as a default. * https://developers.google.com/blockly/guides/configure/web/themes * @param {!Object} options Dictionary of options. - * @return {!Blockly.Theme} A Blockly Theme. + * @return {!Theme} A Blockly Theme. * @private */ -Blockly.Options.parseThemeOptions_ = function(options) { - var theme = options['theme'] || Blockly.Themes.Classic; +Options.parseThemeOptions_ = function(options) { + const theme = options['theme'] || Classic; if (typeof theme == 'string') { - return /** @type {!Blockly.Theme} */ ( - Blockly.registry.getObject(Blockly.registry.Type.THEME, theme)); - } else if (theme instanceof Blockly.Theme) { - return /** @type {!Blockly.Theme} */ (theme); + return /** @type {!Theme} */ ( + registry.getObject(registry.Type.THEME, theme)); + } else if (theme instanceof Theme) { + return /** @type {!Theme} */ (theme); } - return Blockly.Theme.defineTheme(theme.name || - ('builtin' + Blockly.utils.IdGenerator.getNextUniqueId()), theme); + return Theme.defineTheme( + theme.name || ('builtin' + IdGenerator.getNextUniqueId()), theme); }; /** @@ -385,13 +385,13 @@ Blockly.Options.parseThemeOptions_ = function(options) { * @param {?Node|?string} toolboxDef DOM tree of blocks, or text representation * of same. * @return {?Node} DOM tree of blocks, or null. - * @deprecated Use Blockly.utils.toolbox.parseToolboxTree. (2020 September 28) + * @deprecated Use toolbox.parseToolboxTree. (2020 September 28) */ -Blockly.Options.parseToolboxTree = function(toolboxDef) { - Blockly.utils.deprecation.warn( - 'Blockly.Options.parseToolboxTree', - 'September 2020', - 'September 2021', - 'Blockly.utils.toolbox.parseToolboxTree'); - return Blockly.utils.toolbox.parseToolboxTree(toolboxDef); +Options.parseToolboxTree = function(toolboxDef) { + deprecation.warn( + 'Options.parseToolboxTree', 'September 2020', 'September 2021', + 'toolbox.parseToolboxTree'); + return toolbox.parseToolboxTree(toolboxDef); }; + +exports = Options; diff --git a/core/positionable_helpers.js b/core/positionable_helpers.js index 3dc52e50c..812c5f7be 100644 --- a/core/positionable_helpers.js +++ b/core/positionable_helpers.js @@ -10,171 +10,170 @@ */ 'use strict'; -goog.provide('Blockly.uiPosition'); +goog.module('Blockly.uiPosition'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Scrollbar'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.toolbox'); - -goog.requireType('Blockly.MetricsManager'); -goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const MetricsManager = goog.requireType('Blockly.MetricsManager'); +const Rect = goog.require('Blockly.utils.Rect'); +const Scrollbar = goog.require('Blockly.Scrollbar'); +/* eslint-disable-next-line no-unused-vars */ +const Size = goog.requireType('Blockly.utils.Size'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const toolbox = goog.require('Blockly.utils.toolbox'); /** * Enum for vertical positioning. * @enum {number} - * @package */ -Blockly.uiPosition.verticalPosition = { +const verticalPosition = { TOP: 0, BOTTOM: 1 }; +/** @package */ +exports.verticalPosition = verticalPosition; /** * Enum for horizontal positioning. * @enum {number} - * @package */ -Blockly.uiPosition.horizontalPosition = { +const horizontalPosition = { LEFT: 0, RIGHT: 1 }; +/** @package */ +exports.horizontalPosition = horizontalPosition; /** * An object defining a horizontal and vertical positioning. * @typedef {{ - * horizontal: !Blockly.uiPosition.horizontalPosition, - * vertical: !Blockly.uiPosition.verticalPosition + * horizontal: !horizontalPosition, + * vertical: !verticalPosition * }} - * @package */ -Blockly.uiPosition.Position; +let Position; +/** @package */ +exports.Position = Position; /** * Enum for bump rules to use for dealing with collisions. * @enum {number} - * @package */ -Blockly.uiPosition.bumpDirection = { +const bumpDirection = { UP: 0, DOWN: 1 }; +/** @package */ +exports.bumpDirection = bumpDirection; /** * Returns a rectangle representing reasonable position for where to place a UI * element of the specified size given the restraints and locations of the * scrollbars. This method does not take into account any already placed UI * elements. - * @param {!Blockly.uiPosition.Position} position The starting + * @param {!Position} position The starting * horizontal and vertical position. - * @param {!Blockly.utils.Size} size the size of the UI element to get a start + * @param {!Size} size the size of the UI element to get a start * position for. * @param {number} horizontalPadding The horizontal padding to use. * @param {number} verticalPadding The vertical padding to use. - * @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace UI metrics. - * @param {!Blockly.WorkspaceSvg} workspace The workspace. - * @return {!Blockly.utils.Rect} The suggested start position. - * @package + * @param {!MetricsManager.UiMetrics} metrics The workspace UI metrics. + * @param {!WorkspaceSvg} workspace The workspace. + * @return {!Rect} The suggested start position. */ -Blockly.uiPosition.getStartPositionRect = function( - position, size, horizontalPadding, - verticalPadding, metrics, workspace) { +const getStartPositionRect = function( + position, size, horizontalPadding, verticalPadding, metrics, workspace) { // Horizontal positioning. - var left = 0; - var hasVerticalScrollbar = + let left = 0; + const hasVerticalScrollbar = workspace.scrollbar && workspace.scrollbar.canScrollVertically(); - if (position.horizontal === - Blockly.uiPosition.horizontalPosition.LEFT) { + if (position.horizontal === horizontalPosition.LEFT) { left = metrics.absoluteMetrics.left + horizontalPadding; if (hasVerticalScrollbar && workspace.RTL) { - left += Blockly.Scrollbar.scrollbarThickness; + left += Scrollbar.scrollbarThickness; } } else { // position.horizontal == horizontalPosition.RIGHT left = metrics.absoluteMetrics.left + metrics.viewMetrics.width - size.width - horizontalPadding; if (hasVerticalScrollbar && !workspace.RTL) { - left -= Blockly.Scrollbar.scrollbarThickness; + left -= Scrollbar.scrollbarThickness; } } // Vertical positioning. - var top = 0; - if (position.vertical === - Blockly.uiPosition.verticalPosition.TOP) { + let top = 0; + if (position.vertical === verticalPosition.TOP) { top = metrics.absoluteMetrics.top + verticalPadding; } else { // position.vertical == verticalPosition.BOTTOM top = metrics.absoluteMetrics.top + metrics.viewMetrics.height - size.height - verticalPadding; if (workspace.scrollbar && workspace.scrollbar.canScrollHorizontally()) { // The scrollbars are always positioned on the bottom if they exist. - top -= Blockly.Scrollbar.scrollbarThickness; + top -= Scrollbar.scrollbarThickness; } } - return new Blockly.utils.Rect( - top, top + size.height, left, left + size.width); + return new Rect(top, top + size.height, left, left + size.width); }; +/** @package */ +exports.getStartPositionRect = getStartPositionRect; /** * Returns a corner position that is on the opposite side of the workspace from * the toolbox. * If in horizontal orientation, defaults to the bottom corner. If in vertical * orientation, defaults to the right corner. - * @param {!Blockly.WorkspaceSvg} workspace The workspace. - * @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace metrics. - * @return {!Blockly.uiPosition.Position} The suggested corner position. - * @package + * @param {!WorkspaceSvg} workspace The workspace. + * @param {!MetricsManager.UiMetrics} metrics The workspace metrics. + * @return {!Position} The suggested corner position. */ -Blockly.uiPosition.getCornerOppositeToolbox = function(workspace, metrics) { - var leftCorner = - metrics.toolboxMetrics.position !== Blockly.utils.toolbox.Position.LEFT && +const getCornerOppositeToolbox = function(workspace, metrics) { + const leftCorner = + metrics.toolboxMetrics.position !== toolbox.Position.LEFT && (!workspace.horizontalLayout || workspace.RTL); - var topCorner = - metrics.toolboxMetrics.position === Blockly.utils.toolbox.Position.BOTTOM; - var horizontalPosition = leftCorner ? - Blockly.uiPosition.horizontalPosition.LEFT : - Blockly.uiPosition.horizontalPosition.RIGHT; - var verticalPosition = topCorner ? - Blockly.uiPosition.verticalPosition.TOP : - Blockly.uiPosition.verticalPosition.BOTTOM; - return { - horizontal: horizontalPosition, - vertical: verticalPosition - }; + const topCorner = metrics.toolboxMetrics.position === toolbox.Position.BOTTOM; + const hPosition = + leftCorner ? horizontalPosition.LEFT : horizontalPosition.RIGHT; + const vPosition = topCorner ? verticalPosition.TOP : verticalPosition.BOTTOM; + return {horizontal: hPosition, vertical: vPosition}; }; +/** @package */ +exports.getCornerOppositeToolbox = getCornerOppositeToolbox; /** * Returns a position Rect based on a starting position that is bumped * so that it doesn't intersect with any of the provided savedPositions. This * method does not check that the bumped position is still within bounds. - * @param {!Blockly.utils.Rect} startRect The starting position to use. + * @param {!Rect} startRect The starting position to use. * @param {number} margin The margin to use between elements when bumping. - * @param {!Blockly.uiPosition.bumpDirection} bumpDirection The direction - * to bump if there is a collision with an existing UI element. - * @param {!Array} savedPositions List of rectangles that + * @param {!bumpDirection} bumpDir The direction to bump if there is a collision + * with an existing UI element. + * @param {!Array} savedPositions List of rectangles that * represent the positions of UI elements already placed. - * @return {!Blockly.utils.Rect} The suggested position rectangle. - * @package + * @return {!Rect} The suggested position rectangle. */ -Blockly.uiPosition.bumpPositionRect = function( - startRect, margin, bumpDirection, savedPositions) { - var top = startRect.top; - var left = startRect.left; - var width = startRect.right - startRect.left; - var height = startRect.bottom - startRect.top; +const bumpPositionRect = function(startRect, margin, bumpDir, savedPositions) { + let top = startRect.top; + const left = startRect.left; + const width = startRect.right - startRect.left; + const height = startRect.bottom - startRect.top; // Check for collision and bump if needed. - var boundingRect = startRect; - for (var i = 0, otherEl; (otherEl = savedPositions[i]); i++) { + let boundingRect = startRect; + for (let i = 0; i < savedPositions.length; i++) { + const otherEl = savedPositions[i]; if (boundingRect.intersects(otherEl)) { - if (bumpDirection === Blockly.uiPosition.bumpDirection.UP) { + if (bumpDir === bumpDirection.UP) { top = otherEl.top - height - margin; - } else { // bumpDirection == bumpDirection.DOWN + } else { // bumpDir == bumpDirection.DOWN top = otherEl.bottom + margin; } // Recheck other savedPositions - boundingRect = new Blockly.utils.Rect( - top, top + height, left, left + width); + boundingRect = new Rect(top, top + height, left, left + width); i = -1; } } return boundingRect; }; +/** @package */ +exports.bumpPositionRect = bumpPositionRect; diff --git a/core/procedures.js b/core/procedures.js index 3323bb130..e63618e7c 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -14,38 +14,35 @@ * @name Blockly.Procedures * @namespace */ -goog.provide('Blockly.Procedures'); +goog.module('Blockly.Procedures'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Blocks'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Abstract = goog.requireType('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Blocks = goog.require('Blockly.Blocks'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +const Msg = goog.require('Blockly.Msg'); +const Names = goog.require('Blockly.Names'); +const Variables = goog.require('Blockly.Variables'); +const Workspace = goog.require('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const Xml = goog.require('Blockly.Xml'); +const utilsXml = goog.require('Blockly.utils.xml'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockChange'); -goog.require('Blockly.Field'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.Msg'); -goog.require('Blockly.Names'); -goog.require('Blockly.utils.xml'); -goog.require('Blockly.Workspace'); -goog.require('Blockly.Xml'); -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.Events.Abstract'); -goog.requireType('Blockly.WorkspaceSvg'); - - -/** - * Constant to separate procedure names from variables and generated functions - * when running generators. - * @deprecated Use Blockly.internalConstants.PROCEDURE_CATEGORY_NAME - */ -Blockly.Procedures.NAME_TYPE = - Blockly.internalConstants.PROCEDURE_CATEGORY_NAME; /** * The default argument for a procedures_mutatorarg block. * @type {string} */ -Blockly.Procedures.DEFAULT_ARG = 'x'; +const DEFAULT_ARG = 'x'; +exports.DEFAULT_ARG = DEFAULT_ARG; /** * Procedure block type. @@ -55,28 +52,32 @@ Blockly.Procedures.DEFAULT_ARG = 'x'; * getProcedureDef: function():!Array * }} */ -Blockly.Procedures.ProcedureBlock; +let ProcedureBlock; +exports.ProcedureBlock = ProcedureBlock; /** * Find all user-created procedure definitions in a workspace. - * @param {!Blockly.Workspace} root Root workspace. + * @param {!Workspace} root Root workspace. * @return {!Array>} Pair of arrays, the * first contains procedures without return variables, the second with. * Each procedure is defined by a three-element list of name, parameter * list, and return value boolean. */ -Blockly.Procedures.allProcedures = function(root) { - var proceduresNoReturn = root.getBlocksByType('procedures_defnoreturn', false) - .map(function(block) { - return /** @type {!Blockly.Procedures.ProcedureBlock} */ (block).getProcedureDef(); +const allProcedures = function(root) { + const proceduresNoReturn = + root.getBlocksByType('procedures_defnoreturn', false) + .map(function(block) { + return /** @type {!ProcedureBlock} */ (block).getProcedureDef(); + }); + const proceduresReturn = + root.getBlocksByType('procedures_defreturn', false).map(function(block) { + return /** @type {!ProcedureBlock} */ (block).getProcedureDef(); }); - var proceduresReturn = root.getBlocksByType('procedures_defreturn', false).map(function(block) { - return /** @type {!Blockly.Procedures.ProcedureBlock} */ (block).getProcedureDef(); - }); - proceduresNoReturn.sort(Blockly.Procedures.procTupleComparator_); - proceduresReturn.sort(Blockly.Procedures.procTupleComparator_); + proceduresNoReturn.sort(procTupleComparator); + proceduresReturn.sort(procTupleComparator); return [proceduresNoReturn, proceduresReturn]; }; +exports.allProcedures = allProcedures; /** * Comparison function for case-insensitive sorting of the first element of @@ -84,9 +85,8 @@ Blockly.Procedures.allProcedures = function(root) { * @param {!Array} ta First tuple. * @param {!Array} tb Second tuple. * @return {number} -1, 0, or 1 to signify greater than, equality, or less than. - * @private */ -Blockly.Procedures.procTupleComparator_ = function(ta, tb) { +const procTupleComparator = function(ta, tb) { return ta[0].localeCompare(tb[0], undefined, {sensitivity: 'base'}); }; @@ -95,18 +95,18 @@ Blockly.Procedures.procTupleComparator_ = function(ta, tb) { * Take the proposed procedure name, and return a legal name i.e. one that * is not empty and doesn't collide with other procedures. * @param {string} name Proposed procedure name. - * @param {!Blockly.Block} block Block to disambiguate. + * @param {!Block} block Block to disambiguate. * @return {string} Non-colliding name. */ -Blockly.Procedures.findLegalName = function(name, block) { +const findLegalName = function(name, block) { if (block.isInFlyout) { // Flyouts can have multiple procedures called 'do something'. return name; } - name = name || Blockly.Msg['UNNAMED_KEY'] || 'unnamed'; - while (!Blockly.Procedures.isLegalName_(name, block.workspace, block)) { + name = name || Msg['UNNAMED_KEY'] || 'unnamed'; + while (!isLegalName(name, block.workspace, block)) { // Collision with another procedure. - var r = name.match(/^(.*?)(\d+)$/); + const r = name.match(/^(.*?)(\d+)$/); if (!r) { name += '2'; } else { @@ -115,68 +115,68 @@ Blockly.Procedures.findLegalName = function(name, block) { } return name; }; +exports.findLegalName = findLegalName; /** * Does this procedure have a legal name? Illegal names include names of * procedures already defined. * @param {string} name The questionable name. - * @param {!Blockly.Workspace} workspace The workspace to scan for collisions. - * @param {Blockly.Block=} opt_exclude Optional block to exclude from + * @param {!Workspace} workspace The workspace to scan for collisions. + * @param {Block=} opt_exclude Optional block to exclude from * comparisons (one doesn't want to collide with oneself). * @return {boolean} True if the name is legal. - * @private */ -Blockly.Procedures.isLegalName_ = function(name, workspace, opt_exclude) { - return !Blockly.Procedures.isNameUsed(name, workspace, opt_exclude); +const isLegalName = function(name, workspace, opt_exclude) { + return !isNameUsed(name, workspace, opt_exclude); }; /** * Return if the given name is already a procedure name. * @param {string} name The questionable name. - * @param {!Blockly.Workspace} workspace The workspace to scan for collisions. - * @param {Blockly.Block=} opt_exclude Optional block to exclude from + * @param {!Workspace} workspace The workspace to scan for collisions. + * @param {Block=} opt_exclude Optional block to exclude from * comparisons (one doesn't want to collide with oneself). * @return {boolean} True if the name is used, otherwise return false. */ -Blockly.Procedures.isNameUsed = function(name, workspace, opt_exclude) { - var blocks = workspace.getAllBlocks(false); +const isNameUsed = function(name, workspace, opt_exclude) { + const blocks = workspace.getAllBlocks(false); // Iterate through every block and check the name. - for (var i = 0; i < blocks.length; i++) { + for (let i = 0; i < blocks.length; i++) { if (blocks[i] == opt_exclude) { continue; } if (blocks[i].getProcedureDef) { - var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( - blocks[i]); - var procName = procedureBlock.getProcedureDef(); - if (Blockly.Names.equals(procName[0], name)) { + const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]); + const procName = procedureBlock.getProcedureDef(); + if (Names.equals(procName[0], name)) { return true; } } } return false; }; +exports.isNameUsed = isNameUsed; /** * Rename a procedure. Called by the editable field. * @param {string} name The proposed new name. * @return {string} The accepted name. - * @this {Blockly.Field} + * @this {Field} */ -Blockly.Procedures.rename = function(name) { +const rename = function(name) { // Strip leading and trailing whitespace. Beyond this, all names are legal. name = name.trim(); - var legalName = Blockly.Procedures.findLegalName(name, - /** @type {!Blockly.Block} */ (this.getSourceBlock())); - var oldName = this.getValue(); + const legalName = findLegalName( + name, + /** @type {!Block} */ (this.getSourceBlock())); + const oldName = this.getValue(); if (oldName != name && oldName != legalName) { // Rename any callers. - var blocks = this.getSourceBlock().workspace.getAllBlocks(false); - for (var i = 0; i < blocks.length; i++) { + const blocks = this.getSourceBlock().workspace.getAllBlocks(false); + for (let i = 0; i < blocks.length; i++) { if (blocks[i].renameProcedure) { - var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( - blocks[i]); + const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]); procedureBlock.renameProcedure( /** @type {string} */ (oldName), legalName); } @@ -184,45 +184,46 @@ Blockly.Procedures.rename = function(name) { } return legalName; }; +exports.rename = rename; /** * Construct the blocks required by the flyout for the procedure category. - * @param {!Blockly.Workspace} workspace The workspace containing procedures. + * @param {!Workspace} workspace The workspace containing procedures. * @return {!Array} Array of XML block elements. */ -Blockly.Procedures.flyoutCategory = function(workspace) { - var xmlList = []; - if (Blockly.Blocks['procedures_defnoreturn']) { +const flyoutCategory = function(workspace) { + const xmlList = []; + if (Blocks['procedures_defnoreturn']) { // // do something // - var block = Blockly.utils.xml.createElement('block'); + const block = utilsXml.createElement('block'); block.setAttribute('type', 'procedures_defnoreturn'); block.setAttribute('gap', 16); - var nameField = Blockly.utils.xml.createElement('field'); + const nameField = utilsXml.createElement('field'); nameField.setAttribute('name', 'NAME'); - nameField.appendChild(Blockly.utils.xml.createTextNode( - Blockly.Msg['PROCEDURES_DEFNORETURN_PROCEDURE'])); + nameField.appendChild( + utilsXml.createTextNode(Msg['PROCEDURES_DEFNORETURN_PROCEDURE'])); block.appendChild(nameField); xmlList.push(block); } - if (Blockly.Blocks['procedures_defreturn']) { + if (Blocks['procedures_defreturn']) { // // do something // - var block = Blockly.utils.xml.createElement('block'); + const block = utilsXml.createElement('block'); block.setAttribute('type', 'procedures_defreturn'); block.setAttribute('gap', 16); - var nameField = Blockly.utils.xml.createElement('field'); + const nameField = utilsXml.createElement('field'); nameField.setAttribute('name', 'NAME'); - nameField.appendChild(Blockly.utils.xml.createTextNode( - Blockly.Msg['PROCEDURES_DEFRETURN_PROCEDURE'])); + nameField.appendChild( + utilsXml.createTextNode(Msg['PROCEDURES_DEFRETURN_PROCEDURE'])); block.appendChild(nameField); xmlList.push(block); } - if (Blockly.Blocks['procedures_ifreturn']) { + if (Blocks['procedures_ifreturn']) { // - var block = Blockly.utils.xml.createElement('block'); + const block = utilsXml.createElement('block'); block.setAttribute('type', 'procedures_ifreturn'); block.setAttribute('gap', 16); xmlList.push(block); @@ -233,22 +234,22 @@ Blockly.Procedures.flyoutCategory = function(workspace) { } function populateProcedures(procedureList, templateName) { - for (var i = 0; i < procedureList.length; i++) { - var name = procedureList[i][0]; - var args = procedureList[i][1]; + for (let i = 0; i < procedureList.length; i++) { + const name = procedureList[i][0]; + const args = procedureList[i][1]; // // // // // - var block = Blockly.utils.xml.createElement('block'); + const block = utilsXml.createElement('block'); block.setAttribute('type', templateName); block.setAttribute('gap', 16); - var mutation = Blockly.utils.xml.createElement('mutation'); + const mutation = utilsXml.createElement('mutation'); mutation.setAttribute('name', name); block.appendChild(mutation); - for (var j = 0; j < args.length; j++) { - var arg = Blockly.utils.xml.createElement('arg'); + for (let j = 0; j < args.length; j++) { + const arg = utilsXml.createElement('arg'); arg.setAttribute('name', args[j]); mutation.appendChild(arg); } @@ -256,157 +257,155 @@ Blockly.Procedures.flyoutCategory = function(workspace) { } } - var tuple = Blockly.Procedures.allProcedures(workspace); + const tuple = allProcedures(workspace); populateProcedures(tuple[0], 'procedures_callnoreturn'); populateProcedures(tuple[1], 'procedures_callreturn'); return xmlList; }; +exports.flyoutCategory = flyoutCategory; /** * Updates the procedure mutator's flyout so that the arg block is not a * duplicate of another arg. - * @param {!Blockly.Workspace} workspace The procedure mutator's workspace. This + * @param {!Workspace} workspace The procedure mutator's workspace. This * workspace's flyout is what is being updated. - * @private */ -Blockly.Procedures.updateMutatorFlyout_ = function(workspace) { - var usedNames = []; - var blocks = workspace.getBlocksByType('procedures_mutatorarg', false); - for (var i = 0, block; (block = blocks[i]); i++) { +const updateMutatorFlyout = function(workspace) { + const usedNames = []; + const blocks = workspace.getBlocksByType('procedures_mutatorarg', false); + for (let i = 0, block; (block = blocks[i]); i++) { usedNames.push(block.getFieldValue('NAME')); } - var xml = Blockly.utils.xml.createElement('xml'); - var argBlock = Blockly.utils.xml.createElement('block'); + const xmlElement = utilsXml.createElement('xml'); + const argBlock = utilsXml.createElement('block'); argBlock.setAttribute('type', 'procedures_mutatorarg'); - var nameField = Blockly.utils.xml.createElement('field'); + const nameField = utilsXml.createElement('field'); nameField.setAttribute('name', 'NAME'); - var argValue = Blockly.Variables.generateUniqueNameFromOptions( - Blockly.Procedures.DEFAULT_ARG, usedNames); - var fieldContent = Blockly.utils.xml.createTextNode(argValue); + const argValue = + Variables.generateUniqueNameFromOptions(DEFAULT_ARG, usedNames); + const fieldContent = utilsXml.createTextNode(argValue); nameField.appendChild(fieldContent); argBlock.appendChild(nameField); - xml.appendChild(argBlock); + xmlElement.appendChild(argBlock); - workspace.updateToolbox(xml); + workspace.updateToolbox(xmlElement); }; /** * Listens for when a procedure mutator is opened. Then it triggers a flyout * update and adds a mutator change listener to the mutator workspace. - * @param {!Blockly.Events.Abstract} e The event that triggered this listener. - * @package + * @param {!Abstract} e The event that triggered this listener. */ -Blockly.Procedures.mutatorOpenListener = function(e) { - if (!(e.type == Blockly.Events.BUBBLE_OPEN && e.bubbleType === 'mutator' && - e.isOpen)) { +const mutatorOpenListener = function(e) { + if (!(e.type == Events.BUBBLE_OPEN && e.bubbleType === 'mutator' && + e.isOpen)) { return; } - var workspaceId = /** @type {string} */ (e.workspaceId); - var block = Blockly.Workspace.getById(workspaceId) - .getBlockById(e.blockId); - var type = block.type; + const workspaceId = /** @type {string} */ (e.workspaceId); + const block = Workspace.getById(workspaceId).getBlockById(e.blockId); + const type = block.type; if (type != 'procedures_defnoreturn' && type != 'procedures_defreturn') { return; } - var workspace = block.mutator.getWorkspace(); - Blockly.Procedures.updateMutatorFlyout_(workspace); - workspace.addChangeListener(Blockly.Procedures.mutatorChangeListener_); + const workspace = block.mutator.getWorkspace(); + updateMutatorFlyout(workspace); + workspace.addChangeListener(mutatorChangeListener); }; +/** @package */ +exports.mutatorOpenListener = mutatorOpenListener; /** * Listens for changes in a procedure mutator and triggers flyout updates when * necessary. - * @param {!Blockly.Events.Abstract} e The event that triggered this listener. - * @private + * @param {!Abstract} e The event that triggered this listener. */ -Blockly.Procedures.mutatorChangeListener_ = function(e) { - if (e.type != Blockly.Events.BLOCK_CREATE && - e.type != Blockly.Events.BLOCK_DELETE && - e.type != Blockly.Events.BLOCK_CHANGE) { +const mutatorChangeListener = function(e) { + if (e.type != Events.BLOCK_CREATE && e.type != Events.BLOCK_DELETE && + e.type != Events.BLOCK_CHANGE) { return; } - var workspaceId = /** @type {string} */ (e.workspaceId); - var workspace = /** @type {!Blockly.WorkspaceSvg} */ - (Blockly.Workspace.getById(workspaceId)); - Blockly.Procedures.updateMutatorFlyout_(workspace); + const workspaceId = /** @type {string} */ (e.workspaceId); + const workspace = /** @type {!WorkspaceSvg} */ + (Workspace.getById(workspaceId)); + updateMutatorFlyout(workspace); }; /** * Find all the callers of a named procedure. * @param {string} name Name of procedure. - * @param {!Blockly.Workspace} workspace The workspace to find callers in. - * @return {!Array} Array of caller blocks. + * @param {!Workspace} workspace The workspace to find callers in. + * @return {!Array} Array of caller blocks. */ -Blockly.Procedures.getCallers = function(name, workspace) { - var callers = []; - var blocks = workspace.getAllBlocks(false); +const getCallers = function(name, workspace) { + const callers = []; + const blocks = workspace.getAllBlocks(false); // Iterate through every block and check the name. - for (var i = 0; i < blocks.length; i++) { + for (let i = 0; i < blocks.length; i++) { if (blocks[i].getProcedureCall) { - var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( - blocks[i]); - var procName = procedureBlock.getProcedureCall(); + const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]); + const procName = procedureBlock.getProcedureCall(); // Procedure name may be null if the block is only half-built. - if (procName && Blockly.Names.equals(procName, name)) { + if (procName && Names.equals(procName, name)) { callers.push(blocks[i]); } } } return callers; }; +exports.getCallers = getCallers; /** * When a procedure definition changes its parameters, find and edit all its * callers. - * @param {!Blockly.Block} defBlock Procedure definition block. + * @param {!Block} defBlock Procedure definition block. */ -Blockly.Procedures.mutateCallers = function(defBlock) { - var oldRecordUndo = Blockly.Events.recordUndo; - var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( - defBlock); - var name = procedureBlock.getProcedureDef()[0]; - var xmlElement = defBlock.mutationToDom(true); - var callers = Blockly.Procedures.getCallers(name, defBlock.workspace); - for (var i = 0, caller; (caller = callers[i]); i++) { - var oldMutationDom = caller.mutationToDom(); - var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); +const mutateCallers = function(defBlock) { + const oldRecordUndo = Events.recordUndo; + const procedureBlock = /** @type {!ProcedureBlock} */ (defBlock); + const name = procedureBlock.getProcedureDef()[0]; + const xmlElement = defBlock.mutationToDom(true); + const callers = getCallers(name, defBlock.workspace); + for (let i = 0, caller; (caller = callers[i]); i++) { + const oldMutationDom = caller.mutationToDom(); + const oldMutation = oldMutationDom && Xml.domToText(oldMutationDom); caller.domToMutation(xmlElement); - var newMutationDom = caller.mutationToDom(); - var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom); + const newMutationDom = caller.mutationToDom(); + const newMutation = newMutationDom && Xml.domToText(newMutationDom); if (oldMutation != newMutation) { // Fire a mutation on every caller block. But don't record this as an // undo action since it is deterministically tied to the procedure's // definition mutation. - Blockly.Events.recordUndo = false; - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( + Events.recordUndo = false; + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( caller, 'mutation', null, oldMutation, newMutation)); - Blockly.Events.recordUndo = oldRecordUndo; + Events.recordUndo = oldRecordUndo; } } }; +exports.mutateCallers = mutateCallers; /** * Find the definition block for the named procedure. * @param {string} name Name of procedure. - * @param {!Blockly.Workspace} workspace The workspace to search. - * @return {?Blockly.Block} The procedure definition block, or null not found. + * @param {!Workspace} workspace The workspace to search. + * @return {?Block} The procedure definition block, or null not found. */ -Blockly.Procedures.getDefinition = function(name, workspace) { +const getDefinition = function(name, workspace) { // Do not assume procedure is a top block. Some languages allow nested // procedures. Also do not assume it is one of the built-in blocks. Only // rely on getProcedureDef. - var blocks = workspace.getAllBlocks(false); - for (var i = 0; i < blocks.length; i++) { + const blocks = workspace.getAllBlocks(false); + for (let i = 0; i < blocks.length; i++) { if (blocks[i].getProcedureDef) { - var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( - blocks[i]); - var tuple = procedureBlock.getProcedureDef(); - if (tuple && Blockly.Names.equals(tuple[0], name)) { + const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]); + const tuple = procedureBlock.getProcedureDef(); + if (tuple && Names.equals(tuple[0], name)) { return blocks[i]; // Can't use procedureBlock var due to type check. } } } return null; }; +exports.getDefinition = getDefinition; diff --git a/core/registry.js b/core/registry.js index 2959cf73e..5752702ae 100644 --- a/core/registry.js +++ b/core/registry.js @@ -11,20 +11,33 @@ */ 'use strict'; -goog.provide('Blockly.registry'); +goog.module('Blockly.registry'); +goog.module.declareLegacyNamespace(); -goog.requireType('Blockly.blockRendering.Renderer'); -goog.requireType('Blockly.Cursor'); -goog.requireType('Blockly.Events.Abstract'); -goog.requireType('Blockly.Field'); -goog.requireType('Blockly.IBlockDragger'); -goog.requireType('Blockly.IConnectionChecker'); -goog.requireType('Blockly.IFlyout'); -goog.requireType('Blockly.IMetricsManager'); -goog.requireType('Blockly.IToolbox'); -goog.requireType('Blockly.Options'); -goog.requireType('Blockly.Theme'); -goog.requireType('Blockly.ToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const Abstract = goog.requireType('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const Cursor = goog.requireType('Blockly.Cursor'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +/* eslint-disable-next-line no-unused-vars */ +const IBlockDragger = goog.requireType('Blockly.IBlockDragger'); +/* eslint-disable-next-line no-unused-vars */ +const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker'); +/* eslint-disable-next-line no-unused-vars */ +const IFlyout = goog.requireType('Blockly.IFlyout'); +/* eslint-disable-next-line no-unused-vars */ +const IMetricsManager = goog.requireType('Blockly.IMetricsManager'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +/* eslint-disable-next-line no-unused-vars */ +const Options = goog.requireType('Blockly.Options'); +/* eslint-disable-next-line no-unused-vars */ +const Renderer = goog.requireType('Blockly.blockRendering.Renderer'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +/* eslint-disable-next-line no-unused-vars */ +const ToolboxItem = goog.requireType('Blockly.ToolboxItem'); /** @@ -34,13 +47,16 @@ goog.requireType('Blockly.ToolboxItem'); * * @type {Object>} */ -Blockly.registry.typeMap_ = Object.create(null); +const typeMap = Object.create(null); +/** @private */ +exports.typeMap_ = typeMap; /** * The string used to register the default class for a type of plugin. * @type {string} */ -Blockly.registry.DEFAULT = 'default'; +const DEFAULT = 'default'; +exports.DEFAULT = DEFAULT; /** * A name with the type of the element stored in the generic. @@ -48,67 +64,63 @@ Blockly.registry.DEFAULT = 'default'; * @constructor * @template T */ -Blockly.registry.Type = function(name) { +const Type = function(name) { /** * @type {string} * @private */ this.name_ = name; }; +exports.Type = Type; /** * Returns the name of the type. * @return {string} The name. * @override */ -Blockly.registry.Type.prototype.toString = function() { +Type.prototype.toString = function() { return this.name_; }; -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.CONNECTION_CHECKER = - new Blockly.registry.Type('connectionChecker'); +/** @type {!Type} */ +Type.CONNECTION_CHECKER = new Type('connectionChecker'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.CURSOR = new Blockly.registry.Type('cursor'); +/** @type {!Type} */ +Type.CURSOR = new Type('cursor'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.EVENT = new Blockly.registry.Type('event'); +/** @type {!Type} */ +Type.EVENT = new Type('event'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.FIELD = new Blockly.registry.Type('field'); +/** @type {!Type} */ +Type.FIELD = new Type('field'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.RENDERER = new Blockly.registry.Type('renderer'); +/** @type {!Type} */ +Type.RENDERER = new Type('renderer'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.TOOLBOX = new Blockly.registry.Type('toolbox'); +/** @type {!Type} */ +Type.TOOLBOX = new Type('toolbox'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.THEME = new Blockly.registry.Type('theme'); +/** @type {!Type} */ +Type.THEME = new Type('theme'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.TOOLBOX_ITEM = new Blockly.registry.Type('toolboxItem'); +/** @type {!Type} */ +Type.TOOLBOX_ITEM = new Type('toolboxItem'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX = - new Blockly.registry.Type('flyoutsVerticalToolbox'); +/** @type {!Type} */ +Type.FLYOUTS_VERTICAL_TOOLBOX = new Type('flyoutsVerticalToolbox'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX = - new Blockly.registry.Type('flyoutsHorizontalToolbox'); +/** @type {!Type} */ +Type.FLYOUTS_HORIZONTAL_TOOLBOX = new Type('flyoutsHorizontalToolbox'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.METRICS_MANAGER = - new Blockly.registry.Type('metricsManager'); +/** @type {!Type} */ +Type.METRICS_MANAGER = new Type('metricsManager'); -/** @type {!Blockly.registry.Type} */ -Blockly.registry.Type.BLOCK_DRAGGER = - new Blockly.registry.Type('blockDragger'); +/** @type {!Type} */ +Type.BLOCK_DRAGGER = new Type('blockDragger'); /** * Registers a class based on a type and name. - * @param {string|!Blockly.registry.Type} type The type of the plugin. + * @param {string|!Type} type The type of the plugin. * (e.g. Field, Renderer) * @param {string} name The plugin's name. (Ex. field_angle, geras) * @param {?function(new:T, ...?)|Object} registryItem The class or object to @@ -120,9 +132,8 @@ Blockly.registry.Type.BLOCK_DRAGGER = * it's type. * @template T */ -Blockly.registry.register = function( - type, name, registryItem, opt_allowOverrides) { - if ((!(type instanceof Blockly.registry.Type) && typeof type != 'string') || +const register = function(type, name, registryItem, opt_allowOverrides) { + if ((!(type instanceof Type) && typeof type != 'string') || String(type).trim() == '') { throw Error( 'Invalid type "' + type + '". The type must be a' + @@ -139,14 +150,14 @@ Blockly.registry.register = function( if (!registryItem) { throw Error('Can not register a null value'); } - var typeRegistry = Blockly.registry.typeMap_[type]; + let typeRegistry = typeMap[type]; // If the type registry has not been created, create it. if (!typeRegistry) { - typeRegistry = Blockly.registry.typeMap_[type] = Object.create(null); + typeRegistry = typeMap[type] = Object.create(null); } // Validate that the given class has all the required properties. - Blockly.registry.validate_(type, registryItem); + validate(type, registryItem); // Don't throw an error if opt_allowOverrides is true. if (!opt_allowOverrides && typeRegistry[name]) { @@ -155,6 +166,7 @@ Blockly.registry.register = function( } typeRegistry[name] = registryItem; }; +exports.register = register; /** * Checks the given registry item for properties that are required based on the @@ -162,11 +174,10 @@ Blockly.registry.register = function( * @param {string} type The type of the plugin. (e.g. Field, Renderer) * @param {Function|Object} registryItem A class or object that we are checking * for the required properties. - * @private */ -Blockly.registry.validate_ = function(type, registryItem) { +const validate = function(type, registryItem) { switch (type) { - case String(Blockly.registry.Type.FIELD): + case String(Type.FIELD): if (typeof registryItem.fromJson != 'function') { throw Error('Type "' + type + '" must have a fromJson function'); } @@ -176,27 +187,29 @@ Blockly.registry.validate_ = function(type, registryItem) { /** * Unregisters the registry item with the given type and name. - * @param {string|!Blockly.registry.Type} type The type of the plugin. + * @param {string|!Type} type The type of the plugin. * (e.g. Field, Renderer) * @param {string} name The plugin's name. (Ex. field_angle, geras) * @template T */ -Blockly.registry.unregister = function(type, name) { +const unregister = function(type, name) { type = String(type).toLowerCase(); name = name.toLowerCase(); - var typeRegistry = Blockly.registry.typeMap_[type]; + const typeRegistry = typeMap[type]; if (!typeRegistry || !typeRegistry[name]) { - console.warn('Unable to unregister [' + name + '][' + type + '] from the ' + - 'registry.'); + console.warn( + 'Unable to unregister [' + name + '][' + type + '] from the ' + + 'registry.'); return; } - delete Blockly.registry.typeMap_[type][name]; + delete typeMap[type][name]; }; +exports.unregister = unregister; /** * Gets the registry item for the given name and type. This can be either a * class or an object. - * @param {string|!Blockly.registry.Type} type The type of the plugin. + * @param {string|!Type} type The type of the plugin. * (e.g. Field, Renderer) * @param {string} name The plugin's name. (Ex. field_angle, geras) * @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we @@ -205,15 +218,15 @@ Blockly.registry.unregister = function(type, name) { * name and type or null if none exists. * @template T */ -Blockly.registry.getItem_ = function(type, name, opt_throwIfMissing) { +const getItem = function(type, name, opt_throwIfMissing) { type = String(type).toLowerCase(); name = name.toLowerCase(); - var typeRegistry = Blockly.registry.typeMap_[type]; + const typeRegistry = typeMap[type]; if (!typeRegistry || !typeRegistry[name]) { - var msg = 'Unable to find [' + name + '][' + type + '] in the registry.'; + const msg = 'Unable to find [' + name + '][' + type + '] in the registry.'; if (opt_throwIfMissing) { - throw new Error(msg + ' You must require or register a ' + type + - ' plugin.'); + throw new Error( + msg + ' You must require or register a ' + type + ' plugin.'); } else { console.warn(msg); } @@ -225,26 +238,27 @@ Blockly.registry.getItem_ = function(type, name, opt_throwIfMissing) { /** * Returns whether or not the registry contains an item with the given type and * name. - * @param {string|!Blockly.registry.Type} type The type of the plugin. + * @param {string|!Type} type The type of the plugin. * (e.g. Field, Renderer) * @param {string} name The plugin's name. (Ex. field_angle, geras) * @return {boolean} True if the registry has an item with the given type and * name, false otherwise. * @template T */ -Blockly.registry.hasItem = function(type, name) { +const hasItem = function(type, name) { type = String(type).toLowerCase(); name = name.toLowerCase(); - var typeRegistry = Blockly.registry.typeMap_[type]; + const typeRegistry = typeMap[type]; if (!typeRegistry) { return false; } return !!(typeRegistry[name]); }; +exports.hasItem = hasItem; /** * Gets the class for the given name and type. - * @param {string|!Blockly.registry.Type} type The type of the plugin. + * @param {string|!Type} type The type of the plugin. * (e.g. Field, Renderer) * @param {string} name The plugin's name. (Ex. field_angle, geras) * @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we @@ -253,14 +267,15 @@ Blockly.registry.hasItem = function(type, name) { * null if none exists. * @template T */ -Blockly.registry.getClass = function(type, name, opt_throwIfMissing) { +const getClass = function(type, name, opt_throwIfMissing) { return /** @type {?function(new:T, ...?)} */ ( - Blockly.registry.getItem_(type, name, opt_throwIfMissing)); + getItem(type, name, opt_throwIfMissing)); }; +exports.getClass = getClass; /** * Gets the object for the given name and type. - * @param {string|!Blockly.registry.Type} type The type of the plugin. + * @param {string|!Type} type The type of the plugin. * (e.g. Category) * @param {string} name The plugin's name. (Ex. logic_category) * @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we @@ -268,30 +283,30 @@ Blockly.registry.getClass = function(type, name, opt_throwIfMissing) { * @return {?T} The object with the given name and type or null if none exists. * @template T */ -Blockly.registry.getObject = function(type, name, opt_throwIfMissing) { - return /** @type {T} */ ( - Blockly.registry.getItem_(type, name, opt_throwIfMissing)); +const getObject = function(type, name, opt_throwIfMissing) { + return /** @type {T} */ (getItem(type, name, opt_throwIfMissing)); }; +exports.getObject = getObject; /** * Gets the class from Blockly options for the given type. * This is used for plugins that override a built in feature. (e.g. Toolbox) - * @param {!Blockly.registry.Type} type The type of the plugin. - * @param {!Blockly.Options} options The option object to check for the given + * @param {!Type} type The type of the plugin. + * @param {!Options} options The option object to check for the given * plugin. * @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we * are unable to find the plugin. * @return {?function(new:T, ...?)} The class for the plugin. * @template T */ -Blockly.registry.getClassFromOptions = function(type, options, - opt_throwIfMissing) { - var typeName = type.toString(); - var plugin = options.plugins[typeName] || Blockly.registry.DEFAULT; +const getClassFromOptions = function(type, options, opt_throwIfMissing) { + const typeName = type.toString(); + const plugin = options.plugins[typeName] || DEFAULT; // If the user passed in a plugin class instead of a registered plugin name. if (typeof plugin == 'function') { return plugin; } - return Blockly.registry.getClass(type, plugin, opt_throwIfMissing); + return getClass(type, plugin, opt_throwIfMissing); }; +exports.getClassFromOptions = getClassFromOptions; diff --git a/core/rendered_connection.js b/core/rendered_connection.js index cddda9200..0abc123e5 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -10,36 +10,40 @@ */ 'use strict'; -goog.provide('Blockly.RenderedConnection'); +goog.module('Blockly.RenderedConnection'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Connection'); -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.deprecation'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.ConnectionDB'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Connection = goog.require('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const ConnectionDB = goog.requireType('Blockly.ConnectionDB'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +const Svg = goog.require('Blockly.utils.Svg'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const deprecation = goog.require('Blockly.utils.deprecation'); +const dom = goog.require('Blockly.utils.dom'); +const internalConstants = goog.require('Blockly.internalConstants'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** * Class for a connection between blocks that may be rendered on screen. - * @param {!Blockly.BlockSvg} source The block establishing this connection. + * @param {!BlockSvg} source The block establishing this connection. * @param {number} type The type of the connection. - * @extends {Blockly.Connection} + * @extends {Connection} * @constructor */ -Blockly.RenderedConnection = function(source, type) { - Blockly.RenderedConnection.superClass_.constructor.call(this, source, type); +const RenderedConnection = function(source, type) { + RenderedConnection.superClass_.constructor.call(this, source, type); /** * Connection database for connections of this type on the current workspace. - * @const {!Blockly.ConnectionDB} + * @const {!ConnectionDB} * @private */ this.db_ = source.workspace.connectionDBList[type]; @@ -47,34 +51,33 @@ Blockly.RenderedConnection = function(source, type) { /** * Connection database for connections compatible with this type on the * current workspace. - * @const {!Blockly.ConnectionDB} + * @const {!ConnectionDB} * @private */ this.dbOpposite_ = - source.workspace - .connectionDBList[Blockly.internalConstants.OPPOSITE_TYPE[type]]; + source.workspace.connectionDBList[internalConstants.OPPOSITE_TYPE[type]]; /** * Workspace units, (0, 0) is top left of block. - * @type {!Blockly.utils.Coordinate} + * @type {!Coordinate} * @private */ - this.offsetInBlock_ = new Blockly.utils.Coordinate(0, 0); + this.offsetInBlock_ = new Coordinate(0, 0); /** * Describes the state of this connection's tracked-ness. - * @type {Blockly.RenderedConnection.TrackedState} + * @type {RenderedConnection.TrackedState} * @private */ - this.trackedState_ = Blockly.RenderedConnection.TrackedState.WILL_TRACK; + this.trackedState_ = RenderedConnection.TrackedState.WILL_TRACK; /** * Connection this connection connects to. Null if not connected. - * @type {Blockly.RenderedConnection} + * @type {RenderedConnection} */ this.targetConnection = null; }; -Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); +object.inherits(RenderedConnection, Connection); /** * Enum for different kinds of tracked states. @@ -88,7 +91,7 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); * TRACKED means that this connection is currently being tracked. * @enum {number} */ -Blockly.RenderedConnection.TrackedState = { +RenderedConnection.TrackedState = { WILL_TRACK: -1, UNTRACKED: 0, TRACKED: 1 @@ -100,65 +103,65 @@ Blockly.RenderedConnection.TrackedState = { * @override * @package */ -Blockly.RenderedConnection.prototype.dispose = function() { - Blockly.RenderedConnection.superClass_.dispose.call(this); - if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.TRACKED) { +RenderedConnection.prototype.dispose = function() { + RenderedConnection.superClass_.dispose.call(this); + if (this.trackedState_ == RenderedConnection.TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); } }; /** * Get the source block for this connection. - * @return {!Blockly.BlockSvg} The source block. + * @return {!BlockSvg} The source block. * @override */ -Blockly.RenderedConnection.prototype.getSourceBlock = function() { - return /** @type {!Blockly.BlockSvg} */ ( - Blockly.RenderedConnection.superClass_.getSourceBlock.call(this)); +RenderedConnection.prototype.getSourceBlock = function() { + return /** @type {!BlockSvg} */ ( + RenderedConnection.superClass_.getSourceBlock.call(this)); }; /** * Returns the block that this connection connects to. - * @return {?Blockly.BlockSvg} The connected block or null if none is connected. + * @return {?BlockSvg} The connected block or null if none is connected. * @override */ -Blockly.RenderedConnection.prototype.targetBlock = function() { - return /** @type {Blockly.BlockSvg} */ ( - Blockly.RenderedConnection.superClass_.targetBlock.call(this)); +RenderedConnection.prototype.targetBlock = function() { + return /** @type {BlockSvg} */ ( + RenderedConnection.superClass_.targetBlock.call(this)); }; /** * Returns the distance between this connection and another connection in * workspace units. - * @param {!Blockly.Connection} otherConnection The other connection to measure + * @param {!Connection} otherConnection The other connection to measure * the distance to. * @return {number} The distance between connections, in workspace units. */ -Blockly.RenderedConnection.prototype.distanceFrom = function(otherConnection) { - var xDiff = this.x - otherConnection.x; - var yDiff = this.y - otherConnection.y; +RenderedConnection.prototype.distanceFrom = function(otherConnection) { + const xDiff = this.x - otherConnection.x; + const yDiff = this.y - otherConnection.y; return Math.sqrt(xDiff * xDiff + yDiff * yDiff); }; /** * Move the block(s) belonging to the connection to a point where they don't * visually interfere with the specified connection. - * @param {!Blockly.Connection} staticConnection The connection to move away + * @param {!Connection} staticConnection The connection to move away * from. * @package */ -Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) { +RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) { if (this.sourceBlock_.workspace.isDragging()) { // Don't move blocks around while the user is doing the same. return; } // Move the root block. - var rootBlock = this.sourceBlock_.getRootBlock(); + let rootBlock = this.sourceBlock_.getRootBlock(); if (rootBlock.isInFlyout) { // Don't move blocks around in a flyout. return; } - var reverse = false; + let reverse = false; if (!rootBlock.isMovable()) { // Can't bump an uneditable block away. // Check to see if the other block is movable. @@ -171,24 +174,21 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) { reverse = true; } // Raise it to the top for extra visibility. - var selected = Blockly.selected == rootBlock; + const selected = Blockly.selected == rootBlock; selected || rootBlock.addSelect(); - var dx = - (staticConnection.x + Blockly.internalConstants.SNAP_RADIUS + - Math.floor(Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) - + let dx = (staticConnection.x + internalConstants.SNAP_RADIUS + + Math.floor(Math.random() * internalConstants.BUMP_RANDOMNESS)) - this.x; - var dy = - (staticConnection.y + Blockly.internalConstants.SNAP_RADIUS + - Math.floor(Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) - + let dy = (staticConnection.y + internalConstants.SNAP_RADIUS + + Math.floor(Math.random() * internalConstants.BUMP_RANDOMNESS)) - this.y; if (reverse) { // When reversing a bump due to an uneditable block, bump up. dy = -dy; } if (rootBlock.RTL) { - dx = (staticConnection.x - Blockly.internalConstants.SNAP_RADIUS - - Math.floor( - Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) - + dx = (staticConnection.x - internalConstants.SNAP_RADIUS - + Math.floor(Math.random() * internalConstants.BUMP_RANDOMNESS)) - this.x; } rootBlock.moveBy(dx, dy); @@ -200,12 +200,11 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) { * @param {number} x New absolute x coordinate, in workspace coordinates. * @param {number} y New absolute y coordinate, in workspace coordinates. */ -Blockly.RenderedConnection.prototype.moveTo = function(x, y) { - if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.WILL_TRACK) { +RenderedConnection.prototype.moveTo = function(x, y) { + if (this.trackedState_ == RenderedConnection.TrackedState.WILL_TRACK) { this.db_.addConnection(this, y); - this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED; - } else if (this.trackedState_ == Blockly.RenderedConnection - .TrackedState.TRACKED) { + this.trackedState_ = RenderedConnection.TrackedState.TRACKED; + } else if (this.trackedState_ == RenderedConnection.TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); this.db_.addConnection(this, y); } @@ -218,19 +217,19 @@ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { * @param {number} dx Change to x coordinate, in workspace units. * @param {number} dy Change to y coordinate, in workspace units. */ -Blockly.RenderedConnection.prototype.moveBy = function(dx, dy) { +RenderedConnection.prototype.moveBy = function(dx, dy) { this.moveTo(this.x + dx, this.y + dy); }; /** * Move this connection to the location given by its offset within the block and * the location of the block's top left corner. - * @param {!Blockly.utils.Coordinate} blockTL The location of the top left + * @param {!Coordinate} blockTL The location of the top left * corner of the block, in workspace coordinates. */ -Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) { - this.moveTo(blockTL.x + this.offsetInBlock_.x, - blockTL.y + this.offsetInBlock_.y); +RenderedConnection.prototype.moveToOffset = function(blockTL) { + this.moveTo( + blockTL.x + this.offsetInBlock_.x, blockTL.y + this.offsetInBlock_.y); }; /** @@ -238,17 +237,17 @@ Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) { * @param {number} x The new relative x, in workspace units. * @param {number} y The new relative y, in workspace units. */ -Blockly.RenderedConnection.prototype.setOffsetInBlock = function(x, y) { +RenderedConnection.prototype.setOffsetInBlock = function(x, y) { this.offsetInBlock_.x = x; this.offsetInBlock_.y = y; }; /** * Get the offset of this connection relative to the top left of its block. - * @return {!Blockly.utils.Coordinate} The offset of the connection. + * @return {!Coordinate} The offset of the connection. * @package */ -Blockly.RenderedConnection.prototype.getOffsetInBlock = function() { +RenderedConnection.prototype.getOffsetInBlock = function() { return this.offsetInBlock_; }; @@ -256,19 +255,19 @@ Blockly.RenderedConnection.prototype.getOffsetInBlock = function() { * Move the blocks on either side of this connection right next to each other. * @package */ -Blockly.RenderedConnection.prototype.tighten = function() { - var dx = this.targetConnection.x - this.x; - var dy = this.targetConnection.y - this.y; +RenderedConnection.prototype.tighten = function() { + const dx = this.targetConnection.x - this.x; + const dy = this.targetConnection.y - this.y; if (dx != 0 || dy != 0) { - var block = this.targetBlock(); - var svgRoot = block.getSvgRoot(); + const block = this.targetBlock(); + const svgRoot = block.getSvgRoot(); if (!svgRoot) { throw Error('block is not rendered.'); } // Workspace coordinates. - var xy = Blockly.utils.getRelativeXY(svgRoot); - block.getSvgRoot().setAttribute('transform', - 'translate(' + (xy.x - dx) + ',' + (xy.y - dy) + ')'); + const xy = utils.getRelativeXY(svgRoot); + block.getSvgRoot().setAttribute( + 'transform', 'translate(' + (xy.x - dx) + ',' + (xy.y - dy) + ')'); block.moveConnections(-dx, -dy); } }; @@ -277,47 +276,44 @@ Blockly.RenderedConnection.prototype.tighten = function() { * Find the closest compatible connection to this connection. * All parameters are in workspace units. * @param {number} maxLimit The maximum radius to another connection. - * @param {!Blockly.utils.Coordinate} dxy Offset between this connection's location + * @param {!Coordinate} dxy Offset between this connection's location * in the database and the current location (as a result of dragging). - * @return {!{connection: ?Blockly.Connection, radius: number}} Contains two + * @return {!{connection: ?Connection, radius: number}} Contains two * properties: 'connection' which is either another connection or null, * and 'radius' which is the distance. */ -Blockly.RenderedConnection.prototype.closest = function(maxLimit, dxy) { +RenderedConnection.prototype.closest = function(maxLimit, dxy) { return this.dbOpposite_.searchForClosest(this, maxLimit, dxy); }; /** * Add highlighting around this connection. */ -Blockly.RenderedConnection.prototype.highlight = function() { - var steps; - var sourceBlockSvg = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_); - var renderConstants = sourceBlockSvg.workspace.getRenderer().getConstants(); - var shape = renderConstants.shapeFor(this); - if (this.type == Blockly.connectionTypes.INPUT_VALUE || - this.type == Blockly.connectionTypes.OUTPUT_VALUE) { +RenderedConnection.prototype.highlight = function() { + let steps; + const sourceBlockSvg = /** @type {!BlockSvg} */ (this.sourceBlock_); + const renderConstants = sourceBlockSvg.workspace.getRenderer().getConstants(); + const shape = renderConstants.shapeFor(this); + if (this.type == connectionTypes.INPUT_VALUE || + this.type == connectionTypes.OUTPUT_VALUE) { // Vertical line, puzzle tab, vertical line. - var yLen = renderConstants.TAB_OFFSET_FROM_TOP; - steps = Blockly.utils.svgPaths.moveBy(0, -yLen) + - Blockly.utils.svgPaths.lineOnAxis('v', yLen) + - shape.pathDown + - Blockly.utils.svgPaths.lineOnAxis('v', yLen); + const yLen = renderConstants.TAB_OFFSET_FROM_TOP; + steps = utils.svgPaths.moveBy(0, -yLen) + + utils.svgPaths.lineOnAxis('v', yLen) + shape.pathDown + + utils.svgPaths.lineOnAxis('v', yLen); } else { - var xLen = + const xLen = renderConstants.NOTCH_OFFSET_LEFT - renderConstants.CORNER_RADIUS; // Horizontal line, notch, horizontal line. - steps = Blockly.utils.svgPaths.moveBy(-xLen, 0) + - Blockly.utils.svgPaths.lineOnAxis('h', xLen) + - shape.pathLeft + - Blockly.utils.svgPaths.lineOnAxis('h', xLen); + steps = utils.svgPaths.moveBy(-xLen, 0) + + utils.svgPaths.lineOnAxis('h', xLen) + shape.pathLeft + + utils.svgPaths.lineOnAxis('h', xLen); } - var xy = this.sourceBlock_.getRelativeToSurfaceXY(); - var x = this.x - xy.x; - var y = this.y - xy.y; - Blockly.Connection.highlightedPath_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { + const xy = this.sourceBlock_.getRelativeToSurfaceXY(); + const x = this.x - xy.x; + const y = this.y - xy.y; + Connection.highlightedPath_ = dom.createSvgElement( + Svg.PATH, { 'class': 'blocklyHighlightedConnectionPath', 'd': steps, transform: 'translate(' + x + ',' + y + ')' + @@ -329,9 +325,9 @@ Blockly.RenderedConnection.prototype.highlight = function() { /** * Remove the highlighting around this connection. */ -Blockly.RenderedConnection.prototype.unhighlight = function() { - Blockly.utils.dom.removeNode(Blockly.Connection.highlightedPath_); - delete Blockly.Connection.highlightedPath_; +RenderedConnection.prototype.unhighlight = function() { + dom.removeNode(Connection.highlightedPath_); + delete Connection.highlightedPath_; }; /** @@ -339,11 +335,11 @@ Blockly.RenderedConnection.prototype.unhighlight = function() { * @param {boolean} doTracking If true, start tracking. If false, stop tracking. * @package */ -Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { - if ((doTracking && this.trackedState_ == - Blockly.RenderedConnection.TrackedState.TRACKED) || - (!doTracking && this.trackedState_ == - Blockly.RenderedConnection.TrackedState.UNTRACKED)) { +RenderedConnection.prototype.setTracking = function(doTracking) { + if ((doTracking && + this.trackedState_ == RenderedConnection.TrackedState.TRACKED) || + (!doTracking && + this.trackedState_ == RenderedConnection.TrackedState.UNTRACKED)) { return; } if (this.sourceBlock_.isInFlyout) { @@ -352,13 +348,13 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { } if (doTracking) { this.db_.addConnection(this, this.y); - this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED; + this.trackedState_ = RenderedConnection.TrackedState.TRACKED; return; } - if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.TRACKED) { + if (this.trackedState_ == RenderedConnection.TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); } - this.trackedState_ = Blockly.RenderedConnection.TrackedState.UNTRACKED; + this.trackedState_ = RenderedConnection.TrackedState.UNTRACKED; }; /** @@ -369,20 +365,20 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { * Also closes down-stream icons/bubbles. * @package */ -Blockly.RenderedConnection.prototype.stopTrackingAll = function() { +RenderedConnection.prototype.stopTrackingAll = function() { this.setTracking(false); if (this.targetConnection) { - var blocks = this.targetBlock().getDescendants(false); - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; + const blocks = this.targetBlock().getDescendants(false); + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i]; // Stop tracking connections of all children. - var connections = block.getConnections_(true); - for (var j = 0; j < connections.length; j++) { + const connections = block.getConnections_(true); + for (let j = 0; j < connections.length; j++) { connections[j].setTracking(false); } // Close all bubbles of all children. - var icons = block.getIcons(); - for (var j = 0; j < icons.length; j++) { + const icons = block.getIcons(); + for (let j = 0; j < icons.length; j++) { icons[j].setVisible(false); } } @@ -392,23 +388,23 @@ Blockly.RenderedConnection.prototype.stopTrackingAll = function() { /** * Start tracking this connection, as well as all down-stream connections on * any block attached to this connection. This happens when a block is expanded. - * @return {!Array} List of blocks to render. + * @return {!Array} List of blocks to render. */ -Blockly.RenderedConnection.prototype.startTrackingAll = function() { +RenderedConnection.prototype.startTrackingAll = function() { this.setTracking(true); // All blocks that are not tracked must start tracking before any // rendering takes place, since rendering requires knowing the dimensions // of lower blocks. Also, since rendering a block renders all its parents, // we only need to render the leaf nodes. - var renderList = []; - if (this.type != Blockly.connectionTypes.INPUT_VALUE && - this.type != Blockly.connectionTypes.NEXT_STATEMENT) { + const renderList = []; + if (this.type != connectionTypes.INPUT_VALUE && + this.type != connectionTypes.NEXT_STATEMENT) { // Only spider down. return renderList; } - var block = this.targetBlock(); + const block = this.targetBlock(); if (block) { - var connections; + let connections; if (block.isCollapsed()) { // This block should only be partially revealed since it is collapsed. connections = []; @@ -419,7 +415,7 @@ Blockly.RenderedConnection.prototype.startTrackingAll = function() { // Show all connections of this block. connections = block.getConnections_(true); } - for (var i = 0; i < connections.length; i++) { + for (let i = 0; i < connections.length; i++) { renderList.push.apply(renderList, connections[i].startTrackingAll()); } if (!renderList.length) { @@ -432,62 +428,60 @@ Blockly.RenderedConnection.prototype.startTrackingAll = function() { /** * Check if the two connections can be dragged to connect to each other. - * @param {!Blockly.Connection} candidate A nearby connection to check. + * @param {!Connection} candidate A nearby connection to check. * @param {number=} maxRadius The maximum radius allowed for connections, in * workspace units. * @return {boolean} True if the connection is allowed, false otherwise. * @deprecated July 2020 */ -Blockly.RenderedConnection.prototype.isConnectionAllowed = function(candidate, - maxRadius) { - Blockly.utils.deprecation.warn( - 'RenderedConnection.prototype.isConnectionAllowed', - 'July 2020', +RenderedConnection.prototype.isConnectionAllowed = function( + candidate, maxRadius) { + deprecation.warn( + 'RenderedConnection.prototype.isConnectionAllowed', 'July 2020', 'July 2021', 'Blockly.Workspace.prototype.getConnectionChecker().canConnect'); if (this.distanceFrom(candidate) > maxRadius) { return false; } - return Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this, - candidate); + return RenderedConnection.superClass_.isConnectionAllowed.call( + this, candidate); }; /** * Behavior after a connection attempt fails. * Bumps this connection away from the other connection. Called when an * attempted connection fails. - * @param {!Blockly.Connection} otherConnection Connection that this connection + * @param {!Connection} otherConnection Connection that this connection * failed to connect to. * @package */ -Blockly.RenderedConnection.prototype.onFailedConnect = - function(otherConnection) { - var block = this.getSourceBlock(); - if (Blockly.Events.recordUndo) { - var group = Blockly.Events.getGroup(); - setTimeout(function() { - if (!block.isDisposed() && !block.getParent()) { - Blockly.Events.setGroup(group); - this.bumpAwayFrom(otherConnection); - Blockly.Events.setGroup(false); - } - }.bind(this), Blockly.internalConstants.BUMP_DELAY); +RenderedConnection.prototype.onFailedConnect = function(otherConnection) { + const block = this.getSourceBlock(); + if (Events.recordUndo) { + const group = Events.getGroup(); + setTimeout(function() { + if (!block.isDisposed() && !block.getParent()) { + Events.setGroup(group); + this.bumpAwayFrom(otherConnection); + Events.setGroup(false); } - }; + }.bind(this), internalConstants.BUMP_DELAY); + } +}; /** * Disconnect two blocks that are connected by this connection. - * @param {!Blockly.Block} parentBlock The superior block. - * @param {!Blockly.Block} childBlock The inferior block. + * @param {!Block} parentBlock The superior block. + * @param {!Block} childBlock The inferior block. * @protected * @override */ -Blockly.RenderedConnection.prototype.disconnectInternal_ = function(parentBlock, - childBlock) { - Blockly.RenderedConnection.superClass_.disconnectInternal_.call(this, - parentBlock, childBlock); +RenderedConnection.prototype.disconnectInternal_ = function( + parentBlock, childBlock) { + RenderedConnection.superClass_.disconnectInternal_.call( + this, parentBlock, childBlock); // Rerender the parent so that it may reflow. if (parentBlock.rendered) { parentBlock.render(); @@ -506,9 +500,9 @@ Blockly.RenderedConnection.prototype.disconnectInternal_ = function(parentBlock, * @protected * @override */ -Blockly.RenderedConnection.prototype.respawnShadow_ = function() { - Blockly.RenderedConnection.superClass_.respawnShadow_.call(this); - var blockShadow = this.targetBlock(); +RenderedConnection.prototype.respawnShadow_ = function() { + RenderedConnection.superClass_.respawnShadow_.call(this); + const blockShadow = this.targetBlock(); if (!blockShadow) { // This connection must not have a shadowDom_. return; @@ -516,7 +510,7 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() { blockShadow.initSvg(); blockShadow.render(false); - var parentBlock = this.getSourceBlock(); + const parentBlock = this.getSourceBlock(); if (parentBlock.rendered) { parentBlock.render(); } @@ -527,27 +521,27 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() { * Type checking does not apply, since this function is used for bumping. * @param {number} maxLimit The maximum radius to another connection, in * workspace units. - * @return {!Array} List of connections. + * @return {!Array} List of connections. * @package */ -Blockly.RenderedConnection.prototype.neighbours = function(maxLimit) { +RenderedConnection.prototype.neighbours = function(maxLimit) { return this.dbOpposite_.getNeighbours(this, maxLimit); }; /** * Connect two connections together. This is the connection on the superior * block. Rerender blocks as needed. - * @param {!Blockly.Connection} childConnection Connection on inferior block. + * @param {!Connection} childConnection Connection on inferior block. * @protected */ -Blockly.RenderedConnection.prototype.connect_ = function(childConnection) { - Blockly.RenderedConnection.superClass_.connect_.call(this, childConnection); +RenderedConnection.prototype.connect_ = function(childConnection) { + RenderedConnection.superClass_.connect_.call(this, childConnection); - var parentConnection = this; - var parentBlock = parentConnection.getSourceBlock(); - var childBlock = childConnection.getSourceBlock(); - var parentRendered = parentBlock.rendered; - var childRendered = childBlock.rendered; + const parentConnection = this; + const parentBlock = parentConnection.getSourceBlock(); + const childBlock = childConnection.getSourceBlock(); + const parentRendered = parentBlock.rendered; + const childRendered = childBlock.rendered; if (parentRendered) { parentBlock.updateDisabled(); @@ -556,8 +550,8 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) { childBlock.updateDisabled(); } if (parentRendered && childRendered) { - if (parentConnection.type == Blockly.connectionTypes.NEXT_STATEMENT || - parentConnection.type == Blockly.connectionTypes.PREVIOUS_STATEMENT) { + if (parentConnection.type == connectionTypes.NEXT_STATEMENT || + parentConnection.type == connectionTypes.PREVIOUS_STATEMENT) { // Child block may need to square off its corners if it is in a stack. // Rendering a child will render its parent. childBlock.render(); @@ -569,9 +563,9 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) { } // The input the child block is connected to (if any). - var parentInput = parentBlock.getInputWithBlock(childBlock); + const parentInput = parentBlock.getInputWithBlock(childBlock); if (parentInput) { - var visible = parentInput.isVisible(); + const visible = parentInput.isVisible(); childBlock.getSvgRoot().style.display = visible ? 'block' : 'none'; } }; @@ -580,14 +574,17 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) { * Function to be called when this connection's compatible types have changed. * @protected */ -Blockly.RenderedConnection.prototype.onCheckChanged_ = function() { +RenderedConnection.prototype.onCheckChanged_ = function() { // The new value type may not be compatible with the existing connection. - if (this.isConnected() && (!this.targetConnection || - !this.getConnectionChecker().canConnect( - this, this.targetConnection, false))) { - var child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_; + if (this.isConnected() && + (!this.targetConnection || + !this.getConnectionChecker().canConnect( + this, this.targetConnection, false))) { + const child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_; child.unplug(); // Bump away. this.sourceBlock_.bumpNeighbours(); } }; + +exports = RenderedConnection; diff --git a/core/renderers/common/block_rendering.js b/core/renderers/common/block_rendering.js index d1ee94a14..c00d58523 100644 --- a/core/renderers/common/block_rendering.js +++ b/core/renderers/common/block_rendering.js @@ -10,24 +10,30 @@ */ 'use strict'; -/** - * The top level namespace for block rendering. - * @namespace Blockly.blockRendering - */ -goog.provide('Blockly.blockRendering'); +goog.module('Blockly.blockRendering'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.registry'); - -goog.requireType('Blockly.blockRendering.Renderer'); -goog.requireType('Blockly.Theme'); +/* eslint-disable-next-line no-unused-vars */ +const Renderer = goog.requireType('Blockly.blockRendering.Renderer'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +const registry = goog.require('Blockly.registry'); /** * Whether or not the debugger is turned on. * @type {boolean} - * @package */ -Blockly.blockRendering.useDebugger = false; +let useDebugger = false; +/** + * Returns whether the debugger is turned on. + * @return {boolean} Whether the debugger is turned on. + */ +const isDebuggerEnabled = function() { + return useDebugger; +}; +/** @package */ +exports.isDebuggerEnabled = isDebuggerEnabled; /** * Registers a new renderer. @@ -36,48 +42,54 @@ Blockly.blockRendering.useDebugger = false; * to register. * @throws {Error} if a renderer with the same name has already been registered. */ -Blockly.blockRendering.register = function(name, rendererClass) { - Blockly.registry.register(Blockly.registry.Type.RENDERER, name, - rendererClass); +const register = function(name, rendererClass) { + registry.register(registry.Type.RENDERER, name, rendererClass); }; +exports.register = register; /** * Unregisters the renderer registered with the given name. * @param {string} name The name of the renderer. */ -Blockly.blockRendering.unregister = function(name) { - Blockly.registry.unregister(Blockly.registry.Type.RENDERER, name); +const unregister = function(name) { + registry.unregister(registry.Type.RENDERER, name); }; +exports.unregister = unregister; + /** * Turn on the blocks debugger. * @package */ -Blockly.blockRendering.startDebugger = function() { - Blockly.blockRendering.useDebugger = true; +const startDebugger = function() { + useDebugger = true; }; +/** @package */ +exports.startDebugger = startDebugger; /** * Turn off the blocks debugger. * @package */ -Blockly.blockRendering.stopDebugger = function() { - Blockly.blockRendering.useDebugger = false; +const stopDebugger = function() { + useDebugger = false; }; +/** @package */ +exports.stopDebugger = stopDebugger; /** * Initialize anything needed for rendering (constants, etc). * @param {!string} name Name of the renderer to initialize. - * @param {!Blockly.Theme} theme The workspace theme object. + * @param {!Theme} theme The workspace theme object. * @param {Object=} opt_rendererOverrides Rendering constant overrides. - * @return {!Blockly.blockRendering.Renderer} The new instance of a renderer. + * @return {!Renderer} The new instance of a renderer. * Already initialized. * @package */ - -Blockly.blockRendering.init = function(name, theme, opt_rendererOverrides) { - var rendererClass = Blockly.registry.getClass( - Blockly.registry.Type.RENDERER, name); - var renderer = new rendererClass(name); +const init = function(name, theme, opt_rendererOverrides) { + const rendererClass = registry.getClass(registry.Type.RENDERER, name); + const renderer = new rendererClass(name); renderer.init(theme, opt_rendererOverrides); return renderer; }; +/** @package */ +exports.init = init; diff --git a/core/renderers/common/drawer.js b/core/renderers/common/drawer.js index 2dde92d3f..af03eaf2e 100644 --- a/core/renderers/common/drawer.js +++ b/core/renderers/common/drawer.js @@ -26,7 +26,7 @@ const InlineInput = goog.requireType('Blockly.blockRendering.InlineInput'); /* eslint-disable-next-line no-unused-vars */ const RenderInfo = goog.requireType('Blockly.blockRendering.RenderInfo'); /* eslint-disable-next-line no-unused-vars */ -const Row = goog.require('Blockly.blockRendering.Row'); +const Row = goog.requireType('Blockly.blockRendering.Row'); const Types = goog.require('Blockly.blockRendering.Types'); const svgPaths = goog.require('Blockly.utils.svgPaths'); @@ -73,7 +73,7 @@ Drawer.prototype.draw = function() { if (this.info_.RTL) { this.block_.pathObject.flipRTL(); } - if (Blockly.blockRendering.useDebugger) { + if (Blockly.blockRendering.isDebuggerEnabled()) { this.block_.renderingDebugger.drawDebug(this.block_, this.info_); } this.recordSizeOnBlock_(); diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index 6a7dfc2b7..1a8deb11e 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -12,81 +12,85 @@ 'use strict'; -goog.provide('Blockly.blockRendering.IPathObject'); +goog.module('Blockly.blockRendering.IPathObject'); +goog.module.declareLegacyNamespace(); -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.blockRendering.ConstantProvider'); -goog.requireType('Blockly.Theme'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); /** * An interface for a block's path object. * @param {!SVGElement} _root The root SVG element. - * @param {!Blockly.blockRendering.ConstantProvider} _constants The renderer's + * @param {!ConstantProvider} _constants The renderer's * constants. * @interface */ -Blockly.blockRendering.IPathObject = function(_root, _constants) {}; +const IPathObject = function(_root, _constants) {}; /** * The primary path of the block. * @type {!SVGElement} */ -Blockly.blockRendering.IPathObject.prototype.svgPath; +IPathObject.prototype.svgPath; /** * The renderer's constant provider. - * @type {!Blockly.blockRendering.ConstantProvider} + * @type {!ConstantProvider} */ -Blockly.blockRendering.IPathObject.prototype.constants; +IPathObject.prototype.constants; /** * The primary path of the block. - * @type {!Blockly.Theme.BlockStyle} + * @type {!Theme.BlockStyle} */ -Blockly.blockRendering.IPathObject.prototype.style; +IPathObject.prototype.style; /** * Holds the cursors SVG element when the cursor is attached to the block. * This is null if there is no cursor on the block. * @type {SVGElement} */ -Blockly.blockRendering.IPathObject.prototype.cursorSvg; +IPathObject.prototype.cursorSvg; /** * Holds the markers SVG element when the marker is attached to the block. * This is null if there is no marker on the block. * @type {SVGElement} */ -Blockly.blockRendering.IPathObject.prototype.markerSvg; +IPathObject.prototype.markerSvg; /** * Set the path generated by the renderer onto the respective SVG element. * @param {string} pathString The path. * @package */ -Blockly.blockRendering.IPathObject.prototype.setPath; +IPathObject.prototype.setPath; /** * Apply the stored colours to the block's path, taking into account whether * the paths belong to a shadow block. - * @param {!Blockly.Block} block The source block. + * @param {!Block} block The source block. * @package */ -Blockly.blockRendering.IPathObject.prototype.applyColour; +IPathObject.prototype.applyColour; /** * Update the style. - * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. + * @param {!Theme.BlockStyle} blockStyle The block style to use. * @package */ -Blockly.blockRendering.IPathObject.prototype.setStyle; +IPathObject.prototype.setStyle; /** * Flip the SVG paths in RTL. * @package */ -Blockly.blockRendering.IPathObject.prototype.flipRTL; +IPathObject.prototype.flipRTL; /** * Add the cursor SVG to this block's SVG group. @@ -94,7 +98,7 @@ Blockly.blockRendering.IPathObject.prototype.flipRTL; * block SVG group. * @package */ -Blockly.blockRendering.IPathObject.prototype.setCursorSvg; +IPathObject.prototype.setCursorSvg; /** * Add the marker SVG to this block's SVG group. @@ -102,7 +106,7 @@ Blockly.blockRendering.IPathObject.prototype.setCursorSvg; * block SVG group. * @package */ -Blockly.blockRendering.IPathObject.prototype.setMarkerSvg; +IPathObject.prototype.setMarkerSvg; /** * Set whether the block shows a highlight or not. Block highlighting is @@ -110,14 +114,14 @@ Blockly.blockRendering.IPathObject.prototype.setMarkerSvg; * @param {boolean} highlighted True if highlighted. * @package */ -Blockly.blockRendering.IPathObject.prototype.updateHighlighted; +IPathObject.prototype.updateHighlighted; /** * Add or remove styling showing that a block is selected. * @param {boolean} enable True if selection is enabled, false otherwise. * @package */ -Blockly.blockRendering.IPathObject.prototype.updateSelected; +IPathObject.prototype.updateSelected; /** * Add or remove styling showing that a block is dragged over a delete area. @@ -125,7 +129,7 @@ Blockly.blockRendering.IPathObject.prototype.updateSelected; * area, false otherwise. * @package */ -Blockly.blockRendering.IPathObject.prototype.updateDraggingDelete; +IPathObject.prototype.updateDraggingDelete; /** * Add or remove styling showing that a block is an insertion marker. @@ -133,14 +137,14 @@ Blockly.blockRendering.IPathObject.prototype.updateDraggingDelete; * otherwise. * @package */ -Blockly.blockRendering.IPathObject.prototype.updateInsertionMarker; +IPathObject.prototype.updateInsertionMarker; /** * Add or remove styling showing that a block is movable. * @param {boolean} enable True if the block is movable, false otherwise. * @package */ -Blockly.blockRendering.IPathObject.prototype.updateMovable; +IPathObject.prototype.updateMovable; /** * Add or remove styling that shows that if the dragging block is dropped, this @@ -149,4 +153,6 @@ Blockly.blockRendering.IPathObject.prototype.updateMovable; * @param {boolean} enable True if styling should be added. * @package */ -Blockly.blockRendering.IPathObject.prototype.updateReplacementFade; +IPathObject.prototype.updateReplacementFade; + +exports = IPathObject; diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 0f8548192..b5da1701d 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -29,7 +29,7 @@ const InputRow = goog.require('Blockly.blockRendering.InputRow'); const InRowSpacer = goog.require('Blockly.blockRendering.InRowSpacer'); const JaggedEdge = goog.require('Blockly.blockRendering.JaggedEdge'); /* eslint-disable-next-line no-unused-vars */ -const Measurable = goog.require('Blockly.blockRendering.Measurable'); +const Measurable = goog.requireType('Blockly.blockRendering.Measurable'); const NextConnection = goog.require('Blockly.blockRendering.NextConnection'); const OutputConnection = goog.require('Blockly.blockRendering.OutputConnection'); const PreviousConnection = goog.require('Blockly.blockRendering.PreviousConnection'); @@ -37,17 +37,16 @@ const PreviousConnection = goog.require('Blockly.blockRendering.PreviousConnecti const RenderedConnection = goog.requireType('Blockly.RenderedConnection'); /* eslint-disable-next-line no-unused-vars */ const Renderer = goog.requireType('Blockly.blockRendering.Renderer'); -/* eslint-disable-next-line no-unused-vars */ const RoundCorner = goog.require('Blockly.blockRendering.RoundCorner'); /* eslint-disable-next-line no-unused-vars */ -const Row = goog.require('Blockly.blockRendering.Row'); +const Row = goog.requireType('Blockly.blockRendering.Row'); const SpacerRow = goog.require('Blockly.blockRendering.SpacerRow'); const SquareCorner = goog.require('Blockly.blockRendering.SquareCorner'); const StatementInput = goog.require('Blockly.blockRendering.StatementInput'); const TopRow = goog.require('Blockly.blockRendering.TopRow'); const Types = goog.require('Blockly.blockRendering.Types'); -const {ALIGN} = goog.require('Blockly.constants'); -const {DUMMY, STATEMENT, VALUE} = goog.require('Blockly.inputTypes'); +const constants = goog.require('Blockly.constants'); +const inputTypes = goog.require('Blockly.inputTypes'); @@ -290,7 +289,7 @@ RenderInfo.prototype.populateTopRow_ = function() { } const precedesStatement = this.block_.inputList.length && - this.block_.inputList[0].type == STATEMENT; + this.block_.inputList[0].type == inputTypes.STATEMENT; // This is the minimum height for the row. If one of its elements has a // greater height it will be overwritten in the compute pass. @@ -314,7 +313,8 @@ RenderInfo.prototype.populateBottomRow_ = function() { this.bottomRow.hasNextConnection = !!this.block_.nextConnection; const followsStatement = this.block_.inputList.length && - this.block_.inputList[this.block_.inputList.length - 1].type == STATEMENT; + this.block_.inputList[this.block_.inputList.length - 1].type == + inputTypes.STATEMENT; // This is the minimum height for the row. If one of its elements has a // greater height it will be overwritten in the compute pass. @@ -359,16 +359,16 @@ RenderInfo.prototype.populateBottomRow_ = function() { */ RenderInfo.prototype.addInput_ = function(input, activeRow) { // Non-dummy inputs have visual representations onscreen. - if (this.isInline && input.type == VALUE) { + if (this.isInline && input.type == inputTypes.VALUE) { activeRow.elements.push(new InlineInput(this.constants_, input)); activeRow.hasInlineInput = true; - } else if (input.type == STATEMENT) { + } else if (input.type == inputTypes.STATEMENT) { activeRow.elements.push(new StatementInput(this.constants_, input)); activeRow.hasStatement = true; - } else if (input.type == VALUE) { + } else if (input.type == inputTypes.VALUE) { activeRow.elements.push(new ExternalValueInput(this.constants_, input)); activeRow.hasExternalInput = true; - } else if (input.type == DUMMY) { + } else if (input.type == inputTypes.DUMMY) { // Dummy inputs have no visual representation, but the information is still // important. activeRow.minHeight = Math.max( @@ -397,11 +397,12 @@ RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) { return false; } // A statement input or an input following one always gets a new row. - if (input.type == STATEMENT || lastInput.type == STATEMENT) { + if (input.type == inputTypes.STATEMENT || + lastInput.type == inputTypes.STATEMENT) { return true; } // Value and dummy inputs get new row if inputs are not inlined. - if (input.type == VALUE || input.type == DUMMY) { + if (input.type == inputTypes.VALUE || input.type == inputTypes.DUMMY) { return !this.isInline; } return false; @@ -575,14 +576,14 @@ RenderInfo.prototype.addAlignmentPadding_ = function(row, missingSpace) { } // Decide where the extra padding goes. - if (row.align == ALIGN.LEFT) { + if (row.align == constants.ALIGN.LEFT) { // Add padding to the end of the row. lastSpacer.width += missingSpace; - } else if (row.align == ALIGN.CENTRE) { + } else if (row.align == constants.ALIGN.CENTRE) { // Split the padding between the beginning and end of the row. firstSpacer.width += missingSpace / 2; lastSpacer.width += missingSpace / 2; - } else if (row.align == ALIGN.RIGHT) { + } else if (row.align == constants.ALIGN.RIGHT) { // Add padding at the beginning of the row. firstSpacer.width += missingSpace; } else { diff --git a/core/renderers/common/marker_svg.js b/core/renderers/common/marker_svg.js index 36d12b119..171fa36a6 100644 --- a/core/renderers/common/marker_svg.js +++ b/core/renderers/common/marker_svg.js @@ -11,45 +11,73 @@ 'use strict'; -goog.provide('Blockly.blockRendering.MarkerSvg'); +goog.module('Blockly.blockRendering.MarkerSvg'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.ASTNode'); -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.Events'); +const ASTNode = goog.require('Blockly.ASTNode'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocationSvg = goog.requireType('Blockly.IASTNodeLocationSvg'); +/* eslint-disable-next-line no-unused-vars */ +const Marker = goog.requireType('Blockly.Marker'); +/* eslint-disable-next-line no-unused-vars */ +const RenderedConnection = goog.requireType('Blockly.RenderedConnection'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const dom = goog.require('Blockly.utils.dom'); +const svgPaths = goog.require('Blockly.utils.svgPaths'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.MarkerMove'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.blockRendering.ConstantProvider'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.Connection'); -goog.requireType('Blockly.Field'); -goog.requireType('Blockly.IASTNodeLocationSvg'); -goog.requireType('Blockly.Marker'); -goog.requireType('Blockly.RenderedConnection'); -goog.requireType('Blockly.WorkspaceSvg'); +/** + * The name of the CSS class for a cursor. + * @const {string} + */ +const CURSOR_CLASS = 'blocklyCursor'; + +/** + * The name of the CSS class for a marker. + * @const {string} + */ +const MARKER_CLASS = 'blocklyMarker'; + +/** + * What we multiply the height by to get the height of the marker. + * Only used for the block and block connections. + * @const {number} + */ +const HEIGHT_MULTIPLIER = 3 / 4; + /** * Class for a marker. - * @param {!Blockly.WorkspaceSvg} workspace The workspace the marker belongs to. - * @param {!Blockly.blockRendering.ConstantProvider} constants The constants for + * @param {!WorkspaceSvg} workspace The workspace the marker belongs to. + * @param {!ConstantProvider} constants The constants for * the renderer. - * @param {!Blockly.Marker} marker The marker to draw. + * @param {!Marker} marker The marker to draw. * @constructor */ -Blockly.blockRendering.MarkerSvg = function(workspace, constants, marker) { +const MarkerSvg = function(workspace, constants, marker) { /** * The workspace the marker belongs to. - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.workspace_ = workspace; /** * The marker to draw. - * @type {!Blockly.Marker} + * @type {!Marker} * @private */ this.marker_ = marker; @@ -57,14 +85,14 @@ Blockly.blockRendering.MarkerSvg = function(workspace, constants, marker) { /** * The workspace, field, or block that the marker SVG element should be * attached to. - * @type {Blockly.IASTNodeLocationSvg} + * @type {IASTNodeLocationSvg} * @private */ this.parent_ = null; /** * The constants necessary to draw the marker. - * @type {Blockly.blockRendering.ConstantProvider} + * @type {ConstantProvider} * @protected */ this.constants_ = constants; @@ -75,8 +103,8 @@ Blockly.blockRendering.MarkerSvg = function(workspace, constants, marker) { */ this.currentMarkerSvg = null; - var defaultColour = this.isCursor() ? this.constants_.CURSOR_COLOUR : - this.constants_.MARKER_COLOUR; + const defaultColour = this.isCursor() ? this.constants_.CURSOR_COLOUR : + this.constants_.MARKER_COLOUR; /** * The colour of the marker. @@ -85,38 +113,19 @@ Blockly.blockRendering.MarkerSvg = function(workspace, constants, marker) { this.colour_ = marker.colour || defaultColour; }; -/** - * The name of the CSS class for a cursor. - * @const {string} - */ -Blockly.blockRendering.MarkerSvg.CURSOR_CLASS = 'blocklyCursor'; - -/** - * The name of the CSS class for a marker. - * @const {string} - */ -Blockly.blockRendering.MarkerSvg.MARKER_CLASS = 'blocklyMarker'; - -/** - * What we multiply the height by to get the height of the marker. - * Only used for the block and block connections. - * @const {number} - */ -Blockly.blockRendering.MarkerSvg.HEIGHT_MULTIPLIER = 3 / 4; - /** * Return the root node of the SVG or null if none exists. * @return {SVGElement} The root SVG node. */ -Blockly.blockRendering.MarkerSvg.prototype.getSvgRoot = function() { +MarkerSvg.prototype.getSvgRoot = function() { return this.svgGroup_; }; /** * Get the marker. - * @return {!Blockly.Marker} The marker to draw for. + * @return {!Marker} The marker to draw for. */ -Blockly.blockRendering.MarkerSvg.prototype.getMarker = function() { +MarkerSvg.prototype.getMarker = function() { return this.marker_; }; @@ -125,7 +134,7 @@ Blockly.blockRendering.MarkerSvg.prototype.getMarker = function() { * A cursor is drawn as a flashing line. A marker is drawn as a solid line. * @return {boolean} True if the marker is a cursor, false otherwise. */ -Blockly.blockRendering.MarkerSvg.prototype.isCursor = function() { +MarkerSvg.prototype.isCursor = function() { return this.marker_.type == 'cursor'; }; @@ -134,15 +143,11 @@ Blockly.blockRendering.MarkerSvg.prototype.isCursor = function() { * @return {!SVGElement} The marker controls SVG group. * @package */ -Blockly.blockRendering.MarkerSvg.prototype.createDom = function() { - var className = this.isCursor() ? - Blockly.blockRendering.MarkerSvg.CURSOR_CLASS : - Blockly.blockRendering.MarkerSvg.MARKER_CLASS; +MarkerSvg.prototype.createDom = function() { + const className = + this.isCursor() ? CURSOR_CLASS : MARKER_CLASS; - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, { - 'class': className - }, null); + this.svgGroup_ = dom.createSvgElement(Svg.G, {'class': className}, null); this.createDomInternal_(); return this.svgGroup_; @@ -150,11 +155,11 @@ Blockly.blockRendering.MarkerSvg.prototype.createDom = function() { /** * Attaches the SVG root of the marker to the SVG group of the parent. - * @param {!Blockly.IASTNodeLocationSvg} newParent The workspace, field, or + * @param {!IASTNodeLocationSvg} newParent The workspace, field, or * block that the marker SVG element should be attached to. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.setParent_ = function(newParent) { +MarkerSvg.prototype.setParent_ = function(newParent) { if (!this.isCursor()) { if (this.parent_) { this.parent_.setMarkerSvg(null); @@ -171,10 +176,10 @@ Blockly.blockRendering.MarkerSvg.prototype.setParent_ = function(newParent) { /** * Update the marker. - * @param {Blockly.ASTNode} oldNode The previous node the marker was on or null. - * @param {Blockly.ASTNode} curNode The node that we want to draw the marker for. + * @param {ASTNode} oldNode The previous node the marker was on or null. + * @param {ASTNode} curNode The node that we want to draw the marker for. */ -Blockly.blockRendering.MarkerSvg.prototype.draw = function(oldNode, curNode) { +MarkerSvg.prototype.draw = function(oldNode, curNode) { if (!curNode) { this.hide(); return; @@ -182,8 +187,8 @@ Blockly.blockRendering.MarkerSvg.prototype.draw = function(oldNode, curNode) { this.constants_ = this.workspace_.getRenderer().getConstants(); - var defaultColour = this.isCursor() ? this.constants_.CURSOR_COLOUR : - this.constants_.MARKER_COLOUR; + const defaultColour = this.isCursor() ? this.constants_.CURSOR_COLOUR : + this.constants_.MARKER_COLOUR; this.colour_ = this.marker_.colour || defaultColour; this.applyColour_(curNode); @@ -192,7 +197,7 @@ Blockly.blockRendering.MarkerSvg.prototype.draw = function(oldNode, curNode) { this.fireMarkerEvent_(oldNode, curNode); // Ensures the marker will be visible immediately after the move. - var animate = this.currentMarkerSvg.childNodes[0]; + const animate = this.currentMarkerSvg.childNodes[0]; if (animate !== undefined) { animate.beginElement && animate.beginElement(); } @@ -201,28 +206,28 @@ Blockly.blockRendering.MarkerSvg.prototype.draw = function(oldNode, curNode) { /** * Update the marker's visible state based on the type of curNode.. - * @param {!Blockly.ASTNode} curNode The node that we want to draw the marker for. + * @param {!ASTNode} curNode The node that we want to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showAtLocation_ = function(curNode) { - var curNodeAsConnection = - /** @type {!Blockly.Connection} */ (curNode.getLocation()); - var connectionType = curNodeAsConnection.type; - if (curNode.getType() == Blockly.ASTNode.types.BLOCK) { +MarkerSvg.prototype.showAtLocation_ = function(curNode) { + const curNodeAsConnection = + /** @type {!Connection} */ (curNode.getLocation()); + const connectionType = curNodeAsConnection.type; + if (curNode.getType() == ASTNode.types.BLOCK) { this.showWithBlock_(curNode); - } else if (curNode.getType() == Blockly.ASTNode.types.OUTPUT) { + } else if (curNode.getType() == ASTNode.types.OUTPUT) { this.showWithOutput_(curNode); - } else if (connectionType == Blockly.connectionTypes.INPUT_VALUE) { + } else if (connectionType == connectionTypes.INPUT_VALUE) { this.showWithInput_(curNode); - } else if (connectionType == Blockly.connectionTypes.NEXT_STATEMENT) { + } else if (connectionType == connectionTypes.NEXT_STATEMENT) { this.showWithNext_(curNode); - } else if (curNode.getType() == Blockly.ASTNode.types.PREVIOUS) { + } else if (curNode.getType() == ASTNode.types.PREVIOUS) { this.showWithPrevious_(curNode); - } else if (curNode.getType() == Blockly.ASTNode.types.FIELD) { + } else if (curNode.getType() == ASTNode.types.FIELD) { this.showWithField_(curNode); - } else if (curNode.getType() == Blockly.ASTNode.types.WORKSPACE) { + } else if (curNode.getType() == ASTNode.types.WORKSPACE) { this.showWithCoordinates_(curNode); - } else if (curNode.getType() == Blockly.ASTNode.types.STACK) { + } else if (curNode.getType() == ASTNode.types.STACK) { this.showWithStack_(curNode); } }; @@ -234,22 +239,21 @@ Blockly.blockRendering.MarkerSvg.prototype.showAtLocation_ = function(curNode) { /** * Show the marker as a combination of the previous connection and block, * the output connection and block, or just the block. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @private */ -Blockly.blockRendering.MarkerSvg.prototype.showWithBlockPrevOutput_ = function( - curNode) { - var block = /** @type {!Blockly.BlockSvg} */ (curNode.getSourceBlock()); - var width = block.width; - var height = block.height; - var markerHeight = height * Blockly.blockRendering.MarkerSvg.HEIGHT_MULTIPLIER; - var markerOffset = this.constants_.CURSOR_BLOCK_PADDING; +MarkerSvg.prototype.showWithBlockPrevOutput_ = function(curNode) { + const block = /** @type {!BlockSvg} */ (curNode.getSourceBlock()); + const width = block.width; + const height = block.height; + const markerHeight = height * HEIGHT_MULTIPLIER; + const markerOffset = this.constants_.CURSOR_BLOCK_PADDING; if (block.previousConnection) { - var connectionShape = this.constants_.shapeFor(block.previousConnection); + let connectionShape = this.constants_.shapeFor(block.previousConnection); this.positionPrevious_(width, markerOffset, markerHeight, connectionShape); } else if (block.outputConnection) { - var connectionShape = this.constants_.shapeFor(block.outputConnection); + let connectionShape = this.constants_.shapeFor(block.outputConnection); this.positionOutput_(width, height, connectionShape); } else { this.positionBlock_(width, markerOffset, markerHeight); @@ -260,43 +264,41 @@ Blockly.blockRendering.MarkerSvg.prototype.showWithBlockPrevOutput_ = function( /** * Position and display the marker for a block. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithBlock_ = function(curNode) { +MarkerSvg.prototype.showWithBlock_ = function(curNode) { this.showWithBlockPrevOutput_(curNode); }; /** * Position and display the marker for a previous connection. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithPrevious_ = function( - curNode) { +MarkerSvg.prototype.showWithPrevious_ = function(curNode) { this.showWithBlockPrevOutput_(curNode); }; /** * Position and display the marker for an output connection. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithOutput_ = function(curNode) { +MarkerSvg.prototype.showWithOutput_ = function(curNode) { this.showWithBlockPrevOutput_(curNode); }; /** * Position and display the marker for a workspace coordinate. * This is a horizontal line. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithCoordinates_ = function( - curNode) { - var wsCoordinate = curNode.getWsCoordinate(); - var x = wsCoordinate.x; - var y = wsCoordinate.y; +MarkerSvg.prototype.showWithCoordinates_ = function(curNode) { + const wsCoordinate = curNode.getWsCoordinate(); + let x = wsCoordinate.x; + const y = wsCoordinate.y; if (this.workspace_.RTL) { x -= this.constants_.CURSOR_WS_WIDTH; @@ -310,13 +312,13 @@ Blockly.blockRendering.MarkerSvg.prototype.showWithCoordinates_ = function( /** * Position and display the marker for a field. * This is a box around the field. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithField_ = function(curNode) { - var field = /** @type {Blockly.Field} */ (curNode.getLocation()); - var width = field.getSize().width; - var height = field.getSize().height; +MarkerSvg.prototype.showWithField_ = function(curNode) { + const field = /** @type {Field} */ (curNode.getLocation()); + const width = field.getSize().width; + const height = field.getSize().height; this.positionRect_(0, 0, width, height); this.setParent_(field); @@ -326,13 +328,13 @@ Blockly.blockRendering.MarkerSvg.prototype.showWithField_ = function(curNode) { /** * Position and display the marker for an input. * This is a puzzle piece. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithInput_ = function(curNode) { - var connection = /** @type {Blockly.RenderedConnection} */ +MarkerSvg.prototype.showWithInput_ = function(curNode) { + const connection = /** @type {RenderedConnection} */ (curNode.getLocation()); - var sourceBlock = /** @type {!Blockly.BlockSvg} */ (connection.getSourceBlock()); + const sourceBlock = /** @type {!BlockSvg} */ (connection.getSourceBlock()); this.positionInput_(connection); this.setParent_(sourceBlock); @@ -343,17 +345,17 @@ Blockly.blockRendering.MarkerSvg.prototype.showWithInput_ = function(curNode) { /** * Position and display the marker for a next connection. * This is a horizontal line. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithNext_ = function(curNode) { - var connection = - /** @type {!Blockly.RenderedConnection} */ (curNode.getLocation()); - var targetBlock = - /** @type {Blockly.BlockSvg} */ (connection.getSourceBlock()); - var x = 0; - var y = connection.getOffsetInBlock().y; - var width = targetBlock.getHeightWidth().width; +MarkerSvg.prototype.showWithNext_ = function(curNode) { + const connection = + /** @type {!RenderedConnection} */ (curNode.getLocation()); + const targetBlock = + /** @type {BlockSvg} */ (connection.getSourceBlock()); + let x = 0; + const y = connection.getOffsetInBlock().y; + const width = targetBlock.getHeightWidth().width; if (this.workspace_.RTL) { x = -width; } @@ -365,25 +367,26 @@ Blockly.blockRendering.MarkerSvg.prototype.showWithNext_ = function(curNode) { /** * Position and display the marker for a stack. * This is a box with extra padding around the entire stack of blocks. - * @param {!Blockly.ASTNode} curNode The node to draw the marker for. + * @param {!ASTNode} curNode The node to draw the marker for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showWithStack_ = function(curNode) { - var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation()); +MarkerSvg.prototype.showWithStack_ = function(curNode) { + const block = /** @type {BlockSvg} */ (curNode.getLocation()); // Gets the height and width of entire stack. - var heightWidth = block.getHeightWidth(); + const heightWidth = block.getHeightWidth(); // Add padding so that being on a stack looks different than being on a block. - var width = heightWidth.width + this.constants_.CURSOR_STACK_PADDING; - var height = heightWidth.height + this.constants_.CURSOR_STACK_PADDING; + const width = heightWidth.width + this.constants_.CURSOR_STACK_PADDING; + const height = heightWidth.height + this.constants_.CURSOR_STACK_PADDING; - // Shift the rectangle slightly to upper left so padding is equal on all sides. - var xPadding = -this.constants_.CURSOR_STACK_PADDING / 2; - var yPadding = -this.constants_.CURSOR_STACK_PADDING / 2; + // Shift the rectangle slightly to upper left so padding is equal on all + // sides. + const xPadding = -this.constants_.CURSOR_STACK_PADDING / 2; + const yPadding = -this.constants_.CURSOR_STACK_PADDING / 2; - var x = xPadding; - var y = yPadding; + let x = xPadding; + const y = yPadding; if (this.workspace_.RTL) { x = -(width + xPadding); @@ -397,7 +400,7 @@ Blockly.blockRendering.MarkerSvg.prototype.showWithStack_ = function(curNode) { * Show the current marker. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.showCurrent_ = function() { +MarkerSvg.prototype.showCurrent_ = function() { this.hide(); this.currentMarkerSvg.style.display = ''; }; @@ -414,12 +417,12 @@ Blockly.blockRendering.MarkerSvg.prototype.showCurrent_ = function() { * @param {number} markerHeight The height of the marker. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.positionBlock_ = function( +MarkerSvg.prototype.positionBlock_ = function( width, markerOffset, markerHeight) { - var markerPath = Blockly.utils.svgPaths.moveBy(-markerOffset, markerHeight) + - Blockly.utils.svgPaths.lineOnAxis('V', -markerOffset) + - Blockly.utils.svgPaths.lineOnAxis('H', width + markerOffset * 2) + - Blockly.utils.svgPaths.lineOnAxis('V', markerHeight); + const markerPath = svgPaths.moveBy(-markerOffset, markerHeight) + + svgPaths.lineOnAxis('V', -markerOffset) + + svgPaths.lineOnAxis('H', width + markerOffset * 2) + + svgPaths.lineOnAxis('V', markerHeight); this.markerBlock_.setAttribute('d', markerPath); if (this.workspace_.RTL) { this.flipRtl_(this.markerBlock_); @@ -430,22 +433,22 @@ Blockly.blockRendering.MarkerSvg.prototype.positionBlock_ = function( /** * Position the marker for an input connection. * Displays a filled in puzzle piece. - * @param {!Blockly.RenderedConnection} connection The connection to position + * @param {!RenderedConnection} connection The connection to position * marker around. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.positionInput_ = function( - connection) { - var x = connection.getOffsetInBlock().x; - var y = connection.getOffsetInBlock().y; +MarkerSvg.prototype.positionInput_ = function(connection) { + const x = connection.getOffsetInBlock().x; + const y = connection.getOffsetInBlock().y; - var path = Blockly.utils.svgPaths.moveTo(0, 0) + - this.constants_.shapeFor(connection).pathDown; + const path = + svgPaths.moveTo(0, 0) + this.constants_.shapeFor(connection).pathDown; this.markerInput_.setAttribute('d', path); - this.markerInput_.setAttribute('transform', + this.markerInput_.setAttribute( + 'transform', 'translate(' + x + ',' + y + ')' + - (this.workspace_.RTL ? ' scale(-1 1)' : '')); + (this.workspace_.RTL ? ' scale(-1 1)' : '')); this.currentMarkerSvg = this.markerInput_; }; @@ -457,8 +460,7 @@ Blockly.blockRendering.MarkerSvg.prototype.positionInput_ = function( * @param {number} width The new width, in workspace units. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.positionLine_ = function( - x, y, width) { +MarkerSvg.prototype.positionLine_ = function(x, y, width) { this.markerSvgLine_.setAttribute('x', x); this.markerSvgLine_.setAttribute('y', y); this.markerSvgLine_.setAttribute('width', width); @@ -473,16 +475,12 @@ Blockly.blockRendering.MarkerSvg.prototype.positionLine_ = function( * @param {!Object} connectionShape The shape object for the connection. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.positionOutput_ = function( - width, height, connectionShape) { - var markerPath = Blockly.utils.svgPaths.moveBy(width, 0) + - Blockly.utils.svgPaths.lineOnAxis( - 'h', -(width - connectionShape.width)) + - Blockly.utils.svgPaths.lineOnAxis( - 'v', this.constants_.TAB_OFFSET_FROM_TOP) + - connectionShape.pathDown + - Blockly.utils.svgPaths.lineOnAxis('V', height) + - Blockly.utils.svgPaths.lineOnAxis('H', width); +MarkerSvg.prototype.positionOutput_ = function(width, height, connectionShape) { + const markerPath = svgPaths.moveBy(width, 0) + + svgPaths.lineOnAxis('h', -(width - connectionShape.width)) + + svgPaths.lineOnAxis('v', this.constants_.TAB_OFFSET_FROM_TOP) + + connectionShape.pathDown + svgPaths.lineOnAxis('V', height) + + svgPaths.lineOnAxis('H', width); this.markerBlock_.setAttribute('d', markerPath); if (this.workspace_.RTL) { this.flipRtl_(this.markerBlock_); @@ -500,16 +498,14 @@ Blockly.blockRendering.MarkerSvg.prototype.positionOutput_ = function( * @param {!Object} connectionShape The shape object for the connection. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.positionPrevious_ = function( +MarkerSvg.prototype.positionPrevious_ = function( width, markerOffset, markerHeight, connectionShape) { - var markerPath = Blockly.utils.svgPaths.moveBy(-markerOffset, markerHeight) + - Blockly.utils.svgPaths.lineOnAxis('V', -markerOffset) + - Blockly.utils.svgPaths.lineOnAxis( - 'H', this.constants_.NOTCH_OFFSET_LEFT) + + const markerPath = svgPaths.moveBy(-markerOffset, markerHeight) + + svgPaths.lineOnAxis('V', -markerOffset) + + svgPaths.lineOnAxis('H', this.constants_.NOTCH_OFFSET_LEFT) + connectionShape.pathLeft + - Blockly.utils.svgPaths.lineOnAxis( - 'H', width + markerOffset * 2) + - Blockly.utils.svgPaths.lineOnAxis('V', markerHeight); + svgPaths.lineOnAxis('H', width + markerOffset * 2) + + svgPaths.lineOnAxis('V', markerHeight); this.markerBlock_.setAttribute('d', markerPath); if (this.workspace_.RTL) { this.flipRtl_(this.markerBlock_); @@ -526,8 +522,7 @@ Blockly.blockRendering.MarkerSvg.prototype.positionPrevious_ = function( * @param {number} height The new height, in workspace units. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.positionRect_ = function( - x, y, width, height) { +MarkerSvg.prototype.positionRect_ = function(x, y, width, height) { this.markerSvgRect_.setAttribute('x', x); this.markerSvgRect_.setAttribute('y', y); this.markerSvgRect_.setAttribute('width', width); @@ -540,14 +535,14 @@ Blockly.blockRendering.MarkerSvg.prototype.positionRect_ = function( * @param {!SVGElement} markerSvg The marker that we want to flip. * @private */ -Blockly.blockRendering.MarkerSvg.prototype.flipRtl_ = function(markerSvg) { +MarkerSvg.prototype.flipRtl_ = function(markerSvg) { markerSvg.setAttribute('transform', 'scale(-1 1)'); }; /** * Hide the marker. */ -Blockly.blockRendering.MarkerSvg.prototype.hide = function() { +MarkerSvg.prototype.hide = function() { this.markerSvgLine_.style.display = 'none'; this.markerSvgRect_.style.display = 'none'; this.markerInput_.style.display = 'none'; @@ -557,16 +552,15 @@ Blockly.blockRendering.MarkerSvg.prototype.hide = function() { /** * Fire event for the marker or marker. - * @param {Blockly.ASTNode} oldNode The old node the marker used to be on. - * @param {!Blockly.ASTNode} curNode The new node the marker is currently on. + * @param {ASTNode} oldNode The old node the marker used to be on. + * @param {!ASTNode} curNode The new node the marker is currently on. * @private */ -Blockly.blockRendering.MarkerSvg.prototype.fireMarkerEvent_ = function( - oldNode, curNode) { - var curBlock = curNode.getSourceBlock(); - var event = new (Blockly.Events.get(Blockly.Events.MARKER_MOVE))( +MarkerSvg.prototype.fireMarkerEvent_ = function(oldNode, curNode) { + const curBlock = curNode.getSourceBlock(); + const event = new (Events.get(Events.MARKER_MOVE))( curBlock, this.isCursor(), oldNode, curNode); - Blockly.Events.fire(event); + Events.fire(event); }; /** @@ -574,7 +568,7 @@ Blockly.blockRendering.MarkerSvg.prototype.fireMarkerEvent_ = function( * @return {!Object} The object holding attributes to make the marker blink. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.getBlinkProperties_ = function() { +MarkerSvg.prototype.getBlinkProperties_ = function() { return { 'attributeType': 'XML', 'attributeName': 'fill', @@ -590,28 +584,28 @@ Blockly.blockRendering.MarkerSvg.prototype.getBlinkProperties_ = function() { * @return {Element} The SVG node created. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { +MarkerSvg.prototype.createDomInternal_ = function() { /* This markup will be generated and added to the .svgGroup_: + values="transparent;transparent;#fff;transparent" + repeatCount="indefinite" /> */ - this.markerSvg_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - { + this.markerSvg_ = dom.createSvgElement( + Svg.G, { 'width': this.constants_.CURSOR_WS_WIDTH, 'height': this.constants_.WS_CURSOR_HEIGHT - }, this.svgGroup_); + }, + this.svgGroup_); // A horizontal line used to represent a workspace coordinate or next // connection. - this.markerSvgLine_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { + this.markerSvgLine_ = dom.createSvgElement( + Svg.RECT, { 'width': this.constants_.CURSOR_WS_WIDTH, 'height': this.constants_.WS_CURSOR_HEIGHT, 'style': 'display: none' @@ -619,29 +613,23 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { this.markerSvg_); // A filled in rectangle used to represent a stack. - this.markerSvgRect_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { + this.markerSvgRect_ = dom.createSvgElement( + Svg.RECT, { 'class': 'blocklyVerticalMarker', - 'rx': 10, 'ry': 10, + 'rx': 10, + 'ry': 10, 'style': 'display: none' }, this.markerSvg_); // A filled in puzzle piece used to represent an input value. - this.markerInput_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { - 'transform': '', - 'style': 'display: none' - }, - this.markerSvg_); + this.markerInput_ = dom.createSvgElement( + Svg.PATH, {'transform': '', 'style': 'display: none'}, this.markerSvg_); // A path used to represent a previous connection and a block, an output // connection and a block, or a block. - this.markerBlock_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { + this.markerBlock_ = dom.createSvgElement( + Svg.PATH, { 'transform': '', 'style': 'display: none', 'fill': 'none', @@ -651,17 +639,11 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { // Markers and stack markers don't blink. if (this.isCursor()) { - var blinkProperties = this.getBlinkProperties_(); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.ANIMATE, blinkProperties, - this.markerSvgLine_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.ANIMATE, blinkProperties, - this.markerInput_); + const blinkProperties = this.getBlinkProperties_(); + dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerSvgLine_); + dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerInput_); blinkProperties['attributeName'] = 'stroke'; - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.ANIMATE, blinkProperties, - this.markerBlock_); + dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerBlock_); } return this.markerSvg_; @@ -669,18 +651,18 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { /** * Apply the marker's colour. - * @param {!Blockly.ASTNode} _curNode The node that we want to draw the marker + * @param {!ASTNode} _curNode The node that we want to draw the marker * for. * @protected */ -Blockly.blockRendering.MarkerSvg.prototype.applyColour_ = function(_curNode) { +MarkerSvg.prototype.applyColour_ = function(_curNode) { this.markerSvgLine_.setAttribute('fill', this.colour_); this.markerSvgRect_.setAttribute('stroke', this.colour_); this.markerInput_.setAttribute('fill', this.colour_); this.markerBlock_.setAttribute('stroke', this.colour_); if (this.isCursor()) { - var values = this.colour_ + ';transparent;transparent;'; + const values = this.colour_ + ';transparent;transparent;'; this.markerSvgLine_.firstChild.setAttribute('values', values); this.markerInput_.firstChild.setAttribute('values', values); this.markerBlock_.firstChild.setAttribute('values', values); @@ -690,8 +672,10 @@ Blockly.blockRendering.MarkerSvg.prototype.applyColour_ = function(_curNode) { /** * Dispose of this marker. */ -Blockly.blockRendering.MarkerSvg.prototype.dispose = function() { +MarkerSvg.prototype.dispose = function() { if (this.svgGroup_) { - Blockly.utils.dom.removeNode(this.svgGroup_); + dom.removeNode(this.svgGroup_); } }; + +exports = MarkerSvg; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index e81b8e0e2..d8d36c9dc 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -11,34 +11,39 @@ 'use strict'; -goog.provide('Blockly.blockRendering.PathObject'); +goog.module('Blockly.blockRendering.PathObject'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.ConstantProvider'); -goog.require('Blockly.blockRendering.IPathObject'); -goog.require('Blockly.Theme'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const IPathObject = goog.requireType('Blockly.blockRendering.IPathObject'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +const dom = goog.require('Blockly.utils.dom'); /** * An object that handles creating and setting each of the SVG elements * used by the renderer. * @param {!SVGElement} root The root SVG element. - * @param {!Blockly.Theme.BlockStyle} style The style object to use for + * @param {!Theme.BlockStyle} style The style object to use for * colouring. - * @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's + * @param {!ConstantProvider} constants The renderer's * constants. * @constructor - * @implements {Blockly.blockRendering.IPathObject} + * @implements {IPathObject} * @package */ -Blockly.blockRendering.PathObject = function(root, style, constants) { +const PathObject = function(root, style, constants) { /** * The renderer's constant provider. - * @type {!Blockly.blockRendering.ConstantProvider} + * @type {!ConstantProvider} * @package */ this.constants = constants; @@ -50,13 +55,12 @@ Blockly.blockRendering.PathObject = function(root, style, constants) { * @type {!SVGElement} * @package */ - this.svgPath = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - {'class': 'blocklyPath'}, this.svgRoot); + this.svgPath = + dom.createSvgElement(Svg.PATH, {'class': 'blocklyPath'}, this.svgRoot); /** * The style object to use when colouring block paths. - * @type {!Blockly.Theme.BlockStyle} + * @type {!Theme.BlockStyle} * @package */ this.style = style; @@ -83,7 +87,7 @@ Blockly.blockRendering.PathObject = function(root, style, constants) { * @param {string} pathString The path. * @package */ -Blockly.blockRendering.PathObject.prototype.setPath = function(pathString) { +PathObject.prototype.setPath = function(pathString) { this.svgPath.setAttribute('d', pathString); }; @@ -91,7 +95,7 @@ Blockly.blockRendering.PathObject.prototype.setPath = function(pathString) { * Flip the SVG paths in RTL. * @package */ -Blockly.blockRendering.PathObject.prototype.flipRTL = function() { +PathObject.prototype.flipRTL = function() { // Mirror the block's path. this.svgPath.setAttribute('transform', 'scale(-1 1)'); }; @@ -102,7 +106,7 @@ Blockly.blockRendering.PathObject.prototype.flipRTL = function() { * block SVG group. * @package */ -Blockly.blockRendering.PathObject.prototype.setCursorSvg = function(cursorSvg) { +PathObject.prototype.setCursorSvg = function(cursorSvg) { if (!cursorSvg) { this.cursorSvg = null; return; @@ -118,7 +122,7 @@ Blockly.blockRendering.PathObject.prototype.setCursorSvg = function(cursorSvg) { * block SVG group. * @package */ -Blockly.blockRendering.PathObject.prototype.setMarkerSvg = function(markerSvg) { +PathObject.prototype.setMarkerSvg = function(markerSvg) { if (!markerSvg) { this.markerSvg = null; return; @@ -135,10 +139,10 @@ Blockly.blockRendering.PathObject.prototype.setMarkerSvg = function(markerSvg) { /** * Apply the stored colours to the block's path, taking into account whether * the paths belong to a shadow block. - * @param {!Blockly.Block} block The source block. + * @param {!Block} block The source block. * @package */ -Blockly.blockRendering.PathObject.prototype.applyColour = function(block) { +PathObject.prototype.applyColour = function(block) { this.svgPath.setAttribute('stroke', this.style.colourTertiary); this.svgPath.setAttribute('fill', this.style.colourPrimary); @@ -148,10 +152,10 @@ Blockly.blockRendering.PathObject.prototype.applyColour = function(block) { /** * Set the style. - * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. + * @param {!Theme.BlockStyle} blockStyle The block style to use. * @package */ -Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) { +PathObject.prototype.setStyle = function(blockStyle) { this.style = blockStyle; }; @@ -162,14 +166,11 @@ Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) { * be removed. * @protected */ -Blockly.blockRendering.PathObject.prototype.setClass_ = function( - className, add) { +PathObject.prototype.setClass_ = function(className, add) { if (add) { - Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgRoot), - className); + dom.addClass(/** @type {!Element} */ (this.svgRoot), className); } else { - Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgRoot), - className); + dom.removeClass(/** @type {!Element} */ (this.svgRoot), className); } }; @@ -179,11 +180,10 @@ Blockly.blockRendering.PathObject.prototype.setClass_ = function( * @param {boolean} enable True if highlighted. * @package */ -Blockly.blockRendering.PathObject.prototype.updateHighlighted = function( - enable) { +PathObject.prototype.updateHighlighted = function(enable) { if (enable) { - this.svgPath.setAttribute('filter', - 'url(#' + this.constants.embossFilterId + ')'); + this.svgPath.setAttribute( + 'filter', 'url(#' + this.constants.embossFilterId + ')'); } else { this.svgPath.setAttribute('filter', 'none'); } @@ -194,7 +194,7 @@ Blockly.blockRendering.PathObject.prototype.updateHighlighted = function( * @param {boolean} shadow True if the block is a shadow block. * @protected */ -Blockly.blockRendering.PathObject.prototype.updateShadow_ = function(shadow) { +PathObject.prototype.updateShadow_ = function(shadow) { if (shadow) { this.svgPath.setAttribute('stroke', 'none'); this.svgPath.setAttribute('fill', this.style.colourSecondary); @@ -206,12 +206,11 @@ Blockly.blockRendering.PathObject.prototype.updateShadow_ = function(shadow) { * @param {boolean} disabled True if disabled. * @protected */ -Blockly.blockRendering.PathObject.prototype.updateDisabled_ = function( - disabled) { +PathObject.prototype.updateDisabled_ = function(disabled) { this.setClass_('blocklyDisabled', disabled); if (disabled) { - this.svgPath.setAttribute('fill', - 'url(#' + this.constants.disabledPatternId + ')'); + this.svgPath.setAttribute( + 'fill', 'url(#' + this.constants.disabledPatternId + ')'); } }; @@ -220,7 +219,7 @@ Blockly.blockRendering.PathObject.prototype.updateDisabled_ = function( * @param {boolean} enable True if selection is enabled, false otherwise. * @package */ -Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { +PathObject.prototype.updateSelected = function(enable) { this.setClass_('blocklySelected', enable); }; @@ -230,8 +229,7 @@ Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { * area, false otherwise. * @package */ -Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function( - enable) { +PathObject.prototype.updateDraggingDelete = function(enable) { this.setClass_('blocklyDraggingDelete', enable); }; @@ -241,8 +239,7 @@ Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function( * otherwise. * @package */ -Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function( - enable) { +PathObject.prototype.updateInsertionMarker = function(enable) { this.setClass_('blocklyInsertionMarker', enable); }; @@ -251,7 +248,7 @@ Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function( * @param {boolean} enable True if the block is movable, false otherwise. * @package */ -Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) { +PathObject.prototype.updateMovable = function(enable) { this.setClass_('blocklyDraggable', enable); }; @@ -262,21 +259,19 @@ Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) { * @param {boolean} enable True if styling should be added. * @package */ -Blockly.blockRendering.PathObject.prototype.updateReplacementFade = - function(enable) { - /* eslint-disable indent */ +PathObject.prototype.updateReplacementFade = function(enable) { this.setClass_('blocklyReplaceable', enable); -}; /* eslint-enable indent */ +}; /** * Add or remove styling that shows that if the dragging block is dropped, this * block will be connected to the input. - * @param {Blockly.Connection} _conn The connection on the input to highlight. + * @param {Connection} _conn The connection on the input to highlight. * @param {boolean} _enable True if styling should be added. * @package */ -Blockly.blockRendering.PathObject.prototype.updateShapeForInputHighlight = - function(_conn, _enable) { - /* eslint-disable indent */ +PathObject.prototype.updateShapeForInputHighlight = function(_conn, _enable) { // NOP -}; /* eslint-enable indent */ +}; + +exports = PathObject; diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index 37e4a883a..0fdd2d00f 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -10,27 +10,37 @@ */ 'use strict'; -goog.provide('Blockly.blockRendering.Renderer'); +goog.module('Blockly.blockRendering.Renderer'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.ConstantProvider'); -goog.require('Blockly.blockRendering.Debug'); -goog.require('Blockly.blockRendering.Drawer'); -goog.require('Blockly.blockRendering.IPathObject'); -goog.require('Blockly.blockRendering.MarkerSvg'); -goog.require('Blockly.blockRendering.PathObject'); -goog.require('Blockly.blockRendering.RenderInfo'); -goog.require('Blockly.connectionTypes'); -goog.require('Blockly.InsertionMarkerManager'); -goog.require('Blockly.IRegistrable'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.Connection'); -goog.requireType('Blockly.Marker'); -goog.requireType('Blockly.RenderedConnection'); -goog.requireType('Blockly.Theme'); -goog.requireType('Blockly.utils.object'); -goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Connection = goog.require('Blockly.Connection'); +const ConstantProvider = goog.require('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Debug = goog.requireType('Blockly.blockRendering.Debug'); +const Drawer = goog.require('Blockly.blockRendering.Drawer'); +const InsertionMarkerManager = goog.require('Blockly.InsertionMarkerManager'); +/* eslint-disable-next-line no-unused-vars */ +const IRegistrable = goog.requireType('Blockly.IRegistrable'); +/* eslint-disable-next-line no-unused-vars */ +const IPathObject = goog.requireType('Blockly.blockRendering.IPathObject'); +/* eslint-disable-next-line no-unused-vars */ +const Marker = goog.requireType('Blockly.Marker'); +const MarkerSvg = goog.require('Blockly.blockRendering.MarkerSvg'); +const PathObject = goog.require('Blockly.blockRendering.PathObject'); +/* eslint-disable-next-line no-unused-vars */ +const RenderedConnection = goog.requireType('Blockly.RenderedConnection'); +const RenderInfo = goog.require('Blockly.blockRendering.RenderInfo'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const blockRendering = goog.require('Blockly.blockRendering'); +const connectionTypes = goog.require('Blockly.connectionTypes'); +const object = goog.require('Blockly.utils.object'); /** @@ -38,10 +48,9 @@ goog.requireType('Blockly.WorkspaceSvg'); * @param {string} name The renderer name. * @package * @constructor - * @implements {Blockly.IRegistrable} + * @implements {IRegistrable} */ -Blockly.blockRendering.Renderer = function(name) { - +const Renderer = function(name) { /** * The renderer name. * @type {string} @@ -51,7 +60,7 @@ Blockly.blockRendering.Renderer = function(name) { /** * The renderer's constant provider. - * @type {Blockly.blockRendering.ConstantProvider} + * @type {ConstantProvider} * @private */ this.constants_ = null; @@ -69,22 +78,21 @@ Blockly.blockRendering.Renderer = function(name) { * @return {string} The CSS class name. * @package */ -Blockly.blockRendering.Renderer.prototype.getClassName = function() { +Renderer.prototype.getClassName = function() { return this.name + '-renderer'; }; /** * Initialize the renderer. - * @param {!Blockly.Theme} theme The workspace theme object. + * @param {!Theme} theme The workspace theme object. * @param {Object=} opt_rendererOverrides Rendering constant overrides. * @package */ -Blockly.blockRendering.Renderer.prototype.init = function(theme, - opt_rendererOverrides) { +Renderer.prototype.init = function(theme, opt_rendererOverrides) { this.constants_ = this.makeConstants_(); if (opt_rendererOverrides) { this.overrides = opt_rendererOverrides; - Blockly.utils.object.mixin(this.constants_, opt_rendererOverrides); + object.mixin(this.constants_, opt_rendererOverrides); } this.constants_.setTheme(theme); this.constants_.init(); @@ -93,26 +101,27 @@ Blockly.blockRendering.Renderer.prototype.init = function(theme, /** * Create any DOM elements that this renderer needs. * @param {!SVGElement} svg The root of the workspace's SVG. - * @param {!Blockly.Theme} theme The workspace theme object. + * @param {!Theme} theme The workspace theme object. * @package */ -Blockly.blockRendering.Renderer.prototype.createDom = function(svg, theme) { - this.constants_.createDom(svg, this.name + '-' + theme.name, +Renderer.prototype.createDom = function(svg, theme) { + this.constants_.createDom( + svg, this.name + '-' + theme.name, '.' + this.getClassName() + '.' + theme.getClassName()); }; /** * Refresh the renderer after a theme change. * @param {!SVGElement} svg The root of the workspace's SVG. - * @param {!Blockly.Theme} theme The workspace theme object. + * @param {!Theme} theme The workspace theme object. * @package */ -Blockly.blockRendering.Renderer.prototype.refreshDom = function(svg, theme) { - var previousConstants = this.getConstants(); +Renderer.prototype.refreshDom = function(svg, theme) { + const previousConstants = this.getConstants(); previousConstants.dispose(); this.constants_ = this.makeConstants_(); if (this.overrides) { - Blockly.utils.object.mixin(this.constants_, this.overrides); + object.mixin(this.constants_, this.overrides); } // Ensure the constant provider's random identifier does not change. this.constants_.randomIdentifier = previousConstants.randomIdentifier; @@ -126,7 +135,7 @@ Blockly.blockRendering.Renderer.prototype.refreshDom = function(svg, theme) { * Delete all DOM elements that this renderer and its constants created. * @package */ -Blockly.blockRendering.Renderer.prototype.dispose = function() { +Renderer.prototype.dispose = function() { if (this.constants_) { this.constants_.dispose(); } @@ -134,161 +143,158 @@ Blockly.blockRendering.Renderer.prototype.dispose = function() { /** * Create a new instance of the renderer's constant provider. - * @return {!Blockly.blockRendering.ConstantProvider} The constant provider. + * @return {!ConstantProvider} The constant provider. * @protected */ -Blockly.blockRendering.Renderer.prototype.makeConstants_ = function() { - return new Blockly.blockRendering.ConstantProvider(); +Renderer.prototype.makeConstants_ = function() { + return new ConstantProvider(); }; /** * Create a new instance of the renderer's render info object. - * @param {!Blockly.BlockSvg} block The block to measure. - * @return {!Blockly.blockRendering.RenderInfo} The render info object. + * @param {!BlockSvg} block The block to measure. + * @return {!RenderInfo} The render info object. * @protected */ -Blockly.blockRendering.Renderer.prototype.makeRenderInfo_ = function(block) { - return new Blockly.blockRendering.RenderInfo(this, block); +Renderer.prototype.makeRenderInfo_ = function(block) { + return new RenderInfo(this, block); }; /** * Create a new instance of the renderer's drawer. - * @param {!Blockly.BlockSvg} block The block to render. - * @param {!Blockly.blockRendering.RenderInfo} info An object containing all + * @param {!BlockSvg} block The block to render. + * @param {!RenderInfo} info An object containing all * information needed to render this block. - * @return {!Blockly.blockRendering.Drawer} The drawer. + * @return {!Drawer} The drawer. * @protected */ -Blockly.blockRendering.Renderer.prototype.makeDrawer_ = function(block, info) { - return new Blockly.blockRendering.Drawer(block, info); +Renderer.prototype.makeDrawer_ = function(block, info) { + return new Drawer(block, info); }; /** * Create a new instance of the renderer's debugger. - * @return {!Blockly.blockRendering.Debug} The renderer debugger. + * @return {!Debug} The renderer debugger. * @suppress {strictModuleDepCheck} Debug renderer only included in playground. * @protected */ -Blockly.blockRendering.Renderer.prototype.makeDebugger_ = function() { - if (!Blockly.blockRendering.Debug) { +Renderer.prototype.makeDebugger_ = function() { + const Debug = goog.module.get('Blockly.blockRendering.Debug'); + if (!Debug) { throw Error('Missing require for Blockly.blockRendering.Debug'); } - return new Blockly.blockRendering.Debug(this.getConstants()); + return new Debug(this.getConstants()); }; /** * Create a new instance of the renderer's marker drawer. - * @param {!Blockly.WorkspaceSvg} workspace The workspace the marker belongs to. - * @param {!Blockly.Marker} marker The marker. - * @return {!Blockly.blockRendering.MarkerSvg} The object in charge of drawing + * @param {!WorkspaceSvg} workspace The workspace the marker belongs to. + * @param {!Marker} marker The marker. + * @return {!MarkerSvg} The object in charge of drawing * the marker. * @package */ -Blockly.blockRendering.Renderer.prototype.makeMarkerDrawer = function( - workspace, marker) { - return new Blockly.blockRendering.MarkerSvg(workspace, this.getConstants(), marker); +Renderer.prototype.makeMarkerDrawer = function(workspace, marker) { + return new MarkerSvg(workspace, this.getConstants(), marker); }; /** * Create a new instance of a renderer path object. * @param {!SVGElement} root The root SVG element. - * @param {!Blockly.Theme.BlockStyle} style The style object to use for + * @param {!Theme.BlockStyle} style The style object to use for * colouring. - * @return {!Blockly.blockRendering.IPathObject} The renderer path object. + * @return {!IPathObject} The renderer path object. * @package */ -Blockly.blockRendering.Renderer.prototype.makePathObject = function(root, - style) { - return new Blockly.blockRendering.PathObject(root, style, - /** @type {!Blockly.blockRendering.ConstantProvider} */ (this.constants_)); - +Renderer.prototype.makePathObject = function(root, style) { + return new PathObject( + root, style, /** @type {!ConstantProvider} */ (this.constants_)); }; /** * Get the current renderer's constant provider. We assume that when this is * called, the renderer has already been initialized. - * @return {!Blockly.blockRendering.ConstantProvider} The constant provider. + * @return {!ConstantProvider} The constant provider. * @package */ -Blockly.blockRendering.Renderer.prototype.getConstants = function() { - return ( - /** @type {!Blockly.blockRendering.ConstantProvider} */ - (this.constants_)); +Renderer.prototype.getConstants = function() { + return /** @type {!ConstantProvider} */ (this.constants_); }; /** * Determine whether or not to highlight a connection. - * @param {Blockly.Connection} _conn The connection to determine whether or not + * @param {Connection} _conn The connection to determine whether or not * to highlight. * @return {boolean} True if we should highlight the connection. * @package */ -Blockly.blockRendering.Renderer.prototype.shouldHighlightConnection = - function(_conn) { - /* eslint-disable indent */ +Renderer.prototype.shouldHighlightConnection = function(_conn) { return true; -}; /* eslint-enable indent */ +}; /** * Checks if an orphaned block can connect to the "end" of the topBlock's * block-clump. If the clump is a row the end is the last input. If the clump * is a stack, the end is the last next connection. If the clump is neither, * then this returns false. - * @param {!Blockly.BlockSvg} topBlock The top block of the block clump we want to try and - * connect to. - * @param {!Blockly.BlockSvg} orphanBlock The orphan block that wants to find + * @param {!BlockSvg} topBlock The top block of the block clump we want to try + * and connect to. + * @param {!BlockSvg} orphanBlock The orphan block that wants to find * a home. * @param {number} localType The type of the connection being dragged. * @return {boolean} Whether there is a home for the orphan or not. * @package */ -Blockly.blockRendering.Renderer.prototype.orphanCanConnectAtEnd = - function(topBlock, orphanBlock, localType) { - var orphanConnection = localType === Blockly.connectionTypes.OUTPUT_VALUE ? - orphanBlock.outputConnection : orphanBlock.previousConnection; - return !!Blockly.Connection.getConnectionForOrphanedConnection( - /** @type {!Blockly.Block} **/ (topBlock), - /** @type {!Blockly.Connection} **/ (orphanConnection)); - }; +Renderer.prototype.orphanCanConnectAtEnd = function( + topBlock, orphanBlock, localType) { + const orphanConnection = + (localType === connectionTypes.OUTPUT_VALUE ? + orphanBlock.outputConnection : + orphanBlock.previousConnection); + return !!Connection.getConnectionForOrphanedConnection( + /** @type {!Block} **/ (topBlock), + /** @type {!Connection} **/ (orphanConnection)); +}; /** * Chooses a connection preview method based on the available connection, the * current dragged connection, and the block being dragged. - * @param {!Blockly.RenderedConnection} closest The available connection. - * @param {!Blockly.RenderedConnection} local The connection currently being + * @param {!RenderedConnection} closest The available connection. + * @param {!RenderedConnection} local The connection currently being * dragged. - * @param {!Blockly.BlockSvg} topBlock The block currently being dragged. - * @return {!Blockly.InsertionMarkerManager.PREVIEW_TYPE} The preview type + * @param {!BlockSvg} topBlock The block currently being dragged. + * @return {!InsertionMarkerManager.PREVIEW_TYPE} The preview type * to display. * @package */ -Blockly.blockRendering.Renderer.prototype.getConnectionPreviewMethod = function( +Renderer.prototype.getConnectionPreviewMethod = function( closest, local, topBlock) { - if (local.type == Blockly.connectionTypes.OUTPUT_VALUE || - local.type == Blockly.connectionTypes.PREVIOUS_STATEMENT) { + if (local.type == connectionTypes.OUTPUT_VALUE || + local.type == connectionTypes.PREVIOUS_STATEMENT) { if (!closest.isConnected() || this.orphanCanConnectAtEnd( topBlock, - /** @type {!Blockly.BlockSvg} */ (closest.targetBlock()), - local.type)) { - return Blockly.InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER; + /** @type {!BlockSvg} */ (closest.targetBlock()), local.type)) { + return InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER; } - return Blockly.InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE; + return InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE; } - return Blockly.InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER; + return InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER; }; /** * Render the block. - * @param {!Blockly.BlockSvg} block The block to render. + * @param {!BlockSvg} block The block to render. * @package */ -Blockly.blockRendering.Renderer.prototype.render = function(block) { - if (Blockly.blockRendering.useDebugger && !block.renderingDebugger) { +Renderer.prototype.render = function(block) { + if (blockRendering.isDebuggerEnabled() && !block.renderingDebugger) { block.renderingDebugger = this.makeDebugger_(); } - var info = this.makeRenderInfo_(block); + const info = this.makeRenderInfo_(block); info.measure(); this.makeDrawer_(block, info).draw(); }; + +exports = Renderer; diff --git a/core/renderers/geras/constants.js b/core/renderers/geras/constants.js index 0272d921f..9a923a34a 100644 --- a/core/renderers/geras/constants.js +++ b/core/renderers/geras/constants.js @@ -11,20 +11,21 @@ */ 'use strict'; -goog.provide('Blockly.geras.ConstantProvider'); +goog.module('Blockly.geras.ConstantProvider'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.ConstantProvider'); -goog.require('Blockly.utils.object'); +const BaseConstantProvider = goog.require('Blockly.blockRendering.ConstantProvider'); +const object = goog.require('Blockly.utils.object'); /** * An object that provides constants for rendering blocks in Geras mode. * @constructor * @package - * @extends {Blockly.blockRendering.ConstantProvider} + * @extends {BaseConstantProvider} */ -Blockly.geras.ConstantProvider = function() { - Blockly.geras.ConstantProvider.superClass_.constructor.call(this); +const ConstantProvider = function() { + ConstantProvider.superClass_.constructor.call(this); /** * @override @@ -47,23 +48,23 @@ Blockly.geras.ConstantProvider = function() { */ this.STATEMENT_BOTTOM_SPACER = -this.NOTCH_HEIGHT / 2; }; -Blockly.utils.object.inherits(Blockly.geras.ConstantProvider, - Blockly.blockRendering.ConstantProvider); +object.inherits(ConstantProvider, BaseConstantProvider); /** * @override */ -Blockly.geras.ConstantProvider.prototype.getCSS_ = function(selector) { - return Blockly.geras.ConstantProvider.superClass_.getCSS_.call(this, selector) - .concat([ - /* eslint-disable indent */ - // Insertion marker. - selector + ' .blocklyInsertionMarker>.blocklyPathLight,', - selector + ' .blocklyInsertionMarker>.blocklyPathDark {', - 'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';', - 'stroke: none;', - '}', - /* eslint-enable indent */ - ]); +ConstantProvider.prototype.getCSS_ = function(selector) { + return ConstantProvider.superClass_.getCSS_.call(this, selector).concat([ + /* eslint-disable indent */ + // Insertion marker. + selector + ' .blocklyInsertionMarker>.blocklyPathLight,', + selector + ' .blocklyInsertionMarker>.blocklyPathDark {', + 'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';', + 'stroke: none;', + '}', + /* eslint-enable indent */ + ]); }; + +exports = ConstantProvider; diff --git a/core/renderers/geras/drawer.js b/core/renderers/geras/drawer.js index 360d123ce..8c4781890 100644 --- a/core/renderers/geras/drawer.js +++ b/core/renderers/geras/drawer.js @@ -10,51 +10,54 @@ */ 'use strict'; -goog.provide('Blockly.geras.Drawer'); +goog.module('Blockly.geras.Drawer'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.Drawer'); -goog.require('Blockly.geras.Highlighter'); -goog.require('Blockly.geras.RenderInfo'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.svgPaths'); - -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.geras.PathObject'); +const BaseDrawer = goog.require('Blockly.blockRendering.Drawer'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Highlighter = goog.require('Blockly.geras.Highlighter'); +/* eslint-disable-next-line no-unused-vars */ +const PathObject = goog.requireType('Blockly.geras.PathObject'); +/* eslint-disable-next-line no-unused-vars */ +const RenderInfo = goog.requireType('Blockly.geras.RenderInfo'); +const blockRendering = goog.require('Blockly.blockRendering'); +const object = goog.require('Blockly.utils.object'); +const svgPaths = goog.require('Blockly.utils.svgPaths'); /** * An object that draws a block based on the given rendering information. - * @param {!Blockly.BlockSvg} block The block to render. - * @param {!Blockly.geras.RenderInfo} info An object containing all + * @param {!BlockSvg} block The block to render. + * @param {!RenderInfo} info An object containing all * information needed to render this block. * @package * @constructor - * @extends {Blockly.blockRendering.Drawer} + * @extends {BaseDrawer} */ -Blockly.geras.Drawer = function(block, info) { - Blockly.geras.Drawer.superClass_.constructor.call(this, block, info); +const Drawer = function(block, info) { + Drawer.superClass_.constructor.call(this, block, info); // Unlike Thrasos, Geras has highlights and drop shadows. - this.highlighter_ = new Blockly.geras.Highlighter(info); + this.highlighter_ = new Highlighter(info); }; -Blockly.utils.object.inherits(Blockly.geras.Drawer, - Blockly.blockRendering.Drawer); +object.inherits(Drawer, BaseDrawer); /** * @override */ -Blockly.geras.Drawer.prototype.draw = function() { +Drawer.prototype.draw = function() { this.hideHiddenIcons_(); this.drawOutline_(); this.drawInternals_(); - var pathObject = - /** @type {!Blockly.geras.PathObject} */ (this.block_.pathObject); + const pathObject = + /** @type {!PathObject} */ (this.block_.pathObject); pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_); pathObject.setHighlightPath(this.highlighter_.getPath()); if (this.info_.RTL) { pathObject.flipRTL(); } - if (Blockly.blockRendering.useDebugger) { + if (blockRendering.isDebuggerEnabled()) { this.block_.renderingDebugger.drawDebug(this.block_, this.info_); } this.recordSizeOnBlock_(); @@ -63,58 +66,57 @@ Blockly.geras.Drawer.prototype.draw = function() { /** * @override */ -Blockly.geras.Drawer.prototype.drawTop_ = function() { +Drawer.prototype.drawTop_ = function() { this.highlighter_.drawTopCorner(this.info_.topRow); this.highlighter_.drawRightSideRow(this.info_.topRow); - Blockly.geras.Drawer.superClass_.drawTop_.call(this); + Drawer.superClass_.drawTop_.call(this); }; /** * @override */ -Blockly.geras.Drawer.prototype.drawJaggedEdge_ = function(row) { +Drawer.prototype.drawJaggedEdge_ = function(row) { this.highlighter_.drawJaggedEdge_(row); - Blockly.geras.Drawer.superClass_.drawJaggedEdge_.call(this, row); + Drawer.superClass_.drawJaggedEdge_.call(this, row); }; /** * @override */ -Blockly.geras.Drawer.prototype.drawValueInput_ = function(row) { +Drawer.prototype.drawValueInput_ = function(row) { this.highlighter_.drawValueInput(row); - Blockly.geras.Drawer.superClass_.drawValueInput_.call(this, row); + Drawer.superClass_.drawValueInput_.call(this, row); }; /** * @override */ -Blockly.geras.Drawer.prototype.drawStatementInput_ = function(row) { +Drawer.prototype.drawStatementInput_ = function(row) { this.highlighter_.drawStatementInput(row); - Blockly.geras.Drawer.superClass_.drawStatementInput_.call(this, row); + Drawer.superClass_.drawStatementInput_.call(this, row); }; /** * @override */ -Blockly.geras.Drawer.prototype.drawRightSideRow_ = function(row) { +Drawer.prototype.drawRightSideRow_ = function(row) { this.highlighter_.drawRightSideRow(row); - this.outlinePath_ += - Blockly.utils.svgPaths.lineOnAxis('H', row.xPos + row.width) + - Blockly.utils.svgPaths.lineOnAxis('V', row.yPos + row.height); + this.outlinePath_ += svgPaths.lineOnAxis('H', row.xPos + row.width) + + svgPaths.lineOnAxis('V', row.yPos + row.height); }; /** * @override */ -Blockly.geras.Drawer.prototype.drawBottom_ = function() { +Drawer.prototype.drawBottom_ = function() { this.highlighter_.drawBottomRow(this.info_.bottomRow); - Blockly.geras.Drawer.superClass_.drawBottom_.call(this); + Drawer.superClass_.drawBottom_.call(this); }; /** @@ -123,65 +125,64 @@ Blockly.geras.Drawer.prototype.drawBottom_ = function() { * @protected * @override */ -Blockly.geras.Drawer.prototype.drawLeft_ = function() { +Drawer.prototype.drawLeft_ = function() { this.highlighter_.drawLeft(); - Blockly.geras.Drawer.superClass_.drawLeft_.call(this); + Drawer.superClass_.drawLeft_.call(this); }; /** * @override */ -Blockly.geras.Drawer.prototype.drawInlineInput_ = function(input) { +Drawer.prototype.drawInlineInput_ = function(input) { this.highlighter_.drawInlineInput(input); - Blockly.geras.Drawer.superClass_.drawInlineInput_.call(this, input); + Drawer.superClass_.drawInlineInput_.call(this, input); }; /** * @override */ -Blockly.geras.Drawer.prototype.positionInlineInputConnection_ = function(input) { - var yPos = input.centerline - input.height / 2; +Drawer.prototype.positionInlineInputConnection_ = function(input) { + const yPos = input.centerline - input.height / 2; // Move the connection. if (input.connectionModel) { // xPos already contains info about startX - var connX = input.xPos + input.connectionWidth + - this.constants_.DARK_PATH_OFFSET; + let connX = + input.xPos + input.connectionWidth + this.constants_.DARK_PATH_OFFSET; if (this.info_.RTL) { connX *= -1; } input.connectionModel.setOffsetInBlock( - connX, yPos + input.connectionOffsetY + - this.constants_.DARK_PATH_OFFSET); + connX, + yPos + input.connectionOffsetY + this.constants_.DARK_PATH_OFFSET); } }; /** * @override */ -Blockly.geras.Drawer.prototype.positionStatementInputConnection_ = function(row) { - var input = row.getLastInput(); +Drawer.prototype.positionStatementInputConnection_ = function(row) { + const input = row.getLastInput(); if (input.connectionModel) { - var connX = row.xPos + row.statementEdge + input.notchOffset; + let connX = row.xPos + row.statementEdge + input.notchOffset; if (this.info_.RTL) { connX *= -1; } else { connX += this.constants_.DARK_PATH_OFFSET; } - input.connectionModel.setOffsetInBlock(connX, - row.yPos + this.constants_.DARK_PATH_OFFSET); + input.connectionModel.setOffsetInBlock( + connX, row.yPos + this.constants_.DARK_PATH_OFFSET); } }; /** * @override */ -Blockly.geras.Drawer.prototype.positionExternalValueConnection_ = function(row) { - var input = row.getLastInput(); +Drawer.prototype.positionExternalValueConnection_ = function(row) { + const input = row.getLastInput(); if (input.connectionModel) { - var connX = row.xPos + row.width + - this.constants_.DARK_PATH_OFFSET; + let connX = row.xPos + row.width + this.constants_.DARK_PATH_OFFSET; if (this.info_.RTL) { connX *= -1; } @@ -192,15 +193,17 @@ Blockly.geras.Drawer.prototype.positionExternalValueConnection_ = function(row) /** * @override */ -Blockly.geras.Drawer.prototype.positionNextConnection_ = function() { - var bottomRow = this.info_.bottomRow; +Drawer.prototype.positionNextConnection_ = function() { + const bottomRow = this.info_.bottomRow; if (bottomRow.connection) { - var connInfo = bottomRow.connection; - var x = connInfo.xPos; // Already contains info about startX. - var connX = (this.info_.RTL ? -x : x) + - (this.constants_.DARK_PATH_OFFSET / 2); + const connInfo = bottomRow.connection; + const x = connInfo.xPos; // Already contains info about startX. + const connX = + (this.info_.RTL ? -x : x) + (this.constants_.DARK_PATH_OFFSET / 2); connInfo.connectionModel.setOffsetInBlock( connX, bottomRow.baseline + this.constants_.DARK_PATH_OFFSET); } }; + +exports = Drawer; diff --git a/core/renderers/geras/highlight_constants.js b/core/renderers/geras/highlight_constants.js index a986c9e35..5689029b5 100644 --- a/core/renderers/geras/highlight_constants.js +++ b/core/renderers/geras/highlight_constants.js @@ -10,10 +10,12 @@ */ 'use strict'; -goog.provide('Blockly.geras.HighlightConstantProvider'); +goog.module('Blockly.geras.HighlightConstantProvider'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.ConstantProvider'); -goog.require('Blockly.utils.svgPaths'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +const svgPaths = goog.require('Blockly.utils.svgPaths'); /** @@ -21,15 +23,15 @@ goog.require('Blockly.utils.svgPaths'); * Some highlights are simple offsets of the parent paths and can be generated * programmatically. Others, especially on curves, are just made out of piles * of constants and are hard to tweak. - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering + * @param {!ConstantProvider} constants The rendering * constants provider. * @constructor * @package */ -Blockly.geras.HighlightConstantProvider = function(constants) { +const HighlightConstantProvider = function(constants) { /** * The renderer's constant provider. - * @type {!Blockly.blockRendering.ConstantProvider} + * @type {!ConstantProvider} */ this.constantProvider = constants; @@ -44,16 +46,14 @@ Blockly.geras.HighlightConstantProvider = function(constants) { * The start point, which is offset in both X and Y, as an SVG path chunk. * @type {string} */ - this.START_POINT = Blockly.utils.svgPaths.moveBy(this.OFFSET, this.OFFSET); - + this.START_POINT = svgPaths.moveBy(this.OFFSET, this.OFFSET); }; /** * Initialize shape objects based on the constants set in the constructor. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.init = function() { - +HighlightConstantProvider.prototype.init = function() { /** * An object containing sizing and path information about inside corner * highlights. @@ -101,34 +101,32 @@ Blockly.geras.HighlightConstantProvider.prototype.init = function() { * inside corner highlights. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.makeInsideCorner = function() { - var radius = this.constantProvider.CORNER_RADIUS; - var offset = this.OFFSET; +HighlightConstantProvider.prototype.makeInsideCorner = function() { + const radius = this.constantProvider.CORNER_RADIUS; + const offset = this.OFFSET; /** * Distance from shape edge to intersect with a curved corner at 45 degrees. * Applies to highlighting on around the outside of a curve. * @const */ - var distance45outside = (1 - Math.SQRT1_2) * (radius + offset) - offset; + const distance45outside = (1 - Math.SQRT1_2) * (radius + offset) - offset; - var pathTopRtl = - Blockly.utils.svgPaths.moveBy(distance45outside, distance45outside) + - Blockly.utils.svgPaths.arc('a', '0 0,0', radius, - Blockly.utils.svgPaths.point( - -distance45outside - offset, - radius - distance45outside)); + const pathTopRtl = svgPaths.moveBy(distance45outside, distance45outside) + + svgPaths.arc( + 'a', '0 0,0', radius, + svgPaths.point( + -distance45outside - offset, radius - distance45outside)); - var pathBottomRtl = - Blockly.utils.svgPaths.arc('a', '0 0,0', radius + offset, - Blockly.utils.svgPaths.point(radius + offset, radius + offset)); + const pathBottomRtl = svgPaths.arc( + 'a', '0 0,0', radius + offset, + svgPaths.point(radius + offset, radius + offset)); - var pathBottomLtr = - Blockly.utils.svgPaths.moveBy(distance45outside, - distance45outside) + - Blockly.utils.svgPaths.arc('a', '0 0,0', radius + offset, - Blockly.utils.svgPaths.point( - radius - distance45outside, - distance45outside + offset)); + const pathBottomLtr = svgPaths.moveBy(distance45outside, -distance45outside) + + svgPaths.arc( + 'a', '0 0,0', radius + offset, + svgPaths.point( + radius - distance45outside, distance45outside + offset)); return { width: radius + offset, @@ -147,39 +145,40 @@ Blockly.geras.HighlightConstantProvider.prototype.makeInsideCorner = function() * outside corner highlights. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.makeOutsideCorner = function() { - var radius = this.constantProvider.CORNER_RADIUS; - var offset = this.OFFSET; +HighlightConstantProvider.prototype.makeOutsideCorner = function() { + const radius = this.constantProvider.CORNER_RADIUS; + const offset = this.OFFSET; /** * Distance from shape edge to intersect with a curved corner at 45 degrees. * Applies to highlighting on around the inside of a curve. * @const */ - var distance45inside = (1 - Math.SQRT1_2) * (radius - offset) + offset; + const distance45inside = (1 - Math.SQRT1_2) * (radius - offset) + offset; - var topLeftStartX = distance45inside; - var topLeftStartY = distance45inside; - var topLeftCornerHighlightRtl = - Blockly.utils.svgPaths.moveBy(topLeftStartX, topLeftStartY) + - Blockly.utils.svgPaths.arc('a', '0 0,1', radius - offset, - Blockly.utils.svgPaths.point(radius - topLeftStartX, -topLeftStartY + offset)); + const topLeftStartX = distance45inside; + const topLeftStartY = distance45inside; + const topLeftCornerHighlightRtl = + svgPaths.moveBy(topLeftStartX, topLeftStartY) + + svgPaths.arc( + 'a', '0 0,1', radius - offset, + svgPaths.point(radius - topLeftStartX, -topLeftStartY + offset)); /** * SVG path for drawing the highlight on the rounded top-left corner. * @const */ - var topLeftCornerHighlightLtr = - Blockly.utils.svgPaths.moveBy(offset, radius) + - Blockly.utils.svgPaths.arc('a', '0 0,1', radius - offset, - Blockly.utils.svgPaths.point(radius, -radius + offset)); + const topLeftCornerHighlightLtr = svgPaths.moveBy(offset, radius) + + svgPaths.arc( + 'a', '0 0,1', radius - offset, + svgPaths.point(radius, -radius + offset)); - var bottomLeftStartX = distance45inside; - var bottomLeftStartY = -distance45inside; - var bottomLeftPath = Blockly.utils.svgPaths.moveBy( - bottomLeftStartX, bottomLeftStartY) + - Blockly.utils.svgPaths.arc('a', '0 0,1', radius - offset, - Blockly.utils.svgPaths.point(-bottomLeftStartX + offset, - -bottomLeftStartY - radius)); + const bottomLeftStartX = distance45inside; + const bottomLeftStartY = -distance45inside; + const bottomLeftPath = svgPaths.moveBy(bottomLeftStartX, bottomLeftStartY) + + svgPaths.arc( + 'a', '0 0,1', radius - offset, + svgPaths.point( + -bottomLeftStartX + offset, -bottomLeftStartY - radius)); return { height: radius, @@ -197,42 +196,35 @@ Blockly.geras.HighlightConstantProvider.prototype.makeOutsideCorner = function() * puzzle tab highlights. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.makePuzzleTab = function() { - var width = this.constantProvider.TAB_WIDTH; - var height = this.constantProvider.TAB_HEIGHT; +HighlightConstantProvider.prototype.makePuzzleTab = function() { + const width = this.constantProvider.TAB_WIDTH; + const height = this.constantProvider.TAB_HEIGHT; // This is how much of the vertical block edge is actually drawn by the puzzle // tab. - var verticalOverlap = 2.5; + const verticalOverlap = 2.5; - var highlightRtlUp = - Blockly.utils.svgPaths.moveBy(-2, -height + verticalOverlap + 0.9) + - Blockly.utils.svgPaths.lineTo(width * -0.45, -2.1); + const highlightRtlUp = svgPaths.moveBy(-2, -height + verticalOverlap + 0.9) + + svgPaths.lineTo(width * -0.45, -2.1); - var highlightRtlDown = - Blockly.utils.svgPaths.lineOnAxis('v', verticalOverlap) + - Blockly.utils.svgPaths.moveBy(-width * 0.97, 2.5) + - Blockly.utils.svgPaths.curve('q', + const highlightRtlDown = svgPaths.lineOnAxis('v', verticalOverlap) + + svgPaths.moveBy(-width * 0.97, 2.5) + + svgPaths.curve( + 'q', [ - Blockly.utils.svgPaths.point(-width * 0.05, 10), - Blockly.utils.svgPaths.point(width * 0.3, 9.5) + svgPaths.point(-width * 0.05, 10), svgPaths.point(width * 0.3, 9.5) ]) + - Blockly.utils.svgPaths.moveBy(width * 0.67, -1.9) + - Blockly.utils.svgPaths.lineOnAxis('v', verticalOverlap); + svgPaths.moveBy(width * 0.67, -1.9) + + svgPaths.lineOnAxis('v', verticalOverlap); - var highlightLtrUp = - Blockly.utils.svgPaths.lineOnAxis('v', -1.5) + - Blockly.utils.svgPaths.moveBy(width * -0.92, -0.5) + - Blockly.utils.svgPaths.curve('q', - [ - Blockly.utils.svgPaths.point(width * -0.19, -5.5), - Blockly.utils.svgPaths.point(0,-11) - ]) + - Blockly.utils.svgPaths.moveBy(width * 0.92, 1); + const highlightLtrUp = svgPaths.lineOnAxis('v', -1.5) + + svgPaths.moveBy(width * -0.92, -0.5) + + svgPaths.curve( + 'q', [svgPaths.point(width * -0.19, -5.5), svgPaths.point(0, -11)]) + + svgPaths.moveBy(width * 0.92, 1); - var highlightLtrDown = - Blockly.utils.svgPaths.moveBy(-5, height - 0.7) + - Blockly.utils.svgPaths.lineTo(width * 0.46, -2.1); + const highlightLtrDown = + svgPaths.moveBy(-5, height - 0.7) + svgPaths.lineTo(width * 0.46, -2.1); return { width: width, @@ -251,15 +243,11 @@ Blockly.geras.HighlightConstantProvider.prototype.makePuzzleTab = function() { * notch highlights. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.makeNotch = function() { +HighlightConstantProvider.prototype.makeNotch = function() { // This is only for the previous connection. - var pathLeft = - Blockly.utils.svgPaths.lineOnAxis( - 'h', this.OFFSET) + + const pathLeft = svgPaths.lineOnAxis('h', this.OFFSET) + this.constantProvider.NOTCH.pathLeft; - return { - pathLeft: pathLeft - }; + return {pathLeft: pathLeft}; }; /** @@ -267,16 +255,10 @@ Blockly.geras.HighlightConstantProvider.prototype.makeNotch = function() { * collapsed block edge highlights. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.makeJaggedTeeth = function() { - var pathLeft = - Blockly.utils.svgPaths.lineTo(5.1, 2.6) + - Blockly.utils.svgPaths.moveBy(-10.2, 6.8) + - Blockly.utils.svgPaths.lineTo(5.1, 2.6); - return { - pathLeft: pathLeft, - height: 12, - width: 10.2 - }; +HighlightConstantProvider.prototype.makeJaggedTeeth = function() { + const pathLeft = svgPaths.lineTo(5.1, 2.6) + svgPaths.moveBy(-10.2, 6.8) + + svgPaths.lineTo(5.1, 2.6); + return {pathLeft: pathLeft, height: 12, width: 10.2}; }; /** @@ -284,28 +266,22 @@ Blockly.geras.HighlightConstantProvider.prototype.makeJaggedTeeth = function() { * start highlights. * @package */ -Blockly.geras.HighlightConstantProvider.prototype.makeStartHat = function() { - var hatHeight = this.constantProvider.START_HAT.height; - var pathRtl = - Blockly.utils.svgPaths.moveBy(25, -8.7) + - Blockly.utils.svgPaths.curve('c', - [ - Blockly.utils.svgPaths.point(29.7, -6.2), - Blockly.utils.svgPaths.point(57.2, -0.5), - Blockly.utils.svgPaths.point(75, 8.7) - ]); +HighlightConstantProvider.prototype.makeStartHat = function() { + const hatHeight = this.constantProvider.START_HAT.height; + const pathRtl = svgPaths.moveBy(25, -8.7) + svgPaths.curve('c', [ + svgPaths.point(29.7, -6.2), svgPaths.point(57.2, -0.5), + svgPaths.point(75, 8.7) + ]); - var pathLtr = - Blockly.utils.svgPaths.curve('c', - [ - Blockly.utils.svgPaths.point(17.8, -9.2), - Blockly.utils.svgPaths.point(45.3, -14.9), - Blockly.utils.svgPaths.point(75, -8.7) - ]) + - Blockly.utils.svgPaths.moveTo(100.5, hatHeight + 0.5); + const pathLtr = svgPaths.curve('c', [ + svgPaths.point(17.8, -9.2), svgPaths.point(45.3, -14.9), + svgPaths.point(75, -8.7) + ]) + svgPaths.moveTo(100.5, hatHeight + 0.5); return { path: function(rtl) { return rtl ? pathRtl : pathLtr; } }; }; + +exports = HighlightConstantProvider; diff --git a/core/renderers/geras/highlighter.js b/core/renderers/geras/highlighter.js index 74a6bb43d..f04339d29 100644 --- a/core/renderers/geras/highlighter.js +++ b/core/renderers/geras/highlighter.js @@ -11,15 +11,19 @@ */ 'use strict'; -goog.provide('Blockly.geras.Highlighter'); +goog.module('Blockly.geras.Highlighter'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.Types'); -goog.require('Blockly.utils.svgPaths'); - -goog.requireType('Blockly.blockRendering.ConstantProvider'); -goog.requireType('Blockly.geras.HighlightConstantProvider'); -goog.requireType('Blockly.geras.Renderer'); -goog.requireType('Blockly.geras.RenderInfo'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const HighlightConstantProvider = goog.requireType('Blockly.geras.HighlightConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Renderer = goog.requireType('Blockly.geras.Renderer'); +/* eslint-disable-next-line no-unused-vars */ +const RenderInfo = goog.requireType('Blockly.geras.RenderInfo'); +const Types = goog.require('Blockly.blockRendering.Types'); +const svgPaths = goog.require('Blockly.utils.svgPaths'); /** @@ -33,28 +37,28 @@ goog.requireType('Blockly.geras.RenderInfo'); * or closed paths. The highlights for tabs and notches are loosely based on * tab and notch shapes, but are not exactly the same. * - * @param {!Blockly.geras.RenderInfo} info An object containing all + * @param {!RenderInfo} info An object containing all * information needed to render this block. * @package * @constructor */ -Blockly.geras.Highlighter = function(info) { +const Highlighter = function(info) { this.info_ = info; this.steps_ = ''; this.inlineSteps_ = ''; this.RTL_ = this.info_.RTL; - var renderer = /** @type {!Blockly.geras.Renderer} */ (info.getRenderer()); + const renderer = /** @type {!Renderer} */ (info.getRenderer()); /** * The renderer's constant provider. - * @type {!Blockly.blockRendering.ConstantProvider} + * @type {!ConstantProvider} */ this.constants_ = renderer.getConstants(); /** - * @type {!Blockly.geras.HighlightConstantProvider} + * @type {!HighlightConstantProvider} */ this.highlightConstants_ = renderer.getHighlightConstants(); /** @@ -69,8 +73,7 @@ Blockly.geras.Highlighter = function(info) { this.puzzleTabPaths_ = this.highlightConstants_.PUZZLE_TAB; this.notchPaths_ = this.highlightConstants_.NOTCH; this.startPaths_ = this.highlightConstants_.START_HAT; - this.jaggedTeethPaths_ = - this.highlightConstants_.JAGGED_TEETH; + this.jaggedTeethPaths_ = this.highlightConstants_.JAGGED_TEETH; }; /** @@ -78,177 +81,175 @@ Blockly.geras.Highlighter = function(info) { * @return {string} The steps for the highlight path. * @package */ -Blockly.geras.Highlighter.prototype.getPath = function() { +Highlighter.prototype.getPath = function() { return this.steps_ + '\n' + this.inlineSteps_; }; -Blockly.geras.Highlighter.prototype.drawTopCorner = function(row) { - this.steps_ += Blockly.utils.svgPaths.moveBy(row.xPos, this.info_.startY); - for (var i = 0, elem; (elem = row.elements[i]); i++) { - if (Blockly.blockRendering.Types.isLeftSquareCorner(elem)) { +Highlighter.prototype.drawTopCorner = function(row) { + this.steps_ += svgPaths.moveBy(row.xPos, this.info_.startY); + for (let i = 0, elem; (elem = row.elements[i]); i++) { + if (Types.isLeftSquareCorner(elem)) { this.steps_ += this.highlightConstants_.START_POINT; - } else if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) { + } else if (Types.isLeftRoundedCorner(elem)) { this.steps_ += this.outsideCornerPaths_.topLeft(this.RTL_); - } else if (Blockly.blockRendering.Types.isPreviousConnection(elem)) { + } else if (Types.isPreviousConnection(elem)) { this.steps_ += this.notchPaths_.pathLeft; - } else if (Blockly.blockRendering.Types.isHat(elem)) { + } else if (Types.isHat(elem)) { this.steps_ += this.startPaths_.path(this.RTL_); - } else if (Blockly.blockRendering.Types.isSpacer(elem) && elem.width != 0) { + } else if (Types.isSpacer(elem) && elem.width != 0) { // The end point of the spacer needs to be offset by the highlight amount. // So instead of using the spacer's width for a relative horizontal, use // its width and position for an absolute horizontal move. - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('H', - elem.xPos + elem.width - this.highlightOffset_); + this.steps_ += svgPaths.lineOnAxis( + 'H', elem.xPos + elem.width - this.highlightOffset_); } } - var right = row.xPos + row.width - this.highlightOffset_; - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('H', right); + const right = row.xPos + row.width - this.highlightOffset_; + this.steps_ += svgPaths.lineOnAxis('H', right); }; -Blockly.geras.Highlighter.prototype.drawJaggedEdge_ = function(row) { +Highlighter.prototype.drawJaggedEdge_ = function(row) { if (this.info_.RTL) { - var remainder = + const remainder = row.height - this.jaggedTeethPaths_.height - this.highlightOffset_; - this.steps_ += this.jaggedTeethPaths_.pathLeft + - Blockly.utils.svgPaths.lineOnAxis('v', remainder); + this.steps_ += + this.jaggedTeethPaths_.pathLeft + svgPaths.lineOnAxis('v', remainder); } }; -Blockly.geras.Highlighter.prototype.drawValueInput = function(row) { - var input = row.getLastInput(); +Highlighter.prototype.drawValueInput = function(row) { + const input = row.getLastInput(); if (this.RTL_) { - var belowTabHeight = row.height - input.connectionHeight; + const belowTabHeight = row.height - input.connectionHeight; this.steps_ += - Blockly.utils.svgPaths.moveTo( + svgPaths.moveTo( input.xPos + input.width - this.highlightOffset_, row.yPos) + this.puzzleTabPaths_.pathDown(this.RTL_) + - Blockly.utils.svgPaths.lineOnAxis('v', belowTabHeight); + svgPaths.lineOnAxis('v', belowTabHeight); } else { - this.steps_ += - Blockly.utils.svgPaths.moveTo(input.xPos + input.width, row.yPos) + + this.steps_ += svgPaths.moveTo(input.xPos + input.width, row.yPos) + this.puzzleTabPaths_.pathDown(this.RTL_); } }; -Blockly.geras.Highlighter.prototype.drawStatementInput = function(row) { - var input = row.getLastInput(); +Highlighter.prototype.drawStatementInput = function(row) { + const input = row.getLastInput(); if (this.RTL_) { - var innerHeight = row.height - (2 * this.insideCornerPaths_.height); - this.steps_ += - Blockly.utils.svgPaths.moveTo(input.xPos, row.yPos) + + const innerHeight = row.height - (2 * this.insideCornerPaths_.height); + this.steps_ += svgPaths.moveTo(input.xPos, row.yPos) + this.insideCornerPaths_.pathTop(this.RTL_) + - Blockly.utils.svgPaths.lineOnAxis('v', innerHeight) + + svgPaths.lineOnAxis('v', innerHeight) + this.insideCornerPaths_.pathBottom(this.RTL_) + - Blockly.utils.svgPaths.lineTo( + svgPaths.lineTo( row.width - input.xPos - this.insideCornerPaths_.width, 0); } else { - this.steps_ += - Blockly.utils.svgPaths.moveTo(input.xPos, row.yPos + row.height) + + this.steps_ += svgPaths.moveTo(input.xPos, row.yPos + row.height) + this.insideCornerPaths_.pathBottom(this.RTL_) + - Blockly.utils.svgPaths.lineTo( + svgPaths.lineTo( row.width - input.xPos - this.insideCornerPaths_.width, 0); } }; -Blockly.geras.Highlighter.prototype.drawRightSideRow = function(row) { - var rightEdge = row.xPos + row.width - this.highlightOffset_; +Highlighter.prototype.drawRightSideRow = function(row) { + const rightEdge = row.xPos + row.width - this.highlightOffset_; if (row.followsStatement) { - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('H', rightEdge); + this.steps_ += svgPaths.lineOnAxis('H', rightEdge); } if (this.RTL_) { - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('H', rightEdge); + this.steps_ += svgPaths.lineOnAxis('H', rightEdge); if (row.height > this.highlightOffset_) { - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('V', - row.yPos + row.height - this.highlightOffset_); + this.steps_ += svgPaths.lineOnAxis( + 'V', row.yPos + row.height - this.highlightOffset_); } } }; -Blockly.geras.Highlighter.prototype.drawBottomRow = function(row) { +Highlighter.prototype.drawBottomRow = function(row) { // Highlight the vertical edge of the bottom row on the input side. // Highlighting is always from the top left, both in LTR and RTL. if (this.RTL_) { this.steps_ += - Blockly.utils.svgPaths.lineOnAxis('V', row.baseline - this.highlightOffset_); + svgPaths.lineOnAxis('V', row.baseline - this.highlightOffset_); } else { - var cornerElem = this.info_.bottomRow.elements[0]; - if (Blockly.blockRendering.Types.isLeftSquareCorner(cornerElem)) { - this.steps_ += Blockly.utils.svgPaths.moveTo( + const cornerElem = this.info_.bottomRow.elements[0]; + if (Types.isLeftSquareCorner(cornerElem)) { + this.steps_ += svgPaths.moveTo( row.xPos + this.highlightOffset_, row.baseline - this.highlightOffset_); - } else if (Blockly.blockRendering.Types.isLeftRoundedCorner(cornerElem)) { - this.steps_ += Blockly.utils.svgPaths.moveTo(row.xPos, row.baseline); + } else if (Types.isLeftRoundedCorner(cornerElem)) { + this.steps_ += svgPaths.moveTo(row.xPos, row.baseline); this.steps_ += this.outsideCornerPaths_.bottomLeft(); } } }; -Blockly.geras.Highlighter.prototype.drawLeft = function() { - var outputConnection = this.info_.outputConnection; +Highlighter.prototype.drawLeft = function() { + const outputConnection = this.info_.outputConnection; if (outputConnection) { - var tabBottom = + const tabBottom = outputConnection.connectionOffsetY + outputConnection.height; // Draw a line up to the bottom of the tab. if (this.RTL_) { - this.steps_ += Blockly.utils.svgPaths.moveTo(this.info_.startX, tabBottom); + this.steps_ += svgPaths.moveTo(this.info_.startX, tabBottom); } else { - var left = this.info_.startX + this.highlightOffset_; - var bottom = this.info_.bottomRow.baseline - this.highlightOffset_; - this.steps_ += Blockly.utils.svgPaths.moveTo(left, bottom); - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('V', tabBottom); + const left = this.info_.startX + this.highlightOffset_; + const bottom = this.info_.bottomRow.baseline - this.highlightOffset_; + this.steps_ += svgPaths.moveTo(left, bottom); + this.steps_ += svgPaths.lineOnAxis('V', tabBottom); } this.steps_ += this.puzzleTabPaths_.pathUp(this.RTL_); } if (!this.RTL_) { - var topRow = this.info_.topRow; - if (Blockly.blockRendering.Types.isLeftRoundedCorner(topRow.elements[0])) { - this.steps_ += Blockly.utils.svgPaths.lineOnAxis('V', this.outsideCornerPaths_.height); + const topRow = this.info_.topRow; + if (Types.isLeftRoundedCorner(topRow.elements[0])) { + this.steps_ += svgPaths.lineOnAxis('V', this.outsideCornerPaths_.height); } else { this.steps_ += - Blockly.utils.svgPaths.lineOnAxis('V', topRow.capline + this.highlightOffset_); + svgPaths.lineOnAxis('V', topRow.capline + this.highlightOffset_); } } }; -Blockly.geras.Highlighter.prototype.drawInlineInput = function(input) { - var offset = this.highlightOffset_; +Highlighter.prototype.drawInlineInput = function(input) { + const offset = this.highlightOffset_; // Relative to the block's left. - var connectionRight = input.xPos + input.connectionWidth; - var yPos = input.centerline - input.height / 2; - var bottomHighlightWidth = input.width - input.connectionWidth; - var startY = yPos + offset; + const connectionRight = input.xPos + input.connectionWidth; + const yPos = input.centerline - input.height / 2; + const bottomHighlightWidth = input.width - input.connectionWidth; + const startY = yPos + offset; if (this.RTL_) { - var aboveTabHeight = input.connectionOffsetY - offset; - var belowTabHeight = input.height - + const aboveTabHeight = input.connectionOffsetY - offset; + const belowTabHeight = input.height - (input.connectionOffsetY + input.connectionHeight) + offset; - var startX = connectionRight - offset; + const startX = connectionRight - offset; - this.inlineSteps_ += Blockly.utils.svgPaths.moveTo(startX, startY) + + this.inlineSteps_ += svgPaths.moveTo(startX, startY) + // Right edge above tab. - Blockly.utils.svgPaths.lineOnAxis('v', aboveTabHeight) + + svgPaths.lineOnAxis('v', aboveTabHeight) + // Back of tab. this.puzzleTabPaths_.pathDown(this.RTL_) + // Right edge below tab. - Blockly.utils.svgPaths.lineOnAxis('v', belowTabHeight) + + svgPaths.lineOnAxis('v', belowTabHeight) + // Bottom. - Blockly.utils.svgPaths.lineOnAxis('h', bottomHighlightWidth); + svgPaths.lineOnAxis('h', bottomHighlightWidth); } else { - this.inlineSteps_ += // Go to top right corner. - Blockly.utils.svgPaths.moveTo(input.xPos + input.width + offset, startY) + + svgPaths.moveTo(input.xPos + input.width + offset, startY) + // Highlight right edge, bottom. - Blockly.utils.svgPaths.lineOnAxis('v', input.height) + - Blockly.utils.svgPaths.lineOnAxis('h', -bottomHighlightWidth) + + svgPaths.lineOnAxis('v', input.height) + + svgPaths.lineOnAxis('h', -bottomHighlightWidth) + // Go to top of tab. - Blockly.utils.svgPaths.moveTo(connectionRight, yPos + input.connectionOffsetY) + + svgPaths.moveTo(connectionRight, yPos + input.connectionOffsetY) + // Short highlight glint at bottom of tab. this.puzzleTabPaths_.pathDown(this.RTL_); } }; + +exports = Highlighter; diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 121e3b353..582aab2da 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -11,22 +11,25 @@ */ 'use strict'; -goog.provide('Blockly.geras'); -goog.provide('Blockly.geras.RenderInfo'); +goog.module('Blockly.geras.RenderInfo'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.ExternalValueInput'); -goog.require('Blockly.blockRendering.InputRow'); -goog.require('Blockly.blockRendering.InRowSpacer'); -goog.require('Blockly.blockRendering.RenderInfo'); -goog.require('Blockly.blockRendering.Types'); -goog.require('Blockly.geras.InlineInput'); -goog.require('Blockly.geras.StatementInput'); -goog.require('Blockly.inputTypes'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.blockRendering.Field'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.geras.Renderer'); +const BaseRenderInfo = goog.require('Blockly.blockRendering.RenderInfo'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const ExternalValueInput = goog.require('Blockly.blockRendering.ExternalValueInput'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.blockRendering.Field'); +const InlineInput = goog.require('Blockly.geras.InlineInput'); +/* eslint-disable-next-line no-unused-vars */ +const InputRow = goog.requireType('Blockly.blockRendering.InputRow'); +const InRowSpacer = goog.require('Blockly.blockRendering.InRowSpacer'); +/* eslint-disable-next-line no-unused-vars */ +const Renderer = goog.requireType('Blockly.geras.Renderer'); +const StatementInput = goog.require('Blockly.geras.StatementInput'); +const Types = goog.require('Blockly.blockRendering.Types'); +const inputTypes = goog.require('Blockly.inputTypes'); +const object = goog.require('Blockly.utils.object'); /** @@ -36,36 +39,35 @@ goog.requireType('Blockly.geras.Renderer'); * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. * - * @param {!Blockly.geras.Renderer} renderer The renderer in use. - * @param {!Blockly.BlockSvg} block The block to measure. + * @param {!Renderer} renderer The renderer in use. + * @param {!BlockSvg} block The block to measure. * @constructor * @package - * @extends {Blockly.blockRendering.RenderInfo} + * @extends {BaseRenderInfo} */ -Blockly.geras.RenderInfo = function(renderer, block) { - Blockly.geras.RenderInfo.superClass_.constructor.call(this, renderer, block); +const RenderInfo = function(renderer, block) { + RenderInfo.superClass_.constructor.call(this, renderer, block); }; -Blockly.utils.object.inherits(Blockly.geras.RenderInfo, - Blockly.blockRendering.RenderInfo); +object.inherits(RenderInfo, BaseRenderInfo); /** * Get the block renderer in use. - * @return {!Blockly.geras.Renderer} The block renderer in use. + * @return {!Renderer} The block renderer in use. * @package */ -Blockly.geras.RenderInfo.prototype.getRenderer = function() { - return /** @type {!Blockly.geras.Renderer} */ (this.renderer_); +RenderInfo.prototype.getRenderer = function() { + return /** @type {!Renderer} */ (this.renderer_); }; /** * @override */ -Blockly.geras.RenderInfo.prototype.populateBottomRow_ = function() { - Blockly.geras.RenderInfo.superClass_.populateBottomRow_.call(this); +RenderInfo.prototype.populateBottomRow_ = function() { + RenderInfo.superClass_.populateBottomRow_.call(this); - var followsStatement = this.block_.inputList.length && + const followsStatement = this.block_.inputList.length && this.block_.inputList[this.block_.inputList.length - 1].type == - Blockly.inputTypes.STATEMENT; + inputTypes.STATEMENT; // The minimum height of the bottom row is smaller in Geras than in other // renderers, because the dark path adds a pixel. @@ -75,31 +77,27 @@ Blockly.geras.RenderInfo.prototype.populateBottomRow_ = function() { this.bottomRow.minHeight = this.constants_.MEDIUM_PADDING - this.constants_.DARK_PATH_OFFSET; } - }; /** * @override */ -Blockly.geras.RenderInfo.prototype.addInput_ = function(input, activeRow) { +RenderInfo.prototype.addInput_ = function(input, activeRow) { // Non-dummy inputs have visual representations onscreen. - if (this.isInline && input.type == Blockly.inputTypes.VALUE) { - activeRow.elements.push( - new Blockly.geras.InlineInput(this.constants_, input)); + if (this.isInline && input.type == inputTypes.VALUE) { + activeRow.elements.push(new InlineInput(this.constants_, input)); activeRow.hasInlineInput = true; - } else if (input.type == Blockly.inputTypes.STATEMENT) { - activeRow.elements.push( - new Blockly.geras.StatementInput(this.constants_, input)); + } else if (input.type == inputTypes.STATEMENT) { + activeRow.elements.push(new StatementInput(this.constants_, input)); activeRow.hasStatement = true; - } else if (input.type == Blockly.inputTypes.VALUE) { - activeRow.elements.push( - new Blockly.blockRendering.ExternalValueInput(this.constants_, input)); + } else if (input.type == inputTypes.VALUE) { + activeRow.elements.push(new ExternalValueInput(this.constants_, input)); activeRow.hasExternalInput = true; - } else if (input.type == Blockly.inputTypes.DUMMY) { + } else if (input.type == inputTypes.DUMMY) { // Dummy inputs have no visual representation, but the information is still // important. - activeRow.minHeight = Math.max(activeRow.minHeight, - this.constants_.DUMMY_INPUT_MIN_HEIGHT); + activeRow.minHeight = + Math.max(activeRow.minHeight, this.constants_.DUMMY_INPUT_MIN_HEIGHT); activeRow.hasDummyInput = true; } // Ignore row alignment if inline. @@ -111,40 +109,38 @@ Blockly.geras.RenderInfo.prototype.addInput_ = function(input, activeRow) { /** * @override */ -Blockly.geras.RenderInfo.prototype.addElemSpacing_ = function() { - var hasExternalInputs = false; - for (var i = 0, row; (row = this.rows[i]); i++) { +RenderInfo.prototype.addElemSpacing_ = function() { + let hasExternalInputs = false; + for (let i = 0, row; (row = this.rows[i]); i++) { if (row.hasExternalInput) { hasExternalInputs = true; } } - for (var i = 0, row; (row = this.rows[i]); i++) { - var oldElems = row.elements; + for (let i = 0, row; (row = this.rows[i]); i++) { + const oldElems = row.elements; row.elements = []; // No spacing needed before the corner on the top row or the bottom row. if (row.startsWithElemSpacer()) { // There's a spacer before the first element in the row. - row.elements.push(new Blockly.blockRendering.InRowSpacer( + row.elements.push(new InRowSpacer( this.constants_, this.getInRowSpacing_(null, oldElems[0]))); } if (!oldElems.length) { continue; } - for (var e = 0; e < oldElems.length - 1; e++) { + for (let e = 0; e < oldElems.length - 1; e++) { row.elements.push(oldElems[e]); - var spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]); - row.elements.push( - new Blockly.blockRendering.InRowSpacer(this.constants_, spacing)); + const spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]); + row.elements.push(new InRowSpacer(this.constants_, spacing)); } row.elements.push(oldElems[oldElems.length - 1]); if (row.endsWithElemSpacer()) { - var spacing = this.getInRowSpacing_(oldElems[oldElems.length - 1], null); + let spacing = this.getInRowSpacing_(oldElems[oldElems.length - 1], null); if (hasExternalInputs && row.hasDummyInput) { spacing += this.constants_.TAB_WIDTH; } // There's a spacer after the last element in the row. - row.elements.push(new Blockly.blockRendering.InRowSpacer( - this.constants_, spacing)); + row.elements.push(new InRowSpacer(this.constants_, spacing)); } } }; @@ -152,18 +148,18 @@ Blockly.geras.RenderInfo.prototype.addElemSpacing_ = function() { /** * @override */ -Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { +RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { if (!prev) { // Between an editable field and the beginning of the row. - if (next && Blockly.blockRendering.Types.isField(next) && - (/** @type {Blockly.blockRendering.Field} */ (next)).isEditable) { + if (next && Types.isField(next) && + (/** @type {Field} */ (next)).isEditable) { return this.constants_.MEDIUM_PADDING; } // Inline input at the beginning of the row. - if (next && Blockly.blockRendering.Types.isInlineInput(next)) { + if (next && Types.isInlineInput(next)) { return this.constants_.MEDIUM_LARGE_PADDING; } - if (next && Blockly.blockRendering.Types.isStatementInput(next)) { + if (next && Types.isStatementInput(next)) { return this.constants_.STATEMENT_INPUT_PADDING_LEFT; } // Anything else at the beginning of the row. @@ -171,30 +167,28 @@ Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { } // Spacing between a non-input and the end of the row or a statement input. - if (!Blockly.blockRendering.Types.isInput(prev) && (!next || - Blockly.blockRendering.Types.isStatementInput(next))) { + if (!Types.isInput(prev) && (!next || Types.isStatementInput(next))) { // Between an editable field and the end of the row. - if (Blockly.blockRendering.Types.isField(prev) && - (/** @type {Blockly.blockRendering.Field} */ (prev)).isEditable) { + if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) { return this.constants_.MEDIUM_PADDING; } // Padding at the end of an icon-only row to make the block shape clearer. - if (Blockly.blockRendering.Types.isIcon(prev)) { + if (Types.isIcon(prev)) { return (this.constants_.LARGE_PADDING * 2) + 1; } - if (Blockly.blockRendering.Types.isHat(prev)) { + if (Types.isHat(prev)) { return this.constants_.NO_PADDING; } // Establish a minimum width for a block with a previous or next connection. - if (Blockly.blockRendering.Types.isPreviousOrNextConnection(prev)) { + if (Types.isPreviousOrNextConnection(prev)) { return this.constants_.LARGE_PADDING; } // Between rounded corner and the end of the row. - if (Blockly.blockRendering.Types.isLeftRoundedCorner(prev)) { + if (Types.isLeftRoundedCorner(prev)) { return this.constants_.MIN_BLOCK_WIDTH; } // Between a jagged edge and the end of the row. - if (Blockly.blockRendering.Types.isJaggedEdge(prev)) { + if (Types.isJaggedEdge(prev)) { return this.constants_.NO_PADDING; } // Between noneditable fields and icons and the end of the row. @@ -202,33 +196,31 @@ Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { } // Between inputs and the end of the row. - if (Blockly.blockRendering.Types.isInput(prev) && !next) { - if (Blockly.blockRendering.Types.isExternalInput(prev)) { + if (Types.isInput(prev) && !next) { + if (Types.isExternalInput(prev)) { return this.constants_.NO_PADDING; - } else if (Blockly.blockRendering.Types.isInlineInput(prev)) { + } else if (Types.isInlineInput(prev)) { return this.constants_.LARGE_PADDING; - } else if (Blockly.blockRendering.Types.isStatementInput(prev)) { + } else if (Types.isStatementInput(prev)) { return this.constants_.NO_PADDING; } } // Spacing between a non-input and an input. - if (!Blockly.blockRendering.Types.isInput(prev) && - next && Blockly.blockRendering.Types.isInput(next)) { + if (!Types.isInput(prev) && next && Types.isInput(next)) { // Between an editable field and an input. - if (Blockly.blockRendering.Types.isField(prev) && - (/** @type {Blockly.blockRendering.Field} */ (prev)).isEditable) { - if (Blockly.blockRendering.Types.isInlineInput(next)) { + if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) { + if (Types.isInlineInput(next)) { return this.constants_.SMALL_PADDING; - } else if (Blockly.blockRendering.Types.isExternalInput(next)) { + } else if (Types.isExternalInput(next)) { return this.constants_.SMALL_PADDING; } } else { - if (Blockly.blockRendering.Types.isInlineInput(next)) { + if (Types.isInlineInput(next)) { return this.constants_.MEDIUM_LARGE_PADDING; - } else if (Blockly.blockRendering.Types.isExternalInput(next)) { + } else if (Types.isExternalInput(next)) { return this.constants_.MEDIUM_LARGE_PADDING; - } else if (Blockly.blockRendering.Types.isStatementInput(next)) { + } else if (Types.isStatementInput(next)) { return this.constants_.LARGE_PADDING; } } @@ -236,16 +228,14 @@ Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { } // Spacing between an icon and an icon or field. - if (Blockly.blockRendering.Types.isIcon(prev) && - next && !Blockly.blockRendering.Types.isInput(next)) { + if (Types.isIcon(prev) && next && !Types.isInput(next)) { return this.constants_.LARGE_PADDING; } // Spacing between an inline input and a field. - if (Blockly.blockRendering.Types.isInlineInput(prev) && - next && Blockly.blockRendering.Types.isField(next)) { + if (Types.isInlineInput(prev) && next && Types.isField(next)) { // Editable field after inline input. - if ((/** @type {Blockly.blockRendering.Field} */ (next)).isEditable) { + if ((/** @type {Field} */ (next)).isEditable) { return this.constants_.MEDIUM_PADDING; } else { // Noneditable field after inline input. @@ -253,46 +243,43 @@ Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { } } - if (Blockly.blockRendering.Types.isLeftSquareCorner(prev) && next) { + if (Types.isLeftSquareCorner(prev) && next) { // Spacing between a hat and a corner - if (Blockly.blockRendering.Types.isHat(next)) { + if (Types.isHat(next)) { return this.constants_.NO_PADDING; } // Spacing between a square corner and a previous or next connection - if (Blockly.blockRendering.Types.isPreviousConnection(next)) { + if (Types.isPreviousConnection(next)) { return next.notchOffset; - } else if (Blockly.blockRendering.Types.isNextConnection(next)) { + } else if (Types.isNextConnection(next)) { // Next connections are shifted slightly to the left (in both LTR and RTL) // to make the dark path under the previous connection show through. - var offset = (this.RTL ? 1 : -1) * - this.constants_.DARK_PATH_OFFSET / 2; + const offset = (this.RTL ? 1 : -1) * this.constants_.DARK_PATH_OFFSET / 2; return next.notchOffset + offset; } } // Spacing between a rounded corner and a previous or next connection. - if (Blockly.blockRendering.Types.isLeftRoundedCorner(prev) && next) { - if (Blockly.blockRendering.Types.isPreviousConnection(next)) { + if (Types.isLeftRoundedCorner(prev) && next) { + if (Types.isPreviousConnection(next)) { return next.notchOffset - this.constants_.CORNER_RADIUS; - } else if (Blockly.blockRendering.Types.isNextConnection(next)) { + } else if (Types.isNextConnection(next)) { // Next connections are shifted slightly to the left (in both LTR and RTL) // to make the dark path under the previous connection show through. - var offset = (this.RTL ? 1 : -1) * - this.constants_.DARK_PATH_OFFSET / 2; + const offset = (this.RTL ? 1 : -1) * this.constants_.DARK_PATH_OFFSET / 2; return next.notchOffset - this.constants_.CORNER_RADIUS + offset; } } // Spacing between two fields of the same editability. - if (Blockly.blockRendering.Types.isField(prev) && - next && Blockly.blockRendering.Types.isField(next) && - ((/** @type {Blockly.blockRendering.Field} */ (prev)).isEditable == - (/** @type {Blockly.blockRendering.Field} */ (next)).isEditable)) { + if (Types.isField(prev) && next && Types.isField(next) && + ((/** @type {Field} */ (prev)).isEditable == + (/** @type {Field} */ (next)).isEditable)) { return this.constants_.LARGE_PADDING; } // Spacing between anything and a jagged edge. - if (next && Blockly.blockRendering.Types.isJaggedEdge(next)) { + if (next && Types.isJaggedEdge(next)) { return this.constants_.LARGE_PADDING; } @@ -302,15 +289,13 @@ Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { /** * @override */ -Blockly.geras.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { +RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { // If we have an empty block add a spacer to increase the height. - if (Blockly.blockRendering.Types.isTopRow(prev) && - Blockly.blockRendering.Types.isBottomRow(next)) { + if (Types.isTopRow(prev) && Types.isBottomRow(next)) { return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT; } // Top and bottom rows act as a spacer so we don't need any extra padding. - if (Blockly.blockRendering.Types.isTopRow(prev) || - Blockly.blockRendering.Types.isBottomRow(next)) { + if (Types.isTopRow(prev) || Types.isBottomRow(next)) { return this.constants_.NO_PADDING; } if (prev.hasExternalInput && next.hasExternalInput) { @@ -334,33 +319,32 @@ Blockly.geras.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { /** * @override */ -Blockly.geras.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { - if (Blockly.blockRendering.Types.isSpacer(elem)) { +RenderInfo.prototype.getElemCenterline_ = function(row, elem) { + if (Types.isSpacer(elem)) { return row.yPos + elem.height / 2; } - if (Blockly.blockRendering.Types.isBottomRow(row)) { - var baseline = row.yPos + row.height - row.descenderHeight; - if (Blockly.blockRendering.Types.isNextConnection(elem)) { + if (Types.isBottomRow(row)) { + const baseline = row.yPos + row.height - row.descenderHeight; + if (Types.isNextConnection(elem)) { return baseline + elem.height / 2; } return baseline - elem.height / 2; } - if (Blockly.blockRendering.Types.isTopRow(row)) { - if (Blockly.blockRendering.Types.isHat(elem)) { + if (Types.isTopRow(row)) { + if (Types.isHat(elem)) { return row.capline - elem.height / 2; } return row.capline + elem.height / 2; } - var result = row.yPos; - if (Blockly.blockRendering.Types.isField(elem) || - Blockly.blockRendering.Types.isIcon(elem)) { + let result = row.yPos; + if (Types.isField(elem) || Types.isIcon(elem)) { result += (elem.height / 2); if ((row.hasInlineInput || row.hasStatement) && elem.height + this.constants_.TALL_INPUT_FIELD_OFFSET_Y <= row.height) { result += this.constants_.TALL_INPUT_FIELD_OFFSET_Y; } - } else if (Blockly.blockRendering.Types.isInlineInput(elem)) { + } else if (Types.isInlineInput(elem)) { result += elem.height / 2; } else { result += (row.height / 2); @@ -371,22 +355,22 @@ Blockly.geras.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { /** * @override */ -Blockly.geras.RenderInfo.prototype.alignRowElements_ = function() { +RenderInfo.prototype.alignRowElements_ = function() { if (!this.isInline) { - Blockly.geras.RenderInfo.superClass_.alignRowElements_.call(this); + RenderInfo.superClass_.alignRowElements_.call(this); return; } // Walk backgrounds through rows on the block, keeping track of the right // input edge. - var nextRightEdge = 0; - var prevInput = null; - for (var i = this.rows.length - 1, row; (row = this.rows[i]); i--) { + let nextRightEdge = 0; + let prevInput = null; + for (let i = this.rows.length - 1, row; (row = this.rows[i]); i--) { row.nextRightEdge = nextRightEdge; - if (Blockly.blockRendering.Types.isInputRow(row)) { + if (Types.isInputRow(row)) { if (row.hasStatement) { this.alignStatementRow_( - /** @type {!Blockly.blockRendering.InputRow} */ (row)); + /** @type {!InputRow} */ (row)); } if (prevInput && prevInput.hasStatement && row.width < prevInput.width) { row.nextRightEdge = prevInput.width; @@ -398,17 +382,17 @@ Blockly.geras.RenderInfo.prototype.alignRowElements_ = function() { } // Walk down each row from the top, comparing the prev and next right input // edges and setting the desired width to the max of the two. - var prevRightEdge = 0; - for (var i = 0, row; (row = this.rows[i]); i++) { + let prevRightEdge = 0; + for (let i = 0, row; (row = this.rows[i]); i++) { if (row.hasStatement) { prevRightEdge = this.getDesiredRowWidth_(row); - } else if (Blockly.blockRendering.Types.isSpacer(row)) { + } else if (Types.isSpacer(row)) { // Set the spacer row to the max of the prev or next input width. row.width = Math.max(prevRightEdge, row.nextRightEdge); } else { - var currentWidth = row.width; - var desiredWidth = Math.max(prevRightEdge, row.nextRightEdge); - var missingSpace = desiredWidth - currentWidth; + const currentWidth = row.width; + const desiredWidth = Math.max(prevRightEdge, row.nextRightEdge); + const missingSpace = desiredWidth - currentWidth; if (missingSpace > 0) { this.addAlignmentPadding_(row, missingSpace); } @@ -420,26 +404,24 @@ Blockly.geras.RenderInfo.prototype.alignRowElements_ = function() { /** * @override */ -Blockly.geras.RenderInfo.prototype.getDesiredRowWidth_ = function( - row) { +RenderInfo.prototype.getDesiredRowWidth_ = function(row) { // Limit the width of a statement row when a block is inline. if (this.isInline && row.hasStatement) { return this.statementEdge + this.constants_.MAX_BOTTOM_WIDTH + this.startX; } - return Blockly.geras.RenderInfo.superClass_.getDesiredRowWidth_.call(this, - row); + return RenderInfo.superClass_.getDesiredRowWidth_.call(this, row); }; /** * @override */ -Blockly.geras.RenderInfo.prototype.finalize_ = function() { +RenderInfo.prototype.finalize_ = function() { // Performance note: this could be combined with the draw pass, if the time // that this takes is excessive. But it shouldn't be, because it only // accesses and sets properties that already exist on the objects. - var widestRowWithConnectedBlocks = 0; - var yCursor = 0; - for (var i = 0, row; (row = this.rows[i]); i++) { + let widestRowWithConnectedBlocks = 0; + let yCursor = 0; + for (let i = 0, row; (row = this.rows[i]); i++) { row.yPos = yCursor; row.xPos = this.startX; yCursor += row.height; @@ -447,11 +429,11 @@ Blockly.geras.RenderInfo.prototype.finalize_ = function() { widestRowWithConnectedBlocks = Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); // Add padding to the bottom row if block height is less than minimum - var heightWithoutHat = yCursor - this.topRow.ascenderHeight; + const heightWithoutHat = yCursor - this.topRow.ascenderHeight; if (row == this.bottomRow && heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) { // But the hat height shouldn't be part of this. - var diff = this.constants_.MIN_BLOCK_HEIGHT - heightWithoutHat; + const diff = this.constants_.MIN_BLOCK_HEIGHT - heightWithoutHat; this.bottomRow.height += diff; yCursor += diff; } @@ -460,18 +442,20 @@ Blockly.geras.RenderInfo.prototype.finalize_ = function() { if (this.outputConnection && this.block_.nextConnection && this.block_.nextConnection.isConnected()) { // Include width of connected block in value to stack width measurement. - widestRowWithConnectedBlocks = - Math.max(widestRowWithConnectedBlocks, - this.block_.nextConnection.targetBlock().getHeightWidth().width - + widestRowWithConnectedBlocks = Math.max( + widestRowWithConnectedBlocks, + this.block_.nextConnection.targetBlock().getHeightWidth().width - this.constants_.DARK_PATH_OFFSET); } this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight; // The dark (lowlight) adds to the size of the block in both x and y. - this.widthWithChildren = widestRowWithConnectedBlocks + - this.startX + this.constants_.DARK_PATH_OFFSET; + this.widthWithChildren = widestRowWithConnectedBlocks + this.startX + + this.constants_.DARK_PATH_OFFSET; this.width += this.constants_.DARK_PATH_OFFSET; this.height = yCursor + this.constants_.DARK_PATH_OFFSET; this.startY = this.topRow.capline; }; + +exports = RenderInfo; diff --git a/core/renderers/geras/measurables/inline_input.js b/core/renderers/geras/measurables/inline_input.js new file mode 100644 index 000000000..b0e3dd776 --- /dev/null +++ b/core/renderers/geras/measurables/inline_input.js @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Objects representing inline inputs with connections on a + * rendered block. + * @author kozbial@google.com (Monica Kozbial) + */ +'use strict'; + +goog.module('Blockly.geras.InlineInput'); +goog.module.declareLegacyNamespace(); + +const BaseInlineInput = goog.require('Blockly.blockRendering.InlineInput'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const object = goog.require('Blockly.utils.object'); + + +/** + * An object containing information about the space an inline input takes up + * during rendering + * @param {!ConstantProvider} constants The rendering + * constants provider. + * @param {!Input} input The inline input to measure and store + * information for. + * @package + * @constructor + * @extends {BaseInlineInput} + */ +const InlineInput = function(constants, input) { + InlineInput.superClass_.constructor.call(this, constants, input); + + if (this.connectedBlock) { + // We allow the dark path to show on the parent block so that the child + // block looks embossed. This takes up an extra pixel in both x and y. + this.width += this.constants_.DARK_PATH_OFFSET; + this.height += this.constants_.DARK_PATH_OFFSET; + } +}; +object.inherits(InlineInput, BaseInlineInput); + +exports = InlineInput; diff --git a/core/renderers/geras/measurables/inputs.js b/core/renderers/geras/measurables/inputs.js deleted file mode 100644 index 6aca47b77..000000000 --- a/core/renderers/geras/measurables/inputs.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Objects representing inputs with connections on a rendered - * block. - * @author kozbial@google.com (Monica Kozbial) - */ -'use strict'; - -goog.provide('Blockly.geras.InlineInput'); -goog.provide('Blockly.geras.StatementInput'); - -goog.require('Blockly.blockRendering.InlineInput'); -goog.require('Blockly.blockRendering.StatementInput'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.blockRendering.ConstantProvider'); -goog.requireType('Blockly.Input'); - - -/** - * An object containing information about the space an inline input takes up - * during rendering - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering - * constants provider. - * @param {!Blockly.Input} input The inline input to measure and store - * information for. - * @package - * @constructor - * @extends {Blockly.blockRendering.InlineInput} - */ -Blockly.geras.InlineInput = function(constants, input) { - Blockly.geras.InlineInput.superClass_.constructor.call( - this, constants, input); - - if (this.connectedBlock) { - // We allow the dark path to show on the parent block so that the child - // block looks embossed. This takes up an extra pixel in both x and y. - this.width += this.constants_.DARK_PATH_OFFSET; - this.height += this.constants_.DARK_PATH_OFFSET; - } -}; -Blockly.utils.object.inherits(Blockly.geras.InlineInput, - Blockly.blockRendering.InlineInput); - -/** - * An object containing information about the space a statement input takes up - * during rendering - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering - * constants provider. - * @param {!Blockly.Input} input The statement input to measure and store - * information for. - * @package - * @constructor - * @extends {Blockly.blockRendering.StatementInput} - */ -Blockly.geras.StatementInput = function(constants, input) { - Blockly.geras.StatementInput.superClass_.constructor.call( - this, constants, input); - - if (this.connectedBlock) { - // We allow the dark path to show on the parent block so that the child - // block looks embossed. This takes up an extra pixel in both x and y. - this.height += this.constants_.DARK_PATH_OFFSET; - } -}; -Blockly.utils.object.inherits(Blockly.geras.StatementInput, - Blockly.blockRendering.StatementInput); diff --git a/core/renderers/geras/measurables/statement_input.js b/core/renderers/geras/measurables/statement_input.js new file mode 100644 index 000000000..1c49f2b42 --- /dev/null +++ b/core/renderers/geras/measurables/statement_input.js @@ -0,0 +1,47 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Objects representing statement inputs with connections on a + * rendered block. + * @author kozbial@google.com (Monica Kozbial) + */ +'use strict'; + +goog.module('Blockly.geras.StatementInput'); +goog.module.declareLegacyNamespace(); + +const BaseStatementInput = goog.require('Blockly.blockRendering.StatementInput'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const object = goog.require('Blockly.utils.object'); + + +/** + * An object containing information about the space a statement input takes up + * during rendering + * @param {!ConstantProvider} constants The rendering + * constants provider. + * @param {!Input} input The statement input to measure and store + * information for. + * @package + * @constructor + * @extends {BaseStatementInput} + */ +const StatementInput = function(constants, input) { + StatementInput.superClass_.constructor.call(this, constants, input); + + if (this.connectedBlock) { + // We allow the dark path to show on the parent block so that the child + // block looks embossed. This takes up an extra pixel in both x and y. + this.height += this.constants_.DARK_PATH_OFFSET; + } +}; +object.inherits(StatementInput, BaseStatementInput); + +exports = StatementInput; diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 474cad3c0..9d50c672c 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -11,32 +11,35 @@ 'use strict'; -goog.provide('Blockly.geras.PathObject'); +goog.module('Blockly.geras.PathObject'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.PathObject'); -goog.require('Blockly.geras.ConstantProvider'); -goog.require('Blockly.Theme'); -goog.require('Blockly.utils.colour'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Svg'); +const BasePathObject = goog.require('Blockly.blockRendering.PathObject'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.geras.ConstantProvider'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +const colour = goog.require('Blockly.utils.colour'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); /** * An object that handles creating and setting each of the SVG elements * used by the renderer. * @param {!SVGElement} root The root SVG element. - * @param {!Blockly.Theme.BlockStyle} style The style object to use for + * @param {!Theme.BlockStyle} style The style object to use for * colouring. - * @param {!Blockly.geras.ConstantProvider} constants The renderer's constants. + * @param {!ConstantProvider} constants The renderer's constants. * @constructor - * @extends {Blockly.blockRendering.PathObject} + * @extends {BasePathObject} * @package */ -Blockly.geras.PathObject = function(root, style, constants) { +const PathObject = function(root, style, constants) { /** * The renderer's constant provider. - * @type {!Blockly.geras.ConstantProvider} + * @type {!ConstantProvider} */ this.constants = constants; @@ -50,9 +53,8 @@ Blockly.geras.PathObject = function(root, style, constants) { * @type {SVGElement} * @package */ - this.svgPathDark = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, + this.svgPathDark = dom.createSvgElement( + Svg.PATH, {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, this.svgRoot); /** @@ -60,18 +62,16 @@ Blockly.geras.PathObject = function(root, style, constants) { * @type {!SVGElement} * @package */ - this.svgPath = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - {'class': 'blocklyPath'}, this.svgRoot); + this.svgPath = + dom.createSvgElement(Svg.PATH, {'class': 'blocklyPath'}, this.svgRoot); /** * The light path of the block. * @type {SVGElement} * @package */ - this.svgPathLight = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - {'class': 'blocklyPathLight'}, this.svgRoot); + this.svgPathLight = dom.createSvgElement( + Svg.PATH, {'class': 'blocklyPathLight'}, this.svgRoot); /** * The colour of the dark path on the block in '#RRGGBB' format. @@ -82,18 +82,17 @@ Blockly.geras.PathObject = function(root, style, constants) { /** * The style object to use when colouring block paths. - * @type {!Blockly.Theme.BlockStyle} + * @type {!Theme.BlockStyle} * @package */ this.style = style; }; -Blockly.utils.object.inherits(Blockly.geras.PathObject, - Blockly.blockRendering.PathObject); +object.inherits(PathObject, BasePathObject); /** * @override */ -Blockly.geras.PathObject.prototype.setPath = function(mainPath) { +PathObject.prototype.setPath = function(mainPath) { this.svgPath.setAttribute('d', mainPath); this.svgPathDark.setAttribute('d', mainPath); }; @@ -103,14 +102,14 @@ Blockly.geras.PathObject.prototype.setPath = function(mainPath) { * @param {string} highlightPath The highlight path. * @package */ -Blockly.geras.PathObject.prototype.setHighlightPath = function(highlightPath) { +PathObject.prototype.setHighlightPath = function(highlightPath) { this.svgPathLight.setAttribute('d', highlightPath); }; /** * @override */ -Blockly.geras.PathObject.prototype.flipRTL = function() { +PathObject.prototype.flipRTL = function() { // Mirror the block's path. this.svgPath.setAttribute('transform', 'scale(-1 1)'); this.svgPathLight.setAttribute('transform', 'scale(-1 1)'); @@ -120,13 +119,13 @@ Blockly.geras.PathObject.prototype.flipRTL = function() { /** * @override */ -Blockly.geras.PathObject.prototype.applyColour = function(block) { +PathObject.prototype.applyColour = function(block) { this.svgPathLight.style.display = ''; this.svgPathDark.style.display = ''; this.svgPathLight.setAttribute('stroke', this.style.colourTertiary); this.svgPathDark.setAttribute('fill', this.colourDark); - Blockly.geras.PathObject.superClass_.applyColour.call(this, block); + PathObject.superClass_.applyColour.call(this, block); this.svgPath.setAttribute('stroke', 'none'); }; @@ -134,20 +133,19 @@ Blockly.geras.PathObject.prototype.applyColour = function(block) { /** * @override */ -Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) { +PathObject.prototype.setStyle = function(blockStyle) { this.style = blockStyle; this.colourDark = - Blockly.utils.colour.blend('#000', this.style.colourPrimary, 0.2) || - this.colourDark; + colour.blend('#000', this.style.colourPrimary, 0.2) || this.colourDark; }; /** * @override */ -Blockly.geras.PathObject.prototype.updateHighlighted = function(highlighted) { +PathObject.prototype.updateHighlighted = function(highlighted) { if (highlighted) { - this.svgPath.setAttribute('filter', - 'url(#' + this.constants.embossFilterId + ')'); + this.svgPath.setAttribute( + 'filter', 'url(#' + this.constants.embossFilterId + ')'); this.svgPathLight.style.display = 'none'; } else { this.svgPath.setAttribute('filter', 'none'); @@ -158,7 +156,7 @@ Blockly.geras.PathObject.prototype.updateHighlighted = function(highlighted) { /** * @override */ -Blockly.geras.PathObject.prototype.updateShadow_ = function(shadow) { +PathObject.prototype.updateShadow_ = function(shadow) { if (shadow) { this.svgPathLight.style.display = 'none'; this.svgPathDark.setAttribute('fill', this.style.colourSecondary); @@ -170,9 +168,11 @@ Blockly.geras.PathObject.prototype.updateShadow_ = function(shadow) { /** * @override */ -Blockly.geras.PathObject.prototype.updateDisabled_ = function(disabled) { - Blockly.geras.PathObject.superClass_.updateDisabled_.call(this, disabled); +PathObject.prototype.updateDisabled_ = function(disabled) { + PathObject.superClass_.updateDisabled_.call(this, disabled); if (disabled) { this.svgPath.setAttribute('stroke', 'none'); } }; + +exports = PathObject; diff --git a/core/renderers/geras/renderer.js b/core/renderers/geras/renderer.js index 659cb42b6..7c505e8c8 100644 --- a/core/renderers/geras/renderer.js +++ b/core/renderers/geras/renderer.js @@ -10,21 +10,25 @@ */ 'use strict'; -goog.provide('Blockly.geras.Renderer'); +goog.module('Blockly.geras.Renderer'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering'); -goog.require('Blockly.blockRendering.Renderer'); -goog.require('Blockly.geras.ConstantProvider'); -goog.require('Blockly.geras.Drawer'); -goog.require('Blockly.geras.HighlightConstantProvider'); -goog.require('Blockly.geras.PathObject'); -goog.require('Blockly.geras.RenderInfo'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.blockRendering.ConstantProvider'); -goog.requireType('Blockly.blockRendering.RenderInfo'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.Theme'); +const BaseRenderer = goog.require('Blockly.blockRendering.Renderer'); +/* eslint-disable-next-line no-unused-vars */ +const BaseRenderInfo = goog.requireType('Blockly.blockRendering.RenderInfo'); +/* eslint-disable-next-line no-unused-vars */ +const BaseConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const ConstantProvider = goog.require('Blockly.geras.ConstantProvider'); +const Drawer = goog.require('Blockly.geras.Drawer'); +const HighlightConstantProvider = goog.require('Blockly.geras.HighlightConstantProvider'); +const PathObject = goog.require('Blockly.geras.PathObject'); +const RenderInfo = goog.require('Blockly.geras.RenderInfo'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +const blockRendering = goog.require('Blockly.blockRendering'); +const object = goog.require('Blockly.utils.object'); /** @@ -32,20 +36,19 @@ goog.requireType('Blockly.Theme'); * @param {string} name The renderer name. * @package * @constructor - * @extends {Blockly.blockRendering.Renderer} + * @extends {BaseRenderer} */ -Blockly.geras.Renderer = function(name) { - Blockly.geras.Renderer.superClass_.constructor.call(this, name); +const Renderer = function(name) { + Renderer.superClass_.constructor.call(this, name); /** * The renderer's highlight constant provider. - * @type {Blockly.geras.HighlightConstantProvider} + * @type {HighlightConstantProvider} * @private */ this.highlightConstants_ = null; }; -Blockly.utils.object.inherits(Blockly.geras.Renderer, - Blockly.blockRendering.Renderer); +object.inherits(Renderer, BaseRenderer); /** * Initialize the renderer. Geras has a highlight provider in addition to @@ -53,10 +56,8 @@ Blockly.utils.object.inherits(Blockly.geras.Renderer, * @package * @override */ -Blockly.geras.Renderer.prototype.init = function(theme, - opt_rendererOverrides) { - Blockly.geras.Renderer.superClass_.init.call(this, theme, - opt_rendererOverrides); +Renderer.prototype.init = function(theme, opt_rendererOverrides) { + Renderer.superClass_.init.call(this, theme, opt_rendererOverrides); this.highlightConstants_ = this.makeHighlightConstants_(); this.highlightConstants_.init(); }; @@ -64,80 +65,84 @@ Blockly.geras.Renderer.prototype.init = function(theme, /** * @override */ -Blockly.geras.Renderer.prototype.refreshDom = function(svg, theme) { - Blockly.geras.Renderer.superClass_.refreshDom.call(this, svg, theme); +Renderer.prototype.refreshDom = function(svg, theme) { + Renderer.superClass_.refreshDom.call(this, svg, theme); this.getHighlightConstants().init(); }; /** * @override */ -Blockly.geras.Renderer.prototype.makeConstants_ = function() { - return new Blockly.geras.ConstantProvider(); +Renderer.prototype.makeConstants_ = function() { + return new ConstantProvider(); }; /** * Create a new instance of the renderer's render info object. - * @param {!Blockly.BlockSvg} block The block to measure. - * @return {!Blockly.geras.RenderInfo} The render info object. + * @param {!BlockSvg} block The block to measure. + * @return {!RenderInfo} The render info object. * @protected * @override */ -Blockly.geras.Renderer.prototype.makeRenderInfo_ = function(block) { - return new Blockly.geras.RenderInfo(this, block); +Renderer.prototype.makeRenderInfo_ = function(block) { + return new RenderInfo(this, block); }; /** * Create a new instance of the renderer's drawer. - * @param {!Blockly.BlockSvg} block The block to render. - * @param {!Blockly.blockRendering.RenderInfo} info An object containing all + * @param {!BlockSvg} block The block to render. + * @param {!BaseRenderInfo} info An object containing all * information needed to render this block. - * @return {!Blockly.geras.Drawer} The drawer. + * @return {!Drawer} The drawer. * @protected * @override */ -Blockly.geras.Renderer.prototype.makeDrawer_ = function(block, info) { - return new Blockly.geras.Drawer(block, - /** @type {!Blockly.geras.RenderInfo} */ (info)); +Renderer.prototype.makeDrawer_ = function(block, info) { + return new Drawer( + block, + /** @type {!RenderInfo} */ (info)); }; /** * Create a new instance of a renderer path object. * @param {!SVGElement} root The root SVG element. - * @param {!Blockly.Theme.BlockStyle} style The style object to use for + * @param {!Theme.BlockStyle} style The style object to use for * colouring. - * @return {!Blockly.geras.PathObject} The renderer path object. + * @return {!PathObject} The renderer path object. * @package * @override */ -Blockly.geras.Renderer.prototype.makePathObject = function(root, style) { - return new Blockly.geras.PathObject(root, style, - /** @type {!Blockly.geras.ConstantProvider} */ (this.getConstants())); +Renderer.prototype.makePathObject = function(root, style) { + return new PathObject( + root, style, + /** @type {!ConstantProvider} */ (this.getConstants())); }; /** * Create a new instance of the renderer's highlight constant provider. - * @return {!Blockly.geras.HighlightConstantProvider} The highlight constant + * @return {!HighlightConstantProvider} The highlight constant * provider. * @protected */ -Blockly.geras.Renderer.prototype.makeHighlightConstants_ = function() { - return new Blockly.geras.HighlightConstantProvider( - /** @type {!Blockly.blockRendering.ConstantProvider} */ +Renderer.prototype.makeHighlightConstants_ = function() { + return new HighlightConstantProvider( + /** @type {!BaseConstantProvider} */ (this.getConstants())); }; /** * Get the renderer's highlight constant provider. We assume that when this is * called, the renderer has already been initialized. - * @return {!Blockly.geras.HighlightConstantProvider} The highlight constant + * @return {!HighlightConstantProvider} The highlight constant * provider. * @package */ -Blockly.geras.Renderer.prototype.getHighlightConstants = function() { +Renderer.prototype.getHighlightConstants = function() { return ( - /** @type {!Blockly.geras.HighlightConstantProvider} */ - (this.highlightConstants_)); + /** @type {!HighlightConstantProvider} */ + (this.highlightConstants_)); }; -Blockly.blockRendering.register('geras', Blockly.geras.Renderer); +blockRendering.register('geras', Renderer); + +exports = Renderer; diff --git a/core/renderers/measurables/base.js b/core/renderers/measurables/base.js index 22247d9ff..b3a16d061 100644 --- a/core/renderers/measurables/base.js +++ b/core/renderers/measurables/base.js @@ -11,36 +11,39 @@ 'use strict'; -goog.provide('Blockly.blockRendering.Measurable'); +goog.module('Blockly.blockRendering.Measurable'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.Types'); - -goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +const Types = goog.require('Blockly.blockRendering.Types'); /** * The base class to represent a part of a block that takes up space during * rendering. The constructor for each non-spacer Measurable records the size * of the block element (e.g. field, statement input). - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering + * @param {!ConstantProvider} constants The rendering * constants provider. * @package * @constructor */ -Blockly.blockRendering.Measurable = function(constants) { +const Measurable = function(constants) { this.width = 0; this.height = 0; - this.type = Blockly.blockRendering.Types.NONE; + this.type = Types.NONE; this.xPos = 0; this.centerline = 0; /** * The renderer's constant provider. - * @type {!Blockly.blockRendering.ConstantProvider} + * @type {!ConstantProvider} * @protected */ this.constants_ = constants; this.notchOffset = this.constants_.NOTCH_OFFSET_LEFT; }; + +exports = Measurable; diff --git a/core/renderers/measurables/external_value_input.js b/core/renderers/measurables/external_value_input.js new file mode 100644 index 000000000..8835716c4 --- /dev/null +++ b/core/renderers/measurables/external_value_input.js @@ -0,0 +1,53 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class representing external value inputs with connections on a + * rendered block. + * @author fenichel@google.com (Rachel Fenichel) + */ + +goog.module('Blockly.blockRendering.ExternalValueInput'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const InputConnection = goog.require('Blockly.blockRendering.InputConnection'); +const Types = goog.require('Blockly.blockRendering.Types'); +const object = goog.require('Blockly.utils.object'); + + +/** + * An object containing information about the space an external value input + * takes up during rendering + * @param {!ConstantProvider} constants The rendering + * constants provider. + * @param {!Input} input The external value input to measure and store + * information for. + * @package + * @constructor + * @extends {InputConnection} + */ +const ExternalValueInput = function(constants, input) { + ExternalValueInput.superClass_.constructor.call(this, constants, input); + this.type |= Types.EXTERNAL_VALUE_INPUT; + if (!this.connectedBlock) { + this.height = this.shape.height; + } else { + this.height = this.connectedBlockHeight - + this.constants_.TAB_OFFSET_FROM_TOP - this.constants_.MEDIUM_PADDING; + } + this.width = this.shape.width + this.constants_.EXTERNAL_VALUE_INPUT_PADDING; + + this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; + this.connectionHeight = this.shape.height; + this.connectionWidth = this.shape.width; +}; +object.inherits(ExternalValueInput, InputConnection); + +exports = ExternalValueInput; diff --git a/core/renderers/measurables/inline_input.js b/core/renderers/measurables/inline_input.js new file mode 100644 index 000000000..01ac0527d --- /dev/null +++ b/core/renderers/measurables/inline_input.js @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class representing inline inputs with connections on a rendered + * block. + * @author fenichel@google.com (Rachel Fenichel) + */ + +goog.module('Blockly.blockRendering.InlineInput'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const InputConnection = goog.require('Blockly.blockRendering.InputConnection'); +const Types = goog.require('Blockly.blockRendering.Types'); +const object = goog.require('Blockly.utils.object'); + + +/** + * An object containing information about the space an inline input takes up + * during rendering + * @param {!ConstantProvider} constants The rendering + * constants provider. + * @param {!Input} input The inline input to measure and store + * information for. + * @package + * @constructor + * @extends {InputConnection} + */ +const InlineInput = function(constants, input) { + InlineInput.superClass_.constructor.call(this, constants, input); + this.type |= Types.INLINE_INPUT; + + if (!this.connectedBlock) { + this.height = this.constants_.EMPTY_INLINE_INPUT_HEIGHT; + this.width = this.constants_.EMPTY_INLINE_INPUT_PADDING; + } else { + // We allow the dark path to show on the parent block so that the child + // block looks embossed. This takes up an extra pixel in both x and y. + this.width = this.connectedBlockWidth; + this.height = this.connectedBlockHeight; + } + + this.connectionHeight = + !this.isDynamicShape ? this.shape.height : this.shape.height(this.height); + this.connectionWidth = + !this.isDynamicShape ? this.shape.width : this.shape.width(this.height); + if (!this.connectedBlock) { + this.width += this.connectionWidth * (this.isDynamicShape ? 2 : 1); + } + this.connectionOffsetY = this.isDynamicShape ? + this.shape.connectionOffsetY(this.connectionHeight) : + this.constants_.TAB_OFFSET_FROM_TOP; + this.connectionOffsetX = this.isDynamicShape ? + this.shape.connectionOffsetX(this.connectionWidth) : + 0; +}; +object.inherits(InlineInput, InputConnection); + +exports = InlineInput; diff --git a/core/renderers/measurables/input_connection.js b/core/renderers/measurables/input_connection.js new file mode 100644 index 000000000..e6353c643 --- /dev/null +++ b/core/renderers/measurables/input_connection.js @@ -0,0 +1,59 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class representing inputs with connections on a rendered block. + * @author fenichel@google.com (Rachel Fenichel) + */ + +goog.module('Blockly.blockRendering.InputConnection'); +goog.module.declareLegacyNamespace(); + +const Connection = goog.require('Blockly.blockRendering.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const Types = goog.require('Blockly.blockRendering.Types'); +const object = goog.require('Blockly.utils.object'); + + +/** + * The base class to represent an input that takes up space on a block + * during rendering + * @param {!ConstantProvider} constants The rendering + * constants provider. + * @param {!Input} input The input to measure and store information for. + * @package + * @constructor + * @extends {Connection} + */ +const InputConnection = function(constants, input) { + InputConnection.superClass_.constructor.call( + this, constants, input.connection); + + this.type |= Types.INPUT; + this.input = input; + this.align = input.align; + this.connectedBlock = input.connection && input.connection.targetBlock() ? + input.connection.targetBlock() : + null; + + if (this.connectedBlock) { + const bBox = this.connectedBlock.getHeightWidth(); + this.connectedBlockWidth = bBox.width; + this.connectedBlockHeight = bBox.height; + } else { + this.connectedBlockWidth = 0; + this.connectedBlockHeight = 0; + } + + this.connectionOffsetX = 0; + this.connectionOffsetY = 0; +}; +object.inherits(InputConnection, Connection); + +exports = InputConnection; diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js deleted file mode 100644 index 5f845d65b..000000000 --- a/core/renderers/measurables/inputs.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Objects representing inputs with connections on a rendered - * block. - * @author fenichel@google.com (Rachel Fenichel) - */ - -goog.provide('Blockly.blockRendering.ExternalValueInput'); -goog.provide('Blockly.blockRendering.InlineInput'); -goog.provide('Blockly.blockRendering.InputConnection'); -goog.provide('Blockly.blockRendering.StatementInput'); - -goog.require('Blockly.blockRendering.Connection'); -goog.require('Blockly.blockRendering.Types'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.blockRendering.ConstantProvider'); -goog.requireType('Blockly.Input'); - - -/** - * The base class to represent an input that takes up space on a block - * during rendering - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering - * constants provider. - * @param {!Blockly.Input} input The input to measure and store information for. - * @package - * @constructor - * @extends {Blockly.blockRendering.Connection} - */ -Blockly.blockRendering.InputConnection = function(constants, input) { - Blockly.blockRendering.InputConnection.superClass_.constructor.call(this, - constants, input.connection); - - this.type |= Blockly.blockRendering.Types.INPUT; - this.input = input; - this.align = input.align; - this.connectedBlock = input.connection && input.connection.targetBlock() ? - input.connection.targetBlock() : null; - - if (this.connectedBlock) { - var bBox = this.connectedBlock.getHeightWidth(); - this.connectedBlockWidth = bBox.width; - this.connectedBlockHeight = bBox.height; - } else { - this.connectedBlockWidth = 0; - this.connectedBlockHeight = 0; - } - - this.connectionOffsetX = 0; - this.connectionOffsetY = 0; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.InputConnection, - Blockly.blockRendering.Connection); - -/** - * An object containing information about the space an inline input takes up - * during rendering - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering - * constants provider. - * @param {!Blockly.Input} input The inline input to measure and store - * information for. - * @package - * @constructor - * @extends {Blockly.blockRendering.InputConnection} - */ -Blockly.blockRendering.InlineInput = function(constants, input) { - Blockly.blockRendering.InlineInput.superClass_.constructor.call(this, - constants, input); - this.type |= Blockly.blockRendering.Types.INLINE_INPUT; - - if (!this.connectedBlock) { - this.height = this.constants_.EMPTY_INLINE_INPUT_HEIGHT; - this.width = this.constants_.EMPTY_INLINE_INPUT_PADDING; - } else { - // We allow the dark path to show on the parent block so that the child - // block looks embossed. This takes up an extra pixel in both x and y. - this.width = this.connectedBlockWidth; - this.height = this.connectedBlockHeight; - } - - this.connectionHeight = !this.isDynamicShape ? this.shape.height : - this.shape.height(this.height); - this.connectionWidth = !this.isDynamicShape ? this.shape.width : - this.shape.width(this.height); - if (!this.connectedBlock) { - this.width += this.connectionWidth * (this.isDynamicShape ? 2 : 1); - } - this.connectionOffsetY = this.isDynamicShape ? - this.shape.connectionOffsetY(this.connectionHeight) : - this.constants_.TAB_OFFSET_FROM_TOP; - this.connectionOffsetX = this.isDynamicShape ? - this.shape.connectionOffsetX(this.connectionWidth) : 0; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.InlineInput, - Blockly.blockRendering.InputConnection); - -/** - * An object containing information about the space a statement input takes up - * during rendering - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering - * constants provider. - * @param {!Blockly.Input} input The statement input to measure and store - * information for. - * @package - * @constructor - * @extends {Blockly.blockRendering.InputConnection} - */ -Blockly.blockRendering.StatementInput = function(constants, input) { - Blockly.blockRendering.StatementInput.superClass_.constructor.call(this, - constants, input); - this.type |= Blockly.blockRendering.Types.STATEMENT_INPUT; - - if (!this.connectedBlock) { - this.height = this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT; - } else { - // We allow the dark path to show on the parent block so that the child - // block looks embossed. This takes up an extra pixel in both x and y. - this.height = - this.connectedBlockHeight + this.constants_.STATEMENT_BOTTOM_SPACER; - } - this.width = this.constants_.STATEMENT_INPUT_NOTCH_OFFSET + this.shape.width; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.StatementInput, - Blockly.blockRendering.InputConnection); - -/** - * An object containing information about the space an external value input - * takes up during rendering - * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering - * constants provider. - * @param {!Blockly.Input} input The external value input to measure and store - * information for. - * @package - * @constructor - * @extends {Blockly.blockRendering.InputConnection} - */ -Blockly.blockRendering.ExternalValueInput = function(constants, input) { - Blockly.blockRendering.ExternalValueInput.superClass_.constructor.call(this, - constants, input); - this.type |= Blockly.blockRendering.Types.EXTERNAL_VALUE_INPUT; - if (!this.connectedBlock) { - this.height = this.shape.height; - } else { - this.height = - this.connectedBlockHeight - this.constants_.TAB_OFFSET_FROM_TOP - - this.constants_.MEDIUM_PADDING; - } - this.width = this.shape.width + - this.constants_.EXTERNAL_VALUE_INPUT_PADDING; - - this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; - this.connectionHeight = this.shape.height; - this.connectionWidth = this.shape.width; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.ExternalValueInput, - Blockly.blockRendering.InputConnection); diff --git a/core/renderers/measurables/statement_input.js b/core/renderers/measurables/statement_input.js new file mode 100644 index 000000000..6050496d7 --- /dev/null +++ b/core/renderers/measurables/statement_input.js @@ -0,0 +1,52 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Class representing statement inputs with connections on a + * rendered block. + * @author fenichel@google.com (Rachel Fenichel) + */ + +goog.module('Blockly.blockRendering.StatementInput'); +goog.module.declareLegacyNamespace(); + +/* eslint-disable-next-line no-unused-vars */ +const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider'); +/* eslint-disable-next-line no-unused-vars */ +const Input = goog.requireType('Blockly.Input'); +const InputConnection = goog.require('Blockly.blockRendering.InputConnection'); +const Types = goog.require('Blockly.blockRendering.Types'); +const object = goog.require('Blockly.utils.object'); + + +/** + * An object containing information about the space a statement input takes up + * during rendering + * @param {!ConstantProvider} constants The rendering + * constants provider. + * @param {!Input} input The statement input to measure and store + * information for. + * @package + * @constructor + * @extends {InputConnection} + */ +const StatementInput = function(constants, input) { + StatementInput.superClass_.constructor.call(this, constants, input); + this.type |= Types.STATEMENT_INPUT; + + if (!this.connectedBlock) { + this.height = this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT; + } else { + // We allow the dark path to show on the parent block so that the child + // block looks embossed. This takes up an extra pixel in both x and y. + this.height = + this.connectedBlockHeight + this.constants_.STATEMENT_BOTTOM_SPACER; + } + this.width = this.constants_.STATEMENT_INPUT_NOTCH_OFFSET + this.shape.width; +}; +object.inherits(StatementInput, InputConnection); + +exports = StatementInput; diff --git a/core/renderers/measurables/types.js b/core/renderers/measurables/types.js index 19cacceca..655375569 100644 --- a/core/renderers/measurables/types.js +++ b/core/renderers/measurables/types.js @@ -11,42 +11,45 @@ 'use strict'; -goog.provide('Blockly.blockRendering.Types'); +goog.module('Blockly.blockRendering.Types'); +goog.module.declareLegacyNamespace(); -goog.requireType('Blockly.blockRendering.Measurable'); -goog.requireType('Blockly.blockRendering.Row'); +/* eslint-disable-next-line no-unused-vars */ +const Measurable = goog.requireType('Blockly.blockRendering.Measurable'); +/* eslint-disable-next-line no-unused-vars */ +const Row = goog.requireType('Blockly.blockRendering.Row'); /** * Types of rendering elements. * @enum {number} */ -Blockly.blockRendering.Types = { - NONE: 0, // None - FIELD: 1 << 0, // Field. - HAT: 1 << 1, // Hat. - ICON: 1 << 2, // Icon. - SPACER: 1 << 3, // Spacer. - BETWEEN_ROW_SPACER: 1 << 4, // Between Row Spacer. - IN_ROW_SPACER: 1 << 5, // In Row Spacer. - EXTERNAL_VALUE_INPUT: 1 << 6, // External Value Input. - INPUT: 1 << 7, // Input. - INLINE_INPUT: 1 << 8, // Inline Input. - STATEMENT_INPUT: 1 << 9, // Statement Input. - CONNECTION: 1 << 10, // Connection. - PREVIOUS_CONNECTION: 1 << 11, // Previous Connection. - NEXT_CONNECTION: 1 << 12, // Next Connection. - OUTPUT_CONNECTION: 1 << 13, // Output Connection. - CORNER: 1 << 14, // Corner. - LEFT_SQUARE_CORNER: 1 << 15, // Square Corner. - LEFT_ROUND_CORNER: 1 << 16, // Round Corner. - RIGHT_SQUARE_CORNER: 1 << 17, // Right Square Corner. - RIGHT_ROUND_CORNER: 1 << 18, // Right Round Corner. - JAGGED_EDGE: 1 << 19, // Jagged Edge. - ROW: 1 << 20, // Row. - TOP_ROW: 1 << 21, // Top Row. - BOTTOM_ROW: 1 << 22, // Bottom Row. - INPUT_ROW: 1 << 23 // Input Row. +const Types = { + NONE: 0, // None + FIELD: 1 << 0, // Field. + HAT: 1 << 1, // Hat. + ICON: 1 << 2, // Icon. + SPACER: 1 << 3, // Spacer. + BETWEEN_ROW_SPACER: 1 << 4, // Between Row Spacer. + IN_ROW_SPACER: 1 << 5, // In Row Spacer. + EXTERNAL_VALUE_INPUT: 1 << 6, // External Value Input. + INPUT: 1 << 7, // Input. + INLINE_INPUT: 1 << 8, // Inline Input. + STATEMENT_INPUT: 1 << 9, // Statement Input. + CONNECTION: 1 << 10, // Connection. + PREVIOUS_CONNECTION: 1 << 11, // Previous Connection. + NEXT_CONNECTION: 1 << 12, // Next Connection. + OUTPUT_CONNECTION: 1 << 13, // Output Connection. + CORNER: 1 << 14, // Corner. + LEFT_SQUARE_CORNER: 1 << 15, // Square Corner. + LEFT_ROUND_CORNER: 1 << 16, // Round Corner. + RIGHT_SQUARE_CORNER: 1 << 17, // Right Square Corner. + RIGHT_ROUND_CORNER: 1 << 18, // Right Round Corner. + JAGGED_EDGE: 1 << 19, // Jagged Edge. + ROW: 1 << 20, // Row. + TOP_ROW: 1 << 21, // Top Row. + BOTTOM_ROW: 1 << 22, // Bottom Row. + INPUT_ROW: 1 << 23 // Input Row. }; /** @@ -55,9 +58,7 @@ Blockly.blockRendering.Types = { * @const * @package */ -Blockly.blockRendering.Types.LEFT_CORNER = - Blockly.blockRendering.Types.LEFT_SQUARE_CORNER | - Blockly.blockRendering.Types.LEFT_ROUND_CORNER; +Types.LEFT_CORNER = Types.LEFT_SQUARE_CORNER | Types.LEFT_ROUND_CORNER; /** * A Right Corner Union Type. @@ -65,19 +66,17 @@ Blockly.blockRendering.Types.LEFT_CORNER = * @const * @package */ -Blockly.blockRendering.Types.RIGHT_CORNER = - Blockly.blockRendering.Types.RIGHT_SQUARE_CORNER | - Blockly.blockRendering.Types.RIGHT_ROUND_CORNER; +Types.RIGHT_CORNER = Types.RIGHT_SQUARE_CORNER | Types.RIGHT_ROUND_CORNER; /** * Next flag value to use for custom rendering element types. * This must be updated to reflect the next enum flag value * to use if additional elements are added to - * `Blockly.blockRendering.Types`. + * `Types`. * @type {number} * @private */ -Blockly.blockRendering.Types.nextTypeValue_ = 1 << 24; +Types.nextTypeValue_ = 1 << 24; /** * Get the enum flag value of an existing type or register a new type. @@ -85,268 +84,267 @@ Blockly.blockRendering.Types.nextTypeValue_ = 1 << 24; * @return {!number} The enum flag value associated with that type. * @package */ -Blockly.blockRendering.Types.getType = function(type) { - if (!Object.prototype.hasOwnProperty.call(Blockly.blockRendering.Types, type)) { - Blockly.blockRendering.Types[type] = - Blockly.blockRendering.Types.nextTypeValue_; - Blockly.blockRendering.Types.nextTypeValue_ <<= 1; +Types.getType = function(type) { + if (!Object.prototype.hasOwnProperty.call(Types, type)) { + Types[type] = Types.nextTypeValue_; + Types.nextTypeValue_ <<= 1; } - return Blockly.blockRendering.Types[type]; + return Types[type]; }; /** * Whether a measurable stores information about a field. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a field. * @package */ -Blockly.blockRendering.Types.isField = function(elem) { - return elem.type & Blockly.blockRendering.Types.FIELD; +Types.isField = function(elem) { + return elem.type & Types.FIELD; }; /** * Whether a measurable stores information about a hat. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a hat. * @package */ -Blockly.blockRendering.Types.isHat = function(elem) { - return elem.type & Blockly.blockRendering.Types.HAT; +Types.isHat = function(elem) { + return elem.type & Types.HAT; }; /** * Whether a measurable stores information about an icon. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about an icon. * @package */ -Blockly.blockRendering.Types.isIcon = function(elem) { - return elem.type & Blockly.blockRendering.Types.ICON; +Types.isIcon = function(elem) { + return elem.type & Types.ICON; }; /** * Whether a measurable stores information about a spacer. - * @param {!Blockly.blockRendering.Measurable|!Blockly.blockRendering.Row} elem + * @param {!Measurable|!Row} elem * The element to check. * @return {number} 1 if the object stores information about a spacer. * @package */ -Blockly.blockRendering.Types.isSpacer = function(elem) { - return elem.type & Blockly.blockRendering.Types.SPACER; +Types.isSpacer = function(elem) { + return elem.type & Types.SPACER; }; /** * Whether a measurable stores information about an in-row spacer. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about an * in-row spacer. * @package */ -Blockly.blockRendering.Types.isInRowSpacer = function(elem) { - return elem.type & Blockly.blockRendering.Types.IN_ROW_SPACER; +Types.isInRowSpacer = function(elem) { + return elem.type & Types.IN_ROW_SPACER; }; /** * Whether a measurable stores information about an input. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about an input. * @package */ -Blockly.blockRendering.Types.isInput = function(elem) { - return elem.type & Blockly.blockRendering.Types.INPUT; +Types.isInput = function(elem) { + return elem.type & Types.INPUT; }; /** * Whether a measurable stores information about an external input. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about an * external input. * @package */ -Blockly.blockRendering.Types.isExternalInput = function(elem) { - return elem.type & Blockly.blockRendering.Types.EXTERNAL_VALUE_INPUT; +Types.isExternalInput = function(elem) { + return elem.type & Types.EXTERNAL_VALUE_INPUT; }; /** * Whether a measurable stores information about an inline input. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about an * inline input. * @package */ -Blockly.blockRendering.Types.isInlineInput = function(elem) { - return elem.type & Blockly.blockRendering.Types.INLINE_INPUT; +Types.isInlineInput = function(elem) { + return elem.type & Types.INLINE_INPUT; }; /** * Whether a measurable stores information about a statement input. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * statement input. * @package */ -Blockly.blockRendering.Types.isStatementInput = function(elem) { - return elem.type & Blockly.blockRendering.Types.STATEMENT_INPUT; +Types.isStatementInput = function(elem) { + return elem.type & Types.STATEMENT_INPUT; }; /** * Whether a measurable stores information about a previous connection. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * previous connection. * @package */ -Blockly.blockRendering.Types.isPreviousConnection = function(elem) { - return elem.type & Blockly.blockRendering.Types.PREVIOUS_CONNECTION; +Types.isPreviousConnection = function(elem) { + return elem.type & Types.PREVIOUS_CONNECTION; }; /** * Whether a measurable stores information about a next connection. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * next connection. * @package */ -Blockly.blockRendering.Types.isNextConnection = function(elem) { - return elem.type & Blockly.blockRendering.Types.NEXT_CONNECTION; +Types.isNextConnection = function(elem) { + return elem.type & Types.NEXT_CONNECTION; }; /** * Whether a measurable stores information about a previous or next connection. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a previous or * next connection. * @package */ -Blockly.blockRendering.Types.isPreviousOrNextConnection = function(elem) { - return elem.type & (Blockly.blockRendering.Types.PREVIOUS_CONNECTION | - Blockly.blockRendering.Types.NEXT_CONNECTION); +Types.isPreviousOrNextConnection = function(elem) { + return elem.type & (Types.PREVIOUS_CONNECTION | Types.NEXT_CONNECTION); }; /** * Whether a measurable stores information about a left round corner. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * left round corner. * @package */ -Blockly.blockRendering.Types.isLeftRoundedCorner = function(elem) { - return elem.type & Blockly.blockRendering.Types.LEFT_ROUND_CORNER; +Types.isLeftRoundedCorner = function(elem) { + return elem.type & Types.LEFT_ROUND_CORNER; }; /** * Whether a measurable stores information about a right round corner. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * right round corner. * @package */ -Blockly.blockRendering.Types.isRightRoundedCorner = function(elem) { - return elem.type & Blockly.blockRendering.Types.RIGHT_ROUND_CORNER; +Types.isRightRoundedCorner = function(elem) { + return elem.type & Types.RIGHT_ROUND_CORNER; }; /** * Whether a measurable stores information about a left square corner. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * left square corner. * @package */ -Blockly.blockRendering.Types.isLeftSquareCorner = function(elem) { - return elem.type & Blockly.blockRendering.Types.LEFT_SQUARE_CORNER; +Types.isLeftSquareCorner = function(elem) { + return elem.type & Types.LEFT_SQUARE_CORNER; }; /** * Whether a measurable stores information about a right square corner. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * right square corner. * @package */ -Blockly.blockRendering.Types.isRightSquareCorner = function(elem) { - return elem.type & Blockly.blockRendering.Types.RIGHT_SQUARE_CORNER; +Types.isRightSquareCorner = function(elem) { + return elem.type & Types.RIGHT_SQUARE_CORNER; }; /** * Whether a measurable stores information about a corner. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a * corner. * @package */ -Blockly.blockRendering.Types.isCorner = function(elem) { - return elem.type & Blockly.blockRendering.Types.CORNER; +Types.isCorner = function(elem) { + return elem.type & Types.CORNER; }; /** * Whether a measurable stores information about a jagged edge. - * @param {!Blockly.blockRendering.Measurable} elem The element to check. + * @param {!Measurable} elem The element to check. * @return {number} 1 if the object stores information about a jagged edge. * @package */ -Blockly.blockRendering.Types.isJaggedEdge = function(elem) { - return elem.type & Blockly.blockRendering.Types.JAGGED_EDGE; +Types.isJaggedEdge = function(elem) { + return elem.type & Types.JAGGED_EDGE; }; /** * Whether a measurable stores information about a row. - * @param {!Blockly.blockRendering.Row} row The row to check. + * @param {!Row} row The row to check. * @return {number} 1 if the object stores information about a row. * @package */ -Blockly.blockRendering.Types.isRow = function(row) { - return row.type & Blockly.blockRendering.Types.ROW; +Types.isRow = function(row) { + return row.type & Types.ROW; }; /** * Whether a measurable stores information about a between-row spacer. - * @param {!Blockly.blockRendering.Row} row The row to check. + * @param {!Row} row The row to check. * @return {number} 1 if the object stores information about a * between-row spacer. * @package */ -Blockly.blockRendering.Types.isBetweenRowSpacer = function(row) { - return row.type & Blockly.blockRendering.Types.BETWEEN_ROW_SPACER; +Types.isBetweenRowSpacer = function(row) { + return row.type & Types.BETWEEN_ROW_SPACER; }; /** * Whether a measurable stores information about a top row. - * @param {!Blockly.blockRendering.Row} row The row to check. + * @param {!Row} row The row to check. * @return {number} 1 if the object stores information about a top row. * @package */ -Blockly.blockRendering.Types.isTopRow = function(row) { - return row.type & Blockly.blockRendering.Types.TOP_ROW; +Types.isTopRow = function(row) { + return row.type & Types.TOP_ROW; }; /** * Whether a measurable stores information about a bottom row. - * @param {!Blockly.blockRendering.Row} row The row to check. + * @param {!Row} row The row to check. * @return {number} 1 if the object stores information about a bottom row. * @package */ -Blockly.blockRendering.Types.isBottomRow = function(row) { - return row.type & Blockly.blockRendering.Types.BOTTOM_ROW; +Types.isBottomRow = function(row) { + return row.type & Types.BOTTOM_ROW; }; /** * Whether a measurable stores information about a top or bottom row. - * @param {!Blockly.blockRendering.Row} row The row to check. + * @param {!Row} row The row to check. * @return {number} 1 if the object stores information about a top or * bottom row. * @package */ -Blockly.blockRendering.Types.isTopOrBottomRow = function(row) { - return row.type & (Blockly.blockRendering.Types.TOP_ROW | - Blockly.blockRendering.Types.BOTTOM_ROW); +Types.isTopOrBottomRow = function(row) { + return row.type & (Types.TOP_ROW | Types.BOTTOM_ROW); }; /** * Whether a measurable stores information about an input row. - * @param {!Blockly.blockRendering.Row} row The row to check. + * @param {!Row} row The row to check. * @return {number} 1 if the object stores information about an input row. * @package */ -Blockly.blockRendering.Types.isInputRow = function(row) { - return row.type & Blockly.blockRendering.Types.INPUT_ROW; +Types.isInputRow = function(row) { + return row.type & Types.INPUT_ROW; }; + +exports = Types; diff --git a/core/renderers/minimalist/drawer.js b/core/renderers/minimalist/drawer.js index 592710d6d..d0cd3a417 100644 --- a/core/renderers/minimalist/drawer.js +++ b/core/renderers/minimalist/drawer.js @@ -9,24 +9,29 @@ */ 'use strict'; -goog.provide('Blockly.minimalist.Drawer'); +goog.module('Blockly.minimalist.Drawer'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering.Drawer'); -goog.require('Blockly.minimalist.RenderInfo'); -goog.require('Blockly.utils.object'); +const BaseDrawer = goog.require('Blockly.blockRendering.Drawer'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +/* eslint-disable-next-line no-unused-vars */ +const RenderInfo = goog.requireType('Blockly.minimalist.RenderInfo'); +const object = goog.require('Blockly.utils.object'); /** * An object that draws a block based on the given rendering information. - * @param {!Blockly.BlockSvg} block The block to render. - * @param {!Blockly.minimalist.RenderInfo} info An object containing all + * @param {!BlockSvg} block The block to render. + * @param {!RenderInfo} info An object containing all * information needed to render this block. * @package * @constructor - * @extends {Blockly.blockRendering.Drawer} + * @extends {BaseDrawer} */ -Blockly.minimalist.Drawer = function(block, info) { - Blockly.minimalist.Drawer.superClass_.constructor.call(this, block, info); +const Drawer = function(block, info) { + Drawer.superClass_.constructor.call(this, block, info); }; -Blockly.utils.object.inherits(Blockly.minimalist.Drawer, - Blockly.blockRendering.Drawer); +object.inherits(Drawer, BaseDrawer); + +exports = Drawer; diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index 20bad30e4..be1a4fa04 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -53,7 +53,7 @@ Blockly.zelos.Drawer.prototype.draw = function() { if (this.info_.RTL) { pathObject.flipRTL(); } - if (Blockly.blockRendering.useDebugger) { + if (Blockly.blockRendering.isDebuggerEnabled()) { this.block_.renderingDebugger.drawDebug(this.block_, this.info_); } this.recordSizeOnBlock_(); diff --git a/core/requires.js b/core/requires.js index 2ca295441..cc67f564a 100644 --- a/core/requires.js +++ b/core/requires.js @@ -42,7 +42,6 @@ goog.require('Blockly.Trashcan'); goog.require('Blockly.VariablesDynamic'); // Only need to require these two if you're using workspace comments. // goog.require('Blockly.WorkspaceCommentSvg'); -// goog.require('Blockly.WorkspaceCommentSvg.render'); // If zoom controls aren't required, then Blockly.inject's // "zoom"/"controls" configuration must be false. goog.require('Blockly.ZoomControls'); diff --git a/core/scrollbar.js b/core/scrollbar.js index aab3852f2..9877d8201 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -5,24 +5,26 @@ */ /** - * @fileoverview Library for creating scrollbars. + * @fileoverview Object representing a scrollbar. * @author fraser@google.com (Neil Fraser) */ 'use strict'; -goog.provide('Blockly.Scrollbar'); -goog.provide('Blockly.ScrollbarPair'); +goog.module('Blockly.Scrollbar'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.Events'); -goog.require('Blockly.Touch'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Metrics'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.WorkspaceSvg'); +// TODO(#5073): Add Blockly require after fixing circular dependency. +// goog.require('Blockly'); +const Touch = goog.require('Blockly.Touch'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +/* eslint-disable-next-line no-unused-vars */ +const Metrics = goog.requireType('Blockly.utils.Metrics'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const utils = goog.require('Blockly.utils'); /** @@ -30,320 +32,22 @@ goog.requireType('Blockly.WorkspaceSvg'); * scrollbar is in a mutator. */ -/** - * Class for a pair of scrollbars. Horizontal and vertical. - * @param {!Blockly.WorkspaceSvg} workspace Workspace to bind the scrollbars to. - * @param {boolean=} addHorizontal Whether to add a horizontal scrollbar. - * Defaults to true. - * @param {boolean=} addVertical Whether to add a vertical scrollbar. Defaults - * to true. - * @param {string=} opt_class A class to be applied to these scrollbars. - * @param {number=} opt_margin The margin to apply to these scrollbars. - * @constructor - */ -Blockly.ScrollbarPair = function( - workspace, addHorizontal, addVertical, opt_class, opt_margin) { - /** - * The workspace this scrollbar pair is bound to. - * @type {!Blockly.WorkspaceSvg} - * @private - */ - this.workspace_ = workspace; - - addHorizontal = addHorizontal === undefined ? true : addHorizontal; - addVertical = addVertical === undefined ? true : addVertical; - var isPair = addHorizontal && addVertical; - - if (addHorizontal) { - this.hScroll = new Blockly.Scrollbar( - workspace, true, isPair, opt_class, opt_margin); - } - if (addVertical) { - this.vScroll = new Blockly.Scrollbar( - workspace, false, isPair, opt_class, opt_margin); - } - - if (isPair) { - this.corner_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - 'height': Blockly.Scrollbar.scrollbarThickness, - 'width': Blockly.Scrollbar.scrollbarThickness, - 'class': 'blocklyScrollbarBackground' - }, - null); - Blockly.utils.dom.insertAfter(this.corner_, workspace.getBubbleCanvas()); - } - - /** - * Previously recorded metrics from the workspace. - * @type {?Blockly.utils.Metrics} - * @private - */ - this.oldHostMetrics_ = null; -}; - -/** - * Dispose of this pair of scrollbars. - * Unlink from all DOM elements to prevent memory leaks. - * @suppress {checkTypes} - */ -Blockly.ScrollbarPair.prototype.dispose = function() { - Blockly.utils.dom.removeNode(this.corner_); - this.corner_ = null; - this.workspace_ = null; - this.oldHostMetrics_ = null; - if (this.hScroll) { - this.hScroll.dispose(); - this.hScroll = null; - } - if (this.vScroll) { - this.vScroll.dispose(); - this.vScroll = null; - } -}; - -/** - * Recalculate both of the scrollbars' locations and lengths. - * Also reposition the corner rectangle. - */ -Blockly.ScrollbarPair.prototype.resize = function() { - // Look up the host metrics once, and use for both scrollbars. - var hostMetrics = this.workspace_.getMetrics(); - if (!hostMetrics) { - // Host element is likely not visible. - return; - } - - // Only change the scrollbars if there has been a change in metrics. - var resizeH = false; - var resizeV = false; - if (!this.oldHostMetrics_ || - this.oldHostMetrics_.viewWidth != hostMetrics.viewWidth || - this.oldHostMetrics_.viewHeight != hostMetrics.viewHeight || - this.oldHostMetrics_.absoluteTop != hostMetrics.absoluteTop || - this.oldHostMetrics_.absoluteLeft != hostMetrics.absoluteLeft) { - // The window has been resized or repositioned. - resizeH = true; - resizeV = true; - } else { - // Has the content been resized or moved? - if (!this.oldHostMetrics_ || - this.oldHostMetrics_.scrollWidth != hostMetrics.scrollWidth || - this.oldHostMetrics_.viewLeft != hostMetrics.viewLeft || - this.oldHostMetrics_.scrollLeft != hostMetrics.scrollLeft) { - resizeH = true; - } - if (!this.oldHostMetrics_ || - this.oldHostMetrics_.scrollHeight != hostMetrics.scrollHeight || - this.oldHostMetrics_.viewTop != hostMetrics.viewTop || - this.oldHostMetrics_.scrollTop != hostMetrics.scrollTop) { - resizeV = true; - } - } - - if (resizeH || resizeV) { - try { - Blockly.Events.disable(); - if (this.hScroll && resizeH) { - this.hScroll.resize(hostMetrics); - } - if (this.vScroll && resizeV) { - this.vScroll.resize(hostMetrics); - } - } finally { - Blockly.Events.enable(); - } - this.workspace_.maybeFireViewportChangeEvent(); - } - - if (this.hScroll && this.vScroll) { - // Reposition the corner square. - if (!this.oldHostMetrics_ || - this.oldHostMetrics_.viewWidth != hostMetrics.viewWidth || - this.oldHostMetrics_.absoluteLeft != hostMetrics.absoluteLeft) { - this.corner_.setAttribute('x', this.vScroll.position.x); - } - if (!this.oldHostMetrics_ || - this.oldHostMetrics_.viewHeight != hostMetrics.viewHeight || - this.oldHostMetrics_.absoluteTop != hostMetrics.absoluteTop) { - this.corner_.setAttribute('y', this.hScroll.position.y); - } - } - - // Cache the current metrics to potentially short-cut the next resize event. - this.oldHostMetrics_ = hostMetrics; -}; - -/** - * Returns whether scrolling horizontally is enabled. - * @return {boolean} True if horizontal scroll is enabled. - */ -Blockly.ScrollbarPair.prototype.canScrollHorizontally = function() { - return !!this.hScroll; -}; - -/** - * Returns whether scrolling vertically is enabled. - * @return {boolean} True if vertical scroll is enabled. - */ -Blockly.ScrollbarPair.prototype.canScrollVertically = function() { - return !!this.vScroll; -}; - -/** - * Record the origin of the workspace that the scrollbar is in, in pixels - * relative to the injection div origin. This is for times when the scrollbar is - * used in an object whose origin isn't the same as the main workspace - * (e.g. in a flyout.) - * @param {number} x The x coordinate of the scrollbar's origin, in CSS pixels. - * @param {number} y The y coordinate of the scrollbar's origin, in CSS pixels. - * @package - */ -Blockly.ScrollbarPair.prototype.setOrigin = function(x, y) { - if (this.hScroll) { - this.hScroll.setOrigin(x, y); - } - if (this.vScroll) { - this.vScroll.setOrigin(x, y); - } -}; - -/** - * Set the handles of both scrollbars. - * @param {number} x The horizontal content displacement, relative to the view - * in pixels. - * @param {number} y The vertical content displacement, relative to the view in - * pixels. - * @param {boolean} updateMetrics Whether to update metrics on this set call. - * Defaults to true. - */ -Blockly.ScrollbarPair.prototype.set = function(x, y, updateMetrics) { - // This function is equivalent to: - // this.hScroll.set(x); - // this.vScroll.set(y); - // However, that calls setMetrics twice which causes a chain of - // getAttribute->setAttribute->getAttribute resulting in an extra layout pass. - // Combining them speeds up rendering. - if (this.hScroll) { - this.hScroll.set(x, false); - } - if (this.vScroll) { - this.vScroll.set(y, false); - } - - if (updateMetrics || updateMetrics === undefined) { - // Update metrics. - var xyRatio = {}; - if (this.hScroll) { - xyRatio.x = this.hScroll.getRatio_(); - } - if (this.vScroll) { - xyRatio.y = this.vScroll.getRatio_(); - } - this.workspace_.setMetrics(xyRatio); - } -}; - -/** - * Set the handle of the horizontal scrollbar to be at a certain position in - * CSS pixels relative to its parents. - * @param {number} x Horizontal scroll value. - */ -Blockly.ScrollbarPair.prototype.setX = function(x) { - if (this.hScroll) { - this.hScroll.set(x, true); - } -}; - -/** - * Set the handle of the vertical scrollbar to be at a certain position in - * CSS pixels relative to its parents. - * @param {number} y Vertical scroll value. - */ -Blockly.ScrollbarPair.prototype.setY = function(y) { - if (this.vScroll) { - this.vScroll.set(y, true); - } -}; - -/** - * Set whether this scrollbar's container is visible. - * @param {boolean} visible Whether the container is visible. - */ -Blockly.ScrollbarPair.prototype.setContainerVisible = function(visible) { - if (this.hScroll) { - this.hScroll.setContainerVisible(visible); - } - if (this.vScroll) { - this.vScroll.setContainerVisible(visible); - } -}; - -/** - * If any of the scrollbars are visible. Non-paired scrollbars may disappear - * when they aren't needed. - * @return {boolean} True if visible. - */ -Blockly.ScrollbarPair.prototype.isVisible = function() { - var isVisible = false; - if (this.hScroll) { - isVisible = this.hScroll.isVisible(); - } - if (this.vScroll) { - isVisible = isVisible || this.vScroll.isVisible(); - } - return isVisible; -}; - -/** - * Recalculates the scrollbars' locations within their path and length. - * This should be called when the contents of the workspace have changed. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all - * the required dimensions, possibly fetched from the host object. - */ -Blockly.ScrollbarPair.prototype.resizeContent = function(hostMetrics) { - if (this.hScroll) { - this.hScroll.resizeContentHorizontal(hostMetrics); - } - if (this.vScroll) { - this.vScroll.resizeContentVertical(hostMetrics); - } -}; - -/** - * Recalculates the scrollbars' locations on the screen and path length. - * This should be called when the layout or size of the window has changed. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all - * the required dimensions, possibly fetched from the host object. - */ -Blockly.ScrollbarPair.prototype.resizeView = function(hostMetrics) { - if (this.hScroll) { - this.hScroll.resizeViewHorizontal(hostMetrics); - } - if (this.vScroll) { - this.vScroll.resizeViewVertical(hostMetrics); - } -}; - -// -------------------------------------------------------------------- - /** * Class for a pure SVG scrollbar. * This technique offers a scrollbar that is guaranteed to work, but may not * look or behave like the system's scrollbars. - * @param {!Blockly.WorkspaceSvg} workspace Workspace to bind the scrollbar to. + * @param {!WorkspaceSvg} workspace Workspace to bind the scrollbar to. * @param {boolean} horizontal True if horizontal, false if vertical. * @param {boolean=} opt_pair True if scrollbar is part of a horiz/vert pair. * @param {string=} opt_class A class to be applied to this scrollbar. * @param {number=} opt_margin The margin to apply to this scrollbar. * @constructor */ -Blockly.Scrollbar = function( +const Scrollbar = function( workspace, horizontal, opt_pair, opt_class, opt_margin) { /** * The workspace this scrollbar is bound to. - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.workspace_ = workspace; @@ -367,10 +71,11 @@ Blockly.Scrollbar = function( * @private */ this.margin_ = (opt_margin !== undefined) ? - opt_margin : Blockly.Scrollbar.DEFAULT_SCROLLBAR_MARGIN; + opt_margin : + Scrollbar.DEFAULT_SCROLLBAR_MARGIN; /** * Previously recorded metrics from the workspace. - * @type {?Blockly.utils.Metrics} + * @type {?Metrics} * @private */ this.oldHostMetrics_ = null; @@ -387,13 +92,13 @@ Blockly.Scrollbar = function( * The upper left corner of the scrollbar's SVG group in CSS pixels relative * to the scrollbar's origin. This is usually relative to the injection div * origin. - * @type {Blockly.utils.Coordinate} + * @type {Coordinate} * @package */ - this.position = new Blockly.utils.Coordinate(0, 0); + this.position = new Coordinate(0, 0); // Store the thickness in a temp variable for readability. - var scrollbarThickness = Blockly.Scrollbar.scrollbarThickness; + const scrollbarThickness = Scrollbar.scrollbarThickness; if (horizontal) { this.svgBackground_.setAttribute('height', scrollbarThickness); this.outerSvg_.setAttribute('height', scrollbarThickness); @@ -411,10 +116,10 @@ Blockly.Scrollbar = function( this.lengthAttribute_ = 'height'; this.positionAttribute_ = 'y'; } - var scrollbar = this; - this.onMouseDownBarWrapper_ = Blockly.browserEvents.conditionalBind( + const scrollbar = this; + this.onMouseDownBarWrapper_ = browserEvents.conditionalBind( this.svgBackground_, 'mousedown', scrollbar, scrollbar.onMouseDownBar_); - this.onMouseDownHandleWrapper_ = Blockly.browserEvents.conditionalBind( + this.onMouseDownHandleWrapper_ = browserEvents.conditionalBind( this.svgHandle_, 'mousedown', scrollbar, scrollbar.onMouseDownHandle_); }; @@ -422,10 +127,10 @@ Blockly.Scrollbar = function( * The location of the origin of the workspace that the scrollbar is in, * measured in CSS pixels relative to the injection div origin. This is usually * (0, 0). When the scrollbar is in a flyout it may have a different origin. - * @type {Blockly.utils.Coordinate} + * @type {Coordinate} * @private */ -Blockly.Scrollbar.prototype.origin_ = new Blockly.utils.Coordinate(0, 0); +Scrollbar.prototype.origin_ = new Coordinate(0, 0); /** * The position of the mouse along this scrollbar's major axis at the start of @@ -436,7 +141,7 @@ Blockly.Scrollbar.prototype.origin_ = new Blockly.utils.Coordinate(0, 0); * @type {number} * @private */ -Blockly.Scrollbar.prototype.startDragMouse_ = 0; +Scrollbar.prototype.startDragMouse_ = 0; /** * The length of the scrollbars (including the handle and the background), in @@ -445,14 +150,14 @@ Blockly.Scrollbar.prototype.startDragMouse_ = 0; * @type {number} * @private */ -Blockly.Scrollbar.prototype.scrollbarLength_ = 0; +Scrollbar.prototype.scrollbarLength_ = 0; /** * The length of the scrollbar handle in CSS pixels. * @type {number} * @private */ -Blockly.Scrollbar.prototype.handleLength_ = 0; +Scrollbar.prototype.handleLength_ = 0; /** * The offset of the start of the handle from the scrollbar position, in CSS @@ -460,29 +165,29 @@ Blockly.Scrollbar.prototype.handleLength_ = 0; * @type {number} * @private */ -Blockly.Scrollbar.prototype.handlePosition_ = 0; +Scrollbar.prototype.handlePosition_ = 0; /** * Whether the scrollbar handle is visible. * @type {boolean} * @private */ -Blockly.Scrollbar.prototype.isVisible_ = true; +Scrollbar.prototype.isVisible_ = true; /** * Whether the workspace containing this scrollbar is visible. * @type {boolean} * @private */ -Blockly.Scrollbar.prototype.containerVisible_ = true; +Scrollbar.prototype.containerVisible_ = true; /** * Width of vertical scrollbar or height of horizontal scrollbar in CSS pixels. * Scrollbars should be larger on touch devices. */ -Blockly.Scrollbar.scrollbarThickness = 15; -if (Blockly.Touch.TOUCH_ENABLED) { - Blockly.Scrollbar.scrollbarThickness = 25; +Scrollbar.scrollbarThickness = 15; +if (Touch.TOUCH_ENABLED) { + Scrollbar.scrollbarThickness = 25; } /** @@ -492,22 +197,22 @@ if (Blockly.Touch.TOUCH_ENABLED) { * @const * @package */ -Blockly.Scrollbar.DEFAULT_SCROLLBAR_MARGIN = 0.5; +Scrollbar.DEFAULT_SCROLLBAR_MARGIN = 0.5; /** - * @param {!Blockly.utils.Metrics} first An object containing computed + * @param {!Metrics} first An object containing computed * measurements of a workspace. - * @param {!Blockly.utils.Metrics} second Another object containing computed + * @param {!Metrics} second Another object containing computed * measurements of a workspace. * @return {boolean} Whether the two sets of metrics are equivalent. * @private */ -Blockly.Scrollbar.metricsAreEquivalent_ = function(first, second) { - return (first.viewWidth == second.viewWidth && +Scrollbar.metricsAreEquivalent_ = function(first, second) { + return ( + first.viewWidth == second.viewWidth && first.viewHeight == second.viewHeight && - first.viewLeft == second.viewLeft && - first.viewTop == second.viewTop && + first.viewLeft == second.viewLeft && first.viewTop == second.viewTop && first.absoluteTop == second.absoluteTop && first.absoluteLeft == second.absoluteLeft && first.scrollWidth == second.scrollWidth && @@ -521,14 +226,14 @@ Blockly.Scrollbar.metricsAreEquivalent_ = function(first, second) { * Unlink from all DOM elements to prevent memory leaks. * @suppress {checkTypes} */ -Blockly.Scrollbar.prototype.dispose = function() { +Scrollbar.prototype.dispose = function() { this.cleanUp_(); - Blockly.browserEvents.unbind(this.onMouseDownBarWrapper_); + browserEvents.unbind(this.onMouseDownBarWrapper_); this.onMouseDownBarWrapper_ = null; - Blockly.browserEvents.unbind(this.onMouseDownHandleWrapper_); + browserEvents.unbind(this.onMouseDownHandleWrapper_); this.onMouseDownHandleWrapper_ = null; - Blockly.utils.dom.removeNode(this.outerSvg_); + dom.removeNode(this.outerSvg_); this.outerSvg_ = null; this.svgGroup_ = null; this.svgBackground_ = null; @@ -546,7 +251,7 @@ Blockly.Scrollbar.prototype.dispose = function() { * @return {number} Constrained value, in CSS pixels. * @private */ -Blockly.Scrollbar.prototype.constrainHandleLength_ = function(value) { +Scrollbar.prototype.constrainHandleLength_ = function(value) { if (value <= 0 || isNaN(value)) { value = 0; } else { @@ -561,7 +266,7 @@ Blockly.Scrollbar.prototype.constrainHandleLength_ = function(value) { * @param {number} newLength The new scrollbar handle length in CSS pixels. * @private */ -Blockly.Scrollbar.prototype.setHandleLength_ = function(newLength) { +Scrollbar.prototype.setHandleLength_ = function(newLength) { this.handleLength_ = newLength; this.svgHandle_.setAttribute(this.lengthAttribute_, this.handleLength_); }; @@ -573,7 +278,7 @@ Blockly.Scrollbar.prototype.setHandleLength_ = function(newLength) { * @return {number} Constrained value, in CSS pixels. * @private */ -Blockly.Scrollbar.prototype.constrainHandlePosition_ = function(value) { +Scrollbar.prototype.constrainHandlePosition_ = function(value) { if (value <= 0 || isNaN(value)) { value = 0; } else { @@ -590,7 +295,7 @@ Blockly.Scrollbar.prototype.constrainHandlePosition_ = function(value) { * change the SVG attribute accordingly. * @param {number} newPosition The new scrollbar handle offset in CSS pixels. */ -Blockly.Scrollbar.prototype.setHandlePosition = function(newPosition) { +Scrollbar.prototype.setHandlePosition = function(newPosition) { this.handlePosition_ = newPosition; this.svgHandle_.setAttribute(this.positionAttribute_, this.handlePosition_); }; @@ -601,10 +306,11 @@ Blockly.Scrollbar.prototype.setHandlePosition = function(newPosition) { * @param {number} newSize The new scrollbar background length in CSS pixels. * @private */ -Blockly.Scrollbar.prototype.setScrollbarLength_ = function(newSize) { +Scrollbar.prototype.setScrollbarLength_ = function(newSize) { this.scrollbarLength_ = newSize; this.outerSvg_.setAttribute(this.lengthAttribute_, this.scrollbarLength_); - this.svgBackground_.setAttribute(this.lengthAttribute_, this.scrollbarLength_); + this.svgBackground_.setAttribute( + this.lengthAttribute_, this.scrollbarLength_); }; /** @@ -614,25 +320,25 @@ Blockly.Scrollbar.prototype.setScrollbarLength_ = function(newSize) { * @param {number} y The new y coordinate. * @package */ -Blockly.Scrollbar.prototype.setPosition = function(x, y) { +Scrollbar.prototype.setPosition = function(x, y) { this.position.x = x; this.position.y = y; - var tempX = this.position.x + this.origin_.x; - var tempY = this.position.y + this.origin_.y; - var transform = 'translate(' + tempX + 'px,' + tempY + 'px)'; - Blockly.utils.dom.setCssTransform(this.outerSvg_, transform); + const tempX = this.position.x + this.origin_.x; + const tempY = this.position.y + this.origin_.y; + const transform = 'translate(' + tempX + 'px,' + tempY + 'px)'; + dom.setCssTransform(this.outerSvg_, transform); }; /** * Recalculate the scrollbar's location and its length. - * @param {Blockly.utils.Metrics=} opt_metrics A data structure of from the + * @param {Metrics=} opt_metrics A data structure of from the * describing all the required dimensions. If not provided, it will be * fetched from the host object. */ -Blockly.Scrollbar.prototype.resize = function(opt_metrics) { +Scrollbar.prototype.resize = function(opt_metrics) { // Determine the location, height and width of the host element. - var hostMetrics = opt_metrics; + let hostMetrics = opt_metrics; if (!hostMetrics) { hostMetrics = this.workspace_.getMetrics(); if (!hostMetrics) { @@ -641,8 +347,8 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { } } - if (this.oldHostMetrics_ && Blockly.Scrollbar.metricsAreEquivalent_( - hostMetrics, this.oldHostMetrics_)) { + if (this.oldHostMetrics_ && + Scrollbar.metricsAreEquivalent_(hostMetrics, this.oldHostMetrics_)) { return; } @@ -661,12 +367,12 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { /** * Returns whether the a resizeView is necessary by comparing the passed * hostMetrics with cached old host metrics. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. * @return {boolean} Whether a resizeView is necessary. * @private */ -Blockly.Scrollbar.prototype.requiresViewResize_ = function(hostMetrics) { +Scrollbar.prototype.requiresViewResize_ = function(hostMetrics) { if (!this.oldHostMetrics_) { return true; } @@ -678,11 +384,11 @@ Blockly.Scrollbar.prototype.requiresViewResize_ = function(hostMetrics) { /** * Recalculate a horizontal scrollbar's location and length. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. * @private */ -Blockly.Scrollbar.prototype.resizeHorizontal_ = function(hostMetrics) { +Scrollbar.prototype.resizeHorizontal_ = function(hostMetrics) { if (this.requiresViewResize_(hostMetrics)) { this.resizeViewHorizontal(hostMetrics); } else { @@ -693,26 +399,25 @@ Blockly.Scrollbar.prototype.resizeHorizontal_ = function(hostMetrics) { /** * Recalculate a horizontal scrollbar's location on the screen and path length. * This should be called when the layout or size of the window has changed. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. */ -Blockly.Scrollbar.prototype.resizeViewHorizontal = function(hostMetrics) { - var viewSize = hostMetrics.viewWidth - this.margin_ * 2; +Scrollbar.prototype.resizeViewHorizontal = function(hostMetrics) { + let viewSize = hostMetrics.viewWidth - this.margin_ * 2; if (this.pair_) { // Shorten the scrollbar to make room for the corner square. - viewSize -= Blockly.Scrollbar.scrollbarThickness; + viewSize -= Scrollbar.scrollbarThickness; } this.setScrollbarLength_(Math.max(0, viewSize)); - var xCoordinate = - hostMetrics.absoluteLeft + this.margin_; + let xCoordinate = hostMetrics.absoluteLeft + this.margin_; if (this.pair_ && this.workspace_.RTL) { - xCoordinate += Blockly.Scrollbar.scrollbarThickness; + xCoordinate += Scrollbar.scrollbarThickness; } // Horizontal toolbar should always be just above the bottom of the workspace. - var yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight - - Blockly.Scrollbar.scrollbarThickness - this.margin_; + const yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight - + Scrollbar.scrollbarThickness - this.margin_; this.setPosition(xCoordinate, yCoordinate); // If the view has been resized, a content resize will also be necessary. @@ -723,10 +428,10 @@ Blockly.Scrollbar.prototype.resizeViewHorizontal = function(hostMetrics) { /** * Recalculate a horizontal scrollbar's location within its path and length. * This should be called when the contents of the workspace have changed. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. */ -Blockly.Scrollbar.prototype.resizeContentHorizontal = function(hostMetrics) { +Scrollbar.prototype.resizeContentHorizontal = function(hostMetrics) { if (hostMetrics.viewWidth >= hostMetrics.scrollWidth) { // viewWidth is often greater than scrollWidth in flyouts and // non-scrollable workspaces. @@ -745,7 +450,7 @@ Blockly.Scrollbar.prototype.resizeContentHorizontal = function(hostMetrics) { } // Resize the handle. - var handleLength = + let handleLength = this.scrollbarLength_ * hostMetrics.viewWidth / hostMetrics.scrollWidth; handleLength = this.constrainHandleLength_(handleLength); this.setHandleLength_(handleLength); @@ -759,13 +464,13 @@ Blockly.Scrollbar.prototype.resizeContentHorizontal = function(hostMetrics) { // then viewLeft = scrollLeft + scrollWidth - viewWidth // then the offset should be max offset - var maxScrollDistance = hostMetrics.scrollWidth - hostMetrics.viewWidth; - var contentDisplacement = hostMetrics.viewLeft - hostMetrics.scrollLeft; + const maxScrollDistance = hostMetrics.scrollWidth - hostMetrics.viewWidth; + const contentDisplacement = hostMetrics.viewLeft - hostMetrics.scrollLeft; // Percent of content to the left of our current position. - var offsetRatio = contentDisplacement / maxScrollDistance; + const offsetRatio = contentDisplacement / maxScrollDistance; // Area available to scroll * percent to the left - var maxHandleOffset = this.scrollbarLength_ - this.handleLength_; - var handleOffset = maxHandleOffset * offsetRatio; + const maxHandleOffset = this.scrollbarLength_ - this.handleLength_; + let handleOffset = maxHandleOffset * offsetRatio; handleOffset = this.constrainHandlePosition_(handleOffset); this.setHandlePosition(handleOffset); @@ -775,11 +480,11 @@ Blockly.Scrollbar.prototype.resizeContentHorizontal = function(hostMetrics) { /** * Recalculate a vertical scrollbar's location and length. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. * @private */ -Blockly.Scrollbar.prototype.resizeVertical_ = function(hostMetrics) { +Scrollbar.prototype.resizeVertical_ = function(hostMetrics) { if (this.requiresViewResize_(hostMetrics)) { this.resizeViewVertical(hostMetrics); } else { @@ -790,23 +495,23 @@ Blockly.Scrollbar.prototype.resizeVertical_ = function(hostMetrics) { /** * Recalculate a vertical scrollbar's location on the screen and path length. * This should be called when the layout or size of the window has changed. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. */ -Blockly.Scrollbar.prototype.resizeViewVertical = function(hostMetrics) { - var viewSize = hostMetrics.viewHeight - this.margin_ * 2; +Scrollbar.prototype.resizeViewVertical = function(hostMetrics) { + let viewSize = hostMetrics.viewHeight - this.margin_ * 2; if (this.pair_) { // Shorten the scrollbar to make room for the corner square. - viewSize -= Blockly.Scrollbar.scrollbarThickness; + viewSize -= Scrollbar.scrollbarThickness; } this.setScrollbarLength_(Math.max(0, viewSize)); - var xCoordinate = this.workspace_.RTL ? + const xCoordinate = this.workspace_.RTL ? hostMetrics.absoluteLeft + this.margin_ : hostMetrics.absoluteLeft + hostMetrics.viewWidth - - Blockly.Scrollbar.scrollbarThickness - this.margin_; + Scrollbar.scrollbarThickness - this.margin_; - var yCoordinate = hostMetrics.absoluteTop + this.margin_; + const yCoordinate = hostMetrics.absoluteTop + this.margin_; this.setPosition(xCoordinate, yCoordinate); // If the view has been resized, a content resize will also be necessary. The @@ -817,10 +522,10 @@ Blockly.Scrollbar.prototype.resizeViewVertical = function(hostMetrics) { /** * Recalculate a vertical scrollbar's location within its path and length. * This should be called when the contents of the workspace have changed. - * @param {!Blockly.utils.Metrics} hostMetrics A data structure describing all + * @param {!Metrics} hostMetrics A data structure describing all * the required dimensions, possibly fetched from the host object. */ -Blockly.Scrollbar.prototype.resizeContentVertical = function(hostMetrics) { +Scrollbar.prototype.resizeContentVertical = function(hostMetrics) { if (hostMetrics.viewHeight >= hostMetrics.scrollHeight) { // viewHeight is often greater than scrollHeight in flyouts and // non-scrollable workspaces. @@ -839,7 +544,7 @@ Blockly.Scrollbar.prototype.resizeContentVertical = function(hostMetrics) { } // Resize the handle. - var handleLength = + let handleLength = this.scrollbarLength_ * hostMetrics.viewHeight / hostMetrics.scrollHeight; handleLength = this.constrainHandleLength_(handleLength); this.setHandleLength_(handleLength); @@ -853,13 +558,13 @@ Blockly.Scrollbar.prototype.resizeContentVertical = function(hostMetrics) { // then viewTop = scrollTop + scrollHeight - viewHeight // then the offset should be max offset - var maxScrollDistance = hostMetrics.scrollHeight - hostMetrics.viewHeight; - var contentDisplacement = hostMetrics.viewTop - hostMetrics.scrollTop; + const maxScrollDistance = hostMetrics.scrollHeight - hostMetrics.viewHeight; + const contentDisplacement = hostMetrics.viewTop - hostMetrics.scrollTop; // Percent of content to the left of our current position. - var offsetRatio = contentDisplacement / maxScrollDistance; + const offsetRatio = contentDisplacement / maxScrollDistance; // Area available to scroll * percent to the left - var maxHandleOffset = this.scrollbarLength_ - this.handleLength_; - var handleOffset = maxHandleOffset * offsetRatio; + const maxHandleOffset = this.scrollbarLength_ - this.handleLength_; + let handleOffset = maxHandleOffset * offsetRatio; handleOffset = this.constrainHandlePosition_(handleOffset); this.setHandlePosition(handleOffset); @@ -873,7 +578,7 @@ Blockly.Scrollbar.prototype.resizeContentVertical = function(hostMetrics) { * @param {string=} opt_class A class to be applied to this scrollbar. * @private */ -Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { +Scrollbar.prototype.createDom_ = function(opt_class) { /* Create the following DOM: @@ -882,34 +587,24 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { */ - var className = 'blocklyScrollbar' + - (this.horizontal_ ? 'Horizontal' : 'Vertical'); + let className = + 'blocklyScrollbar' + (this.horizontal_ ? 'Horizontal' : 'Vertical'); if (opt_class) { className += ' ' + opt_class; } - this.outerSvg_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.SVG, {'class': className}, null); - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, {}, this.outerSvg_); - this.svgBackground_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, { - 'class': 'blocklyScrollbarBackground' - }, this.svgGroup_); - var radius = Math.floor((Blockly.Scrollbar.scrollbarThickness - 5) / 2); - this.svgHandle_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - 'class': 'blocklyScrollbarHandle', - 'rx': radius, - 'ry': radius - }, + this.outerSvg_ = dom.createSvgElement(Svg.SVG, {'class': className}, null); + this.svgGroup_ = dom.createSvgElement(Svg.G, {}, this.outerSvg_); + this.svgBackground_ = dom.createSvgElement( + Svg.RECT, {'class': 'blocklyScrollbarBackground'}, this.svgGroup_); + const radius = Math.floor((Scrollbar.scrollbarThickness - 5) / 2); + this.svgHandle_ = dom.createSvgElement( + Svg.RECT, {'class': 'blocklyScrollbarHandle', 'rx': radius, 'ry': radius}, this.svgGroup_); this.workspace_.getThemeManager().subscribe( this.svgHandle_, 'scrollbarColour', 'fill'); this.workspace_.getThemeManager().subscribe( this.svgHandle_, 'scrollbarOpacity', 'fill-opacity'); - Blockly.utils.dom.insertAfter(this.outerSvg_, - this.workspace_.getParentSvg()); + dom.insertAfter(this.outerSvg_, this.workspace_.getParentSvg()); }; /** @@ -917,7 +612,7 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { * needed. * @return {boolean} True if visible. */ -Blockly.Scrollbar.prototype.isVisible = function() { +Scrollbar.prototype.isVisible = function() { return this.isVisible_; }; @@ -926,8 +621,8 @@ Blockly.Scrollbar.prototype.isVisible = function() { * display accordingly if visibility has changed. * @param {boolean} visible Whether the container is visible */ -Blockly.Scrollbar.prototype.setContainerVisible = function(visible) { - var visibilityChanged = (visible != this.containerVisible_); +Scrollbar.prototype.setContainerVisible = function(visible) { + const visibilityChanged = (visible != this.containerVisible_); this.containerVisible_ = visible; if (visibilityChanged) { @@ -940,8 +635,8 @@ Blockly.Scrollbar.prototype.setContainerVisible = function(visible) { * Only applies to non-paired scrollbars. * @param {boolean} visible True if visible. */ -Blockly.Scrollbar.prototype.setVisible = function(visible) { - var visibilityChanged = (visible != this.isVisible()); +Scrollbar.prototype.setVisible = function(visible) { + const visibilityChanged = (visible != this.isVisible()); // Ideally this would also apply to scrollbar pairs, but that's a bigger // headache (due to interactions with the corner square). @@ -960,8 +655,8 @@ Blockly.Scrollbar.prototype.setVisible = function(visible) { * We cannot rely on the containing workspace being hidden to hide us * because it is not necessarily our parent in the DOM. */ -Blockly.Scrollbar.prototype.updateDisplay_ = function() { - var show = true; +Scrollbar.prototype.updateDisplay_ = function() { + let show = true; // Check whether our parent/container is visible. if (!this.containerVisible_) { show = false; @@ -981,26 +676,25 @@ Blockly.Scrollbar.prototype.updateDisplay_ = function() { * @param {!Event} e Mouse down event. * @private */ -Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) { +Scrollbar.prototype.onMouseDownBar_ = function(e) { this.workspace_.markFocused(); - Blockly.Touch.clearTouchIdentifier(); // This is really a click. + Touch.clearTouchIdentifier(); // This is really a click. this.cleanUp_(); - if (Blockly.utils.isRightButton(e)) { + if (utils.isRightButton(e)) { // Right-click. // Scrollbars have no context menu. e.stopPropagation(); return; } - var mouseXY = Blockly.utils.mouseToSvg(e, - this.workspace_.getParentSvg(), - this.workspace_.getInverseScreenCTM()); - var mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y; + const mouseXY = utils.mouseToSvg( + e, this.workspace_.getParentSvg(), this.workspace_.getInverseScreenCTM()); + const mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y; - var handleXY = Blockly.utils.getInjectionDivXY_(this.svgHandle_); - var handleStart = this.horizontal_ ? handleXY.x : handleXY.y; - var handlePosition = this.handlePosition_; + const handleXY = utils.getInjectionDivXY_(this.svgHandle_); + const handleStart = this.horizontal_ ? handleXY.x : handleXY.y; + let handlePosition = this.handlePosition_; - var pageLength = this.handleLength_ * 0.95; + const pageLength = this.handleLength_ * 0.95; if (mouseLocation <= handleStart) { // Decrease the scrollbar's value by a page. handlePosition -= pageLength; @@ -1022,10 +716,10 @@ Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) { * @param {!Event} e Mouse down event. * @private */ -Blockly.Scrollbar.prototype.onMouseDownHandle_ = function(e) { +Scrollbar.prototype.onMouseDownHandle_ = function(e) { this.workspace_.markFocused(); this.cleanUp_(); - if (Blockly.utils.isRightButton(e)) { + if (utils.isRightButton(e)) { // Right-click. // Scrollbars have no context menu. e.stopPropagation(); @@ -1041,9 +735,9 @@ Blockly.Scrollbar.prototype.onMouseDownHandle_ = function(e) { // Record the current mouse position. this.startDragMouse_ = this.horizontal_ ? e.clientX : e.clientY; - Blockly.Scrollbar.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind( + Scrollbar.onMouseUpWrapper_ = browserEvents.conditionalBind( document, 'mouseup', this, this.onMouseUpHandle_); - Blockly.Scrollbar.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind( + Scrollbar.onMouseMoveWrapper_ = browserEvents.conditionalBind( document, 'mousemove', this, this.onMouseMoveHandle_); e.stopPropagation(); e.preventDefault(); @@ -1054,10 +748,10 @@ Blockly.Scrollbar.prototype.onMouseDownHandle_ = function(e) { * @param {!Event} e Mouse up event. * @private */ -Blockly.Scrollbar.prototype.onMouseMoveHandle_ = function(e) { - var currentMouse = this.horizontal_ ? e.clientX : e.clientY; - var mouseDelta = currentMouse - this.startDragMouse_; - var handlePosition = this.startDragHandle + mouseDelta; +Scrollbar.prototype.onMouseMoveHandle_ = function(e) { + const currentMouse = this.horizontal_ ? e.clientX : e.clientY; + const mouseDelta = currentMouse - this.startDragMouse_; + const handlePosition = this.startDragHandle + mouseDelta; // Position the bar. this.setHandlePosition(this.constrainHandlePosition_(handlePosition)); this.updateMetrics_(); @@ -1067,10 +761,10 @@ Blockly.Scrollbar.prototype.onMouseMoveHandle_ = function(e) { * Release the scrollbar handle and reset state accordingly. * @private */ -Blockly.Scrollbar.prototype.onMouseUpHandle_ = function() { +Scrollbar.prototype.onMouseUpHandle_ = function() { // Tell the workspace to clean up now that the workspace is done moving. this.workspace_.resetDragSurface(); - Blockly.Touch.clearTouchIdentifier(); + Touch.clearTouchIdentifier(); this.cleanUp_(); }; @@ -1079,26 +773,26 @@ Blockly.Scrollbar.prototype.onMouseUpHandle_ = function() { * wrap up loose ends associated with the scrollbar. * @private */ -Blockly.Scrollbar.prototype.cleanUp_ = function() { +Scrollbar.prototype.cleanUp_ = function() { Blockly.hideChaff(true); - if (Blockly.Scrollbar.onMouseUpWrapper_) { - Blockly.browserEvents.unbind(Blockly.Scrollbar.onMouseUpWrapper_); - Blockly.Scrollbar.onMouseUpWrapper_ = null; + if (Scrollbar.onMouseUpWrapper_) { + browserEvents.unbind(Scrollbar.onMouseUpWrapper_); + Scrollbar.onMouseUpWrapper_ = null; } - if (Blockly.Scrollbar.onMouseMoveWrapper_) { - Blockly.browserEvents.unbind(Blockly.Scrollbar.onMouseMoveWrapper_); - Blockly.Scrollbar.onMouseMoveWrapper_ = null; + if (Scrollbar.onMouseMoveWrapper_) { + browserEvents.unbind(Scrollbar.onMouseMoveWrapper_); + Scrollbar.onMouseMoveWrapper_ = null; } }; /** * Helper to calculate the ratio of handle position to scrollbar view size. * @return {number} Ratio. - * @protected + * @package */ -Blockly.Scrollbar.prototype.getRatio_ = function() { - var scrollHandleRange = this.scrollbarLength_ - this.handleLength_; - var ratio = this.handlePosition_ / scrollHandleRange; +Scrollbar.prototype.getRatio_ = function() { + const scrollHandleRange = this.scrollbarLength_ - this.handleLength_; + let ratio = this.handlePosition_ / scrollHandleRange; if (isNaN(ratio)) { ratio = 0; } @@ -1110,9 +804,9 @@ Blockly.Scrollbar.prototype.getRatio_ = function() { * moved. * @private */ -Blockly.Scrollbar.prototype.updateMetrics_ = function() { - var ratio = this.getRatio_(); - var xyRatio = {}; +Scrollbar.prototype.updateMetrics_ = function() { + const ratio = this.getRatio_(); + const xyRatio = {}; if (this.horizontal_) { xyRatio.x = ratio; } else { @@ -1128,7 +822,7 @@ Blockly.Scrollbar.prototype.updateMetrics_ = function() { * @param {boolean=} updateMetrics Whether to update metrics on this set call. * Defaults to true. */ -Blockly.Scrollbar.prototype.set = function(value, updateMetrics) { +Scrollbar.prototype.set = function(value, updateMetrics) { this.setHandlePosition(this.constrainHandlePosition_(value * this.ratio)); if (updateMetrics || updateMetrics === undefined) { this.updateMetrics_(); @@ -1143,6 +837,8 @@ Blockly.Scrollbar.prototype.set = function(value, updateMetrics) { * @param {number} x The x coordinate of the scrollbar's origin, in CSS pixels. * @param {number} y The y coordinate of the scrollbar's origin, in CSS pixels. */ -Blockly.Scrollbar.prototype.setOrigin = function(x, y) { - this.origin_ = new Blockly.utils.Coordinate(x, y); +Scrollbar.prototype.setOrigin = function(x, y) { + this.origin_ = new Coordinate(x, y); }; + +exports = Scrollbar; diff --git a/core/scrollbar_pair.js b/core/scrollbar_pair.js new file mode 100644 index 000000000..2b240f276 --- /dev/null +++ b/core/scrollbar_pair.js @@ -0,0 +1,321 @@ +/** + * @license + * Copyright 2011 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Object representing a pair of scrollbars. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +goog.module('Blockly.ScrollbarPair'); +goog.module.declareLegacyNamespace(); + +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Metrics = goog.requireType('Blockly.utils.Metrics'); +const Scrollbar = goog.require('Blockly.Scrollbar'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const dom = goog.require('Blockly.utils.dom'); + + +/** + * Class for a pair of scrollbars. Horizontal and vertical. + * @param {!WorkspaceSvg} workspace Workspace to bind the scrollbars to. + * @param {boolean=} addHorizontal Whether to add a horizontal scrollbar. + * Defaults to true. + * @param {boolean=} addVertical Whether to add a vertical scrollbar. Defaults + * to true. + * @param {string=} opt_class A class to be applied to these scrollbars. + * @param {number=} opt_margin The margin to apply to these scrollbars. + * @constructor + */ +const ScrollbarPair = function( + workspace, addHorizontal, addVertical, opt_class, opt_margin) { + /** + * The workspace this scrollbar pair is bound to. + * @type {!WorkspaceSvg} + * @private + */ + this.workspace_ = workspace; + + addHorizontal = addHorizontal === undefined ? true : addHorizontal; + addVertical = addVertical === undefined ? true : addVertical; + const isPair = addHorizontal && addVertical; + + if (addHorizontal) { + this.hScroll = + new Scrollbar(workspace, true, isPair, opt_class, opt_margin); + } + if (addVertical) { + this.vScroll = + new Scrollbar(workspace, false, isPair, opt_class, opt_margin); + } + + if (isPair) { + this.corner_ = dom.createSvgElement( + Svg.RECT, { + 'height': Scrollbar.scrollbarThickness, + 'width': Scrollbar.scrollbarThickness, + 'class': 'blocklyScrollbarBackground' + }, + null); + dom.insertAfter(this.corner_, workspace.getBubbleCanvas()); + } + + /** + * Previously recorded metrics from the workspace. + * @type {?Metrics} + * @private + */ + this.oldHostMetrics_ = null; +}; + +/** + * Dispose of this pair of scrollbars. + * Unlink from all DOM elements to prevent memory leaks. + * @suppress {checkTypes} + */ +ScrollbarPair.prototype.dispose = function() { + dom.removeNode(this.corner_); + this.corner_ = null; + this.workspace_ = null; + this.oldHostMetrics_ = null; + if (this.hScroll) { + this.hScroll.dispose(); + this.hScroll = null; + } + if (this.vScroll) { + this.vScroll.dispose(); + this.vScroll = null; + } +}; + +/** + * Recalculate both of the scrollbars' locations and lengths. + * Also reposition the corner rectangle. + */ +ScrollbarPair.prototype.resize = function() { + // Look up the host metrics once, and use for both scrollbars. + const hostMetrics = this.workspace_.getMetrics(); + if (!hostMetrics) { + // Host element is likely not visible. + return; + } + + // Only change the scrollbars if there has been a change in metrics. + let resizeH = false; + let resizeV = false; + if (!this.oldHostMetrics_ || + this.oldHostMetrics_.viewWidth != hostMetrics.viewWidth || + this.oldHostMetrics_.viewHeight != hostMetrics.viewHeight || + this.oldHostMetrics_.absoluteTop != hostMetrics.absoluteTop || + this.oldHostMetrics_.absoluteLeft != hostMetrics.absoluteLeft) { + // The window has been resized or repositioned. + resizeH = true; + resizeV = true; + } else { + // Has the content been resized or moved? + if (!this.oldHostMetrics_ || + this.oldHostMetrics_.scrollWidth != hostMetrics.scrollWidth || + this.oldHostMetrics_.viewLeft != hostMetrics.viewLeft || + this.oldHostMetrics_.scrollLeft != hostMetrics.scrollLeft) { + resizeH = true; + } + if (!this.oldHostMetrics_ || + this.oldHostMetrics_.scrollHeight != hostMetrics.scrollHeight || + this.oldHostMetrics_.viewTop != hostMetrics.viewTop || + this.oldHostMetrics_.scrollTop != hostMetrics.scrollTop) { + resizeV = true; + } + } + + if (resizeH || resizeV) { + try { + Events.disable(); + if (this.hScroll && resizeH) { + this.hScroll.resize(hostMetrics); + } + if (this.vScroll && resizeV) { + this.vScroll.resize(hostMetrics); + } + } finally { + Events.enable(); + } + this.workspace_.maybeFireViewportChangeEvent(); + } + + if (this.hScroll && this.vScroll) { + // Reposition the corner square. + if (!this.oldHostMetrics_ || + this.oldHostMetrics_.viewWidth != hostMetrics.viewWidth || + this.oldHostMetrics_.absoluteLeft != hostMetrics.absoluteLeft) { + this.corner_.setAttribute('x', this.vScroll.position.x); + } + if (!this.oldHostMetrics_ || + this.oldHostMetrics_.viewHeight != hostMetrics.viewHeight || + this.oldHostMetrics_.absoluteTop != hostMetrics.absoluteTop) { + this.corner_.setAttribute('y', this.hScroll.position.y); + } + } + + // Cache the current metrics to potentially short-cut the next resize event. + this.oldHostMetrics_ = hostMetrics; +}; + +/** + * Returns whether scrolling horizontally is enabled. + * @return {boolean} True if horizontal scroll is enabled. + */ +ScrollbarPair.prototype.canScrollHorizontally = function() { + return !!this.hScroll; +}; + +/** + * Returns whether scrolling vertically is enabled. + * @return {boolean} True if vertical scroll is enabled. + */ +ScrollbarPair.prototype.canScrollVertically = function() { + return !!this.vScroll; +}; + +/** + * Record the origin of the workspace that the scrollbar is in, in pixels + * relative to the injection div origin. This is for times when the scrollbar is + * used in an object whose origin isn't the same as the main workspace + * (e.g. in a flyout.) + * @param {number} x The x coordinate of the scrollbar's origin, in CSS pixels. + * @param {number} y The y coordinate of the scrollbar's origin, in CSS pixels. + * @package + */ +ScrollbarPair.prototype.setOrigin = function(x, y) { + if (this.hScroll) { + this.hScroll.setOrigin(x, y); + } + if (this.vScroll) { + this.vScroll.setOrigin(x, y); + } +}; + +/** + * Set the handles of both scrollbars. + * @param {number} x The horizontal content displacement, relative to the view + * in pixels. + * @param {number} y The vertical content displacement, relative to the view in + * pixels. + * @param {boolean} updateMetrics Whether to update metrics on this set call. + * Defaults to true. + */ +ScrollbarPair.prototype.set = function(x, y, updateMetrics) { + // This function is equivalent to: + // this.hScroll.set(x); + // this.vScroll.set(y); + // However, that calls setMetrics twice which causes a chain of + // getAttribute->setAttribute->getAttribute resulting in an extra layout pass. + // Combining them speeds up rendering. + if (this.hScroll) { + this.hScroll.set(x, false); + } + if (this.vScroll) { + this.vScroll.set(y, false); + } + + if (updateMetrics || updateMetrics === undefined) { + // Update metrics. + const xyRatio = {}; + if (this.hScroll) { + xyRatio.x = this.hScroll.getRatio_(); + } + if (this.vScroll) { + xyRatio.y = this.vScroll.getRatio_(); + } + this.workspace_.setMetrics(xyRatio); + } +}; + +/** + * Set the handle of the horizontal scrollbar to be at a certain position in + * CSS pixels relative to its parents. + * @param {number} x Horizontal scroll value. + */ +ScrollbarPair.prototype.setX = function(x) { + if (this.hScroll) { + this.hScroll.set(x, true); + } +}; + +/** + * Set the handle of the vertical scrollbar to be at a certain position in + * CSS pixels relative to its parents. + * @param {number} y Vertical scroll value. + */ +ScrollbarPair.prototype.setY = function(y) { + if (this.vScroll) { + this.vScroll.set(y, true); + } +}; + +/** + * Set whether this scrollbar's container is visible. + * @param {boolean} visible Whether the container is visible. + */ +ScrollbarPair.prototype.setContainerVisible = function(visible) { + if (this.hScroll) { + this.hScroll.setContainerVisible(visible); + } + if (this.vScroll) { + this.vScroll.setContainerVisible(visible); + } +}; + +/** + * If any of the scrollbars are visible. Non-paired scrollbars may disappear + * when they aren't needed. + * @return {boolean} True if visible. + */ +ScrollbarPair.prototype.isVisible = function() { + let isVisible = false; + if (this.hScroll) { + isVisible = this.hScroll.isVisible(); + } + if (this.vScroll) { + isVisible = isVisible || this.vScroll.isVisible(); + } + return isVisible; +}; + +/** + * Recalculates the scrollbars' locations within their path and length. + * This should be called when the contents of the workspace have changed. + * @param {!Metrics} hostMetrics A data structure describing all + * the required dimensions, possibly fetched from the host object. + */ +ScrollbarPair.prototype.resizeContent = function(hostMetrics) { + if (this.hScroll) { + this.hScroll.resizeContentHorizontal(hostMetrics); + } + if (this.vScroll) { + this.vScroll.resizeContentVertical(hostMetrics); + } +}; + +/** + * Recalculates the scrollbars' locations on the screen and path length. + * This should be called when the layout or size of the window has changed. + * @param {!Metrics} hostMetrics A data structure describing all + * the required dimensions, possibly fetched from the host object. + */ +ScrollbarPair.prototype.resizeView = function(hostMetrics) { + if (this.hScroll) { + this.hScroll.resizeViewHorizontal(hostMetrics); + } + if (this.vScroll) { + this.vScroll.resizeViewVertical(hostMetrics); + } +}; + +exports = ScrollbarPair; diff --git a/core/shortcut_items.js b/core/shortcut_items.js index ef1cb07fc..259a8c4bc 100644 --- a/core/shortcut_items.js +++ b/core/shortcut_items.js @@ -10,25 +10,25 @@ */ 'use strict'; -/** - * @name Blockly.ShortcutItems - * @namespace - */ -goog.provide('Blockly.ShortcutItems'); +goog.module('Blockly.ShortcutItems'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Gesture'); -goog.require('Blockly.ShortcutRegistry'); -goog.require('Blockly.utils.KeyCodes'); - -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.ICopyable'); +const Blockly = goog.require('Blockly'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Gesture = goog.require('Blockly.Gesture'); +/* eslint-disable-next-line no-unused-vars */ +const ICopyable = goog.requireType('Blockly.ICopyable'); +const KeyCodes = goog.require('Blockly.utils.KeyCodes'); +const ShortcutRegistry = goog.require('Blockly.ShortcutRegistry'); +const clipboard = goog.require('Blockly.clipboard'); /** * Object holding the names of the default shortcut items. * @enum {string} */ -Blockly.ShortcutItems.names = { +const names = { ESCAPE: 'escape', DELETE: 'delete', COPY: 'copy', @@ -37,12 +37,13 @@ Blockly.ShortcutItems.names = { UNDO: 'undo', REDO: 'redo' }; +exports.names = names; /** Keyboard shortcut to hide chaff on escape. */ -Blockly.ShortcutItems.registerEscape = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var escapeAction = { - name: Blockly.ShortcutItems.names.ESCAPE, +const registerEscape = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const escapeAction = { + name: names.ESCAPE, preconditionFn: function(workspace) { return !workspace.options.readOnly; }, @@ -51,19 +52,18 @@ Blockly.ShortcutItems.registerEscape = function() { return true; } }; - Blockly.ShortcutRegistry.registry.register(escapeAction); - Blockly.ShortcutRegistry.registry.addKeyMapping( - Blockly.utils.KeyCodes.ESC, escapeAction.name); + ShortcutRegistry.registry.register(escapeAction); + ShortcutRegistry.registry.addKeyMapping(KeyCodes.ESC, escapeAction.name); }; +exports.registerEscape = registerEscape; /** Keyboard shortcut to delete a block on delete or backspace */ -Blockly.ShortcutItems.registerDelete = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var deleteShortcut = { - name: Blockly.ShortcutItems.names.DELETE, +const registerDelete = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const deleteShortcut = { + name: names.DELETE, preconditionFn: function(workspace) { - return !workspace.options.readOnly && - Blockly.selected && + return !workspace.options.readOnly && Blockly.selected && Blockly.selected.isDeletable(); }, callback: function(workspace, e) { @@ -73,127 +73,124 @@ Blockly.ShortcutItems.registerDelete = function() { // data loss. e.preventDefault(); // Don't delete while dragging. Jeez. - if (Blockly.Gesture.inProgress()) { + if (Gesture.inProgress()) { return false; } - Blockly.deleteBlock(/** @type {!Blockly.BlockSvg} */ (Blockly.selected)); + Blockly.deleteBlock(/** @type {!BlockSvg} */ (Blockly.selected)); return true; } }; - Blockly.ShortcutRegistry.registry.register(deleteShortcut); - Blockly.ShortcutRegistry.registry.addKeyMapping( - Blockly.utils.KeyCodes.DELETE, deleteShortcut.name); - Blockly.ShortcutRegistry.registry.addKeyMapping( - Blockly.utils.KeyCodes.BACKSPACE, deleteShortcut.name); + ShortcutRegistry.registry.register(deleteShortcut); + ShortcutRegistry.registry.addKeyMapping(KeyCodes.DELETE, deleteShortcut.name); + ShortcutRegistry.registry.addKeyMapping( + KeyCodes.BACKSPACE, deleteShortcut.name); }; +exports.registerDelete = registerDelete; /** Keyboard shortcut to copy a block on ctrl+c, cmd+c, or alt+c. */ -Blockly.ShortcutItems.registerCopy = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var copyShortcut = { - name: Blockly.ShortcutItems.names.COPY, +const registerCopy = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const copyShortcut = { + name: names.COPY, preconditionFn: function(workspace) { - return !workspace.options.readOnly && - !Blockly.Gesture.inProgress() && - Blockly.selected && - Blockly.selected.isDeletable() && - Blockly.selected.isMovable(); + return !workspace.options.readOnly && !Gesture.inProgress() && + Blockly.selected && Blockly.selected.isDeletable() && + Blockly.selected.isMovable(); }, callback: function(workspace, e) { // Prevent the default copy behavior, which may beep or otherwise indicate // an error due to the lack of a selection. e.preventDefault(); Blockly.hideChaff(); - Blockly.copy(/** @type {!Blockly.ICopyable} */ (Blockly.selected)); + clipboard.copy(/** @type {!ICopyable} */ (Blockly.selected)); return true; } }; - Blockly.ShortcutRegistry.registry.register(copyShortcut); + ShortcutRegistry.registry.register(copyShortcut); - var ctrlC = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.C, [Blockly.utils.KeyCodes.CTRL]); - Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlC, copyShortcut.name); + const ctrlC = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.C, [KeyCodes.CTRL]); + ShortcutRegistry.registry.addKeyMapping(ctrlC, copyShortcut.name); - var altC = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.C, [Blockly.utils.KeyCodes.ALT]); - Blockly.ShortcutRegistry.registry.addKeyMapping(altC, copyShortcut.name); + const altC = + ShortcutRegistry.registry.createSerializedKey(KeyCodes.C, [KeyCodes.ALT]); + ShortcutRegistry.registry.addKeyMapping(altC, copyShortcut.name); - var metaC = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.C, [Blockly.utils.KeyCodes.META]); - Blockly.ShortcutRegistry.registry.addKeyMapping(metaC, copyShortcut.name); + const metaC = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.C, [KeyCodes.META]); + ShortcutRegistry.registry.addKeyMapping(metaC, copyShortcut.name); }; +exports.registerCopy = registerCopy; /** Keyboard shortcut to copy and delete a block on ctrl+x, cmd+x, or alt+x. */ -Blockly.ShortcutItems.registerCut = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var cutShortcut = { - name: Blockly.ShortcutItems.names.CUT, +const registerCut = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const cutShortcut = { + name: names.CUT, preconditionFn: function(workspace) { - return !workspace.options.readOnly && - !Blockly.Gesture.inProgress() && - Blockly.selected && - Blockly.selected.isDeletable() && - Blockly.selected.isMovable() && - !Blockly.selected.workspace.isFlyout; + return !workspace.options.readOnly && !Gesture.inProgress() && + Blockly.selected && Blockly.selected.isDeletable() && + Blockly.selected.isMovable() && !Blockly.selected.workspace.isFlyout; }, callback: function() { - Blockly.copy(/** @type {!Blockly.ICopyable} */ (Blockly.selected)); - Blockly.deleteBlock(/** @type {!Blockly.BlockSvg} */ (Blockly.selected)); + clipboard.copy(/** @type {!ICopyable} */ (Blockly.selected)); + Blockly.deleteBlock(/** @type {!BlockSvg} */ (Blockly.selected)); return true; } }; - Blockly.ShortcutRegistry.registry.register(cutShortcut); + ShortcutRegistry.registry.register(cutShortcut); - var ctrlX = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.X, [Blockly.utils.KeyCodes.CTRL]); - Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlX, cutShortcut.name); + const ctrlX = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.X, [KeyCodes.CTRL]); + ShortcutRegistry.registry.addKeyMapping(ctrlX, cutShortcut.name); - var altX = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.X, [Blockly.utils.KeyCodes.ALT]); - Blockly.ShortcutRegistry.registry.addKeyMapping(altX, cutShortcut.name); + const altX = + ShortcutRegistry.registry.createSerializedKey(KeyCodes.X, [KeyCodes.ALT]); + ShortcutRegistry.registry.addKeyMapping(altX, cutShortcut.name); - var metaX = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.X, [Blockly.utils.KeyCodes.META]); - Blockly.ShortcutRegistry.registry.addKeyMapping(metaX, cutShortcut.name); + const metaX = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.X, [KeyCodes.META]); + ShortcutRegistry.registry.addKeyMapping(metaX, cutShortcut.name); }; +exports.registerCut = registerCut; /** Keyboard shortcut to paste a block on ctrl+v, cmd+v, or alt+v. */ -Blockly.ShortcutItems.registerPaste = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var pasteShortcut = { - name: Blockly.ShortcutItems.names.PASTE, +const registerPaste = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const pasteShortcut = { + name: names.PASTE, preconditionFn: function(workspace) { - return !workspace.options.readOnly && !Blockly.Gesture.inProgress(); + return !workspace.options.readOnly && !Gesture.inProgress(); }, callback: function() { - return Blockly.paste(); + return clipboard.paste(); } }; - Blockly.ShortcutRegistry.registry.register(pasteShortcut); + ShortcutRegistry.registry.register(pasteShortcut); - var ctrlV = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.V, [Blockly.utils.KeyCodes.CTRL]); - Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlV, pasteShortcut.name); + const ctrlV = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.V, [KeyCodes.CTRL]); + ShortcutRegistry.registry.addKeyMapping(ctrlV, pasteShortcut.name); - var altV = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.V, [Blockly.utils.KeyCodes.ALT]); - Blockly.ShortcutRegistry.registry.addKeyMapping(altV, pasteShortcut.name); + const altV = + ShortcutRegistry.registry.createSerializedKey(KeyCodes.V, [KeyCodes.ALT]); + ShortcutRegistry.registry.addKeyMapping(altV, pasteShortcut.name); - var metaV = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.V, [Blockly.utils.KeyCodes.META]); - Blockly.ShortcutRegistry.registry.addKeyMapping(metaV, pasteShortcut.name); + const metaV = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.V, [KeyCodes.META]); + ShortcutRegistry.registry.addKeyMapping(metaV, pasteShortcut.name); }; +exports.registerPaste = registerPaste; /** Keyboard shortcut to undo the previous action on ctrl+z, cmd+z, or alt+z. */ -Blockly.ShortcutItems.registerUndo = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var undoShortcut = { - name: Blockly.ShortcutItems.names.UNDO, +const registerUndo = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const undoShortcut = { + name: names.UNDO, preconditionFn: function(workspace) { - return !workspace.options.readOnly && - !Blockly.Gesture.inProgress(); + return !workspace.options.readOnly && !Gesture.inProgress(); }, callback: function(workspace) { // 'z' for undo 'Z' is for redo. @@ -202,28 +199,32 @@ Blockly.ShortcutItems.registerUndo = function() { return true; } }; - Blockly.ShortcutRegistry.registry.register(undoShortcut); + ShortcutRegistry.registry.register(undoShortcut); - var ctrlZ = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Z, [Blockly.utils.KeyCodes.CTRL]); - Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlZ, undoShortcut.name); + const ctrlZ = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.Z, [KeyCodes.CTRL]); + ShortcutRegistry.registry.addKeyMapping(ctrlZ, undoShortcut.name); - var altZ = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Z, [Blockly.utils.KeyCodes.ALT]); - Blockly.ShortcutRegistry.registry.addKeyMapping(altZ, undoShortcut.name); + const altZ = + ShortcutRegistry.registry.createSerializedKey(KeyCodes.Z, [KeyCodes.ALT]); + ShortcutRegistry.registry.addKeyMapping(altZ, undoShortcut.name); - var metaZ = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Z, [Blockly.utils.KeyCodes.META]); - Blockly.ShortcutRegistry.registry.addKeyMapping(metaZ, undoShortcut.name); + const metaZ = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.Z, [KeyCodes.META]); + ShortcutRegistry.registry.addKeyMapping(metaZ, undoShortcut.name); }; +exports.registerUndo = registerUndo; -/** Keyboard shortcut to redo the previous action on ctrl+shift+z, cmd+shift+z, or alt+shift+z. */ -Blockly.ShortcutItems.registerRedo = function() { - /** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ - var redoShortcut = { - name: Blockly.ShortcutItems.names.REDO, +/** + * Keyboard shortcut to redo the previous action on ctrl+shift+z, cmd+shift+z, + * or alt+shift+z. + */ +const registerRedo = function() { + /** @type {!ShortcutRegistry.KeyboardShortcut} */ + const redoShortcut = { + name: names.REDO, preconditionFn: function(workspace) { - return !Blockly.Gesture.inProgress() && !workspace.options.readOnly; + return !Gesture.inProgress() && !workspace.options.readOnly; }, callback: function(workspace) { // 'z' for undo 'Z' is for redo. @@ -232,44 +233,41 @@ Blockly.ShortcutItems.registerRedo = function() { return true; } }; - Blockly.ShortcutRegistry.registry.register(redoShortcut); + ShortcutRegistry.registry.register(redoShortcut); - var ctrlShiftZ = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Z, - [Blockly.utils.KeyCodes.SHIFT, Blockly.utils.KeyCodes.CTRL]); - Blockly.ShortcutRegistry.registry.addKeyMapping( - ctrlShiftZ, redoShortcut.name); + const ctrlShiftZ = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.Z, [KeyCodes.SHIFT, KeyCodes.CTRL]); + ShortcutRegistry.registry.addKeyMapping(ctrlShiftZ, redoShortcut.name); - var altShiftZ = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Z, - [Blockly.utils.KeyCodes.SHIFT, Blockly.utils.KeyCodes.ALT]); - Blockly.ShortcutRegistry.registry.addKeyMapping(altShiftZ, redoShortcut.name); + const altShiftZ = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.Z, [KeyCodes.SHIFT, KeyCodes.ALT]); + ShortcutRegistry.registry.addKeyMapping(altShiftZ, redoShortcut.name); - var metaShiftZ = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Z, - [Blockly.utils.KeyCodes.SHIFT, Blockly.utils.KeyCodes.META]); - Blockly.ShortcutRegistry.registry.addKeyMapping( - metaShiftZ, redoShortcut.name); + const metaShiftZ = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.Z, [KeyCodes.SHIFT, KeyCodes.META]); + ShortcutRegistry.registry.addKeyMapping(metaShiftZ, redoShortcut.name); // Ctrl-y is redo in Windows. Command-y is never valid on Macs. - var ctrlY = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.Y, [Blockly.utils.KeyCodes.CTRL]); - Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlY, redoShortcut.name); + const ctrlY = ShortcutRegistry.registry.createSerializedKey( + KeyCodes.Y, [KeyCodes.CTRL]); + ShortcutRegistry.registry.addKeyMapping(ctrlY, redoShortcut.name); }; +exports.registerRedo = registerRedo; /** - * Registers all default keyboard shortcut item. This should be called once per instance of - * KeyboardShortcutRegistry. - * @package + * Registers all default keyboard shortcut item. This should be called once per + * instance of KeyboardShortcutRegistry. */ -Blockly.ShortcutItems.registerDefaultShortcuts = function() { - Blockly.ShortcutItems.registerEscape(); - Blockly.ShortcutItems.registerDelete(); - Blockly.ShortcutItems.registerCopy(); - Blockly.ShortcutItems.registerCut(); - Blockly.ShortcutItems.registerPaste(); - Blockly.ShortcutItems.registerUndo(); - Blockly.ShortcutItems.registerRedo(); +const registerDefaultShortcuts = function() { + registerEscape(); + registerDelete(); + registerCopy(); + registerCut(); + registerPaste(); + registerUndo(); + registerRedo(); }; +/** @package */ +exports.registerDefaultShortcuts = registerDefaultShortcuts; -Blockly.ShortcutItems.registerDefaultShortcuts(); +registerDefaultShortcuts(); diff --git a/core/theme.js b/core/theme.js index 182710f16..11c72e491 100644 --- a/core/theme.js +++ b/core/theme.js @@ -9,28 +9,27 @@ */ 'use strict'; -goog.provide('Blockly.Theme'); +goog.module('Blockly.Theme'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.registry'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.object'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); /** * Class for a theme. * @param {string} name Theme name. - * @param {!Object=} opt_blockStyles A map + * @param {!Object=} opt_blockStyles A map * from style names (strings) to objects with style attributes for blocks. - * @param {!Object=} opt_categoryStyles A + * @param {!Object=} opt_categoryStyles A * map from style names (strings) to objects with style attributes for * categories. - * @param {!Blockly.Theme.ComponentStyle=} opt_componentStyles A map of Blockly + * @param {!Theme.ComponentStyle=} opt_componentStyles A map of Blockly * component names to style value. * @constructor */ -Blockly.Theme = function(name, opt_blockStyles, opt_categoryStyles, - opt_componentStyles) { - +const Theme = function( + name, opt_blockStyles, opt_categoryStyles, opt_componentStyles) { /** * The theme name. This can be used to reference a specific theme in CSS. * @type {string} @@ -39,32 +38,32 @@ Blockly.Theme = function(name, opt_blockStyles, opt_categoryStyles, /** * The block styles map. - * @type {!Object} + * @type {!Object} * @package */ this.blockStyles = opt_blockStyles || Object.create(null); /** * The category styles map. - * @type {!Object} + * @type {!Object} * @package */ this.categoryStyles = opt_categoryStyles || Object.create(null); /** * The UI components styles map. - * @type {!Blockly.Theme.ComponentStyle} + * @type {!Theme.ComponentStyle} * @package */ this.componentStyles = opt_componentStyles || - (/** @type {Blockly.Theme.ComponentStyle} */ (Object.create(null))); + (/** @type {Theme.ComponentStyle} */ (Object.create(null))); /** * The font style. - * @type {!Blockly.Theme.FontStyle} + * @type {!Theme.FontStyle} * @package */ - this.fontStyle = /** @type {Blockly.Theme.FontStyle} */ (Object.create(null)); + this.fontStyle = /** @type {Theme.FontStyle} */ (Object.create(null)); /** * Whether or not to add a 'hat' on top of all blocks with no previous or @@ -75,7 +74,7 @@ Blockly.Theme = function(name, opt_blockStyles, opt_categoryStyles, this.startHats = null; // Register the theme by name. - Blockly.registry.register(Blockly.registry.Type.THEME, name, this); + registry.register(registry.Type.THEME, name, this); }; /** @@ -87,7 +86,7 @@ Blockly.Theme = function(name, opt_blockStyles, opt_categoryStyles, * hat:string * }} */ -Blockly.Theme.BlockStyle; +Theme.BlockStyle; /** * A category style. @@ -95,7 +94,7 @@ Blockly.Theme.BlockStyle; * colour:string * }} */ -Blockly.Theme.CategoryStyle; +Theme.CategoryStyle; /** * A component style. @@ -118,7 +117,7 @@ Blockly.Theme.CategoryStyle; * replacementGlowOpacity:?number * }} */ -Blockly.Theme.ComponentStyle; +Theme.ComponentStyle; /** * A font style. @@ -128,33 +127,32 @@ Blockly.Theme.ComponentStyle; * size:?number * }} */ -Blockly.Theme.FontStyle; +Theme.FontStyle; /** * Gets the class name that identifies this theme. * @return {string} The CSS class name. * @package */ -Blockly.Theme.prototype.getClassName = function() { +Theme.prototype.getClassName = function() { return this.name + '-theme'; }; /** * Overrides or adds a style to the blockStyles map. * @param {string} blockStyleName The name of the block style. - * @param {Blockly.Theme.BlockStyle} blockStyle The block style. -*/ -Blockly.Theme.prototype.setBlockStyle = function(blockStyleName, blockStyle) { + * @param {Theme.BlockStyle} blockStyle The block style. + */ +Theme.prototype.setBlockStyle = function(blockStyleName, blockStyle) { this.blockStyles[blockStyleName] = blockStyle; }; /** * Overrides or adds a style to the categoryStyles map. * @param {string} categoryStyleName The name of the category style. - * @param {Blockly.Theme.CategoryStyle} categoryStyle The category style. -*/ -Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName, - categoryStyle) { + * @param {Theme.CategoryStyle} categoryStyle The category style. + */ +Theme.prototype.setCategoryStyle = function(categoryStyleName, categoryStyle) { this.categoryStyles[categoryStyleName] = categoryStyle; }; @@ -164,8 +162,8 @@ Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName, * @param {string} componentName The name of the component. * @return {?string} The style value. */ -Blockly.Theme.prototype.getComponentStyle = function(componentName) { - var style = this.componentStyles[componentName]; +Theme.prototype.getComponentStyle = function(componentName) { + const style = this.componentStyles[componentName]; if (style && typeof style == 'string' && this.getComponentStyle(/** @type {string} */ (style))) { return this.getComponentStyle(/** @type {string} */ (style)); @@ -177,17 +175,16 @@ Blockly.Theme.prototype.getComponentStyle = function(componentName) { * Configure a specific Blockly UI component with a style value. * @param {string} componentName The name of the component. * @param {*} styleValue The style value. -*/ -Blockly.Theme.prototype.setComponentStyle = function(componentName, - styleValue) { + */ +Theme.prototype.setComponentStyle = function(componentName, styleValue) { this.componentStyles[componentName] = styleValue; }; /** * Configure a theme's font style. - * @param {Blockly.Theme.FontStyle} fontStyle The font style. -*/ -Blockly.Theme.prototype.setFontStyle = function(fontStyle) { + * @param {Theme.FontStyle} fontStyle The font style. + */ +Theme.prototype.setFontStyle = function(fontStyle) { this.fontStyle = fontStyle; }; @@ -195,8 +192,8 @@ Blockly.Theme.prototype.setFontStyle = function(fontStyle) { * Configure a theme's start hats. * @param {boolean} startHats True if the theme enables start hats, false * otherwise. -*/ -Blockly.Theme.prototype.setStartHats = function(startHats) { + */ +Theme.prototype.setStartHats = function(startHats) { this.startHats = startHats; }; @@ -204,32 +201,30 @@ Blockly.Theme.prototype.setStartHats = function(startHats) { * Define a new Blockly theme. * @param {string} name The name of the theme. * @param {!Object} themeObj An object containing theme properties. - * @return {!Blockly.Theme} A new Blockly theme. -*/ -Blockly.Theme.defineTheme = function(name, themeObj) { - var theme = new Blockly.Theme(name); - var base = themeObj['base']; + * @return {!Theme} A new Blockly theme. + */ +Theme.defineTheme = function(name, themeObj) { + const theme = new Theme(name); + let base = themeObj['base']; if (base) { - if (typeof base == "string") { - base = Blockly.registry.getObject(Blockly.registry.Type.THEME, base); + if (typeof base == 'string') { + base = registry.getObject(registry.Type.THEME, base); } - if (base instanceof Blockly.Theme) { - Blockly.utils.object.deepMerge(theme, base); + if (base instanceof Theme) { + object.deepMerge(theme, base); theme.name = name; } } - Blockly.utils.object.deepMerge(theme.blockStyles, - themeObj['blockStyles']); - Blockly.utils.object.deepMerge(theme.categoryStyles, - themeObj['categoryStyles']); - Blockly.utils.object.deepMerge(theme.componentStyles, - themeObj['componentStyles']); - Blockly.utils.object.deepMerge(theme.fontStyle, - themeObj['fontStyle']); + object.deepMerge(theme.blockStyles, themeObj['blockStyles']); + object.deepMerge(theme.categoryStyles, themeObj['categoryStyles']); + object.deepMerge(theme.componentStyles, themeObj['componentStyles']); + object.deepMerge(theme.fontStyle, themeObj['fontStyle']); if (themeObj['startHats'] != null) { theme.startHats = themeObj['startHats']; } return theme; }; + +exports = Theme; diff --git a/core/toolbox/category.js b/core/toolbox/category.js index ae9755cad..962a5cb85 100644 --- a/core/toolbox/category.js +++ b/core/toolbox/category.js @@ -10,34 +10,39 @@ */ 'use strict'; -goog.provide('Blockly.ToolboxCategory'); +goog.module('Blockly.ToolboxCategory'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.ISelectableToolboxItem'); -goog.require('Blockly.registry'); -goog.require('Blockly.ToolboxItem'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.aria'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.toolbox'); - -goog.requireType('Blockly.ICollapsibleToolboxItem'); -goog.requireType('Blockly.IToolbox'); +const Blockly = goog.require('Blockly'); +const Css = goog.require('Blockly.Css'); +/* eslint-disable-next-line no-unused-vars */ +const ICollapsibleToolboxItem = goog.requireType('Blockly.ICollapsibleToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const ISelectableToolboxItem = goog.requireType('Blockly.ISelectableToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +const ToolboxItem = goog.require('Blockly.ToolboxItem'); +const aria = goog.require('Blockly.utils.aria'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); +const toolbox = goog.require('Blockly.utils.toolbox'); +const utils = goog.require('Blockly.utils'); /** * Class for a category in a toolbox. - * @param {!Blockly.utils.toolbox.CategoryInfo} categoryDef The information needed + * @param {!toolbox.CategoryInfo} categoryDef The information needed * to create a category in the toolbox. - * @param {!Blockly.IToolbox} toolbox The parent toolbox for the category. - * @param {Blockly.ICollapsibleToolboxItem=} opt_parent The parent category or null if + * @param {!IToolbox} toolbox The parent toolbox for the category. + * @param {ICollapsibleToolboxItem=} opt_parent The parent category or null if * the category does not have a parent. * @constructor - * @extends {Blockly.ToolboxItem} - * @implements {Blockly.ISelectableToolboxItem} + * @extends {ToolboxItem} + * @implements {ISelectableToolboxItem} */ -Blockly.ToolboxCategory = function(categoryDef, toolbox, opt_parent) { - Blockly.ToolboxCategory.superClass_.constructor.call( +const ToolboxCategory = function(categoryDef, toolbox, opt_parent) { + ToolboxCategory.superClass_.constructor.call( this, categoryDef, toolbox, opt_parent); /** @@ -45,7 +50,7 @@ Blockly.ToolboxCategory = function(categoryDef, toolbox, opt_parent) { * @type {string} * @protected */ - this.name_ = Blockly.utils.replaceMessageReferences(categoryDef['name']); + this.name_ = utils.replaceMessageReferences(categoryDef['name']); /** * The colour of the category. @@ -91,13 +96,13 @@ Blockly.ToolboxCategory = function(categoryDef, toolbox, opt_parent) { /** * All the css class names that are used to create a category. - * @type {!Blockly.ToolboxCategory.CssConfig} + * @type {!ToolboxCategory.CssConfig} * @protected */ this.cssConfig_ = this.makeDefaultCssConfig_(); - var cssConfig = categoryDef['cssconfig'] || categoryDef['cssConfig']; - Blockly.utils.object.mixin(this.cssConfig_, cssConfig); + const cssConfig = categoryDef['cssconfig'] || categoryDef['cssConfig']; + object.mixin(this.cssConfig_, cssConfig); /** * True if the category is meant to be hidden, false otherwise. @@ -115,7 +120,7 @@ Blockly.ToolboxCategory = function(categoryDef, toolbox, opt_parent) { /** * The flyout items for this category. - * @type {string|!Blockly.utils.toolbox.FlyoutItemInfoArray} + * @type {string|!toolbox.FlyoutItemInfoArray} * @protected */ this.flyoutItems_ = []; @@ -123,7 +128,7 @@ Blockly.ToolboxCategory = function(categoryDef, toolbox, opt_parent) { this.parseContents_(categoryDef); }; -Blockly.utils.object.inherits(Blockly.ToolboxCategory, Blockly.ToolboxItem); +object.inherits(ToolboxCategory, ToolboxItem); /** * All the CSS class names that are used to create a category. @@ -138,40 +143,40 @@ Blockly.utils.object.inherits(Blockly.ToolboxCategory, Blockly.ToolboxItem); * closedicon:(string|undefined) * }} */ -Blockly.ToolboxCategory.CssConfig; +ToolboxCategory.CssConfig; /** * Name used for registering a toolbox category. * @const {string} */ -Blockly.ToolboxCategory.registrationName = 'category'; +ToolboxCategory.registrationName = 'category'; /** * The number of pixels to move the category over at each nested level. * @type {number} */ -Blockly.ToolboxCategory.nestedPadding = 19; +ToolboxCategory.nestedPadding = 19; /** * The width in pixels of the strip of colour next to each category. * @type {number} */ -Blockly.ToolboxCategory.borderWidth = 8; +ToolboxCategory.borderWidth = 8; /** * The default colour of the category. This is used as the background colour of * the category when it is selected. * @type {string} */ -Blockly.ToolboxCategory.defaultBackgroundColour = '#57e'; +ToolboxCategory.defaultBackgroundColour = '#57e'; /** * Creates an object holding the default classes for a category. - * @return {!Blockly.ToolboxCategory.CssConfig} The configuration object holding + * @return {!ToolboxCategory.CssConfig} The configuration object holding * all the CSS classes for a category. * @protected */ -Blockly.ToolboxCategory.prototype.makeDefaultCssConfig_ = function() { +ToolboxCategory.prototype.makeDefaultCssConfig_ = function() { return { 'container': 'blocklyToolboxCategory', 'row': 'blocklyTreeRow', @@ -188,18 +193,20 @@ Blockly.ToolboxCategory.prototype.makeDefaultCssConfig_ = function() { /** * Parses the contents array depending on if the category is a dynamic category, * or if its contents are meant to be shown in the flyout. - * @param {!Blockly.utils.toolbox.CategoryInfo} categoryDef The information needed + * @param {!toolbox.CategoryInfo} categoryDef The information needed * to create a category. * @protected */ -Blockly.ToolboxCategory.prototype.parseContents_ = function(categoryDef) { - var contents = categoryDef['contents']; +ToolboxCategory.prototype.parseContents_ = function(categoryDef) { + const contents = categoryDef['contents']; if (categoryDef['custom']) { this.flyoutItems_ = categoryDef['custom']; } else if (contents) { - for (var i = 0, itemDef; (itemDef = contents[i]); i++) { - var flyoutItem = /** @type {Blockly.utils.toolbox.FlyoutItemInfo} */ (itemDef); + for (let i = 0; i < contents.length; i++) { + const itemDef = contents[i]; + const flyoutItem = + /** @type {Blockly.utils.toolbox.FlyoutItemInfo} */ (itemDef); this.flyoutItems_.push(flyoutItem); } } @@ -208,7 +215,7 @@ Blockly.ToolboxCategory.prototype.parseContents_ = function(categoryDef) { /** * @override */ -Blockly.ToolboxCategory.prototype.init = function() { +ToolboxCategory.prototype.init = function() { this.createDom_(); if (this.toolboxItemDef_['hidden'] == 'true') { this.hide(); @@ -220,13 +227,13 @@ Blockly.ToolboxCategory.prototype.init = function() { * @return {!Element} The parent element for the category. * @protected */ -Blockly.ToolboxCategory.prototype.createDom_ = function() { +ToolboxCategory.prototype.createDom_ = function() { this.htmlDiv_ = this.createContainer_(); - Blockly.utils.aria.setRole(this.htmlDiv_, Blockly.utils.aria.Role.TREEITEM); - Blockly.utils.aria.setState(/** @type {!Element} */ (this.htmlDiv_), - Blockly.utils.aria.State.SELECTED,false); - Blockly.utils.aria.setState(/** @type {!Element} */ (this.htmlDiv_), - Blockly.utils.aria.State.LEVEL, this.level_); + aria.setRole(this.htmlDiv_, aria.Role.TREEITEM); + aria.setState( + /** @type {!Element} */ (this.htmlDiv_), aria.State.SELECTED, false); + aria.setState( + /** @type {!Element} */ (this.htmlDiv_), aria.State.LEVEL, this.level_); this.rowDiv_ = this.createRowContainer_(); this.rowDiv_.style.pointerEvents = 'auto'; @@ -237,13 +244,14 @@ Blockly.ToolboxCategory.prototype.createDom_ = function() { this.rowDiv_.appendChild(this.rowContents_); this.iconDom_ = this.createIconDom_(); - Blockly.utils.aria.setRole(this.iconDom_, Blockly.utils.aria.Role.PRESENTATION); + aria.setRole(this.iconDom_, aria.Role.PRESENTATION); this.rowContents_.appendChild(this.iconDom_); this.labelDom_ = this.createLabelDom_(this.name_); this.rowContents_.appendChild(this.labelDom_); - Blockly.utils.aria.setState(/** @type {!Element} */ (this.htmlDiv_), - Blockly.utils.aria.State.LABELLEDBY, this.labelDom_.getAttribute('id')); + aria.setState( + /** @type {!Element} */ (this.htmlDiv_), aria.State.LABELLEDBY, + this.labelDom_.getAttribute('id')); this.addColourBorder_(this.colour_); @@ -255,9 +263,9 @@ Blockly.ToolboxCategory.prototype.createDom_ = function() { * @return {!Element} The div that holds the icon and the label. * @protected */ -Blockly.ToolboxCategory.prototype.createContainer_ = function() { - var container = document.createElement('div'); - Blockly.utils.dom.addClass(container, this.cssConfig_['container']); +ToolboxCategory.prototype.createContainer_ = function() { + const container = document.createElement('div'); + dom.addClass(container, this.cssConfig_['container']); return container; }; @@ -267,13 +275,13 @@ Blockly.ToolboxCategory.prototype.createContainer_ = function() { * @return {!Element} The div that holds the contents container. * @protected */ -Blockly.ToolboxCategory.prototype.createRowContainer_ = function() { - var rowDiv = document.createElement('div'); - Blockly.utils.dom.addClass(rowDiv, this.cssConfig_['row']); - var nestedPadding = Blockly.ToolboxCategory.nestedPadding * this.getLevel(); +ToolboxCategory.prototype.createRowContainer_ = function() { + const rowDiv = document.createElement('div'); + dom.addClass(rowDiv, this.cssConfig_['row']); + let nestedPadding = ToolboxCategory.nestedPadding * this.getLevel(); nestedPadding = nestedPadding.toString() + 'px'; this.workspace_.RTL ? rowDiv.style.paddingRight = nestedPadding : - rowDiv.style.paddingLeft = nestedPadding; + rowDiv.style.paddingLeft = nestedPadding; return rowDiv; }; @@ -283,9 +291,9 @@ Blockly.ToolboxCategory.prototype.createRowContainer_ = function() { * @return {!Element} The div that holds the icon and the label. * @protected */ -Blockly.ToolboxCategory.prototype.createRowContentsContainer_ = function() { - var contentsContainer = document.createElement('div'); - Blockly.utils.dom.addClass(contentsContainer, this.cssConfig_['rowcontentcontainer']); +ToolboxCategory.prototype.createRowContentsContainer_ = function() { + const contentsContainer = document.createElement('div'); + dom.addClass(contentsContainer, this.cssConfig_['rowcontentcontainer']); return contentsContainer; }; @@ -294,10 +302,10 @@ Blockly.ToolboxCategory.prototype.createRowContentsContainer_ = function() { * @return {!Element} The span that holds the category icon. * @protected */ -Blockly.ToolboxCategory.prototype.createIconDom_ = function() { - var toolboxIcon = document.createElement('span'); +ToolboxCategory.prototype.createIconDom_ = function() { + const toolboxIcon = document.createElement('span'); if (!this.parentToolbox_.isHorizontal()) { - Blockly.utils.dom.addClass(toolboxIcon, this.cssConfig_['icon']); + dom.addClass(toolboxIcon, this.cssConfig_['icon']); } toolboxIcon.style.display = 'inline-block'; @@ -311,11 +319,11 @@ Blockly.ToolboxCategory.prototype.createIconDom_ = function() { * @return {!Element} The span that holds the category label. * @protected */ -Blockly.ToolboxCategory.prototype.createLabelDom_ = function(name) { - var toolboxLabel = document.createElement('span'); +ToolboxCategory.prototype.createLabelDom_ = function(name) { + const toolboxLabel = document.createElement('span'); toolboxLabel.setAttribute('id', this.getId() + '.label'); toolboxLabel.textContent = name; - Blockly.utils.dom.addClass(toolboxLabel, this.cssConfig_['label']); + dom.addClass(toolboxLabel, this.cssConfig_['label']); return toolboxLabel; }; @@ -323,9 +331,9 @@ Blockly.ToolboxCategory.prototype.createLabelDom_ = function(name) { * Updates the colour for this category. * @public */ -Blockly.ToolboxCategory.prototype.refreshTheme = function() { - this.colour_ = this.getColour_(/** @type {Blockly.utils.toolbox.CategoryInfo} **/ - (this.toolboxItemDef_)); +ToolboxCategory.prototype.refreshTheme = function() { + this.colour_ = this.getColour_(/** @type {toolbox.CategoryInfo} **/ + (this.toolboxItemDef_)); this.addColourBorder_(this.colour_); }; @@ -334,10 +342,10 @@ Blockly.ToolboxCategory.prototype.refreshTheme = function() { * @param {string} colour The category colour. * @protected */ -Blockly.ToolboxCategory.prototype.addColourBorder_ = function(colour) { +ToolboxCategory.prototype.addColourBorder_ = function(colour) { if (colour) { - var border = Blockly.ToolboxCategory.borderWidth + 'px solid ' + - (colour || '#ddd'); + const border = + ToolboxCategory.borderWidth + 'px solid ' + (colour || '#ddd'); if (this.workspace_.RTL) { this.rowDiv_.style.borderRight = border; } else { @@ -348,17 +356,19 @@ Blockly.ToolboxCategory.prototype.addColourBorder_ = function(colour) { /** * Gets either the colour or the style for a category. - * @param {!Blockly.utils.toolbox.CategoryInfo} categoryDef The object holding + * @param {!toolbox.CategoryInfo} categoryDef The object holding * information on the category. * @return {string} The hex colour for the category. * @protected */ -Blockly.ToolboxCategory.prototype.getColour_ = function(categoryDef) { - var styleName = categoryDef['categorystyle'] || categoryDef['categoryStyle']; - var colour = categoryDef['colour']; +ToolboxCategory.prototype.getColour_ = function(categoryDef) { + const styleName = + categoryDef['categorystyle'] || categoryDef['categoryStyle']; + const colour = categoryDef['colour']; if (colour && styleName) { - console.warn('Toolbox category "' + this.name_ + + console.warn( + 'Toolbox category "' + this.name_ + '" must not have both a style and a colour'); } else if (styleName) { return this.getColourfromStyle_(styleName); @@ -375,15 +385,15 @@ Blockly.ToolboxCategory.prototype.getColour_ = function(categoryDef) { * @return {string} The hex colour for the category. * @private */ -Blockly.ToolboxCategory.prototype.getColourfromStyle_ = function(styleName) { - var theme = this.workspace_.getTheme(); +ToolboxCategory.prototype.getColourfromStyle_ = function(styleName) { + const theme = this.workspace_.getTheme(); if (styleName && theme) { - var style = theme.categoryStyles[styleName]; + const style = theme.categoryStyles[styleName]; if (style && style.colour) { return this.parseColour_(style.colour); } else { - console.warn('Style "' + styleName + - '" must exist and contain a colour value'); + console.warn( + 'Style "' + styleName + '" must exist and contain a colour value'); } } return ''; @@ -396,8 +406,8 @@ Blockly.ToolboxCategory.prototype.getColourfromStyle_ = function(styleName) { * @return {!Element} The HTML element that receives clicks. * @public */ -Blockly.ToolboxCategory.prototype.getClickTarget = function() { - return /** @type {!Element} */(this.rowDiv_); +ToolboxCategory.prototype.getClickTarget = function() { + return /** @type {!Element} */ (this.rowDiv_); }; /** @@ -407,23 +417,24 @@ Blockly.ToolboxCategory.prototype.getClickTarget = function() { * @return {string} The hex colour for the category. * @private */ -Blockly.ToolboxCategory.prototype.parseColour_ = function(colourValue) { +ToolboxCategory.prototype.parseColour_ = function(colourValue) { // Decode the colour for any potential message references // (eg. `%{BKY_MATH_HUE}`). - var colour = Blockly.utils.replaceMessageReferences(colourValue); + const colour = utils.replaceMessageReferences(colourValue); if (colour == null || colour === '') { // No attribute. No colour. return ''; } else { - var hue = Number(colour); + const hue = Number(colour); if (!isNaN(hue)) { return Blockly.hueToHex(hue); } else { - var hex = Blockly.utils.colour.parse(colour); + const hex = utils.colour.parse(colour); if (hex) { return hex; } else { - console.warn('Toolbox category "' + this.name_ + + console.warn( + 'Toolbox category "' + this.name_ + '" has unrecognized colour attribute: ' + colour); return ''; } @@ -436,12 +447,12 @@ Blockly.ToolboxCategory.prototype.parseColour_ = function(colourValue) { * @param {?Element} iconDiv The div that holds the icon. * @protected */ -Blockly.ToolboxCategory.prototype.openIcon_ = function(iconDiv) { +ToolboxCategory.prototype.openIcon_ = function(iconDiv) { if (!iconDiv) { return; } - Blockly.utils.dom.removeClasses(iconDiv, this.cssConfig_['closedicon']); - Blockly.utils.dom.addClass(iconDiv, this.cssConfig_['openicon']); + dom.removeClasses(iconDiv, this.cssConfig_['closedicon']); + dom.addClass(iconDiv, this.cssConfig_['openicon']); }; /** @@ -449,12 +460,12 @@ Blockly.ToolboxCategory.prototype.openIcon_ = function(iconDiv) { * @param {?Element} iconDiv The div that holds the icon. * @protected */ -Blockly.ToolboxCategory.prototype.closeIcon_ = function(iconDiv) { +ToolboxCategory.prototype.closeIcon_ = function(iconDiv) { if (!iconDiv) { return; } - Blockly.utils.dom.removeClasses(iconDiv, this.cssConfig_['openicon']); - Blockly.utils.dom.addClass(iconDiv, this.cssConfig_['closedicon']); + dom.removeClasses(iconDiv, this.cssConfig_['openicon']); + dom.addClass(iconDiv, this.cssConfig_['closedicon']); }; /** @@ -463,7 +474,7 @@ Blockly.ToolboxCategory.prototype.closeIcon_ = function(iconDiv) { * @param {boolean} isVisible True if category should be visible. * @protected */ -Blockly.ToolboxCategory.prototype.setVisible_ = function(isVisible) { +ToolboxCategory.prototype.setVisible_ = function(isVisible) { this.htmlDiv_.style.display = isVisible ? 'block' : 'none'; this.isHidden_ = !isVisible; @@ -475,7 +486,7 @@ Blockly.ToolboxCategory.prototype.setVisible_ = function(isVisible) { /** * Hide the category. */ -Blockly.ToolboxCategory.prototype.hide = function() { +ToolboxCategory.prototype.hide = function() { this.setVisible_(false); }; @@ -483,27 +494,29 @@ Blockly.ToolboxCategory.prototype.hide = function() { * Show the category. Category will only appear if its parent category is also * expanded. */ -Blockly.ToolboxCategory.prototype.show = function() { +ToolboxCategory.prototype.show = function() { this.setVisible_(true); }; /** * Whether the category is visible. - * A category is only visible if all of its ancestors are expanded and isHidden_ is false. + * A category is only visible if all of its ancestors are expanded and isHidden_ + * is false. * @return {boolean} True if the category is visible, false otherwise. * @public */ -Blockly.ToolboxCategory.prototype.isVisible = function() { +ToolboxCategory.prototype.isVisible = function() { return !this.isHidden_ && this.allAncestorsExpanded_(); }; /** - * Whether all ancestors of a category (parent and parent's parent, etc.) are expanded. + * Whether all ancestors of a category (parent and parent's parent, etc.) are + * expanded. * @return {boolean} True only if every ancestor is expanded * @protected */ -Blockly.ToolboxCategory.prototype.allAncestorsExpanded_ = function() { - var category = this; +ToolboxCategory.prototype.allAncestorsExpanded_ = function() { + let category = this; while (category.getParent()) { category = category.getParent(); if (!category.isExpanded()) { @@ -516,7 +529,7 @@ Blockly.ToolboxCategory.prototype.allAncestorsExpanded_ = function() { /** * @override */ -Blockly.ToolboxCategory.prototype.isSelectable = function() { +ToolboxCategory.prototype.isSelectable = function() { return this.isVisible() && !this.isDisabled_; }; @@ -525,7 +538,7 @@ Blockly.ToolboxCategory.prototype.isSelectable = function() { * @param {!Event} _e Click event to handle. * @public */ -Blockly.ToolboxCategory.prototype.onClick = function(_e) { +ToolboxCategory.prototype.onClick = function(_e) { // No-op }; @@ -535,29 +548,29 @@ Blockly.ToolboxCategory.prototype.onClick = function(_e) { * otherwise. * @public */ -Blockly.ToolboxCategory.prototype.setSelected = function(isSelected) { +ToolboxCategory.prototype.setSelected = function(isSelected) { if (isSelected) { - var defaultColour = this.parseColour_( - Blockly.ToolboxCategory.defaultBackgroundColour); + const defaultColour = + this.parseColour_(ToolboxCategory.defaultBackgroundColour); this.rowDiv_.style.backgroundColor = this.colour_ || defaultColour; - Blockly.utils.dom.addClass(this.rowDiv_, this.cssConfig_['selected']); + dom.addClass(this.rowDiv_, this.cssConfig_['selected']); } else { this.rowDiv_.style.backgroundColor = ''; - Blockly.utils.dom.removeClass(this.rowDiv_, this.cssConfig_['selected']); + dom.removeClass(this.rowDiv_, this.cssConfig_['selected']); } - Blockly.utils.aria.setState(/** @type {!Element} */ (this.htmlDiv_), - Blockly.utils.aria.State.SELECTED, isSelected); + aria.setState( + /** @type {!Element} */ (this.htmlDiv_), aria.State.SELECTED, isSelected); }; /** * Sets whether the category is disabled. * @param {boolean} isDisabled True to disable the category, false otherwise. */ -Blockly.ToolboxCategory.prototype.setDisabled = function(isDisabled) { +ToolboxCategory.prototype.setDisabled = function(isDisabled) { this.isDisabled_ = isDisabled; this.getDiv().setAttribute('disabled', isDisabled); isDisabled ? this.getDiv().setAttribute('disabled', 'true') : - this.getDiv().removeAttribute('disabled'); + this.getDiv().removeAttribute('disabled'); }; /** @@ -565,32 +578,32 @@ Blockly.ToolboxCategory.prototype.setDisabled = function(isDisabled) { * @return {string} The name of the toolbox item. * @public */ -Blockly.ToolboxCategory.prototype.getName = function() { +ToolboxCategory.prototype.getName = function() { return this.name_; }; /** * @override */ -Blockly.ToolboxCategory.prototype.getParent = function() { +ToolboxCategory.prototype.getParent = function() { return this.parent_; }; /** * @override */ -Blockly.ToolboxCategory.prototype.getDiv = function() { +ToolboxCategory.prototype.getDiv = function() { return this.htmlDiv_; }; /** * Gets the contents of the category. These are items that are meant to be * displayed in the flyout. - * @return {!Blockly.utils.toolbox.FlyoutItemInfoArray|string} The definition + * @return {!toolbox.FlyoutItemInfoArray|string} The definition * of items to be displayed in the flyout. * @public */ -Blockly.ToolboxCategory.prototype.getContents = function() { +ToolboxCategory.prototype.getContents = function() { return this.flyoutItems_; }; @@ -598,12 +611,12 @@ Blockly.ToolboxCategory.prototype.getContents = function() { * Updates the contents to be displayed in the flyout. * If the flyout is open when the contents are updated, refreshSelection on the * toolbox must also be called. - * @param {!Blockly.utils.toolbox.FlyoutDefinition|string} contents The contents + * @param {!toolbox.FlyoutDefinition|string} contents The contents * to be displayed in the flyout. A string can be supplied to create a * dynamic category. * @public */ -Blockly.ToolboxCategory.prototype.updateFlyoutContents = function(contents) { +ToolboxCategory.prototype.updateFlyoutContents = function(contents) { this.flyoutItems_ = []; if (typeof contents == 'string') { @@ -612,97 +625,98 @@ Blockly.ToolboxCategory.prototype.updateFlyoutContents = function(contents) { // Removes old custom field when contents is updated. delete this.toolboxItemDef_['custom']; this.toolboxItemDef_['contents'] = - Blockly.utils.toolbox.convertFlyoutDefToJsonArray(contents); + toolbox.convertFlyoutDefToJsonArray(contents); } this.parseContents_( - /** @type {Blockly.utils.toolbox.CategoryInfo} */ (this.toolboxItemDef_)); + /** @type {toolbox.CategoryInfo} */ (this.toolboxItemDef_)); }; /** * @override */ -Blockly.ToolboxCategory.prototype.dispose = function() { - Blockly.utils.dom.removeNode(this.htmlDiv_); +ToolboxCategory.prototype.dispose = function() { + dom.removeNode(this.htmlDiv_); }; /** * CSS for Toolbox. See css.js for use. */ -Blockly.Css.register([ - /* eslint-disable indent */ - '.blocklyTreeRow:not(.blocklyTreeSelected):hover {', - 'background-color: rgba(255, 255, 255, 0.2);', - '}', +Css.register([ + `.blocklyTreeRow:not(.blocklyTreeSelected):hover { + background-color: rgba(255, 255, 255, 0.2); +}`, - '.blocklyToolboxDiv[layout="h"] .blocklyToolboxCategory {', - 'margin: 1px 5px 1px 0;', - '}', + `.blocklyToolboxDiv[layout="h"] .blocklyToolboxCategory { + margin: 1px 5px 1px 0; +}`, - '.blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategory {', - 'margin: 1px 0 1px 5px;', - '}', + `.blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategory { + margin: 1px 0 1px 5px; +}`, - '.blocklyTreeRow {', - 'height: 22px;', - 'line-height: 22px;', - 'margin-bottom: 3px;', - 'padding-right: 8px;', - 'white-space: nowrap;', - '}', + `.blocklyTreeRow { + height: 22px; + line-height: 22px; + margin-bottom: 3px; + padding-right: 8px; + white-space: nowrap; +}`, - '.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {', - 'margin-left: 8px;', - 'padding-right: 0', - '}', + `.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow { + margin-left: 8px; + padding-right: 0; +}`, - '.blocklyTreeIcon {', - 'background-image: url(<<>>/sprites.png);', - 'height: 16px;', - 'vertical-align: middle;', - 'visibility: hidden;', - 'width: 16px;', - '}', + `.blocklyTreeIcon {', + background-image: url(<<>>/sprites.png); + height: 16px; + vertical-align: middle; + visibility: hidden; + width: 16px; +}`, - '.blocklyTreeIconClosed {', - 'background-position: -32px -1px;', - '}', + `.blocklyTreeIconClosed { + background-position: -32px -1px; +}`, - '.blocklyToolboxDiv[dir="RTL"] .blocklyTreeIconClosed {', - 'background-position: 0 -1px;', - '}', + `.blocklyToolboxDiv[dir="RTL"] .blocklyTreeIconClosed { + background-position: 0 -1px; +}`, - '.blocklyTreeSelected>.blocklyTreeIconClosed {', - 'background-position: -32px -17px;', - '}', + `.blocklyTreeSelected>.blocklyTreeIconClosed { + background-position: -32px -17px; +}`, - '.blocklyToolboxDiv[dir="RTL"] .blocklyTreeSelected>.blocklyTreeIconClosed {', - 'background-position: 0 -17px;', - '}', + `.blocklyToolboxDiv[dir="RTL"] .blocklyTreeSelected>.blocklyTreeIconClosed { + background-position: 0 -17px; +}`, - '.blocklyTreeIconOpen {', - 'background-position: -16px -1px;', - '}', + `.blocklyTreeIconOpen { + background-position: -16px -1px; +}`, - '.blocklyTreeSelected>.blocklyTreeIconOpen {', - 'background-position: -16px -17px;', - '}', + `.blocklyTreeSelected>.blocklyTreeIconOpen { + background-position: -16px -17px; +}`, - '.blocklyTreeLabel {', - 'cursor: default;', - 'font: 16px sans-serif;', - 'padding: 0 3px;', - 'vertical-align: middle;', - '}', + `.blocklyTreeLabel { + cursor: default; + font: 16px sans-serif; + padding: 0 3px; + vertical-align: middle; +}`, - '.blocklyToolboxDelete .blocklyTreeLabel {', - 'cursor: url("<<>>/handdelete.cur"), auto;', - '}', + `.blocklyToolboxDelete .blocklyTreeLabel { + cursor: url("<<>>/handdelete.cur"), auto; +}`, - '.blocklyTreeSelected .blocklyTreeLabel {', - 'color: #fff;', - '}' - /* eslint-enable indent */ + `.blocklyTreeSelected .blocklyTreeLabel { + color: #fff; +}` ]); -Blockly.registry.register(Blockly.registry.Type.TOOLBOX_ITEM, - Blockly.ToolboxCategory.registrationName, Blockly.ToolboxCategory); +registry.register( + registry.Type.TOOLBOX_ITEM, ToolboxCategory.registrationName, + ToolboxCategory); + +exports = ToolboxCategory; diff --git a/core/toolbox/collapsible_category.js b/core/toolbox/collapsible_category.js index 979931848..923d681b2 100644 --- a/core/toolbox/collapsible_category.js +++ b/core/toolbox/collapsible_category.js @@ -10,34 +10,36 @@ */ 'use strict'; -goog.provide('Blockly.CollapsibleToolboxCategory'); +goog.module('Blockly.CollapsibleToolboxCategory'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.ICollapsibleToolboxItem'); -goog.require('Blockly.registry'); -goog.require('Blockly.ToolboxCategory'); -goog.require('Blockly.ToolboxItem'); -goog.require('Blockly.ToolboxSeparator'); -goog.require('Blockly.utils.aria'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.toolbox'); - -goog.requireType('Blockly.IToolbox'); -goog.requireType('Blockly.IToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const ICollapsibleToolboxItem = goog.requireType('Blockly.ICollapsibleToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +/* eslint-disable-next-line no-unused-vars */ +const IToolboxItem = goog.requireType('Blockly.IToolboxItem'); +const ToolboxCategory = goog.require('Blockly.ToolboxCategory'); +const ToolboxSeparator = goog.require('Blockly.ToolboxSeparator'); +const aria = goog.require('Blockly.utils.aria'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); +const toolbox = goog.require('Blockly.utils.toolbox'); /** * Class for a category in a toolbox that can be collapsed. - * @param {!Blockly.utils.toolbox.CategoryInfo} categoryDef The information needed + * @param {!toolbox.CategoryInfo} categoryDef The information needed * to create a category in the toolbox. - * @param {!Blockly.IToolbox} toolbox The parent toolbox for the category. - * @param {Blockly.ICollapsibleToolboxItem=} opt_parent The parent category or null if + * @param {!IToolbox} toolbox The parent toolbox for the category. + * @param {ICollapsibleToolboxItem=} opt_parent The parent category or null if * the category does not have a parent. * @constructor - * @extends {Blockly.ToolboxCategory} - * @implements {Blockly.ICollapsibleToolboxItem} + * @extends {ToolboxCategory} + * @implements {ICollapsibleToolboxItem} */ -Blockly.CollapsibleToolboxCategory = function(categoryDef, toolbox, opt_parent) { +const CollapsibleToolboxCategory = function(categoryDef, toolbox, opt_parent) { /** * Container for any child categories. * @type {?Element} @@ -54,16 +56,16 @@ Blockly.CollapsibleToolboxCategory = function(categoryDef, toolbox, opt_parent) /** * The child toolbox items for this category. - * @type {!Array} + * @type {!Array} * @protected */ this.toolboxItems_ = []; - Blockly.CollapsibleToolboxCategory.superClass_.constructor.call( + CollapsibleToolboxCategory.superClass_.constructor.call( this, categoryDef, toolbox, opt_parent); }; -Blockly.utils.object.inherits(Blockly.CollapsibleToolboxCategory, Blockly.ToolboxCategory); +object.inherits(CollapsibleToolboxCategory, ToolboxCategory); /** * All the CSS class names that are used to create a collapsible @@ -80,19 +82,20 @@ Blockly.utils.object.inherits(Blockly.CollapsibleToolboxCategory, Blockly.Toolbo * contents:?string * }} */ -Blockly.CollapsibleToolboxCategory.CssConfig; +CollapsibleToolboxCategory.CssConfig; /** * Name used for registering a collapsible toolbox category. * @const {string} */ -Blockly.CollapsibleToolboxCategory.registrationName = 'collapsibleCategory'; +CollapsibleToolboxCategory.registrationName = 'collapsibleCategory'; /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.makeDefaultCssConfig_ = function() { - var cssConfig = Blockly.CollapsibleToolboxCategory.superClass_.makeDefaultCssConfig_.call(this); +CollapsibleToolboxCategory.prototype.makeDefaultCssConfig_ = function() { + const cssConfig = + CollapsibleToolboxCategory.superClass_.makeDefaultCssConfig_.call(this); cssConfig['contents'] = 'blocklyToolboxContents'; return cssConfig; }; @@ -100,20 +103,21 @@ Blockly.CollapsibleToolboxCategory.prototype.makeDefaultCssConfig_ = function() /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.parseContents_ = function(categoryDef) { - var contents = categoryDef['contents']; - var prevIsFlyoutItem = true; +CollapsibleToolboxCategory.prototype.parseContents_ = function(categoryDef) { + const contents = categoryDef['contents']; + let prevIsFlyoutItem = true; if (categoryDef['custom']) { this.flyoutItems_ = categoryDef['custom']; } else if (contents) { - for (var i = 0, itemDef; (itemDef = contents[i]); i++) { + for (let i = 0; i < contents.length; i++) { + const itemDef = contents[i]; // Separators can exist as either a flyout item or a toolbox item so // decide where it goes based on the type of the previous item. - if (!Blockly.registry.hasItem(Blockly.registry.Type.TOOLBOX_ITEM, itemDef['kind']) || - (itemDef['kind'].toLowerCase() == Blockly.ToolboxSeparator.registrationName && - prevIsFlyoutItem)) { - var flyoutItem = /** @type {Blockly.utils.toolbox.FlyoutItemInfo} */ (itemDef); + if (!registry.hasItem(registry.Type.TOOLBOX_ITEM, itemDef['kind']) || + (itemDef['kind'].toLowerCase() == ToolboxSeparator.registrationName && + prevIsFlyoutItem)) { + const flyoutItem = /** @type {toolbox.FlyoutItemInfo} */ (itemDef); this.flyoutItems_.push(flyoutItem); prevIsFlyoutItem = true; } else { @@ -126,46 +130,46 @@ Blockly.CollapsibleToolboxCategory.prototype.parseContents_ = function(categoryD /** * Creates a toolbox item and adds it to the list of toolbox items. - * @param {!Blockly.utils.toolbox.ToolboxItemInfo} itemDef The information needed + * @param {!toolbox.ToolboxItemInfo} itemDef The information needed * to create a toolbox item. * @private */ -Blockly.CollapsibleToolboxCategory.prototype.createToolboxItem_ = function(itemDef) { - var registryName = itemDef['kind']; - var categoryDef = /** @type {!Blockly.utils.toolbox.CategoryInfo} */ (itemDef); +CollapsibleToolboxCategory.prototype.createToolboxItem_ = function(itemDef) { + let registryName = itemDef['kind']; + const categoryDef = /** @type {!toolbox.CategoryInfo} */ (itemDef); // Categories that are collapsible are created using a class registered under // a diffferent name. if (registryName.toUpperCase() == 'CATEGORY' && - Blockly.utils.toolbox.isCategoryCollapsible(categoryDef)) { - registryName = Blockly.CollapsibleToolboxCategory.registrationName; + toolbox.isCategoryCollapsible(categoryDef)) { + registryName = CollapsibleToolboxCategory.registrationName; } - var ToolboxItemClass = Blockly.registry.getClass( - Blockly.registry.Type.TOOLBOX_ITEM, registryName); - var toolboxItem = new ToolboxItemClass(itemDef, this.parentToolbox_, this); + const ToolboxItemClass = + registry.getClass(registry.Type.TOOLBOX_ITEM, registryName); + const toolboxItem = new ToolboxItemClass(itemDef, this.parentToolbox_, this); this.toolboxItems_.push(toolboxItem); }; /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.init = function() { - Blockly.CollapsibleToolboxCategory.superClass_.init.call(this); +CollapsibleToolboxCategory.prototype.init = function() { + CollapsibleToolboxCategory.superClass_.init.call(this); - this.setExpanded(this.toolboxItemDef_['expanded'] == 'true' || + this.setExpanded( + this.toolboxItemDef_['expanded'] == 'true' || this.toolboxItemDef_['expanded']); }; /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.createDom_ = function() { - Blockly.CollapsibleToolboxCategory.superClass_.createDom_.call(this); +CollapsibleToolboxCategory.prototype.createDom_ = function() { + CollapsibleToolboxCategory.superClass_.createDom_.call(this); - var subCategories = this.getChildToolboxItems(); + const subCategories = this.getChildToolboxItems(); this.subcategoriesDiv_ = this.createSubCategoriesDom_(subCategories); - Blockly.utils.aria.setRole(this.subcategoriesDiv_, - Blockly.utils.aria.Role.GROUP); + aria.setRole(this.subcategoriesDiv_, aria.Role.GROUP); this.htmlDiv_.appendChild(this.subcategoriesDiv_); return this.htmlDiv_; @@ -174,10 +178,10 @@ Blockly.CollapsibleToolboxCategory.prototype.createDom_ = function() { /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.createIconDom_ = function() { - var toolboxIcon = document.createElement('span'); +CollapsibleToolboxCategory.prototype.createIconDom_ = function() { + const toolboxIcon = document.createElement('span'); if (!this.parentToolbox_.isHorizontal()) { - Blockly.utils.dom.addClass(toolboxIcon, this.cssConfig_['icon']); + dom.addClass(toolboxIcon, this.cssConfig_['icon']); toolboxIcon.style.visibility = 'visible'; } @@ -187,18 +191,19 @@ Blockly.CollapsibleToolboxCategory.prototype.createIconDom_ = function() { /** * Create the DOM for all subcategories. - * @param {!Array} subcategories The subcategories. + * @param {!Array} subcategories The subcategories. * @return {!Element} The div holding all the subcategories. * @protected */ -Blockly.CollapsibleToolboxCategory.prototype.createSubCategoriesDom_ = function(subcategories) { - var contentsContainer = document.createElement('div'); - Blockly.utils.dom.addClass(contentsContainer, this.cssConfig_['contents']); +CollapsibleToolboxCategory.prototype.createSubCategoriesDom_ = function( + subcategories) { + const contentsContainer = document.createElement('div'); + dom.addClass(contentsContainer, this.cssConfig_['contents']); - for (var i = 0; i < subcategories.length; i++) { - var newCategory = subcategories[i]; + for (let i = 0; i < subcategories.length; i++) { + const newCategory = subcategories[i]; newCategory.init(); - var newCategoryDiv = newCategory.getDiv(); + const newCategoryDiv = newCategory.getDiv(); contentsContainer.appendChild(newCategoryDiv); if (newCategory.getClickTarget) { newCategory.getClickTarget().setAttribute('id', newCategory.getId()); @@ -213,7 +218,7 @@ Blockly.CollapsibleToolboxCategory.prototype.createSubCategoriesDom_ = function( * @param {boolean} isExpanded True to expand the category, false to close. * @public */ -Blockly.CollapsibleToolboxCategory.prototype.setExpanded = function(isExpanded) { +CollapsibleToolboxCategory.prototype.setExpanded = function(isExpanded) { if (this.expanded_ == isExpanded) { return; } @@ -225,8 +230,8 @@ Blockly.CollapsibleToolboxCategory.prototype.setExpanded = function(isExpanded) this.subcategoriesDiv_.style.display = 'none'; this.closeIcon_(this.iconDom_); } - Blockly.utils.aria.setState(/** @type {!Element} */ (this.htmlDiv_), - Blockly.utils.aria.State.EXPANDED, isExpanded); + aria.setState( + /** @type {!Element} */ (this.htmlDiv_), aria.State.EXPANDED, isExpanded); this.parentToolbox_.handleToolboxItemResize(); }; @@ -234,9 +239,11 @@ Blockly.CollapsibleToolboxCategory.prototype.setExpanded = function(isExpanded) /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.setVisible_ = function(isVisible) { +CollapsibleToolboxCategory.prototype.setVisible_ = function(isVisible) { this.htmlDiv_.style.display = isVisible ? 'block' : 'none'; - for (var i = 0, child; (child = this.getChildToolboxItems()[i]); i++) { + const childToolboxItems = this.getChildToolboxItems(); + for (let i = 0; i < childToolboxItems.length; i++) { + const child = childToolboxItems[i]; child.setVisible_(isVisible); } this.isHidden_ = !isVisible; @@ -252,21 +259,21 @@ Blockly.CollapsibleToolboxCategory.prototype.setVisible_ = function(isVisible) { * is collapsed. * @public */ -Blockly.CollapsibleToolboxCategory.prototype.isExpanded = function() { +CollapsibleToolboxCategory.prototype.isExpanded = function() { return this.expanded_; }; /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.isCollapsible = function() { +CollapsibleToolboxCategory.prototype.isCollapsible = function() { return true; }; /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.onClick = function(_e) { +CollapsibleToolboxCategory.prototype.onClick = function(_e) { this.toggleExpanded(); }; @@ -274,25 +281,28 @@ Blockly.CollapsibleToolboxCategory.prototype.onClick = function(_e) { * Toggles whether or not the category is expanded. * @public */ -Blockly.CollapsibleToolboxCategory.prototype.toggleExpanded = function() { +CollapsibleToolboxCategory.prototype.toggleExpanded = function() { this.setExpanded(!this.expanded_); }; /** * @override */ -Blockly.CollapsibleToolboxCategory.prototype.getDiv = function() { +CollapsibleToolboxCategory.prototype.getDiv = function() { return this.htmlDiv_; }; /** * Gets any children toolbox items. (ex. Gets the subcategories) - * @return {!Array} The child toolbox items. + * @return {!Array} The child toolbox items. */ -Blockly.CollapsibleToolboxCategory.prototype.getChildToolboxItems = function() { +CollapsibleToolboxCategory.prototype.getChildToolboxItems = function() { return this.toolboxItems_; }; -Blockly.registry.register(Blockly.registry.Type.TOOLBOX_ITEM, - Blockly.CollapsibleToolboxCategory.registrationName, Blockly.CollapsibleToolboxCategory); +registry.register( + registry.Type.TOOLBOX_ITEM, CollapsibleToolboxCategory.registrationName, + CollapsibleToolboxCategory); + +exports = CollapsibleToolboxCategory; diff --git a/core/toolbox/separator.js b/core/toolbox/separator.js index 63ded4a6b..dbf30f4f0 100644 --- a/core/toolbox/separator.js +++ b/core/toolbox/separator.js @@ -11,44 +11,42 @@ */ 'use strict'; -goog.provide('Blockly.ToolboxSeparator'); +goog.module('Blockly.ToolboxSeparator'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.IToolboxItem'); -goog.require('Blockly.registry'); -goog.require('Blockly.ToolboxItem'); -goog.require('Blockly.utils.dom'); - -goog.requireType('Blockly.IToolbox'); -goog.requireType('Blockly.utils.toolbox'); +const Css = goog.require('Blockly.Css'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +const ToolboxItem = goog.require('Blockly.ToolboxItem'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); +/* eslint-disable-next-line no-unused-vars */ +const toolbox = goog.requireType('Blockly.utils.toolbox'); /** * Class for a toolbox separator. This is the thin visual line that appears on * the toolbox. This item is not interactable. - * @param {!Blockly.utils.toolbox.SeparatorInfo} separatorDef The information + * @param {!toolbox.SeparatorInfo} separatorDef The information * needed to create a separator. - * @param {!Blockly.IToolbox} toolbox The parent toolbox for the separator. + * @param {!IToolbox} toolbox The parent toolbox for the separator. * @constructor - * @extends {Blockly.ToolboxItem} - * @implements {Blockly.IToolboxItem} + * @extends {ToolboxItem} */ -Blockly.ToolboxSeparator = function(separatorDef, toolbox) { - - Blockly.ToolboxSeparator.superClass_.constructor.call( - this, separatorDef, toolbox); +const ToolboxSeparator = function(separatorDef, toolbox) { + ToolboxSeparator.superClass_.constructor.call(this, separatorDef, toolbox); /** * All the CSS class names that are used to create a separator. - * @type {!Blockly.ToolboxSeparator.CssConfig} + * @type {!ToolboxSeparator.CssConfig} * @protected */ - this.cssConfig_ = { - 'container': 'blocklyTreeSeparator' - }; + this.cssConfig_ = {'container': 'blocklyTreeSeparator'}; - var cssConfig = separatorDef['cssconfig'] || separatorDef['cssConfig']; - Blockly.utils.object.mixin(this.cssConfig_, cssConfig); + const cssConfig = separatorDef['cssconfig'] || separatorDef['cssConfig']; + object.mixin(this.cssConfig_, cssConfig); }; -Blockly.utils.object.inherits(Blockly.ToolboxSeparator, Blockly.ToolboxItem); +object.inherits(ToolboxSeparator, ToolboxItem); /** * All the CSS class names that are used to create a separator. @@ -56,18 +54,18 @@ Blockly.utils.object.inherits(Blockly.ToolboxSeparator, Blockly.ToolboxItem); * container:(string|undefined) * }} */ -Blockly.ToolboxSeparator.CssConfig; +ToolboxSeparator.CssConfig; /** * Name used for registering a toolbox separator. * @const {string} */ -Blockly.ToolboxSeparator.registrationName = 'sep'; +ToolboxSeparator.registrationName = 'sep'; /** * @override */ -Blockly.ToolboxSeparator.prototype.init = function() { +ToolboxSeparator.prototype.init = function() { this.createDom_(); }; @@ -76,9 +74,9 @@ Blockly.ToolboxSeparator.prototype.init = function() { * @return {!Element} The parent element for the separator. * @protected */ -Blockly.ToolboxSeparator.prototype.createDom_ = function() { - var container = document.createElement('div'); - Blockly.utils.dom.addClass(container, this.cssConfig_['container']); +ToolboxSeparator.prototype.createDom_ = function() { + const container = document.createElement('div'); + dom.addClass(container, this.cssConfig_['container']); this.htmlDiv_ = container; return container; }; @@ -86,38 +84,38 @@ Blockly.ToolboxSeparator.prototype.createDom_ = function() { /** * @override */ -Blockly.ToolboxSeparator.prototype.getDiv = function() { +ToolboxSeparator.prototype.getDiv = function() { return this.htmlDiv_; }; /** * @override */ -Blockly.ToolboxSeparator.prototype.dispose = function() { - Blockly.utils.dom.removeNode(this.htmlDiv_); +ToolboxSeparator.prototype.dispose = function() { + dom.removeNode(this.htmlDiv_); }; /** * CSS for Toolbox. See css.js for use. */ -Blockly.Css.register([ - /* eslint-disable indent */ - '.blocklyTreeSeparator {', - 'border-bottom: solid #e5e5e5 1px;', - 'height: 0;', - 'margin: 5px 0;', - '}', - - '.blocklyToolboxDiv[layout="h"] .blocklyTreeSeparator {', - 'border-right: solid #e5e5e5 1px;', - 'border-bottom: none;', - 'height: auto;', - 'margin: 0 5px 0 5px;', - 'padding: 5px 0;', - 'width: 0;', - '}', - /* eslint-enable indent */ +Css.register([ + `.blocklyTreeSeparator { + border-bottom: solid #e5e5e5 1px; + height: 0; + margin: 5px 0; +}`, + `.blocklyToolboxDiv[layout="h"] .blocklyTreeSeparator { + border-right: solid #e5e5e5 1px; + border-bottom: none; + height: auto; + margin: 0 5px 0 5px; + padding: 5px 0; + width: 0; +}`, ]); -Blockly.registry.register(Blockly.registry.Type.TOOLBOX_ITEM, - Blockly.ToolboxSeparator.registrationName, Blockly.ToolboxSeparator); +registry.register( + registry.Type.TOOLBOX_ITEM, ToolboxSeparator.registrationName, + ToolboxSeparator); + +exports = ToolboxSeparator; diff --git a/core/toolbox/toolbox.js b/core/toolbox/toolbox.js index a2e76ef70..37808a80d 100644 --- a/core/toolbox/toolbox.js +++ b/core/toolbox/toolbox.js @@ -10,58 +10,70 @@ */ 'use strict'; -goog.provide('Blockly.Toolbox'); +goog.module('Blockly.Toolbox'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.BlockSvg'); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.CollapsibleToolboxCategory'); -goog.require('Blockly.ComponentManager'); -/** @suppress {extraRequire} */ -goog.require('Blockly.constants'); -goog.require('Blockly.Css'); -goog.require('Blockly.DeleteArea'); -goog.require('Blockly.Events'); +const Blockly = goog.require('Blockly'); +/* eslint-disable-next-line no-unused-vars */ +const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions'); +const BlockSvg = goog.require('Blockly.BlockSvg'); +const CollapsibleToolboxCategory = goog.require('Blockly.CollapsibleToolboxCategory'); +const ComponentManager = goog.require('Blockly.ComponentManager'); +const Css = goog.require('Blockly.Css'); +const DeleteArea = goog.require('Blockly.DeleteArea'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const IAutoHideable = goog.requireType('Blockly.IAutoHideable'); +/* eslint-disable-next-line no-unused-vars */ +const ICollapsibleToolboxItem = goog.requireType('Blockly.ICollapsibleToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const IDraggable = goog.requireType('Blockly.IDraggable'); +/* eslint-disable-next-line no-unused-vars */ +const IFlyout = goog.requireType('Blockly.IFlyout'); +/* eslint-disable-next-line no-unused-vars */ +const IKeyboardAccessible = goog.requireType('Blockly.IKeyboardAccessible'); +/* eslint-disable-next-line no-unused-vars */ +const ISelectableToolboxItem = goog.requireType('Blockly.ISelectableToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const IStyleable = goog.requireType('Blockly.IStyleable'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +/* eslint-disable-next-line no-unused-vars */ +const IToolboxItem = goog.requireType('Blockly.IToolboxItem'); +const Options = goog.require('Blockly.Options'); +const Rect = goog.require('Blockly.utils.Rect'); +/* eslint-disable-next-line no-unused-vars */ +const ShortcutRegistry = goog.requireType('Blockly.ShortcutRegistry'); +const Touch = goog.require('Blockly.Touch'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const aria = goog.require('Blockly.utils.aria'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const registry = goog.require('Blockly.registry'); +const utils = goog.require('Blockly.utils'); +const toolbox = goog.require('Blockly.utils.toolbox'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.ToolboxItemSelect'); -goog.require('Blockly.IAutoHideable'); -goog.require('Blockly.IKeyboardAccessible'); -goog.require('Blockly.IStyleable'); -goog.require('Blockly.IToolbox'); -goog.require('Blockly.Options'); -goog.require('Blockly.registry'); -goog.require('Blockly.Touch'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.aria'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.toolbox'); - -goog.requireType('Blockly.ICollapsibleToolboxItem'); -goog.requireType('Blockly.IDraggable'); -goog.requireType('Blockly.IFlyout'); -goog.requireType('Blockly.ISelectableToolboxItem'); -goog.requireType('Blockly.IToolboxItem'); -goog.requireType('Blockly.ShortcutRegistry'); -goog.requireType('Blockly.WorkspaceSvg'); /** * Class for a Toolbox. * Creates the toolbox's DOM. - * @param {!Blockly.WorkspaceSvg} workspace The workspace in which to create new + * @param {!WorkspaceSvg} workspace The workspace in which to create new * blocks. * @constructor - * @implements {Blockly.IAutoHideable} - * @implements {Blockly.IKeyboardAccessible} - * @implements {Blockly.IStyleable} - * @implements {Blockly.IToolbox} - * @extends {Blockly.DeleteArea} + * @implements {IAutoHideable} + * @implements {IKeyboardAccessible} + * @implements {IStyleable} + * @implements {IToolbox} + * @extends {DeleteArea} */ -Blockly.Toolbox = function(workspace) { - Blockly.Toolbox.superClass_.constructor.call(this); +const Toolbox = function(workspace) { + Toolbox.superClass_.constructor.call(this); /** * The workspace this toolbox is on. - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @protected */ this.workspace_ = workspace; @@ -75,7 +87,7 @@ Blockly.Toolbox = function(workspace) { /** * The JSON describing the contents of this toolbox. - * @type {!Blockly.utils.toolbox.ToolboxInfo} + * @type {!toolbox.ToolboxInfo} * @protected */ this.toolboxDef_ = workspace.options.languageTree || {'contents': []}; @@ -109,7 +121,7 @@ Blockly.Toolbox = function(workspace) { /** * The list of items in the toolbox. - * @type {!Array} + * @type {!Array} * @protected */ this.contents_ = []; @@ -136,34 +148,34 @@ Blockly.Toolbox = function(workspace) { /** * The flyout for the toolbox. - * @type {?Blockly.IFlyout} + * @type {?IFlyout} * @private */ this.flyout_ = null; /** * A map from toolbox item IDs to toolbox items. - * @type {!Object} + * @type {!Object} * @protected */ this.contentMap_ = Object.create(null); /** * Position of the toolbox and flyout relative to the workspace. - * @type {!Blockly.utils.toolbox.Position} + * @type {!toolbox.Position} */ this.toolboxPosition = workspace.options.toolboxPosition; /** * The currently selected item. - * @type {?Blockly.ISelectableToolboxItem} + * @type {?ISelectableToolboxItem} * @protected */ this.selectedItem_ = null; /** * The previously selected item. - * @type {?Blockly.ISelectableToolboxItem} + * @type {?ISelectableToolboxItem} * @protected */ this.previouslySelectedItem_ = null; @@ -172,20 +184,21 @@ Blockly.Toolbox = function(workspace) { * Array holding info needed to unbind event handlers. * Used for disposing. * Ex: [[node, name, func], [node, name, func]]. - * @type {!Array} + * @type {!Array} * @protected */ this.boundEvents_ = []; }; -Blockly.utils.object.inherits(Blockly.Toolbox, Blockly.DeleteArea); +utils.object.inherits(Toolbox, DeleteArea); /** * Handles the given keyboard shortcut. - * @param {!Blockly.ShortcutRegistry.KeyboardShortcut} _shortcut The shortcut to be handled. + * @param {!ShortcutRegistry.KeyboardShortcut} _shortcut The shortcut to be + * handled. * @return {boolean} True if the shortcut has been handled, false otherwise. * @public */ -Blockly.Toolbox.prototype.onShortcut = function(_shortcut) { +Toolbox.prototype.onShortcut = function(_shortcut) { return false; }; @@ -193,47 +206,47 @@ Blockly.Toolbox.prototype.onShortcut = function(_shortcut) { * Initializes the toolbox * @public */ -Blockly.Toolbox.prototype.init = function() { - var workspace = this.workspace_; - var svg = workspace.getParentSvg(); +Toolbox.prototype.init = function() { + const workspace = this.workspace_; + const svg = workspace.getParentSvg(); this.flyout_ = this.createFlyout_(); this.HtmlDiv = this.createDom_(this.workspace_); - Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), svg); + dom.insertAfter(this.flyout_.createDom('svg'), svg); this.setVisible(true); this.flyout_.init(workspace); this.render(this.toolboxDef_); - var themeManager = workspace.getThemeManager(); - themeManager.subscribe(this.HtmlDiv, 'toolboxBackgroundColour', - 'background-color'); + const themeManager = workspace.getThemeManager(); + themeManager.subscribe( + this.HtmlDiv, 'toolboxBackgroundColour', 'background-color'); themeManager.subscribe(this.HtmlDiv, 'toolboxForegroundColour', 'color'); this.workspace_.getComponentManager().addComponent({ component: this, weight: 1, capabilities: [ - Blockly.ComponentManager.Capability.AUTOHIDEABLE, - Blockly.ComponentManager.Capability.DELETE_AREA, - Blockly.ComponentManager.Capability.DRAG_TARGET + ComponentManager.Capability.AUTOHIDEABLE, + ComponentManager.Capability.DELETE_AREA, + ComponentManager.Capability.DRAG_TARGET ] }); }; /** * Creates the DOM for the toolbox. - * @param {!Blockly.WorkspaceSvg} workspace The workspace this toolbox is on. + * @param {!WorkspaceSvg} workspace The workspace this toolbox is on. * @return {!Element} The HTML container for the toolbox. * @protected */ -Blockly.Toolbox.prototype.createDom_ = function(workspace) { - var svg = workspace.getParentSvg(); +Toolbox.prototype.createDom_ = function(workspace) { + const svg = workspace.getParentSvg(); - var container = this.createContainer_(); + const container = this.createContainer_(); this.contentsDiv_ = this.createContentsContainer_(); this.contentsDiv_.tabIndex = 0; - Blockly.utils.aria.setRole(this.contentsDiv_, Blockly.utils.aria.Role.TREE); + aria.setRole(this.contentsDiv_, aria.Role.TREE); container.appendChild(this.contentsDiv_); svg.parentNode.insertBefore(container, svg); @@ -247,11 +260,11 @@ Blockly.Toolbox.prototype.createDom_ = function(workspace) { * @return {!Element} The HTML container for the toolbox. * @protected */ -Blockly.Toolbox.prototype.createContainer_ = function() { - var toolboxContainer = document.createElement('div'); +Toolbox.prototype.createContainer_ = function() { + const toolboxContainer = document.createElement('div'); toolboxContainer.setAttribute('layout', this.isHorizontal() ? 'h' : 'v'); - Blockly.utils.dom.addClass(toolboxContainer, 'blocklyToolboxDiv'); - Blockly.utils.dom.addClass(toolboxContainer, 'blocklyNonSelectable'); + dom.addClass(toolboxContainer, 'blocklyToolboxDiv'); + dom.addClass(toolboxContainer, 'blocklyNonSelectable'); toolboxContainer.setAttribute('dir', this.RTL ? 'RTL' : 'LTR'); return toolboxContainer; }; @@ -261,9 +274,9 @@ Blockly.Toolbox.prototype.createContainer_ = function() { * @return {!Element} The HTML container for the toolbox contents. * @protected */ -Blockly.Toolbox.prototype.createContentsContainer_ = function() { - var contentsContainer = document.createElement('div'); - Blockly.utils.dom.addClass(contentsContainer, 'blocklyToolboxContents'); +Toolbox.prototype.createContentsContainer_ = function() { + const contentsContainer = document.createElement('div'); + dom.addClass(contentsContainer, 'blocklyToolboxContents'); if (this.isHorizontal()) { contentsContainer.style.flexDirection = 'row'; } @@ -277,16 +290,15 @@ Blockly.Toolbox.prototype.createContentsContainer_ = function() { * of the toolbox. * @protected */ -Blockly.Toolbox.prototype.attachEvents_ = function(container, - contentsContainer) { +Toolbox.prototype.attachEvents_ = function(container, contentsContainer) { // Clicking on toolbox closes popups. - var clickEvent = Blockly.browserEvents.conditionalBind( + const clickEvent = browserEvents.conditionalBind( container, 'click', this, this.onClick_, /* opt_noCaptureIdentifier */ false, /* opt_noPreventDefault */ true); this.boundEvents_.push(clickEvent); - var keyDownEvent = Blockly.browserEvents.conditionalBind( + const keyDownEvent = browserEvents.conditionalBind( contentsContainer, 'keydown', this, this.onKeyDown_, /* opt_noCaptureIdentifier */ false, /* opt_noPreventDefault */ true); @@ -298,15 +310,15 @@ Blockly.Toolbox.prototype.attachEvents_ = function(container, * @param {!Event} e Click event to handle. * @protected */ -Blockly.Toolbox.prototype.onClick_ = function(e) { - if (Blockly.utils.isRightButton(e) || e.target == this.HtmlDiv) { +Toolbox.prototype.onClick_ = function(e) { + if (utils.isRightButton(e) || e.target == this.HtmlDiv) { // Close flyout. Blockly.hideChaff(false); } else { - var targetElement = e.target; - var itemId = targetElement.getAttribute('id'); + const targetElement = e.target; + const itemId = targetElement.getAttribute('id'); if (itemId) { - var item = this.getToolboxItemById(itemId); + const item = this.getToolboxItemById(itemId); if (item.isSelectable()) { this.setSelectedItem(item); item.onClick(e); @@ -315,7 +327,7 @@ Blockly.Toolbox.prototype.onClick_ = function(e) { // Just close popups. Blockly.hideChaff(true); } - Blockly.Touch.clearTouchIdentifier(); // Don't block future drags. + Touch.clearTouchIdentifier(); // Don't block future drags. }; /** @@ -323,25 +335,26 @@ Blockly.Toolbox.prototype.onClick_ = function(e) { * @param {!KeyboardEvent} e The key down event. * @protected */ -Blockly.Toolbox.prototype.onKeyDown_ = function(e) { - var handled = false; +Toolbox.prototype.onKeyDown_ = function(e) { + let handled = false; switch (e.keyCode) { - case Blockly.utils.KeyCodes.DOWN: + case utils.KeyCodes.DOWN: handled = this.selectNext_(); break; - case Blockly.utils.KeyCodes.UP: + case utils.KeyCodes.UP: handled = this.selectPrevious_(); break; - case Blockly.utils.KeyCodes.LEFT: + case utils.KeyCodes.LEFT: handled = this.selectParent_(); break; - case Blockly.utils.KeyCodes.RIGHT: + case utils.KeyCodes.RIGHT: handled = this.selectChild_(); break; - case Blockly.utils.KeyCodes.ENTER: - case Blockly.utils.KeyCodes.SPACE: + case utils.KeyCodes.ENTER: + case utils.KeyCodes.SPACE: if (this.selectedItem_ && this.selectedItem_.isCollapsible()) { - var collapsibleItem = /** @type {!Blockly.ICollapsibleToolboxItem} */ (this.selectedItem_); + const collapsibleItem = + /** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_); collapsibleItem.toggleExpanded(); handled = true; } @@ -361,16 +374,16 @@ Blockly.Toolbox.prototype.onKeyDown_ = function(e) { /** * Creates the flyout based on the toolbox layout. - * @return {!Blockly.IFlyout} The flyout for the toolbox. + * @return {!IFlyout} The flyout for the toolbox. * @throws {Error} If missing a require for `Blockly.HorizontalFlyout`, * `Blockly.VerticalFlyout`, and no flyout plugin is specified. * @protected */ -Blockly.Toolbox.prototype.createFlyout_ = function() { - var workspace = this.workspace_; +Toolbox.prototype.createFlyout_ = function() { + const workspace = this.workspace_; // TODO (#4247): Look into adding a makeFlyout method to Blockly Options. - var workspaceOptions = new Blockly.Options( - /** @type {!Blockly.BlocklyOptions} */ + const workspaceOptions = new Options( + /** @type {!BlocklyOptions} */ ({ 'parentWorkspace': workspace, 'rtl': workspace.RTL, @@ -385,29 +398,27 @@ Blockly.Toolbox.prototype.createFlyout_ = function() { // Options takes in either 'end' or 'start'. This has already been parsed to // be either 0 or 1, so set it after. workspaceOptions.toolboxPosition = workspace.options.toolboxPosition; - var FlyoutClass = null; + let FlyoutClass = null; if (workspace.horizontalLayout) { - FlyoutClass = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, workspace.options, - true); + FlyoutClass = registry.getClassFromOptions( + registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, workspace.options, true); } else { - FlyoutClass = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX, workspace.options, - true); + FlyoutClass = registry.getClassFromOptions( + registry.Type.FLYOUTS_VERTICAL_TOOLBOX, workspace.options, true); } return new FlyoutClass(workspaceOptions); }; /** * Fills the toolbox with new toolbox items and removes any old contents. - * @param {!Blockly.utils.toolbox.ToolboxInfo} toolboxDef Object holding information + * @param {!toolbox.ToolboxInfo} toolboxDef Object holding information * for creating a toolbox. * @package */ -Blockly.Toolbox.prototype.render = function(toolboxDef) { +Toolbox.prototype.render = function(toolboxDef) { this.toolboxDef_ = toolboxDef; - for (var i = 0; i < this.contents_.length; i++) { - var toolboxItem = this.contents_[i]; + for (let i = 0; i < this.contents_.length; i++) { + const toolboxItem = this.contents_[i]; if (toolboxItem) { toolboxItem.dispose(); } @@ -421,15 +432,16 @@ Blockly.Toolbox.prototype.render = function(toolboxDef) { /** * Adds all the toolbox items to the toolbox. - * @param {!Array} toolboxDef Array + * @param {!Array} toolboxDef Array * holding objects containing information on the contents of the toolbox. * @protected */ -Blockly.Toolbox.prototype.renderContents_ = function(toolboxDef) { +Toolbox.prototype.renderContents_ = function(toolboxDef) { // This is for performance reasons. By using document fragment we only have to // add to the DOM once. - var fragment = document.createDocumentFragment(); - for (var i = 0, toolboxItemDef; (toolboxItemDef = toolboxDef[i]); i++) { + const fragment = document.createDocumentFragment(); + for (let i = 0; i < toolboxDef.length; i++) { + const toolboxItemDef = toolboxDef[i]; this.createToolboxItem_(toolboxItemDef, fragment); } this.contentsDiv_.appendChild(fragment); @@ -437,30 +449,30 @@ Blockly.Toolbox.prototype.renderContents_ = function(toolboxDef) { /** * Creates and renders the toolbox item. - * @param {!Blockly.utils.toolbox.ToolboxItemInfo} toolboxItemDef Any information + * @param {!toolbox.ToolboxItemInfo} toolboxItemDef Any information * that can be used to create an item in the toolbox. * @param {!DocumentFragment} fragment The document fragment to add the child * toolbox elements to. * @private */ -Blockly.Toolbox.prototype.createToolboxItem_ = function(toolboxItemDef, fragment) { - var registryName = toolboxItemDef['kind']; +Toolbox.prototype.createToolboxItem_ = function(toolboxItemDef, fragment) { + let registryName = toolboxItemDef['kind']; // Categories that are collapsible are created using a class registered under // a different name. if (registryName.toUpperCase() == 'CATEGORY' && - Blockly.utils.toolbox.isCategoryCollapsible( - /** @type {!Blockly.utils.toolbox.CategoryInfo} */(toolboxItemDef))) { - registryName = Blockly.CollapsibleToolboxCategory.registrationName; + toolbox.isCategoryCollapsible( + /** @type {!toolbox.CategoryInfo} */ (toolboxItemDef))) { + registryName = CollapsibleToolboxCategory.registrationName; } - var ToolboxItemClass = Blockly.registry.getClass( - Blockly.registry.Type.TOOLBOX_ITEM, registryName.toLowerCase()); + const ToolboxItemClass = + registry.getClass(registry.Type.TOOLBOX_ITEM, registryName.toLowerCase()); if (ToolboxItemClass) { - var toolboxItem = new ToolboxItemClass(toolboxItemDef, this); + const toolboxItem = new ToolboxItemClass(toolboxItemDef, this); this.addToolboxItem_(toolboxItem); toolboxItem.init(); - var toolboxItemDom = toolboxItem.getDiv(); + const toolboxItemDom = toolboxItem.getDiv(); if (toolboxItemDom) { fragment.appendChild(toolboxItemDom); } @@ -474,16 +486,18 @@ Blockly.Toolbox.prototype.createToolboxItem_ = function(toolboxItemDef, fragment /** * Adds an item to the toolbox. - * @param {!Blockly.IToolboxItem} toolboxItem The item in the toolbox. + * @param {!IToolboxItem} toolboxItem The item in the toolbox. * @protected */ -Blockly.Toolbox.prototype.addToolboxItem_ = function(toolboxItem) { +Toolbox.prototype.addToolboxItem_ = function(toolboxItem) { this.contents_.push(toolboxItem); this.contentMap_[toolboxItem.getId()] = toolboxItem; if (toolboxItem.isCollapsible()) { - var collapsibleItem = /** @type {Blockly.ICollapsibleToolboxItem} */ + const collapsibleItem = /** @type {ICollapsibleToolboxItem} */ (toolboxItem); - for (var i = 0, child; (child = collapsibleItem.getChildToolboxItems()[i]); i++) { + const childToolboxItems = collapsibleItem.getChildToolboxItems(); + for (let i = 0; i < childToolboxItems.length; i++) { + const child = childToolboxItems[i]; this.addToolboxItem_(child); } } @@ -491,10 +505,10 @@ Blockly.Toolbox.prototype.addToolboxItem_ = function(toolboxItem) { /** * Gets the items in the toolbox. - * @return {!Array} The list of items in the toolbox. + * @return {!Array} The list of items in the toolbox. * @public */ -Blockly.Toolbox.prototype.getToolboxItems = function() { +Toolbox.prototype.getToolboxItems = function() { return this.contents_; }; @@ -503,8 +517,8 @@ Blockly.Toolbox.prototype.getToolboxItems = function() { * @param {string} style The name of the class to add. * @package */ -Blockly.Toolbox.prototype.addStyle = function(style) { - Blockly.utils.dom.addClass(/** @type {!Element} */ (this.HtmlDiv), style); +Toolbox.prototype.addStyle = function(style) { + dom.addClass(/** @type {!Element} */ (this.HtmlDiv), style); }; /** @@ -512,17 +526,17 @@ Blockly.Toolbox.prototype.addStyle = function(style) { * @param {string} style The name of the class to remove. * @package */ -Blockly.Toolbox.prototype.removeStyle = function(style) { - Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.HtmlDiv), style); +Toolbox.prototype.removeStyle = function(style) { + dom.removeClass(/** @type {!Element} */ (this.HtmlDiv), style); }; /** * Returns the bounding rectangle of the drag target area in pixel units * relative to viewport. - * @return {?Blockly.utils.Rect} The component's bounding box. Null if drag + * @return {?Rect} The component's bounding box. Null if drag * target area should be ignored. */ -Blockly.Toolbox.prototype.getClientRect = function() { +Toolbox.prototype.getClientRect = function() { if (!this.HtmlDiv || !this.isVisible_) { return null; } @@ -530,24 +544,24 @@ Blockly.Toolbox.prototype.getClientRect = function() { // BIG_NUM is offscreen padding so that blocks dragged beyond the toolbox // area are still deleted. Must be smaller than Infinity, but larger than // the largest screen size. - var BIG_NUM = 10000000; - var toolboxRect = this.HtmlDiv.getBoundingClientRect(); + const BIG_NUM = 10000000; + const toolboxRect = this.HtmlDiv.getBoundingClientRect(); - var top = toolboxRect.top; - var bottom = top + toolboxRect.height; - var left = toolboxRect.left; - var right = left + toolboxRect.width; + const top = toolboxRect.top; + const bottom = top + toolboxRect.height; + const left = toolboxRect.left; + const right = left + toolboxRect.width; // Assumes that the toolbox is on the SVG edge. If this changes // (e.g. toolboxes in mutators) then this code will need to be more complex. - if (this.toolboxPosition == Blockly.utils.toolbox.Position.TOP) { - return new Blockly.utils.Rect(-BIG_NUM, bottom, -BIG_NUM, BIG_NUM); - } else if (this.toolboxPosition == Blockly.utils.toolbox.Position.BOTTOM) { - return new Blockly.utils.Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM); - } else if (this.toolboxPosition == Blockly.utils.toolbox.Position.LEFT) { - return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, right); + if (this.toolboxPosition == toolbox.Position.TOP) { + return new Rect(-BIG_NUM, bottom, -BIG_NUM, BIG_NUM); + } else if (this.toolboxPosition == toolbox.Position.BOTTOM) { + return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM); + } else if (this.toolboxPosition == toolbox.Position.LEFT) { + return new Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, right); } else { // Right - return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM); + return new Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM); } }; @@ -556,7 +570,7 @@ Blockly.Toolbox.prototype.getClientRect = function() { * this area. * This method should check if the element is deletable and is always called * before onDragEnter/onDragOver/onDragExit. - * @param {!Blockly.IDraggable} element The block or bubble currently being + * @param {!IDraggable} element The block or bubble currently being * dragged. * @param {boolean} _couldConnect Whether the element could could connect to * another. @@ -564,9 +578,9 @@ Blockly.Toolbox.prototype.getClientRect = function() { * this area. * @override */ -Blockly.Toolbox.prototype.wouldDelete = function(element, _couldConnect) { - if (element instanceof Blockly.BlockSvg) { - var block = /** @type {Blockly.BlockSvg} */ (element); +Toolbox.prototype.wouldDelete = function(element, _couldConnect) { + if (element instanceof BlockSvg) { + const block = /** @type {BlockSvg} */ (element); // Prefer dragging to the toolbox over connecting to other blocks. this.updateWouldDelete_(!block.getParent() && block.isDeletable()); } else { @@ -577,21 +591,21 @@ Blockly.Toolbox.prototype.wouldDelete = function(element, _couldConnect) { /** * Handles when a cursor with a block or bubble enters this drag target. - * @param {!Blockly.IDraggable} _dragElement The block or bubble currently being + * @param {!IDraggable} _dragElement The block or bubble currently being * dragged. * @override */ -Blockly.Toolbox.prototype.onDragEnter = function(_dragElement) { +Toolbox.prototype.onDragEnter = function(_dragElement) { this.updateCursorDeleteStyle_(true); }; /** * Handles when a cursor with a block or bubble exits this drag target. - * @param {!Blockly.IDraggable} _dragElement The block or bubble currently being + * @param {!IDraggable} _dragElement The block or bubble currently being * dragged. * @override */ -Blockly.Toolbox.prototype.onDragExit = function(_dragElement) { +Toolbox.prototype.onDragExit = function(_dragElement) { this.updateCursorDeleteStyle_(false); }; @@ -599,11 +613,11 @@ Blockly.Toolbox.prototype.onDragExit = function(_dragElement) { /** * Handles when a block or bubble is dropped on this component. * Should not handle delete here. - * @param {!Blockly.IDraggable} _dragElement The block or bubble currently being + * @param {!IDraggable} _dragElement The block or bubble currently being * dragged. * @override */ -Blockly.Toolbox.prototype.onDrop = function(_dragElement) { +Toolbox.prototype.onDrop = function(_dragElement) { this.updateCursorDeleteStyle_(false); }; @@ -613,7 +627,7 @@ Blockly.Toolbox.prototype.onDrop = function(_dragElement) { * @protected * @override */ -Blockly.Toolbox.prototype.updateWouldDelete_ = function(wouldDelete) { +Toolbox.prototype.updateWouldDelete_ = function(wouldDelete) { if (wouldDelete === this.wouldDelete_) { return; } @@ -634,9 +648,9 @@ Blockly.Toolbox.prototype.updateWouldDelete_ = function(wouldDelete) { * @param {boolean} addStyle Whether the style should be added or removed. * @protected */ -Blockly.Toolbox.prototype.updateCursorDeleteStyle_ = function(addStyle) { - var style = this.wouldDelete_ ? 'blocklyToolboxDelete' : - 'blocklyToolboxGrab'; +Toolbox.prototype.updateCursorDeleteStyle_ = function(addStyle) { + const style = + this.wouldDelete_ ? 'blocklyToolboxDelete' : 'blocklyToolboxGrab'; if (addStyle) { this.addStyle(style); } else { @@ -647,11 +661,11 @@ Blockly.Toolbox.prototype.updateCursorDeleteStyle_ = function(addStyle) { /** * Gets the toolbox item with the given ID. * @param {string} id The ID of the toolbox item. - * @return {?Blockly.IToolboxItem} The toolbox item with the given ID, or null + * @return {?IToolboxItem} The toolbox item with the given ID, or null * if no item exists. * @public */ -Blockly.Toolbox.prototype.getToolboxItemById = function(id) { +Toolbox.prototype.getToolboxItemById = function(id) { return this.contentMap_[id] || null; }; @@ -660,7 +674,7 @@ Blockly.Toolbox.prototype.getToolboxItemById = function(id) { * @return {number} The width of the toolbox. * @public */ -Blockly.Toolbox.prototype.getWidth = function() { +Toolbox.prototype.getWidth = function() { return this.width_; }; @@ -669,45 +683,45 @@ Blockly.Toolbox.prototype.getWidth = function() { * @return {number} The width of the toolbox. * @public */ -Blockly.Toolbox.prototype.getHeight = function() { +Toolbox.prototype.getHeight = function() { return this.height_; }; /** * Gets the toolbox flyout. - * @return {?Blockly.IFlyout} The toolbox flyout. + * @return {?IFlyout} The toolbox flyout. * @public */ -Blockly.Toolbox.prototype.getFlyout = function() { +Toolbox.prototype.getFlyout = function() { return this.flyout_; }; /** * Gets the workspace for the toolbox. - * @return {!Blockly.WorkspaceSvg} The parent workspace for the toolbox. + * @return {!WorkspaceSvg} The parent workspace for the toolbox. * @public */ -Blockly.Toolbox.prototype.getWorkspace = function() { +Toolbox.prototype.getWorkspace = function() { return this.workspace_; }; /** * Gets the selected item. - * @return {?Blockly.ISelectableToolboxItem} The selected item, or null if no item is + * @return {?ISelectableToolboxItem} The selected item, or null if no item is * currently selected. * @public */ -Blockly.Toolbox.prototype.getSelectedItem = function() { +Toolbox.prototype.getSelectedItem = function() { return this.selectedItem_; }; /** * Gets the previously selected item. - * @return {?Blockly.ISelectableToolboxItem} The previously selected item, or null if no + * @return {?ISelectableToolboxItem} The previously selected item, or null if no * item was previously selected. * @public */ -Blockly.Toolbox.prototype.getPreviouslySelectedItem = function() { +Toolbox.prototype.getPreviouslySelectedItem = function() { return this.previouslySelectedItem_; }; @@ -717,7 +731,7 @@ Blockly.Toolbox.prototype.getPreviouslySelectedItem = function() { * vertical. * @public */ -Blockly.Toolbox.prototype.isHorizontal = function() { +Toolbox.prototype.isHorizontal = function() { return this.horizontalLayout_; }; @@ -726,9 +740,9 @@ Blockly.Toolbox.prototype.isHorizontal = function() { * the workspace is in rtl. * @public */ -Blockly.Toolbox.prototype.position = function() { - var workspaceMetrics = this.workspace_.getMetrics(); - var toolboxDiv = this.HtmlDiv; +Toolbox.prototype.position = function() { + const workspaceMetrics = this.workspace_.getMetrics(); + const toolboxDiv = this.HtmlDiv; if (!toolboxDiv) { // Not initialized yet. return; @@ -740,13 +754,13 @@ Blockly.Toolbox.prototype.position = function() { toolboxDiv.style.width = '100%'; this.height_ = toolboxDiv.offsetHeight; this.width_ = workspaceMetrics.viewWidth; - if (this.toolboxPosition == Blockly.utils.toolbox.Position.TOP) { + if (this.toolboxPosition == toolbox.Position.TOP) { toolboxDiv.style.top = '0'; } else { // Bottom toolboxDiv.style.bottom = '0'; } } else { - if (this.toolboxPosition == Blockly.utils.toolbox.Position.RIGHT) { + if (this.toolboxPosition == toolbox.Position.RIGHT) { toolboxDiv.style.right = '0'; } else { // Left toolboxDiv.style.left = '0'; @@ -761,15 +775,15 @@ Blockly.Toolbox.prototype.position = function() { * Handles resizing the toolbox when a toolbox item resizes. * @package */ -Blockly.Toolbox.prototype.handleToolboxItemResize = function() { +Toolbox.prototype.handleToolboxItemResize = function() { // Reposition the workspace so that (0,0) is in the correct position relative // to the new absolute edge (ie toolbox edge). - var workspace = this.workspace_; - var rect = this.HtmlDiv.getBoundingClientRect(); - var newX = this.toolboxPosition == Blockly.utils.toolbox.Position.LEFT ? + const workspace = this.workspace_; + const rect = this.HtmlDiv.getBoundingClientRect(); + const newX = this.toolboxPosition == toolbox.Position.LEFT ? workspace.scrollX + rect.width : workspace.scrollX; - var newY = this.toolboxPosition == Blockly.utils.toolbox.Position.TOP ? + const newY = this.toolboxPosition == toolbox.Position.TOP ? workspace.scrollY + rect.height : workspace.scrollY; workspace.translate(newX, newY); @@ -783,7 +797,7 @@ Blockly.Toolbox.prototype.handleToolboxItemResize = function() { * Unhighlights any previously selected item. * @public */ -Blockly.Toolbox.prototype.clearSelection = function() { +Toolbox.prototype.clearSelection = function() { this.setSelectedItem(null); }; @@ -791,9 +805,9 @@ Blockly.Toolbox.prototype.clearSelection = function() { * Updates the category colours and background colour of selected categories. * @package */ -Blockly.Toolbox.prototype.refreshTheme = function() { - for (var i = 0; i < this.contents_.length; i++) { - var child = this.contents_[i]; +Toolbox.prototype.refreshTheme = function() { + for (let i = 0; i < this.contents_.length; i++) { + const child = this.contents_[i]; if (child.refreshTheme) { child.refreshTheme(); } @@ -806,7 +820,7 @@ Blockly.Toolbox.prototype.refreshTheme = function() { * procedures. * @public */ -Blockly.Toolbox.prototype.refreshSelection = function() { +Toolbox.prototype.refreshSelection = function() { if (this.selectedItem_ && this.selectedItem_.isSelectable() && this.selectedItem_.getContents().length) { this.flyout_.show(this.selectedItem_.getContents()); @@ -818,7 +832,7 @@ Blockly.Toolbox.prototype.refreshSelection = function() { * @param {boolean} isVisible True if toolbox should be visible. * @public */ -Blockly.Toolbox.prototype.setVisible = function(isVisible) { +Toolbox.prototype.setVisible = function(isVisible) { if (this.isVisible_ === isVisible) { return; } @@ -835,7 +849,7 @@ Blockly.Toolbox.prototype.setVisible = function(isVisible) { * @param {boolean} onlyClosePopups Whether only popups should be closed. * Flyouts should not be closed if this is true. */ -Blockly.Toolbox.prototype.autoHide = function(onlyClosePopups) { +Toolbox.prototype.autoHide = function(onlyClosePopups) { if (!onlyClosePopups && this.flyout_ && this.flyout_.autoClose) { this.clearSelection(); } @@ -844,16 +858,16 @@ Blockly.Toolbox.prototype.autoHide = function(onlyClosePopups) { /** * Sets the given item as selected. * No-op if the item is not selectable. - * @param {?Blockly.IToolboxItem} newItem The toolbox item to select. + * @param {?IToolboxItem} newItem The toolbox item to select. * @public */ -Blockly.Toolbox.prototype.setSelectedItem = function(newItem) { - var oldItem = this.selectedItem_; +Toolbox.prototype.setSelectedItem = function(newItem) { + const oldItem = this.selectedItem_; if ((!newItem && !oldItem) || (newItem && !newItem.isSelectable())) { return; } - newItem = /** @type {Blockly.ISelectableToolboxItem} */ (newItem); + newItem = /** @type {ISelectableToolboxItem} */ (newItem); if (this.shouldDeselectItem_(oldItem, newItem) && oldItem != null) { this.deselectItem_(oldItem); @@ -869,14 +883,14 @@ Blockly.Toolbox.prototype.setSelectedItem = function(newItem) { /** * Decides whether the old item should be deselected. - * @param {?Blockly.ISelectableToolboxItem} oldItem The previously selected + * @param {?ISelectableToolboxItem} oldItem The previously selected * toolbox item. - * @param {?Blockly.ISelectableToolboxItem} newItem The newly selected toolbox + * @param {?ISelectableToolboxItem} newItem The newly selected toolbox * item. * @return {boolean} True if the old item should be deselected, false otherwise. * @protected */ -Blockly.Toolbox.prototype.shouldDeselectItem_ = function(oldItem, newItem) { +Toolbox.prototype.shouldDeselectItem_ = function(oldItem, newItem) { // Deselect the old item unless the old item is collapsible and has been // previously clicked on. return oldItem != null && (!oldItem.isCollapsible() || oldItem != newItem); @@ -884,46 +898,48 @@ Blockly.Toolbox.prototype.shouldDeselectItem_ = function(oldItem, newItem) { /** * Decides whether the new item should be selected. - * @param {?Blockly.ISelectableToolboxItem} oldItem The previously selected + * @param {?ISelectableToolboxItem} oldItem The previously selected * toolbox item. - * @param {?Blockly.ISelectableToolboxItem} newItem The newly selected toolbox + * @param {?ISelectableToolboxItem} newItem The newly selected toolbox * item. * @return {boolean} True if the new item should be selected, false otherwise. * @protected */ -Blockly.Toolbox.prototype.shouldSelectItem_ = function(oldItem, newItem) { +Toolbox.prototype.shouldSelectItem_ = function(oldItem, newItem) { // Select the new item unless the old item equals the new item. return newItem != null && newItem != oldItem; }; /** * Deselects the given item, marks it as unselected, and updates aria state. - * @param {!Blockly.ISelectableToolboxItem} item The previously selected + * @param {!ISelectableToolboxItem} item The previously selected * toolbox item which should be deselected. * @protected */ -Blockly.Toolbox.prototype.deselectItem_ = function(item) { +Toolbox.prototype.deselectItem_ = function(item) { this.selectedItem_ = null; this.previouslySelectedItem_ = item; item.setSelected(false); - Blockly.utils.aria.setState(/** @type {!Element} */ (this.contentsDiv_), - Blockly.utils.aria.State.ACTIVEDESCENDANT, ''); + aria.setState( + /** @type {!Element} */ (this.contentsDiv_), aria.State.ACTIVEDESCENDANT, + ''); }; /** * Selects the given item, marks it selected, and updates aria state. - * @param {?Blockly.ISelectableToolboxItem} oldItem The previously selected + * @param {?ISelectableToolboxItem} oldItem The previously selected * toolbox item. - * @param {!Blockly.ISelectableToolboxItem} newItem The newly selected toolbox + * @param {!ISelectableToolboxItem} newItem The newly selected toolbox * item. * @protected */ -Blockly.Toolbox.prototype.selectItem_ = function(oldItem, newItem) { +Toolbox.prototype.selectItem_ = function(oldItem, newItem) { this.selectedItem_ = newItem; this.previouslySelectedItem_ = oldItem; newItem.setSelected(true); - Blockly.utils.aria.setState(/** @type {!Element} */ (this.contentsDiv_), - Blockly.utils.aria.State.ACTIVEDESCENDANT, newItem.getId()); + aria.setState( + /** @type {!Element} */ (this.contentsDiv_), aria.State.ACTIVEDESCENDANT, + newItem.getId()); }; /** @@ -931,9 +947,9 @@ Blockly.Toolbox.prototype.selectItem_ = function(oldItem, newItem) { * @param {number} position The position of the item to select. * @public */ -Blockly.Toolbox.prototype.selectItemByPosition = function(position) { +Toolbox.prototype.selectItemByPosition = function(position) { if (position > -1 && position < this.contents_.length) { - var item = this.contents_[position]; + const item = this.contents_[position]; if (item.isSelectable()) { this.setSelectedItem(item); } @@ -942,11 +958,12 @@ Blockly.Toolbox.prototype.selectItemByPosition = function(position) { /** * Decides whether to hide or show the flyout depending on the selected item. - * @param {?Blockly.ISelectableToolboxItem} oldItem The previously selected toolbox item. - * @param {?Blockly.ISelectableToolboxItem} newItem The newly selected toolbox item. + * @param {?ISelectableToolboxItem} oldItem The previously selected toolbox + * item. + * @param {?ISelectableToolboxItem} newItem The newly selected toolbox item. * @protected */ -Blockly.Toolbox.prototype.updateFlyout_ = function(oldItem, newItem) { +Toolbox.prototype.updateFlyout_ = function(oldItem, newItem) { if ((oldItem == newItem && !newItem.isCollapsible()) || !newItem || !newItem.getContents().length) { this.flyout_.hide(); @@ -958,22 +975,22 @@ Blockly.Toolbox.prototype.updateFlyout_ = function(oldItem, newItem) { /** * Emits an event when a new toolbox item is selected. - * @param {?Blockly.ISelectableToolboxItem} oldItem The previously selected + * @param {?ISelectableToolboxItem} oldItem The previously selected * toolbox item. - * @param {?Blockly.ISelectableToolboxItem} newItem The newly selected toolbox + * @param {?ISelectableToolboxItem} newItem The newly selected toolbox * item. * @private */ -Blockly.Toolbox.prototype.fireSelectEvent_ = function(oldItem, newItem) { - var oldElement = oldItem && oldItem.getName(); - var newElement = newItem && newItem.getName(); +Toolbox.prototype.fireSelectEvent_ = function(oldItem, newItem) { + const oldElement = oldItem && oldItem.getName(); + let newElement = newItem && newItem.getName(); // In this case the toolbox closes, so the newElement should be null. if (oldItem == newItem) { newElement = null; } - var event = new (Blockly.Events.get(Blockly.Events.TOOLBOX_ITEM_SELECT))( + const event = new (Events.get(Events.TOOLBOX_ITEM_SELECT))( oldElement, newElement, this.workspace_.id); - Blockly.Events.fire(event); + Events.fire(event); }; /** @@ -981,16 +998,18 @@ Blockly.Toolbox.prototype.fireSelectEvent_ = function(oldItem, newItem) { * @return {boolean} True if a parent category was selected, false otherwise. * @private */ -Blockly.Toolbox.prototype.selectParent_ = function() { +Toolbox.prototype.selectParent_ = function() { if (!this.selectedItem_) { return false; } if (this.selectedItem_.isCollapsible() && this.selectedItem_.isExpanded()) { - var collapsibleItem = /** @type {!Blockly.ICollapsibleToolboxItem} */ (this.selectedItem_); + const collapsibleItem = + /** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_); collapsibleItem.setExpanded(false); return true; - } else if (this.selectedItem_.getParent() && + } else if ( + this.selectedItem_.getParent() && this.selectedItem_.getParent().isSelectable()) { this.setSelectedItem(this.selectedItem_.getParent()); return true; @@ -1004,11 +1023,11 @@ Blockly.Toolbox.prototype.selectParent_ = function() { * @return {boolean} True if a child category was selected, false otherwise. * @private */ -Blockly.Toolbox.prototype.selectChild_ = function() { +Toolbox.prototype.selectChild_ = function() { if (!this.selectedItem_ || !this.selectedItem_.isCollapsible()) { return false; } - var collapsibleItem = /** @type {Blockly.ICollapsibleToolboxItem} */ + const collapsibleItem = /** @type {ICollapsibleToolboxItem} */ (this.selectedItem_); if (!collapsibleItem.isExpanded()) { collapsibleItem.setExpanded(true); @@ -1024,14 +1043,14 @@ Blockly.Toolbox.prototype.selectChild_ = function() { * @return {boolean} True if a next category was selected, false otherwise. * @private */ -Blockly.Toolbox.prototype.selectNext_ = function() { +Toolbox.prototype.selectNext_ = function() { if (!this.selectedItem_) { return false; } - var nextItemIdx = this.contents_.indexOf(this.selectedItem_) + 1; + let nextItemIdx = this.contents_.indexOf(this.selectedItem_) + 1; if (nextItemIdx > -1 && nextItemIdx < this.contents_.length) { - var nextItem = this.contents_[nextItemIdx]; + let nextItem = this.contents_[nextItemIdx]; while (nextItem && !nextItem.isSelectable()) { nextItem = this.contents_[++nextItemIdx]; } @@ -1048,14 +1067,14 @@ Blockly.Toolbox.prototype.selectNext_ = function() { * @return {boolean} True if a previous category was selected, false otherwise. * @private */ -Blockly.Toolbox.prototype.selectPrevious_ = function() { +Toolbox.prototype.selectPrevious_ = function() { if (!this.selectedItem_) { return false; } - var prevItemIdx = this.contents_.indexOf(this.selectedItem_) - 1; + let prevItemIdx = this.contents_.indexOf(this.selectedItem_) - 1; if (prevItemIdx > -1 && prevItemIdx < this.contents_.length) { - var prevItem = this.contents_[prevItemIdx]; + let prevItem = this.contents_[prevItemIdx]; while (prevItem && !prevItem.isSelectable()) { prevItem = this.contents_[--prevItemIdx]; } @@ -1071,61 +1090,49 @@ Blockly.Toolbox.prototype.selectPrevious_ = function() { * Disposes of this toolbox. * @public */ -Blockly.Toolbox.prototype.dispose = function() { +Toolbox.prototype.dispose = function() { this.workspace_.getComponentManager().removeComponent('toolbox'); this.flyout_.dispose(); - for (var i = 0; i < this.contents_.length; i++) { - var toolboxItem = this.contents_[i]; + for (let i = 0; i < this.contents_.length; i++) { + const toolboxItem = this.contents_[i]; toolboxItem.dispose(); } - for (var j = 0; j < this.boundEvents_.length; j++) { - Blockly.browserEvents.unbind(this.boundEvents_[j]); + for (let j = 0; j < this.boundEvents_.length; j++) { + browserEvents.unbind(this.boundEvents_[j]); } this.boundEvents_ = []; this.contents_ = []; this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv); - Blockly.utils.dom.removeNode(this.HtmlDiv); + dom.removeNode(this.HtmlDiv); }; /** * CSS for Toolbox. See css.js for use. */ -Blockly.Css.register([ +Css.register([ /* eslint-disable indent */ - '.blocklyToolboxDelete {', - 'cursor: url("<<>>/handdelete.cur"), auto;', + '.blocklyToolboxDelete {', 'cursor: url("<<>>/handdelete.cur"), auto;', '}', - '.blocklyToolboxGrab {', - 'cursor: url("<<>>/handclosed.cur"), auto;', - 'cursor: grabbing;', - 'cursor: -webkit-grabbing;', - '}', + '.blocklyToolboxGrab {', 'cursor: url("<<>>/handclosed.cur"), auto;', + 'cursor: grabbing;', 'cursor: -webkit-grabbing;', '}', /* Category tree in Toolbox. */ - '.blocklyToolboxDiv {', - 'background-color: #ddd;', - 'overflow-x: visible;', - 'overflow-y: auto;', - 'padding: 4px 0 4px 0;', - 'position: absolute;', - 'z-index: 70;', /* so blocks go under toolbox when dragging */ - '-webkit-tap-highlight-color: transparent;', /* issue #1345 */ + '.blocklyToolboxDiv {', 'background-color: #ddd;', 'overflow-x: visible;', + 'overflow-y: auto;', 'padding: 4px 0 4px 0;', 'position: absolute;', + 'z-index: 70;', /* so blocks go under toolbox when dragging */ + '-webkit-tap-highlight-color: transparent;', /* issue #1345 */ '}', - '.blocklyToolboxContents {', - 'display: flex;', - 'flex-wrap: wrap;', - 'flex-direction: column;', - '}', + '.blocklyToolboxContents {', 'display: flex;', 'flex-wrap: wrap;', + 'flex-direction: column;', '}', - '.blocklyToolboxContents:focus {', - 'outline: none;', - '}', + '.blocklyToolboxContents:focus {', 'outline: none;', '}', /* eslint-enable indent */ ]); -Blockly.registry.register(Blockly.registry.Type.TOOLBOX, - Blockly.registry.DEFAULT, Blockly.Toolbox); +registry.register(registry.Type.TOOLBOX, registry.DEFAULT, Toolbox); + +exports = Toolbox; diff --git a/core/toolbox/toolbox_item.js b/core/toolbox/toolbox_item.js index febc0a068..7cffe6540 100644 --- a/core/toolbox/toolbox_item.js +++ b/core/toolbox/toolbox_item.js @@ -10,38 +10,43 @@ */ 'use strict'; -goog.provide('Blockly.ToolboxItem'); +goog.module('Blockly.ToolboxItem'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.IToolboxItem'); - -goog.requireType('Blockly.ICollapsibleToolboxItem'); -goog.requireType('Blockly.IToolbox'); -goog.requireType('Blockly.utils.toolbox'); -goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const ICollapsibleToolboxItem = goog.requireType('Blockly.ICollapsibleToolboxItem'); +const IdGenerator = goog.require('Blockly.utils.IdGenerator'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +/* eslint-disable-next-line no-unused-vars */ +const IToolboxItem = goog.requireType('Blockly.IToolboxItem'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const toolbox = goog.requireType('Blockly.utils.toolbox'); /** * Class for an item in the toolbox. - * @param {!Blockly.utils.toolbox.ToolboxItemInfo} toolboxItemDef The JSON defining the + * @param {!toolbox.ToolboxItemInfo} toolboxItemDef The JSON defining the * toolbox item. - * @param {!Blockly.IToolbox} toolbox The toolbox that holds the toolbox item. - * @param {Blockly.ICollapsibleToolboxItem=} opt_parent The parent toolbox item + * @param {!IToolbox} toolbox The toolbox that holds the toolbox item. + * @param {ICollapsibleToolboxItem=} opt_parent The parent toolbox item * or null if the category does not have a parent. * @constructor - * @implements {Blockly.IToolboxItem} + * @implements {IToolboxItem} */ -Blockly.ToolboxItem = function(toolboxItemDef, toolbox, opt_parent) { - +const ToolboxItem = function(toolboxItemDef, toolbox, opt_parent) { /** * The id for the category. * @type {string} * @protected */ - this.id_ = toolboxItemDef['toolboxitemid'] || Blockly.utils.IdGenerator.getNextUniqueId(); + this.id_ = toolboxItemDef['toolboxitemid'] || IdGenerator.getNextUniqueId(); /** * The parent of the category. - * @type {?Blockly.ICollapsibleToolboxItem} + * @type {?ICollapsibleToolboxItem} * @protected */ this.parent_ = opt_parent || null; @@ -55,21 +60,21 @@ Blockly.ToolboxItem = function(toolboxItemDef, toolbox, opt_parent) { /** * The JSON definition of the toolbox item. - * @type {!Blockly.utils.toolbox.ToolboxItemInfo} + * @type {!toolbox.ToolboxItemInfo} * @protected */ this.toolboxItemDef_ = toolboxItemDef; /** * The toolbox this category belongs to. - * @type {!Blockly.IToolbox} + * @type {!IToolbox} * @protected */ this.parentToolbox_ = toolbox; /** * The workspace of the parent toolbox. - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @protected */ this.workspace_ = this.parentToolbox_.getWorkspace(); @@ -81,7 +86,7 @@ Blockly.ToolboxItem = function(toolboxItemDef, toolbox, opt_parent) { * on the info object. * @public */ -Blockly.ToolboxItem.prototype.init = function() { +ToolboxItem.prototype.init = function() { // No-op by default. }; @@ -90,7 +95,7 @@ Blockly.ToolboxItem.prototype.init = function() { * @return {?Element} The div for the toolbox item. * @public */ -Blockly.ToolboxItem.prototype.getDiv = function() { +ToolboxItem.prototype.getDiv = function() { return null; }; @@ -99,17 +104,17 @@ Blockly.ToolboxItem.prototype.getDiv = function() { * @return {string} The ID for the toolbox item. * @public */ -Blockly.ToolboxItem.prototype.getId = function() { +ToolboxItem.prototype.getId = function() { return this.id_; }; /** * Gets the parent if the toolbox item is nested. - * @return {?Blockly.IToolboxItem} The parent toolbox item, or null if + * @return {?IToolboxItem} The parent toolbox item, or null if * this toolbox item is not nested. * @public */ -Blockly.ToolboxItem.prototype.getParent = function() { +ToolboxItem.prototype.getParent = function() { return null; }; @@ -118,7 +123,7 @@ Blockly.ToolboxItem.prototype.getParent = function() { * @return {number} The nested level of the category. * @package */ -Blockly.ToolboxItem.prototype.getLevel = function() { +ToolboxItem.prototype.getLevel = function() { return this.level_; }; @@ -127,7 +132,7 @@ Blockly.ToolboxItem.prototype.getLevel = function() { * @return {boolean} True if the toolbox item can be selected. * @public */ -Blockly.ToolboxItem.prototype.isSelectable = function() { +ToolboxItem.prototype.isSelectable = function() { return false; }; @@ -136,7 +141,7 @@ Blockly.ToolboxItem.prototype.isSelectable = function() { * @return {boolean} True if the toolbox item is collapsible. * @public */ -Blockly.ToolboxItem.prototype.isCollapsible = function() { +ToolboxItem.prototype.isCollapsible = function() { return false; }; @@ -144,5 +149,6 @@ Blockly.ToolboxItem.prototype.isCollapsible = function() { * Dispose of this toolbox item. No-op by default. * @public */ -Blockly.ToolboxItem.prototype.dispose = function() { -}; +ToolboxItem.prototype.dispose = function() {}; + +exports = ToolboxItem; diff --git a/core/tooltip.js b/core/tooltip.js index 12819e13f..d93825815 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -22,6 +22,7 @@ goog.provide('Blockly.Tooltip'); goog.require('Blockly.browserEvents'); +goog.require('Blockly.common'); goog.require('Blockly.utils.string'); @@ -170,7 +171,7 @@ Blockly.Tooltip.createDom = function() { // Create an HTML container for popup overlays (e.g. editor widgets). Blockly.Tooltip.DIV = document.createElement('div'); Blockly.Tooltip.DIV.className = 'blocklyTooltipDiv'; - var container = Blockly.parentContainer || document.body; + var container = Blockly.common.getParentContainer() || document.body; container.appendChild(Blockly.Tooltip.DIV); }; diff --git a/core/trashcan.js b/core/trashcan.js index 619299b21..49596ae83 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -10,47 +10,56 @@ */ 'use strict'; -goog.provide('Blockly.Trashcan'); +goog.module('Blockly.Trashcan'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.ComponentManager'); -goog.require('Blockly.DeleteArea'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Abstract = goog.requireType('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions'); +const ComponentManager = goog.require('Blockly.ComponentManager'); +const DeleteArea = goog.require('Blockly.DeleteArea'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const IAutoHideable = goog.requireType('Blockly.IAutoHideable'); +/* eslint-disable-next-line no-unused-vars */ +const IDraggable = goog.requireType('Blockly.IDraggable'); +/* eslint-disable-next-line no-unused-vars */ +const IFlyout = goog.requireType('Blockly.IFlyout'); +/* eslint-disable-next-line no-unused-vars */ +const IPositionable = goog.requireType('Blockly.IPositionable'); +/* eslint-disable-next-line no-unused-vars */ +const MetricsManager = goog.requireType('Blockly.MetricsManager'); +const Options = goog.require('Blockly.Options'); +const Rect = goog.require('Blockly.utils.Rect'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const Xml = goog.require('Blockly.Xml'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const internalConstants = goog.require('Blockly.internalConstants'); +const registry = goog.require('Blockly.registry'); +const toolbox = goog.require('Blockly.utils.toolbox'); +const uiPosition = goog.require('Blockly.uiPosition'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.TrashcanOpen'); -goog.require('Blockly.IAutoHideable'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.IPositionable'); -goog.require('Blockly.Options'); -goog.require('Blockly.registry'); -goog.require('Blockly.uiPosition'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.utils.toolbox'); -goog.require('Blockly.Xml'); - -goog.requireType('Blockly.Events.Abstract'); -goog.requireType('Blockly.IDraggable'); -goog.requireType('Blockly.IFlyout'); -goog.requireType('Blockly.utils.Rect'); -goog.requireType('Blockly.WorkspaceSvg'); /** * Class for a trash can. - * @param {!Blockly.WorkspaceSvg} workspace The workspace to sit in. + * @param {!WorkspaceSvg} workspace The workspace to sit in. * @constructor - * @implements {Blockly.IAutoHideable} - * @implements {Blockly.IPositionable} - * @extends {Blockly.DeleteArea} + * @implements {IAutoHideable} + * @implements {IPositionable} + * @extends {DeleteArea} */ -Blockly.Trashcan = function(workspace) { - Blockly.Trashcan.superClass_.constructor.call(this); +const Trashcan = function(workspace) { + Trashcan.superClass_.constructor.call(this); /** * The workspace the trashcan sits in. - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.workspace_ = workspace; @@ -71,7 +80,7 @@ Blockly.Trashcan = function(workspace) { /** * The trashcan flyout. - * @type {Blockly.IFlyout} + * @type {IFlyout} * @package */ this.flyout = null; @@ -80,8 +89,8 @@ Blockly.Trashcan = function(workspace) { return; } // Create flyout options. - var flyoutWorkspaceOptions = new Blockly.Options( - /** @type {!Blockly.BlocklyOptions} */ + const flyoutWorkspaceOptions = new Options( + /** @type {!BlocklyOptions} */ ({ 'scrollbars': true, 'parentWorkspace': this.workspace_, @@ -96,130 +105,103 @@ Blockly.Trashcan = function(workspace) { // Create vertical or horizontal flyout. if (this.workspace_.horizontalLayout) { flyoutWorkspaceOptions.toolboxPosition = - this.workspace_.toolboxPosition == Blockly.utils.toolbox.Position.TOP ? - Blockly.utils.toolbox.Position.BOTTOM : Blockly.utils.toolbox.Position.TOP; - var HorizontalFlyout = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, - this.workspace_.options, true); + this.workspace_.toolboxPosition == toolbox.Position.TOP ? + toolbox.Position.BOTTOM : + toolbox.Position.TOP; + const HorizontalFlyout = registry.getClassFromOptions( + registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, this.workspace_.options, + true); this.flyout = new HorizontalFlyout(flyoutWorkspaceOptions); } else { flyoutWorkspaceOptions.toolboxPosition = - this.workspace_.toolboxPosition == Blockly.utils.toolbox.Position.RIGHT ? - Blockly.utils.toolbox.Position.LEFT : Blockly.utils.toolbox.Position.RIGHT; - var VerticalFlyout = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX, - this.workspace_.options, true); + this.workspace_.toolboxPosition == toolbox.Position.RIGHT ? + toolbox.Position.LEFT : + toolbox.Position.RIGHT; + const VerticalFlyout = registry.getClassFromOptions( + registry.Type.FLYOUTS_VERTICAL_TOOLBOX, this.workspace_.options, true); this.flyout = new VerticalFlyout(flyoutWorkspaceOptions); } this.workspace_.addChangeListener(this.onDelete_.bind(this)); }; -Blockly.utils.object.inherits(Blockly.Trashcan, Blockly.DeleteArea); +utils.object.inherits(Trashcan, DeleteArea); /** * Width of both the trash can and lid images. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.WIDTH_ = 47; +const WIDTH = 47; /** * Height of the trashcan image (minus lid). - * @const {number} - * @private */ -Blockly.Trashcan.prototype.BODY_HEIGHT_ = 44; +const BODY_HEIGHT = 44; /** * Height of the lid image. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.LID_HEIGHT_ = 16; +const LID_HEIGHT = 16; /** * Distance between trashcan and bottom or top edge of workspace. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.MARGIN_VERTICAL_ = 20; +const MARGIN_VERTICAL = 20; /** * Distance between trashcan and right or left edge of workspace. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.MARGIN_HORIZONTAL_ = 20; +const MARGIN_HORIZONTAL = 20; /** * Extent of hotspot on all sides beyond the size of the image. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.MARGIN_HOTSPOT_ = 10; +const MARGIN_HOTSPOT = 10; /** * Location of trashcan in sprite image. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.SPRITE_LEFT_ = 0; +const SPRITE_LEFT = 0; /** * Location of trashcan in sprite image. - * @const {number} - * @private */ -Blockly.Trashcan.prototype.SPRITE_TOP_ = 32; +const SPRITE_TOP = 32; /** * The openness of the lid when the trashcan contains blocks. * (0.0 = closed, 1.0 = open) - * @const {number} - * @private */ -Blockly.Trashcan.prototype.HAS_BLOCKS_LID_ANGLE_ = 0.1; +const HAS_BLOCKS_LID_ANGLE = 0.1; /** * The length of the lid open/close animation in milliseconds. - * @const {number} - * @private */ -Blockly.Trashcan.ANIMATION_LENGTH_ = 80; +const ANIMATION_LENGTH = 80; /** * The number of frames in the animation. - * @const {number} - * @private */ -Blockly.Trashcan.ANIMATION_FRAMES_ = 4; +const ANIMATION_FRAMES = 4; /** * The minimum (resting) opacity of the trashcan and lid. - * @const {number} - * @private */ -Blockly.Trashcan.OPACITY_MIN_ = 0.4; +const OPACITY_MIN = 0.4; /** * The maximum (hovered) opacity of the trashcan and lid. - * @const {number} - * @private */ -Blockly.Trashcan.OPACITY_MAX_ = 0.8; +const OPACITY_MAX = 0.8; /** * The maximum angle the trashcan lid can opens to. At the end of the open * animation the lid will be open to this angle. - * @const {number} - * @private */ -Blockly.Trashcan.MAX_LID_ANGLE_ = 45; +const MAX_LID_ANGLE = 45; /** * Current open/close state of the lid. * @type {boolean} */ -Blockly.Trashcan.prototype.isLidOpen = false; +Trashcan.prototype.isLidOpen = false; /** * The minimum openness of the lid. Used to indicate if the trashcan contains @@ -227,62 +209,62 @@ Blockly.Trashcan.prototype.isLidOpen = false; * @type {number} * @private */ -Blockly.Trashcan.prototype.minOpenness_ = 0; +Trashcan.prototype.minOpenness_ = 0; /** * The SVG group containing the trash can. * @type {SVGElement} * @private */ -Blockly.Trashcan.prototype.svgGroup_ = null; +Trashcan.prototype.svgGroup_ = null; /** * The SVG image element of the trash can lid. * @type {SVGElement} * @private */ -Blockly.Trashcan.prototype.svgLid_ = null; +Trashcan.prototype.svgLid_ = null; /** * Task ID of opening/closing animation. * @type {number} * @private */ -Blockly.Trashcan.prototype.lidTask_ = 0; +Trashcan.prototype.lidTask_ = 0; /** * Current state of lid opening (0.0 = closed, 1.0 = open). * @type {number} * @private */ -Blockly.Trashcan.prototype.lidOpen_ = 0; +Trashcan.prototype.lidOpen_ = 0; /** * Left coordinate of the trash can. * @type {number} * @private */ -Blockly.Trashcan.prototype.left_ = 0; +Trashcan.prototype.left_ = 0; /** * Top coordinate of the trash can. * @type {number} * @private */ -Blockly.Trashcan.prototype.top_ = 0; +Trashcan.prototype.top_ = 0; /** * Whether this has been initialized. * @type {boolean} * @private */ -Blockly.Trashcan.prototype.initialized_ = false; +Trashcan.prototype.initialized_ = false; /** * Create the trash can elements. * @return {!SVGElement} The trash can's SVG group. */ -Blockly.Trashcan.prototype.createDom = function() { +Trashcan.prototype.createDom = function() { /* Here's the markup that will be generated: @@ -297,68 +279,52 @@ Blockly.Trashcan.prototype.createDom = function() { clip-path="url(#blocklyTrashLidClipPath837493)"> */ - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - {'class': 'blocklyTrash'}, null); - var clip; - var rnd = String(Math.random()).substring(2); - clip = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.CLIPPATH, - {'id': 'blocklyTrashBodyClipPath' + rnd}, - this.svgGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - 'width': this.WIDTH_, - 'height': this.BODY_HEIGHT_, - 'y': this.LID_HEIGHT_ - }, - clip); - var body = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.IMAGE, { - 'width': Blockly.internalConstants.SPRITE.width, - 'x': -this.SPRITE_LEFT_, - 'height': Blockly.internalConstants.SPRITE.height, - 'y': -this.SPRITE_TOP_, + this.svgGroup_ = dom.createSvgElement(Svg.G, {'class': 'blocklyTrash'}, null); + let clip; + const rnd = String(Math.random()).substring(2); + clip = dom.createSvgElement( + Svg.CLIPPATH, {'id': 'blocklyTrashBodyClipPath' + rnd}, this.svgGroup_); + dom.createSvgElement( + Svg.RECT, {'width': WIDTH, 'height': BODY_HEIGHT, 'y': LID_HEIGHT}, clip); + const body = dom.createSvgElement( + Svg.IMAGE, { + 'width': internalConstants.SPRITE.width, + 'x': -SPRITE_LEFT, + 'height': internalConstants.SPRITE.height, + 'y': -SPRITE_TOP, 'clip-path': 'url(#blocklyTrashBodyClipPath' + rnd + ')' }, this.svgGroup_); body.setAttributeNS( - Blockly.utils.dom.XLINK_NS, 'xlink:href', - this.workspace_.options.pathToMedia + - Blockly.internalConstants.SPRITE.url); + dom.XLINK_NS, 'xlink:href', + this.workspace_.options.pathToMedia + internalConstants.SPRITE.url); - clip = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.CLIPPATH, - {'id': 'blocklyTrashLidClipPath' + rnd}, - this.svgGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - {'width': this.WIDTH_, 'height': this.LID_HEIGHT_}, clip); - this.svgLid_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.IMAGE, { - 'width': Blockly.internalConstants.SPRITE.width, - 'x': -this.SPRITE_LEFT_, - 'height': Blockly.internalConstants.SPRITE.height, - 'y': -this.SPRITE_TOP_, + clip = dom.createSvgElement( + Svg.CLIPPATH, {'id': 'blocklyTrashLidClipPath' + rnd}, this.svgGroup_); + dom.createSvgElement(Svg.RECT, {'width': WIDTH, 'height': LID_HEIGHT}, clip); + this.svgLid_ = dom.createSvgElement( + Svg.IMAGE, { + 'width': internalConstants.SPRITE.width, + 'x': -SPRITE_LEFT, + 'height': internalConstants.SPRITE.height, + 'y': -SPRITE_TOP, 'clip-path': 'url(#blocklyTrashLidClipPath' + rnd + ')' }, this.svgGroup_); this.svgLid_.setAttributeNS( - Blockly.utils.dom.XLINK_NS, 'xlink:href', - this.workspace_.options.pathToMedia + - Blockly.internalConstants.SPRITE.url); + dom.XLINK_NS, 'xlink:href', + this.workspace_.options.pathToMedia + internalConstants.SPRITE.url); // bindEventWithChecks_ quashes events too aggressively. See: // https://groups.google.com/forum/#!topic/blockly/QF4yB9Wx00s // Using bindEventWithChecks_ for blocking mousedown causes issue in mobile. // See #4303 - Blockly.browserEvents.bind( + browserEvents.bind( this.svgGroup_, 'mousedown', this, this.blockMouseDownWhenOpenable_); - Blockly.browserEvents.bind(this.svgGroup_, 'mouseup', this, this.click); + browserEvents.bind(this.svgGroup_, 'mouseup', this, this.click); // Bind to body instead of this.svgGroup_ so that we don't get lid jitters - Blockly.browserEvents.bind(body, 'mouseover', this, this.mouseOver_); - Blockly.browserEvents.bind(body, 'mouseout', this, this.mouseOut_); + browserEvents.bind(body, 'mouseover', this, this.mouseOver_); + browserEvents.bind(body, 'mouseout', this, this.mouseOut_); this.animateLid_(); return this.svgGroup_; }; @@ -366,21 +332,20 @@ Blockly.Trashcan.prototype.createDom = function() { /** * Initializes the trash can. */ -Blockly.Trashcan.prototype.init = function() { +Trashcan.prototype.init = function() { if (this.workspace_.options.maxTrashcanContents > 0) { - Blockly.utils.dom.insertAfter( - this.flyout.createDom(Blockly.utils.Svg.SVG), - this.workspace_.getParentSvg()); + dom.insertAfter( + this.flyout.createDom(Svg.SVG), this.workspace_.getParentSvg()); this.flyout.init(this.workspace_); } this.workspace_.getComponentManager().addComponent({ component: this, weight: 1, capabilities: [ - Blockly.ComponentManager.Capability.AUTOHIDEABLE, - Blockly.ComponentManager.Capability.DELETE_AREA, - Blockly.ComponentManager.Capability.DRAG_TARGET, - Blockly.ComponentManager.Capability.POSITIONABLE + ComponentManager.Capability.AUTOHIDEABLE, + ComponentManager.Capability.DELETE_AREA, + ComponentManager.Capability.DRAG_TARGET, + ComponentManager.Capability.POSITIONABLE ] }); this.initialized_ = true; @@ -392,10 +357,10 @@ Blockly.Trashcan.prototype.init = function() { * Unlink from all DOM elements to prevent memory leaks. * @suppress {checkTypes} */ -Blockly.Trashcan.prototype.dispose = function() { +Trashcan.prototype.dispose = function() { this.workspace_.getComponentManager().removeComponent('trashcan'); if (this.svgGroup_) { - Blockly.utils.dom.removeNode(this.svgGroup_); + dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgLid_ = null; @@ -408,7 +373,7 @@ Blockly.Trashcan.prototype.dispose = function() { * @return {boolean} True if the trashcan has contents. * @private */ -Blockly.Trashcan.prototype.hasContents_ = function() { +Trashcan.prototype.hasContents_ = function() { return !!this.contents_.length; }; @@ -416,18 +381,18 @@ Blockly.Trashcan.prototype.hasContents_ = function() { * Returns true if the trashcan contents-flyout is currently open. * @return {boolean} True if the trashcan contents-flyout is currently open. */ -Blockly.Trashcan.prototype.contentsIsOpen = function() { +Trashcan.prototype.contentsIsOpen = function() { return this.flyout.isVisible(); }; /** * Opens the trashcan flyout. */ -Blockly.Trashcan.prototype.openFlyout = function() { +Trashcan.prototype.openFlyout = function() { if (this.contentsIsOpen()) { return; } - var xml = this.contents_.map(Blockly.Xml.textToDom); + const xml = this.contents_.map(Xml.textToDom); this.flyout.show(xml); this.fireUiEvent_(true); }; @@ -435,7 +400,7 @@ Blockly.Trashcan.prototype.openFlyout = function() { /** * Closes the trashcan flyout. */ -Blockly.Trashcan.prototype.closeFlyout = function() { +Trashcan.prototype.closeFlyout = function() { if (!this.contentsIsOpen()) { return; } @@ -448,7 +413,7 @@ Blockly.Trashcan.prototype.closeFlyout = function() { * @param {boolean} onlyClosePopups Whether only popups should be closed. * Flyouts should not be closed if this is true. */ -Blockly.Trashcan.prototype.autoHide = function(onlyClosePopups) { +Trashcan.prototype.autoHide = function(onlyClosePopups) { // For now the trashcan flyout always autocloses because it overlays the // trashcan UI (no trashcan to click to close it). if (!onlyClosePopups && this.flyout) { @@ -460,7 +425,7 @@ Blockly.Trashcan.prototype.autoHide = function(onlyClosePopups) { * Empties the trashcan's contents. If the contents-flyout is currently open * it will be closed. */ -Blockly.Trashcan.prototype.emptyContents = function() { +Trashcan.prototype.emptyContents = function() { if (!this.hasContents_()) { return; } @@ -473,99 +438,97 @@ Blockly.Trashcan.prototype.emptyContents = function() { * Positions the trashcan. * It is positioned in the opposite corner to the corner the * categories/toolbox starts at. - * @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace metrics. - * @param {!Array} savedPositions List of rectangles that + * @param {!MetricsManager.UiMetrics} metrics The workspace metrics. + * @param {!Array} savedPositions List of rectangles that * are already on the workspace. */ -Blockly.Trashcan.prototype.position = function(metrics, savedPositions) { +Trashcan.prototype.position = function(metrics, savedPositions) { // Not yet initialized. if (!this.initialized_) { return; } - var cornerPosition = - Blockly.uiPosition.getCornerOppositeToolbox(this.workspace_, metrics); + const cornerPosition = + uiPosition.getCornerOppositeToolbox(this.workspace_, metrics); - var height = this.BODY_HEIGHT_ + this.LID_HEIGHT_; - var startRect = Blockly.uiPosition.getStartPositionRect( - cornerPosition, new Blockly.utils.Size(this.WIDTH_, height), - this.MARGIN_HORIZONTAL_, this.MARGIN_VERTICAL_, metrics, this.workspace_); + const height = BODY_HEIGHT + LID_HEIGHT; + const startRect = uiPosition.getStartPositionRect( + cornerPosition, new utils.Size(WIDTH, height), MARGIN_HORIZONTAL, + MARGIN_VERTICAL, metrics, this.workspace_); - var verticalPosition = cornerPosition.vertical; - var bumpDirection = - verticalPosition === Blockly.uiPosition.verticalPosition.TOP ? - Blockly.uiPosition.bumpDirection.DOWN : - Blockly.uiPosition.bumpDirection.UP; - var positionRect = Blockly.uiPosition.bumpPositionRect( - startRect, this.MARGIN_VERTICAL_, bumpDirection, savedPositions); + const verticalPosition = cornerPosition.vertical; + const bumpDirection = verticalPosition === uiPosition.verticalPosition.TOP ? + uiPosition.bumpDirection.DOWN : + uiPosition.bumpDirection.UP; + const positionRect = uiPosition.bumpPositionRect( + startRect, MARGIN_VERTICAL, bumpDirection, savedPositions); this.top_ = positionRect.top; this.left_ = positionRect.left; - this.svgGroup_.setAttribute('transform', - 'translate(' + this.left_ + ',' + this.top_ + ')'); + this.svgGroup_.setAttribute( + 'transform', 'translate(' + this.left_ + ',' + this.top_ + ')'); }; /** * Returns the bounding rectangle of the UI element in pixel units relative to * the Blockly injection div. - * @return {?Blockly.utils.Rect} The UI elements’s bounding box. Null if + * @return {?Rect} The UI elements’s bounding box. Null if * bounding box should be ignored by other UI elements. */ -Blockly.Trashcan.prototype.getBoundingRectangle = function() { - var bottom = this.top_ + this.BODY_HEIGHT_ + this.LID_HEIGHT_; - var right = this.left_ + this.WIDTH_; - return new Blockly.utils.Rect(this.top_, bottom, this.left_, right); +Trashcan.prototype.getBoundingRectangle = function() { + const bottom = this.top_ + BODY_HEIGHT + LID_HEIGHT; + const right = this.left_ + WIDTH; + return new Rect(this.top_, bottom, this.left_, right); }; /** * Returns the bounding rectangle of the drag target area in pixel units * relative to viewport. - * @return {?Blockly.utils.Rect} The component's bounding box. Null if drag + * @return {?Rect} The component's bounding box. Null if drag * target area should be ignored. */ -Blockly.Trashcan.prototype.getClientRect = function() { +Trashcan.prototype.getClientRect = function() { if (!this.svgGroup_) { return null; } - var trashRect = this.svgGroup_.getBoundingClientRect(); - var top = trashRect.top + this.SPRITE_TOP_ - this.MARGIN_HOTSPOT_; - var bottom = top + this.LID_HEIGHT_ + this.BODY_HEIGHT_ + - 2 * this.MARGIN_HOTSPOT_; - var left = trashRect.left + this.SPRITE_LEFT_ - this.MARGIN_HOTSPOT_; - var right = left + this.WIDTH_ + 2 * this.MARGIN_HOTSPOT_; - return new Blockly.utils.Rect(top, bottom, left, right); + const trashRect = this.svgGroup_.getBoundingClientRect(); + const top = trashRect.top + SPRITE_TOP - MARGIN_HOTSPOT; + const bottom = top + LID_HEIGHT + BODY_HEIGHT + 2 * MARGIN_HOTSPOT; + const left = trashRect.left + SPRITE_LEFT - MARGIN_HOTSPOT; + const right = left + WIDTH + 2 * MARGIN_HOTSPOT; + return new Rect(top, bottom, left, right); }; /** * Handles when a cursor with a block or bubble is dragged over this drag * target. - * @param {!Blockly.IDraggable} _dragElement The block or bubble currently being + * @param {!IDraggable} _dragElement The block or bubble currently being * dragged. * @override */ -Blockly.Trashcan.prototype.onDragOver = function(_dragElement) { +Trashcan.prototype.onDragOver = function(_dragElement) { this.setLidOpen(this.wouldDelete_); }; /** * Handles when a cursor with a block or bubble exits this drag target. - * @param {!Blockly.IDraggable} _dragElement The block or bubble currently being + * @param {!IDraggable} _dragElement The block or bubble currently being * dragged. * @override */ -Blockly.Trashcan.prototype.onDragExit = function(_dragElement) { +Trashcan.prototype.onDragExit = function(_dragElement) { this.setLidOpen(false); }; /** * Handles when a block or bubble is dropped on this component. * Should not handle delete here. - * @param {!Blockly.IDraggable} _dragElement The block or bubble currently being + * @param {!IDraggable} _dragElement The block or bubble currently being * dragged. * @override */ -Blockly.Trashcan.prototype.onDrop = function(_dragElement) { +Trashcan.prototype.onDrop = function(_dragElement) { setTimeout(this.setLidOpen.bind(this, false), 100); }; @@ -574,7 +537,7 @@ Blockly.Trashcan.prototype.onDrop = function(_dragElement) { * @param {boolean} state True if open. * @package */ -Blockly.Trashcan.prototype.setLidOpen = function(state) { +Trashcan.prototype.setLidOpen = function(state) { if (this.isLidOpen == state) { return; } @@ -587,24 +550,22 @@ Blockly.Trashcan.prototype.setLidOpen = function(state) { * Rotate the lid open or closed by one step. Then wait and recurse. * @private */ -Blockly.Trashcan.prototype.animateLid_ = function() { - var frames = Blockly.Trashcan.ANIMATION_FRAMES_; +Trashcan.prototype.animateLid_ = function() { + const frames = ANIMATION_FRAMES; - var delta = 1 / (frames + 1); + const delta = 1 / (frames + 1); this.lidOpen_ += this.isLidOpen ? delta : -delta; this.lidOpen_ = Math.min(Math.max(this.lidOpen_, this.minOpenness_), 1); - this.setLidAngle_(this.lidOpen_ * Blockly.Trashcan.MAX_LID_ANGLE_); + this.setLidAngle_(this.lidOpen_ * MAX_LID_ANGLE); - var minOpacity = Blockly.Trashcan.OPACITY_MIN_; - var maxOpacity = Blockly.Trashcan.OPACITY_MAX_; // Linear interpolation between min and max. - var opacity = minOpacity + this.lidOpen_ * (maxOpacity - minOpacity); + const opacity = OPACITY_MIN + this.lidOpen_ * (OPACITY_MAX - OPACITY_MIN); this.svgGroup_.style.opacity = opacity; if (this.lidOpen_ > this.minOpenness_ && this.lidOpen_ < 1) { - this.lidTask_ = setTimeout(this.animateLid_.bind(this), - Blockly.Trashcan.ANIMATION_LENGTH_ / frames); + this.lidTask_ = + setTimeout(this.animateLid_.bind(this), ANIMATION_LENGTH / frames); } }; @@ -613,14 +574,14 @@ Blockly.Trashcan.prototype.animateLid_ = function() { * @param {number} lidAngle The angle at which to set the lid. * @private */ -Blockly.Trashcan.prototype.setLidAngle_ = function(lidAngle) { - var openAtRight = - this.workspace_.toolboxPosition == Blockly.utils.toolbox.Position.RIGHT || +Trashcan.prototype.setLidAngle_ = function(lidAngle) { + const openAtRight = + this.workspace_.toolboxPosition == toolbox.Position.RIGHT || (this.workspace_.horizontalLayout && this.workspace_.RTL); - this.svgLid_.setAttribute('transform', 'rotate(' + - (openAtRight ? -lidAngle : lidAngle) + ',' + - (openAtRight ? 4 : this.WIDTH_ - 4) + ',' + - (this.LID_HEIGHT_ - 2) + ')'); + this.svgLid_.setAttribute( + 'transform', + 'rotate(' + (openAtRight ? -lidAngle : lidAngle) + ',' + + (openAtRight ? 4 : WIDTH - 4) + ',' + (LID_HEIGHT - 2) + ')'); }; /** @@ -630,10 +591,10 @@ Blockly.Trashcan.prototype.setLidAngle_ = function(lidAngle) { * 0 and 1. * @private */ -Blockly.Trashcan.prototype.setMinOpenness_ = function(newMin) { +Trashcan.prototype.setMinOpenness_ = function(newMin) { this.minOpenness_ = newMin; if (!this.isLidOpen) { - this.setLidAngle_(newMin * Blockly.Trashcan.MAX_LID_ANGLE_); + this.setLidAngle_(newMin * MAX_LID_ANGLE); } }; @@ -641,14 +602,14 @@ Blockly.Trashcan.prototype.setMinOpenness_ = function(newMin) { * Flip the lid shut. * Called externally after a drag. */ -Blockly.Trashcan.prototype.closeLid = function() { +Trashcan.prototype.closeLid = function() { this.setLidOpen(false); }; /** * Inspect the contents of the trash. */ -Blockly.Trashcan.prototype.click = function() { +Trashcan.prototype.click = function() { if (!this.hasContents_()) { return; } @@ -660,10 +621,10 @@ Blockly.Trashcan.prototype.click = function() { * @param {boolean} trashcanOpen Whether the flyout is opening. * @private */ -Blockly.Trashcan.prototype.fireUiEvent_ = function(trashcanOpen) { - var uiEvent = new (Blockly.Events.get(Blockly.Events.TRASHCAN_OPEN))( - trashcanOpen,this.workspace_.id); - Blockly.Events.fire(uiEvent); +Trashcan.prototype.fireUiEvent_ = function(trashcanOpen) { + const uiEvent = + new (Events.get(Events.TRASHCAN_OPEN))(trashcanOpen, this.workspace_.id); + Events.fire(uiEvent); }; /** @@ -671,7 +632,7 @@ Blockly.Trashcan.prototype.fireUiEvent_ = function(trashcanOpen) { * @param {!Event} e A mouse down event. * @private */ -Blockly.Trashcan.prototype.blockMouseDownWhenOpenable_ = function(e) { +Trashcan.prototype.blockMouseDownWhenOpenable_ = function(e) { if (!this.contentsIsOpen() && this.hasContents_()) { e.stopPropagation(); // Don't start a workspace scroll. } @@ -681,7 +642,7 @@ Blockly.Trashcan.prototype.blockMouseDownWhenOpenable_ = function(e) { * Indicate that the trashcan can be clicked (by opening it) if it has blocks. * @private */ -Blockly.Trashcan.prototype.mouseOver_ = function() { +Trashcan.prototype.mouseOver_ = function() { if (this.hasContents_()) { this.setLidOpen(true); } @@ -692,7 +653,7 @@ Blockly.Trashcan.prototype.mouseOver_ = function() { * blocks). * @private */ -Blockly.Trashcan.prototype.mouseOut_ = function() { +Trashcan.prototype.mouseOut_ = function() { // No need to do a .hasBlocks check here because if it doesn't the trashcan // won't be open in the first place, and setOpen won't run. this.setLidOpen(false); @@ -700,27 +661,27 @@ Blockly.Trashcan.prototype.mouseOut_ = function() { /** * Handle a BLOCK_DELETE event. Adds deleted blocks oldXml to the content array. - * @param {!Blockly.Events.Abstract} event Workspace event. + * @param {!Abstract} event Workspace event. * @private */ -Blockly.Trashcan.prototype.onDelete_ = function(event) { +Trashcan.prototype.onDelete_ = function(event) { if (this.workspace_.options.maxTrashcanContents <= 0) { return; } // Must check that the tagName exists since oldXml can be a DocumentFragment. - if (event.type == Blockly.Events.BLOCK_DELETE && event.oldXml.tagName && + if (event.type == Events.BLOCK_DELETE && event.oldXml.tagName && event.oldXml.tagName.toLowerCase() != 'shadow') { - var cleanedXML = this.cleanBlockXML_(event.oldXml); + const cleanedXML = this.cleanBlockXML_(event.oldXml); if (this.contents_.indexOf(cleanedXML) != -1) { return; } this.contents_.unshift(cleanedXML); while (this.contents_.length > - this.workspace_.options.maxTrashcanContents) { + this.workspace_.options.maxTrashcanContents) { this.contents_.pop(); } - this.setMinOpenness_(this.HAS_BLOCKS_LID_ANGLE_); + this.setMinOpenness_(HAS_BLOCKS_LID_ANGLE); } }; @@ -733,9 +694,9 @@ Blockly.Trashcan.prototype.onDelete_ = function(event) { * attributes. * @private */ -Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { - var xmlBlock = xml.cloneNode(true); - var node = xmlBlock; +Trashcan.prototype.cleanBlockXML_ = function(xml) { + const xmlBlock = xml.cloneNode(true); + let node = xmlBlock; while (node) { // Things like text inside tags are still treated as nodes, but they // don't have attributes (or the removeAttribute function) so we can @@ -753,7 +714,7 @@ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { } // Try to go down the tree - var nextNode = node.firstChild || node.nextSibling; + let nextNode = node.firstChild || node.nextSibling; // If we can't go down, try to go back up the tree. if (!nextNode) { nextNode = node.parentNode; @@ -770,5 +731,7 @@ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { } node = nextNode; } - return Blockly.Xml.domToText(xmlBlock); + return Xml.domToText(xmlBlock); }; + +exports = Trashcan; diff --git a/core/utils/dom.js b/core/utils/dom.js index 57843c8b9..f226cf406 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -16,36 +16,38 @@ * @name Blockly.utils.dom * @namespace */ -goog.provide('Blockly.utils.dom'); +goog.module('Blockly.utils.dom'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.utils.userAgent'); +/* eslint-disable-next-line no-unused-vars */ +const Svg = goog.requireType('Blockly.utils.Svg'); +const userAgent = goog.require('Blockly.utils.userAgent'); /** * Required name space for SVG elements. * @const */ -Blockly.utils.dom.SVG_NS = 'http://www.w3.org/2000/svg'; +const SVG_NS = 'http://www.w3.org/2000/svg'; /** * Required name space for HTML elements. * @const */ -Blockly.utils.dom.HTML_NS = 'http://www.w3.org/1999/xhtml'; +const HTML_NS = 'http://www.w3.org/1999/xhtml'; /** * Required name space for XLINK elements. * @const */ -Blockly.utils.dom.XLINK_NS = 'http://www.w3.org/1999/xlink'; +const XLINK_NS = 'http://www.w3.org/1999/xlink'; /** * Node type constants. * https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType * @enum {number} */ -Blockly.utils.dom.NodeType = { +const NodeType = { ELEMENT_NODE: 1, TEXT_NODE: 3, COMMENT_NODE: 8, @@ -57,36 +59,35 @@ Blockly.utils.dom.NodeType = { * @type {Object} * @private */ -Blockly.utils.dom.cacheWidths_ = null; +let cacheWidths = null; /** * Number of current references to cache. * @type {number} * @private */ -Blockly.utils.dom.cacheReference_ = 0; +let cacheReference = 0; /** * A HTML canvas context used for computing text width. * @type {CanvasRenderingContext2D} * @private */ -Blockly.utils.dom.canvasContext_ = null; +let canvasContext = null; /** * Helper method for creating SVG elements. - * @param {string|Blockly.utils.Svg} name Element's tag name. + * @param {string|Svg} name Element's tag name. * @param {!Object} attrs Dictionary of attribute names and values. * @param {Element=} opt_parent Optional parent on which to append the element. * @return {T} Newly created SVG element. The return type is {!SVGElement} if - * name is a string or a more specific type if it a member of - * Blockly.utils.Svg + * name is a string or a more specific type if it a member of Svg. * @template T */ -Blockly.utils.dom.createSvgElement = function(name, attrs, opt_parent) { - var e = /** @type {T} */ - (document.createElementNS(Blockly.utils.dom.SVG_NS, String(name))); - for (var key in attrs) { +const createSvgElement = function(name, attrs, opt_parent) { + const e = /** @type {T} */ + (document.createElementNS(SVG_NS, String(name))); + for (const key in attrs) { e.setAttribute(key, attrs[key]); } // IE defines a unique attribute "runtimeStyle", it is NOT applied to @@ -108,8 +109,8 @@ Blockly.utils.dom.createSvgElement = function(name, attrs, opt_parent) { * @param {string} className Name of class to add. * @return {boolean} True if class was added, false if already present. */ -Blockly.utils.dom.addClass = function(element, className) { - var classes = element.getAttribute('class') || ''; +const addClass = function(element, className) { + let classes = element.getAttribute('class') || ''; if ((' ' + classes + ' ').indexOf(' ' + className + ' ') != -1) { return false; } @@ -126,11 +127,10 @@ Blockly.utils.dom.addClass = function(element, className) { * @param {string} classNames A string of one or multiple class names for an * element. */ -Blockly.utils.dom.removeClasses = function(element, classNames) { - var classList = classNames.split(' '); - for (var i = 0; i < classList.length; i++) { - var cssName = classList[i]; - Blockly.utils.dom.removeClass(element, cssName); +const removeClasses = function(element, classNames) { + const classList = classNames.split(' '); + for (let i = 0; i < classList.length; i++) { + removeClass(element, classList[i]); } }; @@ -141,13 +141,13 @@ Blockly.utils.dom.removeClasses = function(element, classNames) { * @param {string} className Name of class to remove. * @return {boolean} True if class was removed, false if never present. */ -Blockly.utils.dom.removeClass = function(element, className) { - var classes = element.getAttribute('class'); +const removeClass = function(element, className) { + const classes = element.getAttribute('class'); if ((' ' + classes + ' ').indexOf(' ' + className + ' ') == -1) { return false; } - var classList = classes.split(/\s+/); - for (var i = 0; i < classList.length; i++) { + const classList = classes.split(/\s+/); + for (let i = 0; i < classList.length; i++) { if (!classList[i] || classList[i] == className) { classList.splice(i, 1); i--; @@ -168,8 +168,8 @@ Blockly.utils.dom.removeClass = function(element, className) { * @param {string} className Name of class to check. * @return {boolean} True if class exists, false otherwise. */ -Blockly.utils.dom.hasClass = function(element, className) { - var classes = element.getAttribute('class'); +const hasClass = function(element, className) { + const classes = element.getAttribute('class'); return (' ' + classes + ' ').indexOf(' ' + className + ' ') != -1; }; @@ -179,7 +179,7 @@ Blockly.utils.dom.hasClass = function(element, className) { * @return {?Node} The node removed if removed; else, null. */ // Copied from Closure goog.dom.removeNode -Blockly.utils.dom.removeNode = function(node) { +const removeNode = function(node) { return node && node.parentNode ? node.parentNode.removeChild(node) : null; }; @@ -189,9 +189,9 @@ Blockly.utils.dom.removeNode = function(node) { * @param {!Element} newNode New element to insert. * @param {!Element} refNode Existing element to precede new node. */ -Blockly.utils.dom.insertAfter = function(newNode, refNode) { - var siblingNode = refNode.nextSibling; - var parentNode = refNode.parentNode; +const insertAfter = function(newNode, refNode) { + const siblingNode = refNode.nextSibling; + const parentNode = refNode.parentNode; if (!parentNode) { throw Error('Reference node has no parent.'); } @@ -208,9 +208,10 @@ Blockly.utils.dom.insertAfter = function(newNode, refNode) { * @param {!Node} descendant The node to test presence of. * @return {boolean} Whether the parent node contains the descendant node. */ -Blockly.utils.dom.containsNode = function(parent, descendant) { - return !!(parent.compareDocumentPosition(descendant) & - Blockly.utils.dom.NodeType.DOCUMENT_POSITION_CONTAINED_BY); +const containsNode = function(parent, descendant) { + return !!( + parent.compareDocumentPosition(descendant) & + NodeType.DOCUMENT_POSITION_CONTAINED_BY); }; /** @@ -220,7 +221,7 @@ Blockly.utils.dom.containsNode = function(parent, descendant) { * @param {!Element} element Element to which the CSS transform will be applied. * @param {string} transform The value of the CSS `transform` property. */ -Blockly.utils.dom.setCssTransform = function(element, transform) { +const setCssTransform = function(element, transform) { element.style['transform'] = transform; element.style['-webkit-transform'] = transform; }; @@ -229,10 +230,10 @@ Blockly.utils.dom.setCssTransform = function(element, transform) { * Start caching text widths. Every call to this function MUST also call * stopTextWidthCache. Caches must not survive between execution threads. */ -Blockly.utils.dom.startTextWidthCache = function() { - Blockly.utils.dom.cacheReference_++; - if (!Blockly.utils.dom.cacheWidths_) { - Blockly.utils.dom.cacheWidths_ = Object.create(null); +const startTextWidthCache = function() { + cacheReference++; + if (!cacheWidths) { + cacheWidths = Object.create(null); } }; @@ -240,10 +241,10 @@ Blockly.utils.dom.startTextWidthCache = function() { * Stop caching field widths. Unless caching was already on when the * corresponding call to startTextWidthCache was made. */ -Blockly.utils.dom.stopTextWidthCache = function() { - Blockly.utils.dom.cacheReference_--; - if (!Blockly.utils.dom.cacheReference_) { - Blockly.utils.dom.cacheWidths_ = null; +const stopTextWidthCache = function() { + cacheReference--; + if (!cacheReference) { + cacheWidths = null; } }; @@ -252,13 +253,13 @@ Blockly.utils.dom.stopTextWidthCache = function() { * @param {!Element} textElement An SVG 'text' element. * @return {number} Width of element. */ -Blockly.utils.dom.getTextWidth = function(textElement) { - var key = textElement.textContent + '\n' + textElement.className.baseVal; - var width; +const getTextWidth = function(textElement) { + const key = textElement.textContent + '\n' + textElement.className.baseVal; + let width; // Return the cached width if it exists. - if (Blockly.utils.dom.cacheWidths_) { - width = Blockly.utils.dom.cacheWidths_[key]; + if (cacheWidths) { + width = cacheWidths[key]; if (width) { return width; } @@ -266,7 +267,7 @@ Blockly.utils.dom.getTextWidth = function(textElement) { // Attempt to compute fetch the width of the SVG text element. try { - if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { + if (userAgent.IE || userAgent.EDGE) { width = textElement.getBBox().width; } else { width = textElement.getComputedTextLength(); @@ -280,8 +281,8 @@ Blockly.utils.dom.getTextWidth = function(textElement) { } // Cache the computed width and return. - if (Blockly.utils.dom.cacheWidths_) { - Blockly.utils.dom.cacheWidths_[key] = width; + if (cacheWidths) { + cacheWidths[key] = width; } return width; }; @@ -296,10 +297,10 @@ Blockly.utils.dom.getTextWidth = function(textElement) { * @param {string} fontFamily The font family to use. * @return {number} Width of element. */ -Blockly.utils.dom.getFastTextWidth = function(textElement, - fontSize, fontWeight, fontFamily) { - return Blockly.utils.dom.getFastTextWidthWithSizeString(textElement, - fontSize + 'pt', fontWeight, fontFamily); +const getFastTextWidth = function( + textElement, fontSize, fontWeight, fontFamily) { + return getFastTextWidthWithSizeString( + textElement, fontSize + 'pt', fontWeight, fontFamily); }; /** @@ -314,41 +315,40 @@ Blockly.utils.dom.getFastTextWidth = function(textElement, * @param {string} fontFamily The font family to use. * @return {number} Width of element. */ -Blockly.utils.dom.getFastTextWidthWithSizeString = function(textElement, - fontSize, fontWeight, fontFamily) { - var text = textElement.textContent; - var key = text + '\n' + textElement.className.baseVal; - var width; +const getFastTextWidthWithSizeString = function( + textElement, fontSize, fontWeight, fontFamily) { + const text = textElement.textContent; + const key = text + '\n' + textElement.className.baseVal; + let width; // Return the cached width if it exists. - if (Blockly.utils.dom.cacheWidths_) { - width = Blockly.utils.dom.cacheWidths_[key]; + if (cacheWidths) { + width = cacheWidths[key]; if (width) { return width; } } - if (!Blockly.utils.dom.canvasContext_) { + if (!canvasContext) { // Inject the canvas element used for computing text widths. - var computeCanvas = document.createElement('canvas'); + const computeCanvas = document.createElement('canvas'); computeCanvas.className = 'blocklyComputeCanvas'; document.body.appendChild(computeCanvas); // Initialize the HTML canvas context and set the font. // The context font must match blocklyText's fontsize and font-family // set in CSS. - Blockly.utils.dom.canvasContext_ = computeCanvas.getContext('2d'); + canvasContext = computeCanvas.getContext('2d'); } // Set the desired font size and family. - Blockly.utils.dom.canvasContext_.font = - fontWeight + ' ' + fontSize + ' ' + fontFamily; + canvasContext.font = fontWeight + ' ' + fontSize + ' ' + fontFamily; // Measure the text width using the helper canvas context. - width = Blockly.utils.dom.canvasContext_.measureText(text).width; + width = canvasContext.measureText(text).width; // Cache the computed width and return. - if (Blockly.utils.dom.cacheWidths_) { - Blockly.utils.dom.cacheWidths_[key] = width; + if (cacheWidths) { + cacheWidths[key] = width; } return width; }; @@ -361,18 +361,16 @@ Blockly.utils.dom.getFastTextWidthWithSizeString = function(textElement, * @param {string} fontFamily The font family to use. * @return {{height: number, baseline: number}} Font measurements. */ -Blockly.utils.dom.measureFontMetrics = function(text, fontSize, fontWeight, - fontFamily) { - - var span = document.createElement('span'); +const measureFontMetrics = function(text, fontSize, fontWeight, fontFamily) { + const span = document.createElement('span'); span.style.font = fontWeight + ' ' + fontSize + ' ' + fontFamily; span.textContent = text; - var block = document.createElement('div'); + const block = document.createElement('div'); block.style.width = '1px'; block.style.height = 0; - var div = document.createElement('div'); + const div = document.createElement('div'); div.setAttribute('style', 'position: fixed; top: 0; left: 0; display: flex;'); div.appendChild(span); div.appendChild(block); @@ -389,3 +387,25 @@ Blockly.utils.dom.measureFontMetrics = function(text, fontSize, fontWeight, } return result; }; + +exports = { + SVG_NS, + HTML_NS, + XLINK_NS, + NodeType, + createSvgElement, + addClass, + removeClasses, + removeClass, + hasClass, + removeNode, + insertAfter, + containsNode, + setCssTransform, + startTextWidthCache, + stopTextWidthCache, + getTextWidth, + getFastTextWidth, + getFastTextWidthWithSizeString, + measureFontMetrics, +}; diff --git a/core/utils/toolbox.js b/core/utils/toolbox.js index 6dabc1fd5..73b57cbd7 100644 --- a/core/utils/toolbox.js +++ b/core/utils/toolbox.js @@ -17,12 +17,12 @@ goog.module('Blockly.utils.toolbox'); goog.module.declareLegacyNamespace(); +/* eslint-disable-next-line no-unused-vars */ +const ToolboxCategory = goog.requireType('Blockly.ToolboxCategory'); +/* eslint-disable-next-line no-unused-vars */ +const ToolboxSeparator = goog.requireType('Blockly.ToolboxSeparator'); +const Xml = goog.require('Blockly.Xml'); const userAgent = goog.require('Blockly.utils.userAgent'); -/* eslint-disable-next-line no-unused-vars */ -const {CssConfig: CategoryCssConfig} = goog.requireType('Blockly.ToolboxCategory'); -/* eslint-disable-next-line no-unused-vars */ -const {CssConfig: SeparatorCssConfig} = goog.requireType('Blockly.ToolboxSeparator'); -const {textToDom} = goog.require('Blockly.Xml'); /** * The information needed to create a block in the toolbox. @@ -43,7 +43,7 @@ exports.BlockInfo = BlockInfo; * kind:string, * id:(string|undefined), * gap:(number|undefined), - * cssconfig:(!SeparatorCssConfig|undefined) + * cssconfig:(!ToolboxSeparator.CssConfig|undefined) * }} */ let SeparatorInfo; @@ -88,7 +88,7 @@ exports.ButtonOrLabelInfo = ButtonOrLabelInfo; * id:(string|undefined), * categorystyle:(string|undefined), * colour:(string|undefined), - * cssconfig:(!CategoryCssConfig|undefined), + * cssconfig:(!ToolboxCategory.CssConfig|undefined), * hidden:(string|undefined) * }} */ @@ -103,7 +103,7 @@ exports.StaticCategoryInfo = StaticCategoryInfo; * id:(string|undefined), * categorystyle:(string|undefined), * colour:(string|undefined), - * cssconfig:(!CategoryCssConfig|undefined), + * cssconfig:(!ToolboxCategory.CssConfig|undefined), * hidden:(string|undefined) * }} */ @@ -413,7 +413,7 @@ const parseToolboxTree = function(toolboxDef) { } } if (typeof toolboxDef == 'string') { - toolboxDef = textToDom(toolboxDef); + toolboxDef = Xml.textToDom(toolboxDef); if (toolboxDef.nodeName.toLowerCase() != 'xml') { throw TypeError('Toolbox should be an document.'); } diff --git a/core/variable_map.js b/core/variable_map.js index 34fa926ec..a22ab75d5 100644 --- a/core/variable_map.js +++ b/core/variable_map.js @@ -10,42 +10,45 @@ */ 'use strict'; -goog.provide('Blockly.VariableMap'); +goog.module('Blockly.VariableMap'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +const Msg = goog.require('Blockly.Msg'); +const Names = goog.require('Blockly.Names'); +const VariableModel = goog.require('Blockly.VariableModel'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.VarDelete'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.VarRename'); -goog.require('Blockly.Msg'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.object'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.VariableModel'); -goog.requireType('Blockly.Workspace'); /** * Class for a variable map. This contains a dictionary data structure with * variable types as keys and lists of variables as values. The list of * variables are the type indicated by the key. - * @param {!Blockly.Workspace} workspace The workspace this map belongs to. + * @param {!Workspace} workspace The workspace this map belongs to. * @constructor */ -Blockly.VariableMap = function(workspace) { +const VariableMap = function(workspace) { /** * 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 {!Object>} + * @type {!Object>} * @private */ this.variableMap_ = Object.create(null); /** * The workspace this map belongs to. - * @type {!Blockly.Workspace} + * @type {!Workspace} */ this.workspace = workspace; }; @@ -53,7 +56,7 @@ Blockly.VariableMap = function(workspace) { /** * Clear the variable map. */ -Blockly.VariableMap.prototype.clear = function() { +VariableMap.prototype.clear = function() { this.variableMap_ = Object.create(null); }; @@ -61,15 +64,15 @@ Blockly.VariableMap.prototype.clear = function() { /** * Rename the given variable by updating its name in the variable map. - * @param {!Blockly.VariableModel} variable Variable to rename. + * @param {!VariableModel} variable Variable to rename. * @param {string} newName New variable name. * @package */ -Blockly.VariableMap.prototype.renameVariable = function(variable, newName) { - var type = variable.type; - var conflictVar = this.getVariable(newName, type); - var blocks = this.workspace.getAllBlocks(false); - Blockly.Events.setGroup(true); +VariableMap.prototype.renameVariable = function(variable, newName) { + const type = variable.type; + const conflictVar = this.getVariable(newName, type); + const blocks = this.workspace.getAllBlocks(false); + Events.setGroup(true); try { // The IDs may match if the rename is a simple case change (name1 -> Name1). if (!conflictVar || conflictVar.getId() == variable.getId()) { @@ -78,7 +81,7 @@ Blockly.VariableMap.prototype.renameVariable = function(variable, newName) { this.renameVariableWithConflict_(variable, newName, conflictVar, blocks); } } finally { - Blockly.Events.setGroup(false); + Events.setGroup(false); } }; @@ -88,8 +91,8 @@ Blockly.VariableMap.prototype.renameVariable = function(variable, newName) { * @param {string} id ID of the variable to rename. * @param {string} newName New variable name. */ -Blockly.VariableMap.prototype.renameVariableById = function(id, newName) { - var variable = this.getVariableById(id); +VariableMap.prototype.renameVariableById = function(id, newName) { + const variable = this.getVariableById(id); if (!variable) { throw Error('Tried to rename a variable that didn\'t exist. ID: ' + id); } @@ -100,18 +103,17 @@ Blockly.VariableMap.prototype.renameVariableById = function(id, newName) { /** * Update the name of the given variable and refresh all references to it. * The new name must not conflict with any existing variable names. - * @param {!Blockly.VariableModel} variable Variable to rename. + * @param {!VariableModel} variable Variable to rename. * @param {string} newName New variable name. - * @param {!Array} blocks The list of all blocks in the + * @param {!Array} blocks The list of all blocks in the * workspace. * @private */ -Blockly.VariableMap.prototype.renameVariableAndUses_ = function(variable, - newName, blocks) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.VAR_RENAME))( - variable, newName)); +VariableMap.prototype.renameVariableAndUses_ = function( + variable, newName, blocks) { + Events.fire(new (Events.get(Events.VAR_RENAME))(variable, newName)); variable.name = newName; - for (var i = 0; i < blocks.length; i++) { + for (let i = 0; i < blocks.length; i++) { blocks[i].updateVarName(variable); } }; @@ -121,18 +123,18 @@ Blockly.VariableMap.prototype.renameVariableAndUses_ = function(variable, * variable. The two variables are coalesced into a single variable with the ID * of the existing variable that was already using newName. * Refresh all references to the variable. - * @param {!Blockly.VariableModel} variable Variable to rename. + * @param {!VariableModel} variable Variable to rename. * @param {string} newName New variable name. - * @param {!Blockly.VariableModel} conflictVar The variable that was already + * @param {!VariableModel} conflictVar The variable that was already * using newName. - * @param {!Array} blocks The list of all blocks in the + * @param {!Array} blocks The list of all blocks in the * workspace. * @private */ -Blockly.VariableMap.prototype.renameVariableWithConflict_ = function(variable, - newName, conflictVar, blocks) { - var type = variable.type; - var oldCase = conflictVar.name; +VariableMap.prototype.renameVariableWithConflict_ = function( + variable, newName, conflictVar, blocks) { + const type = variable.type; + const oldCase = conflictVar.name; if (newName != oldCase) { // Simple rename to change the case and update references. @@ -141,18 +143,16 @@ Blockly.VariableMap.prototype.renameVariableWithConflict_ = function(variable, // These blocks now refer to a different variable. // These will fire change events. - for (var i = 0; i < blocks.length; i++) { + for (let i = 0; i < blocks.length; i++) { blocks[i].renameVarById(variable.getId(), conflictVar.getId()); } // Finally delete the original variable, which is now unreferenced. - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.VAR_DELETE))( - variable)); + Events.fire(new (Events.get(Events.VAR_DELETE))(variable)); // And remove it from the list. - var variableList = this.getVariablesOfType(type); - var variableIndex = variableList.indexOf(variable); + const variableList = this.getVariablesOfType(type); + const variableIndex = variableList.indexOf(variable); this.variableMap_[type].splice(variableIndex, 1); - }; /* End functions for renaming variables. */ @@ -166,14 +166,14 @@ Blockly.VariableMap.prototype.renameVariableWithConflict_ = function(variable, * 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 {!Blockly.VariableModel} The newly created variable. + * @return {!VariableModel} The newly created variable. */ -Blockly.VariableMap.prototype.createVariable = function(name, - opt_type, opt_id) { - var variable = this.getVariable(name, opt_type); +VariableMap.prototype.createVariable = function(name, opt_type, opt_id) { + let variable = this.getVariable(name, opt_type); if (variable) { if (opt_id && variable.getId() != opt_id) { - throw Error('Variable "' + name + '" is already in use and its id is "' + + throw Error( + 'Variable "' + name + '" is already in use and its id is "' + variable.getId() + '" which conflicts with the passed in ' + 'id, "' + opt_id + '".'); } @@ -183,11 +183,11 @@ Blockly.VariableMap.prototype.createVariable = function(name, if (opt_id && this.getVariableById(opt_id)) { throw Error('Variable id, "' + opt_id + '", is already in use.'); } - var id = opt_id || Blockly.utils.genUid(); - var type = opt_type || ''; - variable = new Blockly.VariableModel(this.workspace, name, type, id); + const id = opt_id || utils.genUid(); + const type = opt_type || ''; + variable = new VariableModel(this.workspace, name, type, id); - var variables = this.variableMap_[type] || []; + const variables = this.variableMap_[type] || []; variables.push(variable); // Delete the list of variables of this type, and re-add it so that // the most recent addition is at the end. @@ -202,15 +202,14 @@ Blockly.VariableMap.prototype.createVariable = function(name, /** * Delete a variable. - * @param {!Blockly.VariableModel} variable Variable to delete. + * @param {!VariableModel} variable Variable to delete. */ -Blockly.VariableMap.prototype.deleteVariable = function(variable) { - var variableList = this.variableMap_[variable.type]; - for (var i = 0, tempVar; (tempVar = variableList[i]); i++) { +VariableMap.prototype.deleteVariable = function(variable) { + const variableList = this.variableMap_[variable.type]; + for (let i = 0, tempVar; (tempVar = variableList[i]); i++) { if (tempVar.getId() == variable.getId()) { variableList.splice(i, 1); - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.VAR_DELETE))( - variable)); + Events.fire(new (Events.get(Events.VAR_DELETE))(variable)); return; } } @@ -221,66 +220,64 @@ Blockly.VariableMap.prototype.deleteVariable = function(variable) { * workspace. May prompt the user for confirmation. * @param {string} id ID of variable to delete. */ -Blockly.VariableMap.prototype.deleteVariableById = function(id) { - var variable = this.getVariableById(id); +VariableMap.prototype.deleteVariableById = function(id) { + const variable = this.getVariableById(id); if (variable) { // Check whether this variable is a function parameter before deleting. - var variableName = variable.name; - var uses = this.getVariableUsesById(id); - for (var i = 0, block; (block = uses[i]); i++) { + const variableName = variable.name; + const uses = this.getVariableUsesById(id); + for (let i = 0, block; (block = uses[i]); i++) { if (block.type == 'procedures_defnoreturn' || - block.type == 'procedures_defreturn') { - var procedureName = block.getFieldValue('NAME'); - var deleteText = Blockly.Msg['CANNOT_DELETE_VARIABLE_PROCEDURE']. - replace('%1', variableName). - replace('%2', procedureName); + block.type == 'procedures_defreturn') { + const procedureName = block.getFieldValue('NAME'); + const deleteText = Msg['CANNOT_DELETE_VARIABLE_PROCEDURE'] + .replace('%1', variableName) + .replace('%2', procedureName); Blockly.alert(deleteText); return; } } - var map = this; + const map = this; if (uses.length > 1) { // Confirm before deleting multiple blocks. - var confirmText = Blockly.Msg['DELETE_VARIABLE_CONFIRMATION']. - replace('%1', String(uses.length)). - replace('%2', variableName); - Blockly.confirm(confirmText, - function(ok) { - if (ok && variable) { - map.deleteVariableInternal(variable, uses); - } - }); + const confirmText = Msg['DELETE_VARIABLE_CONFIRMATION'] + .replace('%1', String(uses.length)) + .replace('%2', variableName); + Blockly.confirm(confirmText, function(ok) { + if (ok && variable) { + map.deleteVariableInternal(variable, uses); + } + }); } else { // No confirmation necessary for a single block. map.deleteVariableInternal(variable, uses); } } else { - console.warn("Can't delete non-existent variable: " + id); + console.warn('Can\'t delete non-existent variable: ' + id); } }; /** * Deletes a variable and all of its uses from this workspace without asking the * user for confirmation. - * @param {!Blockly.VariableModel} variable Variable to delete. - * @param {!Array} uses An array of uses of the variable. + * @param {!VariableModel} variable Variable to delete. + * @param {!Array} uses An array of uses of the variable. * @package */ -Blockly.VariableMap.prototype.deleteVariableInternal = function(variable, - uses) { - var existingGroup = Blockly.Events.getGroup(); +VariableMap.prototype.deleteVariableInternal = function(variable, uses) { + const existingGroup = Events.getGroup(); if (!existingGroup) { - Blockly.Events.setGroup(true); + Events.setGroup(true); } try { - for (var i = 0; i < uses.length; i++) { + for (let i = 0; i < uses.length; i++) { uses[i].dispose(true); } this.deleteVariable(variable); } finally { if (!existingGroup) { - Blockly.Events.setGroup(false); + Events.setGroup(false); } } }; @@ -293,15 +290,15 @@ Blockly.VariableMap.prototype.deleteVariableInternal = function(variable, * @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 {?Blockly.VariableModel} The variable with the given name, or null if + * @return {?VariableModel} The variable with the given name, or null if * it was not found. */ -Blockly.VariableMap.prototype.getVariable = function(name, opt_type) { - var type = opt_type || ''; - var list = this.variableMap_[type]; +VariableMap.prototype.getVariable = function(name, opt_type) { + const type = opt_type || ''; + const list = this.variableMap_[type]; if (list) { - for (var j = 0, variable; (variable = list[j]); j++) { - if (Blockly.Names.equals(variable.name, name)) { + for (let j = 0, variable; (variable = list[j]); j++) { + if (Names.equals(variable.name, name)) { return variable; } } @@ -312,13 +309,13 @@ Blockly.VariableMap.prototype.getVariable = function(name, opt_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 {?Blockly.VariableModel} The variable with the given ID. + * @return {?VariableModel} The variable with the given ID. */ -Blockly.VariableMap.prototype.getVariableById = function(id) { - var keys = Object.keys(this.variableMap_); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - for (var j = 0, variable; (variable = this.variableMap_[key][j]); j++) { +VariableMap.prototype.getVariableById = function(id) { + const keys = Object.keys(this.variableMap_); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + for (let j = 0, variable; (variable = this.variableMap_[key][j]); j++) { if (variable.getId() == id) { return variable; } @@ -331,12 +328,12 @@ Blockly.VariableMap.prototype.getVariableById = function(id) { * Get a list containing all of the variables of a 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 + * @return {!Array} The sought after variables of the * passed in type. An empty array if none are found. */ -Blockly.VariableMap.prototype.getVariablesOfType = function(type) { +VariableMap.prototype.getVariablesOfType = function(type) { type = type || ''; - var variable_list = this.variableMap_[type]; + const variable_list = this.variableMap_[type]; if (variable_list) { return variable_list.slice(); } @@ -346,22 +343,21 @@ Blockly.VariableMap.prototype.getVariablesOfType = function(type) { /** * Return all variable and potential variable types. This list always contains * the empty string. - * @param {?Blockly.Workspace} ws The workspace used to look for potential + * @param {?Workspace} ws The workspace used to look for potential * variables. This can be different than the workspace stored on this object * if the passed in ws is a flyout workspace. * @return {!Array} List of variable types. * @package */ -Blockly.VariableMap.prototype.getVariableTypes = function(ws) { - var variableMap = {}; - Blockly.utils.object.mixin(variableMap, this.variableMap_); +VariableMap.prototype.getVariableTypes = function(ws) { + const variableMap = {}; + object.mixin(variableMap, this.variableMap_); if (ws && ws.getPotentialVariableMap()) { - Blockly.utils.object.mixin(variableMap, - ws.getPotentialVariableMap().variableMap_); + object.mixin(variableMap, ws.getPotentialVariableMap().variableMap_); } - var types = Object.keys(variableMap); - var hasEmpty = false; - for (var i = 0; i < types.length; i++) { + const types = Object.keys(variableMap); + let hasEmpty = false; + for (let i = 0; i < types.length; i++) { if (types[i] == '') { hasEmpty = true; } @@ -374,11 +370,11 @@ Blockly.VariableMap.prototype.getVariableTypes = function(ws) { /** * Return all variables of all types. - * @return {!Array} List of variable models. + * @return {!Array} List of variable models. */ -Blockly.VariableMap.prototype.getAllVariables = function() { - var all_variables = []; - for (var key in this.variableMap_) { +VariableMap.prototype.getAllVariables = function() { + let all_variables = []; + for (const key in this.variableMap_) { all_variables = all_variables.concat(this.variableMap_[key]); } return all_variables; @@ -388,11 +384,11 @@ Blockly.VariableMap.prototype.getAllVariables = function() { * Returns all of the variable names of all types. * @return {!Array} All of the variable names of all types. */ -Blockly.VariableMap.prototype.getAllVariableNames = function() { - var allNames = []; - for (var key in this.variableMap_) { - var variables = this.variableMap_[key]; - for (var i = 0, variable; (variable = variables[i]); i++) { +VariableMap.prototype.getAllVariableNames = function() { + const allNames = []; + for (const key in this.variableMap_) { + const variables = this.variableMap_[key]; + for (let i = 0, variable; (variable = variables[i]); i++) { allNames.push(variable.name); } } @@ -402,16 +398,16 @@ Blockly.VariableMap.prototype.getAllVariableNames = function() { /** * Find all the uses of a named variable. * @param {string} id ID of the variable to find. - * @return {!Array} Array of block usages. + * @return {!Array} Array of block usages. */ -Blockly.VariableMap.prototype.getVariableUsesById = function(id) { - var uses = []; - var blocks = this.workspace.getAllBlocks(false); +VariableMap.prototype.getVariableUsesById = function(id) { + const uses = []; + const blocks = this.workspace.getAllBlocks(false); // Iterate through every block and check the name. - for (var i = 0; i < blocks.length; i++) { - var blockVariables = blocks[i].getVarModels(); + for (let i = 0; i < blocks.length; i++) { + const blockVariables = blocks[i].getVarModels(); if (blockVariables) { - for (var j = 0; j < blockVariables.length; j++) { + for (let j = 0; j < blockVariables.length; j++) { if (blockVariables[j].getId() == id) { uses.push(blocks[i]); } @@ -420,3 +416,5 @@ Blockly.VariableMap.prototype.getVariableUsesById = function(id) { } return uses; }; + +exports = VariableMap; diff --git a/core/variable_model.js b/core/variable_model.js index bc097da8a..2f5936f4e 100644 --- a/core/variable_model.js +++ b/core/variable_model.js @@ -10,20 +10,21 @@ */ 'use strict'; -goog.provide('Blockly.VariableModel'); +goog.module('Blockly.VariableModel'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.VarCreate'); -goog.require('Blockly.utils'); - -goog.requireType('Blockly.Workspace'); /** * Class for a variable model. * Holds information for the variable including name, ID, and type. - * @param {!Blockly.Workspace} workspace The variable's workspace. + * @param {!Workspace} workspace The variable's workspace. * @param {string} name The name of the variable. This is the user-visible name * (e.g. 'my var' or '私の変数'), not the generated name. * @param {string=} opt_type The type of the variable like 'int' or 'string'. @@ -34,10 +35,10 @@ goog.requireType('Blockly.Workspace'); * @see {Blockly.FieldVariable} * @constructor */ -Blockly.VariableModel = function(workspace, name, opt_type, opt_id) { +const VariableModel = function(workspace, name, opt_type, opt_id) { /** * The workspace the variable is in. - * @type {!Blockly.Workspace} + * @type {!Workspace} */ this.workspace = workspace; @@ -64,27 +65,28 @@ Blockly.VariableModel = function(workspace, name, opt_type, opt_id) { * @type {string} * @private */ - this.id_ = opt_id || Blockly.utils.genUid(); + this.id_ = opt_id || utils.genUid(); - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.VAR_CREATE))( - this)); + Events.fire(new (Events.get(Events.VAR_CREATE))(this)); }; /** * @return {string} The ID for the variable. */ -Blockly.VariableModel.prototype.getId = function() { +VariableModel.prototype.getId = function() { return this.id_; }; /** * A custom compare function for the VariableModel objects. - * @param {Blockly.VariableModel} var1 First variable to compare. - * @param {Blockly.VariableModel} var2 Second variable to compare. + * @param {VariableModel} var1 First variable to compare. + * @param {VariableModel} var2 Second variable to compare. * @return {number} -1 if name of var1 is less than name of var2, 0 if equal, * and 1 if greater. * @package */ -Blockly.VariableModel.compareByName = function(var1, var2) { +VariableModel.compareByName = function(var1, var2) { return var1.name.localeCompare(var2.name, undefined, {sensitivity: 'base'}); }; + +exports = VariableModel; diff --git a/core/variables_dynamic.js b/core/variables_dynamic.js index 630064eeb..e982d733e 100644 --- a/core/variables_dynamic.js +++ b/core/variables_dynamic.js @@ -11,92 +11,100 @@ */ 'use strict'; -goog.provide('Blockly.VariablesDynamic'); +goog.module('Blockly.VariablesDynamic'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Blocks'); -goog.require('Blockly.Msg'); -goog.require('Blockly.utils.xml'); -goog.require('Blockly.VariableModel'); -goog.require('Blockly.Variables'); - -goog.requireType('Blockly.Workspace'); +const Blocks = goog.require('Blockly.Blocks'); +const Msg = goog.require('Blockly.Msg'); +const VariableModel = goog.require('Blockly.VariableModel'); +const Variables = goog.require('Blockly.Variables'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const xml = goog.require('Blockly.utils.xml'); -Blockly.VariablesDynamic.onCreateVariableButtonClick_String = function(button) { - Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), - undefined, 'String'); +const onCreateVariableButtonClick_String = function(button) { + Variables.createVariableButtonHandler( + button.getTargetWorkspace(), undefined, 'String'); }; -Blockly.VariablesDynamic.onCreateVariableButtonClick_Number = function(button) { - Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), - undefined, 'Number'); +exports.onCreateVariableButtonClick_String = onCreateVariableButtonClick_String; + +const onCreateVariableButtonClick_Number = function(button) { + Variables.createVariableButtonHandler( + button.getTargetWorkspace(), undefined, 'Number'); }; -Blockly.VariablesDynamic.onCreateVariableButtonClick_Colour = function(button) { - Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), - undefined, 'Colour'); +exports.onCreateVariableButtonClick_Number = onCreateVariableButtonClick_Number; + +const onCreateVariableButtonClick_Colour = function(button) { + Variables.createVariableButtonHandler( + button.getTargetWorkspace(), undefined, 'Colour'); }; +exports.onCreateVariableButtonClick_Colour = onCreateVariableButtonClick_Colour; + /** * Construct the elements (blocks and button) required by the flyout for the * variable category. - * @param {!Blockly.Workspace} workspace The workspace containing variables. + * @param {!Workspace} workspace The workspace containing variables. * @return {!Array} Array of XML elements. */ -Blockly.VariablesDynamic.flyoutCategory = function(workspace) { - var xmlList = []; - var button = document.createElement('button'); - button.setAttribute('text', Blockly.Msg['NEW_STRING_VARIABLE']); +const flyoutCategory = function(workspace) { + let xmlList = []; + let button = document.createElement('button'); + button.setAttribute('text', Msg['NEW_STRING_VARIABLE']); button.setAttribute('callbackKey', 'CREATE_VARIABLE_STRING'); xmlList.push(button); button = document.createElement('button'); - button.setAttribute('text', Blockly.Msg['NEW_NUMBER_VARIABLE']); + button.setAttribute('text', Msg['NEW_NUMBER_VARIABLE']); button.setAttribute('callbackKey', 'CREATE_VARIABLE_NUMBER'); xmlList.push(button); button = document.createElement('button'); - button.setAttribute('text', Blockly.Msg['NEW_COLOUR_VARIABLE']); + button.setAttribute('text', Msg['NEW_COLOUR_VARIABLE']); button.setAttribute('callbackKey', 'CREATE_VARIABLE_COLOUR'); xmlList.push(button); - workspace.registerButtonCallback('CREATE_VARIABLE_STRING', - Blockly.VariablesDynamic.onCreateVariableButtonClick_String); - workspace.registerButtonCallback('CREATE_VARIABLE_NUMBER', - Blockly.VariablesDynamic.onCreateVariableButtonClick_Number); - workspace.registerButtonCallback('CREATE_VARIABLE_COLOUR', - Blockly.VariablesDynamic.onCreateVariableButtonClick_Colour); + workspace.registerButtonCallback( + 'CREATE_VARIABLE_STRING', onCreateVariableButtonClick_String); + workspace.registerButtonCallback( + 'CREATE_VARIABLE_NUMBER', onCreateVariableButtonClick_Number); + workspace.registerButtonCallback( + 'CREATE_VARIABLE_COLOUR', onCreateVariableButtonClick_Colour); - var blockList = Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace); + const blockList = flyoutCategoryBlocks(workspace); xmlList = xmlList.concat(blockList); return xmlList; }; +exports.flyoutCategory = flyoutCategory; /** * Construct the blocks required by the flyout for the variable category. - * @param {!Blockly.Workspace} workspace The workspace containing variables. + * @param {!Workspace} workspace The workspace containing variables. * @return {!Array} Array of XML block elements. */ -Blockly.VariablesDynamic.flyoutCategoryBlocks = function(workspace) { - var variableModelList = workspace.getAllVariables(); +const flyoutCategoryBlocks = function(workspace) { + const variableModelList = workspace.getAllVariables(); - var xmlList = []; + const xmlList = []; if (variableModelList.length > 0) { - if (Blockly.Blocks['variables_set_dynamic']) { - var firstVariable = variableModelList[variableModelList.length - 1]; - var block = Blockly.utils.xml.createElement('block'); + if (Blocks['variables_set_dynamic']) { + const firstVariable = variableModelList[variableModelList.length - 1]; + const block = xml.createElement('block'); block.setAttribute('type', 'variables_set_dynamic'); block.setAttribute('gap', 24); - block.appendChild( - Blockly.Variables.generateVariableFieldDom(firstVariable)); + block.appendChild(Variables.generateVariableFieldDom(firstVariable)); xmlList.push(block); } - if (Blockly.Blocks['variables_get_dynamic']) { - variableModelList.sort(Blockly.VariableModel.compareByName); - for (var i = 0, variable; (variable = variableModelList[i]); i++) { - var block = Blockly.utils.xml.createElement('block'); + if (Blocks['variables_get_dynamic']) { + variableModelList.sort(VariableModel.compareByName); + for (let i = 0, variable; (variable = variableModelList[i]); i++) { + const block = xml.createElement('block'); block.setAttribute('type', 'variables_get_dynamic'); block.setAttribute('gap', 8); - block.appendChild(Blockly.Variables.generateVariableFieldDom(variable)); + block.appendChild(Variables.generateVariableFieldDom(variable)); xmlList.push(block); } } } return xmlList; }; +exports.flyoutCategoryBlocks = flyoutCategoryBlocks; diff --git a/core/warning.js b/core/warning.js index 9bbd9c91b..6ed5d0c02 100644 --- a/core/warning.js +++ b/core/warning.js @@ -10,51 +10,53 @@ */ 'use strict'; -goog.provide('Blockly.Warning'); +goog.module('Blockly.Warning'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Bubble'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlockSvg = goog.requireType('Blockly.BlockSvg'); +const Bubble = goog.require('Blockly.Bubble'); +/* eslint-disable-next-line no-unused-vars */ +const Coordinate = goog.requireType('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +const Icon = goog.require('Blockly.Icon'); +const Svg = goog.require('Blockly.utils.Svg'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BubbleOpen'); -goog.require('Blockly.Icon'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.BlockSvg'); -goog.requireType('Blockly.utils.Coordinate'); /** * Class for a warning. - * @param {!Blockly.Block} block The block associated with this warning. - * @extends {Blockly.Icon} + * @param {!Block} block The block associated with this warning. + * @extends {Icon} * @constructor */ -Blockly.Warning = function(block) { - Blockly.Warning.superClass_.constructor.call(this, block); +const Warning = function(block) { + Warning.superClass_.constructor.call(this, block); this.createIcon(); // The text_ object can contain multiple warnings. this.text_ = Object.create(null); }; -Blockly.utils.object.inherits(Blockly.Warning, Blockly.Icon); +object.inherits(Warning, Icon); /** * Does this icon get hidden when the block is collapsed. */ -Blockly.Warning.prototype.collapseHidden = false; +Warning.prototype.collapseHidden = false; /** * Draw the warning icon. * @param {!Element} group The icon group. * @protected */ -Blockly.Warning.prototype.drawIcon_ = function(group) { +Warning.prototype.drawIcon_ = function(group) { // Triangle with rounded corners. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { + dom.createSvgElement( + Svg.PATH, { 'class': 'blocklyIconShape', 'd': 'M2,15Q-1,15 0.5,12L6.5,1.7Q8,-1 9.5,1.7L15.5,12Q17,15 14,15z' }, @@ -62,19 +64,20 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { // Can't use a real '!' text character since different browsers and operating // systems render it differently. // Body of exclamation point. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { + dom.createSvgElement( + Svg.PATH, { 'class': 'blocklyIconSymbol', 'd': 'm7,4.8v3.16l0.27,2.27h1.46l0.27,-2.27v-3.16z' }, group); // Dot of exclamation point. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { + dom.createSvgElement( + Svg.RECT, { 'class': 'blocklyIconSymbol', - 'x': '7', 'y': '11', 'height': '2', 'width': '2' + 'x': '7', + 'y': '11', + 'height': '2', + 'width': '2' }, group); }; @@ -83,12 +86,12 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { * Show or hide the warning bubble. * @param {boolean} visible True if the bubble should be visible. */ -Blockly.Warning.prototype.setVisible = function(visible) { +Warning.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { return; } - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BUBBLE_OPEN))( - this.block_, visible, 'warning')); + Events.fire( + new (Events.get(Events.BUBBLE_OPEN))(this.block_, visible, 'warning')); if (visible) { this.createBubble_(); } else { @@ -100,11 +103,11 @@ Blockly.Warning.prototype.setVisible = function(visible) { * Show the bubble. * @private */ -Blockly.Warning.prototype.createBubble_ = function() { - this.paragraphElement_ = Blockly.Bubble.textToDom(this.getText()); - this.bubble_ = Blockly.Bubble.createNonEditableBubble( - this.paragraphElement_, /** @type {!Blockly.BlockSvg} */ (this.block_), - /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_)); +Warning.prototype.createBubble_ = function() { + this.paragraphElement_ = Bubble.textToDom(this.getText()); + this.bubble_ = Bubble.createNonEditableBubble( + this.paragraphElement_, /** @type {!BlockSvg} */ (this.block_), + /** @type {!Coordinate} */ (this.iconXY_)); this.applyColour(); }; @@ -112,7 +115,7 @@ Blockly.Warning.prototype.createBubble_ = function() { * Dispose of the bubble and references to it. * @private */ -Blockly.Warning.prototype.disposeBubble_ = function() { +Warning.prototype.disposeBubble_ = function() { this.bubble_.dispose(); this.bubble_ = null; this.paragraphElement_ = null; @@ -125,7 +128,7 @@ Blockly.Warning.prototype.disposeBubble_ = function() { * @param {string} id An ID for this text entry to be able to maintain * multiple warnings. */ -Blockly.Warning.prototype.setText = function(text, id) { +Warning.prototype.setText = function(text, id) { if (this.text_[id] == text) { return; } @@ -144,9 +147,9 @@ Blockly.Warning.prototype.setText = function(text, id) { * Get this warning's texts. * @return {string} All texts concatenated into one string. */ -Blockly.Warning.prototype.getText = function() { - var allWarnings = []; - for (var id in this.text_) { +Warning.prototype.getText = function() { + const allWarnings = []; + for (const id in this.text_) { allWarnings.push(this.text_[id]); } return allWarnings.join('\n'); @@ -155,7 +158,9 @@ Blockly.Warning.prototype.getText = function() { /** * Dispose of this warning. */ -Blockly.Warning.prototype.dispose = function() { +Warning.prototype.dispose = function() { this.block_.warning = null; - Blockly.Icon.prototype.dispose.call(this); + Icon.prototype.dispose.call(this); }; + +exports = Warning; diff --git a/core/widgetdiv.js b/core/widgetdiv.js index 316e78b61..106dce645 100644 --- a/core/widgetdiv.js +++ b/core/widgetdiv.js @@ -18,6 +18,7 @@ */ goog.provide('Blockly.WidgetDiv'); +goog.require('Blockly.common'); goog.require('Blockly.utils.dom'); goog.requireType('Blockly.utils.Rect'); @@ -66,7 +67,7 @@ Blockly.WidgetDiv.createDom = function() { */ Blockly.WidgetDiv.DIV = document.createElement('div'); Blockly.WidgetDiv.DIV.className = 'blocklyWidgetDiv'; - var container = Blockly.parentContainer || document.body; + var container = Blockly.common.getParentContainer() || document.body; container.appendChild(Blockly.WidgetDiv.DIV); }; @@ -85,7 +86,7 @@ Blockly.WidgetDiv.show = function(newOwner, rtl, dispose) { div.style.direction = rtl ? 'rtl' : 'ltr'; div.style.display = 'block'; var mainWorkspace = - /** @type {!Blockly.WorkspaceSvg} */ (Blockly.getMainWorkspace()); + /** @type {!Blockly.WorkspaceSvg} */ (Blockly.common.getMainWorkspace()); Blockly.WidgetDiv.rendererClassName_ = mainWorkspace.getRenderer().getClassName(); Blockly.WidgetDiv.themeClassName_ = mainWorkspace.getTheme().getClassName(); @@ -119,7 +120,7 @@ Blockly.WidgetDiv.hide = function() { Blockly.WidgetDiv.themeClassName_ = ''; } (/** @type {!Blockly.WorkspaceSvg} */ ( - Blockly.getMainWorkspace())).markFocused(); + Blockly.common.getMainWorkspace())).markFocused(); }; /** diff --git a/core/workspace.js b/core/workspace.js index 9a1dd8cbb..77b50967e 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -10,62 +10,79 @@ */ 'use strict'; -goog.provide('Blockly.Workspace'); +goog.module('Blockly.Workspace'); +goog.module.declareLegacyNamespace(); +/* eslint-disable-next-line no-unused-vars */ +const Abstract = goog.requireType('Blockly.Events.Abstract'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions'); +/* eslint-disable-next-line no-unused-vars */ +const ConnectionDB = goog.requireType('Blockly.ConnectionDB'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation'); +/* eslint-disable-next-line no-unused-vars */ +const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker'); +const Options = goog.require('Blockly.Options'); +const VariableMap = goog.require('Blockly.VariableMap'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceComment = goog.requireType('Blockly.WorkspaceComment'); +const math = goog.require('Blockly.utils.math'); +const registry = goog.require('Blockly.registry'); +/* eslint-disable-next-line no-unused-vars */ +const toolbox = goog.requireType('Blockly.utils.toolbox'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.ConnectionChecker'); -goog.require('Blockly.Events'); -goog.require('Blockly.IASTNodeLocation'); -goog.require('Blockly.Options'); -goog.require('Blockly.registry'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.math'); -goog.require('Blockly.VariableMap'); -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.ConnectionDB'); -goog.requireType('Blockly.Events.Abstract'); -goog.requireType('Blockly.IConnectionChecker'); -goog.requireType('Blockly.utils.toolbox'); -goog.requireType('Blockly.VariableModel'); +/** + * Database of all workspaces. + * @private + */ +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 {!Blockly.Options=} opt_options Dictionary of options. + * @param {!Options=} opt_options Dictionary of options. * @constructor - * @implements {Blockly.IASTNodeLocation} + * @implements {IASTNodeLocation} */ -Blockly.Workspace = function(opt_options) { +const Workspace = function(opt_options) { /** @type {string} */ - this.id = Blockly.utils.genUid(); - Blockly.Workspace.WorkspaceDB_[this.id] = this; - /** @type {!Blockly.Options} */ - this.options = opt_options || - new Blockly.Options(/** @type {!Blockly.BlocklyOptions} */ ({})); + this.id = utils.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 {Blockly.utils.toolbox.Position} */ + /** @type {toolbox.Position} */ this.toolboxPosition = this.options.toolboxPosition; - var connectionCheckerClass = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.CONNECTION_CHECKER, this.options, true); + const connectionCheckerClass = registry.getClassFromOptions( + registry.Type.CONNECTION_CHECKER, this.options, true); /** * An object that encapsulates logic for safety, type, and dragging checks. - * @type {!Blockly.IConnectionChecker} + * @type {!IConnectionChecker} */ this.connectionChecker = new connectionCheckerClass(this); /** - * @type {!Array} + * @type {!Array} * @private */ this.topBlocks_ = []; /** - * @type {!Array} + * @type {!Array} * @private */ this.topComments_ = []; @@ -80,12 +97,12 @@ Blockly.Workspace = function(opt_options) { */ this.listeners_ = []; /** - * @type {!Array} + * @type {!Array} * @protected */ this.undoStack_ = []; /** - * @type {!Array} + * @type {!Array} * @protected */ this.redoStack_ = []; @@ -104,19 +121,19 @@ Blockly.Workspace = function(opt_options) { * 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 {!Blockly.VariableMap} + * @type {!VariableMap} * @private */ - this.variableMap_ = new Blockly.VariableMap(this); + 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 Blockly.VariableModel. We reconcile + * 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 {?Blockly.VariableMap} + * @type {?VariableMap} * @private */ this.potentialVariableMap_ = null; @@ -126,38 +143,38 @@ Blockly.Workspace = function(opt_options) { * Returns `true` if the workspace is visible and `false` if it's headless. * @type {boolean} */ -Blockly.Workspace.prototype.rendered = false; +Workspace.prototype.rendered = false; /** * Returns `true` if the workspace is currently in the process of a bulk clear. * @type {boolean} * @package */ -Blockly.Workspace.prototype.isClearing = false; +Workspace.prototype.isClearing = false; /** * Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets * it to unlimited. * @type {number} */ -Blockly.Workspace.prototype.MAX_UNDO = 1024; +Workspace.prototype.MAX_UNDO = 1024; /** * Set of databases for rapid lookup of connection locations. - * @type {Array} + * @type {Array} */ -Blockly.Workspace.prototype.connectionDBList = null; +Workspace.prototype.connectionDBList = null; /** * Dispose of this workspace. * Unlink from all DOM elements to prevent memory leaks. * @suppress {checkTypes} */ -Blockly.Workspace.prototype.dispose = function() { +Workspace.prototype.dispose = function() { this.listeners_.length = 0; this.clear(); // Remove from workspace database. - delete Blockly.Workspace.WorkspaceDB_[this.id]; + delete WorkspaceDB_[this.id]; }; /** @@ -166,40 +183,40 @@ Blockly.Workspace.prototype.dispose = function() { * a left to right bias (reversed in RTL). Units are in degrees. * See: https://tvtropes.org/pmwiki/pmwiki.php/Main/DiagonalBilling */ -Blockly.Workspace.SCAN_ANGLE = 3; +Workspace.SCAN_ANGLE = 3; /** * Compare function for sorting objects (blocks, comments, etc) by position; * top to bottom (with slight LTR or RTL bias). - * @param {!Blockly.Block | !Blockly.WorkspaceComment} a The first object to + * @param {!Block | !WorkspaceComment} a The first object to * compare. - * @param {!Blockly.Block | !Blockly.WorkspaceComment} b The second object to + * @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 */ -Blockly.Workspace.prototype.sortObjects_ = function(a, b) { - var aXY = a.getRelativeToSurfaceXY(); - var bXY = b.getRelativeToSurfaceXY(); - return (aXY.y + Blockly.Workspace.prototype.sortObjects_.offset * aXY.x) - - (bXY.y + Blockly.Workspace.prototype.sortObjects_.offset * bXY.x); +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 {!Blockly.Block} block Block to add. + * @param {!Block} block Block to add. */ -Blockly.Workspace.prototype.addTopBlock = function(block) { +Workspace.prototype.addTopBlock = function(block) { this.topBlocks_.push(block); }; /** * Removes a block from the list of top blocks. - * @param {!Blockly.Block} block Block to remove. + * @param {!Block} block Block to remove. */ -Blockly.Workspace.prototype.removeTopBlock = function(block) { - if (!Blockly.utils.arrayRemove(this.topBlocks_, block)) { +Workspace.prototype.removeTopBlock = function(block) { + if (!utils.arrayRemove(this.topBlocks_, block)) { throw Error('Block not present in workspace\'s list of top-most blocks.'); } }; @@ -208,14 +225,13 @@ Blockly.Workspace.prototype.removeTopBlock = function(block) { * 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. + * @return {!Array} The top-level block objects. */ -Blockly.Workspace.prototype.getTopBlocks = function(ordered) { +Workspace.prototype.getTopBlocks = function(ordered) { // Copy the topBlocks_ list. - var blocks = [].concat(this.topBlocks_); + const blocks = [].concat(this.topBlocks_); if (ordered && blocks.length > 1) { - this.sortObjects_.offset = - Math.sin(Blockly.utils.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); + this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); if (this.RTL) { this.sortObjects_.offset *= -1; } @@ -226,9 +242,9 @@ Blockly.Workspace.prototype.getTopBlocks = function(ordered) { /** * Add a block to the list of blocks keyed by type. - * @param {!Blockly.Block} block Block to add. + * @param {!Block} block Block to add. */ -Blockly.Workspace.prototype.addTypedBlock = function(block) { +Workspace.prototype.addTypedBlock = function(block) { if (!this.typedBlocksDB_[block.type]) { this.typedBlocksDB_[block.type] = []; } @@ -237,11 +253,11 @@ Blockly.Workspace.prototype.addTypedBlock = function(block) { /** * Remove a block from the list of blocks keyed by type. - * @param {!Blockly.Block} block Block to remove. + * @param {!Block} block Block to remove. */ -Blockly.Workspace.prototype.removeTypedBlock = function(block) { - this.typedBlocksDB_[block.type].splice(this.typedBlocksDB_[block.type] - .indexOf(block), 1); +Workspace.prototype.removeTypedBlock = function(block) { + this.typedBlocksDB_[block.type].splice( + this.typedBlocksDB_[block.type].indexOf(block), 1); if (!this.typedBlocksDB_[block.type].length) { delete this.typedBlocksDB_[block.type]; } @@ -252,16 +268,15 @@ Blockly.Workspace.prototype.removeTypedBlock = function(block) { * 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. + * @return {!Array} The blocks of the given type. */ -Blockly.Workspace.prototype.getBlocksByType = function(type, ordered) { +Workspace.prototype.getBlocksByType = function(type, ordered) { if (!this.typedBlocksDB_[type]) { return []; } - var blocks = this.typedBlocksDB_[type].slice(0); + const blocks = this.typedBlocksDB_[type].slice(0); if (ordered && blocks.length > 1) { - this.sortObjects_.offset = - Math.sin(Blockly.utils.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); + this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); if (this.RTL) { this.sortObjects_.offset *= -1; } @@ -272,16 +287,17 @@ Blockly.Workspace.prototype.getBlocksByType = function(type, ordered) { /** * Adds a comment to the list of top comments. - * @param {!Blockly.WorkspaceComment} comment comment to add. + * @param {!WorkspaceComment} comment comment to add. * @package */ -Blockly.Workspace.prototype.addTopComment = function(comment) { +Workspace.prototype.addTopComment = function(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 "' + + console.warn( + 'Overriding an existing comment on this workspace, with id "' + comment.id + '"'); } this.commentDB_[comment.id] = comment; @@ -289,12 +305,13 @@ Blockly.Workspace.prototype.addTopComment = function(comment) { /** * Removes a comment from the list of top comments. - * @param {!Blockly.WorkspaceComment} comment comment to remove. + * @param {!WorkspaceComment} comment comment to remove. * @package */ -Blockly.Workspace.prototype.removeTopComment = function(comment) { - if (!Blockly.utils.arrayRemove(this.topComments_, comment)) { - throw Error('Comment not present in workspace\'s list of top-most ' + +Workspace.prototype.removeTopComment = function(comment) { + if (!utils.arrayRemove(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 @@ -306,15 +323,14 @@ Blockly.Workspace.prototype.removeTopComment = function(comment) { * 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. + * @return {!Array} The top-level comment objects. * @package */ -Blockly.Workspace.prototype.getTopComments = function(ordered) { +Workspace.prototype.getTopComments = function(ordered) { // Copy the topComments_ list. - var comments = [].concat(this.topComments_); + const comments = [].concat(this.topComments_); if (ordered && comments.length > 1) { - this.sortObjects_.offset = - Math.sin(Blockly.utils.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); + this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); if (this.RTL) { this.sortObjects_.offset *= -1; } @@ -327,27 +343,28 @@ Blockly.Workspace.prototype.getTopComments = function(ordered) { * 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. + * @return {!Array} Array of blocks. */ -Blockly.Workspace.prototype.getAllBlocks = function(ordered) { +Workspace.prototype.getAllBlocks = function(ordered) { + let blocks; if (ordered) { // Slow, but ordered. - var topBlocks = this.getTopBlocks(true); - var blocks = []; - for (var i = 0; i < topBlocks.length; i++) { + 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. - var blocks = this.getTopBlocks(false); - for (var i = 0; i < blocks.length; i++) { + blocks = this.getTopBlocks(false); + for (let i = 0; i < blocks.length; i++) { blocks.push.apply(blocks, blocks[i].getChildren(false)); } } // Insertion markers exist on the workspace for rendering reasons, but aren't // "real" blocks from a developer perspective. - var filtered = blocks.filter(function(block) { + const filtered = blocks.filter(function(block) { return !block.isInsertionMarker(); }); @@ -357,21 +374,21 @@ Blockly.Workspace.prototype.getAllBlocks = function(ordered) { /** * Dispose of all blocks and comments in workspace. */ -Blockly.Workspace.prototype.clear = function() { +Workspace.prototype.clear = function() { this.isClearing = true; try { - var existingGroup = Blockly.Events.getGroup(); + const existingGroup = Events.getGroup(); if (!existingGroup) { - Blockly.Events.setGroup(true); + Events.setGroup(true); } while (this.topBlocks_.length) { this.topBlocks_[0].dispose(false); } while (this.topComments_.length) { - this.topComments_[this.topComments_.length - 1].dispose(false); + this.topComments_[this.topComments_.length - 1].dispose(); } if (!existingGroup) { - Blockly.Events.setGroup(false); + Events.setGroup(false); } this.variableMap_.clear(); if (this.potentialVariableMap_) { @@ -389,7 +406,7 @@ Blockly.Workspace.prototype.clear = function() { * @param {string} id ID of the variable to rename. * @param {string} newName New variable name. */ -Blockly.Workspace.prototype.renameVariableById = function(id, newName) { +Workspace.prototype.renameVariableById = function(id, newName) { this.variableMap_.renameVariableById(id, newName); }; @@ -402,18 +419,18 @@ Blockly.Workspace.prototype.renameVariableById = function(id, newName) { * 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 {!Blockly.VariableModel} The newly created variable. + * @return {!VariableModel} The newly created variable. */ -Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id) { +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. + * @return {!Array} Array of block usages. */ -Blockly.Workspace.prototype.getVariableUsesById = function(id) { +Workspace.prototype.getVariableUsesById = function(id) { return this.variableMap_.getVariableUsesById(id); }; @@ -422,7 +439,7 @@ Blockly.Workspace.prototype.getVariableUsesById = function(id) { * workspace. May prompt the user for confirmation. * @param {string} id ID of variable to delete. */ -Blockly.Workspace.prototype.deleteVariableById = function(id) { +Workspace.prototype.deleteVariableById = function(id) { this.variableMap_.deleteVariableById(id); }; @@ -431,19 +448,19 @@ Blockly.Workspace.prototype.deleteVariableById = function(id) { * @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 {?Blockly.VariableModel} The variable with the given name. + * @return {?VariableModel} The variable with the given name. */ // TODO (#1559): Possibly delete this function after resolving #1559. -Blockly.Workspace.prototype.getVariable = function(name, opt_type) { +Workspace.prototype.getVariable = function(name, opt_type) { return this.variableMap_.getVariable(name, opt_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 {?Blockly.VariableModel} The variable with the given ID. + * @return {?VariableModel} The variable with the given ID. */ -Blockly.Workspace.prototype.getVariableById = function(id) { +Workspace.prototype.getVariableById = function(id) { return this.variableMap_.getVariableById(id); }; @@ -451,10 +468,10 @@ Blockly.Workspace.prototype.getVariableById = function(id) { * 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 + * @return {!Array} The sought after variables of the * passed in type. An empty array if none are found. */ -Blockly.Workspace.prototype.getVariablesOfType = function(type) { +Workspace.prototype.getVariablesOfType = function(type) { return this.variableMap_.getVariablesOfType(type); }; @@ -463,15 +480,15 @@ Blockly.Workspace.prototype.getVariablesOfType = function(type) { * @return {!Array} List of variable types. * @package */ -Blockly.Workspace.prototype.getVariableTypes = function() { +Workspace.prototype.getVariableTypes = function() { return this.variableMap_.getVariableTypes(this); }; /** * Return all variables of all types. - * @return {!Array} List of variable models. + * @return {!Array} List of variable models. */ -Blockly.Workspace.prototype.getAllVariables = function() { +Workspace.prototype.getAllVariables = function() { return this.variableMap_.getAllVariables(); }; @@ -479,7 +496,7 @@ Blockly.Workspace.prototype.getAllVariables = function() { * Returns all variable names of all types. * @return {!Array} List of all variable names of all types. */ -Blockly.Workspace.prototype.getAllVariableNames = function() { +Workspace.prototype.getAllVariableNames = function() { return this.variableMap_.getAllVariableNames(); }; @@ -491,7 +508,7 @@ Blockly.Workspace.prototype.getAllVariableNames = function() { * Not relevant for a headless workspace. * @return {number} Width. */ -Blockly.Workspace.prototype.getWidth = function() { +Workspace.prototype.getWidth = function() { return 0; }; @@ -501,10 +518,11 @@ Blockly.Workspace.prototype.getWidth = function() { * type-specific functions for this block. * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise * create a new ID. - * @return {!Blockly.Block} The created block. + * @return {!Block} The created block. */ -Blockly.Workspace.prototype.newBlock = function(prototypeName, opt_id) { - return new Blockly.Block(this, prototypeName, opt_id); +Workspace.prototype.newBlock = function(prototypeName, opt_id) { + const Block = goog.module.get('Blockly.Block'); + return new Block(this, prototypeName, opt_id); }; /** @@ -512,7 +530,7 @@ Blockly.Workspace.prototype.newBlock = function(prototypeName, opt_id) { * the maxBlocks. * @return {number} Number of blocks left. */ -Blockly.Workspace.prototype.remainingCapacity = function() { +Workspace.prototype.remainingCapacity = function() { if (isNaN(this.options.maxBlocks)) { return Infinity; } @@ -526,13 +544,14 @@ Blockly.Workspace.prototype.remainingCapacity = function() { * @param {string} type Type of block to return capacity for. * @return {number} Number of blocks of type left. */ -Blockly.Workspace.prototype.remainingCapacityOfType = function(type) { +Workspace.prototype.remainingCapacityOfType = function(type) { if (!this.options.maxInstances) { return Infinity; } - var maxInstanceOfType = (this.options.maxInstances[type] !== undefined) ? - this.options.maxInstances[type] : Infinity; + const maxInstanceOfType = (this.options.maxInstances[type] !== undefined) ? + this.options.maxInstances[type] : + Infinity; return maxInstanceOfType - this.getBlocksByType(type, false).length; }; @@ -547,12 +566,12 @@ Blockly.Workspace.prototype.remainingCapacityOfType = function(type) { * @return {boolean} True if there is capacity for the given map, * false otherwise. */ -Blockly.Workspace.prototype.isCapacityAvailable = function(typeCountsMap) { +Workspace.prototype.isCapacityAvailable = function(typeCountsMap) { if (!this.hasBlockLimits()) { return true; } - var copyableBlocksCount = 0; - for (var type in typeCountsMap) { + let copyableBlocksCount = 0; + for (const type in typeCountsMap) { if (typeCountsMap[type] > this.remainingCapacityOfType(type)) { return false; } @@ -569,25 +588,25 @@ Blockly.Workspace.prototype.isCapacityAvailable = function(typeCountsMap) { * or the maximum number of blocks of specific types. * @return {boolean} True if it has block limits, false otherwise. */ -Blockly.Workspace.prototype.hasBlockLimits = function() { +Workspace.prototype.hasBlockLimits = function() { return this.options.maxBlocks != Infinity || !!this.options.maxInstances; }; /** * Gets the undo stack for workplace. - * @return {!Array} undo stack + * @return {!Array} undo stack * @package */ -Blockly.Workspace.prototype.getUndoStack = function() { +Workspace.prototype.getUndoStack = function() { return this.undoStack_; }; /** * Gets the redo stack for workplace. - * @return {!Array} redo stack + * @return {!Array} redo stack * @package */ -Blockly.Workspace.prototype.getRedoStack = function() { +Workspace.prototype.getRedoStack = function() { return this.redoStack_; }; @@ -595,42 +614,44 @@ Blockly.Workspace.prototype.getRedoStack = function() { * Undo or redo the previous action. * @param {boolean} redo False if undo, true if redo. */ -Blockly.Workspace.prototype.undo = function(redo) { - var inputStack = redo ? this.redoStack_ : this.undoStack_; - var outputStack = redo ? this.undoStack_ : this.redoStack_; - var inputEvent = inputStack.pop(); +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; } - var events = [inputEvent]; + 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) { + inputEvent.group == inputStack[inputStack.length - 1].group) { events.push(inputStack.pop()); } // Push these popped events on the opposite stack. - for (var i = 0, event; (event = events[i]); i++) { + for (let i = 0; i < events.length; i++) { + const event = events[i]; outputStack.push(event); } - events = Blockly.Events.filter(events, redo); - Blockly.Events.recordUndo = false; + events = Events.filter(events, redo); + Events.recordUndo = false; try { - for (var i = 0, event; (event = events[i]); i++) { + for (let i = 0; i < events.length; i++) { + const event = events[i]; event.run(redo); } } finally { - Blockly.Events.recordUndo = true; + Events.recordUndo = true; } }; /** * Clear the undo/redo stacks. */ -Blockly.Workspace.prototype.clearUndo = function() { +Workspace.prototype.clearUndo = function() { this.undoStack_.length = 0; this.redoStack_.length = 0; // Stop any events already in the firing queue from being undoable. - Blockly.Events.clearPendingUndo(); + Events.clearPendingUndo(); }; /** @@ -641,7 +662,7 @@ Blockly.Workspace.prototype.clearUndo = function() { * @param {!Function} func Function to call. * @return {!Function} Obsolete return value, ignore. */ -Blockly.Workspace.prototype.addChangeListener = function(func) { +Workspace.prototype.addChangeListener = function(func) { this.listeners_.push(func); return func; }; @@ -650,15 +671,15 @@ Blockly.Workspace.prototype.addChangeListener = function(func) { * Stop listening for this workspace's changes. * @param {!Function} func Function to stop calling. */ -Blockly.Workspace.prototype.removeChangeListener = function(func) { - Blockly.utils.arrayRemove(this.listeners_, func); +Workspace.prototype.removeChangeListener = function(func) { + utils.arrayRemove(this.listeners_, func); }; /** * Fire a change event. - * @param {!Blockly.Events.Abstract} event Event to fire. + * @param {!Abstract} event Event to fire. */ -Blockly.Workspace.prototype.fireChangeListener = function(event) { +Workspace.prototype.fireChangeListener = function(event) { if (event.recordUndo) { this.undoStack_.push(event); this.redoStack_.length = 0; @@ -666,7 +687,8 @@ Blockly.Workspace.prototype.fireChangeListener = function(event) { this.undoStack_.shift(); } } - for (var i = 0, func; (func = this.listeners_[i]); i++) { + for (let i = 0; i < this.listeners_.length; i++) { + const func = this.listeners_[i]; func(event); } }; @@ -674,19 +696,19 @@ Blockly.Workspace.prototype.fireChangeListener = function(event) { /** * Find the block on this workspace with the specified ID. * @param {string} id ID of block to find. - * @return {?Blockly.Block} The sought after block, or null if not found. + * @return {?Block} The sought after block, or null if not found. */ -Blockly.Workspace.prototype.getBlockById = function(id) { +Workspace.prototype.getBlockById = function(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 {Blockly.Block} block The block to set. + * @param {Block} block The block to set. * @package */ -Blockly.Workspace.prototype.setBlockById = function(id, block) { +Workspace.prototype.setBlockById = function(id, block) { this.blockDB_[id] = block; }; @@ -695,18 +717,18 @@ Blockly.Workspace.prototype.setBlockById = function(id, block) { * @param {string} id ID of block to delete. * @package */ -Blockly.Workspace.prototype.removeBlockById = function(id) { +Workspace.prototype.removeBlockById = function(id) { delete this.blockDB_[id]; }; /** * Find the comment on this workspace with the specified ID. * @param {string} id ID of comment to find. - * @return {?Blockly.WorkspaceComment} The sought after comment, or null if not + * @return {?WorkspaceComment} The sought after comment, or null if not * found. * @package */ -Blockly.Workspace.prototype.getCommentById = function(id) { +Workspace.prototype.getCommentById = function(id) { return this.commentDB_[id] || null; }; @@ -717,10 +739,10 @@ Blockly.Workspace.prototype.getCommentById = function(id) { * whether shadow blocks are counted as filled. Defaults to true. * @return {boolean} True if all inputs are filled, false otherwise. */ -Blockly.Workspace.prototype.allInputsFilled = function( - opt_shadowBlocksAreFilled) { - var blocks = this.getTopBlocks(false); - for (var i = 0, block; (block = blocks[i]); i++) { +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; } @@ -731,10 +753,10 @@ Blockly.Workspace.prototype.allInputsFilled = function( /** * Return the variable map that contains "potential" variables. * These exist in the flyout but not in the workspace. - * @return {?Blockly.VariableMap} The potential variable map. + * @return {?VariableMap} The potential variable map. * @package */ -Blockly.Workspace.prototype.getPotentialVariableMap = function() { +Workspace.prototype.getPotentialVariableMap = function() { return this.potentialVariableMap_; }; @@ -742,51 +764,46 @@ Blockly.Workspace.prototype.getPotentialVariableMap = function() { * Create and store the potential variable map for this workspace. * @package */ -Blockly.Workspace.prototype.createPotentialVariableMap = function() { - this.potentialVariableMap_ = new Blockly.VariableMap(this); +Workspace.prototype.createPotentialVariableMap = function() { + this.potentialVariableMap_ = new VariableMap(this); }; /** * Return the map of all variables on the workspace. - * @return {!Blockly.VariableMap} The variable map. + * @return {!VariableMap} The variable map. */ -Blockly.Workspace.prototype.getVariableMap = function() { +Workspace.prototype.getVariableMap = function() { return this.variableMap_; }; /** * Set the map of all variables on the workspace. - * @param {!Blockly.VariableMap} variableMap The variable map. + * @param {!VariableMap} variableMap The variable map. * @package */ -Blockly.Workspace.prototype.setVariableMap = function(variableMap) { +Workspace.prototype.setVariableMap = function(variableMap) { this.variableMap_ = variableMap; }; - -/** - * Database of all workspaces. - * @private - */ -Blockly.Workspace.WorkspaceDB_ = Object.create(null); - /** * Find the workspace with the specified ID. * @param {string} id ID of workspace to find. - * @return {?Blockly.Workspace} The sought after workspace or null if not found. + * @return {?Workspace} The sought after workspace or null if not found. */ -Blockly.Workspace.getById = function(id) { - return Blockly.Workspace.WorkspaceDB_[id] || null; +Workspace.getById = function(id) { + return WorkspaceDB_[id] || null; }; /** * Find all workspaces. - * @return {!Array} Array of workspaces. + * @return {!Array} Array of workspaces. */ -Blockly.Workspace.getAll = function() { - var workspaces = []; - for (var workspaceId in Blockly.Workspace.WorkspaceDB_) { - workspaces.push(Blockly.Workspace.WorkspaceDB_[workspaceId]); +Workspace.getAll = function() { + const workspaces = []; + for (const workspaceId in WorkspaceDB_) { + workspaces.push(WorkspaceDB_[workspaceId]); } return workspaces; }; + +exports = Workspace; diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 378c19287..ba1da0c95 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -11,28 +11,27 @@ */ 'use strict'; -goog.provide('Blockly.WorkspaceAudio'); +goog.module('Blockly.WorkspaceAudio'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.global'); -goog.require('Blockly.utils.userAgent'); - -goog.requireType('Blockly.WorkspaceSvg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const global = goog.require('Blockly.utils.global'); +const internalConstants = goog.require('Blockly.internalConstants'); +const userAgent = goog.require('Blockly.utils.userAgent'); /** * Class for loading, storing, and playing audio for a workspace. - * @param {Blockly.WorkspaceSvg} parentWorkspace The parent of the workspace + * @param {WorkspaceSvg} parentWorkspace The parent of the workspace * this audio object belongs to, or null. * @constructor */ -Blockly.WorkspaceAudio = function(parentWorkspace) { - +const WorkspaceAudio = function(parentWorkspace) { /** * The parent of the workspace this object belongs to, or null. May be * checked for sounds that this object can't find. - * @type {Blockly.WorkspaceSvg} + * @type {WorkspaceSvg} * @private */ this.parentWorkspace_ = parentWorkspace; @@ -49,13 +48,13 @@ Blockly.WorkspaceAudio = function(parentWorkspace) { * @type {Date} * @private */ -Blockly.WorkspaceAudio.prototype.lastSound_ = null; +WorkspaceAudio.prototype.lastSound_ = null; /** * Dispose of this audio manager. * @package */ -Blockly.WorkspaceAudio.prototype.dispose = function() { +WorkspaceAudio.prototype.dispose = function() { this.parentWorkspace_ = null; this.SOUNDS_ = null; }; @@ -67,24 +66,25 @@ Blockly.WorkspaceAudio.prototype.dispose = function() { * Filenames include path from Blockly's root. File extensions matter. * @param {string} name Name of sound. */ -Blockly.WorkspaceAudio.prototype.load = function(filenames, name) { +WorkspaceAudio.prototype.load = function(filenames, name) { if (!filenames.length) { return; } + let audioTest; try { - var audioTest = new Blockly.utils.global['Audio'](); + audioTest = new global['Audio'](); } catch (e) { // No browser support for Audio. // IE can throw an error even if the Audio object exists. return; } - var sound; - for (var i = 0; i < filenames.length; i++) { - var filename = filenames[i]; - var ext = filename.match(/\.(\w+)$/); + let sound; + for (let i = 0; i < filenames.length; i++) { + const filename = filenames[i]; + const ext = filename.match(/\.(\w+)$/); if (ext && audioTest.canPlayType('audio/' + ext[1])) { // Found an audio format we can play. - sound = new Blockly.utils.global['Audio'](filename); + sound = new global['Audio'](filename); break; } } @@ -97,16 +97,17 @@ Blockly.WorkspaceAudio.prototype.load = function(filenames, name) { * Preload all the audio files so that they play quickly when asked for. * @package */ -Blockly.WorkspaceAudio.prototype.preload = function() { - for (var name in this.SOUNDS_) { - var sound = this.SOUNDS_[name]; +WorkspaceAudio.prototype.preload = function() { + for (const name in this.SOUNDS_) { + const sound = this.SOUNDS_[name]; sound.volume = 0.01; - var playPromise = sound.play(); + const playPromise = sound.play(); // Edge does not return a promise, so we need to check. if (playPromise !== undefined) { - // If we don't wait for the play request to complete before calling pause() - // we will get an exception: (DOMException: The play() request was interrupted) - // See more: https://developers.google.com/web/updates/2017/06/play-request-was-interrupted + // If we don't wait for the play request to complete before calling + // pause() we will get an exception: (DOMException: The play() request was + // interrupted) See more: + // https://developers.google.com/web/updates/2017/06/play-request-was-interrupted playPromise.then(sound.pause).catch(function() { // Play without user interaction was prevented. }); @@ -116,7 +117,7 @@ Blockly.WorkspaceAudio.prototype.preload = function() { // iOS can only process one sound at a time. Trying to load more than one // corrupts the earlier ones. Just load one and leave the others uncached. - if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.IPHONE) { + if (userAgent.IPAD || userAgent.IPHONE) { break; } } @@ -128,18 +129,18 @@ Blockly.WorkspaceAudio.prototype.preload = function() { * @param {string} name Name of sound. * @param {number=} opt_volume Volume of sound (0-1). */ -Blockly.WorkspaceAudio.prototype.play = function(name, opt_volume) { - var sound = this.SOUNDS_[name]; +WorkspaceAudio.prototype.play = function(name, opt_volume) { + const sound = this.SOUNDS_[name]; if (sound) { // Don't play one sound on top of another. - var now = new Date; + const now = new Date; if (this.lastSound_ != null && - now - this.lastSound_ < Blockly.internalConstants.SOUND_LIMIT) { + now - this.lastSound_ < internalConstants.SOUND_LIMIT) { return; } this.lastSound_ = now; - var mySound; - if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.ANDROID) { + let mySound; + if (userAgent.IPAD || userAgent.ANDROID) { // Creating a new audio node causes lag in Android and iPad. Android // refetches the file from the server, iPad uses a singleton audio // node which must be deleted and recreated for each new audio tag. @@ -154,3 +155,5 @@ Blockly.WorkspaceAudio.prototype.play = function(name, opt_volume) { this.parentWorkspace_.getAudioManager().play(name, opt_volume); } }; + +exports = WorkspaceAudio; diff --git a/core/workspace_comment.js b/core/workspace_comment.js index 5399dbe39..78019bc80 100644 --- a/core/workspace_comment.js +++ b/core/workspace_comment.js @@ -10,9 +10,15 @@ */ 'use strict'; -goog.provide('Blockly.WorkspaceComment'); +goog.module('Blockly.WorkspaceComment'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Events'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const utils = goog.require('Blockly.utils'); +const xml = goog.require('Blockly.utils.xml'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.CommentChange'); /** @suppress {extraRequire} */ @@ -21,14 +27,11 @@ goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.CommentMove'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.xml'); /** * Class for a workspace comment. - * @param {!Blockly.Workspace} workspace The block's workspace. + * @param {!Workspace} workspace The block's workspace. * @param {string} content The content of this workspace comment. * @param {number} height Height of the comment. * @param {number} width Width of the comment. @@ -36,37 +39,37 @@ goog.require('Blockly.utils.xml'); * create a new ID. * @constructor */ -Blockly.WorkspaceComment = function(workspace, content, height, width, opt_id) { +const WorkspaceComment = function(workspace, content, height, width, opt_id) { /** @type {string} */ - this.id = (opt_id && !workspace.getCommentById(opt_id)) ? - opt_id : Blockly.utils.genUid(); + this.id = + (opt_id && !workspace.getCommentById(opt_id)) ? opt_id : utils.genUid(); workspace.addTopComment(this); /** * The comment's position in workspace units. (0, 0) is at the workspace's * origin; scale does not change this value. - * @type {!Blockly.utils.Coordinate} + * @type {!Coordinate} * @protected */ - this.xy_ = new Blockly.utils.Coordinate(0, 0); + this.xy_ = new Coordinate(0, 0); /** * The comment's height in workspace units. Scale does not change this value. * @type {number} - * @private + * @protected */ this.height_ = height; /** * The comment's width in workspace units. Scale does not change this value. * @type {number} - * @private + * @protected */ this.width_ = width; /** - * @type {!Blockly.Workspace} + * @type {!Workspace} */ this.workspace = workspace; @@ -100,33 +103,38 @@ Blockly.WorkspaceComment = function(workspace, content, height, width, opt_id) { */ this.content_ = content; + /** + * Whether this comment has been disposed. + * @protected + * @type {boolean} + */ + this.disposed_ = false; + /** * @package * @type {boolean} */ this.isComment = true; - Blockly.WorkspaceComment.fireCreateEvent(this); + WorkspaceComment.fireCreateEvent(this); }; /** * Dispose of this comment. * @package */ -Blockly.WorkspaceComment.prototype.dispose = function() { - if (!this.workspace) { - // The comment has already been deleted. +WorkspaceComment.prototype.dispose = function() { + if (this.disposed_) { return; } - if (Blockly.Events.isEnabled()) { - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.COMMENT_DELETE))(this)); + if (Events.isEnabled()) { + Events.fire(new (Events.get(Events.COMMENT_DELETE))(this)); } // Remove from the list of top comments and the comment database. this.workspace.removeTopComment(this); - this.workspace = null; + this.disposed_ = true; }; // Height, width, x, and y are all stored on even non-rendered comments, to @@ -137,7 +145,7 @@ Blockly.WorkspaceComment.prototype.dispose = function() { * @return {number} Comment height. * @package */ -Blockly.WorkspaceComment.prototype.getHeight = function() { +WorkspaceComment.prototype.getHeight = function() { return this.height_; }; @@ -146,7 +154,7 @@ Blockly.WorkspaceComment.prototype.getHeight = function() { * @param {number} height Comment height. * @package */ -Blockly.WorkspaceComment.prototype.setHeight = function(height) { +WorkspaceComment.prototype.setHeight = function(height) { this.height_ = height; }; @@ -155,7 +163,7 @@ Blockly.WorkspaceComment.prototype.setHeight = function(height) { * @return {number} Comment width. * @package */ -Blockly.WorkspaceComment.prototype.getWidth = function() { +WorkspaceComment.prototype.getWidth = function() { return this.width_; }; @@ -164,18 +172,18 @@ Blockly.WorkspaceComment.prototype.getWidth = function() { * @param {number} width comment width. * @package */ -Blockly.WorkspaceComment.prototype.setWidth = function(width) { +WorkspaceComment.prototype.setWidth = function(width) { this.width_ = width; }; /** * Get stored location. - * @return {!Blockly.utils.Coordinate} The comment's stored location. + * @return {!Coordinate} The comment's stored location. * This is not valid if the comment is currently being dragged. * @package */ -Blockly.WorkspaceComment.prototype.getXY = function() { - return new Blockly.utils.Coordinate(this.xy_.x, this.xy_.y); +WorkspaceComment.prototype.getXY = function() { + return new Coordinate(this.xy_.x, this.xy_.y); }; /** @@ -184,11 +192,11 @@ Blockly.WorkspaceComment.prototype.getXY = function() { * @param {number} dy Vertical offset, in workspace units. * @package */ -Blockly.WorkspaceComment.prototype.moveBy = function(dx, dy) { - var event = new (Blockly.Events.get(Blockly.Events.COMMENT_MOVE))(this); +WorkspaceComment.prototype.moveBy = function(dx, dy) { + const event = new (Events.get(Events.COMMENT_MOVE))(this); this.xy_.translate(dx, dy); event.recordNew(); - Blockly.Events.fire(event); + Events.fire(event); }; /** @@ -196,7 +204,7 @@ Blockly.WorkspaceComment.prototype.moveBy = function(dx, dy) { * @return {boolean} True if deletable. * @package */ -Blockly.WorkspaceComment.prototype.isDeletable = function() { +WorkspaceComment.prototype.isDeletable = function() { return this.deletable_ && !(this.workspace && this.workspace.options.readOnly); }; @@ -206,7 +214,7 @@ Blockly.WorkspaceComment.prototype.isDeletable = function() { * @param {boolean} deletable True if deletable. * @package */ -Blockly.WorkspaceComment.prototype.setDeletable = function(deletable) { +WorkspaceComment.prototype.setDeletable = function(deletable) { this.deletable_ = deletable; }; @@ -215,9 +223,8 @@ Blockly.WorkspaceComment.prototype.setDeletable = function(deletable) { * @return {boolean} True if movable. * @package */ -Blockly.WorkspaceComment.prototype.isMovable = function() { - return this.movable_ && - !(this.workspace && this.workspace.options.readOnly); +WorkspaceComment.prototype.isMovable = function() { + return this.movable_ && !(this.workspace && this.workspace.options.readOnly); }; /** @@ -225,7 +232,7 @@ Blockly.WorkspaceComment.prototype.isMovable = function() { * @param {boolean} movable True if movable. * @package */ -Blockly.WorkspaceComment.prototype.setMovable = function(movable) { +WorkspaceComment.prototype.setMovable = function(movable) { this.movable_ = movable; }; @@ -233,16 +240,15 @@ Blockly.WorkspaceComment.prototype.setMovable = function(movable) { * Get whether this comment is editable or not. * @return {boolean} True if editable. */ -Blockly.WorkspaceComment.prototype.isEditable = function() { - return this.editable_ && - !(this.workspace && this.workspace.options.readOnly); +WorkspaceComment.prototype.isEditable = function() { + return this.editable_ && !(this.workspace && this.workspace.options.readOnly); }; /** * Set whether this comment is editable or not. * @param {boolean} editable True if editable. */ -Blockly.WorkspaceComment.prototype.setEditable = function(editable) { +WorkspaceComment.prototype.setEditable = function(editable) { this.editable_ = editable; }; @@ -251,7 +257,7 @@ Blockly.WorkspaceComment.prototype.setEditable = function(editable) { * @return {string} Comment text. * @package */ -Blockly.WorkspaceComment.prototype.getContent = function() { +WorkspaceComment.prototype.getContent = function() { return this.content_; }; @@ -260,10 +266,10 @@ Blockly.WorkspaceComment.prototype.getContent = function() { * @param {string} content Comment content. * @package */ -Blockly.WorkspaceComment.prototype.setContent = function(content) { +WorkspaceComment.prototype.setContent = function(content) { if (this.content_ != content) { - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.COMMENT_CHANGE))( - this, this.content_, content)); + Events.fire( + new (Events.get(Events.COMMENT_CHANGE))(this, this.content_, content)); this.content_ = content; } }; @@ -274,8 +280,8 @@ Blockly.WorkspaceComment.prototype.setContent = function(content) { * @return {!Element} Tree of XML elements. * @package */ -Blockly.WorkspaceComment.prototype.toXmlWithXY = function(opt_noId) { - var element = this.toXml(opt_noId); +WorkspaceComment.prototype.toXmlWithXY = function(opt_noId) { + const element = this.toXml(opt_noId); element.setAttribute('x', Math.round(this.xy_.x)); element.setAttribute('y', Math.round(this.xy_.y)); element.setAttribute('h', this.height_); @@ -291,8 +297,8 @@ Blockly.WorkspaceComment.prototype.toXmlWithXY = function(opt_noId) { * @return {!Element} Tree of XML elements. * @package */ -Blockly.WorkspaceComment.prototype.toXml = function(opt_noId) { - var commentElement = Blockly.utils.xml.createElement('comment'); +WorkspaceComment.prototype.toXml = function(opt_noId) { + const commentElement = xml.createElement('comment'); if (!opt_noId) { commentElement.id = this.id; } @@ -302,21 +308,20 @@ Blockly.WorkspaceComment.prototype.toXml = function(opt_noId) { /** * Fire a create event for the given workspace comment, if comments are enabled. - * @param {!Blockly.WorkspaceComment} comment The comment that was just created. + * @param {!WorkspaceComment} comment The comment that was just created. * @package */ -Blockly.WorkspaceComment.fireCreateEvent = function(comment) { - if (Blockly.Events.isEnabled()) { - var existingGroup = Blockly.Events.getGroup(); +WorkspaceComment.fireCreateEvent = function(comment) { + if (Events.isEnabled()) { + const existingGroup = Events.getGroup(); if (!existingGroup) { - Blockly.Events.setGroup(true); + Events.setGroup(true); } try { - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.COMMENT_CREATE))(comment)); + Events.fire(new (Events.get(Events.COMMENT_CREATE))(comment)); } finally { if (!existingGroup) { - Blockly.Events.setGroup(false); + Events.setGroup(false); } } } @@ -325,23 +330,23 @@ Blockly.WorkspaceComment.fireCreateEvent = function(comment) { /** * Decode an XML comment tag and create a comment on the workspace. * @param {!Element} xmlComment XML comment element. - * @param {!Blockly.Workspace} workspace The workspace. - * @return {!Blockly.WorkspaceComment} The created workspace comment. + * @param {!Workspace} workspace The workspace. + * @return {!WorkspaceComment} The created workspace comment. * @package */ -Blockly.WorkspaceComment.fromXml = function(xmlComment, workspace) { - var info = Blockly.WorkspaceComment.parseAttributes(xmlComment); +WorkspaceComment.fromXml = function(xmlComment, workspace) { + const info = WorkspaceComment.parseAttributes(xmlComment); - var comment = new Blockly.WorkspaceComment( - workspace, info.content, info.h, info.w, info.id); + const comment = + new WorkspaceComment(workspace, info.content, info.h, info.w, info.id); - var commentX = parseInt(xmlComment.getAttribute('x'), 10); - var commentY = parseInt(xmlComment.getAttribute('y'), 10); + const commentX = parseInt(xmlComment.getAttribute('x'), 10); + const commentY = parseInt(xmlComment.getAttribute('y'), 10); if (!isNaN(commentX) && !isNaN(commentY)) { comment.moveBy(commentX, commentY); } - Blockly.WorkspaceComment.fireCreateEvent(comment); + WorkspaceComment.fireCreateEvent(comment); return comment; }; @@ -352,9 +357,9 @@ Blockly.WorkspaceComment.fromXml = function(xmlComment, workspace) { * object containing the id, size, position, and comment string. * @package */ -Blockly.WorkspaceComment.parseAttributes = function(xml) { - var xmlH = xml.getAttribute('h'); - var xmlW = xml.getAttribute('w'); +WorkspaceComment.parseAttributes = function(xml) { + const xmlH = xml.getAttribute('h'); + const xmlW = xml.getAttribute('w'); return { // @type {string} @@ -377,3 +382,5 @@ Blockly.WorkspaceComment.parseAttributes = function(xml) { content: xml.textContent }; }; + +exports = WorkspaceComment; diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js deleted file mode 100644 index 5097f0c92..000000000 --- a/core/workspace_comment_render_svg.js +++ /dev/null @@ -1,463 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Methods for rendering a workspace comment as SVG - * @author fenichel@google.com (Rachel Fenichel) - */ -'use strict'; - -goog.provide('Blockly.WorkspaceCommentSvg.render'); - -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Svg'); - - -/** - * Size of the resize icon. - * @type {number} - * @const - * @private - */ -Blockly.WorkspaceCommentSvg.RESIZE_SIZE = 8; - -/** - * Radius of the border around the comment. - * @type {number} - * @const - * @private - */ -Blockly.WorkspaceCommentSvg.BORDER_RADIUS = 3; - -/** - * Offset from the foreignobject edge to the textarea edge. - * @type {number} - * @const - * @private - */ -Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET = 2; - -/** - * Offset from the top to make room for a top bar. - * @type {number} - * @const - * @private - */ -Blockly.WorkspaceCommentSvg.TOP_OFFSET = 10; - -/** - * Returns a bounding box describing the dimensions of this comment. - * @return {!{height: number, width: number}} Object with height and width - * properties in workspace units. - * @package - */ -Blockly.WorkspaceCommentSvg.prototype.getHeightWidth = function() { - return { width: this.getWidth(), height: this.getHeight() }; -}; - -/** - * Renders the workspace comment. - * @package - */ -Blockly.WorkspaceCommentSvg.prototype.render = function() { - if (this.rendered_) { - return; - } - - var size = this.getHeightWidth(); - - // Add text area - this.createEditor_(); - this.svgGroup_.appendChild(this.foreignObject_); - - this.svgHandleTarget_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - 'class': 'blocklyCommentHandleTarget', - 'x': 0, - 'y': 0 - }); - this.svgGroup_.appendChild(this.svgHandleTarget_); - this.svgRectTarget_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - 'class': 'blocklyCommentTarget', - 'x': 0, - 'y': 0, - 'rx': Blockly.WorkspaceCommentSvg.BORDER_RADIUS, - 'ry': Blockly.WorkspaceCommentSvg.BORDER_RADIUS - }); - this.svgGroup_.appendChild(this.svgRectTarget_); - - // Add the resize icon - this.addResizeDom_(); - if (this.isDeletable()) { - // Add the delete icon - this.addDeleteDom_(); - } - - this.setSize_(size.width, size.height); - - // Set the content - this.textarea_.value = this.content_; - - this.rendered_ = true; - - if (this.resizeGroup_) { - Blockly.browserEvents.conditionalBind( - this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); - } - - if (this.isDeletable()) { - Blockly.browserEvents.conditionalBind( - this.deleteGroup_, 'mousedown', this, this.deleteMouseDown_); - Blockly.browserEvents.conditionalBind( - this.deleteGroup_, 'mouseout', this, this.deleteMouseOut_); - Blockly.browserEvents.conditionalBind( - this.deleteGroup_, 'mouseup', this, this.deleteMouseUp_); - } -}; - -/** - * Create the text area for the comment. - * @return {!Element} The top-level node of the editor. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() { - /* Create the editor. Here's the markup that will be generated: - - - - - - */ - this.foreignObject_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.FOREIGNOBJECT, - { - 'x': 0, - 'y': Blockly.WorkspaceCommentSvg.TOP_OFFSET, - 'class': 'blocklyCommentForeignObject' - }, - null); - var body = document.createElementNS(Blockly.utils.dom.HTML_NS, 'body'); - body.setAttribute('xmlns', Blockly.utils.dom.HTML_NS); - body.className = 'blocklyMinimalBody'; - var textarea = document.createElementNS(Blockly.utils.dom.HTML_NS, 'textarea'); - textarea.className = 'blocklyCommentTextarea'; - textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR'); - textarea.readOnly = !this.isEditable(); - body.appendChild(textarea); - this.textarea_ = textarea; - this.foreignObject_.appendChild(body); - // Don't zoom with mousewheel. - Blockly.browserEvents.conditionalBind(textarea, 'wheel', this, function(e) { - e.stopPropagation(); - }); - Blockly.browserEvents.conditionalBind( - textarea, 'change', this, - function( - /* eslint-disable no-unused-vars */ e - /* eslint-enable no-unused-vars */) { - this.setContent(textarea.value); - }); - return this.foreignObject_; -}; - -/** - * Add the resize icon to the DOM - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() { - this.resizeGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - { - 'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE' - }, - this.svgGroup_); - var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE; - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.POLYGON, - {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, - this.resizeGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, - { - 'class': 'blocklyResizeLine', - 'x1': resizeSize / 3, 'y1': resizeSize - 1, - 'x2': resizeSize - 1, 'y2': resizeSize / 3 - }, this.resizeGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, - { - 'class': 'blocklyResizeLine', - 'x1': resizeSize * 2 / 3, 'y1': resizeSize - 1, - 'x2': resizeSize - 1, 'y2': resizeSize * 2 / 3 - }, this.resizeGroup_); -}; - -/** - * Add the delete icon to the DOM - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { - this.deleteGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - { - 'class': 'blocklyCommentDeleteIcon' - }, - this.svgGroup_); - this.deleteIconBorder_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.CIRCLE, - { - 'class': 'blocklyDeleteIconShape', - 'r': '7', - 'cx': '7.5', - 'cy': '7.5' - }, - this.deleteGroup_); - // x icon. - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, - { - 'x1': '5', 'y1': '10', - 'x2': '10', 'y2': '5', - 'stroke': '#fff', - 'stroke-width': '2' - }, - this.deleteGroup_); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, - { - 'x1': '5', 'y1': '5', - 'x2': '10', 'y2': '10', - 'stroke': '#fff', - 'stroke-width': '2' - }, - this.deleteGroup_); -}; - -/** - * Handle a mouse-down on comment's resize corner. - * @param {!Event} e Mouse down event. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_ = function(e) { - this.unbindDragEvents_(); - if (Blockly.utils.isRightButton(e)) { - // No right-click. - e.stopPropagation(); - return; - } - // Left-click (or middle click) - this.workspace.startDrag(e, new Blockly.utils.Coordinate( - this.workspace.RTL ? -this.width_ : this.width_, this.height_)); - - this.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind( - document, 'mouseup', this, this.resizeMouseUp_); - this.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind( - document, 'mousemove', this, this.resizeMouseMove_); - Blockly.hideChaff(); - // This event has been handled. No need to bubble up to the document. - e.stopPropagation(); -}; - -/** - * Handle a mouse-down on comment's delete icon. - * @param {!Event} e Mouse down event. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) { - // Highlight the delete icon. - Blockly.utils.dom.addClass( - /** @type {!Element} */ (this.deleteIconBorder_), - 'blocklyDeleteIconHighlighted'); - // This event has been handled. No need to bubble up to the document. - e.stopPropagation(); -}; - -/** - * Handle a mouse-out on comment's delete icon. - * @param {!Event} _e Mouse out event. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(_e) { - // Restore highlight on the delete icon. - Blockly.utils.dom.removeClass( - /** @type {!Element} */ (this.deleteIconBorder_), - 'blocklyDeleteIconHighlighted'); -}; - -/** - * Handle a mouse-up on comment's delete icon. - * @param {!Event} e Mouse up event. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_ = function(e) { - // Delete this comment. - this.dispose(true, true); - // This event has been handled. No need to bubble up to the document. - e.stopPropagation(); -}; - -/** - * Stop binding to the global mouseup and mousemove events. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.unbindDragEvents_ = function() { - if (this.onMouseUpWrapper_) { - Blockly.browserEvents.unbind(this.onMouseUpWrapper_); - this.onMouseUpWrapper_ = null; - } - if (this.onMouseMoveWrapper_) { - Blockly.browserEvents.unbind(this.onMouseMoveWrapper_); - this.onMouseMoveWrapper_ = null; - } -}; - -/** - * Handle a mouse-up event while dragging a comment's border or resize handle. - * @param {!Event} e Mouse up event. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.resizeMouseUp_ = function(/* e */) { - Blockly.Touch.clearTouchIdentifier(); - this.unbindDragEvents_(); -}; - -/** - * Resize this comment to follow the mouse. - * @param {!Event} e Mouse move event. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.resizeMouseMove_ = function(e) { - this.autoLayout_ = false; - var newXY = this.workspace.moveDrag(e); - this.setSize_(this.RTL ? -newXY.x : newXY.x, newXY.y); -}; - -/** - * Callback function triggered when the comment has resized. - * Resize the text area accordingly. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.resizeComment_ = function() { - var size = this.getHeightWidth(); - var topOffset = Blockly.WorkspaceCommentSvg.TOP_OFFSET; - var textOffset = Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET * 2; - - this.foreignObject_.setAttribute('width', size.width); - this.foreignObject_.setAttribute('height', size.height - topOffset); - if (this.RTL) { - this.foreignObject_.setAttribute('x', -size.width); - } - this.textarea_.style.width = (size.width - textOffset) + 'px'; - this.textarea_.style.height = (size.height - textOffset - topOffset) + 'px'; -}; - -/** - * Set size - * @param {number} width width of the container - * @param {number} height height of the container - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.setSize_ = function(width, height) { - // Minimum size of a comment. - width = Math.max(width, 45); - height = Math.max(height, 20 + Blockly.WorkspaceCommentSvg.TOP_OFFSET); - this.width_ = width; - this.height_ = height; - this.svgRect_.setAttribute('width', width); - this.svgRect_.setAttribute('height', height); - this.svgRectTarget_.setAttribute('width', width); - this.svgRectTarget_.setAttribute('height', height); - this.svgHandleTarget_.setAttribute('width', width); - this.svgHandleTarget_.setAttribute('height', - Blockly.WorkspaceCommentSvg.TOP_OFFSET); - if (this.RTL) { - this.svgRect_.setAttribute('transform', 'scale(-1 1)'); - this.svgRectTarget_.setAttribute('transform', 'scale(-1 1)'); - } - - var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE; - if (this.resizeGroup_) { - if (this.RTL) { - // Mirror the resize group. - this.resizeGroup_.setAttribute('transform', 'translate(' + - (-width + resizeSize) + ',' + (height - resizeSize) + ') scale(-1 1)'); - this.deleteGroup_.setAttribute('transform', 'translate(' + - (-width + resizeSize) + ',' + (-resizeSize) + ') scale(-1 1)'); - } else { - this.resizeGroup_.setAttribute('transform', 'translate(' + - (width - resizeSize) + ',' + - (height - resizeSize) + ')'); - this.deleteGroup_.setAttribute('transform', 'translate(' + - (width - resizeSize) + ',' + - (-resizeSize) + ')'); - } - } - - // Allow the contents to resize. - this.resizeComment_(); -}; - -/** - * Dispose of any rendered comment components. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.disposeInternal_ = function() { - this.textarea_ = null; - this.foreignObject_ = null; - this.svgRectTarget_ = null; - this.svgHandleTarget_ = null; - this.disposed_ = true; -}; - -/** - * Set the focus on the text area. - * @package - */ -Blockly.WorkspaceCommentSvg.prototype.setFocus = function() { - var comment = this; - this.focused_ = true; - // Defer CSS changes. - setTimeout(function() { - if (comment.disposed_) { - return; - } - comment.textarea_.focus(); - comment.addFocus(); - Blockly.utils.dom.addClass( - comment.svgRectTarget_, 'blocklyCommentTargetFocused'); - Blockly.utils.dom.addClass( - comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused'); - }, 0); -}; - -/** - * Remove focus from the text area. - * @package - */ -Blockly.WorkspaceCommentSvg.prototype.blurFocus = function() { - var comment = this; - this.focused_ = false; - // Defer CSS changes. - setTimeout(function() { - if (comment.disposed_) { - return; - } - - comment.textarea_.blur(); - comment.removeFocus(); - Blockly.utils.dom.removeClass( - comment.svgRectTarget_, 'blocklyCommentTargetFocused'); - Blockly.utils.dom.removeClass( - comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused'); - }, 0); -}; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 401b840e1..0b68db82e 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -10,10 +10,32 @@ */ 'use strict'; -goog.provide('Blockly.WorkspaceCommentSvg'); +goog.module('Blockly.WorkspaceCommentSvg'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Css'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg'); +const Blockly = goog.require('Blockly'); +const ContextMenu = goog.require('Blockly.ContextMenu'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +const Css = goog.require('Blockly.Css'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const IBoundedElement = goog.requireType('Blockly.IBoundedElement'); +/* eslint-disable-next-line no-unused-vars */ +const IBubble = goog.requireType('Blockly.IBubble'); +/* eslint-disable-next-line no-unused-vars */ +const ICopyable = goog.requireType('Blockly.ICopyable'); +const Rect = goog.require('Blockly.utils.Rect'); +const Svg = goog.require('Blockly.utils.Svg'); +const Touch = goog.require('Blockly.Touch'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); +const WorkspaceComment = goog.require('Blockly.WorkspaceComment'); +const browserEvents = goog.require('Blockly.browserEvents'); +const dom = goog.require('Blockly.utils.dom'); +const object = goog.require('Blockly.utils.object'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.CommentCreate'); /** @suppress {extraRequire} */ @@ -22,45 +44,60 @@ goog.require('Blockly.Events.CommentDelete'); goog.require('Blockly.Events.CommentMove'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.Selected'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.WorkspaceComment'); - -goog.requireType('Blockly.IBoundedElement'); -goog.requireType('Blockly.IBubble'); -goog.requireType('Blockly.ICopyable'); +/** + * Size of the resize icon. + * @type {number} + * @const + */ +const RESIZE_SIZE = 8; + +/** + * Radius of the border around the comment. + * @type {number} + * @const + */ +const BORDER_RADIUS = 3; + +/** + * Offset from the foreignobject edge to the textarea edge. + * @type {number} + * @const + */ +const TEXTAREA_OFFSET = 2; + /** * Class for a workspace comment's SVG representation. - * @param {!Blockly.Workspace} workspace The block's workspace. + * @param {!WorkspaceSvg} workspace The block's workspace. * @param {string} content The content of this workspace comment. * @param {number} height Height of the comment. * @param {number} width Width of the comment. * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise * create a new ID. - * @extends {Blockly.WorkspaceComment} - * @implements {Blockly.IBoundedElement} - * @implements {Blockly.IBubble} - * @implements {Blockly.ICopyable} + * @extends {WorkspaceComment} + * @implements {IBoundedElement} + * @implements {IBubble} + * @implements {ICopyable} * @constructor */ -Blockly.WorkspaceCommentSvg = function( +const WorkspaceCommentSvg = function( workspace, content, height, width, opt_id) { + /** + * @type {!WorkspaceSvg} + */ + this.workspace; + /** * Mouse up event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ this.onMouseUpWrapper_ = null; /** * Mouse move event data. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ this.onMouseMoveWrapper_ = null; @@ -70,18 +107,17 @@ Blockly.WorkspaceCommentSvg = function( * @type {!SVGElement} * @private */ - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, {'class': 'blocklyComment'}, null); + this.svgGroup_ = + dom.createSvgElement(Svg.G, {'class': 'blocklyComment'}, null); this.svgGroup_.translate_ = ''; - this.svgRect_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, { - 'class': 'blocklyCommentRect', - 'x': 0, - 'y': 0, - 'rx': Blockly.WorkspaceCommentSvg.BORDER_RADIUS, - 'ry': Blockly.WorkspaceCommentSvg.BORDER_RADIUS - }); + this.svgRect_ = dom.createSvgElement(Svg.RECT, { + 'class': 'blocklyCommentRect', + 'x': 0, + 'y': 0, + 'rx': BORDER_RADIUS, + 'ry': BORDER_RADIUS + }); this.svgGroup_.appendChild(this.svgRect_); /** @@ -97,16 +133,14 @@ Blockly.WorkspaceCommentSvg = function( * @type {boolean} * @private */ - this.useDragSurface_ = - Blockly.utils.is3dSupported() && !!workspace.blockDragSurface_; + this.useDragSurface_ = utils.is3dSupported() && !!workspace.getBlockDragSurface(); - Blockly.WorkspaceCommentSvg.superClass_.constructor.call( + WorkspaceCommentSvg.superClass_.constructor.call( this, workspace, content, height, width, opt_id); this.render(); }; -Blockly.utils.object.inherits( - Blockly.WorkspaceCommentSvg, Blockly.WorkspaceComment); +object.inherits(WorkspaceCommentSvg, WorkspaceComment); /** * The width and height to use to size a workspace comment when it is first @@ -114,15 +148,22 @@ Blockly.utils.object.inherits( * @type {number} * @package */ -Blockly.WorkspaceCommentSvg.DEFAULT_SIZE = 100; +WorkspaceCommentSvg.DEFAULT_SIZE = 100; + +/** + * Offset from the top to make room for a top bar. + * @type {number} + * @const + * @private + */ +WorkspaceCommentSvg.TOP_OFFSET = 10; /** * Dispose of this comment. * @package */ -Blockly.WorkspaceCommentSvg.prototype.dispose = function() { - if (!this.workspace) { - // The comment has already been deleted. +WorkspaceCommentSvg.prototype.dispose = function() { + if (this.disposed_) { return; } // If this comment is being dragged, unlink the mouse events. @@ -131,39 +172,36 @@ Blockly.WorkspaceCommentSvg.prototype.dispose = function() { this.workspace.cancelCurrentGesture(); } - if (Blockly.Events.isEnabled()) { - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.COMMENT_DELETE))(this)); + if (Events.isEnabled()) { + Events.fire(new (Events.get(Events.COMMENT_DELETE))(this)); } - Blockly.utils.dom.removeNode(this.svgGroup_); - // Sever JavaScript to DOM connections. - this.svgGroup_ = null; - this.svgRect_ = null; + dom.removeNode(this.svgGroup_); // Dispose of any rendered components this.disposeInternal_(); - Blockly.Events.disable(); - Blockly.WorkspaceCommentSvg.superClass_.dispose.call(this); - Blockly.Events.enable(); + Events.disable(); + WorkspaceCommentSvg.superClass_.dispose.call(this); + Events.enable(); }; /** * Create and initialize the SVG representation of a workspace comment. * May be called more than once. * - * @param {boolean=} opt_noSelect Text inside text area will be selected if false + * @param {boolean=} opt_noSelect Text inside text area will be selected if + * false * * @package */ -Blockly.WorkspaceCommentSvg.prototype.initSvg = function(opt_noSelect) { +WorkspaceCommentSvg.prototype.initSvg = function(opt_noSelect) { if (!this.workspace.rendered) { throw TypeError('Workspace is headless.'); } if (!this.workspace.options.readOnly && !this.eventsInit_) { - Blockly.browserEvents.conditionalBind( + browserEvents.conditionalBind( this.svgRectTarget_, 'mousedown', this, this.pathMouseDown_); - Blockly.browserEvents.conditionalBind( + browserEvents.conditionalBind( this.svgHandleTarget_, 'mousedown', this, this.pathMouseDown_); } this.eventsInit_ = true; @@ -183,8 +221,8 @@ Blockly.WorkspaceCommentSvg.prototype.initSvg = function(opt_noSelect) { * @param {!Event} e Mouse down event or touch start event. * @private */ -Blockly.WorkspaceCommentSvg.prototype.pathMouseDown_ = function(e) { - var gesture = this.workspace.getGesture(e); +WorkspaceCommentSvg.prototype.pathMouseDown_ = function(e) { + const gesture = this.workspace.getGesture(e); if (gesture) { gesture.handleBubbleStart(e, this); } @@ -195,44 +233,44 @@ Blockly.WorkspaceCommentSvg.prototype.pathMouseDown_ = function(e) { * @param {!Event} e Mouse event. * @package */ -Blockly.WorkspaceCommentSvg.prototype.showContextMenu = function(e) { +WorkspaceCommentSvg.prototype.showContextMenu = function(e) { if (this.workspace.options.readOnly) { return; } // Save the current workspace comment in a variable for use in closures. - var comment = this; - var menuOptions = []; + const comment = this; + const menuOptions = []; if (this.isDeletable() && this.isMovable()) { - menuOptions.push(Blockly.ContextMenu.commentDuplicateOption(comment)); - menuOptions.push(Blockly.ContextMenu.commentDeleteOption(comment)); + menuOptions.push(ContextMenu.commentDuplicateOption(comment)); + menuOptions.push(ContextMenu.commentDeleteOption(comment)); } - Blockly.ContextMenu.show(e, menuOptions, this.RTL); + ContextMenu.show(e, menuOptions, this.RTL); }; /** * Select this comment. Highlight it visually. * @package */ -Blockly.WorkspaceCommentSvg.prototype.select = function() { +WorkspaceCommentSvg.prototype.select = function() { if (Blockly.selected == this) { return; } - var oldId = null; + let oldId = null; if (Blockly.selected) { oldId = Blockly.selected.id; // Unselect any previously selected block. - Blockly.Events.disable(); + Events.disable(); try { Blockly.selected.unselect(); } finally { - Blockly.Events.enable(); + Events.enable(); } } - var event = new (Blockly.Events.get(Blockly.Events.SELECTED))(oldId, this.id, - this.workspace.id); - Blockly.Events.fire(event); + const event = + new (Events.get(Events.SELECTED))(oldId, this.id, this.workspace.id); + Events.fire(event); Blockly.selected = this; this.addSelect(); }; @@ -241,13 +279,13 @@ Blockly.WorkspaceCommentSvg.prototype.select = function() { * Unselect this comment. Remove its highlighting. * @package */ -Blockly.WorkspaceCommentSvg.prototype.unselect = function() { +WorkspaceCommentSvg.prototype.unselect = function() { if (Blockly.selected != this) { return; } - var event = new (Blockly.Events.get(Blockly.Events.SELECTED))(this.id, null, - this.workspace.id); - Blockly.Events.fire(event); + const event = + new (Events.get(Events.SELECTED))(this.id, null, this.workspace.id); + Events.fire(event); Blockly.selected = null; this.removeSelect(); this.blurFocus(); @@ -257,8 +295,8 @@ Blockly.WorkspaceCommentSvg.prototype.unselect = function() { * Select this comment. Highlight it visually. * @package */ -Blockly.WorkspaceCommentSvg.prototype.addSelect = function() { - Blockly.utils.dom.addClass( +WorkspaceCommentSvg.prototype.addSelect = function() { + dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); this.setFocus(); }; @@ -267,8 +305,8 @@ Blockly.WorkspaceCommentSvg.prototype.addSelect = function() { * Unselect this comment. Remove its highlighting. * @package */ -Blockly.WorkspaceCommentSvg.prototype.removeSelect = function() { - Blockly.utils.dom.removeClass( +WorkspaceCommentSvg.prototype.removeSelect = function() { + dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); this.blurFocus(); }; @@ -277,8 +315,8 @@ Blockly.WorkspaceCommentSvg.prototype.removeSelect = function() { * Focus this comment. Highlight it visually. * @package */ -Blockly.WorkspaceCommentSvg.prototype.addFocus = function() { - Blockly.utils.dom.addClass( +WorkspaceCommentSvg.prototype.addFocus = function() { + dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyFocused'); }; @@ -286,8 +324,8 @@ Blockly.WorkspaceCommentSvg.prototype.addFocus = function() { * Unfocus this comment. Remove its highlighting. * @package */ -Blockly.WorkspaceCommentSvg.prototype.removeFocus = function() { - Blockly.utils.dom.removeClass( +WorkspaceCommentSvg.prototype.removeFocus = function() { + dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyFocused'); }; @@ -297,30 +335,30 @@ Blockly.WorkspaceCommentSvg.prototype.removeFocus = function() { * If the comment is on the workspace, (0, 0) is the origin of the workspace * coordinate system. * This does not change with workspace scale. - * @return {!Blockly.utils.Coordinate} Object with .x and .y properties in + * @return {!Coordinate} Object with .x and .y properties in * workspace coordinates. * @package */ -Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() { - var x = 0; - var y = 0; +WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() { + let x = 0; + let y = 0; - var dragSurfaceGroup = - this.useDragSurface_ ? this.workspace.blockDragSurface_.getGroup() : null; + const dragSurfaceGroup = + this.useDragSurface_ ? this.workspace.getBlockDragSurface().getGroup() : null; - var element = this.getSvgRoot(); + let element = this.getSvgRoot(); if (element) { do { // Loop through this comment and every parent. - var xy = Blockly.utils.getRelativeXY(element); + const xy = utils.getRelativeXY(/** @type {!Element} */ (element)); x += xy.x; y += xy.y; // If this element is the current element on the drag surface, include // the translation of the drag surface itself. if (this.useDragSurface_ && - this.workspace.blockDragSurface_.getCurrentBlock() == element) { - var surfaceTranslation = - this.workspace.blockDragSurface_.getSurfaceTranslation(); + this.workspace.getBlockDragSurface().getCurrentBlock() == element) { + const surfaceTranslation = + this.workspace.getBlockDragSurface().getSurfaceTranslation(); x += surfaceTranslation.x; y += surfaceTranslation.y; } @@ -328,7 +366,7 @@ Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() { } while (element && element != this.workspace.getBubbleCanvas() && element != dragSurfaceGroup); } - this.xy_ = new Blockly.utils.Coordinate(x, y); + this.xy_ = new Coordinate(x, y); return this.xy_; }; @@ -338,14 +376,14 @@ Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() { * @param {number} dy Vertical offset, in workspace units. * @package */ -Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) { - var event = new (Blockly.Events.get(Blockly.Events.COMMENT_MOVE))(this); +WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) { + const event = new (Events.get(Events.COMMENT_MOVE))(this); // TODO: Do I need to look up the relative to surface XY position here? - var xy = this.getRelativeToSurfaceXY(); + const xy = this.getRelativeToSurfaceXY(); this.translate(xy.x + dx, xy.y + dy); - this.xy_ = new Blockly.utils.Coordinate(xy.x + dx, xy.y + dy); + this.xy_ = new Coordinate(xy.x + dx, xy.y + dy); event.recordNew(); - Blockly.Events.fire(event); + Events.fire(event); this.workspace.resizeContents(); }; @@ -356,8 +394,8 @@ Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) { * @param {number} y The y coordinate of the translation in workspace units. * @package */ -Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) { - this.xy_ = new Blockly.utils.Coordinate(x, y); +WorkspaceCommentSvg.prototype.translate = function(x, y) { + this.xy_ = new Coordinate(x, y); this.getSvgRoot().setAttribute('transform', 'translate(' + x + ',' + y + ')'); }; @@ -367,7 +405,7 @@ Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) { * setDragging(true). Does nothing if useDragSurface_ is false. * @package */ -Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface = function() { +WorkspaceCommentSvg.prototype.moveToDragSurface = function() { if (!this.useDragSurface_) { return; } @@ -375,41 +413,23 @@ Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface = function() { // is equal to the current relative-to-surface position, // to keep the position in sync as it move on/off the surface. // This is in workspace coordinates. - var xy = this.getRelativeToSurfaceXY(); + const xy = this.getRelativeToSurfaceXY(); this.clearTransformAttributes_(); - this.workspace.blockDragSurface_.translateSurface(xy.x, xy.y); + this.workspace.getBlockDragSurface().translateSurface(xy.x, xy.y); // Execute the move on the top-level SVG component - this.workspace.blockDragSurface_.setBlocksAndShow(this.getSvgRoot()); -}; - -/** - * Move this comment back to the workspace block canvas. - * Generally should be called at the same time as setDragging(false). - * Does nothing if useDragSurface_ is false. - * @param {!Blockly.utils.Coordinate} newXY The position the comment should take - * on on the workspace canvas, in workspace coordinates. - * @private - */ -Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface = function(newXY) { - if (!this.useDragSurface_) { - return; - } - // Translate to current position, turning off 3d. - this.translate(newXY.x, newXY.y); - this.workspace.blockDragSurface_.clearAndHide(this.workspace.getCanvas()); + this.workspace.getBlockDragSurface().setBlocksAndShow(this.getSvgRoot()); }; /** * Move this comment during a drag, taking into account whether we are using a * drag surface to translate blocks. - * @param {Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries + * @param {BlockDragSurfaceSvg} dragSurface The surface that carries * rendered items during a drag, or null if no drag surface is in use. - * @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in + * @param {!Coordinate} newLoc The location to translate to, in * workspace coordinates. * @package */ -Blockly.WorkspaceCommentSvg.prototype.moveDuringDrag = function( - dragSurface, newLoc) { +WorkspaceCommentSvg.prototype.moveDuringDrag = function(dragSurface, newLoc) { if (dragSurface) { dragSurface.translateSurface(newLoc.x, newLoc.y); } else { @@ -425,7 +445,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveDuringDrag = function( * @param {number} y The y position to move to. * @package */ -Blockly.WorkspaceCommentSvg.prototype.moveTo = function(x, y) { +WorkspaceCommentSvg.prototype.moveTo = function(x, y) { this.translate(x, y); }; @@ -434,7 +454,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveTo = function(x, y) { * Used when the comment is switching from 3d to 2d transform or vice versa. * @private */ -Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { +WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { this.getSvgRoot().removeAttribute('transform'); }; @@ -442,15 +462,16 @@ Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { * Returns the coordinates of a bounding box describing the dimensions of this * comment. * Coordinate system: workspace coordinates. - * @return {!Blockly.utils.Rect} Object with coordinates of the bounding box. + * @return {!Rect} Object with coordinates of the bounding box. * @package */ -Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { - var blockXY = this.getRelativeToSurfaceXY(); - var commentBounds = this.getHeightWidth(); - var top = blockXY.y; - var bottom = blockXY.y + commentBounds.height; - var left, right; +WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { + const blockXY = this.getRelativeToSurfaceXY(); + const commentBounds = this.getHeightWidth(); + const top = blockXY.y; + const bottom = blockXY.y + commentBounds.height; + let left; + let right; if (this.RTL) { left = blockXY.x - commentBounds.width; // Add the width of the tab/puzzle piece knob to the x coordinate @@ -462,19 +483,19 @@ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { left = blockXY.x; right = blockXY.x + commentBounds.width; } - return new Blockly.utils.Rect(top, bottom, left, right); + return new Rect(top, bottom, left, right); }; /** * Add or remove the UI indicating if this comment is movable or not. * @package */ -Blockly.WorkspaceCommentSvg.prototype.updateMovable = function() { +WorkspaceCommentSvg.prototype.updateMovable = function() { if (this.isMovable()) { - Blockly.utils.dom.addClass( + dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } else { - Blockly.utils.dom.removeClass( + dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } }; @@ -484,8 +505,8 @@ Blockly.WorkspaceCommentSvg.prototype.updateMovable = function() { * @param {boolean} movable True if movable. * @package */ -Blockly.WorkspaceCommentSvg.prototype.setMovable = function(movable) { - Blockly.WorkspaceCommentSvg.superClass_.setMovable.call(this, movable); +WorkspaceCommentSvg.prototype.setMovable = function(movable) { + WorkspaceCommentSvg.superClass_.setMovable.call(this, movable); this.updateMovable(); }; @@ -493,8 +514,8 @@ Blockly.WorkspaceCommentSvg.prototype.setMovable = function(movable) { * Set whether this comment is editable or not. * @param {boolean} editable True if editable. */ -Blockly.WorkspaceCommentSvg.prototype.setEditable = function(editable) { - Blockly.WorkspaceCommentSvg.superClass_.setEditable.call(this, editable); +WorkspaceCommentSvg.prototype.setEditable = function(editable) { + WorkspaceCommentSvg.superClass_.setEditable.call(this, editable); if (this.textarea_) { this.textarea_.readOnly = !editable; } @@ -505,15 +526,15 @@ Blockly.WorkspaceCommentSvg.prototype.setEditable = function(editable) { * @param {boolean} adding True if adding, false if removing. * @package */ -Blockly.WorkspaceCommentSvg.prototype.setDragging = function(adding) { +WorkspaceCommentSvg.prototype.setDragging = function(adding) { if (adding) { - var group = this.getSvgRoot(); + const group = this.getSvgRoot(); group.translate_ = ''; group.skew_ = ''; - Blockly.utils.dom.addClass( + dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } else { - Blockly.utils.dom.removeClass( + dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } }; @@ -523,7 +544,7 @@ Blockly.WorkspaceCommentSvg.prototype.setDragging = function(adding) { * @return {!SVGElement} The root SVG node (probably a group). * @package */ -Blockly.WorkspaceCommentSvg.prototype.getSvgRoot = function() { +WorkspaceCommentSvg.prototype.getSvgRoot = function() { return this.svgGroup_; }; @@ -532,7 +553,7 @@ Blockly.WorkspaceCommentSvg.prototype.getSvgRoot = function() { * @return {string} Comment text. * @package */ -Blockly.WorkspaceCommentSvg.prototype.getContent = function() { +WorkspaceCommentSvg.prototype.getContent = function() { return this.textarea_ ? this.textarea_.value : this.content_; }; @@ -541,8 +562,8 @@ Blockly.WorkspaceCommentSvg.prototype.getContent = function() { * @param {string} content Comment content. * @package */ -Blockly.WorkspaceCommentSvg.prototype.setContent = function(content) { - Blockly.WorkspaceCommentSvg.superClass_.setContent.call(this, content); +WorkspaceCommentSvg.prototype.setContent = function(content) { + WorkspaceCommentSvg.superClass_.setContent.call(this, content); if (this.textarea_) { this.textarea_.value = content; } @@ -554,12 +575,12 @@ Blockly.WorkspaceCommentSvg.prototype.setContent = function(content) { * otherwise. * @package */ -Blockly.WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) { +WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) { if (enable) { - Blockly.utils.dom.addClass( + dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete'); } else { - Blockly.utils.dom.removeClass( + dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete'); } }; @@ -572,47 +593,48 @@ Blockly.WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) { * otherwise. * @package */ -Blockly.WorkspaceCommentSvg.prototype.setAutoLayout = function(_enable) { +WorkspaceCommentSvg.prototype.setAutoLayout = function(_enable) { // NOP for compatibility with the bubble dragger. }; /** * Decode an XML comment tag and create a rendered comment on the workspace. * @param {!Element} xmlComment XML comment element. - * @param {!Blockly.Workspace} workspace The workspace. + * @param {!WorkspaceSvg} workspace The workspace. * @param {number=} opt_wsWidth The width of the workspace, which is used to * position comments correctly in RTL. - * @return {!Blockly.WorkspaceCommentSvg} The created workspace comment. + * @return {!WorkspaceCommentSvg} The created workspace comment. * @package */ -Blockly.WorkspaceCommentSvg.fromXml = function( - xmlComment, workspace, opt_wsWidth) { - Blockly.Events.disable(); +WorkspaceCommentSvg.fromXml = function(xmlComment, workspace, opt_wsWidth) { + Events.disable(); + let comment; try { - var info = Blockly.WorkspaceComment.parseAttributes(xmlComment); + const info = WorkspaceComment.parseAttributes(xmlComment); - var comment = new Blockly.WorkspaceCommentSvg( + comment = new WorkspaceCommentSvg( workspace, info.content, info.h, info.w, info.id); if (workspace.rendered) { comment.initSvg(true); - comment.render(false); + comment.render(); } // Position the comment correctly, taking into account the width of a // rendered RTL workspace. if (!isNaN(info.x) && !isNaN(info.y)) { if (workspace.RTL) { - var wsWidth = opt_wsWidth || workspace.getWidth(); + const wsWidth = opt_wsWidth || workspace.getWidth(); comment.moveBy(wsWidth - info.x, info.y); } else { comment.moveBy(info.x, info.y); } } } finally { - Blockly.Events.enable(); + Events.enable(); } - Blockly.WorkspaceComment.fireCreateEvent(comment); - return comment; + WorkspaceComment.fireCreateEvent( + /** @type {!WorkspaceCommentSvg} */ (comment)); + return (/** @type {!WorkspaceCommentSvg} */ (comment)); }; /** @@ -621,14 +643,14 @@ Blockly.WorkspaceCommentSvg.fromXml = function( * @return {!Element} Tree of XML elements. * @package */ -Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) { - var width; // Not used in LTR. +WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) { + let width; // Not used in LTR. if (this.workspace.RTL) { // Here be performance dragons: This calls getMetrics(). width = this.workspace.getWidth(); } - var element = this.toXml(opt_noId); - var xy = this.getRelativeToSurfaceXY(); + const element = this.toXml(opt_noId); + const xy = this.getRelativeToSurfaceXY(); element.setAttribute( 'x', Math.round(this.workspace.RTL ? width - xy.x : xy.x)); element.setAttribute('y', Math.round(xy.y)); @@ -639,17 +661,416 @@ Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) { /** * Encode a comment for copying. - * @return {!Blockly.ICopyable.CopyData} Copy metadata. + * @return {!ICopyable.CopyData} Copy metadata. * @package */ -Blockly.WorkspaceCommentSvg.prototype.toCopyData = function() { +WorkspaceCommentSvg.prototype.toCopyData = function() { return {xml: this.toXmlWithXY(), source: this.workspace, typeCounts: null}; }; +/** + * Returns a bounding box describing the dimensions of this comment. + * @return {!{height: number, width: number}} Object with height and width + * properties in workspace units. + * @package + */ +WorkspaceCommentSvg.prototype.getHeightWidth = function() { + return {width: this.getWidth(), height: this.getHeight()}; +}; + +/** + * Renders the workspace comment. + * @package + */ +WorkspaceCommentSvg.prototype.render = function() { + if (this.rendered_) { + return; + } + + const size = this.getHeightWidth(); + + // Add text area + this.createEditor_(); + this.svgGroup_.appendChild(this.foreignObject_); + + this.svgHandleTarget_ = dom.createSvgElement( + Svg.RECT, {'class': 'blocklyCommentHandleTarget', 'x': 0, 'y': 0}); + this.svgGroup_.appendChild(this.svgHandleTarget_); + this.svgRectTarget_ = dom.createSvgElement(Svg.RECT, { + 'class': 'blocklyCommentTarget', + 'x': 0, + 'y': 0, + 'rx': BORDER_RADIUS, + 'ry': BORDER_RADIUS + }); + this.svgGroup_.appendChild(this.svgRectTarget_); + + // Add the resize icon + this.addResizeDom_(); + if (this.isDeletable()) { + // Add the delete icon + this.addDeleteDom_(); + } + + this.setSize_(size.width, size.height); + + // Set the content + this.textarea_.value = this.content_; + + this.rendered_ = true; + + if (this.resizeGroup_) { + browserEvents.conditionalBind( + this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); + } + + if (this.isDeletable()) { + browserEvents.conditionalBind( + this.deleteGroup_, 'mousedown', this, this.deleteMouseDown_); + browserEvents.conditionalBind( + this.deleteGroup_, 'mouseout', this, this.deleteMouseOut_); + browserEvents.conditionalBind( + this.deleteGroup_, 'mouseup', this, this.deleteMouseUp_); + } +}; + +/** + * Create the text area for the comment. + * @return {!Element} The top-level node of the editor. + * @private + */ +WorkspaceCommentSvg.prototype.createEditor_ = function() { + /* Create the editor. Here's the markup that will be generated: + + + + */ + this.foreignObject_ = dom.createSvgElement( + Svg.FOREIGNOBJECT, { + 'x': 0, + 'y': WorkspaceCommentSvg.TOP_OFFSET, + 'class': 'blocklyCommentForeignObject' + }, + null); + const body = document.createElementNS(dom.HTML_NS, 'body'); + body.setAttribute('xmlns', dom.HTML_NS); + body.className = 'blocklyMinimalBody'; + const textarea = document.createElementNS(dom.HTML_NS, 'textarea'); + textarea.className = 'blocklyCommentTextarea'; + textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR'); + textarea.readOnly = !this.isEditable(); + body.appendChild(textarea); + this.textarea_ = textarea; + this.foreignObject_.appendChild(body); + // Don't zoom with mousewheel. + browserEvents.conditionalBind(textarea, 'wheel', this, function(e) { + e.stopPropagation(); + }); + browserEvents.conditionalBind( + textarea, 'change', this, + function( + /* eslint-disable no-unused-vars */ e + /* eslint-enable no-unused-vars */) { + this.setContent(textarea.value); + }); + return this.foreignObject_; +}; + +/** + * Add the resize icon to the DOM + * @private + */ +WorkspaceCommentSvg.prototype.addResizeDom_ = function() { + this.resizeGroup_ = dom.createSvgElement( + Svg.G, {'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, + this.svgGroup_); + dom.createSvgElement( + Svg.POLYGON, + {'points': '0,x x,x x,0'.replace(/x/g, RESIZE_SIZE.toString())}, + this.resizeGroup_); + dom.createSvgElement( + Svg.LINE, { + 'class': 'blocklyResizeLine', + 'x1': RESIZE_SIZE / 3, + 'y1': RESIZE_SIZE - 1, + 'x2': RESIZE_SIZE - 1, + 'y2': RESIZE_SIZE / 3 + }, + this.resizeGroup_); + dom.createSvgElement( + Svg.LINE, { + 'class': 'blocklyResizeLine', + 'x1': RESIZE_SIZE * 2 / 3, + 'y1': RESIZE_SIZE - 1, + 'x2': RESIZE_SIZE - 1, + 'y2': RESIZE_SIZE * 2 / 3 + }, + this.resizeGroup_); +}; + +/** + * Add the delete icon to the DOM + * @private + */ +WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { + this.deleteGroup_ = dom.createSvgElement( + Svg.G, {'class': 'blocklyCommentDeleteIcon'}, this.svgGroup_); + this.deleteIconBorder_ = dom.createSvgElement( + Svg.CIRCLE, + {'class': 'blocklyDeleteIconShape', 'r': '7', 'cx': '7.5', 'cy': '7.5'}, + this.deleteGroup_); + // x icon. + dom.createSvgElement( + Svg.LINE, { + 'x1': '5', + 'y1': '10', + 'x2': '10', + 'y2': '5', + 'stroke': '#fff', + 'stroke-width': '2' + }, + this.deleteGroup_); + dom.createSvgElement( + Svg.LINE, { + 'x1': '5', + 'y1': '5', + 'x2': '10', + 'y2': '10', + 'stroke': '#fff', + 'stroke-width': '2' + }, + this.deleteGroup_); +}; + +/** + * Handle a mouse-down on comment's resize corner. + * @param {!Event} e Mouse down event. + * @private + */ +WorkspaceCommentSvg.prototype.resizeMouseDown_ = function(e) { + this.unbindDragEvents_(); + if (utils.isRightButton(e)) { + // No right-click. + e.stopPropagation(); + return; + } + // Left-click (or middle click) + this.workspace.startDrag( + e, + new Coordinate( + this.workspace.RTL ? -this.width_ : this.width_, this.height_)); + + this.onMouseUpWrapper_ = browserEvents.conditionalBind( + document, 'mouseup', this, this.resizeMouseUp_); + this.onMouseMoveWrapper_ = browserEvents.conditionalBind( + document, 'mousemove', this, this.resizeMouseMove_); + Blockly.hideChaff(); + // This event has been handled. No need to bubble up to the document. + e.stopPropagation(); +}; + +/** + * Handle a mouse-down on comment's delete icon. + * @param {!Event} e Mouse down event. + * @private + */ +WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) { + // Highlight the delete icon. + dom.addClass( + /** @type {!Element} */ (this.deleteIconBorder_), + 'blocklyDeleteIconHighlighted'); + // This event has been handled. No need to bubble up to the document. + e.stopPropagation(); +}; + +/** + * Handle a mouse-out on comment's delete icon. + * @param {!Event} _e Mouse out event. + * @private + */ +WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(_e) { + // Restore highlight on the delete icon. + dom.removeClass( + /** @type {!Element} */ (this.deleteIconBorder_), + 'blocklyDeleteIconHighlighted'); +}; + +/** + * Handle a mouse-up on comment's delete icon. + * @param {!Event} e Mouse up event. + * @private + */ +WorkspaceCommentSvg.prototype.deleteMouseUp_ = function(e) { + // Delete this comment. + this.dispose(); + // This event has been handled. No need to bubble up to the document. + e.stopPropagation(); +}; + +/** + * Stop binding to the global mouseup and mousemove events. + * @private + */ +WorkspaceCommentSvg.prototype.unbindDragEvents_ = function() { + if (this.onMouseUpWrapper_) { + browserEvents.unbind(this.onMouseUpWrapper_); + this.onMouseUpWrapper_ = null; + } + if (this.onMouseMoveWrapper_) { + browserEvents.unbind(this.onMouseMoveWrapper_); + this.onMouseMoveWrapper_ = null; + } +}; + +/** + * Handle a mouse-up event while dragging a comment's border or resize handle. + * @param {!Event} _e Mouse up event. + * @private + */ +WorkspaceCommentSvg.prototype.resizeMouseUp_ = function(_e) { + Touch.clearTouchIdentifier(); + this.unbindDragEvents_(); +}; + +/** + * Resize this comment to follow the mouse. + * @param {!Event} e Mouse move event. + * @private + */ +WorkspaceCommentSvg.prototype.resizeMouseMove_ = function(e) { + this.autoLayout_ = false; + const newXY = this.workspace.moveDrag(e); + this.setSize_(this.RTL ? -newXY.x : newXY.x, newXY.y); +}; + +/** + * Callback function triggered when the comment has resized. + * Resize the text area accordingly. + * @private + */ +WorkspaceCommentSvg.prototype.resizeComment_ = function() { + const size = this.getHeightWidth(); + const topOffset = WorkspaceCommentSvg.TOP_OFFSET; + const textOffset = TEXTAREA_OFFSET * 2; + + this.foreignObject_.setAttribute('width', size.width); + this.foreignObject_.setAttribute('height', size.height - topOffset); + if (this.RTL) { + this.foreignObject_.setAttribute('x', -size.width); + } + this.textarea_.style.width = (size.width - textOffset) + 'px'; + this.textarea_.style.height = (size.height - textOffset - topOffset) + 'px'; +}; + +/** + * Set size + * @param {number} width width of the container + * @param {number} height height of the container + * @private + */ +WorkspaceCommentSvg.prototype.setSize_ = function(width, height) { + // Minimum size of a comment. + width = Math.max(width, 45); + height = Math.max(height, 20 + WorkspaceCommentSvg.TOP_OFFSET); + this.width_ = width; + this.height_ = height; + this.svgRect_.setAttribute('width', width); + this.svgRect_.setAttribute('height', height); + this.svgRectTarget_.setAttribute('width', width); + this.svgRectTarget_.setAttribute('height', height); + this.svgHandleTarget_.setAttribute('width', width); + this.svgHandleTarget_.setAttribute('height', WorkspaceCommentSvg.TOP_OFFSET); + if (this.RTL) { + this.svgRect_.setAttribute('transform', 'scale(-1 1)'); + this.svgRectTarget_.setAttribute('transform', 'scale(-1 1)'); + } + + if (this.resizeGroup_) { + if (this.RTL) { + // Mirror the resize group. + this.resizeGroup_.setAttribute( + 'transform', + 'translate(' + (-width + RESIZE_SIZE) + ',' + (height - RESIZE_SIZE) + + ') scale(-1 1)'); + this.deleteGroup_.setAttribute( + 'transform', + 'translate(' + (-width + RESIZE_SIZE) + ',' + (-RESIZE_SIZE) + + ') scale(-1 1)'); + } else { + this.resizeGroup_.setAttribute( + 'transform', + 'translate(' + (width - RESIZE_SIZE) + ',' + (height - RESIZE_SIZE) + + ')'); + this.deleteGroup_.setAttribute( + 'transform', + 'translate(' + (width - RESIZE_SIZE) + ',' + (-RESIZE_SIZE) + ')'); + } + } + + // Allow the contents to resize. + this.resizeComment_(); +}; + +/** + * Dispose of any rendered comment components. + * @private + */ +WorkspaceCommentSvg.prototype.disposeInternal_ = function() { + this.textarea_ = null; + this.foreignObject_ = null; + this.svgRectTarget_ = null; + this.svgHandleTarget_ = null; + this.disposed_ = true; +}; + +/** + * Set the focus on the text area. + * @package + */ +WorkspaceCommentSvg.prototype.setFocus = function() { + const comment = this; + this.focused_ = true; + // Defer CSS changes. + setTimeout(function() { + if (comment.disposed_) { + return; + } + comment.textarea_.focus(); + comment.addFocus(); + dom.addClass(comment.svgRectTarget_, 'blocklyCommentTargetFocused'); + dom.addClass(comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused'); + }, 0); +}; + +/** + * Remove focus from the text area. + * @package + */ +WorkspaceCommentSvg.prototype.blurFocus = function() { + const comment = this; + this.focused_ = false; + // Defer CSS changes. + setTimeout(function() { + if (comment.disposed_) { + return; + } + + comment.textarea_.blur(); + comment.removeFocus(); + dom.removeClass(comment.svgRectTarget_, 'blocklyCommentTargetFocused'); + dom.removeClass( + comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused'); + }, 0); +}; + /** * CSS for workspace comment. See css.js for use. */ -Blockly.Css.register([ +Css.register([ // clang-format off /* eslint-disable indent */ '.blocklyCommentForeignObject {', @@ -712,3 +1133,5 @@ Blockly.Css.register([ /* eslint-enable indent */ // clang-format on ]); + +exports = WorkspaceCommentSvg; diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index cef1f7921..8cffb37d6 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -14,13 +14,14 @@ 'use strict'; -goog.provide('Blockly.WorkspaceDragSurfaceSvg'); +goog.module('Blockly.WorkspaceDragSurfaceSvg'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Svg'); - -goog.requireType('Blockly.utils.Coordinate'); +/* eslint-disable-next-line no-unused-vars */ +const Coordinate = goog.requireType('Blockly.utils.Coordinate'); +const Svg = goog.require('Blockly.utils.Svg'); +const dom = goog.require('Blockly.utils.dom'); +const utils = goog.require('Blockly.utils'); /** @@ -30,50 +31,50 @@ goog.requireType('Blockly.utils.Coordinate'); * @param {!Element} container Containing element. * @constructor */ -Blockly.WorkspaceDragSurfaceSvg = function(container) { +const WorkspaceDragSurfaceSvg = function(container) { this.container_ = container; this.createDom(); }; /** - * The SVG drag surface. Set once by Blockly.WorkspaceDragSurfaceSvg.createDom. + * The SVG drag surface. Set once by WorkspaceDragSurfaceSvg.createDom. * @type {SVGElement} * @private */ -Blockly.WorkspaceDragSurfaceSvg.prototype.SVG_ = null; +WorkspaceDragSurfaceSvg.prototype.SVG_ = null; /** * Containing HTML element; parent of the workspace and the drag surface. * @type {Element} * @private */ -Blockly.WorkspaceDragSurfaceSvg.prototype.container_ = null; +WorkspaceDragSurfaceSvg.prototype.container_ = null; /** * Create the drag surface and inject it into the container. */ -Blockly.WorkspaceDragSurfaceSvg.prototype.createDom = function() { +WorkspaceDragSurfaceSvg.prototype.createDom = function() { if (this.SVG_) { return; // Already created. } /** - * Dom structure when the workspace is being dragged. If there is no drag in - * progress, the SVG is empty and display: none. - * - * - * /g> - * - */ - this.SVG_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.SVG, - { - 'xmlns': Blockly.utils.dom.SVG_NS, - 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, + * Dom structure when the workspace is being dragged. If there is no drag in + * progress, the SVG is empty and display: none. + * + * + * /g> + * + */ + this.SVG_ = dom.createSvgElement( + Svg.SVG, { + 'xmlns': dom.SVG_NS, + 'xmlns:html': dom.HTML_NS, + 'xmlns:xlink': dom.XLINK_NS, 'version': '1.1', 'class': 'blocklyWsDragSurface blocklyOverflowVisible' - }, null); + }, + null); this.container_.appendChild(this.SVG_); }; @@ -86,25 +87,25 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.createDom = function() { * @param {number} y Y translation for the entire surface * @package */ -Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) { +WorkspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) { // This is a work-around to prevent a the blocks from rendering // fuzzy while they are being moved on the drag surface. - var fixedX = x.toFixed(0); - var fixedY = y.toFixed(0); + const fixedX = x.toFixed(0); + const fixedY = y.toFixed(0); this.SVG_.style.display = 'block'; - Blockly.utils.dom.setCssTransform( + dom.setCssTransform( this.SVG_, 'translate3d(' + fixedX + 'px, ' + fixedY + 'px, 0)'); }; /** * Reports the surface translation in scaled workspace coordinates. * Use this when finishing a drag to return blocks to the correct position. - * @return {!Blockly.utils.Coordinate} Current translation of the surface + * @return {!Coordinate} Current translation of the surface * @package */ -Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() { - return Blockly.utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); +WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() { + return utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); }; /** @@ -114,36 +115,36 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() { * into. * @package */ -Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { +WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { if (!newSurface) { - throw Error('Couldn\'t clear and hide the drag surface: missing ' + - 'new surface.'); + throw Error( + 'Couldn\'t clear and hide the drag surface: missing new surface.'); } - var blockCanvas = /** @type {!Element} */ (this.SVG_.childNodes[0]); - var bubbleCanvas = /** @type {!Element} */ (this.SVG_.childNodes[1]); + const blockCanvas = /** @type {!Element} */ (this.SVG_.childNodes[0]); + const bubbleCanvas = /** @type {!Element} */ (this.SVG_.childNodes[1]); if (!blockCanvas || !bubbleCanvas || - !Blockly.utils.dom.hasClass(blockCanvas, 'blocklyBlockCanvas') || - !Blockly.utils.dom.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) { - throw Error('Couldn\'t clear and hide the drag surface. ' + - 'A node was missing.'); + !dom.hasClass(blockCanvas, 'blocklyBlockCanvas') || + !dom.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) { + throw Error( + 'Couldn\'t clear and hide the drag surface. A node was missing.'); } // If there is a previous sibling, put the blockCanvas back right afterwards, // otherwise insert it as the first child node in newSurface. if (this.previousSibling_ != null) { - Blockly.utils.dom.insertAfter(blockCanvas, this.previousSibling_); + dom.insertAfter(blockCanvas, this.previousSibling_); } else { newSurface.insertBefore(blockCanvas, newSurface.firstChild); } // Reattach the bubble canvas after the blockCanvas. - Blockly.utils.dom.insertAfter(bubbleCanvas, blockCanvas); + dom.insertAfter(bubbleCanvas, blockCanvas); // Hide the drag surface. this.SVG_.style.display = 'none'; if (this.SVG_.childNodes.length) { throw Error('Drag surface was not cleared.'); } - Blockly.utils.dom.setCssTransform(this.SVG_, ''); + dom.setCssTransform(this.SVG_, ''); this.previousSibling_ = null; }; @@ -160,7 +161,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { * @param {number} scale The scale of the workspace being dragged. * @package */ -Blockly.WorkspaceDragSurfaceSvg.prototype.setContentsAndShow = function( +WorkspaceDragSurfaceSvg.prototype.setContentsAndShow = function( blockCanvas, bubbleCanvas, previousSibling, width, height, scale) { if (this.SVG_.childNodes.length) { throw Error('Already dragging a block.'); @@ -176,3 +177,5 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.setContentsAndShow = function( this.SVG_.appendChild(bubbleCanvas); this.SVG_.style.display = 'block'; }; + +exports = WorkspaceDragSurfaceSvg; diff --git a/core/workspace_dragger.js b/core/workspace_dragger.js index 3ad07a20e..0b056a3f3 100644 --- a/core/workspace_dragger.js +++ b/core/workspace_dragger.js @@ -10,11 +10,14 @@ */ 'use strict'; -goog.provide('Blockly.WorkspaceDragger'); +goog.module('Blockly.WorkspaceDragger'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.utils.Coordinate'); - -goog.requireType('Blockly.WorkspaceSvg'); +// TODO(#5073): Add Blockly require after fixing circular dependency. +// goog.require('Blockly'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); /** @@ -23,12 +26,12 @@ goog.requireType('Blockly.WorkspaceSvg'); * Note that the workspace itself manages whether or not it has a drag surface * and how to do translations based on that. This simply passes the right * commands based on events. - * @param {!Blockly.WorkspaceSvg} workspace The workspace to drag. + * @param {!WorkspaceSvg} workspace The workspace to drag. * @constructor */ -Blockly.WorkspaceDragger = function(workspace) { +const WorkspaceDragger = function(workspace) { /** - * @type {!Blockly.WorkspaceSvg} + * @type {!WorkspaceSvg} * @private */ this.workspace_ = workspace; @@ -50,11 +53,10 @@ Blockly.WorkspaceDragger = function(workspace) { /** * The scroll position of the workspace at the beginning of the drag. * Coordinate system: pixel coordinates. - * @type {!Blockly.utils.Coordinate} + * @type {!Coordinate} * @protected */ - this.startScrollXY_ = new Blockly.utils.Coordinate( - workspace.scrollX, workspace.scrollY); + this.startScrollXY_ = new Coordinate(workspace.scrollX, workspace.scrollY); }; /** @@ -62,7 +64,7 @@ Blockly.WorkspaceDragger = function(workspace) { * @package * @suppress {checkTypes} */ -Blockly.WorkspaceDragger.prototype.dispose = function() { +WorkspaceDragger.prototype.dispose = function() { this.workspace_ = null; }; @@ -70,7 +72,7 @@ Blockly.WorkspaceDragger.prototype.dispose = function() { * Start dragging the workspace. * @package */ -Blockly.WorkspaceDragger.prototype.startDrag = function() { +WorkspaceDragger.prototype.startDrag = function() { if (Blockly.selected) { Blockly.selected.unselect(); } @@ -79,11 +81,11 @@ Blockly.WorkspaceDragger.prototype.startDrag = function() { /** * Finish dragging the workspace and put everything back where it belongs. - * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel coordinates. * @package */ -Blockly.WorkspaceDragger.prototype.endDrag = function(currentDragDeltaXY) { +WorkspaceDragger.prototype.endDrag = function(currentDragDeltaXY) { // Make sure everything is up to date. this.drag(currentDragDeltaXY); this.workspace_.resetDragSurface(); @@ -91,12 +93,12 @@ Blockly.WorkspaceDragger.prototype.endDrag = function(currentDragDeltaXY) { /** * Move the workspace based on the most recent mouse movements. - * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel coordinates. * @package */ -Blockly.WorkspaceDragger.prototype.drag = function(currentDragDeltaXY) { - var newXY = Blockly.utils.Coordinate.sum(this.startScrollXY_, currentDragDeltaXY); +WorkspaceDragger.prototype.drag = function(currentDragDeltaXY) { + const newXY = Coordinate.sum(this.startScrollXY_, currentDragDeltaXY); if (this.horizontalScrollEnabled_ && this.verticalScrollEnabled_) { this.workspace_.scroll(newXY.x, newXY.y); @@ -108,3 +110,5 @@ Blockly.WorkspaceDragger.prototype.drag = function(currentDragDeltaXY) { throw new TypeError('Invalid state.'); } }; + +exports = WorkspaceDragger; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 1c3cee44f..419879bad 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -10,96 +10,128 @@ */ 'use strict'; -goog.provide('Blockly.WorkspaceSvg'); +goog.module('Blockly.WorkspaceSvg'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.blockRendering'); -goog.require('Blockly.BlockSvg'); -goog.require('Blockly.browserEvents'); -goog.require('Blockly.ComponentManager'); -goog.require('Blockly.ConnectionDB'); -goog.require('Blockly.ContextMenu'); -goog.require('Blockly.ContextMenuRegistry'); -goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg'); +const BlockSvg = goog.require('Blockly.BlockSvg'); +/* eslint-disable-next-line no-unused-vars */ +const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions'); +const Classic = goog.require('Blockly.Themes.Classic'); +const ComponentManager = goog.require('Blockly.ComponentManager'); +const ConnectionDB = goog.require('Blockly.ConnectionDB'); +const ContextMenu = goog.require('Blockly.ContextMenu'); +const ContextMenuRegistry = goog.require('Blockly.ContextMenuRegistry'); +const Coordinate = goog.require('Blockly.utils.Coordinate'); +/* eslint-disable-next-line no-unused-vars */ +const Cursor = goog.requireType('Blockly.Cursor'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const FlyoutButton = goog.requireType('Blockly.FlyoutButton'); +const Gesture = goog.require('Blockly.Gesture'); +const Grid = goog.require('Blockly.Grid'); +/* eslint-disable-next-line no-unused-vars */ +const IASTNodeLocationSvg = goog.requireType('Blockly.IASTNodeLocationSvg'); +/* eslint-disable-next-line no-unused-vars */ +const IBoundedElement = goog.requireType('Blockly.IBoundedElement'); +/* eslint-disable-next-line no-unused-vars */ +const IDragTarget = goog.requireType('Blockly.IDragTarget'); +/* eslint-disable-next-line no-unused-vars */ +const IFlyout = goog.requireType('Blockly.IFlyout'); +/* eslint-disable-next-line no-unused-vars */ +const IMetricsManager = goog.requireType('Blockly.IMetricsManager'); +/* eslint-disable-next-line no-unused-vars */ +const IToolbox = goog.requireType('Blockly.IToolbox'); +/* eslint-disable-next-line no-unused-vars */ +const Marker = goog.requireType('Blockly.Marker'); +const MarkerManager = goog.require('Blockly.MarkerManager'); +/* eslint-disable-next-line no-unused-vars */ +const Metrics = goog.requireType('Blockly.utils.Metrics'); +const Options = goog.require('Blockly.Options'); +/* eslint-disable-next-line no-unused-vars */ +const Procedures = goog.requireType('Blockly.Procedures'); +const Rect = goog.require('Blockly.utils.Rect'); +/* eslint-disable-next-line no-unused-vars */ +const Renderer = goog.requireType('Blockly.blockRendering.Renderer'); +/* eslint-disable-next-line no-unused-vars */ +const ScrollbarPair = goog.requireType('Blockly.ScrollbarPair'); +const Size = goog.require('Blockly.utils.Size'); +const Svg = goog.require('Blockly.utils.Svg'); +/* eslint-disable-next-line no-unused-vars */ +const Theme = goog.requireType('Blockly.Theme'); +const ThemeManager = goog.require('Blockly.ThemeManager'); +const TouchGesture = goog.require('Blockly.TouchGesture'); +/* eslint-disable-next-line no-unused-vars */ +const Trashcan = goog.requireType('Blockly.Trashcan'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +/* eslint-disable-next-line no-unused-vars */ +const Variables = goog.requireType('Blockly.Variables'); +/* eslint-disable-next-line no-unused-vars */ +const VariablesDynamic = goog.requireType('Blockly.VariablesDynamic'); +const Workspace = goog.require('Blockly.Workspace'); +const WorkspaceAudio = goog.require('Blockly.WorkspaceAudio'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceComment = goog.requireType('Blockly.WorkspaceComment'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceCommentSvg = goog.requireType('Blockly.WorkspaceCommentSvg'); +/* eslint-disable-next-line no-unused-vars */ +const WorkspaceDragSurfaceSvg = goog.requireType('Blockly.WorkspaceDragSurfaceSvg'); +const Xml = goog.require('Blockly.Xml'); +/* eslint-disable-next-line no-unused-vars */ +const ZoomControls = goog.requireType('Blockly.ZoomControls'); +const blockRendering = goog.require('Blockly.blockRendering'); +const browserEvents = goog.require('Blockly.browserEvents'); +const common = goog.require('Blockly.common'); +const dom = goog.require('Blockly.utils.dom'); +const internalConstants = goog.require('Blockly.internalConstants'); +const object = goog.require('Blockly.utils.object'); +const registry = goog.require('Blockly.registry'); +const toolbox = goog.require('Blockly.utils.toolbox'); +const utils = goog.require('Blockly.utils'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.BlockCreate'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.ThemeChange'); /** @suppress {extraRequire} */ goog.require('Blockly.Events.ViewportChange'); -goog.require('Blockly.Gesture'); -goog.require('Blockly.Grid'); -goog.require('Blockly.IASTNodeLocationSvg'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.MarkerManager'); /** @suppress {extraRequire} */ goog.require('Blockly.MetricsManager'); /** @suppress {extraRequire} */ goog.require('Blockly.Msg'); -goog.require('Blockly.Options'); -goog.require('Blockly.registry'); -goog.require('Blockly.ThemeManager'); -goog.require('Blockly.Themes.Classic'); -goog.require('Blockly.TouchGesture'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Metrics'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Rect'); -goog.require('Blockly.utils.Size'); -goog.require('Blockly.utils.Svg'); -goog.require('Blockly.utils.toolbox'); -goog.require('Blockly.Workspace'); -goog.require('Blockly.WorkspaceAudio'); -goog.require('Blockly.WorkspaceDragSurfaceSvg'); -goog.require('Blockly.Xml'); - -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.BlockDragSurfaceSvg'); -goog.requireType('Blockly.blockRendering.Renderer'); -goog.requireType('Blockly.Cursor'); -goog.requireType('Blockly.FlyoutButton'); -goog.requireType('Blockly.IBoundedElement'); -goog.requireType('Blockly.IDragTarget'); -goog.requireType('Blockly.IFlyout'); -goog.requireType('Blockly.IMetricsManager'); -goog.requireType('Blockly.IToolbox'); -goog.requireType('Blockly.Marker'); -goog.requireType('Blockly.ScrollbarPair'); -goog.requireType('Blockly.Theme'); -goog.requireType('Blockly.Trashcan'); -goog.requireType('Blockly.VariableModel'); -goog.requireType('Blockly.ZoomControls'); /** * Class for a workspace. This is an onscreen area with optional trashcan, * scrollbars, bubbles, and dragging. - * @param {!Blockly.Options} options Dictionary of options. - * @param {Blockly.BlockDragSurfaceSvg=} opt_blockDragSurface Drag surface for + * @param {!Options} options Dictionary of options. + * @param {BlockDragSurfaceSvg=} opt_blockDragSurface Drag surface for * blocks. - * @param {Blockly.WorkspaceDragSurfaceSvg=} opt_wsDragSurface Drag surface for + * @param {WorkspaceDragSurfaceSvg=} opt_wsDragSurface Drag surface for * the workspace. - * @extends {Blockly.Workspace} - * @implements {Blockly.IASTNodeLocationSvg} + * @extends {Workspace} + * @implements {IASTNodeLocationSvg} * @constructor */ -Blockly.WorkspaceSvg = function( +const WorkspaceSvg = function( options, opt_blockDragSurface, opt_wsDragSurface) { - Blockly.WorkspaceSvg.superClass_.constructor.call(this, options); + WorkspaceSvg.superClass_.constructor.call(this, options); - var MetricsManagerClass = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.METRICS_MANAGER, options, true); + const MetricsManagerClass = registry.getClassFromOptions( + registry.Type.METRICS_MANAGER, options, true); /** * Object in charge of calculating metrics for the workspace. - * @type {!Blockly.IMetricsManager} + * @type {!IMetricsManager} * @private */ this.metricsManager_ = new MetricsManagerClass(this); /** * Method to get all the metrics that have to do with a workspace. - * @type {function():!Blockly.utils.Metrics} + * @type {function():!Metrics} * @package */ this.getMetrics = options.getMetrics || @@ -111,15 +143,15 @@ Blockly.WorkspaceSvg = function( * @package */ this.setMetrics = - options.setMetrics || Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_; + options.setMetrics || WorkspaceSvg.setTopLevelWorkspaceMetrics_; /** - * @type {!Blockly.ComponentManager} + * @type {!ComponentManager} * @private */ - this.componentManager_ = new Blockly.ComponentManager(); + this.componentManager_ = new ComponentManager(); - this.connectionDBList = Blockly.ConnectionDB.init(this.connectionChecker); + this.connectionDBList = ConnectionDB.init(this.connectionChecker); if (opt_blockDragSurface) { this.blockDragSurface_ = opt_blockDragSurface; @@ -130,90 +162,94 @@ Blockly.WorkspaceSvg = function( } this.useWorkspaceDragSurface_ = - !!this.workspaceDragSurface_ && Blockly.utils.is3dSupported(); + !!this.workspaceDragSurface_ && utils.is3dSupported(); /** * List of currently highlighted blocks. Block highlighting is often used to * visually mark blocks currently being executed. - * @type {!Array} + * @type {!Array} * @private */ this.highlightedBlocks_ = []; /** * Object in charge of loading, storing, and playing audio for a workspace. - * @type {!Blockly.WorkspaceAudio} + * @type {!WorkspaceAudio} * @private */ - this.audioManager_ = new Blockly.WorkspaceAudio( - /** @type {Blockly.WorkspaceSvg} */ (options.parentWorkspace)); + this.audioManager_ = new WorkspaceAudio( + /** @type {WorkspaceSvg} */ (options.parentWorkspace)); /** * This workspace's grid object or null. - * @type {Blockly.Grid} + * @type {Grid} * @private */ this.grid_ = this.options.gridPattern ? - new Blockly.Grid(this.options.gridPattern, options.gridOptions) : null; + new Grid(this.options.gridPattern, options.gridOptions) : + null; /** * Manager in charge of markers and cursors. - * @type {!Blockly.MarkerManager} + * @type {!MarkerManager} * @private */ - this.markerManager_ = new Blockly.MarkerManager(this); + this.markerManager_ = new MarkerManager(this); /** - * Map from function names to callbacks, for deciding what to do when a custom - * toolbox category is opened. - * @type {!Object>} - * @private - */ + * Map from function names to callbacks, for deciding what to do when a custom + * toolbox category is opened. + * @type {!Object>} + * @private + */ this.toolboxCategoryCallbacks_ = Object.create(null); /** - * Map from function names to callbacks, for deciding what to do when a button - * is clicked. - * @type {!Object} - * @private - */ + * Map from function names to callbacks, for deciding what to do when a button + * is clicked. + * @type {!Object} + * @private + */ this.flyoutButtonCallbacks_ = Object.create(null); - if (Blockly.Variables && Blockly.Variables.flyoutCategory) { + const Variables = goog.module.get('Blockly.Variables'); + if (Variables && Variables.flyoutCategory) { this.registerToolboxCategoryCallback( - Blockly.internalConstants.VARIABLE_CATEGORY_NAME, - Blockly.Variables.flyoutCategory); + internalConstants.VARIABLE_CATEGORY_NAME, Variables.flyoutCategory); } - if (Blockly.VariablesDynamic && Blockly.VariablesDynamic.flyoutCategory) { + + const VariablesDynamic = goog.module.get('Blockly.VariablesDynamic'); + if (VariablesDynamic && VariablesDynamic.flyoutCategory) { this.registerToolboxCategoryCallback( - Blockly.internalConstants.VARIABLE_DYNAMIC_CATEGORY_NAME, - Blockly.VariablesDynamic.flyoutCategory); + internalConstants.VARIABLE_DYNAMIC_CATEGORY_NAME, + VariablesDynamic.flyoutCategory); } - if (Blockly.Procedures && Blockly.Procedures.flyoutCategory) { + + const Procedures = goog.module.get('Blockly.Procedures'); + if (Procedures && Procedures.flyoutCategory) { this.registerToolboxCategoryCallback( - Blockly.internalConstants.PROCEDURE_CATEGORY_NAME, - Blockly.Procedures.flyoutCategory); - this.addChangeListener(Blockly.Procedures.mutatorOpenListener); + internalConstants.PROCEDURE_CATEGORY_NAME, Procedures.flyoutCategory); + this.addChangeListener(Procedures.mutatorOpenListener); } /** * Object in charge of storing and updating the workspace theme. - * @type {!Blockly.ThemeManager} + * @type {!ThemeManager} * @protected */ this.themeManager_ = this.options.parentWorkspace ? this.options.parentWorkspace.getThemeManager() : - new Blockly.ThemeManager(this, - this.options.theme || Blockly.Themes.Classic); + new ThemeManager(this, this.options.theme || Classic); this.themeManager_.subscribeWorkspace(this); /** * The block renderer used for rendering blocks on this workspace. - * @type {!Blockly.blockRendering.Renderer} + * @type {!Renderer} * @private */ - this.renderer_ = Blockly.blockRendering.init(this.options.renderer || 'geras', - this.getTheme(), this.options.rendererOverrides); + this.renderer_ = blockRendering.init( + this.options.renderer || 'geras', this.getTheme(), + this.options.rendererOverrides); /** * Cached parent SVG. @@ -230,7 +266,7 @@ Blockly.WorkspaceSvg = function( /** * The list of top-level bounded elements on the workspace. - * @type {!Array} + * @type {!Array} * @private */ this.topBoundedElements_ = []; @@ -239,8 +275,8 @@ Blockly.WorkspaceSvg = function( * The recorded drag targets. * @type {!Array< * { - * component: !Blockly.IDragTarget, - * clientRect: !Blockly.utils.Rect + * component: !IDragTarget, + * clientRect: !Rect * }>} * @private */ @@ -249,28 +285,28 @@ Blockly.WorkspaceSvg = function( /** * The cached size of the parent svg element. * Used to compute svg metrics. - * @type {!Blockly.utils.Size} + * @type {!Size} * @private */ - this.cachedParentSvgSize_ = new Blockly.utils.Size(0, 0); + this.cachedParentSvgSize_ = new Size(0, 0); }; -Blockly.utils.object.inherits(Blockly.WorkspaceSvg, Blockly.Workspace); +object.inherits(WorkspaceSvg, Workspace); /** * A wrapper function called when a resize event occurs. * You can pass the result to `eventHandling.unbind`. - * @type {?Blockly.browserEvents.Data} + * @type {?browserEvents.Data} * @private */ -Blockly.WorkspaceSvg.prototype.resizeHandlerWrapper_ = null; +WorkspaceSvg.prototype.resizeHandlerWrapper_ = null; /** * The render status of an SVG workspace. * Returns `false` for headless workspaces and true for instances of - * `Blockly.WorkspaceSvg`. + * `WorkspaceSvg`. * @type {boolean} */ -Blockly.WorkspaceSvg.prototype.rendered = true; +WorkspaceSvg.prototype.rendered = true; /** * Whether the workspace is visible. False if the workspace has been hidden @@ -278,20 +314,20 @@ Blockly.WorkspaceSvg.prototype.rendered = true; * @type {boolean} * @private */ -Blockly.WorkspaceSvg.prototype.isVisible_ = true; +WorkspaceSvg.prototype.isVisible_ = true; /** * Is this workspace the surface for a flyout? * @type {boolean} */ -Blockly.WorkspaceSvg.prototype.isFlyout = false; +WorkspaceSvg.prototype.isFlyout = false; /** * Is this workspace the surface for a mutator? * @type {boolean} * @package */ -Blockly.WorkspaceSvg.prototype.isMutator = false; +WorkspaceSvg.prototype.isMutator = false; /** * Whether this workspace has resizes enabled. @@ -299,7 +335,7 @@ Blockly.WorkspaceSvg.prototype.isMutator = false; * @type {boolean} * @private */ -Blockly.WorkspaceSvg.prototype.resizesEnabled_ = true; +WorkspaceSvg.prototype.resizesEnabled_ = true; /** * Current horizontal scrolling offset in pixel units, relative to the @@ -333,7 +369,7 @@ Blockly.WorkspaceSvg.prototype.resizesEnabled_ = true; * * @type {number} */ -Blockly.WorkspaceSvg.prototype.scrollX = 0; +WorkspaceSvg.prototype.scrollX = 0; /** * Current vertical scrolling offset in pixel units, relative to the @@ -367,109 +403,109 @@ Blockly.WorkspaceSvg.prototype.scrollX = 0; * * @type {number} */ -Blockly.WorkspaceSvg.prototype.scrollY = 0; +WorkspaceSvg.prototype.scrollY = 0; /** * Horizontal scroll value when scrolling started in pixel units. * @type {number} */ -Blockly.WorkspaceSvg.prototype.startScrollX = 0; +WorkspaceSvg.prototype.startScrollX = 0; /** * Vertical scroll value when scrolling started in pixel units. * @type {number} */ -Blockly.WorkspaceSvg.prototype.startScrollY = 0; +WorkspaceSvg.prototype.startScrollY = 0; /** * Distance from mouse to object being dragged. - * @type {Blockly.utils.Coordinate} + * @type {Coordinate} * @private */ -Blockly.WorkspaceSvg.prototype.dragDeltaXY_ = null; +WorkspaceSvg.prototype.dragDeltaXY_ = null; /** * Current scale. * @type {number} */ -Blockly.WorkspaceSvg.prototype.scale = 1; +WorkspaceSvg.prototype.scale = 1; /** * Cached scale value. Used to detect changes in viewport. * @type {number} * @private */ -Blockly.WorkspaceSvg.prototype.oldScale_ = 1; +WorkspaceSvg.prototype.oldScale_ = 1; /** * Cached viewport top value. Used to detect changes in viewport. * @type {number} * @private */ -Blockly.WorkspaceSvg.prototype.oldTop_ = 0; +WorkspaceSvg.prototype.oldTop_ = 0; /** * Cached viewport left value. Used to detect changes in viewport. * @type {number} * @private */ -Blockly.WorkspaceSvg.prototype.oldLeft_ = 0; +WorkspaceSvg.prototype.oldLeft_ = 0; /** * The workspace's trashcan (if any). - * @type {Blockly.Trashcan} + * @type {Trashcan} */ -Blockly.WorkspaceSvg.prototype.trashcan = null; +WorkspaceSvg.prototype.trashcan = null; /** * This workspace's scrollbars, if they exist. - * @type {Blockly.ScrollbarPair} + * @type {ScrollbarPair} */ -Blockly.WorkspaceSvg.prototype.scrollbar = null; +WorkspaceSvg.prototype.scrollbar = null; /** * Fixed flyout providing blocks which may be dragged into this workspace. - * @type {Blockly.IFlyout} + * @type {IFlyout} * @private */ -Blockly.WorkspaceSvg.prototype.flyout_ = null; +WorkspaceSvg.prototype.flyout_ = null; /** * Category-based toolbox providing blocks which may be dragged into this * workspace. - * @type {Blockly.IToolbox} + * @type {IToolbox} * @private */ -Blockly.WorkspaceSvg.prototype.toolbox_ = null; +WorkspaceSvg.prototype.toolbox_ = null; /** * The current gesture in progress on this workspace, if any. - * @type {Blockly.TouchGesture} + * @type {TouchGesture} * @private */ -Blockly.WorkspaceSvg.prototype.currentGesture_ = null; +WorkspaceSvg.prototype.currentGesture_ = null; /** * This workspace's surface for dragging blocks, if it exists. - * @type {Blockly.BlockDragSurfaceSvg} + * @type {BlockDragSurfaceSvg} * @private */ -Blockly.WorkspaceSvg.prototype.blockDragSurface_ = null; +WorkspaceSvg.prototype.blockDragSurface_ = null; /** * This workspace's drag surface, if it exists. - * @type {Blockly.WorkspaceDragSurfaceSvg} + * @type {WorkspaceDragSurfaceSvg} * @private */ -Blockly.WorkspaceSvg.prototype.workspaceDragSurface_ = null; +WorkspaceSvg.prototype.workspaceDragSurface_ = null; /** - * Whether to move workspace to the drag surface when it is dragged. - * True if it should move, false if it should be translated directly. - * @type {boolean} - * @private - */ -Blockly.WorkspaceSvg.prototype.useWorkspaceDragSurface_ = false; + * Whether to move workspace to the drag surface when it is dragged. + * True if it should move, false if it should be translated directly. + * @type {boolean} + * @private + */ +WorkspaceSvg.prototype.useWorkspaceDragSurface_ = false; /** * Whether the drag surface is actively in use. When true, calls to @@ -479,7 +515,7 @@ Blockly.WorkspaceSvg.prototype.useWorkspaceDragSurface_ = false; * @type {boolean} * @private */ -Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_ = false; +WorkspaceSvg.prototype.isDragSurfaceActive_ = false; /** * The first parent div with 'injectionDiv' in the name, or null if not set. @@ -487,16 +523,16 @@ Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_ = false; * @type {Element} * @private */ -Blockly.WorkspaceSvg.prototype.injectionDiv_ = null; +WorkspaceSvg.prototype.injectionDiv_ = null; /** * Last known position of the page scroll. * This is used to determine whether we have recalculated screen coordinate * stuff since the page scrolled. - * @type {Blockly.utils.Coordinate} + * @type {Coordinate} * @private */ -Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; +WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; /** * Developers may define this function to add custom menu options to the @@ -504,63 +540,63 @@ Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; * @param {!Array} options List of menu options to add to. * @param {!Event} e The right-click event that triggered the context menu. */ -Blockly.WorkspaceSvg.prototype.configureContextMenu; +WorkspaceSvg.prototype.configureContextMenu; /** * In a flyout, the target workspace where blocks should be placed after a drag. * Otherwise null. - * @type {Blockly.WorkspaceSvg} + * @type {WorkspaceSvg} * @package */ -Blockly.WorkspaceSvg.prototype.targetWorkspace = null; +WorkspaceSvg.prototype.targetWorkspace = null; /** * Inverted screen CTM, for use in mouseToSvg. * @type {?SVGMatrix} * @private */ -Blockly.WorkspaceSvg.prototype.inverseScreenCTM_ = null; +WorkspaceSvg.prototype.inverseScreenCTM_ = null; /** * Inverted screen CTM is dirty, recalculate it. * @type {boolean} * @private */ -Blockly.WorkspaceSvg.prototype.inverseScreenCTMDirty_ = true; +WorkspaceSvg.prototype.inverseScreenCTMDirty_ = true; /** * Get the marker manager for this workspace. - * @return {!Blockly.MarkerManager} The marker manager. + * @return {!MarkerManager} The marker manager. */ -Blockly.WorkspaceSvg.prototype.getMarkerManager = function() { +WorkspaceSvg.prototype.getMarkerManager = function() { return this.markerManager_; }; /** * Gets the metrics manager for this workspace. - * @return {!Blockly.IMetricsManager} The metrics manager. + * @return {!IMetricsManager} The metrics manager. * @public */ -Blockly.WorkspaceSvg.prototype.getMetricsManager = function() { +WorkspaceSvg.prototype.getMetricsManager = function() { return this.metricsManager_; }; /** * Sets the metrics manager for the workspace. - * @param {!Blockly.IMetricsManager} metricsManager The metrics manager. + * @param {!IMetricsManager} metricsManager The metrics manager. * @package */ -Blockly.WorkspaceSvg.prototype.setMetricsManager = function(metricsManager) { +WorkspaceSvg.prototype.setMetricsManager = function(metricsManager) { this.metricsManager_ = metricsManager; this.getMetrics = this.metricsManager_.getMetrics.bind(this.metricsManager_); }; /** * Gets the component manager for this workspace. - * @return {!Blockly.ComponentManager} The component manager. + * @return {!ComponentManager} The component manager. * @public */ -Blockly.WorkspaceSvg.prototype.getComponentManager = function() { +WorkspaceSvg.prototype.getComponentManager = function() { return this.componentManager_; }; @@ -570,7 +606,7 @@ Blockly.WorkspaceSvg.prototype.getComponentManager = function() { * workspace SVG group. * @package */ -Blockly.WorkspaceSvg.prototype.setCursorSvg = function(cursorSvg) { +WorkspaceSvg.prototype.setCursorSvg = function(cursorSvg) { this.markerManager_.setCursorSvg(cursorSvg); }; @@ -580,18 +616,18 @@ Blockly.WorkspaceSvg.prototype.setCursorSvg = function(cursorSvg) { * workspace SVG group. * @package */ -Blockly.WorkspaceSvg.prototype.setMarkerSvg = function(markerSvg) { +WorkspaceSvg.prototype.setMarkerSvg = function(markerSvg) { this.markerManager_.setMarkerSvg(markerSvg); }; /** * Get the marker with the given ID. * @param {string} id The ID of the marker. - * @return {?Blockly.Marker} The marker with the given ID or null if no marker + * @return {?Marker} The marker with the given ID or null if no marker * with the given ID exists. * @package */ -Blockly.WorkspaceSvg.prototype.getMarker = function(id) { +WorkspaceSvg.prototype.getMarker = function(id) { if (this.markerManager_) { return this.markerManager_.getMarker(id); } @@ -600,9 +636,9 @@ Blockly.WorkspaceSvg.prototype.getMarker = function(id) { /** * The cursor for this workspace. - * @return {?Blockly.Cursor} The cursor for the workspace. + * @return {?Cursor} The cursor for the workspace. */ -Blockly.WorkspaceSvg.prototype.getCursor = function() { +WorkspaceSvg.prototype.getCursor = function() { if (this.markerManager_) { return this.markerManager_.getCursor(); } @@ -611,38 +647,38 @@ Blockly.WorkspaceSvg.prototype.getCursor = function() { /** * Get the block renderer attached to this workspace. - * @return {!Blockly.blockRendering.Renderer} The renderer attached to this + * @return {!Renderer} The renderer attached to this * workspace. */ -Blockly.WorkspaceSvg.prototype.getRenderer = function() { +WorkspaceSvg.prototype.getRenderer = function() { return this.renderer_; }; /** * Get the theme manager for this workspace. - * @return {!Blockly.ThemeManager} The theme manager for this workspace. + * @return {!ThemeManager} The theme manager for this workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getThemeManager = function() { +WorkspaceSvg.prototype.getThemeManager = function() { return this.themeManager_; }; /** * Get the workspace theme object. - * @return {!Blockly.Theme} The workspace theme object. + * @return {!Theme} The workspace theme object. */ -Blockly.WorkspaceSvg.prototype.getTheme = function() { +WorkspaceSvg.prototype.getTheme = function() { return this.themeManager_.getTheme(); }; /** * Set the workspace theme object. - * If no theme is passed, default to the `Blockly.Themes.Classic` theme. - * @param {Blockly.Theme} theme The workspace theme object. + * If no theme is passed, default to the `Classic` theme. + * @param {Theme} theme The workspace theme object. */ -Blockly.WorkspaceSvg.prototype.setTheme = function(theme) { +WorkspaceSvg.prototype.setTheme = function(theme) { if (!theme) { - theme = /** @type {!Blockly.Theme} */ (Blockly.Themes.Classic); + theme = /** @type {!Theme} */ (Classic); } this.themeManager_.setTheme(theme); }; @@ -651,17 +687,15 @@ Blockly.WorkspaceSvg.prototype.setTheme = function(theme) { * Refresh all blocks on the workspace after a theme update. * @package */ -Blockly.WorkspaceSvg.prototype.refreshTheme = function() { +WorkspaceSvg.prototype.refreshTheme = function() { if (this.svgGroup_) { this.renderer_.refreshDom(this.svgGroup_, this.getTheme()); } // Update all blocks in workspace that have a style name. - this.updateBlockStyles_(this.getAllBlocks(false).filter( - function(block) { - return !!block.getStyleName(); - } - )); + this.updateBlockStyles_(this.getAllBlocks(false).filter(function(block) { + return !!block.getStyleName(); + })); // Update current toolbox selection. this.refreshToolboxSelection(); @@ -674,20 +708,20 @@ Blockly.WorkspaceSvg.prototype.refreshTheme = function() { this.setVisible(true); } - var event = new (Blockly.Events.get(Blockly.Events.THEME_CHANGE))( - this.getTheme().name, this.id); - Blockly.Events.fire(event); + const event = + new (Events.get(Events.THEME_CHANGE))(this.getTheme().name, this.id); + Events.fire(event); }; /** * Updates all the blocks with new style. - * @param {!Array} blocks List of blocks to update the style + * @param {!Array} blocks List of blocks to update the style * on. * @private */ -Blockly.WorkspaceSvg.prototype.updateBlockStyles_ = function(blocks) { - for (var i = 0, block; (block = blocks[i]); i++) { - var blockStyleName = block.getStyleName(); +WorkspaceSvg.prototype.updateBlockStyles_ = function(blocks) { + for (let i = 0, block; (block = blocks[i]); i++) { + const blockStyleName = block.getStyleName(); if (blockStyleName) { block.setStyle(blockStyleName); if (block.mutator) { @@ -701,11 +735,11 @@ Blockly.WorkspaceSvg.prototype.updateBlockStyles_ = function(blocks) { * Getter for the inverted screen CTM. * @return {?SVGMatrix} The matrix to use in mouseToSvg */ -Blockly.WorkspaceSvg.prototype.getInverseScreenCTM = function() { +WorkspaceSvg.prototype.getInverseScreenCTM = function() { // Defer getting the screen CTM until we actually need it, this should // avoid forced reflows from any calls to updateInverseScreenCTM. if (this.inverseScreenCTMDirty_) { - var ctm = this.getParentSvg().getScreenCTM(); + const ctm = this.getParentSvg().getScreenCTM(); if (ctm) { this.inverseScreenCTM_ = ctm.inverse(); this.inverseScreenCTMDirty_ = false; @@ -718,7 +752,7 @@ Blockly.WorkspaceSvg.prototype.getInverseScreenCTM = function() { /** * Mark the inverse screen CTM as dirty. */ -Blockly.WorkspaceSvg.prototype.updateInverseScreenCTM = function() { +WorkspaceSvg.prototype.updateInverseScreenCTM = function() { this.inverseScreenCTMDirty_ = true; }; @@ -727,7 +761,7 @@ Blockly.WorkspaceSvg.prototype.updateInverseScreenCTM = function() { * @return {boolean} Whether the workspace is visible. * False if the workspace has been hidden by calling `setVisible(false)`. */ -Blockly.WorkspaceSvg.prototype.isVisible = function() { +WorkspaceSvg.prototype.isVisible = function() { return this.isVisible_; }; @@ -736,23 +770,22 @@ Blockly.WorkspaceSvg.prototype.isVisible = function() { * scales that after canvas SVG element, if it's a descendant. * The origin (0,0) is the top-left corner of the Blockly SVG. * @param {!SVGElement} element SVG element to find the coordinates of. - * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. + * @return {!Coordinate} Object with .x and .y properties. * @package */ -Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { - var x = 0; - var y = 0; - var scale = 1; - if (Blockly.utils.dom.containsNode(this.getCanvas(), element) || - Blockly.utils.dom.containsNode(this.getBubbleCanvas(), element)) { +WorkspaceSvg.prototype.getSvgXY = function(element) { + let x = 0; + let y = 0; + let scale = 1; + if (dom.containsNode(this.getCanvas(), element) || + dom.containsNode(this.getBubbleCanvas(), element)) { // Before the SVG canvas, scale the coordinates. scale = this.scale; } do { // Loop through this block and every parent. - var xy = Blockly.utils.getRelativeXY(element); - if (element == this.getCanvas() || - element == this.getBubbleCanvas()) { + const xy = utils.getRelativeXY(element); + if (element == this.getCanvas() || element == this.getBubbleCanvas()) { // After the SVG canvas, don't scale the coordinates. scale = 1; } @@ -760,18 +793,18 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { y += xy.y * scale; element = /** @type {!SVGElement} */ (element.parentNode); } while (element && element != this.getParentSvg()); - return new Blockly.utils.Coordinate(x, y); + return new Coordinate(x, y); }; /** * Gets the size of the workspace's parent SVG element. - * @return {!Blockly.utils.Size} The cached width and height of the workspace's + * @return {!Size} The cached width and height of the workspace's * parent SVG element. * @package */ -Blockly.WorkspaceSvg.prototype.getCachedParentSvgSize = function() { - var size = this.cachedParentSvgSize_; - return new Blockly.utils.Size(size.width, size.height); +WorkspaceSvg.prototype.getCachedParentSvgSize = function() { + const size = this.cachedParentSvgSize_; + return new Size(size.width, size.height); }; /** @@ -779,11 +812,11 @@ Blockly.WorkspaceSvg.prototype.getCachedParentSvgSize = function() { * origin in pixels. * The workspace origin is where a block would render at position (0, 0). * It is not the upper left corner of the workspace SVG. - * @return {!Blockly.utils.Coordinate} Offset in pixels. + * @return {!Coordinate} Offset in pixels. * @package */ -Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { - return Blockly.utils.getInjectionDivXY_(this.getCanvas()); +WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { + return utils.getInjectionDivXY_(this.getCanvas()); }; /** @@ -794,13 +827,13 @@ Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { * @return {!Element} The first parent div with 'injectionDiv' in the name. * @package */ -Blockly.WorkspaceSvg.prototype.getInjectionDiv = function() { +WorkspaceSvg.prototype.getInjectionDiv = function() { // NB: it would be better to pass this in at createDom, but is more likely to // break existing uses of Blockly. if (!this.injectionDiv_) { - var element = this.svgGroup_; + let element = this.svgGroup_; while (element) { - var classes = element.getAttribute('class') || ''; + const classes = element.getAttribute('class') || ''; if ((' ' + classes + ' ').indexOf(' injectionDiv ') != -1) { this.injectionDiv_ = element; break; @@ -816,16 +849,16 @@ Blockly.WorkspaceSvg.prototype.getInjectionDiv = function() { * @return {?SVGElement} The SVG group for the workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getBlockCanvas = function() { +WorkspaceSvg.prototype.getBlockCanvas = function() { return this.svgBlockCanvas_; }; /** * Save resize handler data so we can delete it later in dispose. - * @param {!Blockly.browserEvents.Data} handler Data that can be passed to + * @param {!browserEvents.Data} handler Data that can be passed to * eventHandling.unbind. */ -Blockly.WorkspaceSvg.prototype.setResizeHandlerWrapper = function(handler) { +WorkspaceSvg.prototype.setResizeHandlerWrapper = function(handler) { this.resizeHandlerWrapper_ = handler; }; @@ -835,7 +868,7 @@ Blockly.WorkspaceSvg.prototype.setResizeHandlerWrapper = function(handler) { * 'blocklyMutatorBackground'. * @return {!Element} The workspace's SVG group. */ -Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { +WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { /** * * @@ -845,17 +878,16 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { * * @type {SVGElement} */ - this.svgGroup_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - {'class': 'blocklyWorkspace'}, null); + this.svgGroup_ = + dom.createSvgElement(Svg.G, {'class': 'blocklyWorkspace'}, null); // Note that a alone does not receive mouse events--it must have a // valid target inside it. If no background class is specified, as in the // flyout, the workspace will not receive mouse events. if (opt_backgroundClass) { /** @type {SVGElement} */ - this.svgBackground_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, + this.svgBackground_ = dom.createSvgElement( + Svg.RECT, {'height': '100%', 'width': '100%', 'class': opt_backgroundClass}, this.svgGroup_); @@ -863,43 +895,41 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { this.svgBackground_.style.fill = 'url(#' + this.grid_.getPatternId() + ')'; } else { - this.themeManager_.subscribe(this.svgBackground_, - 'workspaceBackgroundColour', 'fill'); + this.themeManager_.subscribe( + this.svgBackground_, 'workspaceBackgroundColour', 'fill'); } } /** @type {SVGElement} */ - this.svgBlockCanvas_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - {'class': 'blocklyBlockCanvas'}, this.svgGroup_); + this.svgBlockCanvas_ = dom.createSvgElement( + Svg.G, {'class': 'blocklyBlockCanvas'}, this.svgGroup_); /** @type {SVGElement} */ - this.svgBubbleCanvas_ = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - {'class': 'blocklyBubbleCanvas'}, this.svgGroup_); + this.svgBubbleCanvas_ = dom.createSvgElement( + Svg.G, {'class': 'blocklyBubbleCanvas'}, this.svgGroup_); if (!this.isFlyout) { - Blockly.browserEvents.conditionalBind( + browserEvents.conditionalBind( this.svgGroup_, 'mousedown', this, this.onMouseDown_, false, true); // This no-op works around https://bugs.webkit.org/show_bug.cgi?id=226683, // which otherwise prevents zoom/scroll events from being observed in // Safari. Once that bug is fixed it should be removed. document.body.addEventListener('wheel', function() {}); - Blockly.browserEvents.conditionalBind( + browserEvents.conditionalBind( this.svgGroup_, 'wheel', this, this.onMouseWheel_); } // Determine if there needs to be a category tree, or a simple list of // blocks. This cannot be changed later, since the UI is very different. if (this.options.hasCategories) { - var ToolboxClass = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.TOOLBOX, this.options, true); + const ToolboxClass = + registry.getClassFromOptions(registry.Type.TOOLBOX, this.options, true); this.toolbox_ = new ToolboxClass(this); } if (this.grid_) { this.grid_.update(this.scale); } this.recordDragTargets(); - var CursorClass = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.CURSOR, this.options); + const CursorClass = + registry.getClassFromOptions(registry.Type.CURSOR, this.options); CursorClass && this.markerManager_.setCursor(new CursorClass()); @@ -912,14 +942,14 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { * Unlink from all DOM elements to prevent memory leaks. * @suppress {checkTypes} */ -Blockly.WorkspaceSvg.prototype.dispose = function() { +WorkspaceSvg.prototype.dispose = function() { // Stop rerendering. this.rendered = false; if (this.currentGesture_) { this.currentGesture_.cancel(); } if (this.svgGroup_) { - Blockly.utils.dom.removeNode(this.svgGroup_); + dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgBlockCanvas_ = null; @@ -962,7 +992,7 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { this.markerManager_ = null; } - Blockly.WorkspaceSvg.superClass_.dispose.call(this); + WorkspaceSvg.superClass_.dispose.call(this); // Dispose of theme manager after all blocks and mutators are disposed of. if (this.themeManager_) { @@ -982,13 +1012,13 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { if (!this.options.parentWorkspace) { // Top-most workspace. Dispose of the div that the // SVG is injected into (i.e. injectionDiv). - var parentSvg = this.getParentSvg(); + const parentSvg = this.getParentSvg(); if (parentSvg && parentSvg.parentNode) { - Blockly.utils.dom.removeNode(parentSvg.parentNode); + dom.removeNode(parentSvg.parentNode); } } if (this.resizeHandlerWrapper_) { - Blockly.browserEvents.unbind(this.resizeHandlerWrapper_); + browserEvents.unbind(this.resizeHandlerWrapper_); this.resizeHandlerWrapper_ = null; } }; @@ -997,30 +1027,31 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { * Obtain a newly created block. * * This block's SVG must still be initialized - * ([initSvg]{@link Blockly.BlockSvg#initSvg}) and it must be rendered - * ([render]{@link Blockly.BlockSvg#render}) before the block will be visible. + * ([initSvg]{@link BlockSvg#initSvg}) and it must be rendered + * ([render]{@link BlockSvg#render}) before the block will be visible. * @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 {!Blockly.BlockSvg} The created block. + * @return {!BlockSvg} The created block. * @override */ -Blockly.WorkspaceSvg.prototype.newBlock = function(prototypeName, opt_id) { - return new Blockly.BlockSvg(this, prototypeName, opt_id); +WorkspaceSvg.prototype.newBlock = function(prototypeName, opt_id) { + return new BlockSvg(this, prototypeName, opt_id); }; /** * Add a trashcan. * @package */ -Blockly.WorkspaceSvg.prototype.addTrashcan = function() { - if (!Blockly.Trashcan) { +WorkspaceSvg.prototype.addTrashcan = function() { + const Trashcan = goog.module.get('Blockly.Trashcan'); + if (!Trashcan) { throw Error('Missing require for Blockly.Trashcan'); } - /** @type {Blockly.Trashcan} */ - this.trashcan = new Blockly.Trashcan(this); - var svgTrashcan = this.trashcan.createDom(); + /** @type {Trashcan} */ + this.trashcan = new Trashcan(this); + const svgTrashcan = this.trashcan.createDom(); this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); }; @@ -1028,28 +1059,29 @@ Blockly.WorkspaceSvg.prototype.addTrashcan = function() { * Add zoom controls. * @package */ -Blockly.WorkspaceSvg.prototype.addZoomControls = function() { - if (!Blockly.ZoomControls) { +WorkspaceSvg.prototype.addZoomControls = function() { + const ZoomControls = goog.module.get('Blockly.ZoomControls'); + if (!ZoomControls) { throw Error('Missing require for Blockly.ZoomControls'); } - /** @type {Blockly.ZoomControls} */ - this.zoomControls_ = new Blockly.ZoomControls(this); - var svgZoomControls = this.zoomControls_.createDom(); + /** @type {ZoomControls} */ + this.zoomControls_ = new ZoomControls(this); + const svgZoomControls = this.zoomControls_.createDom(); this.svgGroup_.appendChild(svgZoomControls); }; /** * Add a flyout element in an element with the given tag name. * @param {string| - * !Blockly.utils.Svg| - * !Blockly.utils.Svg} tagName What type of tag the + * !Svg| + * !Svg} tagName What type of tag the * flyout belongs in. * @return {!Element} The element containing the flyout DOM. * @package */ -Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { - var workspaceOptions = new Blockly.Options( - /** @type {!Blockly.BlocklyOptions} */ +WorkspaceSvg.prototype.addFlyout = function(tagName) { + const workspaceOptions = new Options( + /** @type {!BlocklyOptions} */ ({ 'parentWorkspace': this, 'rtl': this.RTL, @@ -1063,12 +1095,12 @@ Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { })); workspaceOptions.toolboxPosition = this.options.toolboxPosition; if (this.horizontalLayout) { - var HorizontalFlyout = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, this.options, true); + const HorizontalFlyout = registry.getClassFromOptions( + registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, this.options, true); this.flyout_ = new HorizontalFlyout(workspaceOptions); } else { - var VerticalFlyout = Blockly.registry.getClassFromOptions( - Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX, this.options, true); + const VerticalFlyout = registry.getClassFromOptions( + registry.Type.FLYOUTS_VERTICAL_TOOLBOX, this.options, true); this.flyout_ = new VerticalFlyout(workspaceOptions); } this.flyout_.autoClose = false; @@ -1085,10 +1117,10 @@ Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { * owned by either the toolbox or the workspace, depending on toolbox * configuration. It will be null if there is no flyout. * @param {boolean=} opt_own Whether to only return the workspace's own flyout. - * @return {?Blockly.IFlyout} The flyout on this workspace. + * @return {?IFlyout} The flyout on this workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getFlyout = function(opt_own) { +WorkspaceSvg.prototype.getFlyout = function(opt_own) { if (this.flyout_ || opt_own) { return this.flyout_; } @@ -1100,10 +1132,10 @@ Blockly.WorkspaceSvg.prototype.getFlyout = function(opt_own) { /** * Getter for the toolbox associated with this workspace, if one exists. - * @return {?Blockly.IToolbox} The toolbox on this workspace. + * @return {?IToolbox} The toolbox on this workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getToolbox = function() { +WorkspaceSvg.prototype.getToolbox = function() { return this.toolbox_; }; @@ -1112,7 +1144,7 @@ Blockly.WorkspaceSvg.prototype.getToolbox = function() { * because something has changed (e.g. scroll position, window size). * @private */ -Blockly.WorkspaceSvg.prototype.updateScreenCalculations_ = function() { +WorkspaceSvg.prototype.updateScreenCalculations_ = function() { this.updateInverseScreenCTM(); this.recordDragTargets(); }; @@ -1123,7 +1155,7 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculations_ = function() { * workspace contents if needed. * @package */ -Blockly.WorkspaceSvg.prototype.resizeContents = function() { +WorkspaceSvg.prototype.resizeContents = function() { if (!this.resizesEnabled_ || !this.rendered) { return; } @@ -1140,7 +1172,7 @@ Blockly.WorkspaceSvg.prototype.resizeContents = function() { * requires recalculating dimensions and positions of the * trash, zoom, toolbox, etc. (e.g. window resize). */ -Blockly.WorkspaceSvg.prototype.resize = function() { +WorkspaceSvg.prototype.resize = function() { if (this.toolbox_) { this.toolbox_.position(); } @@ -1148,13 +1180,13 @@ Blockly.WorkspaceSvg.prototype.resize = function() { this.flyout_.position(); } - var positionables = this.componentManager_.getComponents( - Blockly.ComponentManager.Capability.POSITIONABLE, true); - var metrics = this.getMetricsManager().getUiMetrics(); - var savedPositions = []; - for (var i = 0, positionable; (positionable = positionables[i]); i++) { + const positionables = this.componentManager_.getComponents( + ComponentManager.Capability.POSITIONABLE, true); + const metrics = this.getMetricsManager().getUiMetrics(); + const savedPositions = []; + for (let i = 0, positionable; (positionable = positionables[i]); i++) { positionable.position(metrics, savedPositions); - var boundingRect = positionable.getBoundingRectangle(); + const boundingRect = positionable.getBoundingRectangle(); if (boundingRect) { savedPositions.push(boundingRect); } @@ -1171,12 +1203,10 @@ Blockly.WorkspaceSvg.prototype.resize = function() { * scroll position. * @package */ -Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = - function() { - /* eslint-disable indent */ - var currScroll = Blockly.utils.getDocumentScroll(); - if (!Blockly.utils.Coordinate.equals( - this.lastRecordedPageScroll_, currScroll)) { +WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = function() { + /* eslint-disable indent */ + const currScroll = utils.getDocumentScroll(); + if (!Coordinate.equals(this.lastRecordedPageScroll_, currScroll)) { this.lastRecordedPageScroll_ = currScroll; this.updateScreenCalculations_(); } @@ -1186,7 +1216,7 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = * Get the SVG element that forms the drawing surface. * @return {!SVGGElement} SVG group element. */ -Blockly.WorkspaceSvg.prototype.getCanvas = function() { +WorkspaceSvg.prototype.getCanvas = function() { return /** @type {!SVGGElement} */ (this.svgBlockCanvas_); }; @@ -1197,16 +1227,18 @@ Blockly.WorkspaceSvg.prototype.getCanvas = function() { * @param {?number} height The height of the parent SVG element * @package */ -Blockly.WorkspaceSvg.prototype.setCachedParentSvgSize = function(width, height) { - var svg = this.getParentSvg(); +WorkspaceSvg.prototype.setCachedParentSvgSize = function(width, height) { + const svg = this.getParentSvg(); if (width) { this.cachedParentSvgSize_.width = width; - // This is set to support the public (but deprecated) Blockly.svgSize method. + // This is set to support the public (but deprecated) Blockly.svgSize + // method. svg.cachedWidth_ = width; } if (height) { this.cachedParentSvgSize_.height = height; - // This is set to support the public (but deprecated) Blockly.svgSize method. + // This is set to support the public (but deprecated) Blockly.svgSize + // method. svg.cachedHeight_ = height; } }; @@ -1215,7 +1247,7 @@ Blockly.WorkspaceSvg.prototype.setCachedParentSvgSize = function(width, height) * Get the SVG element that forms the bubble surface. * @return {!SVGGElement} SVG group element. */ -Blockly.WorkspaceSvg.prototype.getBubbleCanvas = function() { +WorkspaceSvg.prototype.getBubbleCanvas = function() { return /** @type {!SVGGElement} */ (this.svgBubbleCanvas_); }; @@ -1225,9 +1257,9 @@ Blockly.WorkspaceSvg.prototype.getBubbleCanvas = function() { * into the DOM. * @return {!SVGElement} SVG element. */ -Blockly.WorkspaceSvg.prototype.getParentSvg = function() { +WorkspaceSvg.prototype.getParentSvg = function() { if (!this.cachedParentSvg_) { - var element = this.svgGroup_; + let element = this.svgGroup_; while (element) { if (element.tagName == 'svg') { this.cachedParentSvg_ = element; @@ -1244,26 +1276,25 @@ Blockly.WorkspaceSvg.prototype.getParentSvg = function() { * viewport values. * @package */ -Blockly.WorkspaceSvg.prototype.maybeFireViewportChangeEvent = function() { - if (!Blockly.Events.isEnabled()) { +WorkspaceSvg.prototype.maybeFireViewportChangeEvent = function() { + if (!Events.isEnabled()) { return; } - var scale = this.scale; - var top = -this.scrollY; - var left = -this.scrollX; - if (scale == this.oldScale_ && - Math.abs(top - this.oldTop_) < 1 && + const scale = this.scale; + const top = -this.scrollY; + const left = -this.scrollX; + if (scale == this.oldScale_ && Math.abs(top - this.oldTop_) < 1 && Math.abs(left - this.oldLeft_) < 1) { // Ignore sub-pixel changes in top and left. Due to #4192 there are a lot of // negligible changes in viewport top/left. return; } - var event = new (Blockly.Events.get(Blockly.Events.VIEWPORT_CHANGE))(top, - left, scale, this.id, this.oldScale_); + const event = new (Events.get(Events.VIEWPORT_CHANGE))( + top, left, scale, this.id, this.oldScale_); this.oldScale_ = scale; this.oldTop_ = top; this.oldLeft_ = left; - Blockly.Events.fire(event); + Events.fire(event); }; /** @@ -1273,11 +1304,11 @@ Blockly.WorkspaceSvg.prototype.maybeFireViewportChangeEvent = function() { * @param {number} y Vertical translation, in pixel units relative to the * top left of the Blockly div. */ -Blockly.WorkspaceSvg.prototype.translate = function(x, y) { +WorkspaceSvg.prototype.translate = function(x, y) { if (this.useWorkspaceDragSurface_ && this.isDragSurfaceActive_) { - this.workspaceDragSurface_.translateSurface(x,y); + this.workspaceDragSurface_.translateSurface(x, y); } else { - var translation = 'translate(' + x + ',' + y + ') ' + + const translation = 'translate(' + x + ',' + y + ') ' + 'scale(' + this.scale + ')'; this.svgBlockCanvas_.setAttribute('transform', translation); this.svgBubbleCanvas_.setAttribute('transform', translation); @@ -1300,7 +1331,7 @@ Blockly.WorkspaceSvg.prototype.translate = function(x, y) { * Does nothing if the workspace drag surface is not enabled. * @package */ -Blockly.WorkspaceSvg.prototype.resetDragSurface = function() { +WorkspaceSvg.prototype.resetDragSurface = function() { // Don't do anything if we aren't using a drag surface. if (!this.useWorkspaceDragSurface_) { return; @@ -1308,9 +1339,9 @@ Blockly.WorkspaceSvg.prototype.resetDragSurface = function() { this.isDragSurfaceActive_ = false; - var trans = this.workspaceDragSurface_.getSurfaceTranslation(); + const trans = this.workspaceDragSurface_.getSurfaceTranslation(); this.workspaceDragSurface_.clearAndHide(this.svgGroup_); - var translation = 'translate(' + trans.x + ',' + trans.y + ') ' + + const translation = 'translate(' + trans.x + ',' + trans.y + ') ' + 'scale(' + this.scale + ')'; this.svgBlockCanvas_.setAttribute('transform', translation); this.svgBubbleCanvas_.setAttribute('transform', translation); @@ -1322,7 +1353,7 @@ Blockly.WorkspaceSvg.prototype.resetDragSurface = function() { * Does nothing if the drag surface is not enabled. * @package */ -Blockly.WorkspaceSvg.prototype.setupDragSurface = function() { +WorkspaceSvg.prototype.setupDragSurface = function() { // Don't do anything if we aren't using a drag surface. if (!this.useWorkspaceDragSurface_) { return; @@ -1341,23 +1372,24 @@ Blockly.WorkspaceSvg.prototype.setupDragSurface = function() { // Figure out where we want to put the canvas back. The order // in the is important because things are layered. - var previousElement = - /** @type {Element} */ (this.svgBlockCanvas_.previousSibling); - var width = parseInt(this.getParentSvg().getAttribute('width'), 10); - var height = parseInt(this.getParentSvg().getAttribute('height'), 10); - var coord = Blockly.utils.getRelativeXY(this.getCanvas()); - this.workspaceDragSurface_.setContentsAndShow(this.getCanvas(), - this.getBubbleCanvas(), previousElement, width, height, this.scale); + const previousElement = + /** @type {Element} */ (this.svgBlockCanvas_.previousSibling); + const width = parseInt(this.getParentSvg().getAttribute('width'), 10); + const height = parseInt(this.getParentSvg().getAttribute('height'), 10); + const coord = utils.getRelativeXY(this.getCanvas()); + this.workspaceDragSurface_.setContentsAndShow( + this.getCanvas(), this.getBubbleCanvas(), previousElement, width, height, + this.scale); this.workspaceDragSurface_.translateSurface(coord.x, coord.y); }; /** * Gets the drag surface blocks are moved to when a drag is started. - * @return {?Blockly.BlockDragSurfaceSvg} This workspace's block drag surface, + * @return {?BlockDragSurfaceSvg} This workspace's block drag surface, * if one is in use. * @package */ -Blockly.WorkspaceSvg.prototype.getBlockDragSurface = function() { +WorkspaceSvg.prototype.getBlockDragSurface = function() { return this.blockDragSurface_; }; @@ -1366,8 +1398,8 @@ Blockly.WorkspaceSvg.prototype.getBlockDragSurface = function() { * Intended for LTR/RTL compatibility in XML. * @return {number} Width. */ -Blockly.WorkspaceSvg.prototype.getWidth = function() { - var metrics = this.getMetrics(); +WorkspaceSvg.prototype.getWidth = function() { + const metrics = this.getMetrics(); return metrics ? metrics.viewWidth / this.scale : 0; }; @@ -1376,7 +1408,7 @@ Blockly.WorkspaceSvg.prototype.getWidth = function() { * Currently only intended for main workspace. * @param {boolean} isVisible True if workspace should be visible. */ -Blockly.WorkspaceSvg.prototype.setVisible = function(isVisible) { +WorkspaceSvg.prototype.setVisible = function(isVisible) { this.isVisible_ = isVisible; if (!this.svgGroup_) { return; @@ -1400,9 +1432,9 @@ Blockly.WorkspaceSvg.prototype.setVisible = function(isVisible) { this.toolbox_.setVisible(isVisible); } if (isVisible) { - var blocks = this.getAllBlocks(false); + const blocks = this.getAllBlocks(false); // Tell each block on the workspace to mark its fields as dirty. - for (var i = blocks.length - 1; i >= 0; i--) { + for (let i = blocks.length - 1; i >= 0; i--) { blocks[i].markDirty(); } @@ -1418,17 +1450,17 @@ Blockly.WorkspaceSvg.prototype.setVisible = function(isVisible) { /** * Render all blocks in workspace. */ -Blockly.WorkspaceSvg.prototype.render = function() { +WorkspaceSvg.prototype.render = function() { // Generate list of all blocks. - var blocks = this.getAllBlocks(false); + const blocks = this.getAllBlocks(false); // Render each block. - for (var i = blocks.length - 1; i >= 0; i--) { + for (let i = blocks.length - 1; i >= 0; i--) { blocks[i].render(false); } if (this.currentGesture_) { - var imList = this.currentGesture_.getInsertionMarkers(); - for (var i = 0; i < imList.length; i++) { + const imList = this.currentGesture_.getInsertionMarkers(); + for (let i = 0; i < imList.length; i++) { imList[i].render(false); } } @@ -1445,21 +1477,21 @@ Blockly.WorkspaceSvg.prototype.render = function() { * automatically unhighlight all others. If true or false, manually * highlight/unhighlight the specified block. */ -Blockly.WorkspaceSvg.prototype.highlightBlock = function(id, opt_state) { +WorkspaceSvg.prototype.highlightBlock = function(id, opt_state) { if (opt_state === undefined) { // Unhighlight all blocks. - for (var i = 0, block; (block = this.highlightedBlocks_[i]); i++) { + for (let i = 0, block; (block = this.highlightedBlocks_[i]); i++) { block.setHighlighted(false); } this.highlightedBlocks_.length = 0; } // Highlight/unhighlight the specified block. - var block = id ? this.getBlockById(id) : null; + const block = id ? this.getBlockById(id) : null; if (block) { - var state = (opt_state === undefined) || opt_state; + const state = (opt_state === undefined) || opt_state; // Using Set here would be great, but at the cost of IE10 support. if (!state) { - Blockly.utils.arrayRemove(this.highlightedBlocks_, block); + utils.arrayRemove(this.highlightedBlocks_, block); } else if (this.highlightedBlocks_.indexOf(block) == -1) { this.highlightedBlocks_.push(block); } @@ -1472,12 +1504,14 @@ Blockly.WorkspaceSvg.prototype.highlightBlock = function(id, opt_state) { * @param {!Element|!DocumentFragment} xmlBlock XML block element or an empty * DocumentFragment if the block was an insertion marker. */ -Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { - if (!this.rendered || !xmlBlock.tagName || xmlBlock.getElementsByTagName('block').length >= - this.remainingCapacity()) { +WorkspaceSvg.prototype.paste = function(xmlBlock) { + if (!this.rendered || !xmlBlock.tagName || + xmlBlock.getElementsByTagName('block').length >= + this.remainingCapacity()) { return; } - // The check above for tagName rules out the possibility of this being a DocumentFragment. + // The check above for tagName rules out the possibility of this being a + // DocumentFragment. xmlBlock = /** @type {!Element} */ (xmlBlock); if (this.currentGesture_) { this.currentGesture_.cancel(); // Dragging while pasting? No. @@ -1494,25 +1528,27 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { * @param {!Element} xmlBlock XML block element. * @private */ -Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { - Blockly.Events.disable(); +WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { + Events.disable(); + let block; try { - var block = Blockly.Xml.domToBlock(xmlBlock, this); + block = Xml.domToBlock(xmlBlock, this); // Move the duplicate to original position. - var blockX = parseInt(xmlBlock.getAttribute('x'), 10); - var blockY = parseInt(xmlBlock.getAttribute('y'), 10); + let blockX = parseInt(xmlBlock.getAttribute('x'), 10); + let blockY = parseInt(xmlBlock.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { if (this.RTL) { blockX = -blockX; } // Offset block until not clobbering another block and not in connection // distance with neighbouring blocks. + let collide; do { - var collide = false; - var allBlocks = this.getAllBlocks(false); - for (var i = 0, otherBlock; (otherBlock = allBlocks[i]); i++) { - var otherXY = otherBlock.getRelativeToSurfaceXY(); + collide = false; + const allBlocks = this.getAllBlocks(false); + for (let i = 0, otherBlock; (otherBlock = allBlocks[i]); i++) { + const otherXY = otherBlock.getRelativeToSurfaceXY(); if (Math.abs(blockX - otherXY.x) <= 1 && Math.abs(blockY - otherXY.y) <= 1) { collide = true; @@ -1521,11 +1557,10 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { } if (!collide) { // Check for blocks in snap range to any of its connections. - var connections = block.getConnections_(false); - for (var i = 0, connection; (connection = connections[i]); i++) { - var neighbour = connection.closest( - Blockly.internalConstants.SNAP_RADIUS, - new Blockly.utils.Coordinate(blockX, blockY)); + const connections = block.getConnections_(false); + for (let i = 0, connection; (connection = connections[i]); i++) { + const neighbour = connection.closest( + internalConstants.SNAP_RADIUS, new Coordinate(blockX, blockY)); if (neighbour.connection) { collide = true; break; @@ -1534,21 +1569,20 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { } if (collide) { if (this.RTL) { - blockX -= Blockly.internalConstants.SNAP_RADIUS; + blockX -= internalConstants.SNAP_RADIUS; } else { - blockX += Blockly.internalConstants.SNAP_RADIUS; + blockX += internalConstants.SNAP_RADIUS; } - blockY += Blockly.internalConstants.SNAP_RADIUS * 2; + blockY += internalConstants.SNAP_RADIUS * 2; } } while (collide); block.moveBy(blockX, blockY); } } finally { - Blockly.Events.enable(); + Events.enable(); } - if (Blockly.Events.isEnabled() && !block.isShadow()) { - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(block)); + if (Events.isEnabled() && !block.isShadow()) { + Events.fire(new (Events.get(Events.BLOCK_CREATE))(block)); } block.select(); }; @@ -1560,13 +1594,15 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { * @suppress {checkTypes} Suppress checks while workspace comments are not * bundled in. */ -Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { - Blockly.Events.disable(); +WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { + Events.disable(); + let comment; try { - var comment = Blockly.WorkspaceCommentSvg.fromXml(xmlComment, this); + comment = goog.module.get('Blockly.WorkspaceCommentSvg') + .fromXml(xmlComment, this); // Move the duplicate to original position. - var commentX = parseInt(xmlComment.getAttribute('x'), 10); - var commentY = parseInt(xmlComment.getAttribute('y'), 10); + let commentX = parseInt(xmlComment.getAttribute('x'), 10); + let commentY = parseInt(xmlComment.getAttribute('y'), 10); if (!isNaN(commentX) && !isNaN(commentY)) { if (this.RTL) { commentX = -commentX; @@ -1579,10 +1615,10 @@ Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { comment.moveBy(commentX, commentY); } } finally { - Blockly.Events.enable(); + Events.enable(); } - if (Blockly.Events.isEnabled()) { - Blockly.WorkspaceComment.fireCreateEvent(comment); + if (Events.isEnabled()) { + goog.module.get('Blockly.WorkspaceComment').fireCreateEvent(comment); } comment.select(); }; @@ -1591,8 +1627,8 @@ Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { * Refresh the toolbox unless there's a drag in progress. * @package */ -Blockly.WorkspaceSvg.prototype.refreshToolboxSelection = function() { - var ws = this.isFlyout ? this.targetWorkspace : this; +WorkspaceSvg.prototype.refreshToolboxSelection = function() { + const ws = this.isFlyout ? this.targetWorkspace : this; if (ws && !ws.currentGesture_ && ws.toolbox_ && ws.toolbox_.getFlyout()) { ws.toolbox_.refreshSelection(); } @@ -1604,8 +1640,8 @@ Blockly.WorkspaceSvg.prototype.refreshToolboxSelection = function() { * @param {string} id ID of the variable to rename. * @param {string} newName New variable name. */ -Blockly.WorkspaceSvg.prototype.renameVariableById = function(id, newName) { - Blockly.WorkspaceSvg.superClass_.renameVariableById.call(this, id, newName); +WorkspaceSvg.prototype.renameVariableById = function(id, newName) { + WorkspaceSvg.superClass_.renameVariableById.call(this, id, newName); this.refreshToolboxSelection(); }; @@ -1614,8 +1650,8 @@ Blockly.WorkspaceSvg.prototype.renameVariableById = function(id, newName) { * immediately that the variable is deleted. * @param {string} id ID of variable to delete. */ -Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) { - Blockly.WorkspaceSvg.superClass_.deleteVariableById.call(this, id); +WorkspaceSvg.prototype.deleteVariableById = function(id) { + WorkspaceSvg.superClass_.deleteVariableById.call(this, id); this.refreshToolboxSelection(); }; @@ -1628,11 +1664,10 @@ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) { * 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 {!Blockly.VariableModel} The newly created variable. + * @return {!VariableModel} The newly created variable. */ -Blockly.WorkspaceSvg.prototype.createVariable = function(name, - opt_type, opt_id) { - var newVar = Blockly.WorkspaceSvg.superClass_.createVariable.call( +WorkspaceSvg.prototype.createVariable = function(name, opt_type, opt_id) { + const newVar = WorkspaceSvg.superClass_.createVariable.call( this, name, opt_type, opt_id); this.refreshToolboxSelection(); return newVar; @@ -1642,11 +1677,9 @@ Blockly.WorkspaceSvg.prototype.createVariable = function(name, * Make a list of all the delete areas for this workspace. * @deprecated Use workspace.recordDragTargets. (2021 June) */ -Blockly.WorkspaceSvg.prototype.recordDeleteAreas = function() { - Blockly.utils.deprecation.warn( - 'WorkspaceSvg.prototype.recordDeleteAreas', - 'June 2021', - 'June 2022', +WorkspaceSvg.prototype.recordDeleteAreas = function() { + utils.deprecation.warn( + 'WorkspaceSvg.prototype.recordDeleteAreas', 'June 2021', 'June 2022', 'WorkspaceSvg.prototype.recordDragTargets'); this.recordDragTargets(); }; @@ -1654,13 +1687,13 @@ Blockly.WorkspaceSvg.prototype.recordDeleteAreas = function() { /** * Make a list of all the delete areas for this workspace. */ -Blockly.WorkspaceSvg.prototype.recordDragTargets = function() { - var dragTargets = this.componentManager_.getComponents( - Blockly.ComponentManager.Capability.DRAG_TARGET, true); +WorkspaceSvg.prototype.recordDragTargets = function() { + const dragTargets = this.componentManager_.getComponents( + ComponentManager.Capability.DRAG_TARGET, true); this.dragTargetAreas_ = []; - for (var i = 0, targetArea; (targetArea = dragTargets[i]); i++) { - var rect = targetArea.getClientRect(); + for (let i = 0, targetArea; (targetArea = dragTargets[i]); i++) { + const rect = targetArea.getClientRect(); if (rect) { this.dragTargetAreas_.push({ component: targetArea, @@ -1674,11 +1707,11 @@ Blockly.WorkspaceSvg.prototype.recordDragTargets = function() { /** * Returns the drag target the mouse event is over. * @param {!Event} e Mouse move event. - * @return {?Blockly.IDragTarget} Null if not over a drag target, or the drag + * @return {?IDragTarget} Null if not over a drag target, or the drag * target the event is over. */ -Blockly.WorkspaceSvg.prototype.getDragTarget = function(e) { - for (var i = 0, targetArea; (targetArea = this.dragTargetAreas_[i]); i++) { +WorkspaceSvg.prototype.getDragTarget = function(e) { + for (let i = 0, targetArea; (targetArea = this.dragTargetAreas_[i]); i++) { if (targetArea.clientRect.contains(e.clientX, e.clientY)) { return targetArea.component; } @@ -1691,8 +1724,8 @@ Blockly.WorkspaceSvg.prototype.getDragTarget = function(e) { * @param {!Event} e Mouse down event. * @private */ -Blockly.WorkspaceSvg.prototype.onMouseDown_ = function(e) { - var gesture = this.getGesture(e); +WorkspaceSvg.prototype.onMouseDown_ = function(e) { + const gesture = this.getGesture(e); if (gesture) { gesture.handleWsStart(e, this); } @@ -1701,38 +1734,38 @@ Blockly.WorkspaceSvg.prototype.onMouseDown_ = function(e) { /** * Start tracking a drag of an object on this workspace. * @param {!Event} e Mouse down event. - * @param {!Blockly.utils.Coordinate} xy Starting location of object. + * @param {!Coordinate} xy Starting location of object. */ -Blockly.WorkspaceSvg.prototype.startDrag = function(e, xy) { +WorkspaceSvg.prototype.startDrag = function(e, xy) { // Record the starting offset between the bubble's location and the mouse. - var point = Blockly.utils.mouseToSvg(e, this.getParentSvg(), - this.getInverseScreenCTM()); + const point = + utils.mouseToSvg(e, this.getParentSvg(), this.getInverseScreenCTM()); // Fix scale of mouse event. point.x /= this.scale; point.y /= this.scale; - this.dragDeltaXY_ = Blockly.utils.Coordinate.difference(xy, point); + this.dragDeltaXY_ = Coordinate.difference(xy, point); }; /** * Track a drag of an object on this workspace. * @param {!Event} e Mouse move event. - * @return {!Blockly.utils.Coordinate} New location of object. + * @return {!Coordinate} New location of object. */ -Blockly.WorkspaceSvg.prototype.moveDrag = function(e) { - var point = Blockly.utils.mouseToSvg(e, this.getParentSvg(), - this.getInverseScreenCTM()); +WorkspaceSvg.prototype.moveDrag = function(e) { + const point = + utils.mouseToSvg(e, this.getParentSvg(), this.getInverseScreenCTM()); // Fix scale of mouse event. point.x /= this.scale; point.y /= this.scale; - return Blockly.utils.Coordinate.sum( - /** @type {!Blockly.utils.Coordinate} */ (this.dragDeltaXY_), point); + return Coordinate.sum( + /** @type {!Coordinate} */ (this.dragDeltaXY_), point); }; /** * Is the user currently dragging a block or scrolling the flyout/workspace? * @return {boolean} True if currently dragging or scrolling. */ -Blockly.WorkspaceSvg.prototype.isDragging = function() { +WorkspaceSvg.prototype.isDragging = function() { return this.currentGesture_ != null && this.currentGesture_.isDragging(); }; @@ -1740,7 +1773,7 @@ Blockly.WorkspaceSvg.prototype.isDragging = function() { * Is this workspace draggable? * @return {boolean} True if this workspace may be dragged. */ -Blockly.WorkspaceSvg.prototype.isDraggable = function() { +WorkspaceSvg.prototype.isDraggable = function() { return this.options.moveOptions && this.options.moveOptions.drag; }; @@ -1754,7 +1787,7 @@ Blockly.WorkspaceSvg.prototype.isDraggable = function() { * since the X Y coordinates are decided programmatically. * @return {boolean} True if the workspace is movable, false otherwise. */ -Blockly.WorkspaceSvg.prototype.isMovable = function() { +WorkspaceSvg.prototype.isMovable = function() { return (this.options.moveOptions && !!this.options.moveOptions.scrollbars) || (this.options.moveOptions && this.options.moveOptions.wheel) || (this.options.moveOptions && this.options.moveOptions.drag) || @@ -1767,10 +1800,11 @@ Blockly.WorkspaceSvg.prototype.isMovable = function() { * @return {boolean} True if the workspace is movable horizontally, false * otherwise. */ -Blockly.WorkspaceSvg.prototype.isMovableHorizontally = function() { - var hasScrollbars = !!this.scrollbar; - return this.isMovable() && (!hasScrollbars || - (hasScrollbars && this.scrollbar.canScrollHorizontally())); +WorkspaceSvg.prototype.isMovableHorizontally = function() { + const hasScrollbars = !!this.scrollbar; + return this.isMovable() && + (!hasScrollbars || + (hasScrollbars && this.scrollbar.canScrollHorizontally())); }; /** @@ -1778,10 +1812,11 @@ Blockly.WorkspaceSvg.prototype.isMovableHorizontally = function() { * @return {boolean} True if the workspace is movable vertically, false * otherwise. */ -Blockly.WorkspaceSvg.prototype.isMovableVertically = function() { - var hasScrollbars = !!this.scrollbar; - return this.isMovable() && (!hasScrollbars || - (hasScrollbars && this.scrollbar.canScrollVertically())); +WorkspaceSvg.prototype.isMovableVertically = function() { + const hasScrollbars = !!this.scrollbar; + return this.isMovable() && + (!hasScrollbars || + (hasScrollbars && this.scrollbar.canScrollVertically())); }; /** @@ -1789,33 +1824,35 @@ Blockly.WorkspaceSvg.prototype.isMovableVertically = function() { * @param {!Event} e Mouse wheel event. * @private */ -Blockly.WorkspaceSvg.prototype.onMouseWheel_ = function(e) { +WorkspaceSvg.prototype.onMouseWheel_ = function(e) { // Don't scroll or zoom anything if drag is in progress. - if (Blockly.Gesture.inProgress()) { + if (Gesture.inProgress()) { e.preventDefault(); e.stopPropagation(); return; } - var canWheelZoom = this.options.zoomOptions && this.options.zoomOptions.wheel; - var canWheelMove = this.options.moveOptions && this.options.moveOptions.wheel; + const canWheelZoom = + this.options.zoomOptions && this.options.zoomOptions.wheel; + const canWheelMove = + this.options.moveOptions && this.options.moveOptions.wheel; if (!canWheelZoom && !canWheelMove) { return; } - var scrollDelta = Blockly.utils.getScrollDeltaPixels(e); + const scrollDelta = utils.getScrollDeltaPixels(e); if (canWheelZoom && (e.ctrlKey || !canWheelMove)) { // Zoom. // The vertical scroll distance that corresponds to a click of a zoom // button. - var PIXELS_PER_ZOOM_STEP = 50; - var delta = -scrollDelta.y / PIXELS_PER_ZOOM_STEP; - var position = Blockly.utils.mouseToSvg(e, this.getParentSvg(), - this.getInverseScreenCTM()); + const PIXELS_PER_ZOOM_STEP = 50; + const delta = -scrollDelta.y / PIXELS_PER_ZOOM_STEP; + const position = + utils.mouseToSvg(e, this.getParentSvg(), this.getInverseScreenCTM()); this.zoom(position.x, position.y, delta); } else { // Scroll. - var x = this.scrollX - scrollDelta.x; - var y = this.scrollY - scrollDelta.y; + let x = this.scrollX - scrollDelta.x; + let y = this.scrollY - scrollDelta.y; if (e.shiftKey && !scrollDelta.x) { // Scroll horizontally (based on vertical scroll delta). @@ -1833,26 +1870,26 @@ Blockly.WorkspaceSvg.prototype.onMouseWheel_ = function(e) { * Calculate the bounding box for the blocks on the workspace. * Coordinate system: workspace coordinates. * - * @return {!Blockly.utils.Rect} Contains the position and size of the + * @return {!Rect} Contains the position and size of the * bounding box containing the blocks on the workspace. */ -Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { - var topElements = this.getTopBoundedElements(); +WorkspaceSvg.prototype.getBlocksBoundingBox = function() { + const topElements = this.getTopBoundedElements(); // There are no blocks, return empty rectangle. if (!topElements.length) { - return new Blockly.utils.Rect(0, 0, 0, 0); + return new Rect(0, 0, 0, 0); } // Initialize boundary using the first block. - var boundary = topElements[0].getBoundingRectangle(); + const boundary = topElements[0].getBoundingRectangle(); // Start at 1 since the 0th block was used for initialization. - for (var i = 1; i < topElements.length; i++) { - var topElement = topElements[i]; + for (let i = 1; i < topElements.length; i++) { + const topElement = topElements[i]; if (topElement.isInsertionMarker && topElement.isInsertionMarker()) { continue; } - var blockBoundary = topElement.getBoundingRectangle(); + const blockBoundary = topElement.getBoundingRectangle(); if (blockBoundary.top < boundary.top) { boundary.top = blockBoundary.top; } @@ -1872,23 +1909,22 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { /** * Clean up the workspace by ordering all the blocks in a column. */ -Blockly.WorkspaceSvg.prototype.cleanUp = function() { +WorkspaceSvg.prototype.cleanUp = function() { this.setResizesEnabled(false); - Blockly.Events.setGroup(true); - var topBlocks = this.getTopBlocks(true); - var cursorY = 0; - for (var i = 0, block; (block = topBlocks[i]); i++) { + Events.setGroup(true); + const topBlocks = this.getTopBlocks(true); + let cursorY = 0; + for (let i = 0, block; (block = topBlocks[i]); i++) { if (!block.isMovable()) { continue; } - var xy = block.getRelativeToSurfaceXY(); + const xy = block.getRelativeToSurfaceXY(); block.moveBy(-xy.x, cursorY - xy.y); block.snapToGrid(); - cursorY = block.getRelativeToSurfaceXY().y + - block.getHeightWidth().height + + cursorY = block.getRelativeToSurfaceXY().y + block.getHeightWidth().height + this.renderer_.getConstants().MIN_BLOCK_HEIGHT; } - Blockly.Events.setGroup(false); + Events.setGroup(false); this.setResizesEnabled(true); }; @@ -1897,29 +1933,29 @@ Blockly.WorkspaceSvg.prototype.cleanUp = function() { * @param {!Event} e Mouse event. * @package */ -Blockly.WorkspaceSvg.prototype.showContextMenu = function(e) { +WorkspaceSvg.prototype.showContextMenu = function(e) { if (this.options.readOnly || this.isFlyout) { return; } - var menuOptions = Blockly.ContextMenuRegistry.registry.getContextMenuOptions( - Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, {workspace: this}); + const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( + ContextMenuRegistry.ScopeType.WORKSPACE, {workspace: this}); // Allow the developer to add or modify menuOptions. if (this.configureContextMenu) { this.configureContextMenu(menuOptions, e); } - Blockly.ContextMenu.show(e, menuOptions, this.RTL); + ContextMenu.show(e, menuOptions, this.RTL); }; /** * Modify the block tree on the existing toolbox. - * @param {?Blockly.utils.toolbox.ToolboxDefinition} toolboxDef + * @param {?toolbox.ToolboxDefinition} toolboxDef * DOM tree of toolbox contents, string of toolbox contents, or JSON * representing toolbox definition. */ -Blockly.WorkspaceSvg.prototype.updateToolbox = function(toolboxDef) { - var parsedToolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(toolboxDef); +WorkspaceSvg.prototype.updateToolbox = function(toolboxDef) { + const parsedToolboxDef = toolbox.convertToolboxDefToJson(toolboxDef); if (!parsedToolboxDef) { if (this.options.languageTree) { @@ -1931,7 +1967,7 @@ Blockly.WorkspaceSvg.prototype.updateToolbox = function(toolboxDef) { throw Error('Existing toolbox is null. Can\'t create new toolbox.'); } - if (Blockly.utils.toolbox.hasCategories(parsedToolboxDef)) { + if (toolbox.hasCategories(parsedToolboxDef)) { if (!this.toolbox_) { throw Error('Existing toolbox has no categories. Can\'t change mode.'); } @@ -1949,11 +1985,11 @@ Blockly.WorkspaceSvg.prototype.updateToolbox = function(toolboxDef) { /** * Mark this workspace as the currently focused main workspace. */ -Blockly.WorkspaceSvg.prototype.markFocused = function() { +WorkspaceSvg.prototype.markFocused = function() { if (this.options.parentWorkspace) { this.options.parentWorkspace.markFocused(); } else { - Blockly.mainWorkspace = this; + common.setMainWorkspace(this); // We call e.preventDefault in many event handlers which means we // need to explicitly grab focus (e.g from a textarea) because // the browser will not do it for us. How to do this is browser dependent. @@ -1965,7 +2001,7 @@ Blockly.WorkspaceSvg.prototype.markFocused = function() { * Set the workspace to have focus in the browser. * @private */ -Blockly.WorkspaceSvg.prototype.setBrowserFocus = function() { +WorkspaceSvg.prototype.setBrowserFocus = function() { // Blur whatever was focused since explicitly grabbing focus below does not // work in Edge. // In IE, SVGs can't be blurred or focused. Check to make sure the current @@ -1976,7 +2012,7 @@ Blockly.WorkspaceSvg.prototype.setBrowserFocus = function() { } try { // Focus the workspace SVG - this is for Chrome and Firefox. - this.getParentSvg().focus({preventScroll:true}); + this.getParentSvg().focus({preventScroll: true}); } catch (e) { // IE and Edge do not support focus on SVG elements. When that fails // above, get the injectionDiv (the workspace's parent) and focus that @@ -1988,7 +2024,7 @@ Blockly.WorkspaceSvg.prototype.setBrowserFocus = function() { } catch (e) { // setActive support was discontinued in Edge so when that fails, call // focus instead. - this.getParentSvg().parentNode.focus({preventScroll:true}); + this.getParentSvg().parentNode.focus({preventScroll: true}); } } }; @@ -2005,11 +2041,11 @@ Blockly.WorkspaceSvg.prototype.setBrowserFocus = function() { * the workspace options. Negative amount values zoom out, and positive * amount values zoom in. */ -Blockly.WorkspaceSvg.prototype.zoom = function(x, y, amount) { +WorkspaceSvg.prototype.zoom = function(x, y, amount) { // Scale factor. - var speed = this.options.zoomOptions.scaleSpeed; - var scaleChange = Math.pow(speed, amount); - var newScale = this.scale * scaleChange; + const speed = this.options.zoomOptions.scaleSpeed; + let scaleChange = Math.pow(speed, amount); + const newScale = this.scale * scaleChange; if (this.scale == newScale) { return; // No change in zoom. } @@ -2024,8 +2060,8 @@ Blockly.WorkspaceSvg.prototype.zoom = function(x, y, amount) { // Transform the x/y coordinates from the parentSVG's space into the // canvas' space, so that they are in workspace units relative to the top // left of the visible portion of the workspace. - var matrix = this.getCanvas().getCTM(); - var center = this.getParentSvg().createSVGPoint(); + let matrix = this.getCanvas().getCTM(); + let center = this.getParentSvg().createSVGPoint(); center.x = x; center.y = y; center = center.matrixTransform(matrix.inverse()); @@ -2036,7 +2072,7 @@ Blockly.WorkspaceSvg.prototype.zoom = function(x, y, amount) { // position (relative to the center) after we zoom. // newScale and matrix.a should be identical (within a rounding error). matrix = matrix.translate(x * (1 - scaleChange), y * (1 - scaleChange)) - .scale(scaleChange); + .scale(scaleChange); // scrollX and scrollY are in pixels. // The scrollX and scrollY still need to have absoluteLeft and absoluteTop // subtracted from them, but we'll leave that for setScale so that they're @@ -2050,19 +2086,21 @@ Blockly.WorkspaceSvg.prototype.zoom = function(x, y, amount) { * Zooming the blocks centered in the center of view with zooming in or out. * @param {number} type Type of zooming (-1 zooming out and 1 zooming in). */ -Blockly.WorkspaceSvg.prototype.zoomCenter = function(type) { - var metrics = this.getMetrics(); +WorkspaceSvg.prototype.zoomCenter = function(type) { + const metrics = this.getMetrics(); + let x; + let y; if (this.flyout_) { // If you want blocks in the center of the view (visible portion of the // workspace) to stay centered when the size of the view decreases (i.e. // when the size of the flyout increases) you need the center of the // *blockly div* to stay in the same pixel-position. // Note: This only works because of how scrollCenter positions blocks. - var x = metrics.svgWidth ? metrics.svgWidth / 2 : 0; - var y = metrics.svgHeight ? metrics.svgHeight / 2 : 0; + x = metrics.svgWidth ? metrics.svgWidth / 2 : 0; + y = metrics.svgHeight ? metrics.svgHeight / 2 : 0; } else { - var x = (metrics.viewWidth / 2) + metrics.absoluteLeft; - var y = (metrics.viewHeight / 2) + metrics.absoluteTop; + x = (metrics.viewWidth / 2) + metrics.absoluteLeft; + y = (metrics.viewHeight / 2) + metrics.absoluteTop; } this.zoom(x, y, type); }; @@ -2070,19 +2108,20 @@ Blockly.WorkspaceSvg.prototype.zoomCenter = function(type) { /** * Zoom the blocks to fit in the workspace if possible. */ -Blockly.WorkspaceSvg.prototype.zoomToFit = function() { +WorkspaceSvg.prototype.zoomToFit = function() { if (!this.isMovable()) { - console.warn('Tried to move a non-movable workspace. This could result' + + console.warn( + 'Tried to move a non-movable workspace. This could result' + ' in blocks becoming inaccessible.'); return; } - var metrics = this.getMetrics(); - var workspaceWidth = metrics.viewWidth; - var workspaceHeight = metrics.viewHeight; - var blocksBox = this.getBlocksBoundingBox(); - var blocksWidth = blocksBox.right - blocksBox.left; - var blocksHeight = blocksBox.bottom - blocksBox.top; + const metrics = this.getMetrics(); + let workspaceWidth = metrics.viewWidth; + let workspaceHeight = metrics.viewHeight; + const blocksBox = this.getBlocksBoundingBox(); + let blocksWidth = blocksBox.right - blocksBox.left; + let blocksHeight = blocksBox.bottom - blocksBox.top; if (!blocksWidth) { return; // Prevents zooming to infinity. } @@ -2103,14 +2142,14 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() { } // Scale Units: (pixels / workspaceUnit) - var ratioX = workspaceWidth / blocksWidth; - var ratioY = workspaceHeight / blocksHeight; - Blockly.Events.disable(); + const ratioX = workspaceWidth / blocksWidth; + const ratioY = workspaceHeight / blocksHeight; + Events.disable(); try { this.setScale(Math.min(ratioX, ratioY)); this.scrollCenter(); } finally { - Blockly.Events.enable(); + Events.enable(); } this.maybeFireViewportChangeEvent(); }; @@ -2120,11 +2159,11 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() { * transform changes. * @package */ -Blockly.WorkspaceSvg.prototype.beginCanvasTransition = function() { - Blockly.utils.dom.addClass( +WorkspaceSvg.prototype.beginCanvasTransition = function() { + dom.addClass( /** @type {!SVGElement} */ (this.svgBlockCanvas_), 'blocklyCanvasTransitioning'); - Blockly.utils.dom.addClass( + dom.addClass( /** @type {!SVGElement} */ (this.svgBubbleCanvas_), 'blocklyCanvasTransitioning'); }; @@ -2133,11 +2172,11 @@ Blockly.WorkspaceSvg.prototype.beginCanvasTransition = function() { * Remove transition class from the block and bubble canvas. * @package */ -Blockly.WorkspaceSvg.prototype.endCanvasTransition = function() { - Blockly.utils.dom.removeClass( +WorkspaceSvg.prototype.endCanvasTransition = function() { + dom.removeClass( /** @type {!SVGElement} */ (this.svgBlockCanvas_), 'blocklyCanvasTransitioning'); - Blockly.utils.dom.removeClass( + dom.removeClass( /** @type {!SVGElement} */ (this.svgBubbleCanvas_), 'blocklyCanvasTransitioning'); }; @@ -2145,16 +2184,17 @@ Blockly.WorkspaceSvg.prototype.endCanvasTransition = function() { /** * Center the workspace. */ -Blockly.WorkspaceSvg.prototype.scrollCenter = function() { +WorkspaceSvg.prototype.scrollCenter = function() { if (!this.isMovable()) { - console.warn('Tried to move a non-movable workspace. This could result' + + console.warn( + 'Tried to move a non-movable workspace. This could result' + ' in blocks becoming inaccessible.'); return; } - var metrics = this.getMetrics(); - var x = (metrics.scrollWidth - metrics.viewWidth) / 2; - var y = (metrics.scrollHeight - metrics.viewHeight) / 2; + const metrics = this.getMetrics(); + let x = (metrics.scrollWidth - metrics.viewWidth) / 2; + let y = (metrics.scrollHeight - metrics.viewHeight) / 2; // Convert from workspace directions to canvas directions. x = -x - metrics.scrollLeft; @@ -2167,52 +2207,53 @@ Blockly.WorkspaceSvg.prototype.scrollCenter = function() { * @param {?string} id ID of block center on. * @public */ -Blockly.WorkspaceSvg.prototype.centerOnBlock = function(id) { +WorkspaceSvg.prototype.centerOnBlock = function(id) { if (!this.isMovable()) { - console.warn('Tried to move a non-movable workspace. This could result' + + console.warn( + 'Tried to move a non-movable workspace. This could result' + ' in blocks becoming inaccessible.'); return; } - var block = id ? this.getBlockById(id) : null; + const block = id ? this.getBlockById(id) : null; if (!block) { return; } // XY is in workspace coordinates. - var xy = block.getRelativeToSurfaceXY(); + const xy = block.getRelativeToSurfaceXY(); // Height/width is in workspace units. - var heightWidth = block.getHeightWidth(); + const heightWidth = block.getHeightWidth(); // Find the enter of the block in workspace units. - var blockCenterY = xy.y + heightWidth.height / 2; + const blockCenterY = xy.y + heightWidth.height / 2; // In RTL the block's position is the top right of the block, not top left. - var multiplier = this.RTL ? -1 : 1; - var blockCenterX = xy.x + (multiplier * heightWidth.width / 2); + const multiplier = this.RTL ? -1 : 1; + const blockCenterX = xy.x + (multiplier * heightWidth.width / 2); // Workspace scale, used to convert from workspace coordinates to pixels. - var scale = this.scale; + const scale = this.scale; // Center of block in pixels, relative to workspace origin (center 0,0). // Scrolling to here would put the block in the top-left corner of the // visible workspace. - var pixelX = blockCenterX * scale; - var pixelY = blockCenterY * scale; + const pixelX = blockCenterX * scale; + const pixelY = blockCenterY * scale; - var metrics = this.getMetrics(); + const metrics = this.getMetrics(); // viewHeight and viewWidth are in pixels. - var halfViewWidth = metrics.viewWidth / 2; - var halfViewHeight = metrics.viewHeight / 2; + const halfViewWidth = metrics.viewWidth / 2; + const halfViewHeight = metrics.viewHeight / 2; // Put the block in the center of the visible workspace instead. - var scrollToCenterX = pixelX - halfViewWidth; - var scrollToCenterY = pixelY - halfViewHeight; + const scrollToCenterX = pixelX - halfViewWidth; + const scrollToCenterY = pixelY - halfViewHeight; // Convert from workspace directions to canvas directions. - var x = -scrollToCenterX; - var y = -scrollToCenterY; + const x = -scrollToCenterX; + const y = -scrollToCenterY; this.scroll(x, y); }; @@ -2221,11 +2262,12 @@ Blockly.WorkspaceSvg.prototype.centerOnBlock = function(id) { * Set the workspace's zoom factor. * @param {number} newScale Zoom factor. Units: (pixels / workspaceUnit). */ -Blockly.WorkspaceSvg.prototype.setScale = function(newScale) { +WorkspaceSvg.prototype.setScale = function(newScale) { if (this.options.zoomOptions.maxScale && newScale > this.options.zoomOptions.maxScale) { newScale = this.options.zoomOptions.maxScale; - } else if (this.options.zoomOptions.minScale && + } else if ( + this.options.zoomOptions.minScale && newScale < this.options.zoomOptions.minScale) { newScale = this.options.zoomOptions.minScale; } @@ -2233,7 +2275,7 @@ Blockly.WorkspaceSvg.prototype.setScale = function(newScale) { Blockly.hideChaff(false); // Get the flyout, if any, whether our own or owned by the toolbox. - var flyout = this.getFlyout(false); + const flyout = this.getFlyout(false); if (flyout && flyout.isVisible()) { flyout.reflow(); this.recordDragTargets(); @@ -2245,7 +2287,7 @@ Blockly.WorkspaceSvg.prototype.setScale = function(newScale) { // We call scroll instead of scrollbar.resize() so that we can center the // zoom correctly without scrollbars, but scroll does not resize the // scrollbars so we have to call resizeView/resizeContent as well. - var metrics = this.getMetrics(); + const metrics = this.getMetrics(); this.scrollX -= metrics.absoluteLeft; this.scrollY -= metrics.absoluteTop; @@ -2270,7 +2312,7 @@ Blockly.WorkspaceSvg.prototype.setScale = function(newScale) { * the parent to get the workspace scale. * @return {number} The workspace zoom factor. Units: (pixels / workspaceUnit). */ -Blockly.WorkspaceSvg.prototype.getScale = function() { +WorkspaceSvg.prototype.getScale = function() { if (this.options.parentWorkspace) { return this.options.parentWorkspace.getScale(); } @@ -2285,19 +2327,20 @@ Blockly.WorkspaceSvg.prototype.getScale = function() { * @param {number} y Target Y to scroll to. * @package */ -Blockly.WorkspaceSvg.prototype.scroll = function(x, y) { +WorkspaceSvg.prototype.scroll = function(x, y) { Blockly.hideChaff(/* opt_onlyClosePopups */ true); // Keep scrolling within the bounds of the content. - var metrics = this.getMetrics(); + const metrics = this.getMetrics(); // Canvas coordinates (aka scroll coordinates) have inverse directionality // to workspace coordinates so we have to inverse them. x = Math.min(x, -metrics.scrollLeft); y = Math.min(y, -metrics.scrollTop); - var maxXDisplacement = Math.max(0, metrics.scrollWidth - metrics.viewWidth); - var maxXScroll = metrics.scrollLeft + maxXDisplacement; - var maxYDisplacement = Math.max(0, metrics.scrollHeight - metrics.viewHeight); - var maxYScroll = metrics.scrollTop + maxYDisplacement; + const maxXDisplacement = Math.max(0, metrics.scrollWidth - metrics.viewWidth); + const maxXScroll = metrics.scrollLeft + maxXDisplacement; + const maxYDisplacement = + Math.max(0, metrics.scrollHeight - metrics.viewHeight); + const maxYScroll = metrics.scrollTop + maxYDisplacement; x = Math.max(x, -maxXScroll); y = Math.max(y, -maxYScroll); this.scrollX = x; @@ -2325,25 +2368,25 @@ Blockly.WorkspaceSvg.prototype.scroll = function(x, y) { * @param {!Object} xyRatio Contains an x and/or y property which is a float * between 0 and 1 specifying the degree of scrolling. * @private - * @this {Blockly.WorkspaceSvg} + * @this {WorkspaceSvg} */ -Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { - var metrics = this.getMetrics(); +WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { + const metrics = this.getMetrics(); if (typeof xyRatio.x == 'number') { this.scrollX = -(metrics.scrollLeft + - (metrics.scrollWidth - metrics.viewWidth) * xyRatio.x); + (metrics.scrollWidth - metrics.viewWidth) * xyRatio.x); } if (typeof xyRatio.y == 'number') { this.scrollY = -(metrics.scrollTop + - (metrics.scrollHeight - metrics.viewHeight) * xyRatio.y); + (metrics.scrollHeight - metrics.viewHeight) * xyRatio.y); } // We have to shift the translation so that when the canvas is at 0, 0 the // workspace origin is not underneath the toolbox. - var x = this.scrollX + metrics.absoluteLeft; - var y = this.scrollY + metrics.absoluteTop; + const x = this.scrollX + metrics.absoluteLeft; + const y = this.scrollY + metrics.absoluteTop; // We could call scroll here, but that has extra checks we don't need to do. this.translate(x, y); }; @@ -2351,84 +2394,84 @@ Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { /** * Find the block on this workspace with the specified ID. * @param {string} id ID of block to find. - * @return {?Blockly.BlockSvg} The sought after block, or null if not found. + * @return {?BlockSvg} The sought after block, or null if not found. * @override */ -Blockly.WorkspaceSvg.prototype.getBlockById = function(id) { - return /** @type {Blockly.BlockSvg} */ ( - Blockly.WorkspaceSvg.superClass_.getBlockById.call(this, id)); +WorkspaceSvg.prototype.getBlockById = function(id) { + return /** @type {BlockSvg} */ ( + WorkspaceSvg.superClass_.getBlockById.call(this, id)); }; /** * 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. + * @return {!Array} The top-level block objects. * @override */ -Blockly.WorkspaceSvg.prototype.getTopBlocks = function(ordered) { - return Blockly.WorkspaceSvg.superClass_.getTopBlocks.call(this, ordered); +WorkspaceSvg.prototype.getTopBlocks = function(ordered) { + return WorkspaceSvg.superClass_.getTopBlocks.call(this, ordered); }; /** * Adds a block to the list of top blocks. - * @param {!Blockly.Block} block Block to add. + * @param {!Block} block Block to add. */ -Blockly.WorkspaceSvg.prototype.addTopBlock = function(block) { - this.addTopBoundedElement(/** @type {!Blockly.BlockSvg} */ (block)); - Blockly.WorkspaceSvg.superClass_.addTopBlock.call(this, block); +WorkspaceSvg.prototype.addTopBlock = function(block) { + this.addTopBoundedElement(/** @type {!BlockSvg} */ (block)); + WorkspaceSvg.superClass_.addTopBlock.call(this, block); }; /** * Removes a block from the list of top blocks. - * @param {!Blockly.Block} block Block to remove. + * @param {!Block} block Block to remove. */ -Blockly.WorkspaceSvg.prototype.removeTopBlock = function(block) { - this.removeTopBoundedElement(/** @type {!Blockly.BlockSvg} */ (block)); - Blockly.WorkspaceSvg.superClass_.removeTopBlock.call(this, block); +WorkspaceSvg.prototype.removeTopBlock = function(block) { + this.removeTopBoundedElement(/** @type {!BlockSvg} */ (block)); + WorkspaceSvg.superClass_.removeTopBlock.call(this, block); }; /** * Adds a comment to the list of top comments. - * @param {!Blockly.WorkspaceComment} comment comment to add. + * @param {!WorkspaceComment} comment comment to add. */ -Blockly.WorkspaceSvg.prototype.addTopComment = function(comment) { +WorkspaceSvg.prototype.addTopComment = function(comment) { this.addTopBoundedElement( - /** @type {!Blockly.WorkspaceCommentSvg} */ (comment)); - Blockly.WorkspaceSvg.superClass_.addTopComment.call(this, comment); + /** @type {!WorkspaceCommentSvg} */ (comment)); + WorkspaceSvg.superClass_.addTopComment.call(this, comment); }; /** * Removes a comment from the list of top comments. - * @param {!Blockly.WorkspaceComment} comment comment to remove. + * @param {!WorkspaceComment} comment comment to remove. */ -Blockly.WorkspaceSvg.prototype.removeTopComment = function(comment) { +WorkspaceSvg.prototype.removeTopComment = function(comment) { this.removeTopBoundedElement( - /** @type {!Blockly.WorkspaceCommentSvg} */ (comment)); - Blockly.WorkspaceSvg.superClass_.removeTopComment.call(this, comment); + /** @type {!WorkspaceCommentSvg} */ (comment)); + WorkspaceSvg.superClass_.removeTopComment.call(this, comment); }; /** * Adds a bounded element to the list of top bounded elements. - * @param {!Blockly.IBoundedElement} element Bounded element to add. + * @param {!IBoundedElement} element Bounded element to add. */ -Blockly.WorkspaceSvg.prototype.addTopBoundedElement = function(element) { +WorkspaceSvg.prototype.addTopBoundedElement = function(element) { this.topBoundedElements_.push(element); }; /** * Removes a bounded element from the list of top bounded elements. - * @param {!Blockly.IBoundedElement} element Bounded element to remove. + * @param {!IBoundedElement} element Bounded element to remove. */ -Blockly.WorkspaceSvg.prototype.removeTopBoundedElement = function(element) { - Blockly.utils.arrayRemove(this.topBoundedElements_, element); +WorkspaceSvg.prototype.removeTopBoundedElement = function(element) { + utils.arrayRemove(this.topBoundedElements_, element); }; /** * Finds the top-level bounded elements and returns them. - * @return {!Array} The top-level bounded elements. + * @return {!Array} The top-level bounded elements. */ -Blockly.WorkspaceSvg.prototype.getTopBoundedElements = function() { +WorkspaceSvg.prototype.getTopBoundedElements = function() { return [].concat(this.topBoundedElements_); }; @@ -2439,8 +2482,8 @@ Blockly.WorkspaceSvg.prototype.getTopBoundedElements = function() { * Use to avoid resizing during a batch operation, for performance. * @param {boolean} enabled Whether resizes should be enabled. */ -Blockly.WorkspaceSvg.prototype.setResizesEnabled = function(enabled) { - var reenabled = (!this.resizesEnabled_ && enabled); +WorkspaceSvg.prototype.setResizesEnabled = function(enabled) { + const reenabled = (!this.resizesEnabled_ && enabled); this.resizesEnabled_ = enabled; if (reenabled) { // Newly enabled. Trigger a resize. @@ -2451,9 +2494,9 @@ Blockly.WorkspaceSvg.prototype.setResizesEnabled = function(enabled) { /** * Dispose of all blocks in workspace, with an optimization to prevent resizes. */ -Blockly.WorkspaceSvg.prototype.clear = function() { +WorkspaceSvg.prototype.clear = function() { this.setResizesEnabled(false); - Blockly.WorkspaceSvg.superClass_.clear.call(this); + WorkspaceSvg.superClass_.clear.call(this); this.topBoundedElements_ = []; this.setResizesEnabled(true); }; @@ -2466,10 +2509,10 @@ Blockly.WorkspaceSvg.prototype.clear = function() { * should be matched by a call to * registerButtonCallback("CREATE_VARIABLE", yourCallbackFunction). * @param {string} key The name to use to look up this function. - * @param {function(!Blockly.FlyoutButton)} func The function to call when the + * @param {function(!FlyoutButton)} func The function to call when the * given button is clicked. */ -Blockly.WorkspaceSvg.prototype.registerButtonCallback = function(key, func) { +WorkspaceSvg.prototype.registerButtonCallback = function(key, func) { if (typeof func != 'function') { throw TypeError('Button callbacks must be functions.'); } @@ -2480,11 +2523,11 @@ Blockly.WorkspaceSvg.prototype.registerButtonCallback = function(key, func) { * Get the callback function associated with a given key, for clicks on buttons * and labels in the flyout. * @param {string} key The name to use to look up the function. - * @return {?function(!Blockly.FlyoutButton)} The function corresponding to the + * @return {?function(!FlyoutButton)} The function corresponding to the * given key for this workspace; null if no callback is registered. */ -Blockly.WorkspaceSvg.prototype.getButtonCallback = function(key) { - var result = this.flyoutButtonCallbacks_[key]; +WorkspaceSvg.prototype.getButtonCallback = function(key) { + const result = this.flyoutButtonCallbacks_[key]; return result ? result : null; }; @@ -2492,7 +2535,7 @@ Blockly.WorkspaceSvg.prototype.getButtonCallback = function(key) { * Remove a callback for a click on a button in the flyout. * @param {string} key The name associated with the callback function. */ -Blockly.WorkspaceSvg.prototype.removeButtonCallback = function(key) { +WorkspaceSvg.prototype.removeButtonCallback = function(key) { this.flyoutButtonCallbacks_[key] = null; }; @@ -2501,11 +2544,10 @@ Blockly.WorkspaceSvg.prototype.removeButtonCallback = function(key) { * 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(!Blockly.Workspace):!Array} func The function to + * @param {function(!Workspace):!Array} func The function to * call when the given toolbox category is opened. */ -Blockly.WorkspaceSvg.prototype.registerToolboxCategoryCallback = function(key, - func) { +WorkspaceSvg.prototype.registerToolboxCategoryCallback = function(key, func) { if (typeof func != 'function') { throw TypeError('Toolbox category callbacks must be functions.'); } @@ -2516,11 +2558,11 @@ Blockly.WorkspaceSvg.prototype.registerToolboxCategoryCallback = function(key, * 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(!Blockly.Workspace):!Array} The function + * @return {?function(!Workspace):!Array} The function * corresponding to the given key for this workspace, or null if no function * is registered. */ -Blockly.WorkspaceSvg.prototype.getToolboxCategoryCallback = function(key) { +WorkspaceSvg.prototype.getToolboxCategoryCallback = function(key) { return this.toolboxCategoryCallbacks_[key] || null; }; @@ -2528,7 +2570,7 @@ Blockly.WorkspaceSvg.prototype.getToolboxCategoryCallback = function(key) { * Remove a callback for a click on a custom category's name in the toolbox. * @param {string} key The name associated with the callback function. */ -Blockly.WorkspaceSvg.prototype.removeToolboxCategoryCallback = function(key) { +WorkspaceSvg.prototype.removeToolboxCategoryCallback = function(key) { this.toolboxCategoryCallbacks_[key] = null; }; @@ -2536,15 +2578,16 @@ Blockly.WorkspaceSvg.prototype.removeToolboxCategoryCallback = function(key) { * Look up the gesture that is tracking this touch stream on this workspace. * May create a new gesture. * @param {!Event} e Mouse event or touch event. - * @return {?Blockly.TouchGesture} The gesture that is tracking this touch + * @return {?TouchGesture} The gesture that is tracking this touch * stream, or null if no valid gesture exists. * @package */ -Blockly.WorkspaceSvg.prototype.getGesture = function(e) { - var isStart = (e.type == 'mousedown' || e.type == 'touchstart' || - e.type == 'pointerdown'); +WorkspaceSvg.prototype.getGesture = function(e) { + const isStart = + (e.type == 'mousedown' || e.type == 'touchstart' || + e.type == 'pointerdown'); - var gesture = this.currentGesture_; + const gesture = this.currentGesture_; if (gesture) { if (isStart && gesture.hasStarted()) { console.warn('Tried to start the same gesture twice.'); @@ -2559,7 +2602,7 @@ Blockly.WorkspaceSvg.prototype.getGesture = function(e) { // No gesture existed on this workspace, but this looks like the start of a // new gesture. if (isStart) { - this.currentGesture_ = new Blockly.TouchGesture(e, this); + this.currentGesture_ = new TouchGesture(e, this); return this.currentGesture_; } // No gesture existed and this event couldn't be the start of a new gesture. @@ -2570,7 +2613,7 @@ Blockly.WorkspaceSvg.prototype.getGesture = function(e) { * Clear the reference to the current gesture. * @package */ -Blockly.WorkspaceSvg.prototype.clearGesture = function() { +WorkspaceSvg.prototype.clearGesture = function() { this.currentGesture_ = null; }; @@ -2578,7 +2621,7 @@ Blockly.WorkspaceSvg.prototype.clearGesture = function() { * Cancel the current gesture, if one exists. * @package */ -Blockly.WorkspaceSvg.prototype.cancelCurrentGesture = function() { +WorkspaceSvg.prototype.cancelCurrentGesture = function() { if (this.currentGesture_) { this.currentGesture_.cancel(); } @@ -2586,17 +2629,19 @@ Blockly.WorkspaceSvg.prototype.cancelCurrentGesture = function() { /** * Get the audio manager for this workspace. - * @return {!Blockly.WorkspaceAudio} The audio manager for this workspace. + * @return {!WorkspaceAudio} The audio manager for this workspace. */ -Blockly.WorkspaceSvg.prototype.getAudioManager = function() { +WorkspaceSvg.prototype.getAudioManager = function() { return this.audioManager_; }; /** * Get the grid object for this workspace, or null if there is none. - * @return {?Blockly.Grid} The grid object for this workspace. + * @return {?Grid} The grid object for this workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getGrid = function() { +WorkspaceSvg.prototype.getGrid = function() { return this.grid_; }; + +exports = WorkspaceSvg; diff --git a/core/xml.js b/core/xml.js index e581bfd01..661631d27 100644 --- a/core/xml.js +++ b/core/xml.js @@ -10,61 +10,69 @@ */ 'use strict'; -/** - * @name Blockly.Xml - * @namespace - */ -goog.provide('Blockly.Xml'); -goog.require('Blockly.Events'); -goog.require('Blockly.inputTypes'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.Size'); -goog.require('Blockly.utils.xml'); +goog.module('Blockly.Xml'); +goog.module.declareLegacyNamespace(); -goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +const Events = goog.require('Blockly.Events'); +/* eslint-disable-next-line no-unused-vars */ +const Connection = goog.requireType('Blockly.Connection'); +/* eslint-disable-next-line no-unused-vars */ +const Field = goog.requireType('Blockly.Field'); +const Size = goog.require('Blockly.utils.Size'); +/* eslint-disable-next-line no-unused-vars */ +const VariableModel = goog.requireType('Blockly.VariableModel'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const dom = goog.require('Blockly.utils.dom'); +const inputTypes = goog.require('Blockly.inputTypes'); +const utilsXml = goog.require('Blockly.utils.xml'); goog.requireType('Blockly.Comment'); -goog.requireType('Blockly.Connection'); -goog.requireType('Blockly.Field'); -goog.requireType('Blockly.VariableModel'); -goog.requireType('Blockly.Workspace'); +goog.requireType('Blockly.Variables'); +goog.requireType('Blockly.WorkspaceComment'); +goog.requireType('Blockly.WorkspaceCommentSvg'); /** * Encode a block tree as XML. - * @param {!Blockly.Workspace} workspace The workspace containing blocks. + * @param {!Workspace} workspace The workspace containing blocks. * @param {boolean=} opt_noId True if the encoder should skip the block IDs. * @return {!Element} XML DOM element. */ -Blockly.Xml.workspaceToDom = function(workspace, opt_noId) { - var xml = Blockly.utils.xml.createElement('xml'); - var variablesElement = Blockly.Xml.variablesToDom( - Blockly.Variables.allUsedVarModels(workspace)); +const workspaceToDom = function(workspace, opt_noId) { + const treeXml = utilsXml.createElement('xml'); + const variablesElement = variablesToDom( + goog.module.get('Blockly.Variables').allUsedVarModels(workspace)); if (variablesElement.hasChildNodes()) { - xml.appendChild(variablesElement); + treeXml.appendChild(variablesElement); } - var comments = workspace.getTopComments(true); - for (var i = 0, comment; (comment = comments[i]); i++) { - xml.appendChild(comment.toXmlWithXY(opt_noId)); + const comments = workspace.getTopComments(true); + for (let i = 0; i < comments.length; i++) { + const comment = comments[i]; + treeXml.appendChild(comment.toXmlWithXY(opt_noId)); } - var blocks = workspace.getTopBlocks(true); - for (var i = 0, block; (block = blocks[i]); i++) { - xml.appendChild(Blockly.Xml.blockToDomWithXY(block, opt_noId)); + const blocks = workspace.getTopBlocks(true); + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i]; + treeXml.appendChild(blockToDomWithXY(block, opt_noId)); } - return xml; + return treeXml; }; +exports.workspaceToDom = workspaceToDom; /** * Encode a list of variables as XML. - * @param {!Array} variableList List of all variable + * @param {!Array} variableList List of all variable * models. * @return {!Element} Tree of XML elements. */ -Blockly.Xml.variablesToDom = function(variableList) { - var variables = Blockly.utils.xml.createElement('variables'); - for (var i = 0, variable; (variable = variableList[i]); i++) { - var element = Blockly.utils.xml.createElement('variable'); - element.appendChild(Blockly.utils.xml.createTextNode(variable.name)); +const variablesToDom = function(variableList) { + const variables = utilsXml.createElement('variables'); + for (let i = 0; i < variableList.length; i++) { + const variable = variableList[i]; + const element = utilsXml.createElement('variable'); + element.appendChild(utilsXml.createTextNode(variable.name)); if (variable.type) { element.setAttribute('type', variable.type); } @@ -73,15 +81,16 @@ Blockly.Xml.variablesToDom = function(variableList) { } return variables; }; +exports.variablesToDom = variablesToDom; /** * Encode a block subtree as XML with XY coordinates. - * @param {!Blockly.Block} block The root block to encode. + * @param {!Block} block The root block to encode. * @param {boolean=} opt_noId True if the encoder should skip the block ID. - * @return {!Element|!DocumentFragment} Tree of XML elements or an empty document - * fragment if the block was an insertion marker. + * @return {!Element|!DocumentFragment} Tree of XML elements or an empty + * document fragment if the block was an insertion marker. */ -Blockly.Xml.blockToDomWithXY = function(block, opt_noId) { +const blockToDomWithXY = function(block, opt_noId) { if (block.isInsertionMarker()) { // Skip over insertion markers. block = block.getChildren(false)[0]; if (!block) { @@ -90,29 +99,29 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) { } } - var width; // Not used in LTR. + let width; // Not used in LTR. if (block.workspace.RTL) { width = block.workspace.getWidth(); } - var element = Blockly.Xml.blockToDom(block, opt_noId); - var xy = block.getRelativeToSurfaceXY(); - element.setAttribute('x', - Math.round(block.workspace.RTL ? width - xy.x : xy.x)); + const element = blockToDom(block, opt_noId); + const xy = block.getRelativeToSurfaceXY(); + element.setAttribute( + 'x', Math.round(block.workspace.RTL ? width - xy.x : xy.x)); element.setAttribute('y', Math.round(xy.y)); return element; }; +exports.blockToDomWithXY = blockToDomWithXY; /** * Encode a field as XML. - * @param {!Blockly.Field} field The field to encode. + * @param {!Field} field The field to encode. * @return {?Element} XML element, or null if the field did not need to be * serialized. - * @private */ -Blockly.Xml.fieldToDom_ = function(field) { +const fieldToDom = function(field) { if (field.isSerializable()) { - var container = Blockly.utils.xml.createElement('field'); + const container = utilsXml.createElement('field'); container.setAttribute('name', field.name || ''); return field.toXml(container); } @@ -122,15 +131,16 @@ Blockly.Xml.fieldToDom_ = function(field) { /** * Encode all of a block's fields as XML and attach them to the given tree of * XML elements. - * @param {!Blockly.Block} block A block with fields to be encoded. + * @param {!Block} block A block with fields to be encoded. * @param {!Element} element The XML element to which the field DOM should be * attached. - * @private */ -Blockly.Xml.allFieldsToDom_ = function(block, element) { - for (var i = 0, input; (input = block.inputList[i]); i++) { - for (var j = 0, field; (field = input.fieldRow[j]); j++) { - var fieldDom = Blockly.Xml.fieldToDom_(field); +const allFieldsToDom = function(block, element) { + for (let i = 0; i < block.inputList.length; i++) { + const input = block.inputList[i]; + for (let j = 0; j < input.fieldRow.length; j++) { + const field = input.fieldRow[j]; + const fieldDom = fieldToDom(field); if (fieldDom) { element.appendChild(fieldDom); } @@ -140,26 +150,24 @@ Blockly.Xml.allFieldsToDom_ = function(block, element) { /** * Encode a block subtree as XML. - * @param {!Blockly.Block} block The root block to encode. + * @param {!Block} block The root block to encode. * @param {boolean=} opt_noId True if the encoder should skip the block ID. - * @return {!Element|!DocumentFragment} Tree of XML elements or an empty document - * fragment if the block was an insertion marker. + * @return {!Element|!DocumentFragment} Tree of XML elements or an empty + * document fragment if the block was an insertion marker. */ -Blockly.Xml.blockToDom = function(block, opt_noId) { +const blockToDom = function(block, opt_noId) { // Skip over insertion markers. if (block.isInsertionMarker()) { - var child = block.getChildren(false)[0]; + const child = block.getChildren(false)[0]; if (child) { - return Blockly.Xml.blockToDom(child); + return blockToDom(child); } else { // Disappears when appended. return new DocumentFragment(); } } - - var element = - Blockly.utils.xml.createElement(block.isShadow() ? 'shadow' : 'block'); + const element = utilsXml.createElement(block.isShadow() ? 'shadow' : 'block'); element.setAttribute('type', block.type); if (!opt_noId) { // It's important to use setAttribute here otherwise IE11 won't serialize @@ -168,21 +176,21 @@ Blockly.Xml.blockToDom = function(block, opt_noId) { } if (block.mutationToDom) { // Custom data for an advanced block. - var mutation = block.mutationToDom(); + const mutation = block.mutationToDom(); if (mutation && (mutation.hasChildNodes() || mutation.hasAttributes())) { element.appendChild(mutation); } } - Blockly.Xml.allFieldsToDom_(block, element); + allFieldsToDom(block, element); - var commentText = block.getCommentText(); + const commentText = block.getCommentText(); if (commentText) { - var size = block.commentModel.size; - var pinned = block.commentModel.pinned; + const size = block.commentModel.size; + const pinned = block.commentModel.pinned; - var commentElement = Blockly.utils.xml.createElement('comment'); - commentElement.appendChild(Blockly.utils.xml.createTextNode(commentText)); + const commentElement = utilsXml.createElement('comment'); + commentElement.appendChild(utilsXml.createTextNode(commentText)); commentElement.setAttribute('pinned', pinned); commentElement.setAttribute('h', size.height); commentElement.setAttribute('w', size.width); @@ -191,30 +199,31 @@ Blockly.Xml.blockToDom = function(block, opt_noId) { } if (block.data) { - var dataElement = Blockly.utils.xml.createElement('data'); - dataElement.appendChild(Blockly.utils.xml.createTextNode(block.data)); + const dataElement = utilsXml.createElement('data'); + dataElement.appendChild(utilsXml.createTextNode(block.data)); element.appendChild(dataElement); } - for (var i = 0, input; (input = block.inputList[i]); i++) { - var container; - var empty = true; - if (input.type == Blockly.inputTypes.DUMMY) { + for (let i = 0; i < block.inputList.length; i++) { + const input = block.inputList[i]; + let container; + let empty = true; + if (input.type == inputTypes.DUMMY) { continue; } else { - var childBlock = input.connection.targetBlock(); - if (input.type == Blockly.inputTypes.VALUE) { - container = Blockly.utils.xml.createElement('value'); - } else if (input.type == Blockly.inputTypes.STATEMENT) { - container = Blockly.utils.xml.createElement('statement'); + const childBlock = input.connection.targetBlock(); + if (input.type == inputTypes.VALUE) { + container = utilsXml.createElement('value'); + } else if (input.type == inputTypes.STATEMENT) { + container = utilsXml.createElement('statement'); } - var shadow = input.connection.getShadowDom(); + const shadow = input.connection.getShadowDom(); if (shadow && (!childBlock || !childBlock.isShadow())) { - container.appendChild(Blockly.Xml.cloneShadow_(shadow, opt_noId)); + container.appendChild(cloneShadow(shadow, opt_noId)); } if (childBlock) { - var elem = Blockly.Xml.blockToDom(childBlock, opt_noId); - if (elem.nodeType == Blockly.utils.dom.NodeType.ELEMENT_NODE) { + const elem = blockToDom(childBlock, opt_noId); + if (elem.nodeType == dom.NodeType.ELEMENT_NODE) { container.appendChild(elem); empty = false; } @@ -245,35 +254,36 @@ Blockly.Xml.blockToDom = function(block, opt_noId) { element.setAttribute('editable', false); } - var nextBlock = block.getNextBlock(); + const nextBlock = block.getNextBlock(); + let container; if (nextBlock) { - var elem = Blockly.Xml.blockToDom(nextBlock, opt_noId); - if (elem.nodeType == Blockly.utils.dom.NodeType.ELEMENT_NODE) { - var container = Blockly.utils.xml.createElement('next'); + const elem = blockToDom(nextBlock, opt_noId); + if (elem.nodeType == dom.NodeType.ELEMENT_NODE) { + container = utilsXml.createElement('next'); container.appendChild(elem); element.appendChild(container); } } - var shadow = block.nextConnection && block.nextConnection.getShadowDom(); + const shadow = block.nextConnection && block.nextConnection.getShadowDom(); if (shadow && (!nextBlock || !nextBlock.isShadow())) { - container.appendChild(Blockly.Xml.cloneShadow_(shadow, opt_noId)); + container.appendChild(cloneShadow(shadow, opt_noId)); } return element; }; +exports.blockToDom = blockToDom; /** * Deeply clone the shadow's DOM so that changes don't back-wash to the block. * @param {!Element} shadow A tree of XML elements. * @param {boolean=} opt_noId True if the encoder should skip the block ID. * @return {!Element} A tree of XML elements. - * @private */ -Blockly.Xml.cloneShadow_ = function(shadow, opt_noId) { +const cloneShadow = function(shadow, opt_noId) { shadow = shadow.cloneNode(true); // Walk the tree looking for whitespace. Don't prune whitespace in a tag. - var node = shadow; - var textNode; + let node = shadow; + let textNode; while (node) { if (opt_noId && node.nodeName == 'shadow') { // Strip off IDs from shadow blocks. There should never be a 'block' as @@ -286,19 +296,19 @@ Blockly.Xml.cloneShadow_ = function(shadow, opt_noId) { while (node && !node.nextSibling) { textNode = node; node = node.parentNode; - if (textNode.nodeType == Blockly.utils.dom.NodeType.TEXT_NODE && + if (textNode.nodeType == dom.NodeType.TEXT_NODE && textNode.data.trim() == '' && node.firstChild != textNode) { // Prune whitespace after a tag. - Blockly.utils.dom.removeNode(textNode); + dom.removeNode(textNode); } } if (node) { textNode = node; node = node.nextSibling; - if (textNode.nodeType == Blockly.utils.dom.NodeType.TEXT_NODE && + if (textNode.nodeType == dom.NodeType.TEXT_NODE && textNode.data.trim() == '') { // Prune whitespace before a tag. - Blockly.utils.dom.removeNode(textNode); + dom.removeNode(textNode); } } } @@ -313,28 +323,29 @@ Blockly.Xml.cloneShadow_ = function(shadow, opt_noId) { * @param {!Node} dom A tree of XML nodes. * @return {string} Text representation. */ -Blockly.Xml.domToText = function(dom) { - var text = Blockly.utils.xml.domToText(dom); +const domToText = function(dom) { + const text = utilsXml.domToText(dom); // Unpack self-closing tags. These tags fail when embedded in HTML. // -> return text.replace(/<(\w+)([^<]*)\/>/g, '<$1$2>'); }; +exports.domToText = domToText; /** * Converts a DOM structure into properly indented text. * @param {!Node} dom A tree of XML elements. * @return {string} Text representation. */ -Blockly.Xml.domToPrettyText = function(dom) { +const domToPrettyText = function(dom) { // This function is not guaranteed to be correct for all XML. // But it handles the XML that Blockly generates. - var blob = Blockly.Xml.domToText(dom); + const blob = domToText(dom); // Place every open and close tag on its own line. - var lines = blob.split('<'); + const lines = blob.split('<'); // Indent every line. - var indent = ''; - for (var i = 1; i < lines.length; i++) { - var line = lines[i]; + let indent = ''; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; if (line[0] == '/') { indent = indent.substring(2); } @@ -345,11 +356,12 @@ Blockly.Xml.domToPrettyText = function(dom) { } // Pull simple tags back together. // E.g. - var text = lines.join('\n'); + let text = lines.join('\n'); text = text.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g, '$1'); // Trim leading blank line. return text.replace(/^\n/, ''); }; +exports.domToPrettyText = domToPrettyText; /** * Converts an XML string into a DOM structure. @@ -358,80 +370,85 @@ Blockly.Xml.domToPrettyText = function(dom) { * document element. * @throws if the text doesn't parse. */ -Blockly.Xml.textToDom = function(text) { - var doc = Blockly.utils.xml.textToDomDocument(text); +const textToDom = function(text) { + const doc = utilsXml.textToDomDocument(text); if (!doc || !doc.documentElement || doc.getElementsByTagName('parsererror').length) { throw Error('textToDom was unable to parse: ' + text); } return doc.documentElement; }; +exports.textToDom = textToDom; /** * Clear the given workspace then decode an XML DOM and * create blocks on the workspace. * @param {!Element} xml XML DOM. - * @param {!Blockly.Workspace} workspace The workspace. + * @param {!Workspace} workspace The workspace. * @return {!Array} An array containing new block IDs. */ -Blockly.Xml.clearWorkspaceAndLoadFromXml = function(xml, workspace) { +const clearWorkspaceAndLoadFromXml = function(xml, workspace) { workspace.setResizesEnabled(false); workspace.clear(); - var blockIds = Blockly.Xml.domToWorkspace(xml, workspace); + const blockIds = domToWorkspace(xml, workspace); workspace.setResizesEnabled(true); return blockIds; }; +exports.clearWorkspaceAndLoadFromXml = clearWorkspaceAndLoadFromXml; /** * Decode an XML DOM and create blocks on the workspace. * @param {!Element} xml XML DOM. - * @param {!Blockly.Workspace} workspace The workspace. + * @param {!Workspace} workspace The workspace. * @return {!Array} An array containing new block IDs. * @suppress {strictModuleDepCheck} Suppress module check while workspace * comments are not bundled in. */ -Blockly.Xml.domToWorkspace = function(xml, workspace) { - if (xml instanceof Blockly.Workspace) { - var swap = xml; +const domToWorkspace = function(xml, workspace) { + if (xml instanceof goog.module.get('Blockly.Workspace')) { + const swap = xml; // Closure Compiler complains here because the arguments are reversed. /** @suppress {checkTypes} */ xml = workspace; workspace = swap; - console.warn('Deprecated call to Blockly.Xml.domToWorkspace, ' + - 'swap the arguments.'); + console.warn( + 'Deprecated call to domToWorkspace, ' + + 'swap the arguments.'); } - var width; // Not used in LTR. + let width; // Not used in LTR. if (workspace.RTL) { width = workspace.getWidth(); } - var newBlockIds = []; // A list of block IDs added by this call. - Blockly.utils.dom.startTextWidthCache(); - var existingGroup = Blockly.Events.getGroup(); + const newBlockIds = []; // A list of block IDs added by this call. + dom.startTextWidthCache(); + const existingGroup = Events.getGroup(); if (!existingGroup) { - Blockly.Events.setGroup(true); + Events.setGroup(true); } // Disable workspace resizes as an optimization. if (workspace.setResizesEnabled) { workspace.setResizesEnabled(false); } - var variablesFirst = true; + let variablesFirst = true; try { - for (var i = 0, xmlChild; (xmlChild = xml.childNodes[i]); i++) { - var name = xmlChild.nodeName.toLowerCase(); - var xmlChildElement = /** @type {!Element} */ (xmlChild); - if (name == 'block' || - (name == 'shadow' && !Blockly.Events.recordUndo)) { + for (let i = 0; i < xml.childNodes.length; i++) { + const xmlChild = xml.childNodes[i]; + const name = xmlChild.nodeName.toLowerCase(); + const xmlChildElement = /** @type {!Element} */ (xmlChild); + if (name == 'block' || (name == 'shadow' && !Events.recordUndo)) { // Allow top-level shadow blocks if recordUndo is disabled since // that means an undo is in progress. Such a block is expected // to be moved to a nested destination in the next operation. - var block = Blockly.Xml.domToBlock(xmlChildElement, workspace); + const block = domToBlock(xmlChildElement, workspace); newBlockIds.push(block.id); - var blockX = xmlChildElement.hasAttribute('x') ? - parseInt(xmlChildElement.getAttribute('x'), 10) : 10; - var blockY = xmlChildElement.hasAttribute('y') ? - parseInt(xmlChildElement.getAttribute('y'), 10) : 10; + const blockX = xmlChildElement.hasAttribute('x') ? + parseInt(xmlChildElement.getAttribute('x'), 10) : + 10; + const blockY = xmlChildElement.hasAttribute('y') ? + parseInt(xmlChildElement.getAttribute('y'), 10) : + 10; if (!isNaN(blockX) && !isNaN(blockY)) { block.moveBy(workspace.RTL ? width - blockX : blockX, blockY); } @@ -440,26 +457,33 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { throw TypeError('Shadow block cannot be a top-level block.'); } else if (name == 'comment') { if (workspace.rendered) { - if (!Blockly.WorkspaceCommentSvg) { - console.warn('Missing require for Blockly.WorkspaceCommentSvg, ' + + const WorkspaceCommentSvg = + goog.module.get('Blockly.WorkspaceCommentSvg'); + if (!WorkspaceCommentSvg) { + console.warn( + 'Missing require for Blockly.WorkspaceCommentSvg, ' + 'ignoring workspace comment.'); } else { - Blockly.WorkspaceCommentSvg.fromXml( - xmlChildElement, workspace, width); + WorkspaceCommentSvg.fromXml( + xmlChildElement, + /** @type {!Blockly.WorkspaceSvg} */ (workspace), width); } } else { - if (!Blockly.WorkspaceComment) { - console.warn('Missing require for Blockly.WorkspaceComment, ' + + const WorkspaceComment = goog.module.get('Blockly.WorkspaceComment'); + if (!WorkspaceComment) { + console.warn( + 'Missing require for Blockly.WorkspaceComment, ' + 'ignoring workspace comment.'); } else { - Blockly.WorkspaceComment.fromXml(xmlChildElement, workspace); + WorkspaceComment.fromXml(xmlChildElement, workspace); } } } else if (name == 'variables') { if (variablesFirst) { - Blockly.Xml.domToVariables(xmlChildElement, workspace); + domToVariables(xmlChildElement, workspace); } else { - throw Error('\'variables\' tag must exist once before block and ' + + throw Error( + '\'variables\' tag must exist once before block and ' + 'shadow tag elements in the workspace XML, but it was found in ' + 'another location.'); } @@ -468,47 +492,47 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { } } finally { if (!existingGroup) { - Blockly.Events.setGroup(false); + Events.setGroup(false); } - Blockly.utils.dom.stopTextWidthCache(); + dom.stopTextWidthCache(); } // Re-enable workspace resizing. if (workspace.setResizesEnabled) { workspace.setResizesEnabled(true); } - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.FINISHED_LOADING))( - workspace)); + Events.fire(new (Events.get(Events.FINISHED_LOADING))(workspace)); return newBlockIds; }; +exports.domToWorkspace = domToWorkspace; /** * Decode an XML DOM and create blocks on the workspace. Position the new * blocks immediately below prior blocks, aligned by their starting edge. * @param {!Element} xml The XML DOM. - * @param {!Blockly.Workspace} workspace The workspace to add to. + * @param {!Workspace} workspace The workspace to add to. * @return {!Array} An array containing new block IDs. */ -Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { - var bbox; // Bounding box of the current blocks. +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 // and the position does not matter. if (Object.prototype.hasOwnProperty.call(workspace, 'scale')) { bbox = workspace.getBlocksBoundingBox(); } // Load the new blocks into the workspace and get the IDs of the new blocks. - var newBlockIds = Blockly.Xml.domToWorkspace(xml, workspace); + const newBlockIds = domToWorkspace(xml, workspace); if (bbox && bbox.top != bbox.bottom) { // check if any previous block - var offsetY = 0; // offset to add to y of the new block - var offsetX = 0; - var farY = bbox.bottom; // bottom position - var topX = workspace.RTL ? bbox.right : bbox.left; // x of bounding box + let offsetY = 0; // offset to add to y of the new block + let offsetX = 0; + const farY = bbox.bottom; // bottom position + const topX = workspace.RTL ? bbox.right : bbox.left; // x of bounding box // Check position of the new blocks. - var newLeftX = Infinity; // x of top left corner - var newRightX = -Infinity; // x of top right corner - var newY = Infinity; // y of top corner - var ySeparation = 10; - for (var i = 0; i < newBlockIds.length; i++) { - var blockXY = + let newLeftX = Infinity; // x of top left corner + let newRightX = -Infinity; // x of top right corner + let newY = Infinity; // y of top corner + const ySeparation = 10; + for (let i = 0; i < newBlockIds.length; i++) { + const blockXY = workspace.getBlockById(newBlockIds[i]).getRelativeToSurfaceXY(); if (blockXY.y < newY) { newY = blockXY.y; @@ -522,46 +546,49 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { } offsetY = farY - newY + ySeparation; offsetX = workspace.RTL ? topX - newRightX : topX - newLeftX; - for (var i = 0; i < newBlockIds.length; i++) { - var block = workspace.getBlockById(newBlockIds[i]); + for (let i = 0; i < newBlockIds.length; i++) { + const block = workspace.getBlockById(newBlockIds[i]); block.moveBy(offsetX, offsetY); } } return newBlockIds; }; +exports.appendDomToWorkspace = appendDomToWorkspace; /** * Decode an XML block tag and create a block (and possibly sub blocks) on the * workspace. * @param {!Element} xmlBlock XML block element. - * @param {!Blockly.Workspace} workspace The workspace. - * @return {!Blockly.Block} The root block created. + * @param {!Workspace} workspace The workspace. + * @return {!Block} The root block created. */ -Blockly.Xml.domToBlock = function(xmlBlock, workspace) { - if (xmlBlock instanceof Blockly.Workspace) { - var swap = xmlBlock; +const domToBlock = function(xmlBlock, workspace) { + if (xmlBlock instanceof goog.module.get('Blockly.Workspace')) { + const swap = xmlBlock; // Closure Compiler complains here because the arguments are reversed. /** @suppress {checkTypes} */ xmlBlock = /** @type {!Element} */ (workspace); workspace = swap; - console.warn('Deprecated call to Blockly.Xml.domToBlock, ' + - 'swap the arguments.'); + console.warn( + 'Deprecated call to domToBlock, ' + + 'swap the arguments.'); } // Create top-level block. - Blockly.Events.disable(); - var variablesBeforeCreation = workspace.getAllVariables(); + Events.disable(); + const variablesBeforeCreation = workspace.getAllVariables(); + let topBlock; try { - var topBlock = Blockly.Xml.domToBlockHeadless_(xmlBlock, workspace); + topBlock = domToBlockHeadless(xmlBlock, workspace); // Generate list of all blocks. - var blocks = topBlock.getDescendants(false); + const blocks = topBlock.getDescendants(false); if (workspace.rendered) { // Wait to track connections to speed up assembly. topBlock.setConnectionTracking(false); // Render each block. - for (var i = blocks.length - 1; i >= 0; i--) { + for (let i = blocks.length - 1; i >= 0; i--) { blocks[i].initSvg(); } - for (var i = blocks.length - 1; i >= 0; i--) { + for (let i = blocks.length - 1; i >= 0; i--) { blocks[i].render(false); } // Populating the connection database may be deferred until after the @@ -576,49 +603,50 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing. workspace.resizeContents(); } else { - for (var i = blocks.length - 1; i >= 0; i--) { + for (let i = blocks.length - 1; i >= 0; i--) { blocks[i].initModel(); } } } finally { - Blockly.Events.enable(); + Events.enable(); } - if (Blockly.Events.isEnabled()) { - var newVariables = Blockly.Variables.getAddedVariables(workspace, - variablesBeforeCreation); + if (Events.isEnabled()) { + const newVariables = + goog.module.get('Blockly.Variables') + .getAddedVariables(workspace, variablesBeforeCreation); // Fire a VarCreate event for each (if any) new variable created. - for (var i = 0; i < newVariables.length; i++) { - var thisVariable = newVariables[i]; - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.VAR_CREATE))( - thisVariable)); + for (let i = 0; i < newVariables.length; i++) { + const thisVariable = newVariables[i]; + Events.fire(new (Events.get(Events.VAR_CREATE))(thisVariable)); } // Block events come after var events, in case they refer to newly created // variables. - Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.CREATE))( - topBlock)); + Events.fire(new (Events.get(Events.CREATE))(topBlock)); } return topBlock; }; - +exports.domToBlock = domToBlock; /** * Decode an XML list of variables and add the variables to the workspace. * @param {!Element} xmlVariables List of XML variable elements. - * @param {!Blockly.Workspace} workspace The workspace to which the variable + * @param {!Workspace} workspace The workspace to which the variable * should be added. */ -Blockly.Xml.domToVariables = function(xmlVariables, workspace) { - for (var i = 0, xmlChild; (xmlChild = xmlVariables.childNodes[i]); i++) { - if (xmlChild.nodeType != Blockly.utils.dom.NodeType.ELEMENT_NODE) { +const domToVariables = function(xmlVariables, workspace) { + for (let i = 0; i < xmlVariables.childNodes.length; i++) { + const xmlChild = xmlVariables.childNodes[i]; + if (xmlChild.nodeType != dom.NodeType.ELEMENT_NODE) { continue; // Skip text nodes. } - var type = xmlChild.getAttribute('type'); - var id = xmlChild.getAttribute('id'); - var name = xmlChild.textContent; + const type = xmlChild.getAttribute('type'); + const id = xmlChild.getAttribute('id'); + const name = xmlChild.textContent; workspace.createVariable(name, type, id); } }; +exports.domToVariables = domToVariables; /** * A mapping of nodeName to node for child nodes of xmlBlock. @@ -631,22 +659,21 @@ Blockly.Xml.domToVariables = function(xmlVariables, workspace) { * next: !Array * }} */ -Blockly.Xml.childNodeTagMap; +let childNodeTagMap; // eslint-disable-line no-unused-vars /** * Creates a mapping of childNodes for each supported XML tag for the provided * xmlBlock. Logs a warning for any encountered unsupported tags. * @param {!Element} xmlBlock XML block element. - * @return {!Blockly.Xml.childNodeTagMap} The childNode map from nodeName to + * @return {!childNodeTagMap} The childNode map from nodeName to * node. */ -Blockly.Xml.mapSupportedXmlTags_ = function(xmlBlock) { - var childNodeMap = { - mutation: [], comment: [], data: [], field: [], input: [], - next: [] - }; - for (var i = 0, xmlChild; (xmlChild = xmlBlock.childNodes[i]); i++) { - if (xmlChild.nodeType == Blockly.utils.dom.NodeType.TEXT_NODE) { +const mapSupportedXmlTags = function(xmlBlock) { + const childNodeMap = + {mutation: [], comment: [], data: [], field: [], input: [], next: []}; + for (let i = 0; i < xmlBlock.childNodes.length; i++) { + const xmlChild = xmlBlock.childNodes[i]; + if (xmlChild.nodeType == dom.NodeType.TEXT_NODE) { // Ignore any text at the level. It's all whitespace anyway. continue; } @@ -655,8 +682,9 @@ Blockly.Xml.mapSupportedXmlTags_ = function(xmlBlock) { childNodeMap.mutation.push(xmlChild); break; case 'comment': - if (!Blockly.Comment) { - console.warn('Missing require for Blockly.Comment, ' + + if (!goog.module.get('Blockly.Comment')) { + console.warn( + 'Missing require for Comment, ' + 'ignoring block comment.'); break; } @@ -689,14 +717,14 @@ Blockly.Xml.mapSupportedXmlTags_ = function(xmlBlock) { /** * Applies mutation tag child nodes to the given block. * @param {!Array} xmlChildren Child nodes. - * @param {!Blockly.Block} block The block to apply the child nodes on. + * @param {!Block} block The block to apply the child nodes on. * @return {boolean} True if mutation may have added some elements that need * initialization (requiring initSvg call). - * @private */ -Blockly.Xml.applyMutationTagNodes_ = function(xmlChildren, block) { - var shouldCallInitSvg = false; - for (var i = 0, xmlChild; (xmlChild = xmlChildren[i]); i++) { +const applyMutationTagNodes = function(xmlChildren, block) { + let shouldCallInitSvg = false; + for (let i = 0; i < xmlChildren.length; i++) { + const xmlChild = xmlChildren[i]; // Custom data for an advanced block. if (block.domToMutation) { block.domToMutation(xmlChild); @@ -712,20 +740,20 @@ Blockly.Xml.applyMutationTagNodes_ = function(xmlChildren, block) { /** * Applies comment tag child nodes to the given block. * @param {!Array} xmlChildren Child nodes. - * @param {!Blockly.Block} block The block to apply the child nodes on. - * @private + * @param {!Block} block The block to apply the child nodes on. */ -Blockly.Xml.applyCommentTagNodes_ = function(xmlChildren, block) { - for (var i = 0, xmlChild; (xmlChild = xmlChildren[i]); i++) { - var text = xmlChild.textContent; - var pinned = xmlChild.getAttribute('pinned') == 'true'; - var width = parseInt(xmlChild.getAttribute('w'), 10); - var height = parseInt(xmlChild.getAttribute('h'), 10); +const applyCommentTagNodes = function(xmlChildren, block) { + for (let i = 0; i < xmlChildren.length; i++) { + const xmlChild = xmlChildren[i]; + const text = xmlChild.textContent; + const pinned = xmlChild.getAttribute('pinned') == 'true'; + const width = parseInt(xmlChild.getAttribute('w'), 10); + const height = parseInt(xmlChild.getAttribute('h'), 10); block.setCommentText(text); block.commentModel.pinned = pinned; if (!isNaN(width) && !isNaN(height)) { - block.commentModel.size = new Blockly.utils.Size(width, height); + block.commentModel.size = new Size(width, height); } if (pinned && block.getCommentIcon && !block.isInFlyout) { @@ -739,11 +767,11 @@ Blockly.Xml.applyCommentTagNodes_ = function(xmlChildren, block) { /** * Applies data tag child nodes to the given block. * @param {!Array} xmlChildren Child nodes. - * @param {!Blockly.Block} block The block to apply the child nodes on. - * @private + * @param {!Block} block The block to apply the child nodes on. */ -Blockly.Xml.applyDataTagNodes_ = function(xmlChildren, block) { - for (var i = 0, xmlChild; (xmlChild = xmlChildren[i]); i++) { +const applyDataTagNodes = function(xmlChildren, block) { + for (let i = 0; i < xmlChildren.length; i++) { + const xmlChild = xmlChildren[i]; block.data = xmlChild.textContent; } }; @@ -751,13 +779,13 @@ Blockly.Xml.applyDataTagNodes_ = function(xmlChildren, block) { /** * Applies field tag child nodes to the given block. * @param {!Array} xmlChildren Child nodes. - * @param {!Blockly.Block} block The block to apply the child nodes on. - * @private + * @param {!Block} block The block to apply the child nodes on. */ -Blockly.Xml.applyFieldTagNodes_ = function(xmlChildren, block) { - for (var i = 0, xmlChild; (xmlChild = xmlChildren[i]); i++) { - var nodeName = xmlChild.getAttribute('name'); - Blockly.Xml.domToField_(block, nodeName, xmlChild); +const applyFieldTagNodes = function(xmlChildren, block) { + for (let i = 0; i < xmlChildren.length; i++) { + const xmlChild = xmlChildren[i]; + const nodeName = xmlChild.getAttribute('name'); + domToField(block, nodeName, xmlChild); } }; @@ -766,12 +794,12 @@ Blockly.Xml.applyFieldTagNodes_ = function(xmlChildren, block) { * @param {!Element} xmlNode The XML node to extract child block info from. * @return {{childBlockElement: ?Element, childShadowElement: ?Element}} Any * found child block. - * @private */ -Blockly.Xml.findChildBlocks_ = function(xmlNode) { - var childBlockInfo = {childBlockElement: null, childShadowElement: null}; - for (var i = 0, xmlChild; (xmlChild = xmlNode.childNodes[i]); i++) { - if (xmlChild.nodeType == Blockly.utils.dom.NodeType.ELEMENT_NODE) { +const findChildBlocks = function(xmlNode) { + const childBlockInfo = {childBlockElement: null, childShadowElement: null}; + for (let i = 0; i < xmlNode.childNodes.length; i++) { + const xmlChild = xmlNode.childNodes[i]; + if (xmlChild.nodeType == dom.NodeType.ELEMENT_NODE) { if (xmlChild.nodeName.toLowerCase() == 'block') { childBlockInfo.childBlockElement = /** @type {!Element} */ (xmlChild); } else if (xmlChild.nodeName.toLowerCase() == 'shadow') { @@ -785,29 +813,30 @@ Blockly.Xml.findChildBlocks_ = function(xmlNode) { /** * Applies input child nodes (value or statement) to the given block. * @param {!Array} xmlChildren Child nodes. - * @param {!Blockly.Workspace} workspace The workspace containing the given + * @param {!Workspace} workspace The workspace containing the given * block. - * @param {!Blockly.Block} block The block to apply the child nodes on. + * @param {!Block} block The block to apply the child nodes on. * @param {string} prototypeName The prototype name of the block. - * @private */ -Blockly.Xml.applyInputTagNodes_ = function(xmlChildren, workspace, block, - prototypeName) { - for (var i = 0, xmlChild; (xmlChild = xmlChildren[i]); i++) { - var nodeName = xmlChild.getAttribute('name'); - var input = block.getInput(nodeName); +const applyInputTagNodes = function( + xmlChildren, workspace, block, prototypeName) { + for (let i = 0; i < xmlChildren.length; i++) { + const xmlChild = xmlChildren[i]; + const nodeName = xmlChild.getAttribute('name'); + const input = block.getInput(nodeName); if (!input) { - console.warn('Ignoring non-existent input ' + nodeName + ' in block ' + + console.warn( + 'Ignoring non-existent input ' + nodeName + ' in block ' + prototypeName); break; } - var childBlockInfo = Blockly.Xml.findChildBlocks_(xmlChild); + const childBlockInfo = findChildBlocks(xmlChild); if (childBlockInfo.childBlockElement) { if (!input.connection) { throw TypeError('Input connection does not exist.'); } - Blockly.Xml.domToBlockHeadless_(childBlockInfo.childBlockElement, - workspace, input.connection, false); + domToBlockHeadless( + childBlockInfo.childBlockElement, workspace, input.connection, false); } // Set shadow after so we don't create a shadow we delete immediately. if (childBlockInfo.childShadowElement) { @@ -819,14 +848,14 @@ Blockly.Xml.applyInputTagNodes_ = function(xmlChildren, workspace, block, /** * Applies next child nodes to the given block. * @param {!Array} xmlChildren Child nodes. - * @param {!Blockly.Workspace} workspace The workspace containing the given + * @param {!Workspace} workspace The workspace containing the given * block. - * @param {!Blockly.Block} block The block to apply the child nodes on. - * @private + * @param {!Block} block The block to apply the child nodes on. */ -Blockly.Xml.applyNextTagNodes_ = function(xmlChildren, workspace, block) { - for (var i = 0, xmlChild; (xmlChild = xmlChildren[i]); i++) { - var childBlockInfo = Blockly.Xml.findChildBlocks_(xmlChild); +const applyNextTagNodes = function(xmlChildren, workspace, block) { + for (let i = 0; i < xmlChildren.length; i++) { + const xmlChild = xmlChildren[i]; + const childBlockInfo = findChildBlocks(xmlChild); if (childBlockInfo.childBlockElement) { if (!block.nextConnection) { throw TypeError('Next statement does not exist.'); @@ -836,8 +865,8 @@ Blockly.Xml.applyNextTagNodes_ = function(xmlChildren, workspace, block) { throw TypeError('Next statement is already connected.'); } // Create child block. - Blockly.Xml.domToBlockHeadless_(childBlockInfo.childBlockElement, - workspace, block.nextConnection, + domToBlockHeadless( + childBlockInfo.childBlockElement, workspace, block.nextConnection, true); } // Set shadow after so we don't create a shadow we delete immediately. @@ -852,31 +881,31 @@ Blockly.Xml.applyNextTagNodes_ = function(xmlChildren, workspace, block) { * Decode an XML block tag and create a block (and possibly sub blocks) on the * workspace. * @param {!Element} xmlBlock XML block element. - * @param {!Blockly.Workspace} workspace The workspace. - * @param {!Blockly.Connection=} parentConnection The parent connection to + * @param {!Workspace} workspace The workspace. + * @param {!Connection=} parentConnection The parent connection to * to connect this block to after instantiating. - * @param {boolean=} connectedToParentNext Whether the provided parent connection + * @param {boolean=} connectedToParentNext Whether the provided parent + * connection * is a next connection, rather than output or statement. - * @return {!Blockly.Block} The root block created. - * @private + * @return {!Block} The root block created. */ -Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace, - parentConnection, connectedToParentNext) { - var block = null; - var prototypeName = xmlBlock.getAttribute('type'); +const domToBlockHeadless = function( + xmlBlock, workspace, parentConnection, connectedToParentNext) { + let block = null; + const prototypeName = xmlBlock.getAttribute('type'); if (!prototypeName) { throw TypeError('Block type unspecified: ' + xmlBlock.outerHTML); } - var id = xmlBlock.getAttribute('id'); + const id = xmlBlock.getAttribute('id'); block = workspace.newBlock(prototypeName, id); // Preprocess childNodes so tags can be processed in a consistent order. - var xmlChildNameMap = Blockly.Xml.mapSupportedXmlTags_(xmlBlock); + const xmlChildNameMap = mapSupportedXmlTags(xmlBlock); - var shouldCallInitSvg = - Blockly.Xml.applyMutationTagNodes_(xmlChildNameMap.mutation, block); - Blockly.Xml.applyCommentTagNodes_(xmlChildNameMap.comment, block); - Blockly.Xml.applyDataTagNodes_(xmlChildNameMap.data, block); + const shouldCallInitSvg = + applyMutationTagNodes(xmlChildNameMap.mutation, block); + applyCommentTagNodes(xmlChildNameMap.comment, block); + applyDataTagNodes(xmlChildNameMap.data, block); // Connect parent after processing mutation and before setting fields. if (parentConnection) { @@ -884,8 +913,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace, if (block.previousConnection) { parentConnection.connect(block.previousConnection); } else { - throw TypeError( - 'Next block does not have previous statement.'); + throw TypeError('Next block does not have previous statement.'); } } else { if (block.outputConnection) { @@ -899,44 +927,44 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace, } } - Blockly.Xml.applyFieldTagNodes_(xmlChildNameMap.field, block); - Blockly.Xml.applyInputTagNodes_( - xmlChildNameMap.input, workspace, block, prototypeName); - Blockly.Xml.applyNextTagNodes_(xmlChildNameMap.next, workspace, block); + applyFieldTagNodes(xmlChildNameMap.field, block); + applyInputTagNodes(xmlChildNameMap.input, workspace, block, prototypeName); + applyNextTagNodes(xmlChildNameMap.next, workspace, block); if (shouldCallInitSvg) { // InitSvg needs to be called after variable fields are loaded. block.initSvg(); } - var inline = xmlBlock.getAttribute('inline'); + const inline = xmlBlock.getAttribute('inline'); if (inline) { block.setInputsInline(inline == 'true'); } - var disabled = xmlBlock.getAttribute('disabled'); + const disabled = xmlBlock.getAttribute('disabled'); if (disabled) { block.setEnabled(disabled != 'true' && disabled != 'disabled'); } - var deletable = xmlBlock.getAttribute('deletable'); + const deletable = xmlBlock.getAttribute('deletable'); if (deletable) { block.setDeletable(deletable == 'true'); } - var movable = xmlBlock.getAttribute('movable'); + const movable = xmlBlock.getAttribute('movable'); if (movable) { block.setMovable(movable == 'true'); } - var editable = xmlBlock.getAttribute('editable'); + const editable = xmlBlock.getAttribute('editable'); if (editable) { block.setEditable(editable == 'true'); } - var collapsed = xmlBlock.getAttribute('collapsed'); + const collapsed = xmlBlock.getAttribute('collapsed'); if (collapsed) { block.setCollapsed(collapsed == 'true'); } if (xmlBlock.nodeName.toLowerCase() == 'shadow') { // Ensure all children are also shadows. - var children = block.getChildren(false); - for (var i = 0, child; (child = children[i]); i++) { + const children = block.getChildren(false); + for (let i = 0; i < children.length; i++) { + const child = children[i]; if (!child.isShadow()) { throw TypeError('Shadow block not allowed non-shadow child.'); } @@ -952,16 +980,15 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace, /** * Decode an XML field tag and set the value of that field on the given block. - * @param {!Blockly.Block} block The block that is currently being deserialized. + * @param {!Block} block The block that is currently being deserialized. * @param {string} fieldName The name of the field on the block. * @param {!Element} xml The field tag to decode. - * @private */ -Blockly.Xml.domToField_ = function(block, fieldName, xml) { - var field = block.getField(fieldName); +const domToField = function(block, fieldName, xml) { + const field = block.getField(fieldName); if (!field) { - console.warn('Ignoring non-existent field ' + fieldName + ' in block ' + - block.type); + console.warn( + 'Ignoring non-existent field ' + fieldName + ' in block ' + block.type); return; } field.fromXml(xml); @@ -972,11 +999,13 @@ Blockly.Xml.domToField_ = function(block, fieldName, xml) { * @param {!Element|!DocumentFragment} xmlBlock XML block element or an empty * DocumentFragment if the block was an insertion marker. */ -Blockly.Xml.deleteNext = function(xmlBlock) { - for (var i = 0, child; (child = xmlBlock.childNodes[i]); i++) { +const deleteNext = function(xmlBlock) { + for (let i = 0; i < xmlBlock.childNodes.length; i++) { + const child = xmlBlock.childNodes[i]; if (child.nodeName.toLowerCase() == 'next') { xmlBlock.removeChild(child); break; } } }; +exports.deleteNext = deleteNext; diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 37c1cb17d..eb27b17e3 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -13,11 +13,11 @@ goog.module('Blockly.ZoomControls'); goog.module.declareLegacyNamespace(); -const Blockly = goog.require('Blockly'); const ComponentManager = goog.require('Blockly.ComponentManager'); const Css = goog.require('Blockly.Css'); const Events = goog.require('Blockly.Events'); -const IPositionable = goog.require('Blockly.IPositionable'); +/* eslint-disable-next-line no-unused-vars */ +const IPositionable = goog.requireType('Blockly.IPositionable'); const Rect = goog.require('Blockly.utils.Rect'); const Svg = goog.require('Blockly.utils.Svg'); const Touch = goog.require('Blockly.Touch'); @@ -54,7 +54,7 @@ const ZoomControls = function(workspace) { /** * A handle to use to unbind the mouse down event handler for zoom reset - * button. Opaque data returned from Blockly.bindEventWithChecks_. + * button. Opaque data returned from browserEvents.conditionalBind. * @type {?browserEvents.Data} * @private */ @@ -62,7 +62,7 @@ const ZoomControls = function(workspace) { /** * A handle to use to unbind the mouse down event handler for zoom in button. - * Opaque data returned from Blockly.bindEventWithChecks_. + * Opaque data returned from browserEvents.conditionalBind. * @type {?browserEvents.Data} * @private */ @@ -70,7 +70,7 @@ const ZoomControls = function(workspace) { /** * A handle to use to unbind the mouse down event handler for zoom out button. - * Opaque data returned from Blockly.bindEventWithChecks_. + * Opaque data returned from browserEvents.conditionalBind. * @type {?browserEvents.Data} * @private */ diff --git a/scripts/goog_module/convert-file.sh b/scripts/goog_module/convert-file.sh index ebf791d3b..4d6c13345 100755 --- a/scripts/goog_module/convert-file.sh +++ b/scripts/goog_module/convert-file.sh @@ -125,6 +125,64 @@ commit-step() { success "created commit with message: \"${message}\"" } +####################################### +# Extracts a list of properties that are accessed on the specified module name. +# Excludes any matches +# Arguments: +# The module name to find properties accessed for. +# The modules required by the specified module as a single string. +# The filepath to extract requires from. +# Optional: The top-level module. +# Outputs: +# Writes list of properties to stdout as items separated by spaces. +####################################### +getPropertiesAccessed() { + local module_name="$1" + local requires="$2" + local filepath="$3" + local top_module_name="$4" + # Get any strings that follow "$module_name.", excluding matches for + # "$module_name.prototype" and remove list item duplicates (sort -u). + local properties_accessed=$(perl -nle 'print $& while m{(?<='"${module_name}"'\.)(?!prototype)\w+}g' "${filepath}" | sort -u) + + # Get a list of any requires that are a child of $module_name. + # Ex: Blockly.utils.dom is a child of Blockly.utils, this would return "dom" + local requires_overlap=$(echo "${requires}" | perl -nle 'print $& while m{(?<='"${module_name}"'\.)\w+}g') + # Detect if there was any overlap. + if [[ -n "${requires_overlap}" ]]; then + while read -r requires_overlap_prop; do + # Removes any instances of $requires_overlap_prop. Includes regex + # lookarounds so that it does not simply match string contains. + # Ex: if $requires_overlap is "Svg", then it would update the list + # "isTargetInput mouseToSvg noEvent Svg" to + # "isTargetInput mouseToSvg noEvent " (note that mouseToSvg is unchanged). + properties_accessed=$(echo "${properties_accessed}" | perl -pe 's/(? |-s ]" echo " -h Display help and exit" - echo " -c Create a commit for the specified step [2-4]" - echo " -s Run the specified step [1-4]" + echo " -c Create a commit for the specified step [1-4]" + echo " -s Run the specified step [2-4]" } ####################################### diff --git a/scripts/gulpfiles/build_tasks.js b/scripts/gulpfiles/build_tasks.js index e6f496544..318304189 100644 --- a/scripts/gulpfiles/build_tasks.js +++ b/scripts/gulpfiles/build_tasks.js @@ -90,7 +90,6 @@ var JSCOMP_ERROR = [ // 'strictMissingProperties', 'strictModuleDepCheck', // 'strictPrimitiveOperators', - // 'stricterMissingRequire', 'suspiciousCode', 'typeInvalidation', 'undefinedNames', diff --git a/tests/deps.js b/tests/deps.js index d695aabd8..d11d3833e 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -7,48 +7,59 @@ goog.addDependency('../../blocks/procedures.js', ['Blockly.Blocks.procedures'], goog.addDependency('../../blocks/text.js', ['Blockly.Blocks.texts', 'Blockly.Constants.Text'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldMultilineInput', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Mutator']); goog.addDependency('../../blocks/variables.js', ['Blockly.Blocks.variables', 'Blockly.Constants.Variables'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldLabel', 'Blockly.FieldVariable']); goog.addDependency('../../blocks/variables_dynamic.js', ['Blockly.Constants.VariablesDynamic'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldLabel', 'Blockly.FieldVariable']); -goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.IASTNodeLocation', 'Blockly.IDeletable', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.Workspace', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es5'}); +goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/block_animations.js', ['Blockly.blockAnimations'], ['Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/block_drag_surface.js', ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/block_dragger.js', ['Blockly.BlockDragger'], ['Blockly.Events', 'Blockly.Events.BlockDrag', 'Blockly.Events.BlockMove', 'Blockly.IBlockDragger', 'Blockly.InsertionMarkerManager', 'Blockly.blockAnimations', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.IASTNodeLocationSvg', 'Blockly.IBoundedElement', 'Blockly.ICopyable', 'Blockly.IDraggable', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Xml', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.browserEvents', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent']); -goog.addDependency('../../core/blockly.js', ['Blockly'], ['Blockly.ComponentManager', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.Ui', 'Blockly.Events.UiBase', 'Blockly.Events.VarCreate', 'Blockly.Procedures', 'Blockly.ShortcutRegistry', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.inject', 'Blockly.inputTypes', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.colour', 'Blockly.utils.deprecation', 'Blockly.utils.toolbox']); +goog.addDependency('../../core/block_dragger.js', ['Blockly.BlockDragger'], ['Blockly.Events', 'Blockly.Events.BlockDrag', 'Blockly.Events.BlockMove', 'Blockly.InsertionMarkerManager', 'Blockly.blockAnimations', 'Blockly.common', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.FieldLabel', 'Blockly.MarkerManager', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Xml', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.common', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/blockly.js', ['Blockly'], ['Blockly.ComponentManager', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.Ui', 'Blockly.Events.UiBase', 'Blockly.Events.VarCreate', 'Blockly.Procedures', 'Blockly.ShortcutRegistry', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.clipboard', 'Blockly.common', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.inject', 'Blockly.inputTypes', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.colour', 'Blockly.utils.deprecation', 'Blockly.utils.toolbox']); +goog.addDependency('../../core/blockly_options.js', ['Blockly.BlocklyOptions'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/blocks.js', ['Blockly.Blocks'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/browser_events.js', ['Blockly.browserEvents'], ['Blockly.Touch', 'Blockly.utils.global']); -goog.addDependency('../../core/bubble.js', ['Blockly.Bubble'], ['Blockly.IBubble', 'Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent']); +goog.addDependency('../../core/browser_events.js', ['Blockly.browserEvents'], ['Blockly.Touch', 'Blockly.utils.global'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/bubble.js', ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/bubble_dragger.js', ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.ComponentManager', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/clipboard.js', ['Blockly.clipboard'], ['Blockly.Events'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/comment.js', ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Warning', 'Blockly.browserEvents', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/common.js', ['Blockly.common'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/component_manager.js', ['Blockly.ComponentManager'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/connection.js', ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.IASTNodeLocationWithBlock', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.deprecation'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/connection_checker.js', ['Blockly.ConnectionChecker'], ['Blockly.Connection', 'Blockly.IConnectionChecker', 'Blockly.connectionTypes', 'Blockly.internalConstants', 'Blockly.registry'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/connection_db.js', ['Blockly.ConnectionDB'], ['Blockly.RenderedConnection', 'Blockly.connectionTypes', 'Blockly.constants'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/connection.js', ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.deprecation'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/connection_checker.js', ['Blockly.ConnectionChecker'], ['Blockly.Connection', 'Blockly.common', 'Blockly.connectionTypes', 'Blockly.internalConstants', 'Blockly.registry'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/connection_db.js', ['Blockly.ConnectionDB'], ['Blockly.connectionTypes', 'Blockly.constants'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/connection_types.js', ['Blockly.connectionTypes'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/constants.js', ['Blockly.constants'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/contextmenu.js', ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.userAgent']); -goog.addDependency('../../core/contextmenu_items.js', ['Blockly.ContextMenuItems'], ['Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.constants', 'Blockly.inputTypes'], {'lang': 'es5'}); -goog.addDependency('../../core/contextmenu_registry.js', ['Blockly.ContextMenuRegistry'], [], {'lang': 'es5'}); +goog.addDependency('../../core/contextmenu.js', ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/contextmenu_items.js', ['Blockly.ContextMenuItems'], ['Blockly', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Msg', 'Blockly.clipboard', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/contextmenu_registry.js', ['Blockly.ContextMenuRegistry'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/css.js', ['Blockly.Css'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/delete_area.js', ['Blockly.DeleteArea'], ['Blockly.BlockSvg', 'Blockly.DragTarget', 'Blockly.IDeleteArea', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/drag_target.js', ['Blockly.DragTarget'], ['Blockly.IDragTarget'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style']); -goog.addDependency('../../core/events/block_events.js', ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); +goog.addDependency('../../core/delete_area.js', ['Blockly.DeleteArea'], ['Blockly.BlockSvg', 'Blockly.DragTarget', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/drag_target.js', ['Blockly.DragTarget'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.common', 'Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style']); goog.addDependency('../../core/events/events.js', ['Blockly.Events'], ['Blockly.registry', 'Blockly.utils']); -goog.addDependency('../../core/events/events_abstract.js', ['Blockly.Events.Abstract'], ['Blockly.Events']); -goog.addDependency('../../core/events/events_block_drag.js', ['Blockly.Events.BlockDrag'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_bubble_open.js', ['Blockly.Events.BubbleOpen'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_click.js', ['Blockly.Events.Click'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_marker_move.js', ['Blockly.Events.MarkerMove'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_selected.js', ['Blockly.Events.Selected'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_theme_change.js', ['Blockly.Events.ThemeChange'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_toolbox_item_select.js', ['Blockly.Events.ToolboxItemSelect'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_trashcan_open.js', ['Blockly.Events.TrashcanOpen'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/events_viewport.js', ['Blockly.Events.ViewportChange'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/ui_events.js', ['Blockly.Events.Ui', 'Blockly.Events.UiBase'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/variable_events.js', ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object']); -goog.addDependency('../../core/events/workspace_events.js', ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es5'}); +goog.addDependency('../../core/events/events_abstract.js', ['Blockly.Events.Abstract'], ['Blockly.Events'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_block_base.js', ['Blockly.Events.BlockBase'], ['Blockly.Events.Abstract', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_block_change.js', ['Blockly.Events.BlockChange'], ['Blockly.Events', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_block_create.js', ['Blockly.Events.BlockCreate'], ['Blockly.Events', 'Blockly.Events.BlockBase', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.object', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_block_delete.js', ['Blockly.Events.BlockDelete'], ['Blockly.Events', 'Blockly.Events.BlockBase', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.object', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_block_drag.js', ['Blockly.Events.BlockDrag'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_block_move.js', ['Blockly.Events.BlockMove'], ['Blockly.Events', 'Blockly.Events.BlockBase', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_bubble_open.js', ['Blockly.Events.BubbleOpen'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_click.js', ['Blockly.Events.Click'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_marker_move.js', ['Blockly.Events.MarkerMove'], ['Blockly.ASTNode', 'Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_selected.js', ['Blockly.Events.Selected'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_theme_change.js', ['Blockly.Events.ThemeChange'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_toolbox_item_select.js', ['Blockly.Events.ToolboxItemSelect'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_trashcan_open.js', ['Blockly.Events.TrashcanOpen'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_ui.js', ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_ui_base.js', ['Blockly.Events.UiBase'], ['Blockly.Events.Abstract', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_var_base.js', ['Blockly.Events.VarBase'], ['Blockly.Events.Abstract', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_var_create.js', ['Blockly.Events.VarCreate'], ['Blockly.Events', 'Blockly.Events.VarBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_var_delete.js', ['Blockly.Events.VarDelete'], ['Blockly.Events', 'Blockly.Events.VarBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_var_rename.js', ['Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.VarBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/events_viewport.js', ['Blockly.Events.ViewportChange'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/events/workspace_events.js', ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/events/ws_comment_events.js', ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); goog.addDependency('../../core/extensions.js', ['Blockly.Extensions'], ['Blockly.utils'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/field.js', ['Blockly.Field'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.IASTNodeLocationSvg', 'Blockly.IASTNodeLocationWithBlock', 'Blockly.IKeyboardAccessible', 'Blockly.IRegistrable', 'Blockly.MarkerManager', 'Blockly.Tooltip', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/field.js', ['Blockly.Field'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.MarkerManager', 'Blockly.Tooltip', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_angle.js', ['Blockly.FieldAngle'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.object', 'Blockly.utils.userAgent']); goog.addDependency('../../core/field_checkbox.js', ['Blockly.FieldCheckbox'], ['Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_colour.js', ['Blockly.FieldColour'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils.IdGenerator', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); @@ -61,89 +72,93 @@ goog.addDependency('../../core/field_number.js', ['Blockly.FieldNumber'], ['Bloc goog.addDependency('../../core/field_registry.js', ['Blockly.fieldRegistry'], ['Blockly.registry'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_textinput.js', ['Blockly.FieldTextInput'], ['Blockly', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.fieldRegistry', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly', 'Blockly.Block', 'Blockly.ComponentManager', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.IFlyout', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es5'}); +goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly', 'Blockly.ComponentManager', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/flyout_vertical.js', ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly', 'Blockly.internalConstants', 'Blockly.utils.deprecation'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly.common', 'Blockly.internalConstants', 'Blockly.utils.deprecation'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/gesture.js', ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.WorkspaceDragger', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Coordinate'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/grid.js', ['Blockly.Grid'], ['Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/inject.js', ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.WidgetDiv', 'Blockly.Workspace', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent']); -goog.addDependency('../../core/input.js', ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/input_types.js', ['Blockly.inputTypes'], ['Blockly.connectionTypes']); -goog.addDependency('../../core/insertion_marker_manager.js', ['Blockly.InsertionMarkerManager'], ['Blockly.ComponentManager', 'Blockly.Events', 'Blockly.blockAnimations', 'Blockly.connectionTypes', 'Blockly.internalConstants'], {'lang': 'es5'}); +goog.addDependency('../../core/inject.js', ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.WidgetDiv', 'Blockly.Workspace', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg', 'Blockly.browserEvents', 'Blockly.common', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent']); +goog.addDependency('../../core/input.js', ['Blockly.Input'], ['Blockly.FieldLabel', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/input_types.js', ['Blockly.inputTypes'], ['Blockly.connectionTypes'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/insertion_marker_manager.js', ['Blockly.InsertionMarkerManager'], ['Blockly.ComponentManager', 'Blockly.Events', 'Blockly.blockAnimations', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.internalConstants'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_ast_node_location.js', ['Blockly.IASTNodeLocation'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_ast_node_location_svg.js', ['Blockly.IASTNodeLocationSvg'], ['Blockly.IASTNodeLocation'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_ast_node_location_with_block.js', ['Blockly.IASTNodeLocationWithBlock'], ['Blockly.IASTNodeLocation'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_autohideable.js', ['Blockly.IAutoHideable'], ['Blockly.IComponent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_ast_node_location_svg.js', ['Blockly.IASTNodeLocationSvg'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_ast_node_location_with_block.js', ['Blockly.IASTNodeLocationWithBlock'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_autohideable.js', ['Blockly.IAutoHideable'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_block_dragger.js', ['Blockly.IBlockDragger'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_bounded_element.js', ['Blockly.IBoundedElement'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_bubble.js', ['Blockly.IBubble'], ['Blockly.IContextMenu', 'Blockly.IDraggable'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_collapsible_toolbox_item.js', ['Blockly.ICollapsibleToolboxItem'], ['Blockly.ISelectableToolboxItem'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_bubble.js', ['Blockly.IBubble'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_collapsible_toolbox_item.js', ['Blockly.ICollapsibleToolboxItem'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_component.js', ['Blockly.IComponent'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_connection_checker.js', ['Blockly.IConnectionChecker'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_contextmenu.js', ['Blockly.IContextMenu'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_copyable.js', ['Blockly.ICopyable'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_deletable.js', ['Blockly.IDeletable'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_delete_area.js', ['Blockly.IDeleteArea'], ['Blockly.IDragTarget'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_drag_target.js', ['Blockly.IDragTarget'], ['Blockly.IComponent'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_draggable.js', ['Blockly.IDraggable'], ['Blockly.IDeletable'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_flyout.js', ['Blockly.IFlyout'], ['Blockly.IRegistrable'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_delete_area.js', ['Blockly.IDeleteArea'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_drag_target.js', ['Blockly.IDragTarget'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_draggable.js', ['Blockly.IDraggable'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_flyout.js', ['Blockly.IFlyout'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_keyboard_accessible.js', ['Blockly.IKeyboardAccessible'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_metrics_manager.js', ['Blockly.IMetricsManager'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_movable.js', ['Blockly.IMovable'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_positionable.js', ['Blockly.IPositionable'], ['Blockly.IComponent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_positionable.js', ['Blockly.IPositionable'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_registrable.js', ['Blockly.IRegistrable'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_registrable_field.js', ['Blockly.IRegistrableField'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_selectable.js', ['Blockly.ISelectable'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_selectable_toolbox_item.js', ['Blockly.ISelectableToolboxItem'], ['Blockly.IToolboxItem'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_selectable_toolbox_item.js', ['Blockly.ISelectableToolboxItem'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_styleable.js', ['Blockly.IStyleable'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/interfaces/i_toolbox.js', ['Blockly.IToolbox'], ['Blockly.IRegistrable'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/interfaces/i_toolbox.js', ['Blockly.IToolbox'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/interfaces/i_toolbox_item.js', ['Blockly.IToolboxItem'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/internal_constants.js', ['Blockly.internalConstants'], ['Blockly.connectionTypes'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/keyboard_nav/ast_node.js', ['Blockly.ASTNode'], ['Blockly.connectionTypes', 'Blockly.utils.Coordinate'], {'lang': 'es5'}); +goog.addDependency('../../core/keyboard_nav/ast_node.js', ['Blockly.ASTNode'], ['Blockly.connectionTypes', 'Blockly.utils.Coordinate'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/keyboard_nav/basic_cursor.js', ['Blockly.BasicCursor'], ['Blockly.ASTNode', 'Blockly.Cursor', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/keyboard_nav/cursor.js', ['Blockly.Cursor'], ['Blockly.ASTNode', 'Blockly.Marker', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/keyboard_nav/marker.js', ['Blockly.Marker'], ['Blockly.ASTNode']); +goog.addDependency('../../core/keyboard_nav/marker.js', ['Blockly.Marker'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/keyboard_nav/tab_navigate_cursor.js', ['Blockly.TabNavigateCursor'], ['Blockly.ASTNode', 'Blockly.BasicCursor', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/marker_manager.js', ['Blockly.MarkerManager'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.browserEvents', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/menuitem.js', ['Blockly.MenuItem'], ['Blockly.utils.IdGenerator', 'Blockly.utils.aria', 'Blockly.utils.dom']); -goog.addDependency('../../core/metrics_manager.js', ['Blockly.FlyoutMetricsManager', 'Blockly.MetricsManager'], ['Blockly.IMetricsManager', 'Blockly.registry', 'Blockly.utils.Size', 'Blockly.utils.toolbox'], {'lang': 'es5'}); +goog.addDependency('../../core/menuitem.js', ['Blockly.MenuItem'], ['Blockly.utils.IdGenerator', 'Blockly.utils.aria', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/metrics_manager.js', ['Blockly.FlyoutMetricsManager', 'Blockly.MetricsManager'], ['Blockly.registry', 'Blockly.utils.Size', 'Blockly.utils.toolbox'], {'lang': 'es5'}); goog.addDependency('../../core/msg.js', ['Blockly.Msg'], ['Blockly.utils.global']); -goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml']); -goog.addDependency('../../core/names.js', ['Blockly.Names'], ['Blockly.Msg', 'Blockly.internalConstants']); -goog.addDependency('../../core/options.js', ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.registry', 'Blockly.utils.IdGenerator', 'Blockly.utils.Metrics', 'Blockly.utils.toolbox']); -goog.addDependency('../../core/positionable_helpers.js', ['Blockly.uiPosition'], ['Blockly.Scrollbar', 'Blockly.utils.Rect', 'Blockly.utils.toolbox']); -goog.addDependency('../../core/procedures.js', ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.internalConstants', 'Blockly.utils.xml']); -goog.addDependency('../../core/registry.js', ['Blockly.registry'], []); -goog.addDependency('../../core/rendered_connection.js', ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.connectionTypes', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/common/block_rendering.js', ['Blockly.blockRendering'], ['Blockly.registry']); +goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.internalConstants', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/names.js', ['Blockly.Names'], ['Blockly.Msg', 'Blockly.Variables', 'Blockly.internalConstants'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/options.js', ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.registry', 'Blockly.utils.IdGenerator', 'Blockly.utils.deprecation', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/positionable_helpers.js', ['Blockly.uiPosition'], ['Blockly.Scrollbar', 'Blockly.utils.Rect', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/procedures.js', ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Msg', 'Blockly.Names', 'Blockly.Variables', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/registry.js', ['Blockly.registry'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/rendered_connection.js', ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.connectionTypes', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/common/block_rendering.js', ['Blockly.blockRendering'], ['Blockly.registry'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/renderers/common/constants.js', ['Blockly.blockRendering.ConstantProvider'], ['Blockly.connectionTypes', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.svgPaths', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/renderers/common/debugger.js', ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.Types', 'Blockly.connectionTypes', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es5'}); -goog.addDependency('../../core/renderers/common/drawer.js', ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.Row', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/renderers/common/i_path_object.js', ['Blockly.blockRendering.IPathObject'], []); -goog.addDependency('../../core/renderers/common/info.js', ['Blockly.blockRendering.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.Field', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.Icon', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.JaggedEdge', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.inputTypes'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/renderers/common/marker_svg.js', ['Blockly.blockRendering.MarkerSvg'], ['Blockly.ASTNode', 'Blockly.Events', 'Blockly.Events.MarkerMove', 'Blockly.connectionTypes', 'Blockly.utils.Svg', 'Blockly.utils.dom']); -goog.addDependency('../../core/renderers/common/path_object.js', ['Blockly.blockRendering.PathObject'], ['Blockly.Theme', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom']); -goog.addDependency('../../core/renderers/common/renderer.js', ['Blockly.blockRendering.Renderer'], ['Blockly.IRegistrable', 'Blockly.InsertionMarkerManager', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Debug', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.MarkerSvg', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.connectionTypes']); -goog.addDependency('../../core/renderers/geras/constants.js', ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object'], {'lang': 'es5'}); -goog.addDependency('../../core/renderers/geras/drawer.js', ['Blockly.geras.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.RenderInfo', 'Blockly.utils.object', 'Blockly.utils.svgPaths']); -goog.addDependency('../../core/renderers/geras/highlight_constants.js', ['Blockly.geras.HighlightConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.svgPaths'], {'lang': 'es5'}); -goog.addDependency('../../core/renderers/geras/highlighter.js', ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); -goog.addDependency('../../core/renderers/geras/info.js', ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.inputTypes', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/geras/measurables/inputs.js', ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.StatementInput', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/geras/path_object.js', ['Blockly.geras.PathObject'], ['Blockly.Theme', 'Blockly.blockRendering.PathObject', 'Blockly.geras.ConstantProvider', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/geras/renderer.js', ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/measurables/base.js', ['Blockly.blockRendering.Measurable'], ['Blockly.blockRendering.Types']); +goog.addDependency('../../core/renderers/common/drawer.js', ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/common/i_path_object.js', ['Blockly.blockRendering.IPathObject'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/common/info.js', ['Blockly.blockRendering.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.Field', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.Icon', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.JaggedEdge', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.inputTypes'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/common/marker_svg.js', ['Blockly.blockRendering.MarkerSvg'], ['Blockly.ASTNode', 'Blockly.Events', 'Blockly.Events.MarkerMove', 'Blockly.connectionTypes', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/common/path_object.js', ['Blockly.blockRendering.PathObject'], ['Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/common/renderer.js', ['Blockly.blockRendering.Renderer'], ['Blockly.Connection', 'Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.MarkerSvg', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.connectionTypes', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/constants.js', ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/drawer.js', ['Blockly.geras.Drawer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/highlight_constants.js', ['Blockly.geras.HighlightConstantProvider'], ['Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/highlighter.js', ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/info.js', ['Blockly.geras.RenderInfo'], ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.inputTypes', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/measurables/inline_input.js', ['Blockly.geras.InlineInput'], ['Blockly.blockRendering.InlineInput', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/measurables/statement_input.js', ['Blockly.geras.StatementInput'], ['Blockly.blockRendering.StatementInput', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/path_object.js', ['Blockly.geras.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/geras/renderer.js', ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/measurables/base.js', ['Blockly.blockRendering.Measurable'], ['Blockly.blockRendering.Types'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/renderers/measurables/connections.js', ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/measurables/inputs.js', ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.StatementInput'], ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); +goog.addDependency('../../core/renderers/measurables/external_value_input.js', ['Blockly.blockRendering.ExternalValueInput'], ['Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/measurables/inline_input.js', ['Blockly.blockRendering.InlineInput'], ['Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/measurables/input_connection.js', ['Blockly.blockRendering.InputConnection'], ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/renderers/measurables/row_elements.js', ['Blockly.blockRendering.Field', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.Icon', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.JaggedEdge', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.SquareCorner'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); goog.addDependency('../../core/renderers/measurables/rows.js', ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow'], ['Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/measurables/types.js', ['Blockly.blockRendering.Types'], []); +goog.addDependency('../../core/renderers/measurables/statement_input.js', ['Blockly.blockRendering.StatementInput'], ['Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/renderers/measurables/types.js', ['Blockly.blockRendering.Types'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/renderers/minimalist/constants.js', ['Blockly.minimalist.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object']); -goog.addDependency('../../core/renderers/minimalist/drawer.js', ['Blockly.minimalist.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.minimalist.RenderInfo', 'Blockly.utils.object']); +goog.addDependency('../../core/renderers/minimalist/drawer.js', ['Blockly.minimalist.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/renderers/minimalist/info.js', ['Blockly.minimalist', 'Blockly.minimalist.RenderInfo'], ['Blockly.utils.object']); goog.addDependency('../../core/renderers/minimalist/renderer.js', ['Blockly.minimalist.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.minimalist.ConstantProvider', 'Blockly.minimalist.Drawer', 'Blockly.minimalist.RenderInfo', 'Blockly.utils.object']); goog.addDependency('../../core/renderers/thrasos/info.js', ['Blockly.thrasos', 'Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); @@ -158,28 +173,29 @@ goog.addDependency('../../core/renderers/zelos/measurables/rows.js', ['Blockly.z goog.addDependency('../../core/renderers/zelos/path_object.js', ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider']); goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.connectionTypes', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']); goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer']); -goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Events', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Svg', 'Blockly.utils.dom']); -goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly.Gesture', 'Blockly.ShortcutRegistry', 'Blockly.utils.KeyCodes']); +goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar'], ['Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/scrollbar_pair.js', ['Blockly.ScrollbarPair'], ['Blockly.Events', 'Blockly.Scrollbar', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly', 'Blockly.Gesture', 'Blockly.ShortcutRegistry', 'Blockly.clipboard', '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/theme.js', ['Blockly.Theme'], ['Blockly.registry', 'Blockly.utils', 'Blockly.utils.object']); +goog.addDependency('../../core/theme.js', ['Blockly.Theme'], ['Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/theme/classic.js', ['Blockly.Themes.Classic'], ['Blockly.Theme']); goog.addDependency('../../core/theme/zelos.js', ['Blockly.Themes.Zelos'], ['Blockly.Theme']); goog.addDependency('../../core/theme_manager.js', ['Blockly.ThemeManager'], ['Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/toolbox/category.js', ['Blockly.ToolboxCategory'], ['Blockly.ISelectableToolboxItem', 'Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es5'}); -goog.addDependency('../../core/toolbox/collapsible_category.js', ['Blockly.CollapsibleToolboxCategory'], ['Blockly.ICollapsibleToolboxItem', 'Blockly.ToolboxCategory', 'Blockly.ToolboxItem', 'Blockly.ToolboxSeparator', 'Blockly.registry', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox']); -goog.addDependency('../../core/toolbox/separator.js', ['Blockly.ToolboxSeparator'], ['Blockly.IToolboxItem', 'Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils.dom'], {'lang': 'es5'}); -goog.addDependency('../../core/toolbox/toolbox.js', ['Blockly.Toolbox'], ['Blockly.BlockSvg', 'Blockly.CollapsibleToolboxCategory', 'Blockly.ComponentManager', 'Blockly.Css', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.ToolboxItemSelect', 'Blockly.IAutoHideable', 'Blockly.IKeyboardAccessible', 'Blockly.IStyleable', 'Blockly.IToolbox', 'Blockly.Options', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'}); -goog.addDependency('../../core/toolbox/toolbox_item.js', ['Blockly.ToolboxItem'], ['Blockly.IToolboxItem']); -goog.addDependency('../../core/tooltip.js', ['Blockly.Tooltip'], ['Blockly.browserEvents', 'Blockly.utils.string']); +goog.addDependency('../../core/toolbox/category.js', ['Blockly.ToolboxCategory'], ['Blockly', 'Blockly.Css', 'Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/toolbox/collapsible_category.js', ['Blockly.CollapsibleToolboxCategory'], ['Blockly.ToolboxCategory', 'Blockly.ToolboxSeparator', 'Blockly.registry', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/toolbox/separator.js', ['Blockly.ToolboxSeparator'], ['Blockly.Css', 'Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/toolbox/toolbox.js', ['Blockly.Toolbox'], ['Blockly', 'Blockly.BlockSvg', 'Blockly.CollapsibleToolboxCategory', 'Blockly.ComponentManager', 'Blockly.Css', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.ToolboxItemSelect', 'Blockly.Options', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/toolbox/toolbox_item.js', ['Blockly.ToolboxItem'], ['Blockly.utils.IdGenerator'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/tooltip.js', ['Blockly.Tooltip'], ['Blockly.browserEvents', 'Blockly.common', 'Blockly.utils.string']); goog.addDependency('../../core/touch.js', ['Blockly.Touch'], ['Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.string']); goog.addDependency('../../core/touch_gesture.js', ['Blockly.TouchGesture'], ['Blockly.Gesture', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object']); -goog.addDependency('../../core/trashcan.js', ['Blockly.Trashcan'], ['Blockly.ComponentManager', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.TrashcanOpen', 'Blockly.IAutoHideable', 'Blockly.IPositionable', 'Blockly.Options', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.registry', 'Blockly.uiPosition', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'}); +goog.addDependency('../../core/trashcan.js', ['Blockly.Trashcan'], ['Blockly.ComponentManager', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.TrashcanOpen', 'Blockly.Options', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.registry', 'Blockly.uiPosition', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils.js', ['Blockly.utils'], ['Blockly.Msg', 'Blockly.internalConstants', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.colour', 'Blockly.utils.global', 'Blockly.utils.string', 'Blockly.utils.style', 'Blockly.utils.userAgent']); goog.addDependency('../../core/utils/aria.js', ['Blockly.utils.aria'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/colour.js', ['Blockly.utils.colour'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/coordinate.js', ['Blockly.utils.Coordinate'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/deprecation.js', ['Blockly.utils.deprecation'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/utils/dom.js', ['Blockly.utils.dom'], ['Blockly.utils.Svg', 'Blockly.utils.userAgent']); +goog.addDependency('../../core/utils/dom.js', ['Blockly.utils.dom'], ['Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/global.js', ['Blockly.utils.global'], []); goog.addDependency('../../core/utils/idgenerator.js', ['Blockly.utils.IdGenerator'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/keycodes.js', ['Blockly.utils.KeyCodes'], [], {'lang': 'es6', 'module': 'goog'}); @@ -195,21 +211,20 @@ goog.addDependency('../../core/utils/svg_paths.js', ['Blockly.utils.svgPaths'], goog.addDependency('../../core/utils/toolbox.js', ['Blockly.utils.toolbox'], ['Blockly.Xml', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/useragent.js', ['Blockly.utils.userAgent'], ['Blockly.utils.global']); goog.addDependency('../../core/utils/xml.js', ['Blockly.utils.xml'], []); -goog.addDependency('../../core/variable_map.js', ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.utils', 'Blockly.utils.object']); -goog.addDependency('../../core/variable_model.js', ['Blockly.VariableModel'], ['Blockly.Events', 'Blockly.Events.VarCreate', 'Blockly.utils']); +goog.addDependency('../../core/variable_map.js', ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.Names', 'Blockly.VariableModel', 'Blockly.utils', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/variable_model.js', ['Blockly.VariableModel'], ['Blockly.Events', 'Blockly.Events.VarCreate', 'Blockly.utils'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/variables.js', ['Blockly.Variables'], ['Blockly.Blocks', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Xml', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.xml']); -goog.addDependency('../../core/variables_dynamic.js', ['Blockly.VariablesDynamic'], ['Blockly.Blocks', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.utils.xml']); -goog.addDependency('../../core/warning.js', ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object']); -goog.addDependency('../../core/widgetdiv.js', ['Blockly.WidgetDiv'], ['Blockly.utils.dom']); -goog.addDependency('../../core/workspace.js', ['Blockly.Workspace'], ['Blockly.ConnectionChecker', 'Blockly.Events', 'Blockly.IASTNodeLocation', 'Blockly.Options', 'Blockly.VariableMap', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.math']); -goog.addDependency('../../core/workspace_audio.js', ['Blockly.WorkspaceAudio'], ['Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.userAgent'], {'lang': 'es5'}); -goog.addDependency('../../core/workspace_comment.js', ['Blockly.WorkspaceComment'], ['Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.xml']); -goog.addDependency('../../core/workspace_comment_render_svg.js', ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom']); -goog.addDependency('../../core/workspace_comment_svg.js', ['Blockly.WorkspaceCommentSvg'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Selected', 'Blockly.WorkspaceComment', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object']); -goog.addDependency('../../core/workspace_drag_surface_svg.js', ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom']); -goog.addDependency('../../core/workspace_dragger.js', ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']); -goog.addDependency('../../core/workspace_svg.js', ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.ComponentManager', 'Blockly.ConnectionDB', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.ThemeChange', 'Blockly.Events.ViewportChange', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.IASTNodeLocationSvg', 'Blockly.MarkerManager', 'Blockly.MetricsManager', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es5'}); -goog.addDependency('../../core/xml.js', ['Blockly.Xml'], ['Blockly.Events', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.dom', 'Blockly.utils.xml']); -goog.addDependency('../../core/zoom_controls.js', ['Blockly.ZoomControls'], ['Blockly', 'Blockly.ComponentManager', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.IPositionable', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.uiPosition', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/variables_dynamic.js', ['Blockly.VariablesDynamic'], ['Blockly.Blocks', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/warning.js', ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/widgetdiv.js', ['Blockly.WidgetDiv'], ['Blockly.common', 'Blockly.utils.dom']); +goog.addDependency('../../core/workspace.js', ['Blockly.Workspace'], ['Blockly.ConnectionChecker', 'Blockly.Events', 'Blockly.Options', 'Blockly.VariableMap', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.math'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/workspace_audio.js', ['Blockly.WorkspaceAudio'], ['Blockly.internalConstants', 'Blockly.utils.global', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/workspace_comment.js', ['Blockly.WorkspaceComment'], ['Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/workspace_comment_svg.js', ['Blockly.WorkspaceCommentSvg'], ['Blockly', 'Blockly.ContextMenu', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Selected', 'Blockly.Touch', 'Blockly.WorkspaceComment', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/workspace_drag_surface_svg.js', ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/workspace_dragger.js', ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/workspace_svg.js', ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.ComponentManager', 'Blockly.ConnectionDB', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.ThemeChange', 'Blockly.Events.ViewportChange', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.MarkerManager', 'Blockly.MetricsManager', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.common', 'Blockly.internalConstants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/xml.js', ['Blockly.Xml'], ['Blockly.Events', 'Blockly.inputTypes', 'Blockly.utils.Size', 'Blockly.utils.dom', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/zoom_controls.js', ['Blockly.ZoomControls'], ['Blockly.ComponentManager', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.uiPosition', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('base.js', [], []); diff --git a/tests/generators/run_generators_in_browser.js b/tests/generators/run_generators_in_browser.js index d0ed80009..97dcf9727 100644 --- a/tests/generators/run_generators_in_browser.js +++ b/tests/generators/run_generators_in_browser.js @@ -42,6 +42,7 @@ async function runGeneratorsInBrowser() { capabilities: { browserName: 'chrome', }, + logLevel: 'warn', services: ['selenium-standalone'] }; // Run in headless mode on Github Actions. @@ -50,8 +51,11 @@ async function runGeneratorsInBrowser() { args: ['--headless', '--no-sandbox', '--disable-dev-shm-usage', '--allow-file-access-from-files'] }; } else { + // --disable-gpu is needed to prevent Chrome from hanging on Linux with + // NVIDIA drivers older than v295.20. See + // https://github.com/google/blockly/issues/5345 for details. options.capabilities['goog:chromeOptions'] = { - args: ['--allow-file-access-from-files'] + args: ['--allow-file-access-from-files', '--disable-gpu'] }; } diff --git a/tests/mocha/contextmenu_items_test.js b/tests/mocha/contextmenu_items_test.js index 62dd6f9ea..0d69fa77e 100644 --- a/tests/mocha/contextmenu_items_test.js +++ b/tests/mocha/contextmenu_items_test.js @@ -17,11 +17,11 @@ suite('Context Menu Items', function() { Blockly.ContextMenuItems.registerDefaultOptions(); this.registry = Blockly.ContextMenuRegistry.registry; }); - + teardown(function() { sharedTestTeardown.call(this); }); - + suite('Workspace Items', function() { setup(function() { this.scope = {workspace: this.workspace}; @@ -328,12 +328,12 @@ suite('Context Menu Items', function() { }); test('Calls duplicate', function() { - var stub = sinon.stub(Blockly, 'duplicate'); + var spy = sinon.spy(Blockly.clipboard, 'duplicate'); this.duplicateOption.callback(this.scope); - sinon.assert.calledOnce(stub); - sinon.assert.calledWith(stub, this.block); + sinon.assert.calledOnce(spy); + sinon.assert.calledWith(spy, this.block); }); test('Has correct label', function() { diff --git a/tests/mocha/event_test.js b/tests/mocha/event_test.js index 81ab69519..febcaf1c3 100644 --- a/tests/mocha/event_test.js +++ b/tests/mocha/event_test.js @@ -109,32 +109,10 @@ suite('Events', function() { }); }); - test('Create', function() { - var event = new Blockly.Events.Create(this.block); - sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.CREATE, - this.workspace.id, this.TEST_BLOCK_ID, - { - 'recordUndo': true, - 'group': '', - }); - }); - test('Block create', function() { var event = new Blockly.Events.BlockCreate(this.block); sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.CREATE, - this.workspace.id, this.TEST_BLOCK_ID, - { - 'recordUndo': true, - 'group': '', - }); - }); - - test('Delete', function() { - var event = new Blockly.Events.Delete(this.block); - sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.DELETE, + assertEventEquals(event, Blockly.Events.BLOCK_CREATE, this.workspace.id, this.TEST_BLOCK_ID, { 'recordUndo': true, @@ -145,7 +123,7 @@ suite('Events', function() { test('Block delete', function() { var event = new Blockly.Events.BlockDelete(this.block); sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.DELETE, + assertEventEquals(event, Blockly.Events.BLOCK_DELETE, this.workspace.id, this.TEST_BLOCK_ID, { 'recordUndo': true, @@ -181,30 +159,14 @@ suite('Events', function() { }, true); }); - suite('Move', function() { - test('Move by coordinate', function() { - var coordinate = new Blockly.utils.Coordinate(3, 4); - this.block.xy_ = coordinate; - - var event = new Blockly.Events.Move(this.block); - sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id, - this.TEST_BLOCK_ID, { - 'oldParentId': undefined, - 'oldInputName': undefined, - 'oldCoordinate': coordinate, - 'recordUndo': true, - 'group': '' - }); - }); - - test('Block move by coordinate', function() { + suite('Block Move', function() { + test('by coordinate', function() { var coordinate = new Blockly.utils.Coordinate(3, 4); this.block.xy_ = coordinate; var event = new Blockly.Events.BlockMove(this.block); sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id, + assertEventEquals(event, Blockly.Events.BLOCK_MOVE, this.workspace.id, this.TEST_BLOCK_ID, { 'oldParentId': undefined, 'oldInputName': undefined, @@ -214,22 +176,14 @@ suite('Events', function() { }); }); - suite('Move by parent', function() { - setup(function() { + test('by parent', function() { + try { this.parentBlock = createSimpleTestBlock(this.workspace); - this.block.parentBlock_ = this.parentBlock; this.block.xy_ = new Blockly.utils.Coordinate(3, 4); - }); - teardown(function() { - // This needs to be cleared, otherwise workspace.dispose will fail. - this.block.parentBlock_ = null; - }); - - test('Move by parent', function() { - var event = new Blockly.Events.Move(this.block); + var event = new Blockly.Events.BlockMove(this.block); sinon.assert.calledTwice(this.genUidStub); - assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id, + assertEventEquals(event, Blockly.Events.BLOCK_MOVE, this.workspace.id, this.TEST_BLOCK_ID, { 'oldParentId': this.TEST_PARENT_ID, 'oldInputName': undefined, @@ -237,21 +191,10 @@ suite('Events', function() { 'recordUndo': true, 'group': '' }); - }); - - test('Block move by parent', function() { - var event = new Blockly.Events.BlockMove(this.block); - sinon.assert.calledTwice(this.genUidStub); - assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id, - this.TEST_BLOCK_ID, - { - 'oldParentId': this.TEST_PARENT_ID, - 'oldInputName': undefined, - 'oldCoordinate': undefined, - 'recordUndo': true, - 'group': '' - }); - }); + } finally { + // This needs to be cleared, otherwise workspace.dispose will fail. + this.block.parentBlock_ = null; + } }); }); }); @@ -279,28 +222,11 @@ suite('Events', function() { }); }); - test('Change', function() { - var event = new Blockly.Events.Change( - this.block, 'field', 'FIELD_NAME', 'old', 'new'); - sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.CHANGE, - this.workspace.id, this.TEST_BLOCK_ID, - { - 'varId': undefined, - 'element': 'field', - 'name': 'FIELD_NAME', - 'oldValue': 'old', - 'newValue': 'new', - 'recordUndo': true, - 'group': '', - }); - }); - test('Block change', function() { var event = new Blockly.Events.BlockChange( this.block, 'field', 'FIELD_NAME', 'old', 'new'); sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.CHANGE, + assertEventEquals(event, Blockly.Events.BLOCK_CHANGE, this.workspace.id, this.TEST_BLOCK_ID, { 'varId': undefined, @@ -313,32 +239,10 @@ suite('Events', function() { }); }); - test('Create', function() { - var event = new Blockly.Events.Create(this.block); - sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.CREATE, - this.workspace.id, this.TEST_BLOCK_ID, - { - 'recordUndo': false, - 'group': '', - }); - }); - test('Block create', function() { var event = new Blockly.Events.BlockCreate(this.block); sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.CREATE, - this.workspace.id, this.TEST_BLOCK_ID, - { - 'recordUndo': false, - 'group': '', - }); - }); - - test('Delete', function() { - var event = new Blockly.Events.Delete(this.block); - sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.DELETE, + assertEventEquals(event, Blockly.Events.BLOCK_CREATE, this.workspace.id, this.TEST_BLOCK_ID, { 'recordUndo': false, @@ -349,7 +253,7 @@ suite('Events', function() { test('Block delete', function() { var event = new Blockly.Events.BlockDelete(this.block); sinon.assert.calledOnce(this.genUidStub); - assertEventEquals(event, Blockly.Events.DELETE, + assertEventEquals(event, Blockly.Events.BLOCK_DELETE, this.workspace.id, this.TEST_BLOCK_ID, { 'recordUndo': false, @@ -357,35 +261,14 @@ suite('Events', function() { }); }); - suite('Move', function() { - setup(function() { + test('Block move', function() { + try { this.parentBlock = createSimpleTestBlock(this.workspace); this.block.parentBlock_ = this.parentBlock; this.block.xy_ = new Blockly.utils.Coordinate(3, 4); - }); - - teardown(function() { - // This needs to be cleared, otherwise workspace.dispose will fail. - this.block.parentBlock_ = null; - }); - - test('Move', function() { - var event = new Blockly.Events.Move(this.block); - sinon.assert.calledTwice(this.genUidStub); - assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id, - this.TEST_BLOCK_ID, { - 'oldParentId': this.TEST_PARENT_ID, - 'oldInputName': undefined, - 'oldCoordinate': undefined, - 'recordUndo': false, - 'group': '' - }); - }); - - test('Block move', function() { var event = new Blockly.Events.BlockMove(this.block); sinon.assert.calledTwice(this.genUidStub); - assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id, + assertEventEquals(event, Blockly.Events.BLOCK_MOVE, this.workspace.id, this.TEST_BLOCK_ID, { 'oldParentId': this.TEST_PARENT_ID, @@ -394,7 +277,10 @@ suite('Events', function() { 'recordUndo': false, 'group': '' }); - }); + } finally { + // This needs to be cleared, otherwise workspace.dispose will fail. + this.block.parentBlock_ = null; + } }); }); @@ -408,25 +294,10 @@ suite('Events', function() { this.workspace, 'field_variable_test_block'); }); - test('Change', function() { - var event = new Blockly.Events.Change( - this.block, 'field', 'VAR', 'id1', 'id2'); - assertEventEquals(event, Blockly.Events.CHANGE, this.workspace.id, - this.TEST_BLOCK_ID, - { - 'element': 'field', - 'name': 'VAR', - 'oldValue': 'id1', - 'newValue': 'id2', - 'recordUndo': true, - 'group': '' - }); - }); - test('Block change', function() { var event = new Blockly.Events.BlockChange( this.block, 'field', 'VAR', 'id1', 'id2'); - assertEventEquals(event, Blockly.Events.CHANGE, this.workspace.id, + assertEventEquals(event, Blockly.Events.BLOCK_CHANGE, this.workspace.id, this.TEST_BLOCK_ID, { 'element': 'field', @@ -889,7 +760,7 @@ suite('Events', function() { chai.assert.equal(filteredEvents[1].newCoordinate.y, 1); }); - test('Merge move events', function() { + test('Merge block move events', function() { var block = this.workspace.newBlock('field_variable_test_block', '1'); var events = []; addMoveEvent(events, block, 0, 0); @@ -900,11 +771,11 @@ suite('Events', function() { chai.assert.equal(filteredEvents[0].newCoordinate.y, 1); }); - test('Merge change events', function() { + test('Merge block change events', function() { var block1 = this.workspace.newBlock('field_variable_test_block', '1'); var events = [ - new Blockly.Events.Change(block1, 'field', 'VAR', 'item', 'item1'), - new Blockly.Events.Change(block1, 'field', 'VAR', 'item1', 'item2') + new Blockly.Events.BlockChange(block1, 'field', 'VAR', 'item', 'item1'), + new Blockly.Events.BlockChange(block1, 'field', 'VAR', 'item1', 'item2') ]; var filteredEvents = Blockly.Events.filter(events, true); chai.assert.equal(filteredEvents.length, 1); // second change event merged into first @@ -1042,11 +913,11 @@ suite('Events', function() { sinon.assert.calledTwice(genUidStub); assertNthCallEventArgEquals( - this.eventsFireSpy, 0, Blockly.Events.Delete, + this.eventsFireSpy, 0, Blockly.Events.BlockDelete, {oldXml: expectedOldXml, group: ''}, workspaceSvg.id, expectedId); assertNthCallEventArgEquals( - changeListenerSpy, 0, Blockly.Events.Delete, + changeListenerSpy, 0, Blockly.Events.BlockDelete, {oldXml: expectedOldXml, group: ''}, workspaceSvg.id, expectedId); @@ -1086,7 +957,7 @@ suite('Events', function() { {group: TEST_GROUP_ID, varId: TEST_VAR_ID, varName: TEST_VAR_NAME}, this.workspace.id, undefined); assertNthCallEventArgEquals( - this.changeListenerSpy, 1, Blockly.Events.Create, + this.changeListenerSpy, 1, Blockly.Events.BlockCreate, {group: TEST_GROUP_ID}, this.workspace.id, TEST_BLOCK_ID); // Expect the workspace to have a variable with ID 'test_var_id'. @@ -1131,7 +1002,7 @@ suite('Events', function() { {group: TEST_GROUP_ID, varId: TEST_VAR_ID, varName: TEST_VAR_NAME}, this.workspace.id, undefined); assertNthCallEventArgEquals( - this.changeListenerSpy, 1, Blockly.Events.Create, + this.changeListenerSpy, 1, Blockly.Events.BlockCreate, {group: TEST_GROUP_ID}, this.workspace.id, TEST_BLOCK_ID); // Finished loading event should not be part of event group. diff --git a/tests/mocha/keydown_test.js b/tests/mocha/keydown_test.js index aec646111..22fdbf96e 100644 --- a/tests/mocha/keydown_test.js +++ b/tests/mocha/keydown_test.js @@ -93,7 +93,7 @@ suite('Key Down', function() { suite('Copy', function() { setup(function() { setSelectedBlock(this.workspace); - this.copySpy = sinon.spy(Blockly, 'copy'); + this.copySpy = sinon.spy(Blockly.clipboard, 'copy'); this.hideChaffSpy = sinon.spy(Blockly, 'hideChaff'); }); var testCases = [ diff --git a/tests/mocha/run_mocha_tests_in_browser.js b/tests/mocha/run_mocha_tests_in_browser.js index b562586bd..3034f38cc 100644 --- a/tests/mocha/run_mocha_tests_in_browser.js +++ b/tests/mocha/run_mocha_tests_in_browser.js @@ -24,7 +24,8 @@ async function runMochaTestsInBrowser() { }, services: [ ['selenium-standalone'] - ] + ], + logLevel: 'warn' }; // Run in headless mode on Github Actions. if (process.env.CI) { @@ -35,8 +36,11 @@ async function runMochaTestsInBrowser() { ] }; } else { + // --disable-gpu is needed to prevent Chrome from hanging on Linux with + // NVIDIA drivers older than v295.20. See + // https://github.com/google/blockly/issues/5345 for details. options.capabilities['goog:chromeOptions'] = { - args: ['--allow-file-access-from-files'] + args: ['--allow-file-access-from-files', '--disable-gpu'] }; } diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js index 9e0122d71..3a8bed245 100644 --- a/tests/mocha/trashcan_test.js +++ b/tests/mocha/trashcan_test.js @@ -10,7 +10,7 @@ suite("Trashcan", function() { '' + xmlString + ''); xml = xml.children[0]; - var event = new Blockly.Events.Delete(); + var event = new Blockly.Events.BlockDelete(); event.oldXml = xml; event.workspaceId = workspace.id; Blockly.Events.fire(event); diff --git a/tests/playground.html b/tests/playground.html index 11179a0db..b53e76ea8 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -71,7 +71,6 @@