From d4e0594c2cd1dd5df8962e9638d368133817476f Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 19 Aug 2019 09:24:31 -0700 Subject: [PATCH 001/343] Combined inDB_ and hidden_ into single tracked_ property. --- core/connection_db.js | 9 --------- core/rendered_connection.js | 36 +++++++++++++++--------------------- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/core/connection_db.js b/core/connection_db.js index ce7e9487b..a09a33945 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -49,16 +49,12 @@ Blockly.ConnectionDB = function() { * @param {!Blockly.Connection} connection The connection to be added. */ Blockly.ConnectionDB.prototype.addConnection = function(connection) { - if (connection.inDB_) { - throw Error('Connection already in database.'); - } if (connection.getSourceBlock().isInFlyout) { // Don't bother maintaining a database of connections in a flyout. return; } var position = this.findPositionForConnection_(connection); this.connections_.splice(position, 0, connection); - connection.inDB_ = true; }; /** @@ -136,14 +132,10 @@ Blockly.ConnectionDB.prototype.findPositionForConnection_ = function( * @private */ Blockly.ConnectionDB.prototype.removeConnection_ = function(connection) { - if (!connection.inDB_) { - throw Error('Connection not in database.'); - } var removalIndex = this.findConnection(connection); if (removalIndex == -1) { throw Error('Unable to find connection in connectionDB.'); } - connection.inDB_ = false; this.connections_.splice(removalIndex, 1); }; @@ -207,7 +199,6 @@ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) { return neighbours; }; - /** * Is the candidate connection close to the reference connection. * Extremely fast; only looks at Y distance. diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 5320f819d..79d49af69 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -68,18 +68,11 @@ Blockly.RenderedConnection = function(source, type) { this.offsetInBlock_ = new Blockly.utils.Coordinate(0, 0); /** - * Has this connection been added to the connection database? + * Whether this connections is tracked in the database or not. * @type {boolean} * @private */ - this.inDB_ = false; - - /** - * Whether this connections is hidden (not tracked in a database) or not. - * @type {boolean} - * @private - */ - this.hidden_ = !this.db_; + this.tracked_ = false; }; Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); @@ -87,7 +80,7 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); * @override */ Blockly.RenderedConnection.prototype.dispose = function() { - if (this.inDB_) { + if (this.tracked_) { this.db_.removeConnection_(this); } Blockly.RenderedConnection.superClass_.dispose.call(this); @@ -161,16 +154,12 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) * @param {number} y New absolute y coordinate, in workspace coordinates. */ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { - // Remove it from its old location in the database (if already present) - if (this.inDB_) { + if (this.tracked_) { this.db_.removeConnection_(this); + this.db_.addConnection(this); } this.x_ = x; this.y_ = y; - // Insert it into its new location in the database. - if (!this.hidden_) { - this.db_.addConnection(this); - } }; /** @@ -338,12 +327,17 @@ Blockly.RenderedConnection.prototype.unhighlight = function() { * @param {boolean} hidden True if connection is hidden. */ Blockly.RenderedConnection.prototype.setHidden = function(hidden) { - this.hidden_ = hidden; - if (hidden && this.inDB_) { - this.db_.removeConnection_(this); - } else if (!hidden && !this.inDB_) { - this.db_.addConnection(this); + // Temporary: if we're setting hidden to true we want to set tracked to false. + var track = !hidden; + if (track == this.tracked_) { + return; } + if (track) { + this.db_.addConnection(this); + } else { + this.db_.removeConnection_(this); + } + this.tracked_ = track; }; /** From 9d47e2b34e5fa608a9d461a0bfb9e94a2f78e06c Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 19 Aug 2019 10:26:55 -0700 Subject: [PATCH 002/343] Fixed adding and removing from connection DB (will be cleaned up a future PR, but I want to focus on cleaning connections). --- core/connection_db.js | 49 ++++++++++++++++++++----------------- core/rendered_connection.js | 10 ++++---- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/core/connection_db.js b/core/connection_db.js index a09a33945..d18e85264 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -37,7 +37,7 @@ goog.require('Blockly.Connection'); */ Blockly.ConnectionDB = function() { /** - * Array of connections sorted by y coordinate. + * Array of connections sorted by y position in workspace units. * @type {!Array.} * @private */ @@ -45,32 +45,38 @@ Blockly.ConnectionDB = function() { }; /** - * Add a connection to the database. Must not already exist in DB. + * Add a connection to the database. Should not already exist in the database. * @param {!Blockly.Connection} connection The connection to be added. + * @param {number} yPos The y position used to decide where to insert the + * connection. + * @package */ -Blockly.ConnectionDB.prototype.addConnection = function(connection) { +Blockly.ConnectionDB.prototype.addConnection = function(connection, yPos) { if (connection.getSourceBlock().isInFlyout) { // Don't bother maintaining a database of connections in a flyout. return; } - var position = this.findPositionForConnection_(connection); - this.connections_.splice(position, 0, connection); + var index = this.calculateIndexForYPos_(yPos); + this.connections_.splice(index, 0, connection); }; /** - * Find the given connection. + * Finds the index of the given connection. + * * Starts by doing a binary search to find the approximate location, then - * linearly searches nearby for the exact connection. + * linearly searches nearby for the exact connection. * @param {!Blockly.Connection} conn The connection to find. + * @param {number} yPos The y position used to find the index of the connection. * @return {number} The index of the connection, or -1 if the connection was * not found. + * @private */ -Blockly.ConnectionDB.prototype.findConnection = function(conn) { +Blockly.ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) { if (!this.connections_.length) { return -1; } - var bestGuess = this.findPositionForConnection_(conn); + var bestGuess = this.calculateIndexForYPos_(yPos); if (bestGuess >= this.connections_.length) { // Not in list return -1; @@ -98,15 +104,13 @@ Blockly.ConnectionDB.prototype.findConnection = function(conn) { }; /** - * Finds a candidate position for inserting this connection into the list. - * This will be in the correct y order but makes no guarantees about ordering in - * the x axis. - * @param {!Blockly.Connection} connection The connection to insert. + * Finds the correct index for the given y position. + * @param {number} yPos The y position used to decide where to + * insert the connection. * @return {number} The candidate index. * @private */ -Blockly.ConnectionDB.prototype.findPositionForConnection_ = function( - connection) { +Blockly.ConnectionDB.prototype.calculateIndexForYPos_ = function(yPos) { if (!this.connections_.length) { return 0; } @@ -114,9 +118,9 @@ Blockly.ConnectionDB.prototype.findPositionForConnection_ = function( var pointerMax = this.connections_.length; while (pointerMin < pointerMax) { var pointerMid = Math.floor((pointerMin + pointerMax) / 2); - if (this.connections_[pointerMid].y_ < connection.y_) { + if (this.connections_[pointerMid].y_ < yPos) { pointerMin = pointerMid + 1; - } else if (this.connections_[pointerMid].y_ > connection.y_) { + } else if (this.connections_[pointerMid].y_ > yPos) { pointerMax = pointerMid; } else { pointerMin = pointerMid; @@ -129,14 +133,15 @@ Blockly.ConnectionDB.prototype.findPositionForConnection_ = function( /** * Remove a connection from the database. Must already exist in DB. * @param {!Blockly.Connection} connection The connection to be removed. - * @private + * @param {number} yPos The y position used to find the index of the connection. + * @throws {Error} If the connection cannot be found in the database. */ -Blockly.ConnectionDB.prototype.removeConnection_ = function(connection) { - var removalIndex = this.findConnection(connection); - if (removalIndex == -1) { +Blockly.ConnectionDB.prototype.removeConnection = function(connection, yPos) { + var index = this.findIndexOfConnection_(connection, yPos); + if (index == -1) { throw Error('Unable to find connection in connectionDB.'); } - this.connections_.splice(removalIndex, 1); + this.connections_.splice(index, 1); }; /** diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 79d49af69..0ff9aecad 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -81,7 +81,7 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); */ Blockly.RenderedConnection.prototype.dispose = function() { if (this.tracked_) { - this.db_.removeConnection_(this); + this.db_.removeConnection(this, this.y_); } Blockly.RenderedConnection.superClass_.dispose.call(this); }; @@ -155,8 +155,8 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) */ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { if (this.tracked_) { - this.db_.removeConnection_(this); - this.db_.addConnection(this); + this.db_.removeConnection(this, this.y_); + this.db_.addConnection(this, y); } this.x_ = x; this.y_ = y; @@ -333,9 +333,9 @@ Blockly.RenderedConnection.prototype.setHidden = function(hidden) { return; } if (track) { - this.db_.addConnection(this); + this.db_.addConnection(this, this.y_); } else { - this.db_.removeConnection_(this); + this.db_.removeConnection(this, this.y_); } this.tracked_ = track; }; From 08720929d35ea13ee0b377e28ebf1039b313cfd7 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 19 Aug 2019 10:53:00 -0700 Subject: [PATCH 003/343] Changed setConnectionsHidden to waitToTrackConnections and startTrackingConnections. --- core/block_svg.js | 75 +++++++++++++++++++++++++++++------------------ core/xml.js | 8 ++--- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index b04f5eccb..f2004b684 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -141,6 +141,7 @@ Blockly.utils.object.inherits(Blockly.BlockSvg, Blockly.Block); * Height is in workspace units. */ Blockly.BlockSvg.prototype.height = 0; + /** * Width of this block, including any connected value blocks. * Width is in workspace units. @@ -162,6 +163,15 @@ Blockly.BlockSvg.prototype.dragStartXY_ = null; */ Blockly.BlockSvg.prototype.warningTextDb_ = null; +/** + * Should the block tell its connections to start tracking inside the render + * method? Or it should it wait for startTrackingConnections to be called + * separately? + * @type {boolean} + * @private + */ +Blockly.BlockSvg.prototype.waitToTrackConnections_ = false; + /** * Constant for identifying rows that are to be rendered inline. * Don't collide with Blockly.INPUT_VALUE and friends. @@ -1437,35 +1447,41 @@ Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { return input; }; -/** - * Set whether the connections are hidden (not tracked in a database) or not. - * Recursively walk down all child blocks (except collapsed blocks). - * @param {boolean} hidden True if connections are hidden. - * @package - */ -Blockly.BlockSvg.prototype.setConnectionsHidden = function(hidden) { - if (!hidden && this.isCollapsed()) { - if (this.outputConnection) { - this.outputConnection.setHidden(hidden); +Blockly.BlockSvg.prototype.waitToTrackConnections = function() { + this.waitToTrackConnections_ = true; + var children = this.getChildren(); + for (var i = 0, child; child = children[i]; i++) { + child.waitToTrackConnections(); + } +}; + +Blockly.BlockSvg.prototype.startTrackingConnections = function() { + if (this.previousConnection) { + this.previousConnection.setHidden(false); + } + if (this.outputConnection) { + this.outputConnection.setHidden(false); + } + if (this.nextConnection) { + this.nextConnection.setHidden(false); + var child = this.nextConnection.targetBlock(); + if (child) { + child.startTrackingConnections(); } - if (this.previousConnection) { - this.previousConnection.setHidden(hidden); - } - if (this.nextConnection) { - this.nextConnection.setHidden(hidden); - var child = this.nextConnection.targetBlock(); - if (child) { - child.setConnectionsHidden(hidden); - } - } - } else { - var myConnections = this.getConnections_(true); - for (var i = 0, connection; connection = myConnections[i]; i++) { - connection.setHidden(hidden); - if (connection.isSuperior()) { - var child = connection.targetBlock(); - if (child) { - child.setConnectionsHidden(hidden); + } + + // If we're collapsed we want the invisible inputs' connections + // to remain untracked. + if (!this.collapsed_) { + for (var i = 0; i < this.inputList.length; i++) { + var conn = this.inputList[i].connection; + if (conn) { + conn.setHidden(false); + + // Pass tracking on down the chain. + var block = conn.targetBlock(); + if (block) { + block.startTrackingConnections(); } } } @@ -1616,6 +1632,9 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { (/** @type {!Blockly.WorkspaceSvg} */ (this.workspace)).getRenderer().render(this); // No matter how we rendered, connection locations should now be correct. this.updateConnectionLocations_(); + if (!this.waitToTrackConnections_) { + this.startTrackingConnections(); + } if (opt_bubble !== false) { // Render all blocks above this one (propagate a reflow). var parentBlock = this.getParent(); diff --git a/core/xml.js b/core/xml.js index f152f0a0f..6f6478267 100644 --- a/core/xml.js +++ b/core/xml.js @@ -550,8 +550,8 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { // Generate list of all blocks. var blocks = topBlock.getDescendants(false); if (workspace.rendered) { - // Hide connections to speed up assembly. - topBlock.setConnectionsHidden(true); + // Wait to track connections to speed up assembly. + topBlock.waitToTrackConnections(); // Render each block. for (var i = blocks.length - 1; i >= 0; i--) { blocks[i].initSvg(); @@ -562,8 +562,8 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { // Populating the connection database may be deferred until after the // blocks have rendered. setTimeout(function() { - if (topBlock.workspace) { // Check that the block hasn't been deleted. - topBlock.setConnectionsHidden(false); + if (!topBlock.disposed) { // Check that the block hasn't been deleted. + topBlock.startTrackingConnections(); } }, 1); topBlock.updateDisabled(); From 5aaab251a36779a3e6f010d87b24df783b387fc9 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 19 Aug 2019 12:28:51 -0700 Subject: [PATCH 004/343] Changed all other known 'hiding' references to 'tracking'. --- core/block_svg.js | 8 +-- core/input.js | 4 +- core/keyboard_nav/navigation.js | 2 +- core/rendered_connection.js | 122 ++++++++++++++++---------------- 4 files changed, 68 insertions(+), 68 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index f2004b684..dcab41b85 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1457,13 +1457,13 @@ Blockly.BlockSvg.prototype.waitToTrackConnections = function() { Blockly.BlockSvg.prototype.startTrackingConnections = function() { if (this.previousConnection) { - this.previousConnection.setHidden(false); + this.previousConnection.setTracking(true); } if (this.outputConnection) { - this.outputConnection.setHidden(false); + this.outputConnection.setTracking(true); } if (this.nextConnection) { - this.nextConnection.setHidden(false); + this.nextConnection.setTracking(true); var child = this.nextConnection.targetBlock(); if (child) { child.startTrackingConnections(); @@ -1476,7 +1476,7 @@ Blockly.BlockSvg.prototype.startTrackingConnections = function() { for (var i = 0; i < this.inputList.length; i++) { var conn = this.inputList[i].connection; if (conn) { - conn.setHidden(false); + conn.setTracking(true); // Pass tracking on down the chain. var block = conn.targetBlock(); diff --git a/core/input.js b/core/input.js index 2ad195d94..6d290ca70 100644 --- a/core/input.js +++ b/core/input.js @@ -194,9 +194,9 @@ Blockly.Input.prototype.setVisible = function(visible) { if (this.connection) { // Has a connection. if (visible) { - renderList = this.connection.unhideAll(); + renderList = this.connection.startTrackingAll(); } else { - this.connection.hideAll(); + this.connection.stopTrackingAll(); } var child = this.connection.targetBlock(); if (child) { diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 11e6f9503..6fba4eefd 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -208,7 +208,7 @@ Blockly.navigation.insertFromFlyout = function() { // Connections are hidden when the block is first created. Normally there's // enough time for them to become unhidden in the user's mouse movements, // but not here. - newBlock.setConnectionsHidden(false); + newBlock.startTrackingConnections(); workspace.getCursor().setCurNode( Blockly.ASTNode.createBlockNode(newBlock)); if (!Blockly.navigation.modify_()) { diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 0ff9aecad..2018849d8 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -274,17 +274,68 @@ Blockly.RenderedConnection.prototype.highlight = function() { }; /** - * Unhide this connection, as well as all down-stream connections on any block - * attached to this connection. This happens when a block is expanded. - * Also unhides down-stream comments. + * Remove the highlighting around this connection. + */ +Blockly.RenderedConnection.prototype.unhighlight = function() { + Blockly.utils.dom.removeNode(Blockly.Connection.highlightedPath_); + delete Blockly.Connection.highlightedPath_; +}; + +/** + * Set whether this connections is tracked in the database or not. + * @param {boolean} doTracking If true, start tracking. If false, stop tracking. + */ +Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { + if (doTracking == this.tracked_) { + return; + } + if (doTracking) { + this.db_.addConnection(this, this.y_); + } else { + this.db_.removeConnection(this, this.y_); + } + this.tracked_ = doTracking; +}; + +/** + * Stop tracking this connection, as well as all down-stream connections on + * any block attached to this connection. This happens when a block is + * collapsed. + * + * Also closes down-stream icons/bubbles. + * @package + */ +Blockly.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]; + // Stop tracking connections of all children. + var connections = block.getConnections_(true); + for (var 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++) { + icons[j].setVisible(false); + } + } + } +}; + +/** + * 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. */ -Blockly.RenderedConnection.prototype.unhideAll = function() { - this.setHidden(false); - // All blocks that need unhiding must be unhidden 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. +Blockly.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.INPUT_VALUE && this.type != Blockly.NEXT_STATEMENT) { // Only spider down. @@ -304,7 +355,7 @@ Blockly.RenderedConnection.prototype.unhideAll = function() { connections = block.getConnections_(true); } for (var i = 0; i < connections.length; i++) { - renderList.push.apply(renderList, connections[i].unhideAll()); + renderList.push.apply(renderList, connections[i].startTrackingAll()); } if (!renderList.length) { // Leaf block. @@ -314,57 +365,6 @@ Blockly.RenderedConnection.prototype.unhideAll = function() { return renderList; }; -/** - * Remove the highlighting around this connection. - */ -Blockly.RenderedConnection.prototype.unhighlight = function() { - Blockly.utils.dom.removeNode(Blockly.Connection.highlightedPath_); - delete Blockly.Connection.highlightedPath_; -}; - -/** - * Set whether this connections is hidden (not tracked in a database) or not. - * @param {boolean} hidden True if connection is hidden. - */ -Blockly.RenderedConnection.prototype.setHidden = function(hidden) { - // Temporary: if we're setting hidden to true we want to set tracked to false. - var track = !hidden; - if (track == this.tracked_) { - return; - } - if (track) { - this.db_.addConnection(this, this.y_); - } else { - this.db_.removeConnection(this, this.y_); - } - this.tracked_ = track; -}; - -/** - * Hide this connection, as well as all down-stream connections on any block - * attached to this connection. This happens when a block is collapsed. - * Also hides down-stream comments. - */ -Blockly.RenderedConnection.prototype.hideAll = function() { - this.setHidden(true); - if (this.targetConnection) { - var blocks = this.targetBlock().getDescendants(false); - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - // Hide all connections of all children. - var connections = block.getConnections_(true); - for (var j = 0; j < connections.length; j++) { - connections[j].setHidden(true); - } - // Close all bubbles of all children. - var icons = block.getIcons(); - for (var j = 0; j < icons.length; j++) { - icons[j].setVisible(false); - } - } - } -}; - /** * Check if the two connections can be dragged to connect to each other. * @param {!Blockly.Connection} candidate A nearby connection to check. From df5b5766c16f3866ece65f66019ed77ff2fcdaa1 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 19 Aug 2019 12:29:24 -0700 Subject: [PATCH 005/343] General cleanup. --- core/block_svg.js | 54 +++++++++++++++++++++++++------------ core/connection.js | 3 +-- core/connection_db.js | 36 ++++++++++++------------- core/rendered_connection.js | 8 ++++++ core/xml.js | 2 +- 5 files changed, 64 insertions(+), 39 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index dcab41b85..6c44f2bf2 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -165,12 +165,11 @@ Blockly.BlockSvg.prototype.warningTextDb_ = null; /** * Should the block tell its connections to start tracking inside the render - * method? Or it should it wait for startTrackingConnections to be called - * separately? + * method? * @type {boolean} * @private */ -Blockly.BlockSvg.prototype.waitToTrackConnections_ = false; +Blockly.BlockSvg.prototype.doNotCallTrackConnections_ = false; /** * Constant for identifying rows that are to be rendered inline. @@ -1447,14 +1446,31 @@ Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { return input; }; +/** + * Tell the block to wait for an outside source to call + * startTrackingConnections, rather than starting connection + * tracking automatically. + * + * Also tells children of this block to wait. + * @package + */ Blockly.BlockSvg.prototype.waitToTrackConnections = function() { - this.waitToTrackConnections_ = true; + this.doNotCallTrackConnections_ = true; var children = this.getChildren(); for (var i = 0, child; child = children[i]; i++) { child.waitToTrackConnections(); } }; +/** + * Tell this block's connections to add themselves to the connection + * database (i.e. start tracking). + * + * All following/next blocks will be told to start tracking. Inner blocks + * (i.e. blocks attached to value/statement inputs) will be told to start + * tracking if this block is not collapsed. + * @package + */ Blockly.BlockSvg.prototype.startTrackingConnections = function() { if (this.previousConnection) { this.previousConnection.setTracking(true); @@ -1470,19 +1486,19 @@ Blockly.BlockSvg.prototype.startTrackingConnections = function() { } } - // If we're collapsed we want the invisible inputs' connections - // to remain untracked. - if (!this.collapsed_) { - for (var i = 0; i < this.inputList.length; i++) { - var conn = this.inputList[i].connection; - if (conn) { - conn.setTracking(true); + if (this.collapsed_) { + return; + } - // Pass tracking on down the chain. - var block = conn.targetBlock(); - if (block) { - block.startTrackingConnections(); - } + for (var i = 0; i < this.inputList.length; i++) { + var conn = this.inputList[i].connection; + if (conn) { + conn.setTracking(true); + + // Pass tracking on down the chain. + var block = conn.targetBlock(); + if (block) { + block.startTrackingConnections(); } } } @@ -1632,8 +1648,12 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { (/** @type {!Blockly.WorkspaceSvg} */ (this.workspace)).getRenderer().render(this); // No matter how we rendered, connection locations should now be correct. this.updateConnectionLocations_(); - if (!this.waitToTrackConnections_) { + // TODO: This should be handled inside a robust init method, because it would + // make it a lot cleaner, but for now it's handled here for backwards + // compatibility. + if (!this.doNotCallTrackConnections_) { this.startTrackingConnections(); + this.doNotCallTrackConnections_ = true; } if (opt_bubble !== false) { // Render all blocks above this one (propagate a reflow). diff --git a/core/connection.js b/core/connection.js index 082eb9b8c..f788d82cf 100644 --- a/core/connection.js +++ b/core/connection.js @@ -204,8 +204,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) { }; /** - * Dispose of this connection. Deal with connected blocks and remove this - * connection from the database. + * Dispose of this connection and deal with connected blocks. * @package */ Blockly.Connection.prototype.dispose = function() { diff --git a/core/connection_db.js b/core/connection_db.js index d18e85264..102060210 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -19,14 +19,16 @@ */ /** - * @fileoverview Components for managing connections between blocks. + * @fileoverview A database of all the rendered connections that could + * possibly be connected to (i.e. not collapsed, etc). + * Sorted by y coordinate. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.ConnectionDB'); -goog.require('Blockly.Connection'); +goog.require('Blockly.RenderedConnection'); /** @@ -38,7 +40,7 @@ goog.require('Blockly.Connection'); Blockly.ConnectionDB = function() { /** * Array of connections sorted by y position in workspace units. - * @type {!Array.} + * @type {!Array.} * @private */ this.connections_ = []; @@ -46,16 +48,12 @@ Blockly.ConnectionDB = function() { /** * Add a connection to the database. Should not already exist in the database. - * @param {!Blockly.Connection} connection The connection to be added. + * @param {!Blockly.RenderedConnection} connection The connection to be added. * @param {number} yPos The y position used to decide where to insert the * connection. * @package */ Blockly.ConnectionDB.prototype.addConnection = function(connection, yPos) { - if (connection.getSourceBlock().isInFlyout) { - // Don't bother maintaining a database of connections in a flyout. - return; - } var index = this.calculateIndexForYPos_(yPos); this.connections_.splice(index, 0, connection); }; @@ -65,7 +63,7 @@ Blockly.ConnectionDB.prototype.addConnection = function(connection, yPos) { * * Starts by doing a binary search to find the approximate location, then * linearly searches nearby for the exact connection. - * @param {!Blockly.Connection} conn The connection to find. + * @param {!Blockly.RenderedConnection} conn The connection to find. * @param {number} yPos The y position used to find the index of the connection. * @return {number} The index of the connection, or -1 if the connection was * not found. @@ -132,7 +130,7 @@ Blockly.ConnectionDB.prototype.calculateIndexForYPos_ = function(yPos) { /** * Remove a connection from the database. Must already exist in DB. - * @param {!Blockly.Connection} connection The connection to be removed. + * @param {!Blockly.RenderedConnection} connection The connection to be removed. * @param {number} yPos The y position used to find the index of the connection. * @throws {Error} If the connection cannot be found in the database. */ @@ -147,10 +145,10 @@ Blockly.ConnectionDB.prototype.removeConnection = function(connection, yPos) { /** * Find all nearby connections to the given connection. * Type checking does not apply, since this function is used for bumping. - * @param {!Blockly.Connection} connection The connection whose neighbours - * should be returned. + * @param {!Blockly.RenderedConnection} connection The connection whose + * neighbours should be returned. * @param {number} maxRadius The maximum radius to another connection. - * @return {!Array.} List of connections. + * @return {!Array.} List of connections. */ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) { var db = this.connections_; @@ -219,15 +217,15 @@ Blockly.ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) { /** * Find the closest compatible connection to this connection. - * @param {!Blockly.Connection} conn The connection searching for a compatible + * @param {!Blockly.RenderedConnection} conn The connection searching for a compatible * mate. * @param {number} maxRadius The maximum radius to another connection. * @param {!Blockly.utils.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 - * properties:' connection' which is either another connection or null, - * and 'radius' which is the distance. + * @return {!{connection: Blockly.RenderedConnection, radius: number}} + * Contains two properties: 'connection' which is either another + * connection or null, and 'radius' which is the distance. */ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dxy) { @@ -243,10 +241,10 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, conn.x_ = baseX + dxy.x; conn.y_ = baseY + dxy.y; - // findPositionForConnection finds an index for insertion, which is always + // calculateIndexForYPos_ finds an index for insertion, which is always // after any block with the same y index. We want to search both forward // and back, so search on both sides of the index. - var closestIndex = this.findPositionForConnection_(conn); + var closestIndex = this.calculateIndexForYPos_(conn.y_); var bestConnection = null; var bestRadius = maxRadius; diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 2018849d8..ecf156e59 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -77,7 +77,10 @@ Blockly.RenderedConnection = function(source, type) { Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); /** + * Dispose of this connection. Remove it from the database (if it is + * tracked) and call the super-function to deal with connected blocks. * @override + * @package */ Blockly.RenderedConnection.prototype.dispose = function() { if (this.tracked_) { @@ -284,11 +287,16 @@ Blockly.RenderedConnection.prototype.unhighlight = function() { /** * Set whether this connections is tracked in the database or not. * @param {boolean} doTracking If true, start tracking. If false, stop tracking. + * @package */ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { if (doTracking == this.tracked_) { return; } + if (this.sourceBlock_.isInFlyout) { + // Don't bother maintaining a database of connections in a flyout. + return; + } if (doTracking) { this.db_.addConnection(this, this.y_); } else { diff --git a/core/xml.js b/core/xml.js index 6f6478267..fde92fccd 100644 --- a/core/xml.js +++ b/core/xml.js @@ -562,7 +562,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { // Populating the connection database may be deferred until after the // blocks have rendered. setTimeout(function() { - if (!topBlock.disposed) { // Check that the block hasn't been deleted. + if (!topBlock.disposed) { topBlock.startTrackingConnections(); } }, 1); From f21732015414feecad6161118d4f3451c9733512 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 1 Oct 2019 19:27:47 -0700 Subject: [PATCH 006/343] Unskipped tests. --- tests/mocha/connection_db_test.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/mocha/connection_db_test.js b/tests/mocha/connection_db_test.js index 1e2639a8e..e295a32f6 100644 --- a/tests/mocha/connection_db_test.js +++ b/tests/mocha/connection_db_test.js @@ -47,10 +47,7 @@ suite('Connection Database', function() { } }; }); - // TODO: Re-enable once flyout checking is handled by the connection - // (better yet - let it be handled by the flyout, but that's out of the - // scope of this). - test.skip('Add Connection', function() { + test('Add Connection', function() { var y2 = {y_: 2}; var y4 = {y_: 4}; var y1 = {y_: 1}; @@ -78,7 +75,7 @@ suite('Connection Database', function() { this.database.connections_, [y1, y2, y3b, y3a, y4]); }); - test.skip('Remove Connection', function() { + test('Remove Connection', function() { var y2 = {y_: 2}; var y4 = {y_: 4}; var y1 = {y_: 1}; From 45d66a1264a585b4a2c6723999274602e495a266 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 3 Oct 2019 17:58:29 -0700 Subject: [PATCH 007/343] Get rid of unnecessary nulls in block dragger, insertion marker manager, and gesture dispose functions. --- core/block_dragger.js | 4 ---- core/gesture.js | 10 ---------- core/insertion_marker_manager.js | 8 -------- 3 files changed, 22 deletions(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 7b8f3232b..f1b8a4f5b 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -100,14 +100,10 @@ Blockly.BlockDragger = function(block, workspace) { * @package */ Blockly.BlockDragger.prototype.dispose = function() { - this.draggingBlock_ = null; - this.workspace_ = null; - this.startWorkspace_ = null; this.dragIconData_.length = 0; if (this.draggedConnectionManager_) { this.draggedConnectionManager_.dispose(); - this.draggedConnectionManager_ = null; } }; diff --git a/core/gesture.js b/core/gesture.js index f27dfa982..677feabae 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -250,24 +250,14 @@ Blockly.Gesture.prototype.dispose = function() { Blockly.unbindEvent_(this.onUpWrapper_); } - - this.startField_ = null; - this.startBlock_ = null; - this.targetBlock_ = null; - this.startWorkspace_ = null; - this.flyout_ = null; - if (this.blockDragger_) { this.blockDragger_.dispose(); - this.blockDragger_ = null; } if (this.workspaceDragger_) { this.workspaceDragger_.dispose(); - this.workspaceDragger_ = null; } if (this.bubbleDragger_) { this.bubbleDragger_.dispose(); - this.bubbleDragger_ = null; } }; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 62f46719c..85c23d43a 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -146,27 +146,19 @@ Blockly.InsertionMarkerManager = function(block) { * @package */ Blockly.InsertionMarkerManager.prototype.dispose = function() { - this.topBlock_ = null; - this.workspace_ = null; this.availableConnections_.length = 0; - this.closestConnection_ = null; - this.localConnection_ = null; Blockly.Events.disable(); try { if (this.firstMarker_) { this.firstMarker_.dispose(); - this.firstMarker_ = null; } if (this.lastMarker_) { this.lastMarker_.dispose(); - this.lastMarker_ = null; } } finally { Blockly.Events.enable(); } - - this.highlightedBlock_ = null; }; /** From 79c2fa6688f518fcb0285ec18929dc5a5471d0fd Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 3 Oct 2019 18:08:27 -0700 Subject: [PATCH 008/343] Make trashcan setOpen package and update a few annotations. --- core/block_dragger.js | 4 ++-- core/bubble_dragger.js | 4 ++-- core/trashcan.js | 14 +++++++------- core/workspace_svg.js | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 7b8f3232b..60a2db9f9 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -301,12 +301,12 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() { if (this.wouldDeleteBlock_) { this.draggingBlock_.setDeleteStyle(true); if (this.deleteArea_ == Blockly.DELETE_AREA_TRASH && trashcan) { - trashcan.setOpen_(true); + trashcan.setOpen(true); } } else { this.draggingBlock_.setDeleteStyle(false); if (trashcan) { - trashcan.setOpen_(false); + trashcan.setOpen(false); } } }; diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index e19bb6169..65136e91c 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -178,12 +178,12 @@ Blockly.BubbleDragger.prototype.updateCursorDuringBubbleDrag_ = function() { if (this.wouldDeleteBubble_) { this.draggingBubble_.setDeleteStyle(true); if (this.deleteArea_ == Blockly.DELETE_AREA_TRASH && trashcan) { - trashcan.setOpen_(true); + trashcan.setOpen(true); } } else { this.draggingBubble_.setDeleteStyle(false); if (trashcan) { - trashcan.setOpen_(false); + trashcan.setOpen(false); } } }; diff --git a/core/trashcan.js b/core/trashcan.js index 7b5d676d5..24c845742 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -295,7 +295,7 @@ Blockly.Trashcan.prototype.init = function(verticalSpacing) { } this.verticalSpacing_ = this.MARGIN_BOTTOM_ + verticalSpacing; - this.setOpen_(false); + this.setOpen(false); return this.verticalSpacing_ + this.BODY_HEIGHT_ + this.LID_HEIGHT_; }; @@ -370,9 +370,9 @@ Blockly.Trashcan.prototype.getClientRect = function() { /** * Flip the lid open or shut. * @param {boolean} state True if open. - * @private + * @package */ -Blockly.Trashcan.prototype.setOpen_ = function(state) { +Blockly.Trashcan.prototype.setOpen = function(state) { if (this.isOpen == state) { return; } @@ -416,7 +416,7 @@ Blockly.Trashcan.prototype.setLidAngle_ = function(lidAngle) { * Called externally after a drag. */ Blockly.Trashcan.prototype.close = function() { - this.setOpen_(false); + this.setOpen(false); }; /** @@ -440,7 +440,7 @@ Blockly.Trashcan.prototype.click = function() { */ Blockly.Trashcan.prototype.mouseOver_ = function() { if (this.contents_.length) { - this.setOpen_(true); + this.setOpen(true); } }; @@ -451,8 +451,8 @@ Blockly.Trashcan.prototype.mouseOver_ = function() { */ Blockly.Trashcan.prototype.mouseOut_ = function() { // No need to do a .hasBlocks check here because if it doesn't the trashcan - // wont be open in the first place, and setOpen_ won't run. - this.setOpen_(false); + // won't be open in the first place, and setOpen won't run. + this.setOpen(false); }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index fd0de41bb..8cc431587 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -361,7 +361,7 @@ Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; /** * Map from function names to callbacks, for deciding what to do when a button * is clicked. - * @type {!Object.} + * @type {!Object.} * @private */ Blockly.WorkspaceSvg.prototype.flyoutButtonCallbacks_ = {}; @@ -369,7 +369,7 @@ Blockly.WorkspaceSvg.prototype.flyoutButtonCallbacks_ = {}; /** * Map from function names to callbacks, for deciding what to do when a custom * toolbox category is opened. - * @type {!Object.>} + * @type {!Object.>} * @private */ Blockly.WorkspaceSvg.prototype.toolboxCategoryCallbacks_ = {}; From db33e821da85577ba45bb646bedd1853f1f633a6 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Fri, 4 Oct 2019 15:57:35 -0700 Subject: [PATCH 009/343] Remove call to setText in playground (#3168) * Remove last instance of setText --- tests/playground.html | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/playground.html b/tests/playground.html index 5f9526d55..d8d67fc25 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -237,7 +237,6 @@ function addToolboxButtonCallbacks() { for (var i = 0, block; block = blocks[i]; i++) { var imageField = block.getField('IMAGE'); imageField.setValue(src); - imageField.setText(image); } }; var addVariables = function(button) { From e09a7b8165e8f587fe85fbefbbeaeaef34e3131c Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 5 Oct 2019 12:28:25 -0700 Subject: [PATCH 010/343] Renamed doNotCallTrackConnections_ to callTrackConnections. Flipped logic. Moved it to the constructor. --- core/block_svg.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 6c44f2bf2..e679a7836 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -133,6 +133,14 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @private */ this.markerSvg_ = null; + + /** + * Should the block tell its connections to start tracking inside the render + * method? + * @type {boolean} + * @private + */ + this.callTrackConnections_ = true; }; Blockly.utils.object.inherits(Blockly.BlockSvg, Blockly.Block); @@ -163,14 +171,6 @@ Blockly.BlockSvg.prototype.dragStartXY_ = null; */ Blockly.BlockSvg.prototype.warningTextDb_ = null; -/** - * Should the block tell its connections to start tracking inside the render - * method? - * @type {boolean} - * @private - */ -Blockly.BlockSvg.prototype.doNotCallTrackConnections_ = false; - /** * Constant for identifying rows that are to be rendered inline. * Don't collide with Blockly.INPUT_VALUE and friends. @@ -1455,7 +1455,7 @@ Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { * @package */ Blockly.BlockSvg.prototype.waitToTrackConnections = function() { - this.doNotCallTrackConnections_ = true; + this.callTrackConnections_ = false; var children = this.getChildren(); for (var i = 0, child; child = children[i]; i++) { child.waitToTrackConnections(); @@ -1651,9 +1651,9 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { // TODO: This should be handled inside a robust init method, because it would // make it a lot cleaner, but for now it's handled here for backwards // compatibility. - if (!this.doNotCallTrackConnections_) { + if (this.callTrackConnections_) { this.startTrackingConnections(); - this.doNotCallTrackConnections_ = true; + this.callTrackConnections_ = false; } if (opt_bubble !== false) { // Render all blocks above this one (propagate a reflow). From ddd0cb56327cdafd19441406333094977b43dfd3 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 7 Oct 2019 19:41:12 +0200 Subject: [PATCH 011/343] Localisation updates from https://translatewiki.net. --- msg/json/bcc.json | 2 +- msg/json/qqq.json | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/msg/json/bcc.json b/msg/json/bcc.json index f869b1310..9a13638bd 100644 --- a/msg/json/bcc.json +++ b/msg/json/bcc.json @@ -226,7 +226,7 @@ "LISTS_GET_INDEX_FROM_END": "# از انتها", "LISTS_GET_INDEX_FIRST": "اولین", "LISTS_GET_INDEX_LAST": "اهرین", - "LISTS_GET_INDEX_RANDOM": "تصادفی", + "LISTS_GET_INDEX_RANDOM": "یکپارگی", "LISTS_INDEX_FROM_START_TOOLTIP": "%1 اولین مورد است.", "LISTS_INDEX_FROM_END_TOOLTIP": "%1 آخرین مورد است.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM": "موردی در محل مشخص‌شده بر می‌گرداند.", diff --git a/msg/json/qqq.json b/msg/json/qqq.json index 64d459cf1..c6c5d401a 100644 --- a/msg/json/qqq.json +++ b/msg/json/qqq.json @@ -1,4 +1,13 @@ { + "@metadata": { + "authors": [ + "Espertus", + "Liuxinyu970226", + "Metalhead64", + "Robby", + "Shirayuki" + ] + }, "VARIABLES_DEFAULT_NAME": "default name - A simple, general default name for a variable, preferably short. For more context, see [[Translating:Blockly#infrequent_message_types]].\n{{Identical|Item}}", "UNNAMED_KEY": "default name - A simple, default name for an unnamed function or variable. Preferably indicates that the item is unnamed.", "TODAY": "button text - Button that sets a calendar to today's date.\n{{Identical|Today}}", From 2ac4149d988269f30028f77855692e36ace42d85 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 7 Oct 2019 11:06:56 -0700 Subject: [PATCH 012/343] Misc compiler warnings. (#3172) * Fix misc compiler warnings. Use ws.getToolbox() instead of ws.toolbox_ --- blocks/procedures.js | 4 ++-- core/blockly.js | 9 +++++---- core/bubble.js | 8 +++----- core/bubble_dragger.js | 7 ++++--- core/comment.js | 6 ++++-- core/inject.js | 4 ++-- core/mutator.js | 6 +++--- core/workspace.js | 4 ++-- core/workspace_svg.js | 3 ++- demos/code/code.js | 4 ++-- demos/custom-fields/turtle/index.html | 10 +++++----- tests/generators/index.html | 2 +- tests/jsunit/workspace_test.js | 12 ++++++------ tests/jsunit/xml_test.js | 8 ++++---- tests/mocha/xml_procedures_test.js | 2 +- tests/playground.html | 10 +++++----- tests/screenshot/gen_screenshots.js | 2 +- tests/workspace_svg/workspace_svg_test.js | 20 ++++++++++---------- 18 files changed, 62 insertions(+), 59 deletions(-) diff --git a/blocks/procedures.js b/blocks/procedures.js index ff0a4e3cb..761e4877d 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -496,7 +496,7 @@ Blockly.Blocks['procedures_mutatorcontainer'] = { (event.type != Blockly.Events.BLOCK_DELETE && event.type != Blockly.Events.BLOCK_CREATE)) { return; } - var blocks = this.workspace.getAllBlocks(); + var blocks = this.workspace.getAllBlocks(false); var allVariables = this.workspace.getAllVariables(); if (event.type == Blockly.Events.BLOCK_DELETE) { var variableNamesToKeep = []; @@ -602,7 +602,7 @@ Blockly.Blocks['procedures_mutatorarg'] = { } // Prevents duplicate parameter names in functions - var blocks = sourceBlock.workspace.getAllBlocks(); + var blocks = sourceBlock.workspace.getAllBlocks(false); for (var i = 0; i < blocks.length; i++) { if (blocks[i].id == this.getSourceBlock().id) { continue; diff --git a/core/blockly.js b/core/blockly.js index 6b5abf6fa..e4e8203c0 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -339,10 +339,11 @@ Blockly.hideChaff = function(opt_allowToolbox) { workspace.trashcan.flyout_) { workspace.trashcan.flyout_.hide(); } - if (workspace.toolbox_ && - workspace.toolbox_.flyout_ && - workspace.toolbox_.flyout_.autoClose) { - workspace.toolbox_.clearSelection(); + var toolbox = workspace.getToolbox(); + if (toolbox && + toolbox.flyout_ && + toolbox.flyout_.autoClose) { + toolbox.clearSelection(); } } }; diff --git a/core/bubble.js b/core/bubble.js index 8c245631b..53cbe5755 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -455,12 +455,10 @@ Blockly.Bubble.prototype.layoutBubble_ = function() { /** * Calculate the what percentage of the bubble overlaps with the visible * workspace (what percentage of the bubble is visible). - * @param {!Object} relativeMin The position of the top-left corner of the - * bubble relative to the anchor point. - * @param {number} relativeMin.x The x-position of the relativeMin. - * @param {number} relativeMin.y The y-position of the relativeMin. + * @param {!{x: number, y: number}} relativeMin The position of the top-left + * corner of the bubble relative to the anchor point. * @param {!Object} metrics The metrics of the workspace the bubble will - * appear in. + * appear in. * @return {number} The percentage of the bubble that is visible. * @private */ diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index 65136e91c..c4cc6910d 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -218,10 +218,10 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function( } this.workspace_.setResizesEnabled(true); - if (this.workspace_.toolbox_) { + if (this.workspace_.getToolbox()) { var style = this.draggingBubble_.isDeletable() ? 'blocklyToolboxDelete' : 'blocklyToolboxGrab'; - this.workspace_.toolbox_.removeStyle(style); + this.workspace_.getToolbox().removeStyle(style); } Blockly.Events.setGroup(false); }; @@ -232,7 +232,8 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function( */ Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() { if (this.draggingBubble_.isComment) { - var event = new Blockly.Events.CommentMove(this.draggingBubble_); + var event = new Blockly.Events.CommentMove( + /** @type {!Blockly.WorkspaceCommentSvg} */ (this.draggingBubble_)); event.setOldCoordinate(this.startXY_); event.recordNew(); Blockly.Events.fire(event); diff --git a/core/comment.js b/core/comment.js index ce2b7b642..fe9494630 100644 --- a/core/comment.js +++ b/core/comment.js @@ -255,7 +255,8 @@ Blockly.Comment.prototype.createEditableBubble_ = function() { */ Blockly.Comment.prototype.createNonEditableBubble_ = function() { // TODO (#2917): It would be great if the comment could support line breaks. - Blockly.Warning.prototype.createBubble.call(this); + Blockly.Warning.prototype.createBubble.call( + /** @type {Blockly.Warning} */ (this)); }; /** @@ -265,7 +266,8 @@ Blockly.Comment.prototype.createNonEditableBubble_ = function() { Blockly.Comment.prototype.disposeBubble_ = function() { if (this.paragraphElement_) { // We're using the warning UI so we have to let it dispose. - Blockly.Warning.prototype.disposeBubble.call(this); + Blockly.Warning.prototype.disposeBubble.call( + /** @type {Blockly.Warning} */ (this)); return; } diff --git a/core/inject.js b/core/inject.js index 74c755fa2..2019bc1d9 100644 --- a/core/inject.js +++ b/core/inject.js @@ -411,8 +411,8 @@ Blockly.init_ = function(mainWorkspace) { Blockly.inject.bindDocumentEvents_(); if (options.languageTree) { - if (mainWorkspace.toolbox_) { - mainWorkspace.toolbox_.init(mainWorkspace); + if (mainWorkspace.getToolbox()) { + mainWorkspace.getToolbox().init(mainWorkspace); } else if (mainWorkspace.flyout_) { // Build a fixed flyout with the root blocks. mainWorkspace.flyout_.init(mainWorkspace); diff --git a/core/mutator.js b/core/mutator.js index 0f35789f3..72d8e77df 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -420,14 +420,14 @@ Blockly.Mutator.prototype.dispose = function() { Blockly.Mutator.prototype.updateBlockStyle = function() { var ws = this.workspace_; - if (ws && ws.getAllBlocks()) { - var workspaceBlocks = ws.getAllBlocks(); + if (ws && ws.getAllBlocks(false)) { + var workspaceBlocks = ws.getAllBlocks(false); for (var i = 0; i < workspaceBlocks.length; i++) { var block = workspaceBlocks[i]; block.setStyle(block.getStyleName()); } - var flyoutBlocks = ws.flyout_.workspace_.getAllBlocks(); + var flyoutBlocks = ws.flyout_.workspace_.getAllBlocks(false); for (var i = 0; i < flyoutBlocks.length; i++) { var block = flyoutBlocks[i]; block.setStyle(block.getStyleName()); diff --git a/core/workspace.js b/core/workspace.js index 1d615dbae..cd1514bc5 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -226,7 +226,7 @@ Blockly.Workspace.prototype.setTheme = function(theme) { */ Blockly.Workspace.prototype.refreshTheme = function() { // Update all blocks in workspace that have a style name. - this.updateBlockStyles_(this.getAllBlocks().filter( + this.updateBlockStyles_(this.getAllBlocks(false).filter( function(block) { return block.getStyleName() !== undefined; } @@ -651,7 +651,7 @@ Blockly.Workspace.prototype.remainingCapacity = function() { return Infinity; } - return this.options.maxBlocks - this.getAllBlocks().length; + return this.options.maxBlocks - this.getAllBlocks(false).length; }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 8cc431587..f318c4364 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -90,7 +90,8 @@ Blockly.WorkspaceSvg = function(options, * @type {!Blockly.WorkspaceAudio} * @private */ - this.audioManager_ = new Blockly.WorkspaceAudio(options.parentWorkspace); + this.audioManager_ = new Blockly.WorkspaceAudio( + /** @type {Blockly.WorkspaceSvg} */ (options.parentWorkspace)); /** * This workspace's grid object or null. diff --git a/demos/code/code.js b/demos/code/code.js index 67cace73c..2e8426bf7 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -379,9 +379,9 @@ Code.init = function() { el.style.width = (2 * bBox.width - el.offsetWidth) + 'px'; } // Make the 'Blocks' tab line up with the toolbox. - if (Code.workspace && Code.workspace.toolbox_.width) { + if (Code.workspace && Code.workspace.getToolbox().width) { document.getElementById('tab_blocks').style.minWidth = - (Code.workspace.toolbox_.width - 38) + 'px'; + (Code.workspace.getToolbox().width - 38) + 'px'; // Account for the 19 pixel margin and on each side. } }; diff --git a/demos/custom-fields/turtle/index.html b/demos/custom-fields/turtle/index.html index 682eb8aa8..484fc2b3e 100644 --- a/demos/custom-fields/turtle/index.html +++ b/demos/custom-fields/turtle/index.html @@ -89,7 +89,7 @@ } function setRandomStyle() { - var blocks = workspace.getAllBlocks(); + var blocks = workspace.getAllBlocks(false); var styles = Object.keys(workspace.getTheme().getAllBlockStyles()); styles.splice(styles.indexOf(blocks[0].getStyleName()), 1); var style = styles[Math.floor(Math.random() * styles.length)]; @@ -99,14 +99,14 @@ } function toggleShadow() { - var blocks = workspace.getAllBlocks(); + var blocks = workspace.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setShadow(!block.isShadow()); } } function toggleEnabled() { - var blocks = workspace.getAllBlocks(); + var blocks = workspace.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setEnabled(!block.isEnabled()); } @@ -114,7 +114,7 @@ function toggleEditable() { Blockly.hideChaff(); - var blocks = workspace.getAllBlocks(); + var blocks = workspace.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setEditable(!block.isEditable()); } @@ -122,7 +122,7 @@ function toggleCollapsed() { Blockly.hideChaff(); - var blocks = workspace.getAllBlocks(); + var blocks = workspace.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setCollapsed(!block.isCollapsed()); } diff --git a/tests/generators/index.html b/tests/generators/index.html index 6b5eb4d67..e1f88f22a 100644 --- a/tests/generators/index.html +++ b/tests/generators/index.html @@ -257,7 +257,7 @@ function toDart() { function changeIndex() { var oneBasedIndex = document.getElementById('indexing').checked; demoWorkspace.options.oneBasedIndex = oneBasedIndex; - demoWorkspace.toolbox_.flyout_.workspace_.options.oneBasedIndex = oneBasedIndex; + demoWorkspace.getToolbox().flyout_.workspace_.options.oneBasedIndex = oneBasedIndex; } diff --git a/tests/jsunit/workspace_test.js b/tests/jsunit/workspace_test.js index ff85e7f3d..916cbeead 100644 --- a/tests/jsunit/workspace_test.js +++ b/tests/jsunit/workspace_test.js @@ -38,11 +38,11 @@ function test_emptyWorkspace() { try { assertEquals('Empty workspace (1).', 0, workspace.getTopBlocks(true).length); assertEquals('Empty workspace (2).', 0, workspace.getTopBlocks(false).length); - assertEquals('Empty workspace (3).', 0, workspace.getAllBlocks().length); + assertEquals('Empty workspace (3).', 0, workspace.getAllBlocks(false).length); workspace.clear(); assertEquals('Empty workspace (4).', 0, workspace.getTopBlocks(true).length); assertEquals('Empty workspace (5).', 0, workspace.getTopBlocks(false).length); - assertEquals('Empty workspace (6).', 0, workspace.getAllBlocks().length); + assertEquals('Empty workspace (6).', 0, workspace.getAllBlocks(false).length); } finally { workspaceTest_tearDown(); } @@ -54,19 +54,19 @@ function test_flatWorkspace() { var blockA = workspace.newBlock(''); assertEquals('One block workspace (1).', 1, workspace.getTopBlocks(true).length); assertEquals('One block workspace (2).', 1, workspace.getTopBlocks(false).length); - assertEquals('One block workspace (3).', 1, workspace.getAllBlocks().length); + assertEquals('One block workspace (3).', 1, workspace.getAllBlocks(false).length); var blockB = workspace.newBlock(''); assertEquals('Two block workspace (1).', 2, workspace.getTopBlocks(true).length); assertEquals('Two block workspace (2).', 2, workspace.getTopBlocks(false).length); - assertEquals('Two block workspace (3).', 2, workspace.getAllBlocks().length); + assertEquals('Two block workspace (3).', 2, workspace.getAllBlocks(false).length); blockA.dispose(); assertEquals('One block workspace (4).', 1, workspace.getTopBlocks(true).length); assertEquals('One block workspace (5).', 1, workspace.getTopBlocks(false).length); - assertEquals('One block workspace (6).', 1, workspace.getAllBlocks().length); + assertEquals('One block workspace (6).', 1, workspace.getAllBlocks(false).length); workspace.clear(); assertEquals('Cleared workspace (1).', 0, workspace.getTopBlocks(true).length); assertEquals('Cleared workspace (2).', 0, workspace.getTopBlocks(false).length); - assertEquals('Cleared workspace (3).', 0, workspace.getAllBlocks().length); + assertEquals('Cleared workspace (3).', 0, workspace.getAllBlocks(false).length); } finally { workspaceTest_tearDown(); } diff --git a/tests/jsunit/xml_test.js b/tests/jsunit/xml_test.js index c2c6ec741..afd3dc9c7 100644 --- a/tests/jsunit/xml_test.js +++ b/tests/jsunit/xml_test.js @@ -142,7 +142,7 @@ function test_domToWorkspace_BackwardCompatibility() { ' ' + ''); Blockly.Xml.domToWorkspace(dom, workspace); - assertEquals('Block count', 1, workspace.getAllBlocks().length); + assertEquals('Block count', 1, workspace.getAllBlocks(false).length); checkVariableValues(workspace, 'name1', '', '1'); } finally { xmlTest_tearDownWithMockBlocks(); @@ -165,7 +165,7 @@ function test_domToWorkspace_VariablesAtTop() { ' ' + ''); Blockly.Xml.domToWorkspace(dom, workspace); - assertEquals('Block count', 1, workspace.getAllBlocks().length); + assertEquals('Block count', 1, workspace.getAllBlocks(false).length); checkVariableValues(workspace, 'name1', 'type1', 'id1'); checkVariableValues(workspace, 'name2', 'type2', 'id2'); checkVariableValues(workspace, 'name3', '', 'id3'); @@ -268,9 +268,9 @@ function test_appendDomToWorkspace() { ''); workspace = new Blockly.Workspace(); Blockly.Xml.appendDomToWorkspace(dom, workspace); - assertEquals('Block count', 1, workspace.getAllBlocks().length); + assertEquals('Block count', 1, workspace.getAllBlocks(false).length); var newBlockIds = Blockly.Xml.appendDomToWorkspace(dom, workspace); - assertEquals('Block count', 2, workspace.getAllBlocks().length); + assertEquals('Block count', 2, workspace.getAllBlocks(false).length); assertEquals('Number of new block ids',1,newBlockIds.length); } finally { delete Blockly.Blocks.test_block; diff --git a/tests/mocha/xml_procedures_test.js b/tests/mocha/xml_procedures_test.js index 7af53e635..5af798c9e 100644 --- a/tests/mocha/xml_procedures_test.js +++ b/tests/mocha/xml_procedures_test.js @@ -238,7 +238,7 @@ suite('Procedures XML', function() { // defined for call_noreturn. Make it defined for both. /* chai.assert.isArray(block.argumentVarModels_); chai.assert.isEmpty(block.argumentVarModels_); */ - chai.assert.equal(this.workspace.getAllBlocks().count, 2); + chai.assert.equal(this.workspace.getAllBlocks(false).count, 2); }); }); test('Caller W/ Params', function() { diff --git a/tests/playground.html b/tests/playground.html index d8d67fc25..be4b9b29d 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -192,7 +192,7 @@ function addToolboxButtonCallbacks() { } }; var setRandomStyle = function(button) { - var blocks = button.workspace_.getAllBlocks(); + var blocks = button.workspace_.getAllBlocks(false); var styles = Object.keys(workspace.getTheme().getAllBlockStyles()); styles.splice(styles.indexOf(blocks[0].getStyleName()), 1); var style = styles[Math.floor(Math.random() * styles.length)]; @@ -201,26 +201,26 @@ function addToolboxButtonCallbacks() { } }; var toggleEnabled = function(button) { - var blocks = button.workspace_.getAllBlocks(); + var blocks = button.workspace_.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setEnabled(!block.isEnabled()); } }; var toggleShadow = function(button) { - var blocks = button.workspace_.getAllBlocks(); + var blocks = button.workspace_.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setShadow(!block.isShadow()); } }; var toggleCollapsed = function(button) { - var blocks = button.workspace_.getAllBlocks(); + var blocks = button.workspace_.getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { block.setCollapsed(!block.isCollapsed()); } }; var setInput = function(button) { Blockly.prompt('Input text to set.', 'ab', function(input) { - var blocks = button.getTargetWorkspace().getAllBlocks(); + var blocks = button.getTargetWorkspace().getAllBlocks(false); for(var i = 0, block; block = blocks[i]; i++) { if (block.getField('INPUT')) { block.setFieldValue(input, 'INPUT'); diff --git a/tests/screenshot/gen_screenshots.js b/tests/screenshot/gen_screenshots.js index cd49443dc..fc938ea60 100644 --- a/tests/screenshot/gen_screenshots.js +++ b/tests/screenshot/gen_screenshots.js @@ -167,7 +167,7 @@ async function genSingleScreenshot(browser, dir, test_name, isCollapsed, isInser var xml = Blockly.Xml.textToDom(xml_text); Blockly.Xml.domToWorkspace(xml, workspace); if (isCollapsed || isInsertionMarker || inlineInputs || externalInputs) { - var blocks = workspace.getAllBlocks(); + var blocks = workspace.getAllBlocks(false); for (var i = 0, block; block = blocks[i]; i++) { block.setCollapsed(isCollapsed); block.setInsertionMarker(isInsertionMarker); diff --git a/tests/workspace_svg/workspace_svg_test.js b/tests/workspace_svg/workspace_svg_test.js index 696805df8..56eccb64a 100644 --- a/tests/workspace_svg/workspace_svg_test.js +++ b/tests/workspace_svg/workspace_svg_test.js @@ -73,11 +73,11 @@ function test_emptyWorkspace() { try { assertEquals('Empty workspace (1).', 0, workspace.getTopBlocks(true).length); assertEquals('Empty workspace (2).', 0, workspace.getTopBlocks(false).length); - assertEquals('Empty workspace (3).', 0, workspace.getAllBlocks().length); + assertEquals('Empty workspace (3).', 0, workspace.getAllBlocks(false).length); workspace.clear(); assertEquals('Empty workspace (4).', 0, workspace.getTopBlocks(true).length); assertEquals('Empty workspace (5).', 0, workspace.getTopBlocks(false).length); - assertEquals('Empty workspace (6).', 0, workspace.getAllBlocks().length); + assertEquals('Empty workspace (6).', 0, workspace.getAllBlocks(false).length); } finally { workspace.dispose(); } @@ -90,11 +90,11 @@ function test_flatWorkspace() { blockA = helper_createNewBlock(workspace, ''); assertEquals('One block workspace (1).', 1, workspace.getTopBlocks(true).length); assertEquals('One block workspace (2).', 1, workspace.getTopBlocks(false).length); - assertEquals('One block workspace (3).', 1, workspace.getAllBlocks().length); + assertEquals('One block workspace (3).', 1, workspace.getAllBlocks(false).length); blockB = helper_createNewBlock(workspace, ''); assertEquals('Two block workspace (1).', 2, workspace.getTopBlocks(true).length); assertEquals('Two block workspace (2).', 2, workspace.getTopBlocks(false).length); - assertEquals('Two block workspace (3).', 2, workspace.getAllBlocks().length); + assertEquals('Two block workspace (3).', 2, workspace.getAllBlocks(false).length); try { blockA.dispose(); } catch (e) { @@ -103,11 +103,11 @@ function test_flatWorkspace() { assertEquals('One block workspace (4).', 1, workspace.getTopBlocks(true).length); assertEquals('One block workspace (5).', 1, workspace.getTopBlocks(false).length); - assertEquals('One block workspace (6).', 1, workspace.getAllBlocks().length); + assertEquals('One block workspace (6).', 1, workspace.getAllBlocks(false).length); workspace.clear(); assertEquals('Cleared workspace (1).', 0, workspace.getTopBlocks(true).length); assertEquals('Cleared workspace (2).', 0, workspace.getTopBlocks(false).length); - assertEquals('Cleared workspace (3).', 0, workspace.getAllBlocks().length); + assertEquals('Cleared workspace (3).', 0, workspace.getAllBlocks(false).length); } finally { blockB && blockB.dispose(); blockA && blockA.dispose(); @@ -125,10 +125,10 @@ function test_appendDomToWorkspace() { ' ' + ''); Blockly.Xml.appendDomToWorkspace(dom, workspace); - assertEquals('Block count', 1, workspace.getAllBlocks().length); + assertEquals('Block count', 1, workspace.getAllBlocks(false).length); Blockly.Xml.appendDomToWorkspace(dom, workspace); - assertEquals('Block count', 2, workspace.getAllBlocks().length); - var blocks = workspace.getAllBlocks(); + assertEquals('Block count', 2, workspace.getAllBlocks(false).length); + var blocks = workspace.getAllBlocks(false); assertEquals('Block 1 position x',21,blocks[0].getRelativeToSurfaceXY().x); assertEquals('Block 1 position y',23,blocks[0].getRelativeToSurfaceXY().y); assertEquals('Block 2 position x',21,blocks[1].getRelativeToSurfaceXY().x); @@ -153,7 +153,7 @@ function test_svgDisposeWithShadow() { ''); Blockly.Xml.appendDomToWorkspace(dom, workspace); - assertEquals('Block count', 2, workspace.getAllBlocks().length); + assertEquals('Block count', 2, workspace.getAllBlocks(false).length); var inputConnection = workspace.getTopBlocks()[0].getInput('NAME').connection; blockNew = helper_createNewBlock(workspace, 'simple_test_block'); From a08d9f22777ead11397d4f84e679e1d029a6ad07 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 7 Oct 2019 11:08:45 -0700 Subject: [PATCH 013/343] Re-added resizeBubble_ call. Fixed resizeBubble_ JSDoc. (#3173) --- core/mutator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mutator.js b/core/mutator.js index 72d8e77df..8b6bbd7d8 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -202,8 +202,7 @@ Blockly.Mutator.prototype.updateEditable = function() { }; /** - * Callback function triggered when the bubble has resized. - * Resize the workspace accordingly. + * Resize the bubble to match the size of the workspace. * @private */ Blockly.Mutator.prototype.resizeBubble_ = function() { @@ -294,6 +293,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) { }; this.block_.workspace.addChangeListener(this.sourceListener_); } + this.resizeBubble_(); // When the mutator's workspace changes, update the source block. this.workspace_.addChangeListener(this.workspaceChanged_.bind(this)); this.updateColour(); From 663809297ddde28e13bf2d08bc5a8c909bbe0245 Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Mon, 7 Oct 2019 11:38:32 -0700 Subject: [PATCH 014/343] Set correct defaults for Fields (#3179) null was being converted to 0 by Number() when it should cause the default value to be set instead. This updates FieldNumber and FieldAngle to handle nulls correctly. Also update jsdoc. Fixes #3177 --- core/field.js | 2 +- core/field_angle.js | 30 ++++++++++++----- core/field_number.js | 57 ++++++++++++++++++++------------ core/field_textinput.js | 2 +- tests/mocha/field_angle_test.js | 33 ++++++++++++++++++ tests/mocha/field_number_test.js | 18 ++++++++++ 6 files changed, 109 insertions(+), 33 deletions(-) diff --git a/core/field.js b/core/field.js index ebc8813f6..ad7477830 100644 --- a/core/field.js +++ b/core/field.js @@ -39,7 +39,7 @@ goog.require('Blockly.utils.style'); /** * Abstract class for an editable field. * @param {*} value The initial value of the field. - * @param {Function=} opt_validator A function that is called to validate + * @param {?Function=} opt_validator A function that is called to validate * changes to the field's value. Takes in a value & returns a validated * value, or null to abort the change. * @param {Object=} opt_config A map of options used to configure the field. See diff --git a/core/field_angle.js b/core/field_angle.js index e383598d8..a8f9fb869 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -172,20 +172,32 @@ Blockly.FieldAngle.prototype.configure_ = function(config) { if (typeof clockwise == 'boolean') { this.clockwise_ = clockwise; } - var offset = Number(config['offset']); - if (!isNaN(offset)) { - this.offset_ = offset; + + var offset = config['offset']; + if (offset != null) { + offset = Number(offset); + if (!isNaN(offset)) { + this.offset_ = offset; + } } - var wrap = Number(config['wrap']); - if (!isNaN(wrap)) { - this.wrap_ = wrap; + var wrap = config['wrap']; + if (wrap != null) { + wrap = Number(wrap); + if (!isNaN(wrap)) { + this.wrap_ = wrap; + } } - var round = Number(config['round']); - if (!isNaN(round)) { - this.round_ = round; + var round = config['round']; + if (round != null) { + round = Number(round); + if (!isNaN(round)) { + this.round_ = round; + } } }; + + /** * Create the block UI for this field. * @package diff --git a/core/field_number.js b/core/field_number.js index bbe340896..396cac7f5 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -32,10 +32,10 @@ goog.require('Blockly.utils.object'); * Class for an editable number field. * @param {string|number=} opt_value The initial value of the field. Should cast * to a number. Defaults to 0. - * @param {(string|number)=} opt_min Minimum value. - * @param {(string|number)=} opt_max Maximum value. - * @param {(string|number)=} opt_precision Precision for value. - * @param {Function=} opt_validator A function that is called to validate + * @param {?(string|number)=} opt_min Minimum value. + * @param {?(string|number)=} opt_max Maximum value. + * @param {?(string|number)=} opt_precision Precision for value. + * @param {?Function=} opt_validator A function that is called to validate * changes to the field's value. Takes in a number & returns a validated * number, or null to abort the change. * @param {Object=} opt_config A map of options used to configure the field. @@ -124,9 +124,9 @@ Blockly.FieldNumber.prototype.configure_ = function(config) { * values. That is, the user's value will rounded to the closest multiple of * precision. The least significant digit place is inferred from the precision. * Integers values can be enforces by choosing an integer precision. - * @param {number|string|undefined} min Minimum value. - * @param {number|string|undefined} max Maximum value. - * @param {number|string|undefined} precision Precision for value. + * @param {?(number|string|undefined)} min Minimum value. + * @param {?(number|string|undefined)} max Maximum value. + * @param {?(number|string|undefined)} precision Precision for value. */ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) { this.setMinInternal_(min); @@ -137,7 +137,7 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) { /** * Sets the minimum value this field can contain. Updates the value to reflect. - * @param {number|string|undefined} min Minimum value. + * @param {?(number|string|undefined)} min Minimum value. */ Blockly.FieldNumber.prototype.setMin = function(min) { this.setMinInternal_(min); @@ -147,13 +147,17 @@ Blockly.FieldNumber.prototype.setMin = function(min) { /** * Sets the minimum value this field can contain. Called internally to avoid * value updates. - * @param {number|string|undefined} min Minimum value. + * @param {?(number|string|undefined)} min Minimum value. * @private */ Blockly.FieldNumber.prototype.setMinInternal_ = function(min) { - min = Number(min); - if (!isNaN(min)) { - this.min_ = min; + if (min == null) { + this.min_ = -Infinity; + } else { + min = Number(min); + if (!isNaN(min)) { + this.min_ = min; + } } }; @@ -168,7 +172,7 @@ Blockly.FieldNumber.prototype.getMin = function() { /** * Sets the maximum value this field can contain. Updates the value to reflect. - * @param {number|string|undefined} max Maximum value. + * @param {?(number|string|undefined)} max Maximum value. */ Blockly.FieldNumber.prototype.setMax = function(max) { this.setMaxInternal_(max); @@ -178,13 +182,17 @@ Blockly.FieldNumber.prototype.setMax = function(max) { /** * Sets the maximum value this field can contain. Called internally to avoid * value updates. - * @param {number|string|undefined} max Maximum value. + * @param {?(number|string|undefined)} max Maximum value. * @private */ Blockly.FieldNumber.prototype.setMaxInternal_ = function(max) { - max = Number(max); - if (!isNaN(max)) { - this.max_ = max; + if (max == null) { + this.max_ = Infinity; + } else { + max = Number(max); + if (!isNaN(max)) { + this.max_ = max; + } } }; @@ -200,7 +208,7 @@ Blockly.FieldNumber.prototype.getMax = function() { /** * Sets the precision of this field's value, i.e. the number to which the * value is rounded. Updates the field to reflect. - * @param {number|string|undefined} precision The number to which the + * @param {?(number|string|undefined)} precision The number to which the * field's value is rounded. */ Blockly.FieldNumber.prototype.setPrecision = function(precision) { @@ -211,14 +219,19 @@ Blockly.FieldNumber.prototype.setPrecision = function(precision) { /** * Sets the precision of this field's value. Called internally to avoid * value updates. - * @param {number|string|undefined} precision The number to which the + * @param {?(number|string|undefined)} precision The number to which the * field's value is rounded. * @private */ Blockly.FieldNumber.prototype.setPrecisionInternal_ = function(precision) { - precision = Number(precision); - if (!isNaN(precision)) { - this.precision_ = precision; + if (precision == null) { + // Number(precision) would also be 0, but set explicitly to be clear. + this.precision_ = 0; + } else { + precision = Number(precision); + if (!isNaN(precision)) { + this.precision_ = precision; + } } var precisionString = this.precision_.toString(); diff --git a/core/field_textinput.js b/core/field_textinput.js index f6312ef3e..46bcb7bc5 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -42,7 +42,7 @@ goog.require('Blockly.utils.userAgent'); * Class for an editable text field. * @param {string=} opt_value The initial value of the field. Should cast to a * string. Defaults to an empty string if null or undefined. - * @param {Function=} opt_validator A function that is called to validate + * @param {?Function=} opt_validator A function that is called to validate * changes to the field's value. Takes in a string & returns a validated * string, or null to abort the change. * @param {Object=} opt_config A map of options used to configure the field. diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js index 500c35599..aeb1f8930 100644 --- a/tests/mocha/field_angle_test.js +++ b/tests/mocha/field_angle_test.js @@ -305,6 +305,17 @@ suite('Angle Fields', function() { var field = new Blockly.FieldAngle(); chai.assert.equal(field.offset_, 90); }); + test('Null', function() { + // Note: Generally constants should be set at compile time, not + // runtime (since they are constants) but for testing purposes we + // can do this. + Blockly.FieldAngle.OFFSET = 90; + var field = Blockly.FieldAngle.fromJson({ + value: 0, + offset: null + }); + chai.assert.equal(field.offset_, 90); + }); }); suite('Wrap', function() { test('JS Configuration', function() { @@ -328,6 +339,17 @@ suite('Angle Fields', function() { var field = new Blockly.FieldAngle(); chai.assert.equal(field.wrap_, 180); }); + test('Null', function() { + // Note: Generally constants should be set at compile time, not + // runtime (since they are constants) but for testing purposes we + // can do this. + Blockly.FieldAngle.WRAP = 180; + var field = Blockly.FieldAngle.fromJson({ + value: 0, + wrap: null + }); + chai.assert.equal(field.wrap_, 180); + }); }); suite('Round', function() { test('JS Configuration', function() { @@ -351,6 +373,17 @@ suite('Angle Fields', function() { var field = new Blockly.FieldAngle(); chai.assert.equal(field.round_, 30); }); + test('Null', function() { + // Note: Generally constants should be set at compile time, not + // runtime (since they are constants) but for testing purposes we + // can do this. + Blockly.FieldAngle.ROUND = 30; + var field = Blockly.FieldAngle.fromJson({ + value: 0, + round: null + }); + chai.assert.equal(field.round_, 30); + }); }); suite('Mode', function() { suite('Compass', function() { diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index ca2a94dc3..1a4d9f700 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -247,6 +247,12 @@ suite('Number Fields', function() { numberField.setValue(123.456); assertValue(numberField, 123); }); + test('null', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: null}); + numberField.setValue(123.456); + assertValue(numberField, 123.456); + }); }); suite('Min', function() { test('-10', function() { @@ -276,6 +282,12 @@ suite('Number Fields', function() { numberField.setValue(20); assertValue(numberField, 20); }); + test('null', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ min: null}); + numberField.setValue(-20); + assertValue(numberField, -20); + }); }); suite('Max', function() { test('-10', function() { @@ -305,6 +317,12 @@ suite('Number Fields', function() { numberField.setValue(20); assertValue(numberField, 10); }); + test('null', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ max: null}); + numberField.setValue(20); + assertValue(numberField, 20); + }); }); }); }); From bc4cb542e88fd92ce72f7bc52def5c2f43425f10 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 7 Oct 2019 13:05:49 -0700 Subject: [PATCH 015/343] Fix capitalization (#3182) --- demos/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/index.html b/demos/index.html index eb06f3d7c..1b22326a3 100644 --- a/demos/index.html +++ b/demos/index.html @@ -239,7 +239,7 @@ - +
Demos keyboard navigation.
From 9ce41598c0143affba4e1c0ef9a39e0ee70c41e1 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 7 Oct 2019 13:25:47 -0700 Subject: [PATCH 016/343] Clean up todos. --- core/renderers/common/constants.js | 1 - core/renderers/common/info.js | 3 --- core/renderers/geras/highlighter.js | 1 - core/renderers/measurables/inputs.js | 3 ++- core/renderers/measurables/rows.js | 1 - core/renderers/zelos/constants.js | 1 - 6 files changed, 2 insertions(+), 8 deletions(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index b21d5646a..b300d7de1 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -288,7 +288,6 @@ Blockly.blockRendering.ConstantProvider.prototype.makeNotch = function() { Blockly.utils.svgPaths.point(dir * outerWidth, -height) ]); } - // TODO: Find a relationship between width and path var pathLeft = makeMainPath(1); var pathRight = makeMainPath(-1); diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 2819623d7..ce8ca9418 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -457,7 +457,6 @@ Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, ne /** * Figure out where the right edge of the block and right edge of statement inputs * should be placed. - * TODO: More cleanup. * @protected */ Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() { @@ -476,9 +475,7 @@ Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() { Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); } - this.statementEdge = widestStatementRowFields; - this.width = blockWidth; for (var i = 0, row; (row = this.rows[i]); i++) { diff --git a/core/renderers/geras/highlighter.js b/core/renderers/geras/highlighter.js index 7a49b6f4d..a740fe1cf 100644 --- a/core/renderers/geras/highlighter.js +++ b/core/renderers/geras/highlighter.js @@ -237,7 +237,6 @@ Blockly.geras.Highlighter.prototype.drawInlineInput = function(input) { var startY = yPos + offset; if (this.RTL_) { - // TODO: Check if this is different when the inline input is populated. var aboveTabHeight = input.connectionOffsetY - offset; var belowTabHeight = input.height - (input.connectionOffsetY + input.connectionHeight) + offset; diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index 5ff02a77b..2d44fd02b 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -61,7 +61,8 @@ Blockly.blockRendering.InputConnection = function(constants, input) { this.connectedBlockHeight = 0; } - // TODO: change references to connectionModel, since that's on Connection. + // TODO (#3186): change references to connectionModel, since that's on + // Connection. this.connection = input.connection; this.connectionOffsetX = 0; this.connectionOffsetY = 0; diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index 3783a0f4c..141ceb08a 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -166,7 +166,6 @@ Blockly.blockRendering.Row.prototype.measure = function() { /** * Get the last input on this row, if it has one. - * TODO: Consider moving this to InputRow, if possible. * @return {Blockly.blockRendering.InputConnection} The last input on the row, * or null. * @package diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 66f06c47f..2c74a1a03 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -241,7 +241,6 @@ Blockly.zelos.ConstantProvider.prototype.makeNotch = function() { ); } - // TODO: Find a relationship between width and path var pathLeft = makeMainPath(1); var pathRight = makeMainPath(-1); From fcfeb316e7e863bfe6d66209485ff61f1e8845b4 Mon Sep 17 00:00:00 2001 From: zochris <20927697+zochris@users.noreply.github.com> Date: Mon, 7 Oct 2019 23:16:24 +0200 Subject: [PATCH 017/343] Make "Infinity" case-insensitive in number field (#3188) --- core/field_number.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/field_number.js b/core/field_number.js index 396cac7f5..be5ac735d 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -274,6 +274,8 @@ Blockly.FieldNumber.prototype.doClassValidation_ = function(opt_newValue) { newValue = newValue.replace(/O/ig, '0'); // Strip out thousands separators. newValue = newValue.replace(/,/g, ''); + // Ignore case of 'Infinity'. + newValue = newValue.replace(/infinity/i, 'Infinity'); // Clean up number. var n = Number(newValue || 0); From a1b18368f2ff1d60822cb452e2e9dd37af59d489 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 7 Oct 2019 14:20:37 -0700 Subject: [PATCH 018/343] Remove dead code from ast node (#3183) --- core/keyboard_nav/ast_node.js | 27 --------------------------- tests/mocha/astnode_test.js | 17 ----------------- 2 files changed, 44 deletions(-) diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index 9f1ed6e9d..f4328a0ae 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -242,33 +242,6 @@ Blockly.ASTNode.prototype.isConnection = function() { return this.isConnection_; }; -/** - * Get either the previous editable field, or get the first editable field for - * the given input. - * @param {!(Blockly.Field|Blockly.Connection)} location The current location of - * the cursor, which must be a field or connection. - * @param {!Blockly.Input} parentInput The parentInput of the field. - * @param {boolean=} opt_last If true find the last editable field otherwise get - * the previous field. - * @return {Blockly.ASTNode} The AST node holding the previous or last field or - * null if no previous field exists. - * @private - */ -Blockly.ASTNode.prototype.findPreviousEditableField_ = function(location, - parentInput, opt_last) { - var fieldRow = parentInput.fieldRow; - var fieldIdx = fieldRow.indexOf(location); - var previousField = null; - var startIdx = (opt_last ? fieldRow.length : fieldIdx) - 1; - for (var i = startIdx, field; field = fieldRow[i]; i--) { - if (field.EDITABLE) { - previousField = field; - return Blockly.ASTNode.createFieldNode(previousField); - } - } - return null; -}; - /** * 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 diff --git a/tests/mocha/astnode_test.js b/tests/mocha/astnode_test.js index ae3f65a43..b172de82f 100644 --- a/tests/mocha/astnode_test.js +++ b/tests/mocha/astnode_test.js @@ -110,23 +110,6 @@ suite('ASTNode', function() { }); suite('HelperFunctions', function() { - test('findPreviousEditableField_', function() { - var input = this.blocks.statementInput1.inputList[0]; - var field = input.fieldRow[1]; - var prevField = input.fieldRow[0]; - var node = Blockly.ASTNode.createFieldNode(prevField); - var editableField = node.findPreviousEditableField_(field, input); - assertEquals(editableField.getLocation(), prevField); - }); - - test('findPreviousEditableFieldLast_', function() { - var input = this.blocks.statementInput1.inputList[0]; - var field = input.fieldRow[0]; - var node = Blockly.ASTNode.createFieldNode(field); - var editableField = node.findPreviousEditableField_(field, input, true); - assertEquals(editableField.getLocation(), input.fieldRow[1]); - }); - test('findNextForInput_', function() { var input = this.blocks.statementInput1.inputList[0]; var input2 = this.blocks.statementInput1.inputList[1]; From 1d113b50691035b869be989e339b5d43f7436a94 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 7 Oct 2019 17:28:18 -0700 Subject: [PATCH 019/343] Add support for setting the direction in RTL. (#3192) --- core/dropdowndiv.js | 34 +++++++++++++++++++++------------- core/field_colour.js | 1 + 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 551aa03b9..5132b99a4 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -62,7 +62,7 @@ Blockly.DropDownDiv.owner_ = null; /** * Whether the dropdown was positioned to a field or the source block. - * @type {boolean} + * @type {?boolean} * @private */ Blockly.DropDownDiv.positionToField_ = null; @@ -119,15 +119,15 @@ Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOR = '#fff'; /** * Timer for animation out, to be cleared if we need to immediately hide * without disrupting new shows. - * @type {number} + * @type {?number} */ Blockly.DropDownDiv.animateOutTimer_ = null; /** * Callback for when the drop-down is hidden. - * @type {Function} + * @type {?Function} */ -Blockly.DropDownDiv.onHide_ = 0; +Blockly.DropDownDiv.onHide_ = null; /** * Create and insert the DOM element for this div. @@ -246,7 +246,7 @@ Blockly.DropDownDiv.showPositionedByBlock = function(field, block, Blockly.DropDownDiv.setBoundsElement( block.workspace.getParentSvg().parentNode); return Blockly.DropDownDiv.show( - field, primaryX, primaryY, secondaryX, secondaryY, opt_onHide); + field, block.RTL, primaryX, primaryY, secondaryX, secondaryY, opt_onHide); }; /** @@ -254,16 +254,16 @@ Blockly.DropDownDiv.showPositionedByBlock = function(field, block, * by a particular field. The primary position will be below the field, * and the secondary position above the field. Drop-down will be * constrained to the block's workspace. - * @param {!Object} owner The object showing the drop-down. + * @param {!Blockly.Field} field The field to position the dropdown against. * @param {Function=} opt_onHide Optional callback for when the drop-down is * hidden. * @param {number=} opt_secondaryYOffset Optional Y offset for above-block * positioning. * @return {boolean} True if the menu rendered below block; false if above. */ -Blockly.DropDownDiv.showPositionedByField = function(owner, +Blockly.DropDownDiv.showPositionedByField = function(field, opt_onHide, opt_secondaryYOffset) { - var position = owner.fieldGroup_.getBoundingClientRect(); + var position = field.fieldGroup_.getBoundingClientRect(); // If we can fit it, render below the block. var primaryX = position.left + position.width / 2; var primaryY = position.bottom; @@ -273,12 +273,14 @@ Blockly.DropDownDiv.showPositionedByField = function(owner, if (opt_secondaryYOffset) { secondaryY += opt_secondaryYOffset; } + var sourceBlock = field.getSourceBlock(); // Set bounds to workspace; show the drop-down. Blockly.DropDownDiv.positionToField_ = true; Blockly.DropDownDiv.setBoundsElement( - owner.getSourceBlock().workspace.getParentSvg().parentNode); + sourceBlock.workspace.getParentSvg().parentNode); return Blockly.DropDownDiv.show( - owner, primaryX, primaryY, secondaryX, secondaryY, opt_onHide); + field, sourceBlock.RTL, + primaryX, primaryY, secondaryX, secondaryY, opt_onHide); }; /** @@ -290,17 +292,19 @@ Blockly.DropDownDiv.showPositionedByField = function(owner, * If we can't maintain the container bounds at the primary point, fall-back to the * secondary point and position above. * @param {Object} owner The object showing the drop-down + * @param {boolean} rtl Right-to-left (true) or left-to-right (false). * @param {number} primaryX Desired origin point x, in absolute px * @param {number} primaryY Desired origin point y, in absolute px * @param {number} secondaryX Secondary/alternative origin point x, in absolute px * @param {number} secondaryY Secondary/alternative origin point y, in absolute px * @param {Function=} opt_onHide Optional callback for when the drop-down is hidden * @return {boolean} True if the menu rendered at the primary origin point. + * @package */ -Blockly.DropDownDiv.show = function(owner, primaryX, primaryY, +Blockly.DropDownDiv.show = function(owner, rtl, primaryX, primaryY, secondaryX, secondaryY, opt_onHide) { Blockly.DropDownDiv.owner_ = owner; - Blockly.DropDownDiv.onHide_ = opt_onHide; + Blockly.DropDownDiv.onHide_ = opt_onHide || null; var metrics = Blockly.DropDownDiv.getPositionMetrics(primaryX, primaryY, secondaryX, secondaryY); // Update arrow CSS. @@ -314,6 +318,9 @@ Blockly.DropDownDiv.show = function(owner, primaryX, primaryY, Blockly.DropDownDiv.arrow_.style.display = 'none'; } + // Set direction. + Blockly.DropDownDiv.DIV_.style.direction = rtl ? 'rtl' : 'ltr'; + // When we change `translate` multiple times in close succession, // Chrome may choose to wait and apply them all at once. // Since we want the translation to initial X, Y to be immediate, @@ -364,7 +371,8 @@ Blockly.DropDownDiv.getBoundsInfo_ = function() { Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, secondaryX, secondaryY) { var boundsInfo = Blockly.DropDownDiv.getBoundsInfo_(); - var divSize = Blockly.utils.style.getSize(Blockly.DropDownDiv.DIV_); + var divSize = Blockly.utils.style.getSize( + /** @type {!Element} */ (Blockly.DropDownDiv.DIV_)); // Can we fit in-bounds below the target? if (primaryY + divSize.height < boundsInfo.bottom) { diff --git a/core/field_colour.js b/core/field_colour.js index 75c4e2c65..88c9891d4 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -507,6 +507,7 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { var table = document.createElement('table'); table.className = 'blocklyColourTable'; table.tabIndex = 0; + table.dir = 'ltr'; Blockly.utils.aria.setRole(table, Blockly.utils.aria.Role.GRID); Blockly.utils.aria.setState(table, From a782645851b7008e2850d3db18666f1d17db6c92 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 8 Oct 2019 11:12:29 -0700 Subject: [PATCH 020/343] Add setLocale to the Blockly typescript definition file. (#3197) --- gulpfile.js | 1 - typings/blockly.d.ts | 14 +++++++------- typings/parts/blockly-interfaces.d.ts | 7 +++++++ typings/parts/goog-closure.d.ts | 6 ------ 4 files changed, 14 insertions(+), 14 deletions(-) delete mode 100644 typings/parts/goog-closure.d.ts diff --git a/gulpfile.js b/gulpfile.js index aee799e8b..f4959161e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -369,7 +369,6 @@ gulp.task('typings', function (cb) { const srcs = [ 'typings/parts/blockly-header.d.ts', 'typings/parts/blockly-interfaces.d.ts', - 'typings/parts/goog-closure.d.ts', `${tmpDir}/core/**`, `${tmpDir}/core/components/**`, `${tmpDir}/core/components/tree/**`, diff --git a/typings/blockly.d.ts b/typings/blockly.d.ts index 2043e6fd2..a8136d568 100644 --- a/typings/blockly.d.ts +++ b/typings/blockly.d.ts @@ -79,13 +79,13 @@ declare module Blockly { viewWidth: number; } -} - -declare namespace goog { - function require(name: string): void; - function provide(name: string): void; - function inherits(child: any, parent: any): void; - function isFunction(f: any): boolean; + /** + * Set the Blockly locale. + * Note: this method is only available in the npm release of Blockly. + * @param {!Object} msg An object of Blockly message strings in the desired + * language. + */ + function setLocale(msg: {[key: string]: string;}): void; } diff --git a/typings/parts/blockly-interfaces.d.ts b/typings/parts/blockly-interfaces.d.ts index 5241054c8..a7a7879bb 100644 --- a/typings/parts/blockly-interfaces.d.ts +++ b/typings/parts/blockly-interfaces.d.ts @@ -56,4 +56,11 @@ declare module Blockly { viewWidth: number; } + /** + * Set the Blockly locale. + * Note: this method is only available in the npm release of Blockly. + * @param {!Object} msg An object of Blockly message strings in the desired + * language. + */ + function setLocale(msg: {[key: string]: string;}): void; } diff --git a/typings/parts/goog-closure.d.ts b/typings/parts/goog-closure.d.ts deleted file mode 100644 index 367be8352..000000000 --- a/typings/parts/goog-closure.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare namespace goog { - function require(name: string): void; - function provide(name: string): void; - function inherits(child: any, parent: any): void; - function isFunction(f: any): boolean; -} From cf04a9529b77b2b8263e7871582c4b869a7bd2a8 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Tue, 8 Oct 2019 11:34:39 -0700 Subject: [PATCH 021/343] Fix compilier warnings for keyboard nav (#3196) * Fix compilier warnings for keyboard nav --- core/block.js | 2 +- core/connection.js | 16 ++++---- core/keyboard_nav/ast_node.js | 69 +++++++++++++++++---------------- core/keyboard_nav/cursor_svg.js | 2 +- core/keyboard_nav/key_map.js | 4 +- core/keyboard_nav/navigation.js | 19 ++++++--- core/workspace.js | 4 +- core/workspace_svg.js | 27 +++++++------ tests/mocha/connection_test.js | 42 ++++++++++---------- 9 files changed, 96 insertions(+), 89 deletions(-) diff --git a/core/block.js b/core/block.js index 71453bf6c..1d4b50163 100644 --- a/core/block.js +++ b/core/block.js @@ -639,7 +639,7 @@ Blockly.Block.prototype.getRootBlock = function() { * 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. - * @private + * @package */ Blockly.Block.prototype.getTopStackBlock = function() { var block = this; diff --git a/core/connection.js b/core/connection.js index 3c0f1ace0..cbe6a217a 100644 --- a/core/connection.js +++ b/core/connection.js @@ -224,7 +224,7 @@ Blockly.Connection.prototype.dispose = function() { /** * Get the source block for this connection. - * @return {Blockly.Block} The source block, or null if there is none. + * @return {!Blockly.Block} The source block. */ Blockly.Connection.prototype.getSourceBlock = function() { return this.sourceBlock_; @@ -253,9 +253,9 @@ Blockly.Connection.prototype.isConnected = function() { * @param {Blockly.Connection} target Connection to check compatibility with. * @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal, * an error code otherwise. - * @private + * @package */ -Blockly.Connection.prototype.canConnectWithReason_ = function(target) { +Blockly.Connection.prototype.canConnectWithReason = function(target) { if (!target) { return Blockly.Connection.REASON_TARGET_NULL; } @@ -285,10 +285,10 @@ Blockly.Connection.prototype.canConnectWithReason_ = function(target) { * and throws an exception if they are not. * @param {Blockly.Connection} target The connection to check compatibility * with. - * @private + * @package */ -Blockly.Connection.prototype.checkConnection_ = function(target) { - switch (this.canConnectWithReason_(target)) { +Blockly.Connection.prototype.checkConnection = function(target) { + switch (this.canConnectWithReason(target)) { case Blockly.Connection.CAN_CONNECT: break; case Blockly.Connection.REASON_SELF_CONNECTION: @@ -358,7 +358,7 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) { return false; } // Type checking. - var canConnect = this.canConnectWithReason_(candidate); + var canConnect = this.canConnectWithReason(candidate); if (canConnect != Blockly.Connection.CAN_CONNECT) { return false; } @@ -431,7 +431,7 @@ Blockly.Connection.prototype.connect = function(otherConnection) { // Already connected together. NOP. return; } - this.checkConnection_(otherConnection); + this.checkConnection(otherConnection); var eventGroup = Blockly.Events.getGroup(); if (!eventGroup) { Blockly.Events.setGroup(true); diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index f4328a0ae..b1ee7c70f 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -30,7 +30,7 @@ goog.provide('Blockly.ASTNode'); * creating a node directly. * @param {string} type The type of the location. * Must be in Bockly.ASTNode.types. - * @param {Blockly.Block|Blockly.Connection|Blockly.Field|Blockly.Workspace} + * @param {!(Blockly.Block|Blockly.Connection|Blockly.Field|Blockly.Workspace)} * location The position in the AST. * @param {!Object=} opt_params Optional dictionary of options. * @constructor @@ -107,10 +107,13 @@ 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 {Blockly.Field} field The location of the AST node. + * @return {Blockly.ASTNode} An AST node pointing to a field. */ Blockly.ASTNode.createFieldNode = function(field) { + if (!field) { + return null; + } return new Blockly.ASTNode(Blockly.ASTNode.types.FIELD, field); }; @@ -144,10 +147,10 @@ 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. + * @return {Blockly.ASTNode} An AST node pointing to a input. */ Blockly.ASTNode.createInputNode = function(input) { - if (!input) { + if (!input || !input.connection) { return null; } return new Blockly.ASTNode(Blockly.ASTNode.types.INPUT, input.connection); @@ -155,22 +158,28 @@ Blockly.ASTNode.createInputNode = function(input) { /** * 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 {Blockly.Block} block The block used to create an AST node. + * @return {Blockly.ASTNode} An AST node pointing to a block. */ Blockly.ASTNode.createBlockNode = function(block) { + if (!block) { + return null; + } return new Blockly.ASTNode(Blockly.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 {Blockly.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 {Blockly.ASTNode} An AST node of type stack that points to the top * block on the stack. */ Blockly.ASTNode.createStackNode = function(topBlock) { + if (!topBlock) { + return null; + } return new Blockly.ASTNode(Blockly.ASTNode.types.STACK, topBlock); }; @@ -179,10 +188,13 @@ Blockly.ASTNode.createStackNode = function(topBlock) { * @param {!Blockly.Workspace} workspace The workspace that we are on. * @param {Blockly.utils.Coordinate} wsCoordinate The position on the workspace * for this node. - * @return {!Blockly.ASTNode} An AST node pointing to a workspace and a position + * @return {Blockly.ASTNode} An AST node pointing to a workspace and a position * on the workspace. */ Blockly.ASTNode.createWorkspaceNode = function(workspace, wsCoordinate) { + if (!wsCoordinate || !workspace) { + return null; + } var params = { wsCoordinate: wsCoordinate }; @@ -278,7 +290,7 @@ Blockly.ASTNode.prototype.findNextForInput_ = function() { * @private */ Blockly.ASTNode.prototype.findNextForField_ = function() { - var location = this.location_; + var location = /** @type {!Blockly.Field} */ (this.location_); var input = location.getParentInput(); var block = location.getSourceBlock(); var curIdx = block.inputList.indexOf(input); @@ -332,7 +344,7 @@ Blockly.ASTNode.prototype.findPrevForInput_ = function() { * @private */ Blockly.ASTNode.prototype.findPrevForField_ = function() { - var location = this.location_; + var location = /** @type {!Blockly.Field} */ (this.location_); var parentInput = location.getParentInput(); var block = location.getSourceBlock(); var curIdx = block.inputList.indexOf(parentInput); @@ -398,9 +410,11 @@ Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) { Blockly.ASTNode.prototype.findTopASTNodeForBlock_ = function(block) { var topConnection = block.previousConnection || block.outputConnection; if (topConnection) { - return Blockly.ASTNode.createConnectionNode(topConnection); + return /** @type {!Blockly.ASTNode} */ (Blockly.ASTNode.createConnectionNode( + topConnection)); } else { - return Blockly.ASTNode.createBlockNode(block); + return /** @type {!Blockly.ASTNode} */ (Blockly.ASTNode.createBlockNode( + block)); } }; @@ -477,20 +491,14 @@ Blockly.ASTNode.prototype.next = function() { case Blockly.ASTNode.types.BLOCK: var nextConnection = this.location_.nextConnection; - if (nextConnection) { - return Blockly.ASTNode.createConnectionNode(nextConnection); - } - break; + return Blockly.ASTNode.createConnectionNode(nextConnection); case Blockly.ASTNode.types.PREVIOUS: return Blockly.ASTNode.createBlockNode(this.location_.getSourceBlock()); case Blockly.ASTNode.types.NEXT: var targetConnection = this.location_.targetConnection; - if (targetConnection) { - return Blockly.ASTNode.createConnectionNode(targetConnection); - } - break; + return Blockly.ASTNode.createConnectionNode(targetConnection); } return null; @@ -517,14 +525,11 @@ Blockly.ASTNode.prototype.in = function() { case Blockly.ASTNode.types.BLOCK: var block = /** @type {!Blockly.Block} */ (this.location_); - return this.findFirstFieldOrInput_(this.location_); + return this.findFirstFieldOrInput_(block); case Blockly.ASTNode.types.INPUT: var targetConnection = this.location_.targetConnection; - if (targetConnection) { - return Blockly.ASTNode.createConnectionNode(targetConnection); - } - break; + return Blockly.ASTNode.createConnectionNode(targetConnection); } return null; @@ -551,13 +556,9 @@ Blockly.ASTNode.prototype.prev = function() { return this.findPrevForInput_(); case Blockly.ASTNode.types.BLOCK: - var prevConnection = this.location_.previousConnection; - var outputConnection = this.location_.outputConnection; - var topConnection = prevConnection || outputConnection; - if (topConnection) { - return Blockly.ASTNode.createConnectionNode(topConnection); - } - break; + var block = this.location_; + var topConnection = block.previousConnection || block.outputConnection; + return Blockly.ASTNode.createConnectionNode(topConnection); case Blockly.ASTNode.types.PREVIOUS: var targetConnection = this.location_.targetConnection; diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index 0151d4881..0c33aa8a7 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -274,7 +274,7 @@ Blockly.CursorSvg.prototype.showWithField_ = function(curNode) { Blockly.CursorSvg.prototype.showWithInput_ = function(curNode) { var connection = /** @type {Blockly.Connection} */ (curNode.getLocation()); - var sourceBlock = /** @type {Blockly.BlockSvg} */ (connection.getSourceBlock()); + var sourceBlock = /** @type {!Blockly.BlockSvg} */ (connection.getSourceBlock()); this.positionInput_(connection); this.setParent_(sourceBlock); diff --git a/core/keyboard_nav/key_map.js b/core/keyboard_nav/key_map.js index 2491cbc5b..e8bc32c54 100644 --- a/core/keyboard_nav/key_map.js +++ b/core/keyboard_nav/key_map.js @@ -30,7 +30,7 @@ goog.require('Blockly.utils.object'); /** * Holds the serialized key to key action mapping. - * @type {Object} + * @type {!Object} */ Blockly.user.keyMap.map_ = {}; @@ -63,7 +63,7 @@ Blockly.user.keyMap.setActionForKey = function(keyCode, action) { /** * Creates a new key map. - * @param {Object} keyMap The object holding the key + * @param {!Object} keyMap The object holding the key * to action mapping. * @package */ diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 6aaecacff..90577c187 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -283,7 +283,7 @@ Blockly.navigation.modifyWarn_ = function() { /** * Disconnect the block from its parent and move to the position of the * workspace node. - * @param {!Blockly.Block} block The block to be moved to the workspace. + * @param {Blockly.Block} block The block to be moved to the workspace. * @param {!Blockly.ASTNode} wsNode The workspace node holding the position the * block will be moved to. * @return {boolean} True if the block can be moved to the workspace, @@ -291,6 +291,9 @@ Blockly.navigation.modifyWarn_ = function() { * @private */ Blockly.navigation.moveBlockToWorkspace_ = function(block, wsNode) { + if (!block) { + return false; + } if (block.isShadow()) { Blockly.navigation.warn_('Cannot move a shadow block to the workspace.'); return false; @@ -323,10 +326,14 @@ Blockly.navigation.modify_ = function() { var markerLoc = markerNode.getLocation(); if (markerNode.isConnection() && cursorNode.isConnection()) { + cursorLoc = /** @type {!Blockly.Connection} */ (cursorLoc); + markerLoc = /** @type {!Blockly.Connection} */ (markerLoc); return Blockly.navigation.connect_(cursorLoc, markerLoc); } else if (markerNode.isConnection() && (cursorType == Blockly.ASTNode.types.BLOCK || cursorType == Blockly.ASTNode.types.STACK)) { + cursorLoc = /** @type {!Blockly.Block} */ (cursorLoc); + markerLoc = /** @type {!Blockly.Connection} */ (markerLoc); return Blockly.navigation.insertBlock(cursorLoc, markerLoc); } else if (markerType == Blockly.ASTNode.types.WORKSPACE) { var block = Blockly.navigation.getSourceBlock_(cursorNode); @@ -372,7 +379,7 @@ Blockly.navigation.moveAndConnect_ = function(movingConnection, destConnection) } var movingBlock = movingConnection.getSourceBlock(); - if (destConnection.canConnectWithReason_(movingConnection) == + if (destConnection.canConnectWithReason(movingConnection) == Blockly.Connection.CAN_CONNECT) { Blockly.navigation.disconnectChild_(movingConnection, destConnection); @@ -458,7 +465,7 @@ Blockly.navigation.connect_ = function(movingConnection, destConnection) { return true; } else { try { - destConnection.checkConnection_(movingConnection); + destConnection.checkConnection(movingConnection); } catch (e) { // If nothing worked report the error from the original connections. @@ -472,7 +479,7 @@ Blockly.navigation.connect_ = function(movingConnection, destConnection) { * Tries to connect the given block to the destination connection, making an * intelligent guess about which connection to use to on the moving block. * @param {!Blockly.Block} block The block to move. - * @param {Blockly.Connection} destConnection The connection to connect to. + * @param {!Blockly.Connection} destConnection The connection to connect to. * @return {boolean} Whether the connection was successful. */ Blockly.navigation.insertBlock = function(block, destConnection) { @@ -525,7 +532,7 @@ Blockly.navigation.disconnectBlocks_ = function() { Blockly.navigation.log_('Cannot disconnect blocks when the cursor is not on a connection'); return; } - var curConnection = curNode.getLocation(); + var curConnection = /** @type {!Blockly.Connection} */ (curNode.getLocation()); if (!curConnection.isConnected()) { Blockly.navigation.log_('Cannot disconnect unconnected connection'); return; @@ -652,7 +659,7 @@ Blockly.navigation.moveCursorOnBlockDelete = function(deletedBlock) { } // If the cursor is on a block whose parent is being deleted, move the // cursor to the workspace. - } else if (deletedBlock.getChildren(false).indexOf(block) > -1) { + } else if (block && deletedBlock.getChildren(false).indexOf(block) > -1) { cursor.setCurNode(Blockly.ASTNode.createWorkspaceNode(block.workspace, block.getRelativeToSurfaceXY())); } diff --git a/core/workspace.js b/core/workspace.js index cd1514bc5..cefd46038 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -168,7 +168,7 @@ Blockly.Workspace.prototype.connectionDBList = null; /** * Sets the cursor for keyboard navigation. - * @param {Blockly.Cursor} cursor The cursor used to navigate around the Blockly + * @param {!Blockly.Cursor} cursor The cursor used to navigate around the Blockly * AST for keyboard navigation. */ Blockly.Workspace.prototype.setCursor = function(cursor) { @@ -177,7 +177,7 @@ Blockly.Workspace.prototype.setCursor = function(cursor) { /** * Sets the marker for keyboard navigation. - * @param {Blockly.MarkerCursor} marker The marker used to mark a location for + * @param {!Blockly.MarkerCursor} marker The marker used to mark a location for * keyboard navigation. */ Blockly.Workspace.prototype.setMarker = function(marker) { diff --git a/core/workspace_svg.js b/core/workspace_svg.js index f318c4364..6b01121cd 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -415,35 +415,31 @@ Blockly.WorkspaceSvg.prototype.getRenderer = function() { /** * Sets the cursor for use with keyboard navigation. * - * @param {Blockly.Cursor} cursor The cursor used to move around this workspace. + * @param {!Blockly.Cursor} cursor The cursor used to move around this workspace. * @override */ Blockly.WorkspaceSvg.prototype.setCursor = function(cursor) { - if (this.cursor_ && this.cursor_.getDrawer()) { + if (this.cursor_.getDrawer()) { this.cursor_.getDrawer().dispose(); } this.cursor_ = cursor; - if (this.cursor_) { - this.cursor_.setDrawer(this.getRenderer().makeCursorDrawer(this, false)); - this.setCursorSvg(this.cursor_.getDrawer().createDom()); - } + this.cursor_.setDrawer(this.getRenderer().makeCursorDrawer(this, false)); + this.setCursorSvg(this.cursor_.getDrawer().createDom()); }; /** * Sets the marker for use with keyboard navigation. - * @param {Blockly.MarkerCursor} marker The immovable cursor used to mark a + * @param {!Blockly.MarkerCursor} marker The immovable cursor used to mark a * location on the workspace. * @override */ Blockly.WorkspaceSvg.prototype.setMarker = function(marker) { - if (this.marker_ && this.marker_.getDrawer()) { + if (this.marker_.getDrawer()) { this.marker_.getDrawer().dispose(); } this.marker_ = marker; - if (this.marker_) { - this.marker_.setDrawer(this.getRenderer().makeCursorDrawer(this, true)); - this.setMarkerSvg(this.marker_.getDrawer().createDom()); - } + this.marker_.setDrawer(this.getRenderer().makeCursorDrawer(this, true)); + this.setMarkerSvg(this.marker_.getDrawer().createDom()); }; /** @@ -1187,8 +1183,11 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { // Handle paste for keyboard navigation var markedNode = this.getMarker().getCurNode(); - if (Blockly.keyboardAccessibilityMode && markedNode) { - Blockly.navigation.insertBlock(block, markedNode.getLocation()); + if (Blockly.keyboardAccessibilityMode && markedNode && + markedNode.isConnection()) { + var markedLocation = + /** @type {!Blockly.Connection} */ (markedNode.getLocation()); + Blockly.navigation.insertBlock(block, markedLocation); return; } diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js index 0e8776425..6a7faaf97 100644 --- a/tests/mocha/connection_test.js +++ b/tests/mocha/connection_test.js @@ -19,7 +19,7 @@ suite('Connections', function() { suite('Can Connect With Reason', function() { test('Target Null', function() { var connection = new Blockly.Connection({}, Blockly.INPUT_VALUE); - chai.assert.equal(connection.canConnectWithReason_(null), + chai.assert.equal(connection.canConnectWithReason(null), Blockly.Connection.REASON_TARGET_NULL); }); test('Target Self', function() { @@ -27,7 +27,7 @@ suite('Connections', function() { var connection1 = new Blockly.Connection(block, Blockly.INPUT_VALUE); var connection2 = new Blockly.Connection(block, Blockly.OUTPUT_VALUE); - chai.assert.equal(connection1.canConnectWithReason_(connection2), + chai.assert.equal(connection1.canConnectWithReason(connection2), Blockly.Connection.REASON_SELF_CONNECTION); }); test('Different Workspaces', function() { @@ -36,7 +36,7 @@ suite('Connections', function() { var connection2 = new Blockly.Connection( {workspace: 2}, Blockly.OUTPUT_VALUE); - chai.assert.equal(connection1.canConnectWithReason_(connection2), + chai.assert.equal(connection1.canConnectWithReason(connection2), Blockly.Connection.REASON_DIFFERENT_WORKSPACES); }); suite('Types', function() { @@ -57,51 +57,51 @@ suite('Connections', function() { inBlock, Blockly.INPUT_VALUE); }); test('Previous, Next', function() { - chai.assert.equal(this.previous.canConnectWithReason_(this.next), + chai.assert.equal(this.previous.canConnectWithReason(this.next), Blockly.Connection.CAN_CONNECT); }); test('Previous, Output', function() { - chai.assert.equal(this.previous.canConnectWithReason_(this.output), + chai.assert.equal(this.previous.canConnectWithReason(this.output), Blockly.Connection.REASON_WRONG_TYPE); }); test('Previous, Input', function() { - chai.assert.equal(this.previous.canConnectWithReason_(this.input), + chai.assert.equal(this.previous.canConnectWithReason(this.input), Blockly.Connection.REASON_WRONG_TYPE); }); test('Next, Previous', function() { - chai.assert.equal(this.next.canConnectWithReason_(this.previous), + chai.assert.equal(this.next.canConnectWithReason(this.previous), Blockly.Connection.CAN_CONNECT); }); test('Next, Output', function() { - chai.assert.equal(this.next.canConnectWithReason_(this.output), + chai.assert.equal(this.next.canConnectWithReason(this.output), Blockly.Connection.REASON_WRONG_TYPE); }); test('Next, Input', function() { - chai.assert.equal(this.next.canConnectWithReason_(this.input), + chai.assert.equal(this.next.canConnectWithReason(this.input), Blockly.Connection.REASON_WRONG_TYPE); }); test('Output, Previous', function() { - chai.assert.equal(this.output.canConnectWithReason_(this.previous), + chai.assert.equal(this.output.canConnectWithReason(this.previous), Blockly.Connection.REASON_WRONG_TYPE); }); test('Output, Next', function() { - chai.assert.equal(this.output.canConnectWithReason_(this.next), + chai.assert.equal(this.output.canConnectWithReason(this.next), Blockly.Connection.REASON_WRONG_TYPE); }); test('Output, Input', function() { - chai.assert.equal(this.output.canConnectWithReason_(this.input), + chai.assert.equal(this.output.canConnectWithReason(this.input), Blockly.Connection.CAN_CONNECT); }); test('Input, Previous', function() { - chai.assert.equal(this.input.canConnectWithReason_(this.previous), + chai.assert.equal(this.input.canConnectWithReason(this.previous), Blockly.Connection.REASON_WRONG_TYPE); }); test('Input, Next', function() { - chai.assert.equal(this.input.canConnectWithReason_(this.next), + chai.assert.equal(this.input.canConnectWithReason(this.next), Blockly.Connection.REASON_WRONG_TYPE); }); test('Input, Output', function() { - chai.assert.equal(this.input.canConnectWithReason_(this.output), + chai.assert.equal(this.input.canConnectWithReason(this.output), Blockly.Connection.CAN_CONNECT); }); }); @@ -112,7 +112,7 @@ suite('Connections', function() { var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT); var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT); - chai.assert.equal(prev.canConnectWithReason_(next), + chai.assert.equal(prev.canConnectWithReason(next), Blockly.Connection.CAN_CONNECT); }); test('Next Shadow', function() { @@ -121,7 +121,7 @@ suite('Connections', function() { var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT); var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT); - chai.assert.equal(prev.canConnectWithReason_(next), + chai.assert.equal(prev.canConnectWithReason(next), Blockly.Connection.REASON_SHADOW_PARENT); }); test('Prev and Next Shadow', function() { @@ -130,7 +130,7 @@ suite('Connections', function() { var prev = new Blockly.Connection(prevBlock, Blockly.PREVIOUS_STATEMENT); var next = new Blockly.Connection(nextBlock, Blockly.NEXT_STATEMENT); - chai.assert.equal(prev.canConnectWithReason_(next), + chai.assert.equal(prev.canConnectWithReason(next), Blockly.Connection.CAN_CONNECT); }); test('Output Shadow', function() { @@ -139,7 +139,7 @@ suite('Connections', function() { var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE); var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE); - chai.assert.equal(outCon.canConnectWithReason_(inCon), + chai.assert.equal(outCon.canConnectWithReason(inCon), Blockly.Connection.CAN_CONNECT); }); test('Input Shadow', function() { @@ -148,7 +148,7 @@ suite('Connections', function() { var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE); var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE); - chai.assert.equal(outCon.canConnectWithReason_(inCon), + chai.assert.equal(outCon.canConnectWithReason(inCon), Blockly.Connection.REASON_SHADOW_PARENT); }); test('Output and Input Shadow', function() { @@ -157,7 +157,7 @@ suite('Connections', function() { var outCon = new Blockly.Connection(outBlock, Blockly.OUTPUT_VALUE); var inCon = new Blockly.Connection(inBlock, Blockly.INPUT_VALUE); - chai.assert.equal(outCon.canConnectWithReason_(inCon), + chai.assert.equal(outCon.canConnectWithReason(inCon), Blockly.Connection.CAN_CONNECT); }); }); From f4f9a679035eebdc2bc39345b93e7b8715b7121e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 8 Oct 2019 16:48:31 -0700 Subject: [PATCH 022/343] Fixed field editor disposal (#3109) * Fixed field editor disposal. --- core/field_angle.js | 4 +++- core/field_colour.js | 2 +- core/field_dropdown.js | 2 +- core/field_textinput.js | 20 +++++++------------- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index a8f9fb869..7e88f154c 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -304,13 +304,15 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { }; /** - * Dispose of events belonging to the angle editor. + * Disposes of events and dom-references belonging to the angle editor. * @private */ Blockly.FieldAngle.prototype.dropdownDispose_ = function() { Blockly.unbindEvent_(this.clickWrapper_); Blockly.unbindEvent_(this.clickSurfaceWrapper_); Blockly.unbindEvent_(this.moveSurfaceWrapper_); + this.gauge_ = null; + this.line_ = null; }; /** diff --git a/core/field_colour.js b/core/field_colour.js index 88c9891d4..abc481243 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -556,7 +556,7 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { }; /** - * Dispose of events belonging to the colour editor. + * Disposes of events and dom-references belonging to the colour editor. * @private */ Blockly.FieldColour.prototype.dropdownDispose_ = function() { diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 44be889fa..238eb7f07 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -269,7 +269,7 @@ Blockly.FieldDropdown.prototype.dropdownCreate_ = function() { }; /** - * Dispose of events belonging to the dropdown editor. + * Disposes of events and dom-references belonging to the dropdown editor. * @private */ Blockly.FieldDropdown.prototype.dropdownDispose_ = function() { diff --git a/core/field_textinput.js b/core/field_textinput.js index 46bcb7bc5..f9079fc31 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -292,34 +292,28 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { }; /** - * Close the editor, save the results, and dispose any events bound to the - * text input's editor. + * Closes the editor, saves the results, and disposes of any events or + * dom-references belonging to the editor. * @private */ Blockly.FieldTextInput.prototype.widgetDispose_ = function() { - // Finalize value. + // Non-disposal related things that we do when the editor closes. this.isBeingEdited_ = false; this.isTextValid_ = true; - - // Always re-render when the we close the editor as value - // set on the field's node may be inconsistent with the field's - // internal value. + // Make sure the field's node matches the field's internal value. this.forceRerender(); - - // Call onFinishEditing - // TODO: Get rid of this or make it less of a hack. + // TODO(#2496): Make this less of a hack. if (this.onFinishEditing_) { this.onFinishEditing_(this.value_); } - // Remove htmlInput events. + // Actual disposal. this.unbindInputEvents_(); - - // Delete style properties. var style = Blockly.WidgetDiv.DIV.style; style.width = 'auto'; style.height = 'auto'; style.fontSize = ''; + this.htmlInput_ = null; }; /** From b9dd13cde015002e875974b3f08be73c98c6264a Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 8 Oct 2019 17:29:53 -0700 Subject: [PATCH 023/343] Fix #3169 (#3199) --- core/rendered_connection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rendered_connection.js b/core/rendered_connection.js index a29ea967d..55ac387ad 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -80,10 +80,10 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); * @package */ Blockly.RenderedConnection.prototype.dispose = function() { + Blockly.RenderedConnection.superClass_.dispose.call(this); if (this.tracked_) { this.db_.removeConnection(this, this.y_); } - Blockly.RenderedConnection.superClass_.dispose.call(this); }; /** From 65cf0c5e98ef6b9b80269e785b36fa072be1c264 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 8 Oct 2019 18:04:05 -0700 Subject: [PATCH 024/343] Initialize drag delta to (0,0) and update annotation. Remove 12 warnings. --- core/gesture.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/gesture.js b/core/gesture.js index 677feabae..e8c81b034 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -63,10 +63,10 @@ Blockly.Gesture = function(e, creatorWorkspace) { /** * How far the mouse has moved during this drag, in pixel units. * (0, 0) is at this.mouseDownXY_. - * @type {Blockly.utils.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ - this.currentDragDeltaXY_ = null; + this.currentDragDeltaXY_ = new Blockly.utils.Coordinate(0, 0); /** * The bubble that the gesture started on, or null if it did not start on a From 4b35320c8689a95867d4760bbbe5493fea4b3790 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 9 Oct 2019 10:10:12 -0700 Subject: [PATCH 025/343] Fix #2811 (#3205) --- core/field.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/field.js b/core/field.js index ad7477830..a9d7b919c 100644 --- a/core/field.js +++ b/core/field.js @@ -557,8 +557,10 @@ Blockly.Field.prototype.updateColour = function() { * @protected */ Blockly.Field.prototype.render_ = function() { - this.textContent_.nodeValue = this.getDisplayText_(); - this.updateSize_(); + if (this.textContent_) { + this.textContent_.nodeValue = this.getDisplayText_(); + this.updateSize_(); + } }; /** From 3368a9f7134c067bfc823ca7ced5f89d07fecc62 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 9 Oct 2019 11:16:16 -0700 Subject: [PATCH 026/343] Revert calling onHide before the animation is complete to avoid double click issues. (#3202) --- core/dropdowndiv.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 5132b99a4..cb403bcbd 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -263,7 +263,7 @@ Blockly.DropDownDiv.showPositionedByBlock = function(field, block, */ Blockly.DropDownDiv.showPositionedByField = function(field, opt_onHide, opt_secondaryYOffset) { - var position = field.fieldGroup_.getBoundingClientRect(); + var position = field.getSvgRoot().getBoundingClientRect(); // If we can fit it, render below the block. var primaryX = position.left + position.width / 2; var primaryY = position.bottom; @@ -574,11 +574,11 @@ Blockly.DropDownDiv.hide = function() { Blockly.DropDownDiv.animateOutTimer_ = setTimeout(function() { Blockly.DropDownDiv.hideWithoutAnimation(); - if (Blockly.DropDownDiv.onHide_) { - Blockly.DropDownDiv.onHide_(); - Blockly.DropDownDiv.onHide_ = null; - } }, Blockly.DropDownDiv.ANIMATION_TIME * 1000); + if (Blockly.DropDownDiv.onHide_) { + Blockly.DropDownDiv.onHide_(); + Blockly.DropDownDiv.onHide_ = null; + } }; /** From e18dcd1bea388527bdbf8e9c11edfda6d9f4313e Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 9 Oct 2019 16:08:23 -0700 Subject: [PATCH 027/343] bringToFront optimization for large workspaces (#3214) * bringToFront optimization for large workspaces --- core/block_svg.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/block_svg.js b/core/block_svg.js index eaf20126d..7c1ef782a 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1375,7 +1375,12 @@ Blockly.BlockSvg.prototype.bringToFront = function() { var block = this; do { var root = block.getSvgRoot(); - root.parentNode.appendChild(root); + var parent = root.parentNode; + var childNodes = parent.childNodes; + // Avoid moving the block if it's already at the bottom. + if (childNodes[childNodes.length - 1] !== root) { + parent.appendChild(root); + } block = block.getParent(); } while (block); }; From 43f9ab68899fa96565a3d3d2ac131c3dce283e29 Mon Sep 17 00:00:00 2001 From: Josh Lory Date: Fri, 11 Oct 2019 15:30:26 -0700 Subject: [PATCH 028/343] Look up notch height from the current renderer (#3217) --- core/block_svg.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/block_svg.js b/core/block_svg.js index 7c1ef782a..1ebaa5388 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1807,7 +1807,9 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { var nextBlock = this.getNextBlock(); if (nextBlock) { var nextHeightWidth = nextBlock.getHeightWidth(); - height += nextHeightWidth.height - 4; // Height of tab. + var workspace = /** @type {!Blockly.WorkspaceSvg} */ (this.workspace); + var tabHeight = workspace.getRenderer().getConstants().NOTCH_HEIGHT; + height += nextHeightWidth.height - tabHeight; width = Math.max(width, nextHeightWidth.width); } return {height: height, width: width}; From bf7abee679a5022fd0f9ea43d6e8a0009a48d0f3 Mon Sep 17 00:00:00 2001 From: zochris Date: Sun, 13 Oct 2019 13:00:54 +0200 Subject: [PATCH 029/343] Rephrase "variable already exists" message The message now includes the name with casing of the already existing variable. --- core/variables.js | 8 +++++--- msg/messages.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/variables.js b/core/variables.js index 74ca01bf4..f5d7216c0 100644 --- a/core/variables.js +++ b/core/variables.js @@ -286,11 +286,12 @@ Blockly.Variables.createVariableButtonHandler = function( var lowerCase = text.toLowerCase(); if (existing.type == type) { var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS'].replace( - '%1', lowerCase); + '%1', lowerCase).replace('%2', existing.name); } else { var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']; - msg = msg.replace('%1', lowerCase).replace('%2', existing.type); + msg = msg.replace('%1', lowerCase).replace('%2', existing.type) + .replace('%3', existing.name); } Blockly.alert(msg, function() { @@ -352,7 +353,8 @@ Blockly.Variables.renameVariable = function(workspace, variable, if (existing) { var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'] .replace('%1', newName.toLowerCase()) - .replace('%2', existing.type); + .replace('%2', existing.type) + .replace('%3', existing.name); Blockly.alert(msg, function() { promptAndCheckWithAlert(newName); // Recurse diff --git a/msg/messages.js b/msg/messages.js index 2cb5c3ed8..a56e5ae3c 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -172,10 +172,10 @@ Blockly.Msg.NEW_VARIABLE_TYPE_TITLE = 'New variable type:'; Blockly.Msg.NEW_VARIABLE_TITLE = 'New variable name:'; /** @type {string} */ /// alert - Tells the user that the name they entered is already in use. -Blockly.Msg.VARIABLE_ALREADY_EXISTS = 'A variable named "%1" already exists.'; +Blockly.Msg.VARIABLE_ALREADY_EXISTS = 'A variable named "%1" already exists (as "%2").'; /** @type {string} */ /// alert - Tells the user that the name they entered is already in use for another type. -Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE = 'A variable named "%1" already exists for another type: "%2".'; +Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE = 'A variable named "%1" already exists for another type: "%2" (as "%3").'; // Variable deletion. /** @type {string} */ From f26829eb6dde952a531e7686c14e698a7f81b449 Mon Sep 17 00:00:00 2001 From: zochris Date: Sun, 13 Oct 2019 20:32:19 +0200 Subject: [PATCH 030/343] Change variable exists message to show casing --- core/variables.js | 11 ++++------- msg/messages.js | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/core/variables.js b/core/variables.js index f5d7216c0..ab85adb6e 100644 --- a/core/variables.js +++ b/core/variables.js @@ -283,15 +283,13 @@ Blockly.Variables.createVariableButtonHandler = function( var existing = Blockly.Variables.nameUsedWithAnyType_(text, workspace); if (existing) { - var lowerCase = text.toLowerCase(); if (existing.type == type) { var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS'].replace( - '%1', lowerCase).replace('%2', existing.name); + '%1', existing.name); } else { var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']; - msg = msg.replace('%1', lowerCase).replace('%2', existing.type) - .replace('%3', existing.name); + msg = msg.replace('%1', existing.name).replace('%2', existing.type); } Blockly.alert(msg, function() { @@ -352,9 +350,8 @@ Blockly.Variables.renameVariable = function(workspace, variable, variable.type, workspace); if (existing) { var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'] - .replace('%1', newName.toLowerCase()) - .replace('%2', existing.type) - .replace('%3', existing.name); + .replace('%1', existing.name) + .replace('%2', existing.type); Blockly.alert(msg, function() { promptAndCheckWithAlert(newName); // Recurse diff --git a/msg/messages.js b/msg/messages.js index a56e5ae3c..2cb5c3ed8 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -172,10 +172,10 @@ Blockly.Msg.NEW_VARIABLE_TYPE_TITLE = 'New variable type:'; Blockly.Msg.NEW_VARIABLE_TITLE = 'New variable name:'; /** @type {string} */ /// alert - Tells the user that the name they entered is already in use. -Blockly.Msg.VARIABLE_ALREADY_EXISTS = 'A variable named "%1" already exists (as "%2").'; +Blockly.Msg.VARIABLE_ALREADY_EXISTS = 'A variable named "%1" already exists.'; /** @type {string} */ /// alert - Tells the user that the name they entered is already in use for another type. -Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE = 'A variable named "%1" already exists for another type: "%2" (as "%3").'; +Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE = 'A variable named "%1" already exists for another type: "%2".'; // Variable deletion. /** @type {string} */ From c98bf0201200ac445f36935702287ef93ea45dd0 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 14 Oct 2019 17:17:03 +0200 Subject: [PATCH 031/343] Localisation updates from https://translatewiki.net. --- msg/json/fr.json | 129 ++++++++++++++++++++++++----------------------- msg/json/pt.json | 1 + msg/json/tr.json | 17 ++++--- 3 files changed, 75 insertions(+), 72 deletions(-) diff --git a/msg/json/fr.json b/msg/json/fr.json index fb5be7823..bad9356f1 100644 --- a/msg/json/fr.json +++ b/msg/json/fr.json @@ -15,7 +15,8 @@ "RoboErikG", "Zarisi", "Alacabe", - "Pititnatole" + "Pititnatole", + "Verdy p" ] }, "VARIABLES_DEFAULT_NAME": "élément", @@ -40,20 +41,20 @@ "HELP": "Aide", "UNDO": "Annuler", "REDO": "Refaire", - "CHANGE_VALUE_TITLE": "Modifier la valeur :", - "RENAME_VARIABLE": "Renommer la variable…", - "RENAME_VARIABLE_TITLE": "Renommer toutes les variables « %1 » en :", + "CHANGE_VALUE_TITLE": "Modifier la valeur :", + "RENAME_VARIABLE": "Renommer la variable...", + "RENAME_VARIABLE_TITLE": "Renommer toutes les variables « %1 » en :", "NEW_VARIABLE": "Créer une variable...", - "NEW_STRING_VARIABLE": "Créer une variable chaîne…", - "NEW_NUMBER_VARIABLE": "Créer une variable nombre…", - "NEW_COLOUR_VARIABLE": "Créer une variable couleur…", - "NEW_VARIABLE_TYPE_TITLE": "Nouveau type de variable :", - "NEW_VARIABLE_TITLE": "Nom de la nouvelle variable :", - "VARIABLE_ALREADY_EXISTS": "Une variable appelée '%1' existe déjà.", - "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Une variable nommée '%1' existe déjà pour un autre type : '%2'.", - "DELETE_VARIABLE_CONFIRMATION": "Supprimer %1 utilisations de la variable '%2' ?", - "CANNOT_DELETE_VARIABLE_PROCEDURE": "Impossible de supprimer la variable '%1' parce qu’elle fait partie de la définition de la fonction '%2'", - "DELETE_VARIABLE": "Supprimer la variable '%1'", + "NEW_STRING_VARIABLE": "Créer une variable de chaîne...", + "NEW_NUMBER_VARIABLE": "Créer une variable numérique...", + "NEW_COLOUR_VARIABLE": "Créer une variable de couleur...", + "NEW_VARIABLE_TYPE_TITLE": "Nouveau type de variable :", + "NEW_VARIABLE_TITLE": "Nom de la nouvelle variable :", + "VARIABLE_ALREADY_EXISTS": "Une variable nommée « %1 » existe déjà.", + "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Une variable nommée « %1 » existe déjà pour un autre type : « %2 ».", + "DELETE_VARIABLE_CONFIRMATION": "Supprimer %1 utilisations de la variable « %2 » ?", + "CANNOT_DELETE_VARIABLE_PROCEDURE": "Impossible de supprimer la variable « %1 » parce qu’elle fait partie de la définition de la fonction « %2 »", + "DELETE_VARIABLE": "Supprimer la variable « %1 »", "COLOUR_PICKER_HELPURL": "https://fr.wikipedia.org/wiki/Couleur", "COLOUR_PICKER_TOOLTIP": "Choisir une couleur dans la palette.", "COLOUR_RANDOM_TITLE": "couleur aléatoire", @@ -78,31 +79,31 @@ "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "répéter jusqu’à", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Tant qu’une valeur est vraie, alors exécuter des instructions.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Tant qu’une valeur est fausse, alors exécuter des instructions.", - "CONTROLS_FOR_TOOLTIP": "Faire prendre à la variable « %1 » les valeurs depuis le nombre de début jusqu’au nombre de fin, en s’incrémentant du pas spécifié, et exécuter les instructions spécifiées.", + "CONTROLS_FOR_TOOLTIP": "Faire prendre successivement à la variable « %1 » les valeurs entre deux nombres de début et de fin par incrément du pas spécifié et exécuter les instructions spécifiées.", "CONTROLS_FOR_TITLE": "compter avec %1 de %2 à %3 par %4", "CONTROLS_FOREACH_TITLE": "pour chaque élément %1 dans la liste %2", - "CONTROLS_FOREACH_TOOLTIP": "Pour chaque élément d’une liste, assigner la valeur de l’élément à la variable '%1', puis exécuter des instructions.", + "CONTROLS_FOREACH_TOOLTIP": "Pour chaque élément d’une liste, assigner la valeur de l’élément à la variable « %1 », puis exécuter des instructions.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "quitter la boucle", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "passer à l’itération de boucle suivante", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Sortir de la boucle englobante.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Sauter le reste de cette boucle, et poursuivre avec l’itération suivante.", - "CONTROLS_FLOW_STATEMENTS_WARNING": "Attention : Ce bloc ne devrait être utilisé que dans une boucle.", - "CONTROLS_IF_TOOLTIP_1": "Si une valeur est vraie, alors exécuter certains ordres.", - "CONTROLS_IF_TOOLTIP_2": "Si une valeur est vraie, alors exécuter le premier bloc d’ordres. Sinon, exécuter le second bloc d’ordres.", - "CONTROLS_IF_TOOLTIP_3": "Si la première valeur est vraie, alors exécuter le premier bloc d’ordres. Sinon, si la seconde valeur est vraie, exécuter le second bloc d’ordres.", - "CONTROLS_IF_TOOLTIP_4": "Si la première valeur est vraie, alors exécuter le premier bloc d’ordres. Sinon, si la seconde valeur est vraie, exécuter le second bloc d’ordres. Si aucune des valeurs n’est vraie, exécuter le dernier bloc d’ordres.", + "CONTROLS_FLOW_STATEMENTS_WARNING": "Attention : ce bloc ne devrait être utilisé que dans une boucle.", + "CONTROLS_IF_TOOLTIP_1": "Si une valeur est vraie, alors exécuter certaines instructions.", + "CONTROLS_IF_TOOLTIP_2": "Si une valeur est vraie, alors exécuter le premier bloc d’instructions. Sinon, exécuter le second bloc d’instructions.", + "CONTROLS_IF_TOOLTIP_3": "Si la première valeur est vraie, alors exécuter le premier bloc d’instructions. Sinon, si la seconde valeur est vraie, exécuter le second bloc d’instructions.", + "CONTROLS_IF_TOOLTIP_4": "Si la première valeur est vraie, alors exécuter le premier bloc d’instructions. Sinon, si la seconde valeur est vraie, exécuter le second bloc d’instruction. Si aucune des valeurs n’est vraie, exécuter le dernier bloc d’instruction.", "CONTROLS_IF_MSG_IF": "si", "CONTROLS_IF_MSG_ELSEIF": "sinon si", "CONTROLS_IF_MSG_ELSE": "sinon", - "CONTROLS_IF_IF_TOOLTIP": "Ajouter, supprimer ou réordonner les sections pour reconfigurer ce bloc si.", - "CONTROLS_IF_ELSEIF_TOOLTIP": "Ajouter une condition au bloc si.", - "CONTROLS_IF_ELSE_TOOLTIP": "Ajouter une condition finale fourre-tout au bloc si.", + "CONTROLS_IF_IF_TOOLTIP": "Ajouter, supprimer ou réordonner les sections pour reconfigurer ce bloc conditionnel.", + "CONTROLS_IF_ELSEIF_TOOLTIP": "Ajouter une condition au bloc conditionnel.", + "CONTROLS_IF_ELSE_TOOLTIP": "Ajouter une condition finale déclenchée dans tous les autres cas au bloc conditionnel.", "IOS_OK": "OK", "IOS_CANCEL": "Annuler", "IOS_ERROR": "Erreur", "IOS_PROCEDURES_INPUTS": "ENTRÉES", "IOS_PROCEDURES_ADD_INPUT": "+ Ajouter une entrée", - "IOS_PROCEDURES_ALLOW_STATEMENTS": "Ordres autorisés", + "IOS_PROCEDURES_ALLOW_STATEMENTS": "Instructions autorisées", "IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR": "Cette fonction a des entrées dupliquées.", "IOS_VARIABLES_ADD_VARIABLE": "+ Ajouter une variable", "IOS_VARIABLES_ADD_BUTTON": "Ajouter", @@ -121,7 +122,7 @@ "LOGIC_OPERATION_AND": "et", "LOGIC_OPERATION_TOOLTIP_OR": "Renvoyer vrai si au moins une des entrées est vraie.", "LOGIC_OPERATION_OR": "ou", - "LOGIC_NEGATE_TITLE": "pas %1", + "LOGIC_NEGATE_TITLE": "non %1", "LOGIC_NEGATE_TOOLTIP": "Renvoie vrai si l’entrée est fausse. Renvoie faux si l’entrée est vraie.", "LOGIC_BOOLEAN_TRUE": "vrai", "LOGIC_BOOLEAN_FALSE": "faux", @@ -133,7 +134,7 @@ "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "si vrai", "LOGIC_TERNARY_IF_FALSE": "si faux", - "LOGIC_TERNARY_TOOLTIP": "Vérifier la condition dans 'test'. Si elle est vraie, renvoie la valeur 'si vrai' ; sinon renvoie la valeur 'si faux'.", + "LOGIC_TERNARY_TOOLTIP": "Vérifier la condition indiquée dans « test ». Si elle est vraie, renvoie la valeur « si vrai » ; sinon renvoie la valeur « si faux ».", "MATH_NUMBER_HELPURL": "https://fr.wikipedia.org/wiki/Nombre", "MATH_NUMBER_TOOLTIP": "Un nombre.", "MATH_ARITHMETIC_HELPURL": "https://fr.wikipedia.org/wiki/Arithm%C3%A9tique", @@ -150,7 +151,7 @@ "MATH_SINGLE_TOOLTIP_NEG": "Renvoie l’opposé d’un nombre", "MATH_SINGLE_TOOLTIP_LN": "Renvoie le logarithme naturel d’un nombre.", "MATH_SINGLE_TOOLTIP_LOG10": "Renvoie le logarithme décimal d’un nombre.", - "MATH_SINGLE_TOOLTIP_EXP": "Renvoie e à la puissance d’un nombre.", + "MATH_SINGLE_TOOLTIP_EXP": "Renvoie e à la puissance d’un nombre.", "MATH_SINGLE_TOOLTIP_POW10": "Renvoie 10 à la puissance d’un nombre.", "MATH_TRIG_HELPURL": "https://fr.wikipedia.org/wiki/Fonction_trigonom%C3%A9trique", "MATH_TRIG_TOOLTIP_SIN": "Renvoie le sinus d’un angle en degrés (pas en radians).", @@ -160,7 +161,7 @@ "MATH_TRIG_TOOLTIP_ACOS": "Renvoie l’arccosinus d’un nombre.", "MATH_TRIG_TOOLTIP_ATAN": "Renvoie l’arctangente d’un nombre.", "MATH_CONSTANT_HELPURL": "https://fr.wikipedia.org/wiki/Table_de_constantes_math%C3%A9matiques", - "MATH_CONSTANT_TOOLTIP": "Renvoie une des constantes courantes : π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), ou ∞ (infini).", + "MATH_CONSTANT_TOOLTIP": "Renvoie une des constantes courantes : π = 3,14159... (pi) ; e = 2,71828... ; φ = (1+√5)/2 = 1,61803… (nombre d’or) ; √2 = 1,41421... ; √(½) = 0,70710… ; ou ∞ (infini).", "MATH_IS_EVEN": "est pair", "MATH_IS_ODD": "est impair", "MATH_IS_PRIME": "est premier", @@ -168,15 +169,15 @@ "MATH_IS_POSITIVE": "est positif", "MATH_IS_NEGATIVE": "est négatif", "MATH_IS_DIVISIBLE_BY": "est divisible par", - "MATH_IS_TOOLTIP": "Vérifier si un nombre est pair, impair, premier, entier, positif, négatif, ou s’il est divisible par un certain nombre. Renvoie vrai ou faux.", + "MATH_IS_TOOLTIP": "Vérifier si un nombre est pair, impair, premier, entier, positif, négatif ou s’il est divisible par un certain nombre. Renvoie vrai ou faux.", "MATH_CHANGE_HELPURL": "https://fr.wikipedia.org/wiki/Idiome_de_programmation", "MATH_CHANGE_TITLE": "incrémenter %1 de %2", - "MATH_CHANGE_TOOLTIP": "Ajouter un nombre à la variable '%1'.", + "MATH_CHANGE_TOOLTIP": "Ajouter un nombre à la variable « %1 ».", "MATH_ROUND_HELPURL": "https://fr.wikipedia.org/wiki/Arrondi_(math%C3%A9matiques)", "MATH_ROUND_TOOLTIP": "Arrondir un nombre au-dessus ou au-dessous.", "MATH_ROUND_OPERATOR_ROUND": "arrondir", - "MATH_ROUND_OPERATOR_ROUNDUP": "arrondir par excès", - "MATH_ROUND_OPERATOR_ROUNDDOWN": "arrondir par défaut", + "MATH_ROUND_OPERATOR_ROUNDUP": "arrondir par excès (à l’entier supérieur le plus proche)", + "MATH_ROUND_OPERATOR_ROUNDDOWN": "arrondir par défaut (à l’entier inférieur le plus proche)", "MATH_ONLIST_OPERATOR_SUM": "somme de la liste", "MATH_ONLIST_TOOLTIP_SUM": "Renvoyer la somme de tous les nombres dans la liste.", "MATH_ONLIST_OPERATOR_MIN": "minimum de la liste", @@ -188,82 +189,82 @@ "MATH_ONLIST_OPERATOR_MEDIAN": "médiane de la liste", "MATH_ONLIST_TOOLTIP_MEDIAN": "Renvoyer le nombre médian de la liste.", "MATH_ONLIST_OPERATOR_MODE": "majoritaires de la liste", - "MATH_ONLIST_TOOLTIP_MODE": "Renvoyer une liste des élément(s) le(s) plus courant(s) dans la liste.", - "MATH_ONLIST_OPERATOR_STD_DEV": "écart-type de la liste", - "MATH_ONLIST_TOOLTIP_STD_DEV": "Renvoyer l’écart-type de la liste.", + "MATH_ONLIST_TOOLTIP_MODE": "Renvoyer une liste d’un ou plusieurs éléments les plus fréquents dans la liste.", + "MATH_ONLIST_OPERATOR_STD_DEV": "écart type de la liste", + "MATH_ONLIST_TOOLTIP_STD_DEV": "Renvoyer l’écart type de la liste.", "MATH_ONLIST_OPERATOR_RANDOM": "élément aléatoire de la liste", - "MATH_ONLIST_TOOLTIP_RANDOM": "Renvoyer un élément dans la liste au hasard.", + "MATH_ONLIST_TOOLTIP_RANDOM": "Renvoyer un élément au hasard dans la liste.", "MATH_MODULO_HELPURL": "https://fr.wikipedia.org/wiki/Modulo_(op%C3%A9ration)", "MATH_MODULO_TITLE": "reste de %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Renvoyer le reste de la division euclidienne des deux nombres.", "MATH_CONSTRAIN_TITLE": "contraindre %1 entre %2 et %3", - "MATH_CONSTRAIN_TOOLTIP": "Contraindre un nombre à être entre les limites spécifiées (incluses).", + "MATH_CONSTRAIN_TOOLTIP": "Contraindre un nombre à rester entre les limites spécifiées (incluses).", "MATH_RANDOM_INT_HELPURL": "https://fr.wikipedia.org/wiki/G%C3%A9n%C3%A9rateur_de_nombres_al%C3%A9atoires", "MATH_RANDOM_INT_TITLE": "entier aléatoire entre %1 et %2", "MATH_RANDOM_INT_TOOLTIP": "Renvoyer un entier aléatoire entre les deux limites spécifiées, incluses.", "MATH_RANDOM_FLOAT_HELPURL": "https://fr.wikipedia.org/wiki/G%C3%A9n%C3%A9rateur_de_nombres_al%C3%A9atoires", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fraction aléatoire", - "MATH_RANDOM_FLOAT_TOOLTIP": "Renvoyer une fraction aléatoire entre 0.0 (inclus) et 1.0 (exclus).", + "MATH_RANDOM_FLOAT_TOOLTIP": "Renvoyer une fraction aléatoire entre 0,0 (inclus) et 1,0 (exclus).", "MATH_ATAN2_HELPURL": "https://fr.wikipedia.org/wiki/Atan2", - "MATH_ATAN2_TITLE": "atan2 de X:%1 Y:%2", - "MATH_ATAN2_TOOLTIP": "Renvoie l'arc tangente du point (X, Y) en degrés entre -180 et 180.", + "MATH_ATAN2_TITLE": "atan2 de (X : %1 ; Y : %2)", + "MATH_ATAN2_TOOLTIP": "Renvoie l’arc-tangente du point (X, Y) en degrés entre -180 et 180.", "TEXT_TEXT_HELPURL": "https://fr.wikipedia.org/wiki/Cha%C3%AEne_de_caract%C3%A8res", "TEXT_TEXT_TOOLTIP": "Une lettre, un mot ou une ligne de texte.", "TEXT_JOIN_TITLE_CREATEWITH": "créer un texte avec", - "TEXT_JOIN_TOOLTIP": "Créer un morceau de texte en agrégeant un nombre quelconque d’éléments.", + "TEXT_JOIN_TOOLTIP": "Créer un morceau de texte en joignant bout à bout et successivement un nombre quelconque d’éléments dans le même ordre.", "TEXT_CREATE_JOIN_TITLE_JOIN": "joindre", "TEXT_CREATE_JOIN_TOOLTIP": "Ajouter, supprimer, ou réordonner des sections pour reconfigurer ce bloc de texte.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Ajouter un élément au texte.", "TEXT_APPEND_TITLE": "ajouter le texte %2 à %1", - "TEXT_APPEND_TOOLTIP": "Ajouter du texte à la variable '%1'.", + "TEXT_APPEND_TOOLTIP": "Ajouter du texte à la variable « %1 ».", "TEXT_LENGTH_TITLE": "longueur de %1", - "TEXT_LENGTH_TOOLTIP": "Renvoie le nombre de lettres (espaces compris) dans le texte fourni.", + "TEXT_LENGTH_TOOLTIP": "Renvoie le nombre de lettres (chiffres, ponctuations, symboles et espaces compris) dans le texte fourni.", "TEXT_ISEMPTY_TITLE": "%1 est vide", "TEXT_ISEMPTY_TOOLTIP": "Renvoie vrai si le texte fourni est vide.", "TEXT_INDEXOF_TOOLTIP": "Renvoie l’index de la première/dernière occurrence de la première chaîne dans la seconde. Renvoie %1 si la chaîne n’est pas trouvée.", - "TEXT_INDEXOF_TITLE": "dans le texte %1 %2 %3", + "TEXT_INDEXOF_TITLE": "%2 %3 dans le texte %1", "TEXT_INDEXOF_OPERATOR_FIRST": "trouver la première occurrence de la chaîne", - "TEXT_INDEXOF_OPERATOR_LAST": "trouver la dernière occurrence de la chaîne", - "TEXT_CHARAT_TITLE": "dans le texte %1 %2", - "TEXT_CHARAT_FROM_START": "obtenir la lettre #", - "TEXT_CHARAT_FROM_END": "obtenir la lettre # depuis la fin", + "TEXT_INDEXOF_OPERATOR_LAST": "trouver la dernière occurrence du texte", + "TEXT_CHARAT_TITLE": "%2 dans le texte %1", + "TEXT_CHARAT_FROM_START": "obtenir la lettre nº", + "TEXT_CHARAT_FROM_END": "obtenir la lettre nº (depuis la fin)", "TEXT_CHARAT_FIRST": "obtenir la première lettre", "TEXT_CHARAT_LAST": "obtenir la dernière lettre", "TEXT_CHARAT_RANDOM": "obtenir une lettre au hasard", "TEXT_CHARAT_TOOLTIP": "Renvoie la lettre à la position indiquée.", "TEXT_GET_SUBSTRING_TOOLTIP": "Renvoie une partie indiquée du texte.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "dans le texte", - "TEXT_GET_SUBSTRING_START_FROM_START": "obtenir la sous-chaîne depuis la lettre #", - "TEXT_GET_SUBSTRING_START_FROM_END": "obtenir la sous-chaîne depuis la lettre # depuis la fin", + "TEXT_GET_SUBSTRING_START_FROM_START": "obtenir la sous-chaîne depuis la lettre nº", + "TEXT_GET_SUBSTRING_START_FROM_END": "obtenir la sous-chaîne depuis la lettre nº (depuis la fin)", "TEXT_GET_SUBSTRING_START_FIRST": "obtenir la sous-chaîne depuis la première lettre", - "TEXT_GET_SUBSTRING_END_FROM_START": "jusqu’à la lettre #", - "TEXT_GET_SUBSTRING_END_FROM_END": "jusqu’à la lettre # depuis la fin", + "TEXT_GET_SUBSTRING_END_FROM_START": "jusqu’à la lettre nº", + "TEXT_GET_SUBSTRING_END_FROM_END": "jusqu’à la lettre nº (depuis la fin)", "TEXT_GET_SUBSTRING_END_LAST": "jusqu’à la dernière lettre", "TEXT_CHANGECASE_TOOLTIP": "Renvoyer une copie du texte dans une autre casse.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "en MAJUSCULES", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "en minuscules", - "TEXT_CHANGECASE_OPERATOR_TITLECASE": "en Majuscule Au Début De Chaque Mot", - "TEXT_TRIM_TOOLTIP": "Renvoyer une copie du texte avec les espaces supprimés d’un bout ou des deux.", - "TEXT_TRIM_OPERATOR_BOTH": "supprimer les espaces des deux côtés", - "TEXT_TRIM_OPERATOR_LEFT": "supprimer les espaces du côté gauche", - "TEXT_TRIM_OPERATOR_RIGHT": "supprimer les espaces du côté droit", + "TEXT_CHANGECASE_OPERATOR_TITLECASE": "en Capitale Initiale Pour Chaque Mot", + "TEXT_TRIM_TOOLTIP": "Renvoyer une copie du texte avec les espaces supprimés d’un ou des deux bouts.", + "TEXT_TRIM_OPERATOR_BOTH": "supprimer les espaces des deux côtés de", + "TEXT_TRIM_OPERATOR_LEFT": "supprimer les espaces du côté gauche de", + "TEXT_TRIM_OPERATOR_RIGHT": "supprimer les espaces du côté droit de", "TEXT_PRINT_TITLE": "afficher %1", "TEXT_PRINT_TOOLTIP": "Afficher le texte, le nombre ou une autre valeur spécifiée.", - "TEXT_PROMPT_TYPE_TEXT": "invite pour un texte avec un message", - "TEXT_PROMPT_TYPE_NUMBER": "invite pour un nombre avec un message", + "TEXT_PROMPT_TYPE_TEXT": "demander un texte avec un message", + "TEXT_PROMPT_TYPE_NUMBER": "demander un nombre avec un message", "TEXT_PROMPT_TOOLTIP_NUMBER": "Demander un nombre à l’utilisateur.", "TEXT_PROMPT_TOOLTIP_TEXT": "Demander un texte à l’utilisateur.", "TEXT_COUNT_MESSAGE0": "nombre %1 sur %2", "TEXT_COUNT_HELPURL": "https://github.com/google/blockly/wiki/Text#counting-substrings", - "TEXT_COUNT_TOOLTIP": "Compter combien de fois un texte donné apparait dans un autre.", + "TEXT_COUNT_TOOLTIP": "Compter combien de fois un texte donné apparaît dans un autre.", "TEXT_REPLACE_MESSAGE0": "remplacer %1 par %2 dans %3", "TEXT_REPLACE_HELPURL": "https://github.com/google/blockly/wiki/Text#replacing-substrings", "TEXT_REPLACE_TOOLTIP": "Remplacer toutes les occurrences d’un texte par un autre.", - "TEXT_REVERSE_MESSAGE0": "inverser %1", + "TEXT_REVERSE_MESSAGE0": "renverser %1", "TEXT_REVERSE_HELPURL": "https://github.com/google/blockly/wiki/Text#reversing-text", - "TEXT_REVERSE_TOOLTIP": "Inverse l’ordre des caractères dans le texte.", + "TEXT_REVERSE_TOOLTIP": "Renverse l’ordre des caractères dans le texte.", "LISTS_CREATE_EMPTY_TITLE": "créer une liste vide", - "LISTS_CREATE_EMPTY_TOOLTIP": "Renvoyer une liste, de longueur 0, ne contenant aucun enregistrement", + "LISTS_CREATE_EMPTY_TOOLTIP": "Renvoyer une liste, de longueur 0, ne contenant aucun enregistrement de données", "LISTS_CREATE_WITH_HELPURL": "https://github.com/google/blockly/wiki/Lists#create-list-with", "LISTS_CREATE_WITH_TOOLTIP": "Créer une liste avec un nombre quelconque d’éléments.", "LISTS_CREATE_WITH_INPUT_WITH": "créer une liste avec", diff --git a/msg/json/pt.json b/msg/json/pt.json index 6dcf155f9..111ca7055 100644 --- a/msg/json/pt.json +++ b/msg/json/pt.json @@ -20,6 +20,7 @@ ] }, "VARIABLES_DEFAULT_NAME": "item", + "UNNAMED_KEY": "sem nome", "TODAY": "Hoje", "DUPLICATE_BLOCK": "Duplicar", "ADD_COMMENT": "Adicionar Comentário", diff --git a/msg/json/tr.json b/msg/json/tr.json index 44eabbd34..cd0f99098 100644 --- a/msg/json/tr.json +++ b/msg/json/tr.json @@ -18,7 +18,8 @@ "By erdo can", "Azerhan Özen", "Hedda", - "BaRaN6161 TURK" + "BaRaN6161 TURK", + "Grkn gll" ] }, "VARIABLES_DEFAULT_NAME": "öge", @@ -31,8 +32,8 @@ "EXTERNAL_INPUTS": "Harici Girişler", "INLINE_INPUTS": "Satır içi girdiler", "DELETE_BLOCK": "Bloğu Sil", - "DELETE_X_BLOCKS": "%1 Bloğu Sil", - "DELETE_ALL_BLOCKS": "Tüm %1 blok silinsin mi?", + "DELETE_X_BLOCKS": "%1 Bloğunu Sil", + "DELETE_ALL_BLOCKS": "Tüm %1 blokları silinsin mi?", "CLEAN_UP": "Blokları temizle", "COLLAPSE_BLOCK": "Bloğu Daralt", "COLLAPSE_ALL": "Blokları Daralt", @@ -66,7 +67,7 @@ "COLOUR_RGB_RED": "kırmızı", "COLOUR_RGB_GREEN": "yeşil", "COLOUR_RGB_BLUE": "mavi", - "COLOUR_RGB_TOOLTIP": "Kırmızı, yeşil ve mavinin belirtilen miktarıyla bir renk oluştur. Tüm değerler 0 ile 100 arasında olmalıdır.", + "COLOUR_RGB_TOOLTIP": "Kırmızı, yeşil ve mavinin belirli miktarıyla bir renk oluştur. Tüm değerler 0 ile 100 arasında olmalıdır.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "karıştır", "COLOUR_BLEND_COLOUR1": "1. renk", @@ -100,7 +101,7 @@ "CONTROLS_IF_IF_TOOLTIP": "If bloğuna ekle, kaldır veya yeniden düzenleme yap.", "CONTROLS_IF_ELSEIF_TOOLTIP": "If bloğuna bir koşul ekleyin.", "CONTROLS_IF_ELSE_TOOLTIP": "If bloğuna kalan durumları \"yakalayan\" bir son ekle.", - "IOS_OK": "OK", + "IOS_OK": "TAMAM", "IOS_CANCEL": "İptal", "IOS_ERROR": "Hata", "IOS_PROCEDURES_INPUTS": "GİRDİLER", @@ -130,10 +131,10 @@ "LOGIC_BOOLEAN_FALSE": "false = Olumsuz", "LOGIC_BOOLEAN_TOOLTIP": "Ya 'True' yada 'False' değerini verir.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", - "LOGIC_NULL": "sıfır", - "LOGIC_NULL_TOOLTIP": "sıfır verir.", + "LOGIC_NULL": "boş", + "LOGIC_NULL_TOOLTIP": "boş değer döndürür.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", - "LOGIC_TERNARY_CONDITION": "test", + "LOGIC_TERNARY_CONDITION": "deneme", "LOGIC_TERNARY_IF_TRUE": "doğru ise", "LOGIC_TERNARY_IF_FALSE": "yanlış ise", "LOGIC_TERNARY_TOOLTIP": "'test'deki şartı test eder. Eğer şart doğru ise 'doğru' değeri döndürür, aksi halde 'yanlış' değeri döndürür.", From d09b85dc9e81cb423ac5ff24ccbbd8c2395bea09 Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Mon, 14 Oct 2019 09:57:38 -0700 Subject: [PATCH 032/343] Cleanup for #3179 (#3229) --- core/field_angle.js | 1 + tests/mocha/field_number_test.js | 13 +++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index 7e88f154c..415662a08 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -173,6 +173,7 @@ Blockly.FieldAngle.prototype.configure_ = function(config) { this.clockwise_ = clockwise; } + // If these are passed as null then we should leave them on the default. var offset = config['offset']; if (offset != null) { offset = Number(offset); diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index 1a4d9f700..56d8aaa0d 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -247,11 +247,10 @@ suite('Number Fields', function() { numberField.setValue(123.456); assertValue(numberField, 123); }); - test('null', function() { + test('Null', function() { var numberField = new Blockly.FieldNumber .fromJson({ precision: null}); - numberField.setValue(123.456); - assertValue(numberField, 123.456); + assertEquals(numberField.getPrecision(), 0); }); }); suite('Min', function() { @@ -282,11 +281,10 @@ suite('Number Fields', function() { numberField.setValue(20); assertValue(numberField, 20); }); - test('null', function() { + test('Null', function() { var numberField = new Blockly.FieldNumber .fromJson({ min: null}); - numberField.setValue(-20); - assertValue(numberField, -20); + assertEquals(numberField.getMin(), -Infinity); }); }); suite('Max', function() { @@ -320,8 +318,7 @@ suite('Number Fields', function() { test('null', function() { var numberField = new Blockly.FieldNumber .fromJson({ max: null}); - numberField.setValue(20); - assertValue(numberField, 20); + assertEquals(numberField.getMax(), Infinity); }); }); }); From e62c2a3f6befac79fbcc0778a22135f3397b1d89 Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Mon, 14 Oct 2019 10:40:22 -0700 Subject: [PATCH 033/343] Remove multi-line comments to avoid escaping (#3231) Fixes #3230 by removing multi-line comments for procedures. --- generators/javascript.js | 11 +- generators/python.js | 9 +- tests/generators/golden/generated.js | 338 +++++++-------------------- tests/generators/golden/generated.py | 255 +++++++------------- 4 files changed, 176 insertions(+), 437 deletions(-) diff --git a/generators/javascript.js b/generators/javascript.js index fa71a5d5b..2dae1fa93 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -253,15 +253,8 @@ Blockly.JavaScript.scrub_ = function(block, code, opt_thisOnly) { var comment = block.getCommentText(); if (comment) { comment = Blockly.utils.string.wrap(comment, - Blockly.JavaScript.COMMENT_WRAP - 3); - if (block.getProcedureDef) { - // Use a comment block for function comments. - commentCode += '/**\n' + - Blockly.JavaScript.prefixLines(comment + '\n', ' * ') + - ' */\n'; - } else { - commentCode += Blockly.JavaScript.prefixLines(comment + '\n', '// '); - } + Blockly.JavaScript.COMMENT_WRAP - 3); + commentCode += Blockly.JavaScript.prefixLines(comment + '\n', '// '); } // Collect comments for all value arguments. // Don't collect comments for nested statements. diff --git a/generators/python.js b/generators/python.js index 6676fea2e..544cd29a2 100644 --- a/generators/python.js +++ b/generators/python.js @@ -267,13 +267,8 @@ Blockly.Python.scrub_ = function(block, code, opt_thisOnly) { var comment = block.getCommentText(); if (comment) { comment = Blockly.utils.string.wrap(comment, - Blockly.Python.COMMENT_WRAP - 3); - if (block.getProcedureDef) { - // Use a comment block for function comments. - commentCode += '"""' + comment + '\n"""\n'; - } else { - commentCode += Blockly.Python.prefixLines(comment + '\n', '# '); - } + Blockly.Python.COMMENT_WRAP - 3); + commentCode += Blockly.Python.prefixLines(comment + '\n', '# '); } // Collect comments for all value arguments. // Don't collect comments for nested statements. diff --git a/tests/generators/golden/generated.js b/tests/generators/golden/generated.js index a24dd0bdd..c9b80a7a7 100644 --- a/tests/generators/golden/generated.js +++ b/tests/generators/golden/generated.js @@ -69,9 +69,7 @@ function unittest_fail(message) { unittestResults.push([false, "Fail.", message]); } -/** - * Describe this function... - */ +// Describe this function... function test_if() { if (false) { unittest_fail('if false'); @@ -108,9 +106,7 @@ function test_if() { assertEquals(ok, true, 'elseif 4'); } -/** - * Describe this function... - */ +// Describe this function... function test_ifelse() { ok = false; if (true) { @@ -128,9 +124,7 @@ function test_ifelse() { assertEquals(ok, true, 'ifelse false'); } -/** - * Describe this function... - */ +// Describe this function... function test_equalities() { assertEquals(2 == 2, true, 'Equal yes'); assertEquals(3 == 4, false, 'Equal no'); @@ -146,9 +140,7 @@ function test_equalities() { assertEquals(15 >= 16, false, 'Greater-equal no'); } -/** - * Describe this function... - */ +// Describe this function... function test_and() { assertEquals(true && true, true, 'And true/true'); assertEquals(false && true, false, 'And false/true'); @@ -156,9 +148,7 @@ function test_and() { assertEquals(false && false, false, 'And false/false'); } -/** - * Describe this function... - */ +// Describe this function... function test_or() { assertEquals(true || true, true, 'Or true/true'); assertEquals(false || true, true, 'Or false/true'); @@ -166,17 +156,13 @@ function test_or() { assertEquals(false || false, false, 'Or false/false'); } -/** - * Describe this function... - */ +// Describe this function... function test_ternary() { assertEquals(true ? 42 : 99, 42, 'if true'); assertEquals(false ? 42 : 99, 99, 'if true'); } -/** - * Describe this function... - */ +// Describe this function... function test_foreach() { log = ''; var x_list = ['a', 'b', 'c']; @@ -187,9 +173,7 @@ function test_foreach() { assertEquals(log, 'abc', 'for loop'); } -/** - * Describe this function... - */ +// Describe this function... function test_repeat() { count = 0; for (var count2 = 0; count2 < 10; count2++) { @@ -198,9 +182,7 @@ function test_repeat() { assertEquals(count, 10, 'repeat 10'); } -/** - * Describe this function... - */ +// Describe this function... function test_while() { while (false) { unittest_fail('while 0'); @@ -220,9 +202,7 @@ function test_while() { assertEquals(count, 10, 'until 10'); } -/** - * Describe this function... - */ +// Describe this function... function test_repeat_ext() { count = 0; for (var count3 = 0; count3 < 10; count3++) { @@ -231,9 +211,7 @@ function test_repeat_ext() { assertEquals(count, 10, 'repeat 10'); } -/** - * Describe this function... - */ +// Describe this function... function test_count_by() { log = ''; for (x = 1; x <= 8; x += 2) { @@ -285,9 +263,7 @@ function test_count_by() { assertEquals(loglist, [5.5, 4.5, 3.5, 2.5, 1.5], 'count with floats'); } -/** - * Describe this function... - */ +// Describe this function... function test_count_loops() { log = ''; for (x = 1; x <= 8; x++) { @@ -323,9 +299,7 @@ function test_count_loops() { assertEquals(loglist, [4, 3, 2, 1], 'count down non-trivial'); } -/** - * Describe this function... - */ +// Describe this function... function test_continue() { log = ''; count = 0; @@ -367,9 +341,7 @@ function test_continue() { assertEquals(log, 'abd', 'for continue'); } -/** - * Describe this function... - */ +// Describe this function... function test_break() { count = 1; while (count != 10) { @@ -407,9 +379,7 @@ function test_break() { assertEquals(log, 'ab', 'for break'); } -/** - * Tests the "single" block. - */ +// Tests the "single" block. function test_single() { assertEquals(Math.sqrt(25), 5, 'sqrt'); assertEquals(Math.abs(-25), 25, 'abs'); @@ -420,10 +390,8 @@ function test_single() { assertEquals(Math.pow(10,2), 100, 'power10'); } -/** - * Tests the "arithmetic" block for all operations and checks - * parenthesis are properly generated for different orders. - */ +// Tests the "arithmetic" block for all operations and checks +// parenthesis are properly generated for different orders. function test_arithmetic() { assertEquals(1 + 2, 3, 'add'); assertEquals(1 - 2, -1, 'subtract'); @@ -437,9 +405,7 @@ function test_arithmetic() { assertEquals(Math.pow(10, 0 + 4), 10000, 'power order'); } -/** - * Tests the "trig" block. - */ +// Tests the "trig" block. function test_trig() { assertEquals(Math.sin(90 / 180 * Math.PI), 1, 'sin'); assertEquals(Math.cos(180 / 180 * Math.PI), -1, 'cos'); @@ -449,9 +415,7 @@ function test_trig() { assertEquals(Math.atan(1) / Math.PI * 180, 45, 'atan'); } -/** - * Tests the "constant" blocks. - */ +// Tests the "constant" blocks. function test_constant() { assertEquals(Math.floor(Math.PI * 1000), 3141, 'const pi'); assertEquals(Math.floor(Math.E * 1000), 2718, 'const e'); @@ -480,9 +444,7 @@ function mathIsPrime(n) { return true; } -/** - * Tests the "number property" blocks. - */ +// Tests the "number property" blocks. function test_number_properties() { assertEquals(42 % 2 == 0, true, 'even'); assertEquals(42.1 % 2 == 1, false, 'odd'); @@ -495,18 +457,14 @@ function test_number_properties() { assertEquals(42 % 2 == 0, true, 'divisible'); } -/** - * Tests the "round" block. - */ +// Tests the "round" block. function test_round() { assertEquals(Math.round(42.42), 42, 'round'); assertEquals(Math.ceil(-42.42), -42, 'round up'); assertEquals(Math.floor(42.42), 42, 'round down'); } -/** - * Tests the "change" block. - */ +// Tests the "change" block. function test_change() { varToChange = 100; varToChange = (typeof varToChange == 'number' ? varToChange : 0) + 42; @@ -574,9 +532,7 @@ function mathRandomList(list) { return list[x]; } -/** - * Tests the "list operation" blocks. - */ +// Tests the "list operation" blocks. function test_operations_on_list() { assertEquals([3, 4, 5].reduce(function(x, y) {return x + y;}), 12, 'sum'); assertEquals(Math.min.apply(null, [3, 4, 5]), 3, 'min'); @@ -589,16 +545,12 @@ function test_operations_on_list() { assertEquals([3, 4, 5].indexOf(mathRandomList([3, 4, 5])) + 1 > 0, true, 'random'); } -/** - * Tests the "mod" block. - */ +// Tests the "mod" block. function test_mod() { assertEquals(42 % 5, 2, 'mod'); } -/** - * Tests the "constrain" block. - */ +// Tests the "constrain" block. function test_constraint() { assertEquals(Math.min(Math.max(100, 0), 42), 42, 'constraint'); } @@ -613,43 +565,33 @@ function mathRandomInt(a, b) { return Math.floor(Math.random() * (b - a + 1) + a); } -/** - * Tests the "random integer" block. - */ +// Tests the "random integer" block. function test_random_integer() { rand = mathRandomInt(5, 10); assertEquals(rand >= 5 && rand <= 10, true, 'randRange'); assertEquals(rand % 1 == 0, true, 'randInteger'); } -/** - * Tests the "random fraction" block. - */ +// Tests the "random fraction" block. function test_random_fraction() { rand = Math.random(); assertEquals(rand >= 0 && rand <= 1, true, 'randFloat'); } -/** - * Describe this function... - */ +// Describe this function... function test_atan2() { assertEquals(Math.atan2(5, -5) / Math.PI * 180, 135, 'atan2'); assertEquals(Math.atan2(-12, 0) / Math.PI * 180, -90, 'atan2'); } -/** - * Checks that the number of calls is one in order - * to confirm that a function was only called once. - */ +// Checks that the number of calls is one in order +// to confirm that a function was only called once. function check_number_of_calls(test_name) { test_name += 'number of calls'; assertEquals(number_of_calls, 1, test_name); } -/** - * Tests the "create text with" block with varying number of inputs. - */ +// Tests the "create text with" block with varying number of inputs. function test_create_text() { assertEquals('', '', 'no text'); assertEquals('Hello', 'Hello', 'create single'); @@ -660,16 +602,12 @@ function test_create_text() { assertEquals([1,true ? 0 : null,'M'].join(''), '10M', 'create order'); } -/** - * Creates an empty string for use with the empty test. - */ +// Creates an empty string for use with the empty test. function get_empty() { return ''; } -/** - * Tests the "is empty" block". - */ +// Tests the "is empty" block". function test_empty_text() { assertEquals(!'Google'.length, false, 'not empty'); assertEquals(!''.length, true, 'empty'); @@ -677,18 +615,14 @@ function test_empty_text() { assertEquals(!(true ? '' : null).length, true, 'empty order'); } -/** - * Tests the "length" block. - */ +// Tests the "length" block. function test_text_length() { assertEquals(''.length, 0, 'zero length'); assertEquals('Google'.length, 6, 'non-zero length'); assertEquals((true ? 'car' : null).length, 3, 'length order'); } -/** - * Tests the "append text" block with different types of parameters. - */ +// Tests the "append text" block with different types of parameters. function test_append() { item = 'Miserable'; item += 'Failure'; @@ -701,9 +635,7 @@ function test_append() { assertEquals(item, 'Something Positive', 'append order'); } -/** - * Tests the "find" block with a variable. - */ +// Tests the "find" block with a variable. function test_find_text_simple() { text = 'Banana'; assertEquals(text.indexOf('an') + 1, 2, 'find first simple'); @@ -711,17 +643,13 @@ function test_find_text_simple() { assertEquals(text.indexOf('Peel') + 1, 0, 'find none simple'); } -/** - * Creates a string for use with the find test. - */ +// Creates a string for use with the find test. function get_fruit() { number_of_calls = (typeof number_of_calls == 'number' ? number_of_calls : 0) + 1; return 'Banana'; } -/** - * Tests the "find" block with a function call. - */ +// Tests the "find" block with a function call. function test_find_text_complex() { number_of_calls = 0; assertEquals(get_fruit().indexOf('an') + 1, 2, 'find first complex'); @@ -748,9 +676,7 @@ function textRandomLetter(text) { return text[x]; } -/** - * Tests the "get letter" block with a variable. - */ +// Tests the "get letter" block with a variable. function test_get_text_simple() { text = 'Blockly'; assertEquals(text.charAt(0), 'B', 'get first simple'); @@ -763,17 +689,13 @@ function test_get_text_simple() { assertEquals(text.slice((-(0 + 3))).charAt(0), 'k', 'get #-end order simple'); } -/** - * Creates a string for use with the get test. - */ +// Creates a string for use with the get test. function get_Blockly() { number_of_calls = (typeof number_of_calls == 'number' ? number_of_calls : 0) + 1; return 'Blockly'; } -/** - * Tests the "get letter" block with a function call. - */ +// Tests the "get letter" block with a function call. function test_get_text_complex() { text = 'Blockly'; number_of_calls = 0; @@ -809,17 +731,13 @@ function test_get_text_complex() { check_number_of_calls('get #-end order complex'); } -/** - * Creates a string for use with the substring test. - */ +// Creates a string for use with the substring test. function get_numbers() { number_of_calls = (typeof number_of_calls == 'number' ? number_of_calls : 0) + 1; return '123456789'; } -/** - * Tests the "get substring" block with a variable. - */ +// Tests the "get substring" block with a variable. function test_substring_simple() { text = '123456789'; assertEquals(text.slice(1, 3), '23', 'substring # simple'); @@ -876,9 +794,7 @@ function subsequenceFromEndLast(sequence, at1) { return sequence.slice(start, end); } -/** - * Tests the "get substring" block with a function call. - */ +// Tests the "get substring" block with a function call. function test_substring_complex() { number_of_calls = 0; assertEquals(get_numbers().slice(1, 3), '23', 'substring # complex'); @@ -931,9 +847,7 @@ function textToTitleCase(str) { function(txt) {return txt[0].toUpperCase() + txt.substring(1).toLowerCase();}); } -/** - * Tests the "change casing" block. - */ +// Tests the "change casing" block. function test_case() { text = 'Hello World'; assertEquals(text.toUpperCase(), 'HELLO WORLD', 'uppercase'); @@ -946,9 +860,7 @@ function test_case() { assertEquals(textToTitleCase(true ? text : null), 'Hello World', 'titlecase order'); } -/** - * Tests the "trim" block. - */ +// Tests the "trim" block. function test_trim() { text = ' abc def '; assertEquals(text.trim(), 'abc def', 'trim both'); @@ -967,9 +879,7 @@ function textCount(haystack, needle) { } } -/** - * Tests the "trim" block. - */ +// Tests the "trim" block. function test_count_text() { text = 'woolloomooloo'; assertEquals(textCount(text, 'o'), 8, 'len 1'); @@ -981,9 +891,7 @@ function test_count_text() { assertEquals(textCount('', 'chicken'), 0, 'empty source'); } -/** - * Tests the "trim" block. - */ +// Tests the "trim" block. function test_text_reverse() { assertEquals(''.split('').reverse().join(''), '', 'empty string'); assertEquals('a'.split('').reverse().join(''), 'a', 'len 1'); @@ -997,9 +905,7 @@ function textReplace(haystack, needle, replacement) { return haystack.replace(new RegExp(needle, 'g'), replacement); } -/** - * Tests the "trim" block. - */ +// Tests the "trim" block. function test_replace() { assertEquals(textReplace('woolloomooloo', 'oo', '123'), 'w123ll123m123l123', 'replace all instances 1'); assertEquals(textReplace('woolloomooloo', '.oo', 'X'), 'woolloomooloo', 'literal string replacement'); @@ -1010,10 +916,8 @@ function test_replace() { assertEquals(textReplace('', 'a', 'chicken'), '', 'empty source'); } -/** - * Checks that the number of calls is one in order - * to confirm that a function was only called once. - */ +// Checks that the number of calls is one in order +// to confirm that a function was only called once. function check_number_of_calls2(test_name) { test_name += 'number of calls'; assertEquals(number_of_calls, 1, test_name); @@ -1027,9 +931,7 @@ function listsRepeat(value, n) { return array; } -/** - * Tests the "create list with" and "create empty list" blocks. - */ +// Tests the "create list with" and "create empty list" blocks. function test_create_lists() { assertEquals([], [], 'create empty'); assertEquals([true, 'love'], [true, 'love'], 'create items'); @@ -1037,16 +939,12 @@ function test_create_lists() { assertEquals(listsRepeat('Eject', 0 + 3), ['Eject', 'Eject', 'Eject'], 'create repeated order'); } -/** - * Creates an empty list for use with the empty test. - */ +// Creates an empty list for use with the empty test. function get_empty_list() { return []; } -/** - * Tests the "is empty" block. - */ +// Tests the "is empty" block. function test_lists_empty() { assertEquals(![0].length, false, 'not empty'); assertEquals(![].length, true, 'empty'); @@ -1054,9 +952,7 @@ function test_lists_empty() { assertEquals(!(true ? [] : null).length, true, 'empty order'); } -/** - * Tests the "length" block. - */ +// Tests the "length" block. function test_lists_length() { assertEquals([].length, 0, 'zero length'); assertEquals(['cat'].length, 1, 'one length'); @@ -1064,9 +960,7 @@ function test_lists_length() { assertEquals((true ? ['cat', true] : null).length, 2, 'two length order'); } -/** - * Tests the "find" block with a variable. - */ +// Tests the "find" block with a variable. function test_find_lists_simple() { list = ['Alice', 'Eve', 'Bob', 'Eve']; assertEquals(list.indexOf('Eve') + 1, 2, 'find first simple'); @@ -1074,17 +968,13 @@ function test_find_lists_simple() { assertEquals(list.indexOf('Dave') + 1, 0, 'find none simple'); } -/** - * Creates a list for use with the find test. - */ +// Creates a list for use with the find test. function get_names() { number_of_calls = (typeof number_of_calls == 'number' ? number_of_calls : 0) + 1; return ['Alice', 'Eve', 'Bob', 'Eve']; } -/** - * Tests the "find" block with a function call. - */ +// Tests the "find" block with a function call. function test_find_lists_complex() { number_of_calls = 0; assertEquals(get_names().indexOf('Eve') + 1, 2, 'find first complex'); @@ -1115,9 +1005,7 @@ function listsGetRandomItem(list, remove) { } } -/** - * Tests the "get" block with a variable. - */ +// Tests the "get" block with a variable. function test_get_lists_simple() { list = ['Kirk', 'Spock', 'McCoy']; assertEquals(list[0], 'Kirk', 'get first simple'); @@ -1130,17 +1018,13 @@ function test_get_lists_simple() { assertEquals(list.slice((-(0 + 3)))[0], 'Kirk', 'get #-end order simple'); } -/** - * Creates a list for use with the get test. - */ +// Creates a list for use with the get test. function get_star_wars() { number_of_calls = (typeof number_of_calls == 'number' ? number_of_calls : 0) + 1; return ['Kirk', 'Spock', 'McCoy']; } -/** - * Tests the "get" block with a function call. - */ +// Tests the "get" block with a function call. function test_get_lists_complex() { list = ['Kirk', 'Spock', 'McCoy']; number_of_calls = 0; @@ -1176,9 +1060,7 @@ function test_get_lists_complex() { check_number_of_calls('get #-end order complex'); } -/** - * Tests the "get and remove" block. - */ +// Tests the "get and remove" block. function test_getRemove() { list = ['Kirk', 'Spock', 'McCoy']; assertEquals(list.shift(), 'Kirk', 'getremove first'); @@ -1213,9 +1095,7 @@ function test_getRemove() { assertEquals(list, ['Spock', 'McCoy'], 'getremove #-end order list'); } -/** - * Tests the "remove" block. - */ +// Tests the "remove" block. function test_remove() { list = ['Kirk', 'Spock', 'McCoy']; list.shift(); @@ -1249,9 +1129,7 @@ function test_remove() { (true ? list : null).splice((-(0 + 3)), 1);assertEquals(list, ['Spock', 'McCoy'], 'remove #-end order list'); } -/** - * Tests the "set" block. - */ +// Tests the "set" block. function test_set() { list = ['Picard', 'Riker', 'Crusher']; list[0] = 'Jean-Luc'; @@ -1292,9 +1170,7 @@ function test_set() { assertEquals(list, ['Picard', 'Pulaski', 'Crusher'], 'set #-end order list'); } -/** - * Tests the "insert" block. - */ +// Tests the "insert" block. function test_insert() { list = ['Picard', 'Riker', 'Crusher']; list.unshift('Data'); @@ -1334,9 +1210,7 @@ function test_insert() { assertEquals(list, ['Picard', 'Data', 'Riker', 'Crusher'], 'insert #-end order list'); } -/** - * Tests the "get sub-list" block with a variable. - */ +// Tests the "get sub-list" block with a variable. function test_sublist_simple() { list = ['Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour']; assertEquals(list.slice(1, 3), ['Challenger', 'Discovery'], 'sublist # simple'); @@ -1361,17 +1235,13 @@ function test_sublist_simple() { assertEquals(list.slice(((0 + 1) - 1), list.length - ((0 + 1) - 1)), list, 'sublist all with # #-end math simple'); } -/** - * Creates a list for use with the sublist test. - */ +// Creates a list for use with the sublist test. function get_space_shuttles() { number_of_calls = (typeof number_of_calls == 'number' ? number_of_calls : 0) + 1; return ['Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour']; } -/** - * Tests the "get sub-list" block with a function call. - */ +// Tests the "get sub-list" block with a function call. function test_sublist_complex() { number_of_calls = 0; assertEquals(get_space_shuttles().slice(1, 3), ['Challenger', 'Discovery'], 'sublist # start complex'); @@ -1419,18 +1289,14 @@ function test_sublist_complex() { check_number_of_calls('sublist all with # #-end math complex'); } -/** - * Tests the "join" block. - */ +// Tests the "join" block. function test_join() { list = ['Vulcan', 'Klingon', 'Borg']; assertEquals(list.join(','), 'Vulcan,Klingon,Borg', 'join'); assertEquals((true ? list : null).join(','), 'Vulcan,Klingon,Borg', 'join order'); } -/** - * Tests the "split" block. - */ +// Tests the "split" block. function test_split() { text = 'Vulcan,Klingon,Borg'; assertEquals(text.split(','), ['Vulcan', 'Klingon', 'Borg'], 'split'); @@ -1450,36 +1316,28 @@ function listsGetSortCompare(type, direction) { return function(a, b) { return compare(a, b) * direction; } } -/** - * Tests the "alphabetic sort" block. - */ +// Tests the "alphabetic sort" block. function test_sort_alphabetic() { list = ['Vulcan', 'klingon', 'Borg']; assertEquals(list.slice().sort(listsGetSortCompare("TEXT", 1)), ['Borg', 'Vulcan', 'klingon'], 'sort alphabetic ascending'); assertEquals((true ? list : null).slice().sort(listsGetSortCompare("TEXT", 1)), ['Borg', 'Vulcan', 'klingon'], 'sort alphabetic ascending order'); } -/** - * Tests the "alphabetic sort ignore case" block. - */ +// Tests the "alphabetic sort ignore case" block. function test_sort_ignoreCase() { list = ['Vulcan', 'klingon', 'Borg']; assertEquals(list.slice().sort(listsGetSortCompare("IGNORE_CASE", 1)), ['Borg', 'klingon', 'Vulcan'], 'sort ignore case ascending'); assertEquals((true ? list : null).slice().sort(listsGetSortCompare("IGNORE_CASE", 1)), ['Borg', 'klingon', 'Vulcan'], 'sort ignore case ascending order'); } -/** - * Tests the "numeric sort" block. - */ +// Tests the "numeric sort" block. function test_sort_numeric() { list = [8, 18, -1]; assertEquals(list.slice().sort(listsGetSortCompare("NUMERIC", -1)), [18, 8, -1], 'sort numeric descending'); assertEquals((true ? list : null).slice().sort(listsGetSortCompare("NUMERIC", -1)), [18, 8, -1], 'sort numeric descending order'); } -/** - * Tests the "list reverse" block. - */ +// Tests the "list reverse" block. function test_lists_reverse() { list = [8, 18, -1, 64]; assertEquals(list.slice().reverse(), [64, -1, 18, 8], 'reverse a copy'); @@ -1488,9 +1346,7 @@ function test_lists_reverse() { assertEquals(list.slice().reverse(), [], 'empty list'); } -/** - * Describe this function... - */ +// Describe this function... function test_colour_picker() { assertEquals('#ff6600', '#ff6600', 'static colour'); } @@ -1505,9 +1361,7 @@ function colourRgb(r, g, b) { return '#' + r + g + b; } -/** - * Describe this function... - */ +// Describe this function... function test_rgb() { assertEquals(colourRgb(100, 40, 0), '#ff6600', 'from rgb'); } @@ -1517,9 +1371,7 @@ function colourRandom() { return '#' + ('00000' + num.toString(16)).substr(-6); } -/** - * Describe this function... - */ +// Describe this function... function test_colour_random() { for (var count4 = 0; count4 < 100; count4++) { item = colourRandom(); @@ -1548,16 +1400,12 @@ function colourBlend(c1, c2, ratio) { return '#' + r + g + b; } -/** - * Describe this function... - */ +// Describe this function... function test_blend() { assertEquals(colourBlend('#ff0000', colourRgb(100, 40, 0), 0.4), '#ff2900', 'blend'); } -/** - * Describe this function... - */ +// Describe this function... function test_procedure() { procedure_1(8, 2); assertEquals(proc_z, 4, 'procedure with global'); @@ -1569,16 +1417,12 @@ function test_procedure() { assertEquals(proc_w, false, 'procedure return'); } -/** - * Describe this function... - */ +// Describe this function... function procedure_1(proc_x, proc_y) { proc_z = proc_x / proc_y; } -/** - * Describe this function... - */ +// Describe this function... function procedure_2(proc_x) { if (proc_x) { return; @@ -1586,9 +1430,7 @@ function procedure_2(proc_x) { proc_w = true; } -/** - * Describe this function... - */ +// Describe this function... function test_function() { assertEquals(function_1(2, 3), -1, 'function with arguments'); assertEquals(func_z, 'side effect', 'function with side effect'); @@ -1600,25 +1442,19 @@ function test_function() { assertEquals(function_3(false), false, 'function no return'); } -/** - * Describe this function... - */ +// Describe this function... function function_1(func_x, func_y) { func_z = 'side effect'; return func_x - func_y; } -/** - * Describe this function... - */ +// Describe this function... function function_2(func_a) { func_a = (typeof func_a == 'number' ? func_a : 0) + 1; return String(func_a) + String(func_c); } -/** - * Describe this function... - */ +// Describe this function... function function_3(func_a) { if (func_a) { return true; @@ -1626,9 +1462,7 @@ function function_3(func_a) { return false; } -/** - * Describe this function... - */ +// Describe this function... function recurse(n) { if (n > 0) { text = [recurse(n - 1),n,recurse(n - 1)].join(''); diff --git a/tests/generators/golden/generated.py b/tests/generators/golden/generated.py index 603a4ddd2..b20142bb6 100644 --- a/tests/generators/golden/generated.py +++ b/tests/generators/golden/generated.py @@ -71,8 +71,7 @@ def fail(message): raise Exception("Orphaned assert equals: " + message) unittestResults.append((False, "Fail.", message)) -"""Describe this function... -""" +# Describe this function... def test_if(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults if False: @@ -104,8 +103,7 @@ def test_if(): fail('elseif 3') assertEquals(ok, True, 'elseif 4') -"""Describe this function... -""" +# Describe this function... def test_ifelse(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults ok = False @@ -121,8 +119,7 @@ def test_ifelse(): ok = True assertEquals(ok, True, 'ifelse false') -"""Describe this function... -""" +# Describe this function... def test_equalities(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(2 == 2, True, 'Equal yes') @@ -138,8 +135,7 @@ def test_equalities(): assertEquals(14 >= 14, True, 'Greater-equal yes') assertEquals(15 >= 16, False, 'Greater-equal no') -"""Describe this function... -""" +# Describe this function... def test_and(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(True and True, True, 'And true/true') @@ -147,8 +143,7 @@ def test_and(): assertEquals(True and False, False, 'And true/false') assertEquals(False and False, False, 'And false/false') -"""Describe this function... -""" +# Describe this function... def test_or(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(True or True, True, 'Or true/true') @@ -156,15 +151,13 @@ def test_or(): assertEquals(True or False, True, 'Or true/false') assertEquals(False or False, False, 'Or false/false') -"""Describe this function... -""" +# Describe this function... def test_ternary(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(42 if True else 99, 42, 'if true') assertEquals(42 if False else 99, 99, 'if true') -"""Describe this function... -""" +# Describe this function... def test_foreach(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults log = '' @@ -172,8 +165,7 @@ def test_foreach(): log = str(log) + str(x) assertEquals(log, 'abc', 'for loop') -"""Describe this function... -""" +# Describe this function... def test_repeat(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults count = 0 @@ -181,8 +173,7 @@ def test_repeat(): count = (count if isinstance(count, Number) else 0) + 1 assertEquals(count, 10, 'repeat 10') -"""Describe this function... -""" +# Describe this function... def test_while(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults while False: @@ -198,8 +189,7 @@ def test_while(): count = (count if isinstance(count, Number) else 0) + 1 assertEquals(count, 10, 'until 10') -"""Describe this function... -""" +# Describe this function... def test_repeat_ext(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults count = 0 @@ -217,8 +207,7 @@ def downRange(start, stop, step): yield start start -= abs(step) -"""Describe this function... -""" +# Describe this function... def test_count_by(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults log = '' @@ -254,8 +243,7 @@ def test_count_by(): loglist.append(x) assertEquals(loglist, [5.5, 4.5, 3.5, 2.5, 1.5], 'count with floats') -"""Describe this function... -""" +# Describe this function... def test_count_loops(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults log = '' @@ -279,8 +267,7 @@ def test_count_loops(): loglist.append(x) assertEquals(loglist, [4, 3, 2, 1], 'count down non-trivial') -"""Describe this function... -""" +# Describe this function... def test_continue(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults log = '' @@ -312,8 +299,7 @@ def test_continue(): log = str(log) + str(x) assertEquals(log, 'abd', 'for continue') -"""Describe this function... -""" +# Describe this function... def test_break(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults count = 1 @@ -341,8 +327,7 @@ def test_break(): log = str(log) + str(x) assertEquals(log, 'ab', 'for break') -"""Tests the "single" block. -""" +# Tests the "single" block. def test_single(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(math.sqrt(25), 5, 'sqrt') @@ -353,9 +338,8 @@ def test_single(): assertEquals(math.exp(2), 7.38905609893065, 'exp') assertEquals(math.pow(10,2), 100, 'power10') -"""Tests the "arithmetic" block for all operations and checks -parenthesis are properly generated for different orders. -""" +# Tests the "arithmetic" block for all operations and checks +# parenthesis are properly generated for different orders. def test_arithmetic(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(1 + 2, 3, 'add') @@ -369,8 +353,7 @@ def test_arithmetic(): assertEquals(10 ** 4, 10000, 'power') assertEquals(10 ** (0 + 4), 10000, 'power order') -"""Tests the "trig" block. -""" +# Tests the "trig" block. def test_trig(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(math.sin(90 / 180.0 * math.pi), 1, 'sin') @@ -380,8 +363,7 @@ def test_trig(): assertEquals(math.acos(1) / math.pi * 180, 0, 'acos') assertEquals(math.atan(1) / math.pi * 180, 45, 'atan') -"""Tests the "constant" blocks. -""" +# Tests the "constant" blocks. def test_constant(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(math.floor(math.pi * 1000), 3141, 'const pi') @@ -410,8 +392,7 @@ def math_isPrime(n): return False return True -"""Tests the "number property" blocks. -""" +# Tests the "number property" blocks. def test_number_properties(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(42 % 2 == 0, True, 'even') @@ -424,16 +405,14 @@ def test_number_properties(): assertEquals(-42 < 0, True, 'negative') assertEquals(42 % 2 == 0, True, 'divisible') -"""Tests the "round" block. -""" +# Tests the "round" block. def test_round(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(round(42.42), 42, 'round') assertEquals(math.ceil(-42.42), -42, 'round up') assertEquals(math.floor(42.42), 42, 'round down') -"""Tests the "change" block. -""" +# Tests the "change" block. def test_change(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults varToChange = 100 @@ -485,8 +464,7 @@ def first_index(my_list, elem): except: index = 0 return index -"""Tests the "list operation" blocks. -""" +# Tests the "list operation" blocks. def test_operations_on_list(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(sum([3, 4, 5]), 12, 'sum') @@ -499,50 +477,43 @@ def test_operations_on_list(): assertEquals(math_standard_deviation([3, 3, 3]), 0, 'standard dev') assertEquals(first_index([3, 4, 5], random.choice([3, 4, 5])) > 0, True, 'random') -"""Tests the "mod" block. -""" +# Tests the "mod" block. def test_mod(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(42 % 5, 2, 'mod') -"""Tests the "constrain" block. -""" +# Tests the "constrain" block. def test_constraint(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(min(max(100, 0), 42), 42, 'constraint') -"""Tests the "random integer" block. -""" +# Tests the "random integer" block. def test_random_integer(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults rand = random.randint(5, 10) assertEquals(rand >= 5 and rand <= 10, True, 'randRange') assertEquals(rand % 1 == 0, True, 'randInteger') -"""Tests the "random fraction" block. -""" +# Tests the "random fraction" block. def test_random_fraction(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults rand = random.random() assertEquals(rand >= 0 and rand <= 1, True, 'randFloat') -"""Describe this function... -""" +# Describe this function... def test_atan2(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(math.atan2(5, -5) / math.pi * 180, 135, 'atan2') assertEquals(math.atan2(-12, 0) / math.pi * 180, -90, 'atan2') -"""Checks that the number of calls is one in order -to confirm that a function was only called once. -""" +# Checks that the number of calls is one in order +# to confirm that a function was only called once. def check_number_of_calls(test_name): global naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults test_name = str(test_name) + 'number of calls' assertEquals(number_of_calls, 1, test_name) -"""Tests the "create text with" block with varying number of inputs. -""" +# Tests the "create text with" block with varying number of inputs. def test_create_text(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals('', '', 'no text') @@ -553,14 +524,12 @@ def test_create_text(): assertEquals(''.join([str(x2) for x2 in [1, 2, 3]]), '123', 'create triple') assertEquals(''.join([str(x3) for x3 in [1, 0 if True else None, 'M']]), '10M', 'create order') -"""Creates an empty string for use with the empty test. -""" +# Creates an empty string for use with the empty test. def get_empty(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults return '' -"""Tests the "is empty" block". -""" +# Tests the "is empty" block". def test_empty_text(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(not len('Google'), False, 'not empty') @@ -568,16 +537,14 @@ def test_empty_text(): assertEquals(not len(get_empty()), True, 'empty complex') assertEquals(not len('' if True else None), True, 'empty order') -"""Tests the "length" block. -""" +# Tests the "length" block. def test_text_length(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(len(''), 0, 'zero length') assertEquals(len('Google'), 6, 'non-zero length') assertEquals(len('car' if True else None), 3, 'length order') -"""Tests the "append text" block with different types of parameters. -""" +# Tests the "append text" block with different types of parameters. def test_append(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults item = 'Miserable' @@ -590,8 +557,7 @@ def test_append(): item = str(item) + str('Positive' if True else None) assertEquals(item, 'Something Positive', 'append order') -"""Tests the "find" block with a variable. -""" +# Tests the "find" block with a variable. def test_find_text_simple(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = 'Banana' @@ -599,15 +565,13 @@ def test_find_text_simple(): assertEquals(text.rfind('an') + 1, 4, 'find last simple') assertEquals(text.find('Peel') + 1, 0, 'find none simple') -"""Creates a string for use with the find test. -""" +# Creates a string for use with the find test. def get_fruit(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = (number_of_calls if isinstance(number_of_calls, Number) else 0) + 1 return 'Banana' -"""Tests the "find" block with a function call. -""" +# Tests the "find" block with a function call. def test_find_text_complex(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = 0 @@ -633,8 +597,7 @@ def text_random_letter(text): x = int(random.random() * len(text)) return text[x]; -"""Tests the "get letter" block with a variable. -""" +# Tests the "get letter" block with a variable. def test_get_text_simple(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = 'Blockly' @@ -647,15 +610,13 @@ def test_get_text_simple(): # The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. assertEquals(text[-int(0 + 3)], 'k', 'get #-end order simple') -"""Creates a string for use with the get test. -""" +# Creates a string for use with the get test. def get_Blockly(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = (number_of_calls if isinstance(number_of_calls, Number) else 0) + 1 return 'Blockly' -"""Tests the "get letter" block with a function call. -""" +# Tests the "get letter" block with a function call. def test_get_text_complex(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = 'Blockly' @@ -691,15 +652,13 @@ def test_get_text_complex(): assertEquals((get_Blockly() if True else None)[-int(0 + 3)], 'k', 'get #-end order complex') check_number_of_calls('get #-end order complex') -"""Creates a string for use with the substring test. -""" +# Creates a string for use with the substring test. def get_numbers(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = (number_of_calls if isinstance(number_of_calls, Number) else 0) + 1 return '123456789' -"""Tests the "get substring" block with a variable. -""" +# Tests the "get substring" block with a variable. def test_substring_simple(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = '123456789' @@ -720,8 +679,7 @@ def test_substring_simple(): # Checks that the whole string is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where substring uses [x:length - y] for # #-end. assertEquals(text[int((0 + 1) - 1) : -int((0 + 1) - 1) or sys.maxsize], '123456789', 'substring all with # #-end math simple') -"""Tests the "get substring" block with a function call. -""" +# Tests the "get substring" block with a function call. def test_substring_complex(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = 0 @@ -769,8 +727,7 @@ def test_substring_complex(): assertEquals(get_numbers()[int((0 + 1) - 1) : -int((0 + 1) - 1) or sys.maxsize], '123456789', 'substring all with # #-end math complex') check_number_of_calls('substring all with # #-end math complex') -"""Tests the "change casing" block. -""" +# Tests the "change casing" block. def test_case(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = 'Hello World' @@ -783,8 +740,7 @@ def test_case(): assertEquals(text.title(), 'Hello World', 'titlecase') assertEquals((text if True else None).title(), 'Hello World', 'titlecase order') -"""Tests the "trim" block. -""" +# Tests the "trim" block. def test_trim(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = ' abc def ' @@ -795,8 +751,7 @@ def test_trim(): assertEquals(text.rstrip(), ' abc def', 'trim right') assertEquals((text if True else None).rstrip(), ' abc def', 'trim right order') -"""Tests the "trim" block. -""" +# Tests the "trim" block. def test_count_text(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = 'woolloomooloo' @@ -808,8 +763,7 @@ def test_count_text(): assertEquals(text.count(''), 14, 'empty needle') assertEquals(''.count('chicken'), 0, 'empty source') -"""Tests the "trim" block. -""" +# Tests the "trim" block. def test_text_reverse(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(''[::-1], '', 'empty string') @@ -817,8 +771,7 @@ def test_text_reverse(): assertEquals('ab'[::-1], 'ba', 'len 2') assertEquals('woolloomooloo'[::-1], 'ooloomoolloow', 'longer') -"""Tests the "trim" block. -""" +# Tests the "trim" block. def test_replace(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals('woolloomooloo'.replace('oo', '123'), 'w123ll123m123l123', 'replace all instances 1') @@ -829,16 +782,14 @@ def test_replace(): assertEquals('aaaaa'.replace('a', ''), '', 'empty replacement 3') assertEquals(''.replace('a', 'chicken'), '', 'empty source') -"""Checks that the number of calls is one in order -to confirm that a function was only called once. -""" +# Checks that the number of calls is one in order +# to confirm that a function was only called once. def check_number_of_calls2(test_name): global naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults test_name = str(test_name) + 'number of calls' assertEquals(number_of_calls, 1, test_name) -"""Tests the "create list with" and "create empty list" blocks. -""" +# Tests the "create list with" and "create empty list" blocks. def test_create_lists(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals([], [], 'create empty') @@ -846,14 +797,12 @@ def test_create_lists(): assertEquals(['Eject'] * 3, ['Eject', 'Eject', 'Eject'], 'create repeated') assertEquals(['Eject'] * (0 + 3), ['Eject', 'Eject', 'Eject'], 'create repeated order') -"""Creates an empty list for use with the empty test. -""" +# Creates an empty list for use with the empty test. def get_empty_list(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults return [] -"""Tests the "is empty" block. -""" +# Tests the "is empty" block. def test_lists_empty(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(not len([0]), False, 'not empty') @@ -861,8 +810,7 @@ def test_lists_empty(): assertEquals(not len(get_empty_list()), True, 'empty complex') assertEquals(not len([] if True else None), True, 'empty order') -"""Tests the "length" block. -""" +# Tests the "length" block. def test_lists_length(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(len([]), 0, 'zero length') @@ -875,8 +823,7 @@ def last_index(my_list, elem): except: index = 0 return index -"""Tests the "find" block with a variable. -""" +# Tests the "find" block with a variable. def test_find_lists_simple(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Alice', 'Eve', 'Bob', 'Eve'] @@ -884,15 +831,13 @@ def test_find_lists_simple(): assertEquals(last_index(list2, 'Eve'), 4, 'find last simple') assertEquals(first_index(list2, 'Dave'), 0, 'find none simple') -"""Creates a list for use with the find test. -""" +# Creates a list for use with the find test. def get_names(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = (number_of_calls if isinstance(number_of_calls, Number) else 0) + 1 return ['Alice', 'Eve', 'Bob', 'Eve'] -"""Tests the "find" block with a function call. -""" +# Tests the "find" block with a function call. def test_find_lists_complex(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = 0 @@ -914,8 +859,7 @@ def test_find_lists_complex(): assertEquals(first_index(get_names() if True else None, 'Dave'), 0, 'find none order complex') check_number_of_calls('find none order complex') -"""Tests the "get" block with a variable. -""" +# Tests the "get" block with a variable. def test_get_lists_simple(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Kirk', 'Spock', 'McCoy'] @@ -928,15 +872,13 @@ def test_get_lists_simple(): # The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index. assertEquals(list2[-int(0 + 3)], 'Kirk', 'get #-end order simple') -"""Creates a list for use with the get test. -""" +# Creates a list for use with the get test. def get_star_wars(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = (number_of_calls if isinstance(number_of_calls, Number) else 0) + 1 return ['Kirk', 'Spock', 'McCoy'] -"""Tests the "get" block with a function call. -""" +# Tests the "get" block with a function call. def test_get_lists_complex(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Kirk', 'Spock', 'McCoy'] @@ -976,8 +918,7 @@ def lists_remove_random_item(myList): x = int(random.random() * len(myList)) return myList.pop(x) -"""Tests the "get and remove" block. -""" +# Tests the "get and remove" block. def test_getRemove(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Kirk', 'Spock', 'McCoy'] @@ -1012,8 +953,7 @@ def test_getRemove(): assertEquals((list2 if True else None).pop(-int(0 + 3)), 'Kirk', 'getremove #-end order') assertEquals(list2, ['Spock', 'McCoy'], 'getremove #-end order list') -"""Tests the "remove" block. -""" +# Tests the "remove" block. def test_remove(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Kirk', 'Spock', 'McCoy'] @@ -1049,8 +989,7 @@ def test_remove(): (list2 if True else None).pop(-int(0 + 3)) assertEquals(list2, ['Spock', 'McCoy'], 'remove #-end order list') -"""Tests the "set" block. -""" +# Tests the "set" block. def test_set(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Picard', 'Riker', 'Crusher'] @@ -1089,8 +1028,7 @@ def test_set(): (list2 if True else None)[-int(0 + 2)] = 'Pulaski' assertEquals(list2, ['Picard', 'Pulaski', 'Crusher'], 'set #-end order list') -"""Tests the "insert" block. -""" +# Tests the "insert" block. def test_insert(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Picard', 'Riker', 'Crusher'] @@ -1129,8 +1067,7 @@ def test_insert(): (list2 if True else None).insert(-int(0 + 2), 'Data') assertEquals(list2, ['Picard', 'Data', 'Riker', 'Crusher'], 'insert #-end order list') -"""Tests the "get sub-list" block with a variable. -""" +# Tests the "get sub-list" block with a variable. def test_sublist_simple(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour'] @@ -1155,15 +1092,13 @@ def test_sublist_simple(): # Checks that the whole list is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where sublist uses [x:length - y] for # #-end. assertEquals(list2[int((0 + 1) - 1) : -int((0 + 1) - 1) or sys.maxsize], list2, 'sublist all with # #-end math simple') -"""Creates a list for use with the sublist test. -""" +# Creates a list for use with the sublist test. def get_space_shuttles(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = (number_of_calls if isinstance(number_of_calls, Number) else 0) + 1 return ['Columbia', 'Challenger', 'Discovery', 'Atlantis', 'Endeavour'] -"""Tests the "get sub-list" block with a function call. -""" +# Tests the "get sub-list" block with a function call. def test_sublist_complex(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults number_of_calls = 0 @@ -1211,16 +1146,14 @@ def test_sublist_complex(): assertEquals(get_space_shuttles()[int((0 + 1) - 1) : -int((0 + 1) - 1) or sys.maxsize], list2, 'sublist all with # #-end math complex') check_number_of_calls('sublist all with # #-end math complex') -"""Tests the "join" block. -""" +# Tests the "join" block. def test_join(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Vulcan', 'Klingon', 'Borg'] assertEquals(','.join(list2), 'Vulcan,Klingon,Borg', 'join') assertEquals(','.join(list2 if True else None), 'Vulcan,Klingon,Borg', 'join order') -"""Tests the "split" block. -""" +# Tests the "split" block. def test_split(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults text = 'Vulcan,Klingon,Borg' @@ -1242,32 +1175,28 @@ def lists_sort(my_list, type, reverse): list_cpy = list(my_list) return sorted(list_cpy, key=key_func, reverse=reverse) -"""Tests the "alphabetic sort" block. -""" +# Tests the "alphabetic sort" block. def test_sort_alphabetic(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Vulcan', 'klingon', 'Borg'] assertEquals(lists_sort(list2, "TEXT", False), ['Borg', 'Vulcan', 'klingon'], 'sort alphabetic ascending') assertEquals(lists_sort(list2 if True else None, "TEXT", False), ['Borg', 'Vulcan', 'klingon'], 'sort alphabetic ascending order') -"""Tests the "alphabetic sort ignore case" block. -""" +# Tests the "alphabetic sort ignore case" block. def test_sort_ignoreCase(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = ['Vulcan', 'klingon', 'Borg'] assertEquals(lists_sort(list2, "IGNORE_CASE", False), ['Borg', 'klingon', 'Vulcan'], 'sort ignore case ascending') assertEquals(lists_sort(list2 if True else None, "IGNORE_CASE", False), ['Borg', 'klingon', 'Vulcan'], 'sort ignore case ascending order') -"""Tests the "numeric sort" block. -""" +# Tests the "numeric sort" block. def test_sort_numeric(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = [8, 18, -1] assertEquals(lists_sort(list2, "NUMERIC", True), [18, 8, -1], 'sort numeric descending') assertEquals(lists_sort(list2 if True else None, "NUMERIC", True), [18, 8, -1], 'sort numeric descending order') -"""Tests the "list reverse" block. -""" +# Tests the "list reverse" block. def test_lists_reverse(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults list2 = [8, 18, -1, 64] @@ -1276,8 +1205,7 @@ def test_lists_reverse(): list2 = [] assertEquals(list(reversed(list2)), [], 'empty list') -"""Describe this function... -""" +# Describe this function... def test_colour_picker(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals('#ff6600', '#ff6600', 'static colour') @@ -1288,14 +1216,12 @@ def colour_rgb(r, g, b): b = round(min(100, max(0, b)) * 2.55) return '#%02x%02x%02x' % (r, g, b) -"""Describe this function... -""" +# Describe this function... def test_rgb(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(colour_rgb(100, 40, 0), '#ff6600', 'from rgb') -"""Describe this function... -""" +# Describe this function... def test_colour_random(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults for count4 in range(100): @@ -1315,14 +1241,12 @@ def colour_blend(colour1, colour2, ratio): b = round(b1 * (1 - ratio) + b2 * ratio) return '#%02x%02x%02x' % (r, g, b) -"""Describe this function... -""" +# Describe this function... def test_blend(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(colour_blend('#ff0000', colour_rgb(100, 40, 0), 0.4), '#ff2900', 'blend') -"""Describe this function... -""" +# Describe this function... def test_procedure(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults procedure_1(8, 2) @@ -1334,22 +1258,19 @@ def test_procedure(): procedure_2(True) assertEquals(proc_w, False, 'procedure return') -"""Describe this function... -""" +# Describe this function... def procedure_1(proc_x, proc_y): global test_name, naked, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults proc_z = proc_x / proc_y -"""Describe this function... -""" +# Describe this function... def procedure_2(proc_x): global test_name, naked, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults if proc_x: return proc_w = True -"""Describe this function... -""" +# Describe this function... def test_function(): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults assertEquals(function_1(2, 3), -1, 'function with arguments') @@ -1361,30 +1282,26 @@ def test_function(): assertEquals(function_3(True), True, 'function return') assertEquals(function_3(False), False, 'function no return') -"""Describe this function... -""" +# Describe this function... def function_1(func_x, func_y): global test_name, naked, proc_x, proc_y, func_a, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults func_z = 'side effect' return func_x - func_y -"""Describe this function... -""" +# Describe this function... def function_2(func_a): global test_name, naked, proc_x, proc_y, func_x, func_y, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults func_a = (func_a if isinstance(func_a, Number) else 0) + 1 return str(func_a) + str(func_c) -"""Describe this function... -""" +# Describe this function... def function_3(func_a): global test_name, naked, proc_x, proc_y, func_x, func_y, n, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults if func_a: return True return False -"""Describe this function... -""" +# Describe this function... def recurse(n): global test_name, naked, proc_x, proc_y, func_x, func_y, func_a, ok, log, count, varToChange, rand, item, text, number_of_calls, list2, proc_z, func_z, x, proc_w, func_c, if2, i, loglist, changing_list, list_copy, unittestResults if n > 0: From e11c7b04887feecdb0b84a06400a31f0b7c3b67f Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 14 Oct 2019 14:02:43 -0600 Subject: [PATCH 034/343] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 20f3e4789..9ba3270c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "2.20190722.0-develop", + "version": "3.20191014.0-develop", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" From 8eb003f01f45ae2a5dbfaf4f0057a0041ca257b5 Mon Sep 17 00:00:00 2001 From: Noah Glaser Date: Mon, 14 Oct 2019 22:53:15 -0700 Subject: [PATCH 035/343] Fix capitolization error --- demos/blockfactory/factory_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/blockfactory/factory_utils.js b/demos/blockfactory/factory_utils.js index 048760567..dfed4578e 100644 --- a/demos/blockfactory/factory_utils.js +++ b/demos/blockfactory/factory_utils.js @@ -490,7 +490,7 @@ FactoryUtils.getFieldsJs_ = function(block) { var width = Number(block.getFieldValue('WIDTH')); var height = Number(block.getFieldValue('HEIGHT')); var alt = JSON.stringify(block.getFieldValue('ALT')); - var flipRtl = Json.stringify(block.getFieldValue('FLIP_RTL')); + var flipRtl = JSON.stringify(block.getFieldValue('FLIP_RTL')); fields.push('new Blockly.FieldImage(' + src + ', ' + width + ', ' + height + ', { alt: ' + alt + ', flipRtl: ' + flipRtl + ' })'); From b913295028bc0f1ec0986af4dd8c33e70298e922 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Tue, 15 Oct 2019 09:01:03 -0700 Subject: [PATCH 036/343] restart cursor animation on cursor move (#3226) --- core/keyboard_nav/cursor_svg.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index 0c33aa8a7..3fef7338c 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -511,6 +511,12 @@ Blockly.CursorSvg.prototype.draw = function(curNode) { } else if (curNode.getType() === Blockly.ASTNode.types.STACK) { this.showWithStack_(curNode); } + + // Ensures the cursor will be visible immediately after the move. + var animate = this.currentCursorSvg.childNodes[0]; + if (animate !== undefined) { + animate.beginElement && animate.beginElement(); + } }; /** From ef859d351d6dc5106694d8cacdad2c88b60d9581 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Tue, 15 Oct 2019 09:28:37 -0700 Subject: [PATCH 037/343] Fix jsdoc syntax (#3246) --- core/components/component.js | 21 ++++++++---- core/components/tree/basenode.js | 50 ++++++++++++++++++++++------- core/components/tree/treecontrol.js | 3 +- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/core/components/component.js b/core/components/component.js index f64e161aa..82507405c 100644 --- a/core/components/component.js +++ b/core/components/component.js @@ -40,7 +40,8 @@ Blockly.Component = function() { /** * Whether the component is rendered right-to-left. - * @private {boolean} + * @type {boolean} + * @private */ this.rightToLeft_ = Blockly.Component.defaultRightToLeft; @@ -48,26 +49,30 @@ Blockly.Component = function() { * Unique ID of the component, lazily initialized in {@link * Blockly.Component#getId} if needed. This property is strictly private and * must not be accessed directly outside of this class! - * @private {?string} + * @type {?string} + * @private */ this.id_ = null; /** * Whether the component is in the document. - * @private {boolean} + * @type {boolean} + * @private */ this.inDocument_ = false; /** * The DOM element for the component. - * @private {?Element} + * @type {?Element} + * @private */ this.element_ = null; /** * Parent component to which events will be propagated. This property is * strictly private and must not be accessed directly outside of this class! - * @private {?Blockly.Component} + * @type {?Blockly.Component} + * @private */ this.parent_ = null; @@ -75,7 +80,8 @@ Blockly.Component = function() { * Array of child components. * Must be kept in sync with `childIndex_`. This property is strictly * private and must not be accessed directly outside of this class! - * @private {?Array.} + * @type {?Array.} + * @private */ this.children_ = []; @@ -85,7 +91,8 @@ Blockly.Component = function() { * Must be kept in sync with `children_`. This property is strictly * private and must not be accessed directly outside of this class! * - * @private {?Object} + * @type {?Object} + * @private */ this.childIndex_ = {}; }; diff --git a/core/components/tree/basenode.js b/core/components/tree/basenode.js index f1e846c82..9127dbe32 100644 --- a/core/components/tree/basenode.js +++ b/core/components/tree/basenode.js @@ -58,55 +58,81 @@ Blockly.tree.BaseNode = function(content, config) { */ this.content_ = content; - /** @private {string} */ + /** + * @type {string} + * @private + */ this.iconClass_; - /** @private {string} */ + /** + * @type {string} + * @private + */ this.expandedIconClass_; - /** @protected {Blockly.tree.TreeControl} */ + /** + * @type {Blockly.tree.TreeControl} + * @protected + */ this.tree; - /** @private {Blockly.tree.BaseNode} */ + /** + * @type {Blockly.tree.BaseNode} + * @private + */ this.previousSibling_; - /** @private {Blockly.tree.BaseNode} */ + /** + * @type {Blockly.tree.BaseNode} + * @private + */ this.nextSibling_; - /** @private {Blockly.tree.BaseNode} */ + /** + * @type {Blockly.tree.BaseNode} + * @private + */ this.firstChild_; - /** @private {Blockly.tree.BaseNode} */ + /** + * @type {Blockly.tree.BaseNode} + * @private + */ this.lastChild_; /** * Whether the tree item is selected. - * @private {boolean} + * @type {boolean} + * @private */ this.selected_ = false; /** * Whether the tree node is expanded. - * @private {boolean} + * @type {boolean} + * @private */ this.expanded_ = false; /** * Tooltip for the tree item - * @private {?string} + * @type {?string} + * @private */ this.toolTip_ = null; /** * Whether to allow user to collapse this node. - * @private {boolean} + * @type {boolean} + * @private */ this.isUserCollapsible_ = true; /** * Nesting depth of this node; cached result of computeDepth_. * -1 if value has not been cached. - * @private {number} + * @type {number} + * @private */ this.depth_ = -1; }; diff --git a/core/components/tree/treecontrol.js b/core/components/tree/treecontrol.js index cfd0b01cf..7e9a58659 100644 --- a/core/components/tree/treecontrol.js +++ b/core/components/tree/treecontrol.js @@ -52,7 +52,8 @@ Blockly.tree.TreeControl = function(toolbox, config) { /** * Currently selected item. - * @private {Blockly.tree.BaseNode} + * @type {Blockly.tree.BaseNode} + * @private */ this.selectedItem_ = this; }; From a9420154a253de7056b2459bbc457f2107a59aa1 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Tue, 15 Oct 2019 10:14:39 -0700 Subject: [PATCH 038/343] Update todos so they are no longer in jsdocs (#3250) (#3257) --- core/block_svg.js | 8 ++++---- core/gesture.js | 2 +- core/icon.js | 2 +- core/renderers/common/info.js | 1 + core/renderers/measurables/rows.js | 1 + 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 1ebaa5388..9bc5a35a8 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -187,34 +187,34 @@ Blockly.BlockSvg.COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_'; // Leftover UI constants from block_render_svg.js. /** * Vertical space between elements. - * TODO (#3142): Remove. * @const * @package */ +// TODO (#3142): Remove. Blockly.BlockSvg.SEP_SPACE_Y = 10; /** * Minimum height of a block. - * TODO (#3142): Remove. * @const * @package */ +// TODO (#3142): Remove. Blockly.BlockSvg.MIN_BLOCK_Y = 25; /** * Width of horizontal puzzle tab. - * TODO (#3142): Remove. * @const * @package */ +// TODO (#3142): Remove. Blockly.BlockSvg.TAB_WIDTH = 8; /** * Do blocks with no previous or output connections have a 'hat' on top? - * TODO (#3142): Remove. * @const * @package */ +// TODO (#3142): Remove. Blockly.BlockSvg.START_HAT = false; /** diff --git a/core/gesture.js b/core/gesture.js index e8c81b034..ba80a8fdc 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -446,9 +446,9 @@ Blockly.Gesture.prototype.startDraggingBlock_ = function() { /** * Create a bubble dragger and start dragging the selected bubble. - * TODO (fenichel): Possibly combine this and startDraggingBlock_. * @private */ +// TODO (fenichel): Possibly combine this and startDraggingBlock_. Blockly.Gesture.prototype.startDraggingBubble_ = function() { this.bubbleDragger_ = new Blockly.BubbleDragger(this.startBubble_, this.startWorkspace_); diff --git a/core/icon.js b/core/icon.js index 084df886c..cd76e888c 100644 --- a/core/icon.js +++ b/core/icon.js @@ -185,9 +185,9 @@ Blockly.Icon.prototype.getIconLocation = function() { * Get the size of the icon as used for rendering. * This differs from the actual size of the icon, because it bulges slightly * out of its row rather than increasing the height of its row. - * TODO (#2562): Remove getCorrectedSize. * @return {!Blockly.utils.Size} Height and width. */ +// TODO (#2562): Remove getCorrectedSize. Blockly.Icon.prototype.getCorrectedSize = function() { return new Blockly.utils.Size( Blockly.Icon.prototype.SIZE, Blockly.Icon.prototype.SIZE - 2); diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index ce8ca9418..6f978889e 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -459,6 +459,7 @@ Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, ne * should be placed. * @protected */ +// TODO: More cleanup. Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() { var widestStatementRowFields = 0; var blockWidth = 0; diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index 141ceb08a..7b85ae0f0 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -170,6 +170,7 @@ Blockly.blockRendering.Row.prototype.measure = function() { * or null. * @package */ +// TODO: Consider moving this to InputRow, if possible. Blockly.blockRendering.Row.prototype.getLastInput = function() { for (var i = this.elements.length - 1, elem; (elem = this.elements[i]); i--) { if (Blockly.blockRendering.Types.isInput(elem)) { From b2a81727207278b8dbd6ff284072fdce4e885444 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 15 Oct 2019 07:14:38 -0700 Subject: [PATCH 039/343] Fixed disabled blocks in trashcan. --- core/trashcan.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/trashcan.js b/core/trashcan.js index 24c845742..6f45f130b 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -287,11 +287,6 @@ Blockly.Trashcan.prototype.init = function(verticalSpacing) { Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), this.workspace_.getParentSvg()); this.flyout_.init(this.workspace_); - this.flyout_.isBlockCreatable_ = function() { - // All blocks, including disabled ones, can be dragged from the - // trashcan flyout. - return true; - }; } this.verticalSpacing_ = this.MARGIN_BOTTOM_ + verticalSpacing; @@ -501,6 +496,7 @@ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { node.removeAttribute('x'); node.removeAttribute('y'); node.removeAttribute('id'); + node.removeAttribute('disabled'); } // Try to go down the tree From 8f73fdb512851819ed2734c42e5f8427da54bcf2 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 15 Oct 2019 07:22:57 -0700 Subject: [PATCH 040/343] Fixed comments in trashcan. --- core/trashcan.js | 5 +++++ tests/mocha/trashcan_test.js | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/trashcan.js b/core/trashcan.js index 6f45f130b..a452d2004 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -497,6 +497,11 @@ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { node.removeAttribute('y'); node.removeAttribute('id'); node.removeAttribute('disabled'); + if (node.nodeName == 'comment') { // Future proof just in case. + node.removeAttribute('h'); + node.removeAttribute('w'); + node.removeAttribute('pinned'); + } } // Try to go down the tree diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js index c2e8584f5..992e2cd91 100644 --- a/tests/mocha/trashcan_test.js +++ b/tests/mocha/trashcan_test.js @@ -102,7 +102,9 @@ suite("Trashcan", function() { test("No Disabled - Disabled True", function() { sendDeleteEvent(''); sendDeleteEvent(''); - chai.assert.equal(this.trashcan.contents_.length, 2); + // Disabled tags get removed because disabled blocks aren't allowed to + // be dragged from flyouts. See #2239 and #3243. + chai.assert.equal(this.trashcan.contents_.length, 1); }); test("No Editable - Editable False", function() { sendDeleteEvent(''); @@ -244,9 +246,8 @@ suite("Trashcan", function() { ' comment_text' + '' ); - // TODO (#2574): These blocks are treated as different, but appear - // identical when the trashcan is opened. - chai.assert.equal(this.trashcan.contents_.length, 2); + // h & w tags are removed b/c the blocks appear the same. + chai.assert.equal(this.trashcan.contents_.length, 1); }); test("Different Comment Pinned", function() { sendDeleteEvent( @@ -259,9 +260,8 @@ suite("Trashcan", function() { ' comment_text' + '' ); - // TODO (#2574): These blocks are treated as different, but appear - // identical when the trashcan is opened. - chai.assert.equal(this.trashcan.contents_.length, 2); + // pinned tags are removed b/c the blocks appear the same. + chai.assert.equal(this.trashcan.contents_.length, 1); }); test("No Mutator - Mutator", function() { sendDeleteEvent(''); From 07d6f33db9b09e22368fd0f5f07f0759c912d984 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 15 Oct 2019 15:05:50 -0600 Subject: [PATCH 041/343] Rebuild task in gulp. --- gulpfile.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/gulpfile.js b/gulpfile.js index f4959161e..752430613 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -770,3 +770,51 @@ gulp.task('release', gulp.series(['build', 'typings', function() { // The default task builds Blockly. gulp.task('default', gulp.series(['build'])); + +// Stash current state, check out develop, and sync with google/blockly. +gulp.task('syncDevelop', function(done) { + execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); + execSync('git checkout develop', { stdio: 'inherit' }); + execSync('git pull https://github.com/google/blockly.git develop', + { stdio: 'inherit' }); + execSync('git push origin develop', { stdio: 'inherit' }); + done(); +}); + +// Helper function: get a name for a rebuild branch. Format: rebuild_mm_dd_yyyy. +function getRebuildBranchName() { + var date = new Date(); + var mm = date.getMonth() + 1; // Month, 0-11 + var dd = date.getDate(); // Day of the month, 1-31 + var yyyy = date.getFullYear(); + return 'rebuild_' + mm + '_' + dd + '_' + yyyy; +} + +// Stash and make a new branch for a rebuild. +gulp.task('make-rebuild-branch', function(done) { + execSync('git stash save -m "Stash for rebuild"', { stdio: 'inherit' }); + var branchName = getRebuildBranchName(); + console.log('make-rebuild-branch: creating branch ' + branchName); + execSync('git checkout -b ' + branchName, { stdio: 'inherit' }); + done(); +}); + +// Commit and push the current rebuild branch. +gulp.task('push-rebuild-branch', function(done) { + console.log('push-rebuild-branch: committing rebuild'); + execSync('git commit -am "Rebuild"', { stdio: 'inherit' }); + var branchName = getRebuildBranchName(); + execSync('git push origin ' + branchName, { stdio: 'inherit' }); + console.log('Branch ' + branchName + ' pushed to GitHub.'); + console.log('Next step: create a pull request against develop.'); + done(); +}); + +// Recompile and push to origin. +gulp.task('recompile', gulp.series[ + 'syncDevelop', + 'make-rebuild-branch' + 'build', + 'push-rebuild-branch' + ] +); From e411077b9f2767f74ced855de5101b23bf1168a6 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 15 Oct 2019 17:36:33 -0500 Subject: [PATCH 042/343] Fix blocks tests (#3252) --- tests/blocks/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/blocks/index.html b/tests/blocks/index.html index fa5e6cbf2..3187af9d2 100644 --- a/tests/blocks/index.html +++ b/tests/blocks/index.html @@ -3,7 +3,7 @@ Unit Tests for Blockly Blocks - + From 2224bb2a4efda53d3c4f6b12c21baf11a3155273 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 15 Oct 2019 17:56:53 -0500 Subject: [PATCH 043/343] More field dispose (#3201) * Dispose of element references in fields. * Fewer warnings --- core/blockly.js | 11 ++++- core/components/component.js | 2 +- core/field.js | 95 +++++++++++++++++++++++++++--------- core/field_angle.js | 45 +++++++++++++++-- core/field_colour.js | 84 ++++++++++++++++++++++++++----- core/field_dropdown.js | 63 ++++++++++++++++-------- core/field_image.js | 26 ++++++---- core/field_multilineinput.js | 27 ++++++---- core/field_textinput.js | 37 +++++++++++--- core/field_variable.js | 3 +- 10 files changed, 308 insertions(+), 85 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index e4e8203c0..c56224ba3 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -113,6 +113,13 @@ Blockly.clipboardTypeCounts_ = null; */ Blockly.cache3dSupported_ = null; +/** + * Blockly opaque event data used to unbind events when using + * `Blockly.bindEvent_` and `Blockly.bindEventWithChecks_`. + * @typedef {!Array.} + */ +Blockly.EventData; + /** * Returns the dimensions of the specified SVG image. * @param {!Element} svg SVG image. @@ -455,7 +462,7 @@ Blockly.defineBlocksWithJsonArray = function(jsonArray) { * should prevent the default handler. False by default. If * opt_noPreventDefault is provided, opt_noCaptureIdentifier must also be * provided. - * @return {!Array.} Opaque data that can be passed to unbindEvent_. + * @return {!Blockly.EventData} Opaque data that can be passed to unbindEvent_. */ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, opt_noCaptureIdentifier, opt_noPreventDefault) { @@ -521,7 +528,7 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, * @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 {!Array.} Opaque data that can be passed to unbindEvent_. + * @return {!Blockly.EventData} Opaque data that can be passed to unbindEvent_. */ Blockly.bindEvent_ = function(node, name, thisObject, func) { var wrapFunc = function(e) { diff --git a/core/components/component.js b/core/components/component.js index 82507405c..86e55fab8 100644 --- a/core/components/component.js +++ b/core/components/component.js @@ -339,7 +339,7 @@ Blockly.Component.prototype.exitDocument = function() { /** * Disposes of the object. If the object hasn't already been disposed of, calls * {@link #disposeInternal}. - * @protected + * @package */ Blockly.Component.prototype.dispose = function() { if (!this.disposed_) { diff --git a/core/field.js b/core/field.js index a9d7b919c..ee88f82f7 100644 --- a/core/field.js +++ b/core/field.js @@ -94,6 +94,41 @@ Blockly.Field = function(value, opt_validator, opt_config) { */ this.markerSvg_ = null; + /** + * The rendered field's SVG group element. + * @type {SVGGElement} + * @protected + */ + this.fieldGroup_ = null; + + /** + * The rendered field's SVG border element. + * @type {SVGRectElement} + * @protected + */ + this.borderRect_ = null; + + /** + * The rendered field's SVG text element. + * @type {SVGTextElement} + * @protected + */ + this.textElement_ = null; + + /** + * The rendered field's text content element. + * @type {Text} + * @protected + */ + this.textContent_ = null; + + /** + * Mouse down event listener data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseDownWrapper_ = null; + opt_config && this.configure_(opt_config); this.setValue(value); opt_validator && this.setValidator(opt_validator); @@ -186,11 +221,21 @@ Blockly.Field.prototype.clickTarget_ = null; * A developer hook to override the returned text of this field. * Override if the text representation of the value of this field * is not just a string cast of its value. + * Return null to resort to a string cast. * @return {?string} Current text. Return null to resort to a string cast. * @protected */ Blockly.Field.prototype.getText_; +/** + * An optional method that can be defined to show an editor when the field is + * clicked. Blockly will automatically set the field as clickable if this + * method is defined. + * @return {void} + * @protected + */ +Blockly.Field.prototype.showEditor_; + /** * Non-breaking space. * @const @@ -260,11 +305,13 @@ Blockly.Field.prototype.init = function() { // Field has already been initialized once. return; } - this.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + this.fieldGroup_ = /** @type {!SVGGElement} **/ + (Blockly.utils.dom.createSvgElement('g', {}, null)); if (!this.isVisible()) { this.fieldGroup_.style.display = 'none'; } - this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); + var sourceBlockSvg = /** @type {!Blockly.BlockSvg} **/ (this.sourceBlock_); + sourceBlockSvg.getSvgRoot().appendChild(this.fieldGroup_); this.initView(); this.updateEditable(); this.setTooltip(this.tooltip_); @@ -300,15 +347,16 @@ Blockly.Field.prototype.createBorderRect_ = function() { Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT); this.size_.width = Math.max(this.size_.width, Blockly.Field.X_PADDING); - this.borderRect_ = Blockly.utils.dom.createSvgElement('rect', - { - 'rx': 4, - 'ry': 4, - 'x': 0, - 'y': 0, - 'height': this.size_.height, - 'width': this.size_.width - }, this.fieldGroup_); + this.borderRect_ = /** @type {!SVGRectElement} **/ + (Blockly.utils.dom.createSvgElement('rect', + { + 'rx': 4, + 'ry': 4, + 'x': 0, + 'y': 0, + 'height': this.size_.height, + 'width': this.size_.width + }, this.fieldGroup_)); }; /** @@ -319,13 +367,14 @@ Blockly.Field.prototype.createBorderRect_ = function() { */ Blockly.Field.prototype.createTextElement_ = function() { var xOffset = this.borderRect_ ? Blockly.Field.DEFAULT_TEXT_OFFSET : 0; - this.textElement_ = Blockly.utils.dom.createSvgElement('text', - { - 'class': 'blocklyText', - // The y position is the baseline of the text. - 'y': Blockly.Field.TEXT_DEFAULT_HEIGHT, - 'x': xOffset - }, this.fieldGroup_); + this.textElement_ = /** @type {!SVGTextElement} **/ + (Blockly.utils.dom.createSvgElement('text', + { + 'class': 'blocklyText', + // The y position is the baseline of the text. + 'y': Blockly.Field.TEXT_DEFAULT_HEIGHT, + 'x': xOffset + }, this.fieldGroup_)); this.textContent_ = document.createTextNode(''); this.textElement_.appendChild(this.textContent_); }; @@ -534,10 +583,10 @@ Blockly.Field.prototype.callValidator = function(text) { /** * Gets the group element for this editable field. * Used for measuring the size and for positioning. - * @return {!SVGElement} The group element. + * @return {!SVGGElement} The group element. */ Blockly.Field.prototype.getSvgRoot = function() { - return /** @type {!SVGElement} */ (this.fieldGroup_); + return /** @type {!SVGGElement} */ (this.fieldGroup_); }; /** @@ -582,7 +631,8 @@ Blockly.Field.prototype.updateWidth = function() { * @protected */ Blockly.Field.prototype.updateSize_ = function() { - var textWidth = Blockly.utils.dom.getTextWidth(this.textElement_); + var textWidth = Blockly.utils.dom.getTextWidth( + /** @type {!SVGTextElement} */ (this.textElement_)); var totalWidth = textWidth; if (this.borderRect_) { totalWidth += Blockly.Field.X_PADDING; @@ -881,7 +931,8 @@ Blockly.Field.prototype.getClickTarget_ = function() { * @private */ Blockly.Field.prototype.getAbsoluteXY_ = function() { - return Blockly.utils.style.getPageOffset(this.borderRect_); + return Blockly.utils.style.getPageOffset( + /** @type {!SVGRectElement} */ (this.borderRect_)); }; /** diff --git a/core/field_angle.js b/core/field_angle.js index 415662a08..b7002a495 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -83,6 +83,39 @@ Blockly.FieldAngle = function(opt_value, opt_validator, opt_config) { Blockly.FieldAngle.superClass_.constructor.call( this, opt_value || 0, opt_validator, opt_config); + + /** + * The angle picker's gauge path depending on the value. + * @type {SVGElement} + */ + this.gauge_ = null; + + /** + * The angle picker's line drawn representing the value's angle. + * @type {SVGElement} + */ + this.line_ = null; + + /** + * Wrapper click event data. + * @type {?Blockly.EventData} + * @private + */ + this.clickWrapper_ = null; + + /** + * Surface click event data. + * @type {?Blockly.EventData} + * @private + */ + this.clickSurfaceWrapper_ = null; + + /** + * Surface mouse move event data. + * @type {?Blockly.EventData} + * @private + */ + this.moveSurfaceWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.FieldAngle, Blockly.FieldTextInput); @@ -309,9 +342,15 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { * @private */ Blockly.FieldAngle.prototype.dropdownDispose_ = function() { - Blockly.unbindEvent_(this.clickWrapper_); - Blockly.unbindEvent_(this.clickSurfaceWrapper_); - Blockly.unbindEvent_(this.moveSurfaceWrapper_); + if (this.clickWrapper_) { + Blockly.unbindEvent_(this.clickWrapper_); + } + if (this.clickSurfaceWrapper_) { + Blockly.unbindEvent_(this.clickSurfaceWrapper_); + } + if (this.moveSurfaceWrapper_) { + Blockly.unbindEvent_(this.moveSurfaceWrapper_); + } this.gauge_ = null; this.line_ = null; }; diff --git a/core/field_colour.js b/core/field_colour.js index abc481243..2e6913a68 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -65,6 +65,55 @@ Blockly.FieldColour = function(opt_value, opt_validator, opt_config) { */ this.size_ = new Blockly.utils.Size(Blockly.FieldColour.DEFAULT_WIDTH, Blockly.FieldColour.DEFAULT_HEIGHT); + + /** + * The field's colour picker element. + * @type {Element} + * @private + */ + this.picker_ = null; + + /** + * Index of the currently highlighted element. + * @type {?number} + * @private + */ + this.highlightedIndex_ = null; + + /** + * Mouse click event data. + * @type {?Blockly.EventData} + * @private + */ + this.onClickWrapper_ = null; + + /** + * Mouse move event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseMoveWrapper_ = null; + + /** + * Mouse enter event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseEnterWrapper_ = null; + + /** + * Mouse leave event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseLeaveWrapper_ = null; + + /** + * Key down event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeyDownWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.FieldColour, Blockly.Field); @@ -160,7 +209,7 @@ Blockly.FieldColour.prototype.configure_ = function(config) { */ Blockly.FieldColour.prototype.initView = function() { this.createBorderRect_(); - this.borderRect_.style['fillOpacity'] = 1; + this.borderRect_.style['fillOpacity'] = '1'; this.borderRect_.style.fill = this.value_; }; @@ -415,7 +464,7 @@ Blockly.FieldColour.prototype.moveHighlightBy_ = function(dx, dy) { } // Move the highlight to the new coordinates. - var cell = this.picker_.childNodes[y].childNodes[x]; + var cell = /** @type {!Element} */ (this.picker_.childNodes[y].childNodes[x]); var index = (y * columns) + x; this.setHighlightedCell_(cell, index); }; @@ -427,9 +476,9 @@ Blockly.FieldColour.prototype.moveHighlightBy_ = function(dx, dy) { */ Blockly.FieldColour.prototype.onMouseMove_ = function(e) { var cell = /** @type {!Element} */ (e.target); - var index = cell && cell.getAttribute('data-index'); + var index = cell && Number(cell.getAttribute('data-index')); if (index !== null && index !== this.highlightedIndex_) { - this.setHighlightedCell_(cell, Number(index)); + this.setHighlightedCell_(cell, index); } }; @@ -456,7 +505,7 @@ Blockly.FieldColour.prototype.onMouseLeave_ = function() { /** * Returns the currently highlighted item (if any). - * @return {Element} Highlighted item (null if none). + * @return {HTMLElement} Highlighted item (null if none). * @private */ Blockly.FieldColour.prototype.getHighlighted_ = function() { @@ -467,7 +516,7 @@ Blockly.FieldColour.prototype.getHighlighted_ = function() { if (!row) { return null; } - var col = row.childNodes[x]; + var col = /** @type {HTMLElement} */ (row.childNodes[x]); return col; }; @@ -489,7 +538,7 @@ Blockly.FieldColour.prototype.setHighlightedCell_ = function(cell, index) { this.highlightedIndex_ = index; // Update accessibility roles. - Blockly.utils.aria.setState(this.picker_, + Blockly.utils.aria.setState(/** @type {!Element} */ (this.picker_), Blockly.utils.aria.State.ACTIVEDESCENDANT, cell.getAttribute('id')); }; @@ -560,12 +609,23 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { * @private */ Blockly.FieldColour.prototype.dropdownDispose_ = function() { - Blockly.unbindEvent_(this.onClickWrapper_); - Blockly.unbindEvent_(this.onMouseMoveWrapper_); - Blockly.unbindEvent_(this.onMouseEnterWrapper_); - Blockly.unbindEvent_(this.onMouseLeaveWrapper_); - Blockly.unbindEvent_(this.onKeyDownWrapper_); + if (this.onClickWrapper_) { + Blockly.unbindEvent_(this.onClickWrapper_); + } + if (this.onMouseMoveWrapper_) { + Blockly.unbindEvent_(this.onMouseMoveWrapper_); + } + if (this.onMouseEnterWrapper_) { + Blockly.unbindEvent_(this.onMouseEnterWrapper_); + } + if (this.onMouseLeaveWrapper_) { + Blockly.unbindEvent_(this.onMouseLeaveWrapper_); + } + if (this.onKeyDownWrapper_) { + Blockly.unbindEvent_(this.onKeyDownWrapper_); + } this.picker_ = null; + this.highlightedIndex_ = null; }; /** diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 238eb7f07..d01a89c1a 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -91,19 +91,33 @@ Blockly.FieldDropdown = function(menuGenerator, opt_validator, opt_config) { Blockly.FieldDropdown.superClass_.constructor.call( this, firstTuple[1], opt_validator, opt_config); - /** - * SVG image element if currently selected option is an image, or null. - * @type {SVGElement} - * @private - */ - this.imageElement_ = null; - /** * A reference to the currently selected menu item. * @type {Blockly.MenuItem} * @private */ this.selectedMenuItem_ = null; + + /** + * The dropdown menu. + * @type {Blockly.Menu} + * @private + */ + this.menu_ = null; + + /** + * SVG image element if currently selected option is an image, or null. + * @type {SVGImageElement} + * @private + */ + this.imageElement_ = null; + + /** + * SVG arrow element. + * @type {SVGTSpanElement} + * @private + */ + this.arrow_ = null; }; Blockly.utils.object.inherits(Blockly.FieldDropdown, Blockly.Field); @@ -182,12 +196,15 @@ Blockly.FieldDropdown.prototype.CURSOR = 'default'; Blockly.FieldDropdown.prototype.initView = function() { Blockly.FieldDropdown.superClass_.initView.call(this); - this.imageElement_ = Blockly.utils.dom.createSvgElement( 'image', - { - 'y': Blockly.FieldDropdown.IMAGE_Y_OFFSET - }, this.fieldGroup_); + this.imageElement_ = /** @type {!SVGImageElement} */ + (Blockly.utils.dom.createSvgElement('image', + { + 'y': Blockly.FieldDropdown.IMAGE_Y_OFFSET + }, this.fieldGroup_)); - this.arrow_ = Blockly.utils.dom.createSvgElement('tspan', {}, this.textElement_); + this.arrow_ = /** @type {!SVGTSpanElement} */ + (Blockly.utils.dom.createSvgElement('tspan', + {}, this.textElement_)); this.arrow_.appendChild(document.createTextNode( this.sourceBlock_.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : @@ -228,7 +245,7 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { /** * Create the dropdown editor. - * @return {Blockly.Menu} The newly created dropdown menu. + * @return {!Blockly.Menu} The newly created dropdown menu. * @private */ Blockly.FieldDropdown.prototype.dropdownCreate_ = function() { @@ -273,8 +290,11 @@ Blockly.FieldDropdown.prototype.dropdownCreate_ = function() { * @private */ Blockly.FieldDropdown.prototype.dropdownDispose_ = function() { - this.menu_.dispose(); + if (this.menu_) { + this.menu_.dispose(); + } this.menu_ = null; + this.selectedMenuItem_ = null; }; /** @@ -284,15 +304,16 @@ Blockly.FieldDropdown.prototype.dropdownDispose_ = function() { */ Blockly.FieldDropdown.prototype.handleMenuActionEvent_ = function(menuItem) { Blockly.DropDownDiv.hideIfOwner(this, true); - this.onItemSelected(this.menu_, menuItem); + this.onItemSelected_(/** @type {!Blockly.Menu} */ (this.menu_), menuItem); }; /** * Handle the selection of an item in the dropdown menu. * @param {!Blockly.Menu} menu The Menu component clicked. * @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu. + * @protected */ -Blockly.FieldDropdown.prototype.onItemSelected = function(menu, menuItem) { +Blockly.FieldDropdown.prototype.onItemSelected_ = function(menu, menuItem) { this.setValue(menuItem.getValue()); }; @@ -492,7 +513,8 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { this.imageElement_.setAttribute('height', imageJson.height); this.imageElement_.setAttribute('width', imageJson.width); - var arrowWidth = Blockly.utils.dom.getTextWidth(this.arrow_); + var arrowWidth = Blockly.utils.dom.getTextWidth( + /** @type {!SVGTSpanElement} */ (this.arrow_)); var imageHeight = Number(imageJson.height); var imageWidth = Number(imageJson.width); @@ -531,9 +553,9 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { }; /** - * Use the `getText_` developer hook to override the field's text representation. - * Get the selected option text. If the selected option is an image - * we return the image alt text. + * Use the `getText_` developer hook to override the field's text + * representation. Get the selected option text. If the selected option is an + * image we return the image alt text. * @return {?string} Selected option text. * @protected * @override @@ -611,4 +633,5 @@ Blockly.FieldDropdown.prototype.onBlocklyAction = function(action) { return Blockly.FieldDropdown.superClass_.onBlocklyAction.call(this, action); }; + Blockly.fieldRegistry.register('field_dropdown', Blockly.FieldDropdown); diff --git a/core/field_image.js b/core/field_image.js index cd7d0df10..fe699a867 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -115,6 +115,13 @@ Blockly.FieldImage = function(src, width, height, if (typeof opt_onClick == 'function') { this.clickHandler_ = opt_onClick; } + + /** + * The rendered field's image element. + * @type {SVGImageElement} + * @private + */ + this.imageElement_ = null; }; Blockly.utils.object.inherits(Blockly.FieldImage, Blockly.Field); @@ -173,14 +180,15 @@ Blockly.FieldImage.prototype.configure_ = function(config) { * @package */ Blockly.FieldImage.prototype.initView = function() { - this.imageElement_ = Blockly.utils.dom.createSvgElement( - 'image', - { - 'height': this.imageHeight_ + 'px', - 'width': this.size_.width + 'px', - 'alt': this.altText_ - }, - this.fieldGroup_); + this.imageElement_ = /** @type {!SVGImageElement} */ + (Blockly.utils.dom.createSvgElement( + 'image', + { + 'height': this.imageHeight_ + 'px', + 'width': this.size_.width + 'px', + 'alt': this.altText_ + }, + this.fieldGroup_)); this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_)); }; @@ -208,7 +216,7 @@ Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) { this.value_ = newValue; if (this.imageElement_) { this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS, - 'xlink:href', this.value_ || ''); + 'xlink:href', String(this.value_)); } }; diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 2b1f21c73..349afc37e 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -58,6 +58,13 @@ Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) { } Blockly.FieldMultilineInput.superClass_.constructor.call(this, opt_value, opt_validator, opt_config); + + /** + * The SVG group element that will contain a text element for each text row + * when initialized. + * @type {SVGGElement} + */ + this.textGroup_ = null; }; Blockly.utils.object.inherits(Blockly.FieldMultilineInput, Blockly.FieldTextInput); @@ -89,10 +96,11 @@ Blockly.FieldMultilineInput.fromJson = function(options) { */ Blockly.FieldMultilineInput.prototype.initView = function() { this.createBorderRect_(); - this.textGroup_ = Blockly.utils.dom.createSvgElement('g', - { - 'class': 'blocklyEditableText', - }, this.fieldGroup_); + this.textGroup_ = /** @type {!SVGGElement} **/ + (Blockly.utils.dom.createSvgElement('g', + { + 'class': 'blocklyEditableText', + }, this.fieldGroup_)); }; /** @@ -167,12 +175,13 @@ Blockly.FieldMultilineInput.prototype.render_ = function() { } else { this.resizeEditor_(); } + var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_); if (!this.isTextValid_) { - Blockly.utils.dom.addClass(this.htmlInput_, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(this.htmlInput_, 'invalid', true); + Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.aria.setState(htmlInput, 'invalid', true); } else { - Blockly.utils.dom.removeClass(this.htmlInput_, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(this.htmlInput_, 'invalid', false); + Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.aria.setState(htmlInput, 'invalid', false); } } }; @@ -186,7 +195,7 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() { var totalWidth = 0; var totalHeight = 0; for (var i = 0; i < nodes.length; i++) { - var tspan = nodes[i]; + var tspan = /** @type {!Element} */ (nodes[i]); var textWidth = Blockly.utils.dom.getTextWidth(tspan); if (textWidth > totalWidth) { totalWidth = textWidth; diff --git a/core/field_textinput.js b/core/field_textinput.js index f9079fc31..f6ebb0a22 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -64,6 +64,26 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { } Blockly.FieldTextInput.superClass_.constructor.call(this, opt_value, opt_validator, opt_config); + + /** + * The HTML input element. + * @type {HTMLElement} + */ + this.htmlInput_ = null; + + /** + * Key down event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeyDownWrapper_ = null; + + /** + * Key input event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeyInputWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field); @@ -183,12 +203,13 @@ Blockly.FieldTextInput.prototype.render_ = function() { } else { this.resizeEditor_(); } + var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_); if (!this.isTextValid_) { - Blockly.utils.dom.addClass(this.htmlInput_, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(this.htmlInput_, 'invalid', true); + Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.aria.setState(htmlInput, 'invalid', true); } else { - Blockly.utils.dom.removeClass(this.htmlInput_, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(this.htmlInput_, 'invalid', false); + Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.aria.setState(htmlInput, 'invalid', false); } } }; @@ -338,8 +359,12 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { * @private */ Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() { - Blockly.unbindEvent_(this.onKeyDownWrapper_); - Blockly.unbindEvent_(this.onKeyInputWrapper_); + if (this.onKeyDownWrapper_) { + Blockly.unbindEvent_(this.onKeyDownWrapper_); + } + if (this.onKeyInputWrapper_) { + Blockly.unbindEvent_(this.onKeyInputWrapper_); + } }; /** diff --git a/core/field_variable.js b/core/field_variable.js index 159a9914e..5ac85d736 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -440,8 +440,9 @@ Blockly.FieldVariable.dropdownCreate = function() { * In the rename case, prompt the user for a new name. * @param {!Blockly.Menu} menu The Menu component clicked. * @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu. + * @protected */ -Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) { +Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) { var id = menuItem.getValue(); // Handle special cases. if (this.sourceBlock_ && this.sourceBlock_.workspace) { From 013f2714a330083e847b465db4be726a37ce0db4 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 15 Oct 2019 22:43:23 -0700 Subject: [PATCH 044/343] Cleanup aria usage. (#3261) Use enums instead of arbitrary strings. Delete unused Aria properties Add missing requires. Delete unused code. --- core/components/menu/menu.js | 2 +- core/components/menu/menuitem.js | 6 +- core/components/tree/basenode.js | 6 +- core/field_colour.js | 11 +- core/field_dropdown.js | 5 +- core/field_multilineinput.js | 7 +- core/field_number.js | 1 + core/field_textinput.js | 8 +- core/utils/aria.js | 322 ++----------------------------- 9 files changed, 39 insertions(+), 329 deletions(-) diff --git a/core/components/menu/menu.js b/core/components/menu/menu.js index 00fd13e4e..4386f47ac 100644 --- a/core/components/menu/menu.js +++ b/core/components/menu/menu.js @@ -92,7 +92,7 @@ Blockly.Menu.prototype.blur = function() { /** * Set the menu accessibility role. - * @param {!Blockly.utils.aria.Role|string} roleName role name. + * @param {!Blockly.utils.aria.Role} roleName role name. * @package */ Blockly.Menu.prototype.setRole = function(roleName) { diff --git a/core/components/menu/menuitem.js b/core/components/menu/menuitem.js index 7e529279d..9639aab43 100644 --- a/core/components/menu/menuitem.js +++ b/core/components/menu/menuitem.js @@ -95,8 +95,8 @@ Blockly.MenuItem.prototype.createDom = function() { Blockly.utils.aria.setRole(element, this.roleName_ || (this.checkable_ ? Blockly.utils.aria.Role.MENUITEMCHECKBOX : Blockly.utils.aria.Role.MENUITEM)); - Blockly.utils.aria.setState(element, - Blockly.utils.aria.State.SELECTED, (this.checkable_ && this.checked_) || false); + Blockly.utils.aria.setState(element, Blockly.utils.aria.State.SELECTED, + (this.checkable_ && this.checked_) || false); }; /** @@ -164,7 +164,7 @@ Blockly.MenuItem.prototype.getValue = function() { /** * Set the menu accessibility role. - * @param {!Blockly.utils.aria.Role|string} roleName role name. + * @param {!Blockly.utils.aria.Role} roleName Role name. * @package */ Blockly.MenuItem.prototype.setRole = function(roleName) { diff --git a/core/components/tree/basenode.js b/core/components/tree/basenode.js index 9127dbe32..40130fb71 100644 --- a/core/components/tree/basenode.js +++ b/core/components/tree/basenode.js @@ -188,10 +188,8 @@ Blockly.tree.BaseNode.prototype.initAccessibility = function() { label.id = this.getId() + '.label'; } - Blockly.utils.aria.setRole(el, - Blockly.utils.aria.Role.TREEITEM); - Blockly.utils.aria.setState(el, - Blockly.utils.aria.State.SELECTED, false); + Blockly.utils.aria.setRole(el, Blockly.utils.aria.Role.TREEITEM); + Blockly.utils.aria.setState(el, Blockly.utils.aria.State.SELECTED, false); Blockly.utils.aria.setState(el, Blockly.utils.aria.State.LEVEL, this.getDepth()); if (label) { diff --git a/core/field_colour.js b/core/field_colour.js index 2e6913a68..6878977e6 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -557,13 +557,12 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { table.className = 'blocklyColourTable'; table.tabIndex = 0; table.dir = 'ltr'; - Blockly.utils.aria.setRole(table, - Blockly.utils.aria.Role.GRID); - Blockly.utils.aria.setState(table, - Blockly.utils.aria.State.EXPANDED, true); - Blockly.utils.aria.setState(table, 'rowcount', + Blockly.utils.aria.setRole(table, Blockly.utils.aria.Role.GRID); + Blockly.utils.aria.setState(table, Blockly.utils.aria.State.EXPANDED, true); + Blockly.utils.aria.setState(table, Blockly.utils.aria.State.ROWCOUNT, Math.floor(colours.length / columns)); - Blockly.utils.aria.setState(table, 'colcount', columns); + Blockly.utils.aria.setState(table, Blockly.utils.aria.State.COLCOUNT, + columns); var row; for (var i = 0; i < colours.length; i++) { if (i % columns == 0) { diff --git a/core/field_dropdown.js b/core/field_dropdown.js index d01a89c1a..3f38b3a6d 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -33,6 +33,7 @@ goog.require('Blockly.Menu'); goog.require('Blockly.MenuItem'); goog.require('Blockly.navigation'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.aria'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.object'); goog.require('Blockly.utils.Size'); @@ -251,7 +252,7 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { Blockly.FieldDropdown.prototype.dropdownCreate_ = function() { var menu = new Blockly.Menu(); menu.setRightToLeft(this.sourceBlock_.RTL); - menu.setRole('listbox'); + menu.setRole(Blockly.utils.aria.Role.LISTBOX); var options = this.getOptions(false); this.selectedMenuItem_ = null; @@ -266,7 +267,7 @@ Blockly.FieldDropdown.prototype.dropdownCreate_ = function() { content = image; } var menuItem = new Blockly.MenuItem(content); - menuItem.setRole('option'); + menuItem.setRole(Blockly.utils.aria.Role.OPTION); menuItem.setRightToLeft(this.sourceBlock_.RTL); menuItem.setValue(value); menuItem.setCheckable(true); diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 349afc37e..41e16b0fd 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -29,6 +29,7 @@ goog.require('Blockly.Css'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.aria'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.KeyCodes'); @@ -178,10 +179,12 @@ Blockly.FieldMultilineInput.prototype.render_ = function() { var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_); if (!this.isTextValid_) { Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(htmlInput, 'invalid', true); + Blockly.utils.aria.setState(htmlInput, + Blockly.utils.aria.State.INVALID, true); } else { Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(htmlInput, 'invalid', false); + Blockly.utils.aria.setState(htmlInput, + Blockly.utils.aria.State.INVALID, false); } } }; diff --git a/core/field_number.js b/core/field_number.js index be5ac735d..9cdd99439 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -25,6 +25,7 @@ goog.provide('Blockly.FieldNumber'); goog.require('Blockly.fieldRegistry'); goog.require('Blockly.FieldTextInput'); +goog.require('Blockly.utils.aria'); goog.require('Blockly.utils.object'); diff --git a/core/field_textinput.js b/core/field_textinput.js index f6ebb0a22..2d7d3b762 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -77,7 +77,7 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { * @private */ this.onKeyDownWrapper_ = null; - + /** * Key input event data. * @type {?Blockly.EventData} @@ -206,10 +206,12 @@ Blockly.FieldTextInput.prototype.render_ = function() { var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_); if (!this.isTextValid_) { Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(htmlInput, 'invalid', true); + Blockly.utils.aria.setState(htmlInput, + Blockly.utils.aria.State.INVALID, true); } else { Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); - Blockly.utils.aria.setState(htmlInput, 'invalid', false); + Blockly.utils.aria.setState(htmlInput, + Blockly.utils.aria.State.INVALID, false); } } }; diff --git a/core/utils/aria.js b/core/utils/aria.js index 14f31beb2..3ba1eac11 100644 --- a/core/utils/aria.js +++ b/core/utils/aria.js @@ -44,55 +44,6 @@ Blockly.utils.aria.ROLE_ATTRIBUTE_ = 'role'; * @enum {string} */ Blockly.utils.aria.Role = { - // ARIA role for an alert element that doesn't need to be explicitly closed. - ALERT: 'alert', - - // ARIA role for an alert dialog element that takes focus and must be closed. - ALERTDIALOG: 'alertdialog', - - // ARIA role for an application that implements its own keyboard navigation. - APPLICATION: 'application', - - // ARIA role for an article. - ARTICLE: 'article', - - // ARIA role for a banner containing mostly site content, not page content. - BANNER: 'banner', - - // ARIA role for a button element. - BUTTON: 'button', - - // ARIA role for a checkbox button element; use with the CHECKED state. - CHECKBOX: 'checkbox', - - // ARIA role for a column header of a table or grid. - COLUMNHEADER: 'columnheader', - - // ARIA role for a combo box element. - COMBOBOX: 'combobox', - - // ARIA role for a supporting section of the document. - COMPLEMENTARY: 'complementary', - - // ARIA role for a large perceivable region that contains information - // about the parent document. - CONTENTINFO: 'contentinfo', - - // ARIA role for a definition of a term or concept. - DEFINITION: 'definition', - - // ARIA role for a dialog, some descendant must take initial focus. - DIALOG: 'dialog', - - // ARIA role for a directory, like a table of contents. - DIRECTORY: 'directory', - - // ARIA role for a part of a page that's a document, not a web application. - DOCUMENT: 'document', - - // ARIA role for a landmark region logically considered one form. - FORM: 'form', - // ARIA role for an interactive control of tabular data. GRID: 'grid', @@ -102,57 +53,18 @@ Blockly.utils.aria.Role = { // ARIA role for a group of related elements like tree item siblings. GROUP: 'group', - // ARIA role for a heading element. - HEADING: 'heading', - - // ARIA role for a container of elements that together comprise one image. - IMG: 'img', - - // ARIA role for a link. - LINK: 'link', - - // ARIA role for a list of non-interactive list items. - LIST: 'list', - // ARIA role for a listbox. LISTBOX: 'listbox', - // ARIA role for a list item. - LISTITEM: 'listitem', - - // ARIA role for a live region where new information is added. - LOG: 'log', - - // ARIA landmark role for the main content in a document. Use only once. - MAIN: 'main', - - // ARIA role for a live region of non-essential information that changes. - MARQUEE: 'marquee', - - // ARIA role for a mathematical expression. - MATH: 'math', - // ARIA role for a popup menu. MENU: 'menu', - // ARIA role for a menubar element containing menu elements. - MENUBAR: 'menubar', - // ARIA role for menu item elements. MENUITEM: 'menuitem', // ARIA role for a checkbox box element inside a menu. MENUITEMCHECKBOX: 'menuitemcheckbox', - // ARIA role for a radio button element inside a menu. - MENUITEMRADIO: 'menuitemradio', - - // ARIA landmark role for a collection of navigation links. - NAVIGATION: 'navigation', - - // ARIA role for a section ancillary to the main content. - NOTE: 'note', - // ARIA role for option items that are children of combobox, listbox, menu, // radiogroup, or tree elements. OPTION: 'option', @@ -160,78 +72,12 @@ Blockly.utils.aria.Role = { // ARIA role for ignorable cosmetic elements with no semantic significance. PRESENTATION: 'presentation', - // ARIA role for a progress bar element. - PROGRESSBAR: 'progressbar', - - // ARIA role for a radio button element. - RADIO: 'radio', - - // ARIA role for a group of connected radio button elements. - RADIOGROUP: 'radiogroup', - - // ARIA role for an important region of the page. - REGION: 'region', - // ARIA role for a row of cells in a grid. ROW: 'row', - // ARIA role for a group of one or more rows in a grid. - ROWGROUP: 'rowgroup', - - // ARIA role for a row header of a table or grid. - ROWHEADER: 'rowheader', - - // ARIA role for a scrollbar element. - SCROLLBAR: 'scrollbar', - - // ARIA landmark role for a part of the page providing search functionality. - SEARCH: 'search', - - // ARIA role for a menu separator. - SEPARATOR: 'separator', - - // ARIA role for a slider. - SLIDER: 'slider', - - // ARIA role for a spin button. - SPINBUTTON: 'spinbutton', - - // ARIA role for a live region with advisory info less severe than an alert. - STATUS: 'status', - - // ARIA role for a tab button. - TAB: 'tab', - - // ARIA role for a table. - TABLE: 'table', - - // ARIA role for a tab bar (i.e. a list of tab buttons). - TABLIST: 'tablist', - - // ARIA role for a tab page (i.e. the element holding tab contents). - TABPANEL: 'tabpanel', - - // ARIA role for a textbox element. - TEXTBOX: 'textbox', - - // ARIA role for a textinfo element. - TEXTINFO: 'textinfo', - - // ARIA role for an element displaying elapsed time or time remaining. - TIMER: 'timer', - - // ARIA role for a toolbar element. - TOOLBAR: 'toolbar', - - // ARIA role for a tooltip element. - TOOLTIP: 'tooltip', - // ARIA role for a tree. TREE: 'tree', - // ARIA role for a grid whose rows can be expanded and collapsed like a tree. - TREEGRID: 'treegrid', - // ARIA role for a tree item that sometimes may be expanded or collapsed. TREEITEM: 'treeitem' }; @@ -246,65 +92,15 @@ Blockly.utils.aria.State = { // for example the selected item in a list box. Value: ID of an element. ACTIVEDESCENDANT: 'activedescendant', - // ARIA property that, if true, indicates that all of a changed region should - // be presented, instead of only parts. Value: one of {true, false}. - ATOMIC: 'atomic', - - // ARIA property to specify that input completion is provided. Value: - // one of {'inline', 'list', 'both', 'none'}. - AUTOCOMPLETE: 'autocomplete', - - // ARIA state to indicate that an element and its subtree are being updated. - // Value: one of {true, false}. - BUSY: 'busy', - - // ARIA state for a checked item. Value: one of {'true', 'false', 'mixed', - // undefined}. - CHECKED: 'checked', - - // ARIA state that defines an element's column index or position with respect - // to the total number of columns within a table, grid, or treegrid. - // Value: number. - COLINDEX: 'colindex', - - // ARIA property that identifies the element or elements whose contents or - // presence are controlled by this element. - // Value: space-separated IDs of other elements. - CONTROLS: 'controls', - - // ARIA property that identifies the element or elements that describe - // this element. Value: space-separated IDs of other elements. - DESCRIBEDBY: 'describedby', - - // ARIA state for a disabled item. Value: one of {true, false}. - DISABLED: 'disabled', - - // ARIA property that indicates what functions can be performed when a - // dragged object is released on the drop target. Value: one of - // {'copy', 'move', 'link', 'execute', 'popup', 'none'}. - DROPEFFECT: 'dropeffect', + // ARIA property defines the total number of columns in a table, grid, or + // treegrid. + // Value: integer. + COLCOUNT: 'colcount', // ARIA state for setting whether the element like a tree node is expanded. // Value: one of {true, false, undefined}. EXPANDED: 'expanded', - // ARIA property that identifies the next element (or elements) in the - // recommended reading order of content. Value: space-separated ids of - // elements to flow to. - FLOWTO: 'flowto', - - // ARIA state that indicates an element's "grabbed" state in drag-and-drop. - // Value: one of {true, false, undefined}. - GRABBED: 'grabbed', - - // ARIA property indicating whether the element has a popup. - // Value: one of {true, false}. - HASPOPUP: 'haspopup', - - // ARIA state indicating that the element is not visible or perceivable - // to any user. Value: one of {true, false}. - HIDDEN: 'hidden', - // ARIA state indicating that the entered value does not conform. Value: // one of {false, true, 'grammar', 'spelling'} INVALID: 'invalid', @@ -321,54 +117,18 @@ Blockly.utils.aria.State = { // Value: integer. LEVEL: 'level', - // ARIA property indicating that an element will be updated, and - // describes the types of updates the user agents, assistive technologies, - // and user can expect from the live region. Value: one of {'off', 'polite', - // 'assertive'}. - LIVE: 'live', - - // ARIA property indicating whether a text box can accept multiline input. - // Value: one of {true, false}. - MULTILINE: 'multiline', - - // ARIA property indicating if the user may select more than one item. - // Value: one of {true, false}. - MULTISELECTABLE: 'multiselectable', - // ARIA property indicating if the element is horizontal or vertical. // Value: one of {'vertical', 'horizontal'}. ORIENTATION: 'orientation', - // ARIA property creating a visual, functional, or contextual parent/child - // relationship when the DOM hierarchy can't be used to represent it. - // Value: Space-separated IDs of elements. - OWNS: 'owns', - // ARIA property that defines an element's number of position in a list. // Value: integer. POSINSET: 'posinset', - // ARIA state for a pressed item. - // Value: one of {true, false, undefined, 'mixed'}. - PRESSED: 'pressed', - - // ARIA property indicating that an element is not editable. - // Value: one of {true, false}. - READONLY: 'readonly', - - // ARIA property indicating that change notifications within this subtree - // of a live region should be announced. Value: one of {'additions', - // 'removals', 'text', 'all', 'additions text'}. - RELEVANT: 'relevant', - - // ARIA property indicating that user input is required on this element - // before a form may be submitted. Value: one of {true, false}. - REQUIRED: 'required', - - // ARIA state that defines an element's row index or position with respect - // to the total number of rows within a table, grid, or treegrid. - // Value: number. - ROWINDEX: 'rowindex', + // ARIA property defines the total number of rows in a table, grid, or + // treegrid. + // Value: integer. + ROWCOUNT: 'rowcount', // ARIA state for setting the currently selected item in the list. // Value: one of {true, false, undefined}. @@ -377,72 +137,30 @@ Blockly.utils.aria.State = { // ARIA property defining the number of items in a list. Value: integer. SETSIZE: 'setsize', - // ARIA property indicating if items are sorted. Value: one of {'ascending', - // 'descending', 'none', 'other'}. - SORT: 'sort', - // ARIA property for slider maximum value. Value: number. VALUEMAX: 'valuemax', // ARIA property for slider minimum value. Value: number. - VALUEMIN: 'valuemin', - - // ARIA property for slider active value. Value: number. - VALUENOW: 'valuenow', - - // ARIA property for slider active value represented as text. - // Value: string. - VALUETEXT: 'valuetext' + VALUEMIN: 'valuemin' }; /** - * Sets the role of an element. If the roleName is - * empty string or null, the role for the element is removed. - * We encourage clients to call the goog.a11y.aria.removeRole - * method instead of setting null and empty string values. - * Special handling for this case is added to ensure - * backword compatibility with existing code. + * Sets the role of an element. * * Similar to Closure's goog.a11y.aria * * @param {!Element} element DOM node to set role of. - * @param {!Blockly.utils.aria.Role|string} roleName role name(s). + * @param {!Blockly.utils.aria.Role} roleName Role name. */ Blockly.utils.aria.setRole = function(element, roleName) { - if (!roleName) { - // Setting the ARIA role to empty string is not allowed - // by the ARIA standard. - Blockly.utils.aria.removeRole(element); - } else { - element.setAttribute(Blockly.utils.aria.ROLE_ATTRIBUTE_, roleName); - } -}; - -/** - * Gets role of an element. - * Copied from Closure's goog.a11y.aria - * @param {!Element} element DOM element to get role of. - * @return {?Blockly.utils.aria.Role} ARIA Role name. - */ -Blockly.utils.aria.getRole = function(element) { - var role = element.getAttribute(Blockly.utils.aria.ROLE_ATTRIBUTE_); - return /** @type {Blockly.utils.aria.Role} */ (role) || null; -}; - -/** - * Removes role of an element. - * Copied from Closure's goog.a11y.aria - * @param {!Element} element DOM element to remove the role from. - */ -Blockly.utils.aria.removeRole = function(element) { - element.removeAttribute(Blockly.utils.aria.ROLE_ATTRIBUTE_); + element.setAttribute(Blockly.utils.aria.ROLE_ATTRIBUTE_, roleName); }; /** * Sets the state or property of an element. * Copied from Closure's goog.a11y.aria * @param {!Element} element DOM node where we set state. - * @param {!(Blockly.utils.aria.State|string)} stateName State attribute being set. + * @param {!Blockly.utils.aria.State} stateName State attribute being set. * Automatically adds prefix 'aria-' to the state name if the attribute is * not an extra attribute. * @param {string|boolean|number|!Array.} value Value @@ -452,18 +170,6 @@ Blockly.utils.aria.setState = function(element, stateName, value) { if (Array.isArray(value)) { value = value.join(' '); } - var attrStateName = Blockly.utils.aria.getAriaAttributeName_(stateName); + var attrStateName = Blockly.utils.aria.ARIA_PREFIX_ + stateName; element.setAttribute(attrStateName, value); }; - -/** - * Adds the 'aria-' prefix to ariaName. - * Copied from Closure's goog.a11y.aria - * @param {string} ariaName ARIA state/property name. - * @private - * @return {string} The ARIA attribute name with added 'aria-' prefix. - * @throws {Error} If no such attribute exists. - */ -Blockly.utils.aria.getAriaAttributeName_ = function(ariaName) { - return Blockly.utils.aria.ARIA_PREFIX_ + ariaName; -}; From 2eaabd180daa0d7c0e136900d42e03af7f1bff15 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 16 Oct 2019 06:19:37 -0700 Subject: [PATCH 045/343] Minor cleanup in keyboard nav (#3264) * Clean cursor code Some obvious inefficiencies that jumped out while randomly browsing the compiled code. * Typos * Multiplying by minus one. --- core/flyout_horizontal.js | 2 +- core/keyboard_nav/cursor_svg.js | 95 +++++++++++++------------------ core/keyboard_nav/navigation.js | 22 ++++--- core/renderers/zelos/constants.js | 6 +- 4 files changed, 57 insertions(+), 68 deletions(-) diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index 199a8ea70..cf76bff3d 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -203,7 +203,7 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(width, // Bottom. path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1, -this.CORNER_RADIUS, this.CORNER_RADIUS); - path.push('h', -1 * width); + path.push('h', -width); // Left. path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1, -this.CORNER_RADIUS, -this.CORNER_RADIUS); diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index 3fef7338c..e428a7a6b 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -319,8 +319,8 @@ Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) { var height = heightWidth.height + Blockly.CursorSvg.STACK_PADDING; // Shift the rectangle slightly to upper left so padding is equal on all sides. - var xPadding = -1 * Blockly.CursorSvg.STACK_PADDING / 2; - var yPadding = -1 * Blockly.CursorSvg.STACK_PADDING / 2; + var xPadding = -Blockly.CursorSvg.STACK_PADDING / 2; + var yPadding = -Blockly.CursorSvg.STACK_PADDING / 2; var x = xPadding; var y = yPadding; @@ -354,8 +354,8 @@ Blockly.CursorSvg.prototype.showCurrent_ = function() { * @param {number} cursorHeight The height of the cursor. */ Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, cursorHeight) { - var cursorPath = Blockly.utils.svgPaths.moveBy(-1 * cursorOffset, cursorHeight) + - Blockly.utils.svgPaths.lineOnAxis('V', -1 * cursorOffset) + + var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) + + Blockly.utils.svgPaths.lineOnAxis('V', -cursorOffset) + Blockly.utils.svgPaths.lineOnAxis('H', width + cursorOffset * 2) + Blockly.utils.svgPaths.lineOnAxis('V', cursorHeight); this.cursorBlock_.setAttribute('d', cursorPath); @@ -375,7 +375,7 @@ Blockly.CursorSvg.prototype.positionInput_ = function(connection) { var x = connection.getOffsetInBlock().x; var y = connection.getOffsetInBlock().y; - var path = Blockly.utils.svgPaths.moveTo(0,0) + + var path = Blockly.utils.svgPaths.moveTo(0, 0) + this.constants_.PUZZLE_TAB.pathDown; this.cursorInput_.setAttribute('d', path); @@ -408,7 +408,7 @@ Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) { */ Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) { var cursorPath = Blockly.utils.svgPaths.moveBy(width, 0) + - Blockly.utils.svgPaths.lineOnAxis('h', -1 * (width - this.constants_.PUZZLE_TAB.width)) + + Blockly.utils.svgPaths.lineOnAxis('h', -(width - this.constants_.PUZZLE_TAB.width)) + Blockly.utils.svgPaths.lineOnAxis('v', this.constants_.TAB_OFFSET_FROM_TOP) + this.constants_.PUZZLE_TAB.pathDown + Blockly.utils.svgPaths.lineOnAxis('V', height) + @@ -430,8 +430,8 @@ Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) { * @private */ Blockly.CursorSvg.prototype.positionPrevious_ = function(width, cursorOffset, cursorHeight) { - var cursorPath = Blockly.utils.svgPaths.moveBy(-1 * cursorOffset, cursorHeight) + - Blockly.utils.svgPaths.lineOnAxis('V', -1 * cursorOffset) + + var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) + + Blockly.utils.svgPaths.lineOnAxis('V', -cursorOffset) + Blockly.utils.svgPaths.lineOnAxis('H', this.constants_.NOTCH_OFFSET_LEFT) + this.constants_.NOTCH.pathLeft + Blockly.utils.svgPaths.lineOnAxis('H', width + cursorOffset * 2) + @@ -491,24 +491,24 @@ Blockly.CursorSvg.prototype.draw = function(curNode) { return; } - if (curNode.getType() === Blockly.ASTNode.types.BLOCK) { + if (curNode.getType() == Blockly.ASTNode.types.BLOCK) { var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation()); this.showWithBlockPrevOutput_(block); - } else if (curNode.getType() === Blockly.ASTNode.types.OUTPUT) { + } else if (curNode.getType() == Blockly.ASTNode.types.OUTPUT) { var outputBlock = /** @type {Blockly.BlockSvg} */ (curNode.getLocation().getSourceBlock()); this.showWithBlockPrevOutput_(outputBlock); - } else if (curNode.getLocation().type === Blockly.INPUT_VALUE) { + } else if (curNode.getLocation().type == Blockly.INPUT_VALUE) { this.showWithInput_(curNode); - } else if (curNode.getLocation().type === Blockly.NEXT_STATEMENT) { + } else if (curNode.getLocation().type == Blockly.NEXT_STATEMENT) { this.showWithNext_(curNode); - } else if (curNode.getType() === Blockly.ASTNode.types.PREVIOUS) { + } else if (curNode.getType() == Blockly.ASTNode.types.PREVIOUS) { var previousBlock = /** @type {Blockly.BlockSvg} */ (curNode.getLocation().getSourceBlock()); this.showWithBlockPrevOutput_(previousBlock); - } else if (curNode.getType() === Blockly.ASTNode.types.FIELD) { + } else if (curNode.getType() == Blockly.ASTNode.types.FIELD) { this.showWithField_(curNode); - } else if (curNode.getType() === Blockly.ASTNode.types.WORKSPACE) { + } else if (curNode.getType() == Blockly.ASTNode.types.WORKSPACE) { this.showWithCoordinates_(curNode); - } else if (curNode.getType() === Blockly.ASTNode.types.STACK) { + } else if (curNode.getType() == Blockly.ASTNode.types.STACK) { this.showWithStack_(curNode); } @@ -545,12 +545,12 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { // A horizontal line used to represent a workspace coordinate or next connection. this.cursorSvgLine_ = Blockly.utils.dom.createSvgElement('rect', { - 'x': '0', - 'y': '0', + 'x': 0, + 'y': 0, 'fill': colour, 'width': Blockly.CursorSvg.CURSOR_WIDTH, 'height': Blockly.CursorSvg.CURSOR_HEIGHT, - 'style': 'display: none;' + 'style': 'display: none' }, this.cursorSvg_); @@ -558,10 +558,10 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { this.cursorSvgRect_ = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyVerticalCursor', - 'x': '0', - 'y': '0', - 'rx': '10', 'ry': '10', - 'style': 'display: none;', + 'x': 0, + 'y': 0, + 'rx': 10, 'ry': 10, + 'style': 'display: none', 'stroke': colour }, this.cursorSvg_); @@ -572,57 +572,42 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { { 'width': Blockly.CursorSvg.CURSOR_WIDTH, 'height': Blockly.CursorSvg.CURSOR_HEIGHT, - 'transform':'', - 'style':'display: none;', + 'transform': '', + 'style': 'display: none', 'fill': colour }, this.cursorSvg_); - // A path used to repreesent a previous connection and a block, an output + // A path used to represent a previous connection and a block, an output // connection and a block, or a block. this.cursorBlock_ = Blockly.utils.dom.createSvgElement( 'path', { 'width': Blockly.CursorSvg.CURSOR_WIDTH, 'height': Blockly.CursorSvg.CURSOR_HEIGHT, - 'transform':'', - 'style':'display: none;', + 'transform': '', + 'style': 'display: none', 'fill': 'none', 'stroke': colour, - 'stroke-width': '4' + 'stroke-width': 4 }, this.cursorSvg_); // Markers and stack cursors don't blink. if (!this.isMarker_) { - Blockly.utils.dom.createSvgElement('animate', - { - 'attributeType': 'XML', - 'attributeName': 'fill', - 'dur': '1s', - 'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;', - 'repeatCount': 'indefinite' - }, + var properties = { + 'attributeType': 'XML', + 'attributeName': 'fill', + 'dur': '1s', + 'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;', + 'repeatCount': 'indefinite' + }; + Blockly.utils.dom.createSvgElement('animate', properties, this.cursorSvgLine_); - - Blockly.utils.dom.createSvgElement('animate', - { - 'attributeType': 'XML', - 'attributeName': 'fill', - 'dur': '1s', - 'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;', - 'repeatCount': 'indefinite' - }, + Blockly.utils.dom.createSvgElement('animate', properties, this.cursorInput_); - - Blockly.utils.dom.createSvgElement('animate', - { - 'attributeType': 'XML', - 'attributeName': 'stroke', - 'dur': '1s', - 'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;', - 'repeatCount': 'indefinite' - }, + properties['attributeName'] = 'stroke'; + Blockly.utils.dom.createSvgElement('animate', properties, this.cursorBlock_); } diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 90577c187..07b34d68b 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -330,8 +330,8 @@ Blockly.navigation.modify_ = function() { markerLoc = /** @type {!Blockly.Connection} */ (markerLoc); return Blockly.navigation.connect_(cursorLoc, markerLoc); } else if (markerNode.isConnection() && - (cursorType == Blockly.ASTNode.types.BLOCK || - cursorType == Blockly.ASTNode.types.STACK)) { + (cursorType == Blockly.ASTNode.types.BLOCK || + cursorType == Blockly.ASTNode.types.STACK)) { cursorLoc = /** @type {!Blockly.Block} */ (cursorLoc); markerLoc = /** @type {!Blockly.Connection} */ (markerLoc); return Blockly.navigation.insertBlock(cursorLoc, markerLoc); @@ -374,7 +374,7 @@ Blockly.navigation.disconnectChild_ = function(movingConnection, destConnection) * @private */ Blockly.navigation.moveAndConnect_ = function(movingConnection, destConnection) { - if (!movingConnection || ! destConnection) { + if (!movingConnection || !destConnection) { return false; } var movingBlock = movingConnection.getSourceBlock(); @@ -951,7 +951,8 @@ Blockly.navigation.ACTION_PREVIOUS = new Blockly.Action( * @type {!Blockly.Action} */ Blockly.navigation.ACTION_OUT = new Blockly.Action( - Blockly.navigation.actionNames.OUT, 'Go to the parent of the current location.'); + Blockly.navigation.actionNames.OUT, + 'Go to the parent of the current location.'); /** * The next action. @@ -965,7 +966,8 @@ Blockly.navigation.ACTION_NEXT = new Blockly.Action( * @type {!Blockly.Action} */ Blockly.navigation.ACTION_IN = new Blockly.Action( - Blockly.navigation.actionNames.IN, 'Go to the first child of the current location.'); + Blockly.navigation.actionNames.IN, + 'Go to the first child of the current location.'); /** * The action to try to insert a block. @@ -987,8 +989,8 @@ Blockly.navigation.ACTION_MARK = new Blockly.Action( * @type {!Blockly.Action} */ Blockly.navigation.ACTION_DISCONNECT = new Blockly.Action( - Blockly.navigation.actionNames.DISCONNECT, 'Dicsonnect the block at the' + - 'current location from its parent.'); + Blockly.navigation.actionNames.DISCONNECT, + 'Disconnect the block at the current location from its parent.'); /** * The action to open the toolbox. @@ -1002,14 +1004,16 @@ Blockly.navigation.ACTION_TOOLBOX = new Blockly.Action( * @type {!Blockly.Action} */ Blockly.navigation.ACTION_EXIT = new Blockly.Action( - Blockly.navigation.actionNames.EXIT, 'Close the current modal, such as a toolbox or field editor.'); + Blockly.navigation.actionNames.EXIT, + 'Close the current modal, such as a toolbox or field editor.'); /** * The action to toggle keyboard navigation mode on and off. * @type {!Blockly.Action} */ Blockly.navigation.ACTION_TOGGLE_KEYBOARD_NAV = new Blockly.Action( - Blockly.navigation.actionNames.TOGGLE_KEYBOARD_NAV, 'Turns on and off keyboard navigation.'); + Blockly.navigation.actionNames.TOGGLE_KEYBOARD_NAV, + 'Turns on and off keyboard navigation.'); /** * List of actions that can be performed in read only mode. diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 2c74a1a03..9a7e5f415 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -96,9 +96,9 @@ Blockly.zelos.ConstantProvider.prototype.makeHexagonal = function() { var width = height / 2; var forward = up ? -1 : 1; var direction = right ? -1 : 1; - - return Blockly.utils.svgPaths.lineTo(-1 * direction * width, forward * height / 2) + - Blockly.utils.svgPaths.lineTo(direction * width, forward * height / 2); + var dy = forward * height / 2; + return Blockly.utils.svgPaths.lineTo(-direction * width, dy) + + Blockly.utils.svgPaths.lineTo(direction * width, dy); } return { From 267deceb8208b383f2d3e748fb6b4dfb3ba410e6 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 16 Oct 2019 10:20:40 -0500 Subject: [PATCH 046/343] Dropdowndiv positioning (#3212) * Fix positioning of the dropdown div --- core/css.js | 2 +- core/dropdowndiv.js | 249 ++++++++++++++++++-------------- tests/mocha/dropdowndiv_test.js | 10 +- 3 files changed, 147 insertions(+), 114 deletions(-) diff --git a/core/css.js b/core/css.js index ef9f17295..8eca3fe0c 100644 --- a/core/css.js +++ b/core/css.js @@ -169,7 +169,7 @@ Blockly.Css.CONTENT = [ '}', '.blocklyDropDownDiv {', - 'position: fixed;', + 'position: absolute;', 'left: 0;', 'top: 0;', 'z-index: 1000;', diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index cb403bcbd..721d66af1 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -34,6 +34,7 @@ goog.require('Blockly.utils.style'); /** * Class for drop-down div. * @constructor + * @package */ Blockly.DropDownDiv = function() { }; @@ -68,21 +69,24 @@ Blockly.DropDownDiv.owner_ = null; Blockly.DropDownDiv.positionToField_ = null; /** - * Arrow size in px. Should match the value in CSS (need to position pre-render). + * Arrow size in px. Should match the value in CSS + * (need to position pre-render). * @type {number} * @const */ Blockly.DropDownDiv.ARROW_SIZE = 16; /** - * Drop-down border size in px. Should match the value in CSS (need to position the arrow). + * Drop-down border size in px. Should match the value in CSS (need to position + * the arrow). * @type {number} * @const */ Blockly.DropDownDiv.BORDER_SIZE = 1; /** - * Amount the arrow must be kept away from the edges of the main drop-down div, in px. + * Amount the arrow must be kept away from the edges of the main drop-down div, + * in px. * @type {number} * @const */ @@ -120,17 +124,20 @@ Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOR = '#fff'; * Timer for animation out, to be cleared if we need to immediately hide * without disrupting new shows. * @type {?number} + * @private */ Blockly.DropDownDiv.animateOutTimer_ = null; /** * Callback for when the drop-down is hidden. * @type {?Function} + * @private */ Blockly.DropDownDiv.onHide_ = null; /** * Create and insert the DOM element for this div. + * @package */ Blockly.DropDownDiv.createDom = function() { if (Blockly.DropDownDiv.DIV_) { @@ -205,14 +212,6 @@ Blockly.DropDownDiv.setColour = function(backgroundColour, borderColour) { Blockly.DropDownDiv.DIV_.style.borderColor = borderColour; }; -/** - * Set the category for the drop-down. - * @param {string} category The new category for the drop-down. - */ -Blockly.DropDownDiv.setCategory = function(category) { - Blockly.DropDownDiv.DIV_.setAttribute('data-category', category); -}; - /** * Shortcut to show and place the drop-down with positioning determined * by a particular block. The primary position will be below the block, @@ -228,25 +227,9 @@ Blockly.DropDownDiv.setCategory = function(category) { */ Blockly.DropDownDiv.showPositionedByBlock = function(field, block, opt_onHide, opt_secondaryYOffset) { - var scale = block.workspace.scale; - var bBox = {width: block.width, height: block.height}; - bBox.width *= scale; - bBox.height *= scale; - var position = block.getSvgRoot().getBoundingClientRect(); - // If we can fit it, render below the block. - var primaryX = position.left + bBox.width / 2; - var primaryY = position.top + bBox.height; - // If we can't fit it, render above the entire parent block. - var secondaryX = primaryX; - var secondaryY = position.top; - if (opt_secondaryYOffset) { - secondaryY += opt_secondaryYOffset; - } - // Set bounds to workspace; show the drop-down. - Blockly.DropDownDiv.setBoundsElement( - block.workspace.getParentSvg().parentNode); - return Blockly.DropDownDiv.show( - field, block.RTL, primaryX, primaryY, secondaryX, secondaryY, opt_onHide); + return Blockly.DropDownDiv.showPositionedByRect_( + Blockly.DropDownDiv.getScaledBboxOfBlock_(block), + field, opt_onHide, opt_secondaryYOffset); }; /** @@ -263,19 +246,67 @@ Blockly.DropDownDiv.showPositionedByBlock = function(field, block, */ Blockly.DropDownDiv.showPositionedByField = function(field, opt_onHide, opt_secondaryYOffset) { - var position = field.getSvgRoot().getBoundingClientRect(); + Blockly.DropDownDiv.positionToField_ = true; + return Blockly.DropDownDiv.showPositionedByRect_( + Blockly.DropDownDiv.getScaledBboxOfField_(field), + field, opt_onHide, opt_secondaryYOffset); +}; + +/** + * Get the scaled bounding box of a block. + * @param {!Blockly.Block} block The block. + * @return {!Blockly.utils.Rect} The scaled bounding box of the block. + * @private + */ +Blockly.DropDownDiv.getScaledBboxOfBlock_ = function(block) { + var bBox = block.getSvgRoot().getBBox(); + var scale = block.workspace.scale; + var scaledHeight = bBox.height * scale; + var scaledWidth = bBox.width * scale; + var xy = Blockly.utils.style.getPageOffset(block.getSvgRoot()); + return new Blockly.utils.Rect( + xy.y, xy.y + scaledHeight, xy.x, xy.x + scaledWidth); +}; + +/** + * Get the scaled bounding box of a field. + * @param {!Blockly.Field} field The field. + * @return {!Blockly.utils.Rect} The scaled bounding box of the field. + * @private + */ +Blockly.DropDownDiv.getScaledBboxOfField_ = function(field) { + var bBox = field.getScaledBBox_(); + return new Blockly.utils.Rect( + bBox.top, bBox.bottom, bBox.left, bBox.right); +}; + +/** + * Helper method to show and place the drop-down with positioning determined + * by a scaled bounding box. The primary position will be below the rect, + * and the secondary position above the rect. Drop-down will be constrained to + * the block's workspace. + * @param {!Blockly.utils.Rect} bBox The scaled bounding box. + * @param {!Blockly.Field} field The field to position the dropdown against. + * @param {Function=} opt_onHide Optional callback for when the drop-down is + * hidden. + * @param {number=} opt_secondaryYOffset Optional Y offset for above-block + * positioning. + * @return {boolean} True if the menu rendered below block; false if above. + * @private + */ +Blockly.DropDownDiv.showPositionedByRect_ = function(bBox, field, + opt_onHide, opt_secondaryYOffset) { // If we can fit it, render below the block. - var primaryX = position.left + position.width / 2; - var primaryY = position.bottom; + var primaryX = bBox.left + (bBox.right - bBox.left) / 2; + var primaryY = bBox.bottom; // If we can't fit it, render above the entire parent block. var secondaryX = primaryX; - var secondaryY = position.top; + var secondaryY = bBox.top; if (opt_secondaryYOffset) { secondaryY += opt_secondaryYOffset; } var sourceBlock = field.getSourceBlock(); // Set bounds to workspace; show the drop-down. - Blockly.DropDownDiv.positionToField_ = true; Blockly.DropDownDiv.setBoundsElement( sourceBlock.workspace.getParentSvg().parentNode); return Blockly.DropDownDiv.show( @@ -286,18 +317,21 @@ Blockly.DropDownDiv.showPositionedByField = function(field, /** * Show and place the drop-down. * The drop-down is placed with an absolute "origin point" (x, y) - i.e., - * the arrow will point at this origin and box will positioned below or above it. - * If we can maintain the container bounds at the primary point, the arrow will - * point there, and the container will be positioned below it. - * If we can't maintain the container bounds at the primary point, fall-back to the - * secondary point and position above. + * the arrow will point at this origin and box will positioned below or above + * it. If we can maintain the container bounds at the primary point, the arrow + * will point there, and the container will be positioned below it. + * If we can't maintain the container bounds at the primary point, fall-back to + * the secondary point and position above. * @param {Object} owner The object showing the drop-down * @param {boolean} rtl Right-to-left (true) or left-to-right (false). - * @param {number} primaryX Desired origin point x, in absolute px - * @param {number} primaryY Desired origin point y, in absolute px - * @param {number} secondaryX Secondary/alternative origin point x, in absolute px - * @param {number} secondaryY Secondary/alternative origin point y, in absolute px - * @param {Function=} opt_onHide Optional callback for when the drop-down is hidden + * @param {number} primaryX Desired origin point x, in absolute px. + * @param {number} primaryY Desired origin point y, in absolute px. + * @param {number} secondaryX Secondary/alternative origin point x, in absolute + * px. + * @param {number} secondaryY Secondary/alternative origin point y, in absolute + * px. + * @param {Function=} opt_onHide Optional callback for when the drop-down is + * hidden. * @return {boolean} True if the menu rendered at the primary origin point. * @package */ @@ -305,19 +339,6 @@ Blockly.DropDownDiv.show = function(owner, rtl, primaryX, primaryY, secondaryX, secondaryY, opt_onHide) { Blockly.DropDownDiv.owner_ = owner; Blockly.DropDownDiv.onHide_ = opt_onHide || null; - var metrics = Blockly.DropDownDiv.getPositionMetrics(primaryX, primaryY, - secondaryX, secondaryY); - // Update arrow CSS. - if (metrics.arrowVisible) { - Blockly.DropDownDiv.arrow_.style.display = ''; - Blockly.DropDownDiv.arrow_.style.transform = 'translate(' + - metrics.arrowX + 'px,' + metrics.arrowY + 'px) rotate(45deg)'; - Blockly.DropDownDiv.arrow_.setAttribute('class', metrics.arrowAtTop ? - 'blocklyDropDownArrow arrowTop' : 'blocklyDropDownArrow arrowBottom'); - } else { - Blockly.DropDownDiv.arrow_.style.display = 'none'; - } - // Set direction. Blockly.DropDownDiv.DIV_.style.direction = rtl ? 'rtl' : 'ltr'; @@ -330,10 +351,8 @@ Blockly.DropDownDiv.show = function(owner, rtl, primaryX, primaryY, // Using both `left`, `top` for the initial translation and then `translate` // for the animated transition to final X, Y is a workaround. - Blockly.DropDownDiv.positionInternal_( - metrics.initialX, metrics.initialY, - metrics.finalX, metrics.finalY); - return metrics.arrowAtTop; + return Blockly.DropDownDiv.positionInternal_( + primaryX, primaryY, secondaryX, secondaryY); }; /** @@ -343,8 +362,10 @@ Blockly.DropDownDiv.show = function(owner, rtl, primaryX, primaryY, * @private */ Blockly.DropDownDiv.getBoundsInfo_ = function() { - var boundPosition = Blockly.DropDownDiv.boundsElement_.getBoundingClientRect(); - var boundSize = Blockly.utils.style.getSize(Blockly.DropDownDiv.boundsElement_); + var boundPosition = Blockly.DropDownDiv.boundsElement_ + .getBoundingClientRect(); + var boundSize = Blockly.utils.style.getSize( + Blockly.DropDownDiv.boundsElement_); return { left: boundPosition.left, @@ -367,8 +388,9 @@ Blockly.DropDownDiv.getBoundsInfo_ = function() { * in absolute px. * @return {Object} Various final metrics, including rendered positions * for drop-down and arrow. + * @private */ -Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, +Blockly.DropDownDiv.getPositionMetrics_ = function(primaryX, primaryY, secondaryX, secondaryY) { var boundsInfo = Blockly.DropDownDiv.getBoundsInfo_(); var divSize = Blockly.utils.style.getSize( @@ -376,27 +398,27 @@ Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, // Can we fit in-bounds below the target? if (primaryY + divSize.height < boundsInfo.bottom) { - return Blockly.DropDownDiv.getPositionBelowMetrics( + return Blockly.DropDownDiv.getPositionBelowMetrics_( primaryX, primaryY, boundsInfo, divSize); } // Can we fit in-bounds above the target? if (secondaryY - divSize.height > boundsInfo.top) { - return Blockly.DropDownDiv.getPositionAboveMetrics( + return Blockly.DropDownDiv.getPositionAboveMetrics_( secondaryX, secondaryY, boundsInfo, divSize); } // Can we fit outside the workspace bounds (but inside the window) below? if (primaryY + divSize.height < document.documentElement.clientHeight) { - return Blockly.DropDownDiv.getPositionBelowMetrics( + return Blockly.DropDownDiv.getPositionBelowMetrics_( primaryX, primaryY, boundsInfo, divSize); } // Can we fit outside the workspace bounds (but inside the window) above? if (secondaryY - divSize.height > document.documentElement.clientTop) { - return Blockly.DropDownDiv.getPositionAboveMetrics( + return Blockly.DropDownDiv.getPositionAboveMetrics_( secondaryX, secondaryY, boundsInfo, divSize); } // Last resort, render at top of page. - return Blockly.DropDownDiv.getPositionTopOfPageMetrics( + return Blockly.DropDownDiv.getPositionTopOfPageMetrics_( primaryX, boundsInfo, divSize); }; @@ -410,8 +432,9 @@ Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, * of the DropDownDiv (width & height). * @return {Object} Various final metrics, including rendered positions * for drop-down and arrow. + * @private */ -Blockly.DropDownDiv.getPositionBelowMetrics = function( +Blockly.DropDownDiv.getPositionBelowMetrics_ = function( primaryX, primaryY, boundsInfo, divSize) { var xCoords = Blockly.DropDownDiv.getPositionX( @@ -445,8 +468,9 @@ Blockly.DropDownDiv.getPositionBelowMetrics = function( * of the DropDownDiv (width & height). * @return {Object} Various final metrics, including rendered positions * for drop-down and arrow. + * @private */ -Blockly.DropDownDiv.getPositionAboveMetrics = function( +Blockly.DropDownDiv.getPositionAboveMetrics_ = function( secondaryX, secondaryY, boundsInfo, divSize) { var xCoords = Blockly.DropDownDiv.getPositionX( @@ -478,8 +502,9 @@ Blockly.DropDownDiv.getPositionAboveMetrics = function( * of the DropDownDiv (width & height). * @return {Object} Various final metrics, including rendered positions * for drop-down and arrow. + * @private */ -Blockly.DropDownDiv.getPositionTopOfPageMetrics = function( +Blockly.DropDownDiv.getPositionTopOfPageMetrics_ = function( sourceX, boundsInfo, divSize) { var xCoords = Blockly.DropDownDiv.getPositionX( @@ -506,6 +531,7 @@ Blockly.DropDownDiv.getPositionTopOfPageMetrics = function( * @param {number} divWidth The width of the div in px. * @return {{divX: number, arrowX: number}} An object containing metrics for * the x positions of the left side of the DropDownDiv and the arrow. + * @package */ Blockly.DropDownDiv.getPositionX = function( sourceX, boundsLeft, boundsRight, divWidth) { @@ -613,21 +639,35 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { /** * Set the dropdown div's position. - * @param {number} initialX Initial Horizontal location - * (window coordinates, not body). - * @param {number} initialY Initial Vertical location - * (window coordinates, not body). - * @param {number} finalX Final Horizontal location - * (window coordinates, not body). - * @param {number} finalY Final Vertical location - * (window coordinates, not body). + * @param {number} primaryX Desired origin point x, in absolute px. + * @param {number} primaryY Desired origin point y, in absolute px. + * @param {number} secondaryX Secondary/alternative origin point x, + * in absolute px. + * @param {number} secondaryY Secondary/alternative origin point y, + * in absolute px. + * @return {boolean} True if the menu rendered at the primary origin point. * @private */ -Blockly.DropDownDiv.positionInternal_ = function(initialX, initialY, finalX, finalY) { - initialX = Math.floor(initialX); - initialY = Math.floor(initialY); - finalX = Math.floor(finalX); - finalY = Math.floor(finalY); +Blockly.DropDownDiv.positionInternal_ = function( + primaryX, primaryY, secondaryX, secondaryY) { + var metrics = Blockly.DropDownDiv.getPositionMetrics_(primaryX, primaryY, + secondaryX, secondaryY); + + // Update arrow CSS. + if (metrics.arrowVisible) { + Blockly.DropDownDiv.arrow_.style.display = ''; + Blockly.DropDownDiv.arrow_.style.transform = 'translate(' + + metrics.arrowX + 'px,' + metrics.arrowY + 'px) rotate(45deg)'; + Blockly.DropDownDiv.arrow_.setAttribute('class', metrics.arrowAtTop ? + 'blocklyDropDownArrow arrowTop' : 'blocklyDropDownArrow arrowBottom'); + } else { + Blockly.DropDownDiv.arrow_.style.display = 'none'; + } + + var initialX = Math.floor(metrics.initialX); + var initialY = Math.floor(metrics.initialY); + var finalX = Math.floor(metrics.finalX); + var finalY = Math.floor(metrics.finalY); var div = Blockly.DropDownDiv.DIV_; // First apply initial translation. @@ -643,42 +683,35 @@ Blockly.DropDownDiv.positionInternal_ = function(initialX, initialY, finalX, fin var dx = finalX - initialX; var dy = finalY - initialY; div.style.transform = 'translate(' + dx + 'px,' + dy + 'px)'; + + return metrics.arrowAtTop; }; /** - * Repositions the dropdownDiv on window resize. If it doesn't know how to - * calculate the new position, it will just hide it instead. + * Repositions the dropdownDiv on window resize. If it doesn't know how to + * calculate the new position, it will just hide it instead. + * @package */ Blockly.DropDownDiv.repositionForWindowResize = function() { // This condition mainly catches the dropdown div when it is being used as a // dropdown. It is important not to close it in this case because on Android, // when a field is focused, the soft keyboard opens triggering a window resize - // event and we want the dropdown div to stick around so users can type into it. + // event and we want the dropdown div to stick around so users can type into + // it. if (Blockly.DropDownDiv.owner_) { + var field = Blockly.DropDownDiv.owner_; var block = Blockly.DropDownDiv.owner_.getSourceBlock(); - var scale = block.workspace.scale; - var bBox = { - width: Blockly.DropDownDiv.positionToField_ ? - Blockly.DropDownDiv.owner_.size_.width : block.width, - height: Blockly.DropDownDiv.positionToField_ ? - Blockly.DropDownDiv.owner_.size_.height : block.height - }; - bBox.width *= scale; - bBox.height *= scale; - var position = Blockly.DropDownDiv.positionToField_ ? - Blockly.DropDownDiv.owner_.fieldGroup_.getBoundingClientRect() : - block.getSvgRoot().getBoundingClientRect(); + var bBox = Blockly.DropDownDiv.positionToField_ ? + Blockly.DropDownDiv.getScaledBboxOfField_(field) : + Blockly.DropDownDiv.getScaledBboxOfBlock_(block); // If we can fit it, render below the block. - var primaryX = position.left + bBox.width / 2; - var primaryY = position.top + bBox.height; + var primaryX = bBox.left + (bBox.right - bBox.left) / 2; + var primaryY = bBox.bottom; // If we can't fit it, render above the entire parent block. var secondaryX = primaryX; - var secondaryY = position.top; - var metrics = Blockly.DropDownDiv.getPositionMetrics( - primaryX, primaryY, secondaryX, secondaryY); + var secondaryY = bBox.top; Blockly.DropDownDiv.positionInternal_( - metrics.initialX, metrics.initialY, - metrics.finalX, metrics.finalY); + primaryX, primaryY, secondaryX, secondaryY); } else { Blockly.DropDownDiv.hide(); } diff --git a/tests/mocha/dropdowndiv_test.js b/tests/mocha/dropdowndiv_test.js index 541c262e6..0f7c89bb0 100644 --- a/tests/mocha/dropdowndiv_test.js +++ b/tests/mocha/dropdowndiv_test.js @@ -44,7 +44,7 @@ suite('DropDownDiv', function() { this.clientTopStub.restore(); }); test('Below, in Bounds', function() { - var metrics = Blockly.DropDownDiv.getPositionMetrics(50, 0, 50, -10); + var metrics = Blockly.DropDownDiv.getPositionMetrics_(50, 0, 50, -10); // "Above" in value actually means below in render. chai.assert.isAtLeast(metrics.initialY, 0); chai.assert.isAbove(metrics.finalY, 0); @@ -52,7 +52,7 @@ suite('DropDownDiv', function() { chai.assert.isTrue(metrics.arrowAtTop); }); test('Above, in Bounds', function() { - var metrics = Blockly.DropDownDiv.getPositionMetrics(50, 100, 50, 90); + var metrics = Blockly.DropDownDiv.getPositionMetrics_(50, 100, 50, 90); // "Below" in value actually means above in render. chai.assert.isAtMost(metrics.initialY, 100); chai.assert.isBelow(metrics.finalY, 100); @@ -60,7 +60,7 @@ suite('DropDownDiv', function() { chai.assert.isFalse(metrics.arrowAtTop); }); test('Below, out of Bounds', function() { - var metrics = Blockly.DropDownDiv.getPositionMetrics(50, 60, 50, 50); + var metrics = Blockly.DropDownDiv.getPositionMetrics_(50, 60, 50, 50); // "Above" in value actually means below in render. chai.assert.isAtLeast(metrics.initialY, 60); chai.assert.isAbove(metrics.finalY, 60); @@ -68,7 +68,7 @@ suite('DropDownDiv', function() { chai.assert.isTrue(metrics.arrowAtTop); }); test('Above, in Bounds', function() { - var metrics = Blockly.DropDownDiv.getPositionMetrics(50, 100, 50, 90); + var metrics = Blockly.DropDownDiv.getPositionMetrics_(50, 100, 50, 90); // "Below" in value actually means above in render. chai.assert.isAtMost(metrics.initialY, 100); chai.assert.isBelow(metrics.finalY, 100); @@ -77,7 +77,7 @@ suite('DropDownDiv', function() { }); test('No Solution, Render At Top', function() { this.clientHeightStub.get(function() { return 100; }); - var metrics = Blockly.DropDownDiv.getPositionMetrics(50, 60, 50, 50); + var metrics = Blockly.DropDownDiv.getPositionMetrics_(50, 60, 50, 50); // "Above" in value actually means below in render. chai.assert.equal(metrics.initialY, 0); chai.assert.equal(metrics.finalY, 0); From 01b6992efd44a9f1b162168f50e4c8989f2b88fa Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 16 Oct 2019 09:40:02 -0700 Subject: [PATCH 047/343] Normalize to one spelling of color/colour. --- core/dropdowndiv.js | 18 +++++++++--------- core/keyboard_nav/cursor_svg.js | 14 +++++++------- core/renderers/common/debugger.js | 2 +- core/utils/colour.js | 6 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 721d66af1..689d32a3e 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -107,18 +107,18 @@ Blockly.DropDownDiv.PADDING_Y = 16; Blockly.DropDownDiv.ANIMATION_TIME = 0.25; /** - * The default dropdown div border color. + * The default dropdown div border colour. * @type {string} * @const */ -Blockly.DropDownDiv.DEFAULT_DROPDOWN_BORDER_COLOR = '#dadce0'; +Blockly.DropDownDiv.DEFAULT_DROPDOWN_BORDER_COLOUR = '#dadce0'; /** - * The default dropdown div color. + * The default dropdown div colour. * @type {string} * @const */ -Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOR = '#fff'; +Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOUR = '#fff'; /** * Timer for animation out, to be cleared if we need to immediately hide @@ -145,8 +145,8 @@ Blockly.DropDownDiv.createDom = function() { } var div = document.createElement('div'); div.className = 'blocklyDropDownDiv'; - div.style.backgroundColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOR; - div.style.borderColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_BORDER_COLOR; + div.style.backgroundColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOUR; + div.style.borderColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_BORDER_COLOUR; document.body.appendChild(div); Blockly.DropDownDiv.DIV_ = div; @@ -626,8 +626,8 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { div.style.top = ''; div.style.opacity = 0; div.style.display = 'none'; - div.style.backgroundColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOR; - div.style.borderColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_BORDER_COLOR; + div.style.backgroundColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_COLOUR; + div.style.borderColor = Blockly.DropDownDiv.DEFAULT_DROPDOWN_BORDER_COLOUR; if (Blockly.DropDownDiv.onHide_) { Blockly.DropDownDiv.onHide_(); @@ -663,7 +663,7 @@ Blockly.DropDownDiv.positionInternal_ = function( } else { Blockly.DropDownDiv.arrow_.style.display = 'none'; } - + var initialX = Math.floor(metrics.initialX); var initialY = Math.floor(metrics.initialY); var finalX = Math.floor(metrics.finalX); diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index e428a7a6b..6747e1a28 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -119,18 +119,18 @@ Blockly.CursorSvg.BLOCK_PADDING = 2; Blockly.CursorSvg.HEIGHT_MULTIPLIER = 3 / 4; /** - * Cursor color. + * Cursor colour. * @type {string} * @const */ -Blockly.CursorSvg.CURSOR_COLOR = '#cc0a0a'; +Blockly.CursorSvg.CURSOR_COLOUR = '#cc0a0a'; /** - * Immovable marker color. + * Immovable marker colour. * @type {string} * @const */ -Blockly.CursorSvg.MARKER_COLOR = '#4286f4'; +Blockly.CursorSvg.MARKER_COLOUR = '#4286f4'; /** * The name of the CSS class for a cursor. @@ -534,8 +534,8 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { */ - var colour = this.isMarker_ ? Blockly.CursorSvg.MARKER_COLOR : - Blockly.CursorSvg.CURSOR_COLOR; + var colour = this.isMarker_ ? Blockly.CursorSvg.MARKER_COLOUR : + Blockly.CursorSvg.CURSOR_COLOUR; this.cursorSvg_ = Blockly.utils.dom.createSvgElement('g', { 'width': Blockly.CursorSvg.CURSOR_WIDTH, @@ -599,7 +599,7 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { 'attributeType': 'XML', 'attributeName': 'fill', 'dur': '1s', - 'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;', + 'values': Blockly.CursorSvg.CURSOR_COLOUR + ';transparent;transparent;', 'repeatCount': 'indefinite' }; Blockly.utils.dom.createSvgElement('animate', properties, diff --git a/core/renderers/common/debugger.js b/core/renderers/common/debugger.js index 023405588..a405fc650 100644 --- a/core/renderers/common/debugger.js +++ b/core/renderers/common/debugger.js @@ -175,7 +175,7 @@ Blockly.blockRendering.Debug.prototype.drawRenderedElem = function(elem, isRtl) /** * Draw a circle at the location of the given connection. Inputs and outputs - * share the same colors, as do previous and next. When positioned correctly + * share the same colours, as do previous and next. When positioned correctly * a connected pair will look like a bullseye. * @param {Blockly.RenderedConnection} conn The connection to circle. * @package diff --git a/core/utils/colour.js b/core/utils/colour.js index be304ef3e..849737448 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -88,11 +88,11 @@ Blockly.utils.colour.rgbToHex = function(r, g, b) { /** * Converts a hex representation of a colour to RGB. - * @param {string} hexColor Colour in '#ff0000' format. + * @param {string} hexColour Colour in '#ff0000' format. * @return {!Array.} RGB representation of the colour. */ -Blockly.utils.colour.hexToRgb = function(hexColor) { - var rgb = parseInt(hexColor.substr(1), 16); +Blockly.utils.colour.hexToRgb = function(hexColour) { + var rgb = parseInt(hexColour.substr(1), 16); var r = rgb >> 16; var g = (rgb >> 8) & 255; var b = rgb & 255; From 986e965be8a36833d9e952cbc3058df946e13d8b Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 16 Oct 2019 11:48:09 -0500 Subject: [PATCH 048/343] Private/protected visibility cleanup (#3263) * Fix a number of private visibility issues --- core/block_svg.js | 2 ++ core/blocks.js | 2 +- core/bubble.js | 7 ++++--- core/field_angle.js | 7 ++++--- core/field_image.js | 1 + core/flyout_base.js | 1 + core/gesture.js | 3 ++- core/insertion_marker_manager.js | 3 +++ core/keyboard_nav/cursor_svg.js | 1 + core/scrollbar.js | 2 ++ core/theme.js | 3 +++ core/toolbox.js | 1 + core/workspace_comment_render_svg.js | 2 +- core/workspace_svg.js | 2 ++ demos/blockfactory/factory.js | 2 +- demos/blockfactory/factory_utils.js | 2 +- demos/blockfactory/workspacefactory/wfactory_controller.js | 6 +++--- demos/blockfactory/workspacefactory/wfactory_model.js | 2 +- .../com/google/blockly/android/webview/JsDialogHelper.java | 2 +- externs/svg-externs.js | 2 +- generators/php/lists.js | 2 +- tests/generators/index.html | 2 +- 22 files changed, 38 insertions(+), 19 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 9bc5a35a8..92cbd4d84 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1076,6 +1076,7 @@ Blockly.BlockSvg.prototype.updateColour = function() { /** * Sets the colour of the border. * Removes the light and dark paths if a border colour is defined. + * @private */ Blockly.BlockSvg.prototype.setBorderColour_ = function() { var borderColours = this.getColourBorder(); @@ -1097,6 +1098,7 @@ Blockly.BlockSvg.prototype.setBorderColour_ = function() { /** * Sets the colour of shadow blocks. * @return {?string} The background colour of the block. + * @private */ Blockly.BlockSvg.prototype.setShadowColour_ = function() { var shadowColour = this.getColourShadow(); diff --git a/core/blocks.js b/core/blocks.js index 328eacf43..ca1367afe 100644 --- a/core/blocks.js +++ b/core/blocks.js @@ -27,7 +27,7 @@ */ goog.provide('Blockly.Blocks'); -/* +/** * A mapping of block type names to block prototype objects. * @type {!Object.} */ diff --git a/core/bubble.js b/core/bubble.js index 53cbe5755..a319efcba 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -126,6 +126,7 @@ Blockly.Bubble.onMouseMoveWrapper_ = null; /** * Function to call on resize of bubble. * @type {Function} + * @private */ Blockly.Bubble.prototype.resizeCallback_ = null; @@ -144,12 +145,12 @@ Blockly.Bubble.unbindDragEvents_ = function() { } }; -/* +/** * Handle a mouse-up event while dragging a bubble's border or resize handle. - * @param {!Event} e Mouse up event. + * @param {!Event} _e Mouse up event. * @private */ -Blockly.Bubble.bubbleMouseUp_ = function(/* e */) { +Blockly.Bubble.bubbleMouseUp_ = function(_e) { Blockly.Touch.clearTouchIdentifier(); Blockly.Bubble.unbindDragEvents_(); }; diff --git a/core/field_angle.js b/core/field_angle.js index b7002a495..eb26c4597 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -331,9 +331,9 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { // a click handler on the drag surface to update the value if the surface // is clicked. this.clickSurfaceWrapper_ = - Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove, true, true); + Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove_, true, true); this.moveSurfaceWrapper_ = - Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove, true, true); + Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove_, true, true); return svg; }; @@ -367,8 +367,9 @@ Blockly.FieldAngle.prototype.hide_ = function() { /** * Set the angle to match the mouse's position. * @param {!Event} e Mouse move event. + * @protected */ -Blockly.FieldAngle.prototype.onMouseMove = function(e) { +Blockly.FieldAngle.prototype.onMouseMove_ = function(e) { // Calculate angle. var bBox = this.gauge_.ownerSVGElement.getBoundingClientRect(); var dx = e.clientX - bBox.left - Blockly.FieldAngle.HALF; diff --git a/core/field_image.js b/core/field_image.js index fe699a867..f60c40a92 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -247,6 +247,7 @@ Blockly.FieldImage.prototype.setAlt = function(alt) { /** * If field click is called, and click handler defined, * call the handler. + * @protected */ Blockly.FieldImage.prototype.showEditor_ = function() { if (this.clickHandler_) { diff --git a/core/flyout_base.js b/core/flyout_base.js index 24326655d..35b353e6e 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -111,6 +111,7 @@ Blockly.Flyout = function(workspaceOptions) { /** * Width of output tab. * @type {number} + * @protected * @const */ this.tabWidth_ = this.workspace_.getRenderer().getConstants().TAB_WIDTH; diff --git a/core/gesture.js b/core/gesture.js index ba80a8fdc..c8aadf03b 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -38,7 +38,7 @@ goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.WorkspaceDragger'); -/* +/** * Note: In this file "start" refers to touchstart, mousedown, and pointerstart * events. "End" refers to touchend, mouseup, and pointerend events. */ @@ -57,6 +57,7 @@ Blockly.Gesture = function(e, creatorWorkspace) { * The position of the mouse when the gesture started. Units are CSS pixels, * with (0, 0) at the top left of the browser window (mouseEvent clientX/Y). * @type {Blockly.utils.Coordinate} + * @private */ this.mouseDownXY_ = null; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 85c23d43a..c936aed43 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -352,6 +352,7 @@ Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function( * 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_(); @@ -559,6 +560,7 @@ Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() { /** * Add highlighting showing which block will be replaced. + * @private */ Blockly.InsertionMarkerManager.prototype.highlightBlock_ = function() { var closest = this.closestConnection_; @@ -576,6 +578,7 @@ Blockly.InsertionMarkerManager.prototype.highlightBlock_ = function() { /** * Get rid of the highlighting marking the block that will be replaced. + * @private */ Blockly.InsertionMarkerManager.prototype.unhighlightBlock_ = function() { var closest = this.closestConnection_; diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index 6747e1a28..13a5e4a8d 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -352,6 +352,7 @@ Blockly.CursorSvg.prototype.showCurrent_ = function() { * @param {number} width The width of the block. * @param {number} cursorOffset The extra padding for around the block. * @param {number} cursorHeight The height of the cursor. + * @private */ Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, cursorHeight) { var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) + diff --git a/core/scrollbar.js b/core/scrollbar.js index c327d8f52..4042635e9 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -255,6 +255,7 @@ Blockly.Scrollbar.prototype.origin_ = new Blockly.utils.Coordinate(0, 0); * For a horizontal scrollbar this is the x coordinate of the mouse down event; * for a vertical scrollbar it's the y coordinate of the mouse down event. * @type {Blockly.utils.Coordinate} + * @private */ Blockly.Scrollbar.prototype.startDragMouse_ = 0; @@ -359,6 +360,7 @@ Blockly.Scrollbar.prototype.dispose = function() { * Set the length of the scrollbar's handle and change the SVG attribute * accordingly. * @param {number} newLength The new scrollbar handle length in CSS pixels. + * @private */ Blockly.Scrollbar.prototype.setHandleLength_ = function(newLength) { this.handleLength_ = newLength; diff --git a/core/theme.js b/core/theme.js index b5528863f..58adea0e2 100644 --- a/core/theme.js +++ b/core/theme.js @@ -38,18 +38,21 @@ Blockly.Theme = function(blockStyles, categoryStyles, opt_componentStyles) { /** * The block styles map. * @type {!Object.} + * @private */ this.blockStyles_ = blockStyles; /** * The category styles map. * @type {!Object.} + * @private */ this.categoryStyles_ = categoryStyles; /** * The UI components styles map. * @type {!Object.} + * @private */ this.componentStyles_ = opt_componentStyles || Object.create(null); }; diff --git a/core/toolbox.js b/core/toolbox.js index 0d72efc78..046cfb345 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -531,6 +531,7 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, * @param {string} styleName Name of the style. * @param {!Blockly.tree.TreeNode} childOut The child to set the hexColour on. * @param {string} categoryName Name of the toolbox category. + * @private */ Blockly.Toolbox.prototype.setColourFromStyle_ = function( styleName, childOut, categoryName) { diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index 74e43d23b..6ba4383c2 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -325,7 +325,7 @@ Blockly.WorkspaceCommentSvg.prototype.unbindDragEvents_ = function() { } }; -/* +/** * Handle a mouse-up event while dragging a comment's border or resize handle. * @param {!Event} e Mouse up event. * @private diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 6b01121cd..dc8c3216f 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -143,6 +143,7 @@ Blockly.utils.object.inherits(Blockly.WorkspaceSvg, Blockly.Workspace); * A wrapper function called when a resize event occurs. * You can pass the result to `unbindEvent_`. * @type {Array.} + * @private */ Blockly.WorkspaceSvg.prototype.resizeHandlerWrapper_ = null; @@ -1175,6 +1176,7 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { /** * Paste the provided block onto the workspace. * @param {!Element} xmlBlock XML block element. + * @private */ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { Blockly.Events.disable(); diff --git a/demos/blockfactory/factory.js b/demos/blockfactory/factory.js index 8218846f1..77ab56ff1 100644 --- a/demos/blockfactory/factory.js +++ b/demos/blockfactory/factory.js @@ -71,7 +71,7 @@ BlockFactory.updateBlocksFlag = false; // TODO: Replace global state with parameter passed to functions. BlockFactory.updateBlocksFlagDelayed = false; -/* +/** * The starting XML for the Block Factory main workspace. Contains the * unmovable, undeletable factory_base block. */ diff --git a/demos/blockfactory/factory_utils.js b/demos/blockfactory/factory_utils.js index dfed4578e..92f5a3370 100644 --- a/demos/blockfactory/factory_utils.js +++ b/demos/blockfactory/factory_utils.js @@ -988,7 +988,7 @@ FactoryUtils.cleanXml = function(xml) { return newXml; }; -/* +/** * Checks if a block has a variable field. Blocks with variable fields cannot * be shadow blocks. * @param {Blockly.Block} block The block to check if a variable field exists. diff --git a/demos/blockfactory/workspacefactory/wfactory_controller.js b/demos/blockfactory/workspacefactory/wfactory_controller.js index c1305fde6..30f032eae 100644 --- a/demos/blockfactory/workspacefactory/wfactory_controller.js +++ b/demos/blockfactory/workspacefactory/wfactory_controller.js @@ -917,7 +917,7 @@ WorkspaceFactoryController.prototype.clearAll = function() { this.updatePreview(); }; -/* +/** * Makes the currently selected block a user-generated shadow block. These * blocks are not made into real shadow blocks, but recorded in the model * and visually marked as shadow blocks, allowing the user to move and edit @@ -1262,7 +1262,7 @@ WorkspaceFactoryController.prototype.importBlocks = function(file, format) { reader.readAsText(file); }; -/* +/** * Updates the block library category in the toolbox workspace toolbox. * @param {!Element} categoryXml XML for the block library category. * @param {!Array.} libBlockTypes Array of block types from the block @@ -1323,7 +1323,7 @@ WorkspaceFactoryController.prototype.warnForUndefinedBlocks_ = function() { } }; -/* +/** * Determines if a standard variable category is in the custom toolbox. * @return {boolean} True if a variables category is in use, false otherwise. */ diff --git a/demos/blockfactory/workspacefactory/wfactory_model.js b/demos/blockfactory/workspacefactory/wfactory_model.js index a295a496a..ff9eaff8e 100644 --- a/demos/blockfactory/workspacefactory/wfactory_model.js +++ b/demos/blockfactory/workspacefactory/wfactory_model.js @@ -390,7 +390,7 @@ WorkspaceFactoryModel.prototype.setOptions = function(options) { this.options = options; }; -/* +/** * Returns an array of all the block types currently being used in the toolbox * and the pre-loaded blocks. No duplicates. * TODO(evd2014): Move pushBlockTypesToList to FactoryUtils. diff --git a/demos/mobile/android/app/src/main/java/com/google/blockly/android/webview/JsDialogHelper.java b/demos/mobile/android/app/src/main/java/com/google/blockly/android/webview/JsDialogHelper.java index 0849d0a27..ae1f7e322 100644 --- a/demos/mobile/android/app/src/main/java/com/google/blockly/android/webview/JsDialogHelper.java +++ b/demos/mobile/android/app/src/main/java/com/google/blockly/android/webview/JsDialogHelper.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/externs/svg-externs.js b/externs/svg-externs.js index 68cd99706..5fca4dcde 100644 --- a/externs/svg-externs.js +++ b/externs/svg-externs.js @@ -1,4 +1,4 @@ -/* +/** * Copyright 2017 The Closure Compiler Authors * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/generators/php/lists.js b/generators/php/lists.js index 17b522a6c..a1d90b59f 100644 --- a/generators/php/lists.js +++ b/generators/php/lists.js @@ -20,7 +20,7 @@ * @author daarond@gmail.com (Daaron Dwyer) */ -/* +/** * Lists in PHP are known to break when non-variables are passed into blocks * that require a list. PHP, unlike other languages, passes arrays as reference * value instead of value so we are unable to support it to the extent we can diff --git a/tests/generators/index.html b/tests/generators/index.html index e1f88f22a..a7082e286 100644 --- a/tests/generators/index.html +++ b/tests/generators/index.html @@ -91,7 +91,7 @@ function start() { changeIndex(); } -/* +/** * Run this test to load all of the tests in the selected suites. The contents * will be loaded into the workspace in order. To test the generators: * - select your language from the buttons above the text area From 3c2c4677df3605ef3a27a2b9fe73b3faab95e10e Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 16 Oct 2019 12:13:37 -0500 Subject: [PATCH 049/343] Fix 55 warnings related to flyouts. (#3211) * Fix 55 warnings related to flyouts. --- core/blockly.js | 14 +++--- core/dropdowndiv.js | 5 ++- core/flyout_base.js | 25 ++++++----- core/gesture.js | 5 ++- core/inject.js | 35 ++++++++------- core/mutator.js | 24 +++++----- core/scrollbar.js | 12 +++-- core/toolbox.js | 46 ++++++++++++------- core/trashcan.js | 20 ++++++--- core/workspace.js | 9 ++++ core/workspace_drag_surface_svg.js | 6 +-- core/workspace_dragger.js | 2 +- core/workspace_svg.js | 72 +++++++++++++++++++----------- 13 files changed, 174 insertions(+), 101 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index c56224ba3..30de3b1cb 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -122,7 +122,7 @@ Blockly.EventData; /** * Returns the dimensions of the specified SVG image. - * @param {!Element} svg SVG image. + * @param {!SVGElement} svg SVG image. * @return {!Object} Contains width and height properties. */ Blockly.svgSize = function(svg) { @@ -177,11 +177,11 @@ Blockly.svgResize = function(workspace) { * Handle a key-down on SVG drawing surface. Does nothing if the main workspace * is not visible. * @param {!Event} e Key down event. - * @private + * @package */ // 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) { +Blockly.onKeyDown = function(e) { var mainWorkspace = Blockly.mainWorkspace; if (Blockly.utils.isTargetInput(e) || @@ -343,13 +343,13 @@ Blockly.hideChaff = function(opt_allowToolbox) { // For now the trashcan flyout always autocloses because it overlays the // trashcan UI (no trashcan to click to close it). if (workspace.trashcan && - workspace.trashcan.flyout_) { - workspace.trashcan.flyout_.hide(); + workspace.trashcan.flyout) { + workspace.trashcan.flyout.hide(); } var toolbox = workspace.getToolbox(); if (toolbox && - toolbox.flyout_ && - toolbox.flyout_.autoClose) { + toolbox.getFlyout() && + toolbox.getFlyout().autoClose) { toolbox.clearSelection(); } } diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 689d32a3e..68412dbee 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -259,11 +259,12 @@ Blockly.DropDownDiv.showPositionedByField = function(field, * @private */ Blockly.DropDownDiv.getScaledBboxOfBlock_ = function(block) { - var bBox = block.getSvgRoot().getBBox(); + var blockSvg = block.getSvgRoot(); + var bBox = blockSvg.getBBox(); var scale = block.workspace.scale; var scaledHeight = bBox.height * scale; var scaledWidth = bBox.width * scale; - var xy = Blockly.utils.style.getPageOffset(block.getSvgRoot()); + var xy = Blockly.utils.style.getPageOffset(blockSvg); return new Blockly.utils.Rect( xy.y, xy.y + scaledHeight, xy.x, xy.x + scaledWidth); }; diff --git a/core/flyout_base.js b/core/flyout_base.js index 35b353e6e..349322715 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -43,7 +43,8 @@ goog.require('Blockly.Xml'); /** * Class for a flyout. - * @param {!Object} workspaceOptions Dictionary of options for the workspace. + * @param {!Blockly.Options} workspaceOptions Dictionary of options for the + * workspace. * @constructor */ Blockly.Flyout = function(workspaceOptions) { @@ -228,15 +229,17 @@ Blockly.Flyout.prototype.createDom = function(tagName) { this.svgBackground_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyFlyoutBackground'}, this.svgGroup_); this.svgGroup_.appendChild(this.workspace_.createDom()); - this.workspace_.getThemeManager().subscribe(this.svgBackground_, 'flyout', 'fill'); - this.workspace_.getThemeManager().subscribe(this.svgBackground_, 'flyoutOpacity', 'fill-opacity'); + this.workspace_.getThemeManager().subscribe( + this.svgBackground_, 'flyout', 'fill'); + this.workspace_.getThemeManager().subscribe( + this.svgBackground_, 'flyoutOpacity', 'fill-opacity'); return this.svgGroup_; }; /** * Initializes the flyout. - * @param {!Blockly.Workspace} targetWorkspace The workspace in which to create - * new blocks. + * @param {!Blockly.WorkspaceSvg} targetWorkspace The workspace in which to + * create new blocks. */ Blockly.Flyout.prototype.init = function(targetWorkspace) { this.targetWorkspace_ = targetWorkspace; @@ -265,7 +268,7 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) { this.targetWorkspace_.getGesture.bind(this.targetWorkspace_); // Get variables from the main workspace rather than the target workspace. - this.workspace_.variableMap_ = this.targetWorkspace_.getVariableMap(); + this.workspace_.setVariableMap(this.targetWorkspace_.getVariableMap()); this.workspace_.createPotentialVariableMap(); }; @@ -432,7 +435,7 @@ Blockly.Flyout.prototype.hide = function() { /** * Show and populate the flyout. - * @param {!Array|string} xmlList List of blocks to show. + * @param {!Array|!NodeList|string} xmlList List of blocks to show. * Variables and procedures have a custom set of blocks. */ Blockly.Flyout.prototype.show = function(xmlList) { @@ -575,6 +578,7 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() { * @param {!SVGElement} rect The invisible rectangle under the block that acts * as a mat for that block. * @protected + * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) { this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mousedown', null, @@ -788,8 +792,8 @@ Blockly.Flyout.prototype.isScrollable = function() { /** * Copy a block from the flyout to the workspace and position it correctly. - * @param {!Blockly.Block} oldBlock The flyout block to copy. - * @return {!Blockly.Block} The new block in the main workspace. + * @param {!Blockly.BlockSvg} oldBlock The flyout block to copy. + * @return {!Blockly.BlockSvg} The new block in the main workspace. * @private */ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) { @@ -807,7 +811,8 @@ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) { // Using domToBlock instead of domToWorkspace means that the new block will be // placed at position (0, 0) in main workspace units. - var block = Blockly.Xml.domToBlock(xml, targetWorkspace); + var block = /** @type {!Blockly.BlockSvg} */ + (Blockly.Xml.domToBlock(xml, targetWorkspace)); var svgRootNew = block.getSvgRoot(); if (!svgRootNew) { throw Error('block is not rendered.'); diff --git a/core/gesture.js b/core/gesture.js index c8aadf03b..df369b9fe 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -315,6 +315,9 @@ Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) { * @private */ Blockly.Gesture.prototype.updateIsDraggingFromFlyout_ = function() { + if (!this.targetBlock_) { + return false; + } if (!this.flyout_.isBlockCreatable_(this.targetBlock_)) { return false; } @@ -621,7 +624,7 @@ Blockly.Gesture.prototype.cancel = function() { Blockly.Gesture.prototype.handleRightClick = function(e) { if (this.targetBlock_) { this.bringBlockToFront_(); - Blockly.hideChaff(this.flyout_); + Blockly.hideChaff(!!this.flyout_); this.targetBlock_.showContextMenu_(e); } else if (this.startBubble_) { this.startBubble_.showContextMenu_(e); diff --git a/core/inject.js b/core/inject.js index 2019bc1d9..1d9b72f8b 100644 --- a/core/inject.js +++ b/core/inject.js @@ -41,10 +41,10 @@ goog.require('Blockly.WorkspaceSvg'); /** * Inject a Blockly editor into the specified container element (usually a div). - * @param {!Element|string} container Containing element, or its ID, + * @param {Element|string} container Containing element, or its ID, * or a CSS selector. * @param {Object=} opt_options Optional dictionary of options. - * @return {!Blockly.Workspace} Newly created main workspace. + * @return {!Blockly.WorkspaceSvg} Newly created main workspace. */ Blockly.inject = function(container, opt_options) { Blockly.checkBlockColourConstants(); @@ -54,7 +54,7 @@ Blockly.inject = function(container, opt_options) { document.querySelector(container); } // Verify that the container is in document. - if (!Blockly.utils.dom.containsNode(document, container)) { + if (!container || !Blockly.utils.dom.containsNode(document, container)) { throw Error('Error: container is not in current document.'); } var options = new Blockly.Options(opt_options || {}); @@ -206,7 +206,7 @@ Blockly.createDom_ = function(container, options) { * for the blocks. * @param {!Blockly.WorkspaceDragSurfaceSvg} workspaceDragSurface Drag surface * SVG for the workspace. - * @return {!Blockly.Workspace} Newly created main workspace. + * @return {!Blockly.WorkspaceSvg} Newly created main workspace. * @private */ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, @@ -219,7 +219,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, if (!options.hasCategories && options.languageTree) { // Add flyout as an that is a sibling of the workspace svg. - var flyout = mainWorkspace.addFlyout_('svg'); + var flyout = mainWorkspace.addFlyout('svg'); Blockly.utils.dom.insertAfter(flyout, svg); } if (options.hasTrashcan) { @@ -385,7 +385,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, /** * Initialize Blockly with various handlers. - * @param {!Blockly.Workspace} mainWorkspace Newly created main workspace. + * @param {!Blockly.WorkspaceSvg} mainWorkspace Newly created main workspace. * @private */ Blockly.init_ = function(mainWorkspace) { @@ -393,7 +393,8 @@ Blockly.init_ = function(mainWorkspace) { var svg = mainWorkspace.getParentSvg(); // Suppress the browser's context menu. - Blockly.bindEventWithChecks_(svg.parentNode, 'contextmenu', null, + Blockly.bindEventWithChecks_( + /** @type {!Element} */ (svg.parentNode), 'contextmenu', null, function(e) { if (!Blockly.utils.isTargetInput(e)) { e.preventDefault(); @@ -411,13 +412,15 @@ Blockly.init_ = function(mainWorkspace) { Blockly.inject.bindDocumentEvents_(); if (options.languageTree) { - if (mainWorkspace.getToolbox()) { - mainWorkspace.getToolbox().init(mainWorkspace); - } else if (mainWorkspace.flyout_) { + var toolbox = mainWorkspace.getToolbox(); + var flyout = mainWorkspace.getFlyout(true); + if (toolbox) { + toolbox.init(); + } else if (flyout) { // Build a fixed flyout with the root blocks. - mainWorkspace.flyout_.init(mainWorkspace); - mainWorkspace.flyout_.show(options.languageTree.childNodes); - mainWorkspace.flyout_.scrollToStart(); + flyout.init(mainWorkspace); + flyout.show(options.languageTree.childNodes); + flyout.scrollToStart(); } } @@ -452,6 +455,7 @@ Blockly.init_ = function(mainWorkspace) { * Also, 'keydown' has to be on the whole document since the browser doesn't * understand a concept of focus on the SVG image. * @private + * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.inject.bindDocumentEvents_ = function() { if (!Blockly.documentEventsBound_) { @@ -463,7 +467,7 @@ Blockly.inject.bindDocumentEvents_ = function() { } } }); - Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown_); + Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown); // longStop needs to run to stop the context menu from showing up. It // should run regardless of what other touch event handlers have run. Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); @@ -473,7 +477,8 @@ Blockly.inject.bindDocumentEvents_ = function() { Blockly.bindEventWithChecks_(window, 'orientationchange', document, function() { // TODO (#397): Fix for multiple Blockly workspaces. - Blockly.svgResize(Blockly.getMainWorkspace()); + Blockly.svgResize(/** @type {!Blockly.WorkspaceSvg} */ + (Blockly.getMainWorkspace())); }); } } diff --git a/core/mutator.js b/core/mutator.js index 8b6bbd7d8..af5d9e0b9 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -141,7 +141,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { } else { var quarkXml = null; } - var workspaceOptions = { + var workspaceOptions = /** @type {!Blockly.Options} */ ({ // If you want to enable disabling, also remove the // event filter from workspaceChanged_ . disable: false, @@ -156,7 +156,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { getMetrics: this.getFlyoutMetrics_.bind(this), setMetrics: null, renderer: this.block_.workspace.options.renderer - }; + }); this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions); this.workspace_.isMutator = true; this.workspace_.addChangeListener(Blockly.Events.disableOrphans); @@ -165,7 +165,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { // 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 = this.workspace_.addFlyout_('g'); + var flyoutSvg = this.workspace_.addFlyout('g'); var background = this.workspace_.createDom('blocklyMutatorBackground'); // Insert the flyout after the but before the block canvas so that @@ -215,8 +215,9 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { width = workspaceSize.width + workspaceSize.x; } var height = workspaceSize.height + doubleBorderWidth * 3; - if (this.workspace_.flyout_) { - var flyoutMetrics = this.workspace_.flyout_.getMetrics_(); + var flyout = this.workspace_.getFlyout(); + if (flyout) { + var flyoutMetrics = flyout.getMetrics_(); height = Math.max(height, flyoutMetrics.contentHeight + 20); } width += doubleBorderWidth * 3; @@ -260,9 +261,10 @@ Blockly.Mutator.prototype.setVisible = function(visible) { // Expose this mutator's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); var tree = this.workspace_.options.languageTree; + var flyout = this.workspace_.getFlyout(); if (tree) { - this.workspace_.flyout_.init(this.workspace_); - this.workspace_.flyout_.show(tree.childNodes); + flyout.init(this.workspace_); + flyout.show(tree.childNodes); } this.rootBlock_ = this.block_.decompose(this.workspace_); @@ -273,9 +275,9 @@ Blockly.Mutator.prototype.setVisible = function(visible) { // The root block should not be dragable or deletable. this.rootBlock_.setMovable(false); this.rootBlock_.setDeletable(false); - if (this.workspace_.flyout_) { - var margin = this.workspace_.flyout_.CORNER_RADIUS * 2; - var x = this.workspace_.getFlyout().getWidth() + margin; + if (flyout) { + var margin = flyout.CORNER_RADIUS * 2; + var x = flyout.getWidth() + margin; } else { var margin = 16; var x = margin; @@ -427,7 +429,7 @@ Blockly.Mutator.prototype.updateBlockStyle = function() { block.setStyle(block.getStyleName()); } - var flyoutBlocks = ws.flyout_.workspace_.getAllBlocks(false); + var flyoutBlocks = ws.getFlyout().workspace_.getAllBlocks(false); for (var i = 0; i < flyoutBlocks.length; i++) { var block = flyoutBlocks[i]; block.setStyle(block.getStyleName()); diff --git a/core/scrollbar.js b/core/scrollbar.js index 4042635e9..92ae14164 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -627,9 +627,12 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { 'ry': radius }, this.svgGroup_); - this.workspace_.getThemeManager().subscribe(this.svgHandle_, 'scrollbar', 'fill'); - this.workspace_.getThemeManager().subscribe(this.svgHandle_, 'scrollbarOpacity', 'fill-opacity'); - Blockly.utils.dom.insertAfter(this.outerSvg_, this.workspace_.getParentSvg()); + this.workspace_.getThemeManager().subscribe( + this.svgHandle_, 'scrollbar', 'fill'); + this.workspace_.getThemeManager().subscribe( + this.svgHandle_, 'scrollbarOpacity', 'fill-opacity'); + Blockly.utils.dom.insertAfter(this.outerSvg_, + this.workspace_.getParentSvg()); }; /** @@ -711,7 +714,8 @@ Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) { e.stopPropagation(); return; } - var mouseXY = Blockly.utils.mouseToSvg(e, this.workspace_.getParentSvg(), + var mouseXY = Blockly.utils.mouseToSvg(e, + this.workspace_.getParentSvg(), this.workspace_.getInverseScreenCTM()); var mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y; diff --git a/core/toolbox.js b/core/toolbox.js index 046cfb345..448eded68 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -110,6 +110,13 @@ Blockly.Toolbox = function(workspace) { 'blocklyHorizontalTreeRtl' : 'blocklyHorizontalTree'); this.config_['cssTreeIcon'] = ''; } + + /** + * The toolbox flyout. + * @type {Blockly.Flyout} + * @private + */ + this.flyout_ = null; }; /** @@ -140,6 +147,8 @@ Blockly.Toolbox.prototype.lastCategory_ = null; /** * Initializes the toolbox. + * @throws {Error} If missing a require for both `Blockly.HorizontalFlyout` and + * `Blockly.VerticalFlyout`. */ Blockly.Toolbox.prototype.init = function() { var workspace = this.workspace_; @@ -178,11 +187,6 @@ Blockly.Toolbox.prototype.init = function() { toolboxPosition: workspace.options.toolboxPosition, renderer: workspace.options.renderer }; - /** - * @type {!Blockly.Flyout} - * @private - */ - this.flyout_ = null; if (workspace.horizontalLayout) { if (!Blockly.HorizontalFlyout) { throw Error('Missing require for Blockly.HorizontalFlyout'); @@ -194,9 +198,13 @@ Blockly.Toolbox.prototype.init = function() { } this.flyout_ = new Blockly.VerticalFlyout(workspaceOptions); } + if (!this.flyout_) { + throw Error('One of Blockly.VerticalFlyout or Blockly.Horizontal must be' + + 'required.'); + } + // Insert the flyout after the workspace. - Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), - this.workspace_.getParentSvg()); + Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), svg); this.flyout_.init(workspace); this.config_['cleardotPath'] = workspace.options.pathToMedia + '1x1.gif'; @@ -207,7 +215,7 @@ Blockly.Toolbox.prototype.init = function() { /** * Fill the toolbox with categories and blocks. - * @param {!Node} languageTree DOM tree of blocks. + * @param {Node} languageTree DOM tree of blocks. * @package */ Blockly.Toolbox.prototype.renderTree = function(languageTree) { @@ -225,8 +233,8 @@ Blockly.Toolbox.prototype.renderTree = function(languageTree) { if (languageTree) { this.tree_.blocks = []; this.hasColours_ = false; - var openNode = - this.syncTrees_(languageTree, this.tree_, this.workspace_.options.pathToMedia); + openNode = this.syncTrees_( + languageTree, this.tree_, this.workspace_.options.pathToMedia); if (this.tree_.blocks.length) { throw Error('Toolbox cannot have both blocks and categories ' + @@ -245,7 +253,8 @@ Blockly.Toolbox.prototype.renderTree = function(languageTree) { // Trees have an implicit orientation of vertical, so we only need to set this // when the toolbox is in horizontal mode. if (this.horizontalLayout_) { - Blockly.utils.aria.setState(/** @type {!Element} */ (this.tree_.getElement()), + Blockly.utils.aria.setState( + /** @type {!Element} */ (this.tree_.getElement()), Blockly.utils.aria.State.ORIENTATION, 'horizontal'); } }; @@ -353,7 +362,6 @@ Blockly.Toolbox.prototype.dispose = function() { this.tree_.dispose(); this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv); Blockly.utils.dom.removeNode(this.HtmlDiv); - this.workspace_ = null; this.lastCategory_ = null; }; @@ -373,6 +381,14 @@ Blockly.Toolbox.prototype.getHeight = function() { return this.height; }; +/** + * Get the toolbox flyout. + * @return {Blockly.Flyout} The toolbox flyout. + */ +Blockly.Toolbox.prototype.getFlyout = function() { + return this.flyout_; +}; + /** * Move the toolbox to the edge. */ @@ -382,8 +398,7 @@ Blockly.Toolbox.prototype.position = function() { // Not initialized yet. return; } - var svg = this.workspace_.getParentSvg(); - var svgSize = Blockly.svgSize(svg); + var svgSize = Blockly.svgSize(this.workspace_.getParentSvg()); if (this.horizontalLayout_) { treeDiv.style.left = '0'; treeDiv.style.height = 'auto'; @@ -474,7 +489,8 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) { // Separator between two categories. // treeOut.add(new Blockly.Toolbox.TreeSeparator( - /** @type {!Blockly.tree.BaseNode.Config} */ (this.treeSeparatorConfig_))); + /** @type {!Blockly.tree.BaseNode.Config} */ + (this.treeSeparatorConfig_))); break; } // Otherwise falls through. diff --git a/core/trashcan.js b/core/trashcan.js index a452d2004..fecc23a06 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -31,13 +31,13 @@ goog.require('Blockly.Xml'); /** * Class for a trash can. - * @param {!Blockly.Workspace} workspace The workspace to sit in. + * @param {!Blockly.WorkspaceSvg} workspace The workspace to sit in. * @constructor */ Blockly.Trashcan = function(workspace) { /** * The workspace the trashcan sits in. - * @type {!Blockly.Workspace} + * @type {!Blockly.WorkspaceSvg} * @private */ this.workspace_ = workspace; @@ -49,6 +49,12 @@ Blockly.Trashcan = function(workspace) { */ this.contents_ = []; + /** + * The trashcan flyout. + * @type {Blockly.Flyout} + * @package + */ + this.flyout = null; if (this.workspace_.options.maxTrashcanContents <= 0) { return; @@ -70,7 +76,7 @@ Blockly.Trashcan = function(workspace) { if (!Blockly.HorizontalFlyout) { throw Error('Missing require for Blockly.HorizontalFlyout'); } - this.flyout_ = new Blockly.HorizontalFlyout(flyoutWorkspaceOptions); + this.flyout = new Blockly.HorizontalFlyout(flyoutWorkspaceOptions); } else { flyoutWorkspaceOptions.toolboxPosition = this.workspace_.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT ? @@ -78,7 +84,7 @@ Blockly.Trashcan = function(workspace) { if (!Blockly.VerticalFlyout) { throw Error('Missing require for Blockly.VerticalFlyout'); } - this.flyout_ = new Blockly.VerticalFlyout(flyoutWorkspaceOptions); + this.flyout = new Blockly.VerticalFlyout(flyoutWorkspaceOptions); } this.workspace_.addChangeListener(this.onDelete_.bind(this)); }; @@ -284,9 +290,9 @@ Blockly.Trashcan.prototype.createDom = function() { */ Blockly.Trashcan.prototype.init = function(verticalSpacing) { if (this.workspace_.options.maxTrashcanContents > 0) { - Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), + Blockly.utils.dom.insertAfter(this.flyout.createDom('svg'), this.workspace_.getParentSvg()); - this.flyout_.init(this.workspace_); + this.flyout.init(this.workspace_); } this.verticalSpacing_ = this.MARGIN_BOTTOM_ + verticalSpacing; @@ -426,7 +432,7 @@ Blockly.Trashcan.prototype.click = function() { for (var i = 0, text; text = this.contents_[i]; i++) { xml[i] = Blockly.Xml.textToDom(text); } - this.flyout_.show(xml); + this.flyout.show(xml); }; /** diff --git a/core/workspace.js b/core/workspace.js index cefd46038..32cbbdd00 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -848,6 +848,15 @@ Blockly.Workspace.prototype.getVariableMap = function() { return this.variableMap_; }; +/** + * Set the map of all variables on the workspace. + * @param {Blockly.VariableMap} variableMap The variable map. + * @package + */ +Blockly.Workspace.prototype.setVariableMap = function(variableMap) { + this.variableMap_ = variableMap; +}; + /** * Database of all workspaces. * @private diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index 9e33f2ae7..70a5dd360 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -121,7 +121,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) { * @package */ Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() { - return Blockly.utils.getRelativeXY(this.SVG_); + return Blockly.utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); }; /** @@ -136,8 +136,8 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { throw Error('Couldn\'t clear and hide the drag surface: missing ' + 'new surface.'); } - var blockCanvas = this.SVG_.childNodes[0]; - var bubbleCanvas = this.SVG_.childNodes[1]; + var blockCanvas = /** @type {!Element} */ (this.SVG_.childNodes[0]); + var bubbleCanvas = /** @type {!Element} */ (this.SVG_.childNodes[1]); if (!blockCanvas || !bubbleCanvas || !Blockly.utils.dom.hasClass(blockCanvas, 'blocklyBlockCanvas') || !Blockly.utils.dom.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) { diff --git a/core/workspace_dragger.js b/core/workspace_dragger.js index 67527322f..01b97955f 100644 --- a/core/workspace_dragger.js +++ b/core/workspace_dragger.js @@ -46,7 +46,7 @@ Blockly.WorkspaceDragger = function(workspace) { * The scroll position of the workspace at the beginning of the drag. * Coordinate system: pixel coordinates. * @type {!Blockly.utils.Coordinate} - * @private + * @protected */ this.startScrollXY_ = new Blockly.utils.Coordinate( workspace.scrollX, workspace.scrollY); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index dc8c3216f..b16fe82a6 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -136,6 +136,13 @@ Blockly.WorkspaceSvg = function(options, * @private */ this.renderer_ = Blockly.blockRendering.init(this.options.renderer || 'geras'); + + /** + * Cached parent SVG. + * @type {SVGElement} + * @private + */ + this.cachedParentSvg_ = null; }; Blockly.utils.object.inherits(Blockly.WorkspaceSvg, Blockly.Workspace); @@ -346,7 +353,7 @@ Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_ = false; /** * The first parent div with 'injectionDiv' in the name, or null if not set. * Access this with getInjectionDiv. - * @type {!Element} + * @type {Element} * @private */ Blockly.WorkspaceSvg.prototype.injectionDiv_ = null; @@ -355,7 +362,7 @@ Blockly.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 {Blockly.utils.Coordinate} * @private */ Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; @@ -381,7 +388,7 @@ Blockly.WorkspaceSvg.prototype.toolboxCategoryCallbacks_ = {}; * workspace's context menu or edit the workspace-created set of menu options. * @param {!Array.} options List of menu options to add to. */ -Blockly.WorkspaceSvg.prototype.configureContextMenu = null; +Blockly.WorkspaceSvg.prototype.configureContextMenu; /** * In a flyout, the target workspace where blocks should be placed after a drag. @@ -545,7 +552,7 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { } x += xy.x * scale; y += xy.y * scale; - element = element.parentNode; + element = /** @type {!Element} */ (element.parentNode); } while (element && element != this.getParentSvg()); return new Blockly.utils.Coordinate(x, y); }; @@ -565,6 +572,8 @@ Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { /** * Return the injection div that is a parent of this workspace. * Walks the DOM the first time it's called, then returns a cached value. + * Note: We assume this is only called after the workspace has been injected + * into the DOM. * @return {!Element} The first parent div with 'injectionDiv' in the name. * @package */ @@ -579,10 +588,10 @@ Blockly.WorkspaceSvg.prototype.getInjectionDiv = function() { this.injectionDiv_ = element; break; } - element = element.parentNode; + element = /** @type {!Element} */ (element.parentNode); } } - return this.injectionDiv_; + return /** @type {!Element} */ (this.injectionDiv_); }; /** @@ -790,9 +799,9 @@ Blockly.WorkspaceSvg.prototype.addZoomControls = function() { * Add a flyout element in an element with the given tag name. * @param {string} tagName What type of tag the flyout belongs in. * @return {!Element} The element containing the flyout DOM. - * @private + * @package */ -Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) { +Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { var workspaceOptions = { disabledPatternId: this.options.disabledPatternId, parentWorkspace: this, @@ -825,15 +834,16 @@ Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) { * Getter for the flyout associated with this workspace. This flyout may be * 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 Only return the workspace's own flyout if True. * @return {Blockly.Flyout} The flyout on this workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getFlyout = function() { - if (this.flyout_) { +Blockly.WorkspaceSvg.prototype.getFlyout = function(opt_own) { + if (this.flyout_ || opt_own) { return this.flyout_; } if (this.toolbox_) { - return this.toolbox_.flyout_; + return this.toolbox_.getFlyout(); } return null; }; @@ -935,21 +945,22 @@ Blockly.WorkspaceSvg.prototype.getBubbleCanvas = function() { /** * Get the SVG element that contains this workspace. - * @return {SVGElement} SVG element. + * Note: We assume this is only called after the workspace has been injected + * into the DOM. + * @return {!SVGElement} SVG element. */ Blockly.WorkspaceSvg.prototype.getParentSvg = function() { - if (this.cachedParentSvg_) { - return this.cachedParentSvg_; - } - var element = this.svgGroup_; - while (element) { - if (element.tagName == 'svg') { - this.cachedParentSvg_ = element; - return element; + if (!this.cachedParentSvg_) { + var element = this.svgGroup_; + while (element) { + if (element.tagName == 'svg') { + this.cachedParentSvg_ = element; + break; + } + element = /** @type {!SVGElement} */ (element.parentNode); } - element = /** @type {!SVGElement} */ (element.parentNode); } - return null; + return /** @type {!SVGElement} */ (this.cachedParentSvg_); }; /** @@ -1283,7 +1294,7 @@ Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { */ Blockly.WorkspaceSvg.prototype.refreshToolboxSelection = function() { var ws = this.isFlyout ? this.targetWorkspace : this; - if (ws && !ws.currentGesture_ && ws.toolbox_ && ws.toolbox_.flyout_) { + if (ws && !ws.currentGesture_ && ws.toolbox_ && ws.toolbox_.getFlyout()) { ws.toolbox_.refreshSelection(); } }; @@ -1889,9 +1900,9 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() { // the flyout, and the area we want to fit them includes the portion of // the workspace that is behind the flyout. if (this.horizontalLayout) { - workspaceHeight += this.flyout_.height_; + workspaceHeight += this.flyout_.getHeight(); // Convert from pixels to workspace coordinates. - blocksHeight += this.flyout_.height_ / this.scale; + blocksHeight += this.flyout_.getHeight() / this.scale; } else { workspaceWidth += this.flyout_.getWidth(); // Convert from pixels to workspace coordinates. @@ -2353,6 +2364,17 @@ Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { this.translate(x, y); }; +/** + * 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. + * @override + */ +Blockly.WorkspaceSvg.prototype.getTopBlocks = function(ordered) { + return Blockly.WorkspaceSvg.superClass_.getTopBlocks.call(this, ordered); +}; + /** * Update whether this workspace has resizes enabled. * If enabled, workspace will resize when appropriate. From 90f529603ee3d81b90913f98175cb06fd6ef4032 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 16 Oct 2019 11:17:59 -0600 Subject: [PATCH 050/343] Review feedback --- gulpfile.js | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 752430613..32fe0cfef 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -772,7 +772,7 @@ gulp.task('release', gulp.series(['build', 'typings', function() { gulp.task('default', gulp.series(['build'])); // Stash current state, check out develop, and sync with google/blockly. -gulp.task('syncDevelop', function(done) { +gulp.task('git-sync-develop', function(done) { execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); execSync('git checkout develop', { stdio: 'inherit' }); execSync('git pull https://github.com/google/blockly.git develop', @@ -788,33 +788,27 @@ function getRebuildBranchName() { var dd = date.getDate(); // Day of the month, 1-31 var yyyy = date.getFullYear(); return 'rebuild_' + mm + '_' + dd + '_' + yyyy; -} - -// Stash and make a new branch for a rebuild. -gulp.task('make-rebuild-branch', function(done) { - execSync('git stash save -m "Stash for rebuild"', { stdio: 'inherit' }); - var branchName = getRebuildBranchName(); - console.log('make-rebuild-branch: creating branch ' + branchName); - execSync('git checkout -b ' + branchName, { stdio: 'inherit' }); - done(); -}); - -// Commit and push the current rebuild branch. -gulp.task('push-rebuild-branch', function(done) { - console.log('push-rebuild-branch: committing rebuild'); - execSync('git commit -am "Rebuild"', { stdio: 'inherit' }); - var branchName = getRebuildBranchName(); - execSync('git push origin ' + branchName, { stdio: 'inherit' }); - console.log('Branch ' + branchName + ' pushed to GitHub.'); - console.log('Next step: create a pull request against develop.'); - done(); -}); +}; // Recompile and push to origin. -gulp.task('recompile', gulp.series[ - 'syncDevelop', - 'make-rebuild-branch' +gulp.task('recompile', gulp.series([ + 'git-sync-develop', + function(done) { + execSync('git stash save -m "Stash for rebuild"', { stdio: 'inherit' }); + var branchName = getRebuildBranchName(); + console.log('make-rebuild-branch: creating branch ' + branchName); + execSync('git checkout -b ' + branchName, { stdio: 'inherit' }); + done(); + }, 'build', - 'push-rebuild-branch' - ] + function(done) { + console.log('push-rebuild-branch: committing rebuild'); + execSync('git commit -am "Rebuild"', { stdio: 'inherit' }); + var branchName = getRebuildBranchName(); + execSync('git push origin ' + branchName, { stdio: 'inherit' }); + console.log('Branch ' + branchName + ' pushed to GitHub.'); + console.log('Next step: create a pull request against develop.'); + done(); + } + ]) ); From 17f47ee2cb2a42adbd6ab55c67e820caf956154a Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 16 Oct 2019 11:29:54 -0600 Subject: [PATCH 051/343] Make git-sync-master as well as git-sync-develop --- gulpfile.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 32fe0cfef..93e9ed9ab 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -771,15 +771,25 @@ gulp.task('release', gulp.series(['build', 'typings', function() { // The default task builds Blockly. gulp.task('default', gulp.series(['build'])); + +// Stash current state, check out the named branch, and sync with +// google/blockly. +function syncBranch(branchName) { + return function(done) { + execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); + execSync('git checkout ' + branchName, { stdio: 'inherit' }); + execSync('git pull https://github.com/google/blockly.git ' + branchName, + { stdio: 'inherit' }); + execSync('git push origin ' + branchName, { stdio: 'inherit' }); + done(); + } +} + // Stash current state, check out develop, and sync with google/blockly. -gulp.task('git-sync-develop', function(done) { - execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); - execSync('git checkout develop', { stdio: 'inherit' }); - execSync('git pull https://github.com/google/blockly.git develop', - { stdio: 'inherit' }); - execSync('git push origin develop', { stdio: 'inherit' }); - done(); -}); +gulp.task('git-sync-develop', syncBranch('develop')); + +// Stash current state, check out master, and sync with google/blockly. +gulp.task('git-sync-master', syncBranch('master')); // Helper function: get a name for a rebuild branch. Format: rebuild_mm_dd_yyyy. function getRebuildBranchName() { From 35e894af13bb1cdc661ff7698ddaf38679a6ed3c Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 16 Oct 2019 11:53:08 -0600 Subject: [PATCH 052/343] Fix #1714 --- core/xml.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/xml.js b/core/xml.js index 710b8d5ac..e25a2c703 100644 --- a/core/xml.js +++ b/core/xml.js @@ -389,10 +389,6 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { } var newBlockIds = []; // A list of block IDs added by this call. Blockly.utils.dom.startTextWidthCache(); - // Safari 7.1.3 is known to provide node lists with extra references to - // children beyond the lists' length. Trust the length, do not use the - // looping pattern of checking the index for an object. - var childCount = xml.childNodes.length; var existingGroup = Blockly.Events.getGroup(); if (!existingGroup) { Blockly.Events.setGroup(true); @@ -404,8 +400,7 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { } var variablesFirst = true; try { - for (var i = 0; i < childCount; i++) { - var xmlChild = xml.childNodes[i]; + for (var i = 0, xmlChild; xmlChild = xml.childNodes[i]; i++) { var name = xmlChild.nodeName.toLowerCase(); if (name == 'block' || (name == 'shadow' && !Blockly.Events.recordUndo)) { From 8407428e8f4e6af2ac96bce8bc6300f623d840b4 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 16 Oct 2019 14:54:47 -0700 Subject: [PATCH 053/343] Reverted scrollbar resize change. (#3274) --- core/workspace_svg.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/workspace_svg.js b/core/workspace_svg.js index b16fe82a6..9f75e6520 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -878,9 +878,7 @@ Blockly.WorkspaceSvg.prototype.resizeContents = function() { return; } if (this.scrollbar) { - var metrics = this.getMetrics(); - this.scrollbar.hScroll.resizeContentHorizontal(metrics); - this.scrollbar.vScroll.resizeContentVertical(metrics); + this.scrollbar.resize(); } this.updateInverseScreenCTM(); }; From c1c9121fcc22fa32f0f298fd31779c1a06c5aec3 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 16 Oct 2019 17:01:36 -0500 Subject: [PATCH 054/343] Fix jsdoc. @return instead of @returns (#3271) * Fix jsdoc. @return instead of @returns --- core/field_textinput.js | 4 ++-- core/renderers/measurables/rows.js | 4 ++-- core/renderers/zelos/measurables/rows.js | 4 ++-- demos/custom-fields/pitch/field_pitch.js | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/field_textinput.js b/core/field_textinput.js index 2d7d3b762..2fb87c2e2 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -528,7 +528,7 @@ Blockly.FieldTextInput.prototype.getText_ = function() { * than the field's value. This should be coupled with an override of * `getValueFromEditorText_`. * @param {*} value The value stored in this field. - * @returns {string} The text to show on the html input. + * @return {string} The text to show on the html input. * @protected */ Blockly.FieldTextInput.prototype.getEditorText_ = function(value) { @@ -542,7 +542,7 @@ Blockly.FieldTextInput.prototype.getEditorText_ = function(value) { * than the field's value. This should be coupled with an override of * `getEditorText_`. * @param {string} text Text received from the html input. - * @returns {*} The value to store. + * @return {*} The value to store. * @protected */ Blockly.FieldTextInput.prototype.getValueFromEditorText_ = function(text) { diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index 7b85ae0f0..b998eb7f3 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -280,7 +280,7 @@ Blockly.utils.object.inherits(Blockly.blockRendering.TopRow, /** * Returns whether or not the top row has a left square corner. * @param {!Blockly.BlockSvg} block The block whose top row this represents. - * @returns {boolean} Whether or not the top row has a left square corner. + * @return {boolean} Whether or not the top row has a left square corner. */ Blockly.blockRendering.TopRow.prototype.hasLeftSquareCorner = function(block) { var hasHat = block.hat ? block.hat === 'cap' : Blockly.BlockSvg.START_HAT; @@ -372,7 +372,7 @@ Blockly.utils.object.inherits(Blockly.blockRendering.BottomRow, /** * Returns whether or not the bottom row has a left square corner. * @param {!Blockly.BlockSvg} block The block whose bottom row this represents. - * @returns {boolean} Whether or not the bottom row has a left square corner. + * @return {boolean} Whether or not the bottom row has a left square corner. */ Blockly.blockRendering.BottomRow.prototype.hasLeftSquareCorner = function( block) { diff --git a/core/renderers/zelos/measurables/rows.js b/core/renderers/zelos/measurables/rows.js index 376fa90e3..8fa9e495d 100644 --- a/core/renderers/zelos/measurables/rows.js +++ b/core/renderers/zelos/measurables/rows.js @@ -70,7 +70,7 @@ Blockly.zelos.TopRow.prototype.hasLeftSquareCorner = function(block) { /** * Returns whether or not the top row has a right square corner. * @param {!Blockly.BlockSvg} block The block whose top row this represents. - * @returns {boolean} Whether or not the top row has a left square corner. + * @return {boolean} Whether or not the top row has a left square corner. */ Blockly.zelos.TopRow.prototype.hasRightSquareCorner = function(block) { // Render a round corner unless the block has an output connection. @@ -112,7 +112,7 @@ Blockly.zelos.BottomRow.prototype.hasLeftSquareCorner = function(block) { /** * Returns whether or not the bottom row has a right square corner. * @param {!Blockly.BlockSvg} block The block whose bottom row this represents. - * @returns {boolean} Whether or not the bottom row has a left square corner. + * @return {boolean} Whether or not the bottom row has a left square corner. */ Blockly.zelos.BottomRow.prototype.hasRightSquareCorner = function(block) { // Render a round corner unless the block has an output connection. diff --git a/demos/custom-fields/pitch/field_pitch.js b/demos/custom-fields/pitch/field_pitch.js index b69789d52..f5bdf505b 100644 --- a/demos/custom-fields/pitch/field_pitch.js +++ b/demos/custom-fields/pitch/field_pitch.js @@ -173,7 +173,7 @@ CustomFields.FieldPitch.prototype.getText_ = function() { /** * Transform the provided value into a text to show in the HTML input. * @param {*} value The value stored in this field. - * @returns {string} The text to show on the HTML input. + * @return {string} The text to show on the HTML input. */ CustomFields.FieldPitch.prototype.getEditorText_ = function(value) { return this.valueToNote(value); @@ -183,7 +183,7 @@ CustomFields.FieldPitch.prototype.getEditorText_ = function(value) { * Transform the text received from the HTML input (note) into a value * to store in this field. * @param {string} text Text received from the HTML input. - * @returns {*} The value to store. + * @return {*} The value to store. */ CustomFields.FieldPitch.prototype.getValueFromEditorText_ = function(text) { return this.noteToValue(text); From 90f6948c275ffbe8b316c9a7235bab09a9f031eb Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 17 Oct 2019 10:21:55 -0600 Subject: [PATCH 055/343] Remove unnecessary stash --- gulpfile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index 93e9ed9ab..b6bc06afc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -804,7 +804,6 @@ function getRebuildBranchName() { gulp.task('recompile', gulp.series([ 'git-sync-develop', function(done) { - execSync('git stash save -m "Stash for rebuild"', { stdio: 'inherit' }); var branchName = getRebuildBranchName(); console.log('make-rebuild-branch: creating branch ' + branchName); execSync('git checkout -b ' + branchName, { stdio: 'inherit' }); From 7f41532717ce2516763a4c78de0647166980f36c Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 11:44:41 -0500 Subject: [PATCH 056/343] Print the output of the closure compiler in the console after a debug compile. (#3272) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ba3270c6..41f86d187 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "scripts": { "build": "gulp build", - "build:debug": "gulp build-core --verbose > build-debug.log 2>&1", + "build:debug": "gulp build-core --verbose > build-debug.log 2>&1 && tail -3 -r build-debug.log", "lint": "eslint .", "package": "gulp package", "prepare": "npm run package", From 526528354f70ea5e4e276dbee3ebe08ba8d3568a Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 11:46:57 -0500 Subject: [PATCH 057/343] Fix 10 warnings related to visibility (#3275) --- core/block.js | 2 +- core/block_svg.js | 6 +++--- core/blockly.js | 4 ++-- core/connection.js | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/block.js b/core/block.js index 1d4b50163..9a439349d 100644 --- a/core/block.js +++ b/core/block.js @@ -496,7 +496,7 @@ 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. - * @private + * @package */ Blockly.Block.prototype.getConnections_ = function(_all) { var myConnections = []; diff --git a/core/block_svg.js b/core/block_svg.js index 92cbd4d84..81bbbffde 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -899,12 +899,12 @@ Blockly.BlockSvg.prototype.setDragging = function(adding) { var group = this.getSvgRoot(); group.translate_ = ''; group.skew_ = ''; - Blockly.draggingConnections_ = - Blockly.draggingConnections_.concat(this.getConnections_(true)); + Blockly.draggingConnections = + Blockly.draggingConnections.concat(this.getConnections_(true)); Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } else { - Blockly.draggingConnections_ = []; + Blockly.draggingConnections = []; Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } diff --git a/core/blockly.js b/core/blockly.js index 30de3b1cb..856ef4b62 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -81,9 +81,9 @@ Blockly.keyboardAccessibilityMode = false; /** * All of the connections on blocks that are currently being dragged. * @type {!Array.} - * @private + * @package */ -Blockly.draggingConnections_ = []; +Blockly.draggingConnections = []; /** * Contents of the local clipboard. diff --git a/core/connection.js b/core/connection.js index cbe6a217a..8a2e87086 100644 --- a/core/connection.js +++ b/core/connection.js @@ -328,7 +328,7 @@ Blockly.Connection.prototype.canConnectToPrevious_ = function(candidate) { } // Don't let blocks try to connect to themselves or ones they nest. - if (Blockly.draggingConnections_.indexOf(candidate) != -1) { + if (Blockly.draggingConnections.indexOf(candidate) != -1) { return false; } @@ -405,7 +405,7 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) { } // Don't let blocks try to connect to themselves or ones they nest. - if (Blockly.draggingConnections_.indexOf(candidate) != -1) { + if (Blockly.draggingConnections.indexOf(candidate) != -1) { return false; } From 664cc3d6cd7493131720710691f9c891c528abeb Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 11:47:30 -0500 Subject: [PATCH 058/343] Fix warnings related to number of arguments passed. (#3270) --- blocks/procedures.js | 2 +- core/block_svg.js | 4 ++-- core/blockly.js | 3 ++- core/connection.js | 4 ++-- core/generator.js | 6 ++++-- core/insertion_marker_manager.js | 2 +- core/variable_map.js | 2 +- core/workspace.js | 6 +++--- 8 files changed, 16 insertions(+), 13 deletions(-) diff --git a/blocks/procedures.js b/blocks/procedures.js index 761e4877d..4b6e44975 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -942,7 +942,7 @@ Blockly.Blocks['procedures_callnoreturn'] = { var def = Blockly.Procedures.getDefinition(name, this.workspace); if (!def) { Blockly.Events.setGroup(event.group); - this.dispose(true, false); + this.dispose(true); Blockly.Events.setGroup(false); } } else if (event.type == Blockly.Events.CHANGE && event.element == 'disabled') { diff --git a/core/block_svg.js b/core/block_svg.js index 81bbbffde..c9859f334 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -577,7 +577,7 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { * @return {!Blockly.utils.Rect} Object with coordinates of the bounding box. */ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { - var blockXY = this.getRelativeToSurfaceXY(this); + var blockXY = this.getRelativeToSurfaceXY(); var tab = this.outputConnection ? Blockly.BlockSvg.TAB_WIDTH : 0; var blockBounds = this.getHeightWidth(); var top = blockXY.y; @@ -1513,7 +1513,7 @@ Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { */ Blockly.BlockSvg.prototype.waitToTrackConnections = function() { this.callTrackConnections_ = false; - var children = this.getChildren(); + var children = this.getChildren(false); for (var i = 0, child; child = children[i]; i++) { child.waitToTrackConnections(); } diff --git a/core/blockly.js b/core/blockly.js index 856ef4b62..e37078bb5 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -269,7 +269,8 @@ Blockly.onKeyDown = function(e) { if (deleteBlock && !Blockly.selected.workspace.isFlyout) { Blockly.Events.setGroup(true); Blockly.hideChaff(); - Blockly.selected.dispose(/* heal */ true, true); + var selected = /** @type {!Blockly.BlockSvg} */ (Blockly.selected); + selected.dispose(/* heal */ true, true); Blockly.Events.setGroup(false); } }; diff --git a/core/connection.js b/core/connection.js index 8a2e87086..c8a4d2879 100644 --- a/core/connection.js +++ b/core/connection.js @@ -121,7 +121,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) { if (orphanBlock.isShadow()) { // Save the shadow block so that field values are preserved. shadowDom = Blockly.Xml.blockToDom(orphanBlock); - orphanBlock.dispose(); + orphanBlock.dispose(false); orphanBlock = null; } else if (parentConnection.type == Blockly.INPUT_VALUE) { // Value connections. @@ -212,7 +212,7 @@ Blockly.Connection.prototype.dispose = function() { var targetBlock = this.targetBlock(); if (targetBlock.isShadow()) { // Destroy the attached shadow block & its children. - targetBlock.dispose(); + targetBlock.dispose(false); } else { // Disconnect the attached normal block. targetBlock.unplug(); diff --git a/core/generator.js b/core/generator.js index fee9478b6..7ae832e1e 100644 --- a/core/generator.js +++ b/core/generator.js @@ -431,10 +431,12 @@ Blockly.Generator.prototype.init = function(_workspace) { * value blocks. * @param {!Blockly.Block} _block The current block. * @param {string} code The code created for this block. + * @param {boolean=} _opt_thisOnly True to generate code for only this + * statement. * @return {string} Code with comments and subsequent blocks added. - * @private + * @protected */ -Blockly.Generator.prototype.scrub_ = function(_block, code) { +Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) { // Optionally override return code; }; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index c936aed43..3e9c234f0 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -247,7 +247,7 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo Blockly.Events.disable(); try { var result = this.workspace_.newBlock(imType); - result.setInsertionMarker(true, sourceBlock.width); + result.setInsertionMarker(true); result.setCollapsed(sourceBlock.isCollapsed()); if (sourceBlock.mutationToDom) { var oldMutationDom = sourceBlock.mutationToDom(); diff --git a/core/variable_map.js b/core/variable_map.js index 3e13d67d2..76fefb438 100644 --- a/core/variable_map.js +++ b/core/variable_map.js @@ -276,7 +276,7 @@ Blockly.VariableMap.prototype.deleteVariableInternal_ = function(variable, } try { for (var i = 0; i < uses.length; i++) { - uses[i].dispose(true, false); + uses[i].dispose(true); } this.deleteVariable(variable); } finally { diff --git a/core/workspace.js b/core/workspace.js index 32cbbdd00..8cecaea90 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -479,10 +479,10 @@ Blockly.Workspace.prototype.clear = function() { Blockly.Events.setGroup(true); } while (this.topBlocks_.length) { - this.topBlocks_[0].dispose(); + this.topBlocks_[0].dispose(false); } while (this.topComments_.length) { - this.topComments_[this.topComments_.length - 1].dispose(); + this.topComments_[this.topComments_.length - 1].dispose(false); } if (!existingGroup) { Blockly.Events.setGroup(false); @@ -665,7 +665,7 @@ Blockly.Workspace.prototype.remainingCapacityOfType = function(type) { return Infinity; } return (this.options.maxInstances[type] || Infinity) - - this.getBlocksByType(type).length; + this.getBlocksByType(type, false).length; }; /** From ce02665044226d26262ed83b122611b4aed507fa Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 17 Oct 2019 11:17:37 -0700 Subject: [PATCH 059/343] Replace static reserved word list with dynamic scan (#3269) This change means the list is complete for every environment. This makes evaling code more safe. However it also means that code generated on one environment isn't guaranteed to be free of global collisions when executed on another environment (with the exception of the JS Interpreter). So if you are generating code in Node, and then executing it with eval() in a user's browser a user's program could declare a variable named `location`, assign to it, and the browser will redirect to that URL. Honestly, that's what you get for evaling untrusted code between users. Use the JS Interpreter if you are doing anything other than just generating and executing in the same environment. --- generators/javascript.js | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/generators/javascript.js b/generators/javascript.js index 2dae1fa93..29bc0373c 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -24,6 +24,7 @@ goog.provide('Blockly.JavaScript'); goog.require('Blockly.Generator'); +goog.require('Blockly.utils.global'); goog.require('Blockly.utils.string'); @@ -41,28 +42,16 @@ Blockly.JavaScript = new Blockly.Generator('JavaScript'); * @private */ Blockly.JavaScript.addReservedWords( - 'Blockly,' + // In case JS is evaled in the current window. - // https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words - 'break,case,catch,continue,debugger,default,delete,do,else,finally,for,function,if,in,instanceof,new,return,switch,this,throw,try,typeof,var,void,while,with,' + - 'class,enum,export,extends,import,super,implements,interface,let,package,private,protected,public,static,yield,' + - 'const,null,true,false,' + - // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects - 'Array,ArrayBuffer,Boolean,Date,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Error,eval,EvalError,Float32Array,Float64Array,Function,Infinity,Int16Array,Int32Array,Int8Array,isFinite,isNaN,Iterator,JSON,Math,NaN,Number,Object,parseFloat,parseInt,RangeError,ReferenceError,RegExp,StopIteration,String,SyntaxError,TypeError,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray,undefined,uneval,URIError,' + - // https://developer.mozilla.org/en/DOM/window - 'applicationCache,closed,Components,content,_content,controllers,crypto,defaultStatus,dialogArguments,directories,document,frameElement,frames,fullScreen,globalStorage,history,innerHeight,innerWidth,length,location,locationbar,localStorage,menubar,messageManager,mozAnimationStartTime,mozInnerScreenX,mozInnerScreenY,mozPaintCount,name,navigator,opener,outerHeight,outerWidth,pageXOffset,pageYOffset,parent,performance,personalbar,pkcs11,returnValue,screen,screenX,screenY,scrollbars,scrollMaxX,scrollMaxY,scrollX,scrollY,self,sessionStorage,sidebar,status,statusbar,toolbar,top,URL,window,' + - 'addEventListener,alert,atob,back,blur,btoa,captureEvents,clearImmediate,clearInterval,clearTimeout,close,confirm,disableExternalCapture,dispatchEvent,dump,enableExternalCapture,escape,find,focus,forward,GeckoActiveXObject,getAttention,getAttentionWithCycleCount,getComputedStyle,getSelection,home,matchMedia,maximize,minimize,moveBy,moveTo,mozRequestAnimationFrame,open,openDialog,postMessage,print,prompt,QueryInterface,releaseEvents,removeEventListener,resizeBy,resizeTo,restore,routeEvent,scroll,scrollBy,scrollByLines,scrollByPages,scrollTo,setCursor,setImmediate,setInterval,setResizable,setTimeout,showModalDialog,sizeToContent,stop,unescape,updateCommands,XPCNativeWrapper,XPCSafeJSObjectWrapper,' + - 'onabort,onbeforeunload,onblur,onchange,onclick,onclose,oncontextmenu,ondevicemotion,ondeviceorientation,ondragdrop,onerror,onfocus,onhashchange,onkeydown,onkeypress,onkeyup,onload,onmousedown,onmousemove,onmouseout,onmouseover,onmouseup,onmozbeforepaint,onpaint,onpopstate,onreset,onresize,onscroll,onselect,onsubmit,onunload,onpageshow,onpagehide,' + - 'Image,Option,Worker,' + - // https://developer.mozilla.org/en/Gecko_DOM_Reference - 'Event,Range,File,FileReader,Blob,BlobBuilder,' + - 'Attr,CDATASection,CharacterData,Comment,console,DocumentFragment,DocumentType,DomConfiguration,DOMError,DOMErrorHandler,DOMException,DOMImplementation,DOMImplementationList,DOMImplementationRegistry,DOMImplementationSource,DOMLocator,DOMObject,DOMString,DOMStringList,DOMTimeStamp,DOMUserData,Entity,EntityReference,MediaQueryList,MediaQueryListListener,NameList,NamedNodeMap,Node,NodeFilter,NodeIterator,NodeList,Notation,Plugin,PluginArray,ProcessingInstruction,SharedWorker,Text,TimeRanges,Treewalker,TypeInfo,UserDataHandler,Worker,WorkerGlobalScope,' + - 'HTMLDocument,HTMLElement,HTMLAnchorElement,HTMLAppletElement,HTMLAudioElement,HTMLAreaElement,HTMLBaseElement,HTMLBaseFontElement,HTMLBodyElement,HTMLBRElement,HTMLButtonElement,HTMLCanvasElement,HTMLDirectoryElement,HTMLDivElement,HTMLDListElement,HTMLEmbedElement,HTMLFieldSetElement,HTMLFontElement,HTMLFormElement,HTMLFrameElement,HTMLFrameSetElement,HTMLHeadElement,HTMLHeadingElement,HTMLHtmlElement,HTMLHRElement,HTMLIFrameElement,HTMLImageElement,HTMLInputElement,HTMLKeygenElement,HTMLLabelElement,HTMLLIElement,HTMLLinkElement,HTMLMapElement,HTMLMenuElement,HTMLMetaElement,HTMLModElement,HTMLObjectElement,HTMLOListElement,HTMLOptGroupElement,HTMLOptionElement,HTMLOutputElement,HTMLParagraphElement,HTMLParamElement,HTMLPreElement,HTMLQuoteElement,HTMLScriptElement,HTMLSelectElement,HTMLSourceElement,HTMLSpanElement,HTMLStyleElement,HTMLTableElement,HTMLTableCaptionElement,HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement,HTMLTableColElement,HTMLTableRowElement,HTMLTableSectionElement,HTMLTextAreaElement,HTMLTimeElement,HTMLTitleElement,HTMLTrackElement,HTMLUListElement,HTMLUnknownElement,HTMLVideoElement,' + - 'HTMLCanvasElement,CanvasRenderingContext2D,CanvasGradient,CanvasPattern,TextMetrics,ImageData,CanvasPixelArray,HTMLAudioElement,HTMLVideoElement,NotifyAudioAvailableEvent,HTMLCollection,HTMLAllCollection,HTMLFormControlsCollection,HTMLOptionsCollection,HTMLPropertiesCollection,DOMTokenList,DOMSettableTokenList,DOMStringMap,RadioNodeList,' + - 'SVGDocument,SVGElement,SVGAElement,SVGAltGlyphElement,SVGAltGlyphDefElement,SVGAltGlyphItemElement,SVGAnimationElement,SVGAnimateElement,SVGAnimateColorElement,SVGAnimateMotionElement,SVGAnimateTransformElement,SVGSetElement,SVGCircleElement,SVGClipPathElement,SVGColorProfileElement,SVGCursorElement,SVGDefsElement,SVGDescElement,SVGEllipseElement,SVGFilterElement,SVGFilterPrimitiveStandardAttributes,SVGFEBlendElement,SVGFEColorMatrixElement,SVGFEComponentTransferElement,SVGFECompositeElement,SVGFEConvolveMatrixElement,SVGFEDiffuseLightingElement,SVGFEDisplacementMapElement,SVGFEDistantLightElement,SVGFEFloodElement,SVGFEGaussianBlurElement,SVGFEImageElement,SVGFEMergeElement,SVGFEMergeNodeElement,SVGFEMorphologyElement,SVGFEOffsetElement,SVGFEPointLightElement,SVGFESpecularLightingElement,SVGFESpotLightElement,SVGFETileElement,SVGFETurbulenceElement,SVGComponentTransferFunctionElement,SVGFEFuncRElement,SVGFEFuncGElement,SVGFEFuncBElement,SVGFEFuncAElement,SVGFontElement,SVGFontFaceElement,SVGFontFaceFormatElement,SVGFontFaceNameElement,SVGFontFaceSrcElement,SVGFontFaceUriElement,SVGForeignObjectElement,SVGGElement,SVGGlyphElement,SVGGlyphRefElement,SVGGradientElement,SVGLinearGradientElement,SVGRadialGradientElement,SVGHKernElement,SVGImageElement,SVGLineElement,SVGMarkerElement,SVGMaskElement,SVGMetadataElement,SVGMissingGlyphElement,SVGMPathElement,SVGPathElement,SVGPatternElement,SVGPolylineElement,SVGPolygonElement,SVGRectElement,SVGScriptElement,SVGStopElement,SVGStyleElement,SVGSVGElement,SVGSwitchElement,SVGSymbolElement,SVGTextElement,SVGTextPathElement,SVGTitleElement,SVGTRefElement,SVGTSpanElement,SVGUseElement,SVGViewElement,SVGVKernElement,' + - 'SVGAngle,SVGColor,SVGICCColor,SVGElementInstance,SVGElementInstanceList,SVGLength,SVGLengthList,SVGMatrix,SVGNumber,SVGNumberList,SVGPaint,SVGPoint,SVGPointList,SVGPreserveAspectRatio,SVGRect,SVGStringList,SVGTransform,SVGTransformList,' + - 'SVGAnimatedAngle,SVGAnimatedBoolean,SVGAnimatedEnumeration,SVGAnimatedInteger,SVGAnimatedLength,SVGAnimatedLengthList,SVGAnimatedNumber,SVGAnimatedNumberList,SVGAnimatedPreserveAspectRatio,SVGAnimatedRect,SVGAnimatedString,SVGAnimatedTransformList,' + - 'SVGPathSegList,SVGPathSeg,SVGPathSegArcAbs,SVGPathSegArcRel,SVGPathSegClosePath,SVGPathSegCurvetoCubicAbs,SVGPathSegCurvetoCubicRel,SVGPathSegCurvetoCubicSmoothAbs,SVGPathSegCurvetoCubicSmoothRel,SVGPathSegCurvetoQuadraticAbs,SVGPathSegCurvetoQuadraticRel,SVGPathSegCurvetoQuadraticSmoothAbs,SVGPathSegCurvetoQuadraticSmoothRel,SVGPathSegLinetoAbs,SVGPathSegLinetoHorizontalAbs,SVGPathSegLinetoHorizontalRel,SVGPathSegLinetoRel,SVGPathSegLinetoVerticalAbs,SVGPathSegLinetoVerticalRel,SVGPathSegMovetoAbs,SVGPathSegMovetoRel,ElementTimeControl,TimeEvent,SVGAnimatedPathData,' + - 'SVGAnimatedPoints,SVGColorProfileRule,SVGCSSRule,SVGExternalResourcesRequired,SVGFitToViewBox,SVGLangSpace,SVGLocatable,SVGRenderingIntent,SVGStylable,SVGTests,SVGTextContentElement,SVGTextPositioningElement,SVGTransformable,SVGUnitTypes,SVGURIReference,SVGViewSpec,SVGZoomAndPan'); + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords + 'break,case,catch,class,const,continue,debugger,default,delete,do,else,export,extends,finally,for,function,if,import,in,instanceof,new,return,super,switch,this,throw,try,typeof,var,void,while,with,yield,' + + 'enum,' + + 'implements,interface,let,package,private,protected,public,static,' + + 'await,' + + 'null,true,false,' + + // Magic variable. + 'arguments,' + + // Everything in the current environment (835 items in Chrome, 104 in Node). + Object.getOwnPropertyNames(Blockly.utils.global).join(',')); /** * Order of operation ENUMs. From bde1edff85bafb25d95fab3cdc7239d67a60bcdf Mon Sep 17 00:00:00 2001 From: Navil Perez Date: Thu, 17 Oct 2019 11:41:31 -0700 Subject: [PATCH 060/343] Add dragStart and dragEnd UI events --- core/block_dragger.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index eca2cfbec..2fb096c1d 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -26,6 +26,7 @@ goog.provide('Blockly.BlockDragger'); goog.require('Blockly.blockAnimations'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockMove'); +goog.require('Blockly.Events.Ui'); goog.require('Blockly.InsertionMarkerManager'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); @@ -147,6 +148,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, if (!Blockly.Events.getGroup()) { Blockly.Events.setGroup(true); } + this.fireDragStartEvent_(); // Mutators don't have the same type of z-ordering as the normal workspace // during a drag. They have to rely on the order of the blocks in the SVG. @@ -186,6 +188,16 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, } }; +/** + * Fire a ui event at the start of a block drag. + * @private + */ +Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() { + var event = new Blockly.Events.Ui(this.draggingBlock_, 'dragStart', + null, this.draggingBlock_.getDescendants(false)); + Blockly.Events.fire(event) +}; + /** * Execute a step of block dragging, based on the given event. Update the * display accordingly. @@ -218,7 +230,8 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { // Make sure internal state is fresh. this.dragBlock(e, currentDragDeltaXY); this.dragIconData_ = []; - + this.fireDragEndEvent_(); + Blockly.utils.dom.stopTextWidthCache(); Blockly.blockAnimations.disconnectUiStop(); @@ -252,6 +265,16 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { Blockly.Events.setGroup(false); }; +/** + * Fire a ui event at the end of a block drag. + * @private + */ +Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() { + var event = new Blockly.Events.Ui(this.draggingBlock_, 'dragStop', + this.draggingBlock_.getDescendants(false), null); + Blockly.Events.fire(event); +}; + /** * Fire a move event at the end of a block drag. * @private From 36524a3b4a1d6391bd154648aab780fa14519b2c Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 14:08:06 -0500 Subject: [PATCH 061/343] Only add a hat if there's no output connection or previous connection (#3280) * Only add a hat if there's no output connection or previous connection --- core/renderers/common/info.js | 5 +++-- core/renderers/measurables/rows.js | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 6f978889e..f39cc9187 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -253,9 +253,10 @@ Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() { * @package */ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() { - var hasHat = this.block_.hat ? - this.block_.hat === 'cap' : Blockly.BlockSvg.START_HAT; var hasPrevious = !!this.block_.previousConnection; + var hasHat = (this.block_.hat ? + this.block_.hat === 'cap' : Blockly.BlockSvg.START_HAT) && + !this.outputConnection && !hasPrevious; var leftSquareCorner = this.topRow.hasLeftSquareCorner(this.block_); if (leftSquareCorner) { diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index b998eb7f3..5f17f96ce 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -283,7 +283,8 @@ Blockly.utils.object.inherits(Blockly.blockRendering.TopRow, * @return {boolean} Whether or not the top row has a left square corner. */ Blockly.blockRendering.TopRow.prototype.hasLeftSquareCorner = function(block) { - var hasHat = block.hat ? block.hat === 'cap' : Blockly.BlockSvg.START_HAT; + var hasHat = (block.hat ? block.hat === 'cap' : Blockly.BlockSvg.START_HAT) && + !block.outputConnection && !block.previousConnection; var prevBlock = block.getPreviousBlock(); return !!block.outputConnection || From e07a3f03a9884d87aa352cfbf2f6b2ee66a46330 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 15:06:22 -0500 Subject: [PATCH 062/343] Fix 14 warnings related to workspace svg (#3273) * Fix warnings related to workspace svg --- core/options.js | 7 ++++--- core/workspace.js | 2 +- core/workspace_svg.js | 42 ++++++++++++++++++++++++++++-------------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/core/options.js b/core/options.js index ed081da42..c02b44cc7 100644 --- a/core/options.js +++ b/core/options.js @@ -154,14 +154,15 @@ Blockly.Options.prototype.parentWorkspace = null; /** * If set, sets the translation of the workspace to match the scrollbars. + * @return {void} */ -Blockly.Options.prototype.setMetrics = null; +Blockly.Options.prototype.setMetrics; /** * Return an object with the metrics required to size the workspace. - * @return {Object} Contains size and position metrics, or null. + * @return {!Object} Contains size and position metrics. */ -Blockly.Options.prototype.getMetrics = null; +Blockly.Options.prototype.getMetrics; /** * Parse the user-specified move options, using reasonable defaults where diff --git a/core/workspace.js b/core/workspace.js index 8cecaea90..abb4ab85d 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -44,7 +44,7 @@ Blockly.Workspace = function(opt_options) { this.id = Blockly.utils.genUid(); Blockly.Workspace.WorkspaceDB_[this.id] = this; /** @type {!Blockly.Options} */ - this.options = opt_options || {}; + this.options = opt_options || /** @type {!Blockly.Options} */ ({}); /** @type {boolean} */ this.RTL = !!this.options.RTL; /** @type {boolean} */ diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 9f75e6520..1bbd16165 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -59,8 +59,10 @@ goog.require('Blockly.Xml'); Blockly.WorkspaceSvg = function(options, opt_blockDragSurface, opt_wsDragSurface) { Blockly.WorkspaceSvg.superClass_.constructor.call(this, options); + /** @type {function():!Object} */ this.getMetrics = options.getMetrics || Blockly.WorkspaceSvg.getTopLevelWorkspaceMetrics_; + /** @type {function(!Object)} */ this.setMetrics = options.setMetrics || Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_; @@ -75,12 +77,12 @@ Blockly.WorkspaceSvg = function(options, } this.useWorkspaceDragSurface_ = - this.workspaceDragSurface_ && Blockly.utils.is3dSupported(); + !!this.workspaceDragSurface_ && Blockly.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_ = []; @@ -566,7 +568,7 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { * @package */ Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { - return Blockly.utils.getInjectionDivXY_(this.svgBlockCanvas_); + return Blockly.utils.getInjectionDivXY_(this.getCanvas()); }; /** @@ -927,18 +929,18 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = /** * Get the SVG element that forms the drawing surface. - * @return {!SVGElement} SVG element. + * @return {!SVGGElement} SVG group element. */ Blockly.WorkspaceSvg.prototype.getCanvas = function() { - return this.svgBlockCanvas_; + return /** @type {!SVGGElement} */ (this.svgBlockCanvas_); }; /** * Get the SVG element that forms the bubble surface. - * @return {!SVGGElement} SVG element. + * @return {!SVGGElement} SVG group element. */ Blockly.WorkspaceSvg.prototype.getBubbleCanvas = function() { - return this.svgBubbleCanvas_; + return /** @type {!SVGGElement} */ (this.svgBubbleCanvas_); }; /** @@ -1034,12 +1036,13 @@ 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 = this.svgBlockCanvas_.previousSibling; + 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.svgBlockCanvas_); - this.workspaceDragSurface_.setContentsAndShow(this.svgBlockCanvas_, - this.svgBubbleCanvas_, previousElement, width, height, this.scale); + var coord = Blockly.utils.getRelativeXY(this.getCanvas()); + this.workspaceDragSurface_.setContentsAndShow(this.getCanvas(), + this.getBubbleCanvas(), previousElement, width, height, this.scale); this.workspaceDragSurface_.translateSurface(coord.x, coord.y); }; @@ -1324,10 +1327,10 @@ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) { * Create a new variable with the given name. Update the flyout to show the * new variable immediately. * @param {string} name The new variable's name. - * @param {string=} opt_type The type of the variable like 'int' or 'string'. + * @param {?string=} opt_type The type of the variable like 'int' or 'string'. * Does not need to be unique. Field_variable can filter variables based on * their type. This will default to '' which is a specific type. - * @param {string=} opt_id The unique ID of the variable. This will default to + * @param {?string=} opt_id The unique ID of the variable. This will default to * a UUID. * @return {Blockly.VariableModel} The newly created variable. * @package @@ -1974,7 +1977,7 @@ Blockly.WorkspaceSvg.prototype.centerOnBlock = function(id) { return; } - var block = this.getBlockById(id); + var block = id ? this.getBlockById(id) : null; if (!block) { return; } @@ -2362,6 +2365,17 @@ Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { this.translate(x, y); }; +/** + * 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. + * @override + */ +Blockly.WorkspaceSvg.prototype.getBlockById = function(id) { + return /** @type {Blockly.BlockSvg} */ ( + Blockly.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). From a5a4e5161c28f7b70427f0437fd6ada8304d65fd Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 16:30:48 -0500 Subject: [PATCH 063/343] Fix 11 warnings related to block_svg (#3276) * Fix 11 warnings related to block_svg --- core/block_svg.js | 43 +++++++++++++++++++-------------- core/comment.js | 8 +++--- core/field.js | 10 ++++++++ core/gesture.js | 2 +- core/keyboard_nav/navigation.js | 2 +- core/workspace_svg.js | 2 +- 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index c9859f334..d3d5ffa24 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -97,6 +97,9 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { /** @type {boolean} */ this.rendered = false; + /** @type {!Blockly.WorkspaceSvg} */ + this.workspace = workspace; + /** * Whether to move the block to the drag surface when it is dragged. * True if it should move, false if it should be translated directly. @@ -104,7 +107,7 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @private */ this.useDragSurface_ = - Blockly.utils.is3dSupported() && !!workspace.blockDragSurface_; + Blockly.utils.is3dSupported() && !!workspace.getBlockDragSurface(); Blockly.Tooltip.bindMouseEvents(this.svgPath_); Blockly.BlockSvg.superClass_.constructor.call(this, @@ -254,14 +257,15 @@ Blockly.BlockSvg.prototype.initSvg = function() { } this.updateColour(); this.updateMovable(); - if (!this.workspace.options.readOnly && !this.eventsInit_) { + var svg = this.getSvgRoot(); + if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) { Blockly.bindEventWithChecks_( - this.getSvgRoot(), 'mousedown', this, this.onMouseDown_); + svg, 'mousedown', this, this.onMouseDown_); } this.eventsInit_ = true; - if (!this.getSvgRoot().parentNode) { - this.workspace.getCanvas().appendChild(this.getSvgRoot()); + if (!svg.parentNode) { + this.workspace.getCanvas().appendChild(svg); } }; @@ -355,7 +359,7 @@ Blockly.BlockSvg.prototype.getIcons = function() { /** * Set parent of this block to be a new block or null. - * @param {Blockly.BlockSvg} newParent New parent block. + * @param {Blockly.Block} newParent New parent block. * @override */ Blockly.BlockSvg.prototype.setParent = function(newParent) { @@ -405,7 +409,7 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { var y = 0; var dragSurfaceGroup = this.useDragSurface_ ? - this.workspace.blockDragSurface_.getGroup() : null; + this.workspace.getBlockDragSurface().getGroup() : null; var element = this.getSvgRoot(); if (element) { @@ -417,9 +421,9 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { // 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) { + this.workspace.getBlockDragSurface().getCurrentBlock() == element) { var surfaceTranslation = - this.workspace.blockDragSurface_.getSurfaceTranslation(); + this.workspace.getBlockDragSurface().getSurfaceTranslation(); x += surfaceTranslation.x; y += surfaceTranslation.y; } @@ -480,9 +484,12 @@ Blockly.BlockSvg.prototype.moveToDragSurface_ = function() { // This is in workspace coordinates. var 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()); + var svg = this.getSvgRoot(); + if (svg) { + this.workspace.getBlockDragSurface().setBlocksAndShow(svg); + } }; /** @@ -508,7 +515,7 @@ Blockly.BlockSvg.prototype.moveOffDragSurface_ = function(newXY) { } // Translate to current position, turning off 3d. this.translate(newXY.x, newXY.y); - this.workspace.blockDragSurface_.clearAndHide(this.workspace.getCanvas()); + this.workspace.getBlockDragSurface().clearAndHide(this.workspace.getCanvas()); }; /** @@ -521,7 +528,7 @@ Blockly.BlockSvg.prototype.moveOffDragSurface_ = function(newXY) { */ Blockly.BlockSvg.prototype.moveDuringDrag = function(newLoc) { if (this.useDragSurface_) { - this.workspace.blockDragSurface_.translateSurface(newLoc.x, newLoc.y); + this.workspace.getBlockDragSurface().translateSurface(newLoc.x, newLoc.y); } else { this.svgGroup_.translate_ = 'translate(' + newLoc.x + ',' + newLoc.y + ')'; this.svgGroup_.setAttribute('transform', @@ -680,7 +687,7 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { */ Blockly.BlockSvg.prototype.tab = function(start, forward) { var list = this.createTabList_(); - var i = list.indexOf(start); + var i = start != null ? list.indexOf(start) : -1; if (i == -1) { // No start location, start at the beginning or end. i = forward ? -1 : list.length; @@ -693,7 +700,7 @@ Blockly.BlockSvg.prototype.tab = function(start, forward) { parent.tab(this, forward); } } else if (target instanceof Blockly.Field) { - target.showEditor_(); + target.showEditor(); } else { target.tab(null, forward); } @@ -701,7 +708,7 @@ Blockly.BlockSvg.prototype.tab = function(start, forward) { /** * Create an ordered list of all text fields and connected inputs. - * @return {!Array.} The ordered list. + * @return {!Array.} The ordered list. * @private */ Blockly.BlockSvg.prototype.createTabList_ = function() { @@ -1033,7 +1040,7 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { for (var i = 0; i < icons.length; i++) { icons[i].dispose(); } - Blockly.BlockSvg.superClass_.dispose.call(this, healStack); + Blockly.BlockSvg.superClass_.dispose.call(this, !!healStack); Blockly.utils.dom.removeNode(this.svgGroup_); blockWorkspace.resizeContents(); @@ -1101,7 +1108,7 @@ Blockly.BlockSvg.prototype.setBorderColour_ = function() { * @private */ Blockly.BlockSvg.prototype.setShadowColour_ = function() { - var shadowColour = this.getColourShadow(); + var shadowColour = this.getColourShadow() || ''; this.svgPathLight_.style.display = 'none'; this.svgPathDark_.setAttribute('fill', shadowColour); diff --git a/core/comment.js b/core/comment.js index fe9494630..803e1459c 100644 --- a/core/comment.js +++ b/core/comment.js @@ -252,22 +252,22 @@ Blockly.Comment.prototype.createEditableBubble_ = function() { /** * Show a non-editable bubble. * @private + * @suppress {checkTypes} Suppress `this` type mismatch. */ Blockly.Comment.prototype.createNonEditableBubble_ = function() { // TODO (#2917): It would be great if the comment could support line breaks. - Blockly.Warning.prototype.createBubble.call( - /** @type {Blockly.Warning} */ (this)); + Blockly.Warning.prototype.createBubble.call(this); }; /** * Dispose of the bubble. * @private + * @suppress {checkTypes} Suppress `this` type mismatch. */ Blockly.Comment.prototype.disposeBubble_ = function() { if (this.paragraphElement_) { // We're using the warning UI so we have to let it dispose. - Blockly.Warning.prototype.disposeBubble.call( - /** @type {Blockly.Warning} */ (this)); + Blockly.Warning.prototype.disposeBubble.call(this); return; } diff --git a/core/field.js b/core/field.js index ee88f82f7..5e5216533 100644 --- a/core/field.js +++ b/core/field.js @@ -612,6 +612,16 @@ Blockly.Field.prototype.render_ = function() { } }; +/** + * Show an editor when the field is clicked only if the field is clickable. + * @package + */ +Blockly.Field.prototype.showEditor = function() { + if (this.isClickable()) { + this.showEditor_(); + } +}; + /** * Updates the width of the field. Redirects to updateSize_(). * @deprecated May 2019 Use Blockly.Field.updateSize_() to force an update diff --git a/core/gesture.js b/core/gesture.js index df369b9fe..c0071aaf9 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -723,7 +723,7 @@ Blockly.Gesture.prototype.doBubbleClick_ = function() { * @private */ Blockly.Gesture.prototype.doFieldClick_ = function() { - this.startField_.showEditor_(); + this.startField_.showEditor(); this.bringBlockToFront_(); }; diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 07b34d68b..aad1c5204 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -924,7 +924,7 @@ Blockly.navigation.handleEnterForWS_ = function() { var curNode = cursor.getCurNode(); var nodeType = curNode.getType(); if (nodeType == Blockly.ASTNode.types.FIELD) { - curNode.getLocation().showEditor_(); + curNode.getLocation().showEditor(); } else if (curNode.isConnection() || nodeType == Blockly.ASTNode.types.WORKSPACE) { Blockly.navigation.markAtCursor_(); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 1bbd16165..fd9fba79a 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -533,7 +533,7 @@ Blockly.WorkspaceSvg.prototype.isVisible = function() { * The origin (0,0) is the top-left corner of the Blockly SVG. * @param {!Element} element Element to find the coordinates of. * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. - * @private + * @package */ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { var x = 0; From 8eba82b906d97102a5488830b34191d83161840f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 16:52:52 -0500 Subject: [PATCH 064/343] Fix 4 misc warnings (#3283) --- core/dropdowndiv.js | 4 ++-- core/field.js | 4 ++-- core/field_multilineinput.js | 2 +- core/field_textinput.js | 2 +- core/tooltip.js | 2 ++ core/utils/style.js | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 68412dbee..5931c937c 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -276,7 +276,7 @@ Blockly.DropDownDiv.getScaledBboxOfBlock_ = function(block) { * @private */ Blockly.DropDownDiv.getScaledBboxOfField_ = function(field) { - var bBox = field.getScaledBBox_(); + var bBox = field.getScaledBBox(); return new Blockly.utils.Rect( bBox.top, bBox.bottom, bBox.left, bBox.right); }; @@ -700,7 +700,7 @@ Blockly.DropDownDiv.repositionForWindowResize = function() { // event and we want the dropdown div to stick around so users can type into // it. if (Blockly.DropDownDiv.owner_) { - var field = Blockly.DropDownDiv.owner_; + var field = /** @type {!Blockly.Field} */ (Blockly.DropDownDiv.owner_); var block = Blockly.DropDownDiv.owner_.getSourceBlock(); var bBox = Blockly.DropDownDiv.positionToField_ ? Blockly.DropDownDiv.getScaledBboxOfField_(field) : diff --git a/core/field.js b/core/field.js index 5e5216533..e089adc3b 100644 --- a/core/field.js +++ b/core/field.js @@ -680,9 +680,9 @@ Blockly.Field.prototype.getSize = function() { * scaling. * @return {!Object} An object with top, bottom, left, and right in pixels * relative to the top left corner of the page (window coordinates). - * @protected + * @package */ -Blockly.Field.prototype.getScaledBBox_ = function() { +Blockly.Field.prototype.getScaledBBox = function() { var bBox = this.borderRect_.getBBox(); var scaledHeight = bBox.height * this.sourceBlock_.workspace.scale; var scaledWidth = bBox.width * this.sourceBlock_.workspace.scale; diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 41e16b0fd..26ba0a34c 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -220,7 +220,7 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() { */ Blockly.FieldMultilineInput.prototype.resizeEditor_ = function() { var div = Blockly.WidgetDiv.DIV; - var bBox = this.getScaledBBox_(); + var bBox = this.getScaledBBox(); div.style.width = bBox.right - bBox.left + 'px'; div.style.height = bBox.bottom - bBox.top + 'px'; diff --git a/core/field_textinput.js b/core/field_textinput.js index 2fb87c2e2..004348309 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -436,7 +436,7 @@ Blockly.FieldTextInput.prototype.setEditorValue_ = function(newValue) { */ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { var div = Blockly.WidgetDiv.DIV; - var bBox = this.getScaledBBox_(); + var bBox = this.getScaledBBox(); div.style.width = bBox.right - bBox.left + 'px'; div.style.height = bBox.bottom - bBox.top + 'px'; diff --git a/core/tooltip.js b/core/tooltip.js index 747bd3f18..28ddefeb8 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -78,6 +78,7 @@ Blockly.Tooltip.lastY_ = 0; /** * Current element being pointed at. + * @type {Element} * @private */ Blockly.Tooltip.element_ = null; @@ -85,6 +86,7 @@ Blockly.Tooltip.element_ = null; /** * Once a tooltip has opened for an element, that element is 'poisoned' and * cannot respawn a tooltip until the pointer moves over a different element. + * @type {Element} * @private */ Blockly.Tooltip.poisonedElement_ = null; diff --git a/core/utils/style.js b/core/utils/style.js index 8f9ecddbb..3e01fe053 100644 --- a/core/utils/style.js +++ b/core/utils/style.js @@ -67,7 +67,7 @@ Blockly.utils.style.getSize = function(element) { /** * Gets the height and width of an element when the display is not none. * @param {!Element} element Element to get size of. - * @return {!goog.math.Size} Object with width/height properties. + * @return {!Blockly.utils.Size} Object with width/height properties. * @private */ Blockly.utils.style.getSizeWithDisplay_ = function(element) { From ce4163c7e4dfae39647499c1130743f9f9e443d1 Mon Sep 17 00:00:00 2001 From: Navil Perez Date: Thu, 17 Oct 2019 15:13:26 -0700 Subject: [PATCH 065/343] Fix capitalization in the docstring. --- core/block_dragger.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 2fb096c1d..6e6857506 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -189,7 +189,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, }; /** - * Fire a ui event at the start of a block drag. + * Fire a UI event at the start of a block drag. * @private */ Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() { @@ -266,7 +266,7 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { }; /** - * Fire a ui event at the end of a block drag. + * Fire a UI event at the end of a block drag. * @private */ Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() { From c0784a61e7212bbbc394dcf14dc3b9f9a6aacb17 Mon Sep 17 00:00:00 2001 From: Navil Perez Date: Thu, 17 Oct 2019 15:23:10 -0700 Subject: [PATCH 066/343] Linting Fix --- core/block_dragger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 6e6857506..9b6110f6b 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -195,7 +195,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() { var event = new Blockly.Events.Ui(this.draggingBlock_, 'dragStart', null, this.draggingBlock_.getDescendants(false)); - Blockly.Events.fire(event) + Blockly.Events.fire(event); }; /** From 5507a1eb8883718fb169d2600d36b71aeeb06bbb Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 17 Oct 2019 15:45:43 -0700 Subject: [PATCH 067/343] Add task to create a release candidate. --- gulpfile.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gulpfile.js b/gulpfile.js index b6bc06afc..288a487a4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -800,6 +800,18 @@ function getRebuildBranchName() { return 'rebuild_' + mm + '_' + dd + '_' + yyyy; }; +// Helper function: get a name for a rebuild branch. Format: rebuild_month_yyyy. +function getRCBranchName() { + var date = new Date(); + var monthNames = [ + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + ]; + var month = monthNames[date.getMonth()]; + var yy = date.getFullYear().slice(-2); + return 'rc_' + month + '_' + yyyy; +}; + // Recompile and push to origin. gulp.task('recompile', gulp.series([ 'git-sync-develop', @@ -821,3 +833,17 @@ gulp.task('recompile', gulp.series([ } ]) ); + +// Create and push an RC branch. +// Note that this pushes to google/blockly. +gulp.task('git-create-rc', gulp.series([ + 'git-sync-develop', + function(done) { + var branchName = getRCBranchName(); + execSync('git checkout -b ' + branchName, { stdio: 'inherit' }); + execSync('git push https://github.com/google/blockly.git ' + branchName, + { stdio: 'inherit' }); + done(); + }, + ]) +); From 19018a5e8e5d36ae02f2bdee08d3b7d295fd7810 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 17 Oct 2019 17:58:15 -0500 Subject: [PATCH 068/343] Fix compiler warnings related to XML (#3277) * Fix 5 warnings. --- core/block_svg.js | 1 - core/utils/xml.js | 4 ++-- core/xml.js | 43 +++++++++++++++++++++++-------------------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index d3d5ffa24..bfc5c7bb7 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -206,7 +206,6 @@ Blockly.BlockSvg.MIN_BLOCK_Y = 25; /** * Width of horizontal puzzle tab. - * @const * @package */ // TODO (#3142): Remove. diff --git a/core/utils/xml.js b/core/utils/xml.js index 054aac94f..ec6302b10 100644 --- a/core/utils/xml.js +++ b/core/utils/xml.js @@ -58,7 +58,7 @@ Blockly.utils.xml.createElement = function(tagName) { /** * Create text element for XML. * @param {string} text Text content. - * @return {!Node} New DOM node. + * @return {!Text} New DOM text node. * @public */ Blockly.utils.xml.createTextNode = function(text) { @@ -80,7 +80,7 @@ Blockly.utils.xml.textToDomDocument = function(text) { /** * Converts a DOM structure into plain text. * Currently the text format is fairly ugly: all one line with no whitespace. - * @param {!Element} dom A tree of XML elements. + * @param {!Node} dom A tree of XML nodes. * @return {string} Text representation. * @public */ diff --git a/core/xml.js b/core/xml.js index e25a2c703..1125e1a7f 100644 --- a/core/xml.js +++ b/core/xml.js @@ -41,7 +41,7 @@ goog.require('Blockly.utils.xml'); * Encode a block tree as XML. * @param {!Blockly.Workspace} workspace The workspace containing blocks. * @param {boolean=} opt_noId True if the encoder should skip the block IDs. - * @return {!Element} XML document. + * @return {!Element} XML DOM element. */ Blockly.Xml.workspaceToDom = function(workspace, opt_noId) { var xml = Blockly.utils.xml.createElement('xml'); @@ -65,7 +65,7 @@ Blockly.Xml.workspaceToDom = function(workspace, opt_noId) { * Encode a list of variables as XML. * @param {!Array.} variableList List of all variable * models. - * @return {!Element} List of XML elements. + * @return {!Element} Tree of XML elements. */ Blockly.Xml.variablesToDom = function(variableList) { var variables = Blockly.utils.xml.createElement('variables'); @@ -110,7 +110,7 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) { Blockly.Xml.fieldToDom_ = function(field) { if (field.isSerializable()) { var container = Blockly.utils.xml.createElement('field'); - container.setAttribute('name', field.name); + container.setAttribute('name', field.name || ''); return field.toXml(container); } return null; @@ -285,7 +285,7 @@ Blockly.Xml.cloneShadow_ = function(shadow, opt_noId) { * Converts a DOM structure into plain text. * Currently the text format is fairly ugly: all one line with no whitespace, * unless the DOM itself has whitespace built-in. - * @param {!Element} dom A tree of XML elements. + * @param {!Node} dom A tree of XML nodes. * @return {string} Text representation. */ Blockly.Xml.domToText = function(dom) { @@ -306,7 +306,7 @@ Blockly.Xml.domToText = function(dom) { /** * Converts a DOM structure into properly indented text. - * @param {!Element} dom A tree of XML elements. + * @param {!Node} dom A tree of XML elements. * @return {string} Text representation. */ Blockly.Xml.domToPrettyText = function(dom) { @@ -402,17 +402,18 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { 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)) { // 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(xmlChild, workspace); + var block = Blockly.Xml.domToBlock(xmlChildElement, workspace); newBlockIds.push(block.id); - var blockX = xmlChild.hasAttribute('x') ? - parseInt(xmlChild.getAttribute('x'), 10) : 10; - var blockY = xmlChild.hasAttribute('y') ? - parseInt(xmlChild.getAttribute('y'), 10) : 10; + var blockX = xmlChildElement.hasAttribute('x') ? + parseInt(xmlChildElement.getAttribute('x'), 10) : 10; + var blockY = xmlChildElement.hasAttribute('y') ? + parseInt(xmlChildElement.getAttribute('y'), 10) : 10; if (!isNaN(blockX) && !isNaN(blockY)) { block.moveBy(workspace.RTL ? width - blockX : blockX, blockY); } @@ -425,19 +426,20 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { console.warn('Missing require for Blockly.WorkspaceCommentSvg, ' + 'ignoring workspace comment.'); } else { - Blockly.WorkspaceCommentSvg.fromXml(xmlChild, workspace, width); + Blockly.WorkspaceCommentSvg.fromXml( + xmlChildElement, workspace, width); } } else { if (!Blockly.WorkspaceComment) { console.warn('Missing require for Blockly.WorkspaceComment, ' + 'ignoring workspace comment.'); } else { - Blockly.WorkspaceComment.fromXml(xmlChild, workspace); + Blockly.WorkspaceComment.fromXml(xmlChildElement, workspace); } } } else if (name == 'variables') { if (variablesFirst) { - Blockly.Xml.domToVariables(xmlChild, workspace); + Blockly.Xml.domToVariables(xmlChildElement, workspace); } else { throw Error('\'variables\' tag must exist once before block and ' + 'shadow tag elements in the workspace XML, but it was found in ' + @@ -481,7 +483,7 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { } } // Load the new blocks into the workspace and get the IDs of the new blocks. - var newBlockIds = Blockly.Xml.domToWorkspace(xml,workspace); + var newBlockIds = Blockly.Xml.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; @@ -646,11 +648,12 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { } var name = xmlChild.getAttribute('name'); + var xmlChildElement = /** @type {!Element} */ (xmlChild); switch (xmlChild.nodeName.toLowerCase()) { case 'mutation': // Custom data for an advanced block. if (block.domToMutation) { - block.domToMutation(xmlChild); + block.domToMutation(xmlChildElement); if (block.initSvg) { // Mutation may have added some elements that need initializing. block.initSvg(); @@ -663,10 +666,10 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { 'ignoring block comment.'); break; } - var text = xmlChild.textContent; - var pinned = xmlChild.getAttribute('pinned') == 'true'; - var width = parseInt(xmlChild.getAttribute('w'), 10); - var height = parseInt(xmlChild.getAttribute('h'), 10); + var text = xmlChildElement.textContent; + var pinned = xmlChildElement.getAttribute('pinned') == 'true'; + var width = parseInt(xmlChildElement.getAttribute('w'), 10); + var height = parseInt(xmlChildElement.getAttribute('h'), 10); block.setCommentText(text); block.commentModel.pinned = pinned; @@ -687,7 +690,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { // Titles were renamed to field in December 2013. // Fall through. case 'field': - Blockly.Xml.domToField_(block, name, xmlChild); + Blockly.Xml.domToField_(block, name, xmlChildElement); break; case 'value': case 'statement': From 8e5797e2bcb0f7b82234f419f6bc354af85a9cd2 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 18 Oct 2019 02:00:31 -0700 Subject: [PATCH 069/343] Add missing utils.global (#3286) Compile is breaking due to the JS environment sweep. --- build.py | 3 ++- gulpfile.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build.py b/build.py index 0ac8efd23..a26d1a78c 100755 --- a/build.py +++ b/build.py @@ -266,6 +266,7 @@ goog.provide('Blockly.Mutator'); # with the compiler. params.append(("js_code", """ goog.provide('Blockly.Generator'); +goog.provide('Blockly.utils.global'); goog.provide('Blockly.utils.string'); """)) filenames = glob.glob( @@ -280,7 +281,7 @@ goog.provide('Blockly.utils.string'); # Remove Blockly.Generator and Blockly.utils.string to be compatible # with Blockly. - remove = r"var Blockly=\{[^;]*\};\s*Blockly.utils.string={};\n?" + remove = r"var Blockly=\{[^;]*\};\s*Blockly.utils.global={};\s*Blockly.utils.string={};\n?" self.do_compile(params, target_filename, filenames, remove) def do_compile(self, params, target_filename, filenames, remove): diff --git a/gulpfile.js b/gulpfile.js index b6bc06afc..4e96cd278 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -173,6 +173,7 @@ goog.provide('Blockly.Mutator');`; function buildGenerator(language, namespace) { var provides = ` goog.provide('Blockly.Generator'); +goog.provide('Blockly.utils.global'); goog.provide('Blockly.utils.string');`; return gulp.src([`generators/${language}.js`, `generators/${language}/*.js`], {base: './'}) .pipe(stripApacheLicense()) @@ -185,7 +186,7 @@ goog.provide('Blockly.utils.string');`; }, argv.verbose)) .pipe(gulp.replace('\'use strict\';', '\'use strict\';\n\n\n')) // Remove Blockly.Generator and Blockly.utils.string to be compatible with Blockly. - .pipe(gulp.replace(/var Blockly=\{[^;]*\};\s*Blockly.utils.string={};\n?/, '')) + .pipe(gulp.replace(/var Blockly=\{[^;]*\};\s*Blockly.utils.global={};\s*Blockly.utils.string={};\n?/, '')) .pipe(prependHeader()) .pipe(gulp.dest('./')); }; From 6d4c52fb6f4b4b81f42c41b79d497a371b5d8eda Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 17 Oct 2019 16:48:39 -0700 Subject: [PATCH 070/343] Make finished-loading events be UI events --- core/events.js | 3 +++ core/workspace_events.js | 6 +++--- demos/mirror/index.html | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/events.js b/core/events.js index a693cae04..f52a838c2 100644 --- a/core/events.js +++ b/core/events.js @@ -390,6 +390,9 @@ Blockly.Events.fromJson = function(json, workspace) { case Blockly.Events.COMMENT_DELETE: event = new Blockly.Events.CommentDelete(null); break; + case Blockly.Events.FINISHED_LOADING: + event = new Blockly.Events.FinishedLoading(null); + break; default: throw Error('Unknown event type.'); } diff --git a/core/workspace_events.js b/core/workspace_events.js index 581366574..b3b690f25 100644 --- a/core/workspace_events.js +++ b/core/workspace_events.js @@ -24,7 +24,7 @@ goog.provide('Blockly.Events.FinishedLoading'); goog.require('Blockly.Events'); -goog.require('Blockly.Events.Abstract'); +goog.require('Blockly.Events.Ui'); goog.require('Blockly.utils.object'); @@ -46,7 +46,7 @@ Blockly.Events.FinishedLoading = function(workspace) { this.workspaceId = workspace.id; /** - * The event group id for the group this event belongs to. Groups define + * The event group ID for the group this event belongs to. Groups define * events that should be treated as an single action from the user's * perspective, and should be undone together. * @type {string} @@ -57,7 +57,7 @@ Blockly.Events.FinishedLoading = function(workspace) { this.recordUndo = false; }; Blockly.utils.object.inherits(Blockly.Events.FinishedLoading, - Blockly.Events.Abstract); + Blockly.Events.Ui); /** * Type of this event. diff --git a/demos/mirror/index.html b/demos/mirror/index.html index 10c23df02..84762f31d 100644 --- a/demos/mirror/index.html +++ b/demos/mirror/index.html @@ -65,7 +65,7 @@ primaryWorkspace.addChangeListener(mirrorEvent); function mirrorEvent(primaryEvent) { - if (primaryEvent.type == Blockly.Events.UI) { + if (primaryEvent instanceof Blockly.Events.Ui) { return; // Don't mirror UI events. } // Convert event to JSON. This could then be transmitted across the net. From 9fd4f8edffa58f447f28593eb0a282cb18a88b14 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 18 Oct 2019 10:23:55 -0700 Subject: [PATCH 071/343] Change branch name format --- gulpfile.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 288a487a4..649accc9e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -800,16 +800,12 @@ function getRebuildBranchName() { return 'rebuild_' + mm + '_' + dd + '_' + yyyy; }; -// Helper function: get a name for a rebuild branch. Format: rebuild_month_yyyy. +// Helper function: get a name for a rebuild branch. Format: rebuild_yyyy_mm. function getRCBranchName() { var date = new Date(); - var monthNames = [ - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' - ]; - var month = monthNames[date.getMonth()]; - var yy = date.getFullYear().slice(-2); - return 'rc_' + month + '_' + yyyy; + var mm = date.getMonth() + 1; // Month, 0-11 + var yyyy = date.getFullYear(); + return 'rc_' + yyyy + '_' + mm; }; // Recompile and push to origin. From ff87c135eedbf7576d5d78dcef214faca8590f46 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 18 Oct 2019 10:56:47 -0700 Subject: [PATCH 072/343] 3.20191018.0-develop --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e149f20aa..2bdeb72e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "2.20190722.0-develop", + "version": "3.20191018.0-develop", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 41f86d187..7e25ac26a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "3.20191014.0-develop", + "version": "3.20191018.0-develop", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" From 3946b56a261278001a7efeb237eb0a8907c86118 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 18 Oct 2019 14:23:17 -0700 Subject: [PATCH 073/343] Add script to bump minor version number Creates a new branch, bumps, builds, tags, and pushes the new branch and new tag. --- gulpfile.js | 39 +++++++++++++++++++++++++++++++++++++-- package.json | 4 ++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index d879fdb84..f31e784f9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -37,6 +37,7 @@ var closureCompiler = require('google-closure-compiler').gulp(); var packageJson = require('./package.json'); var argv = require('yargs').argv; +const upstream_url = "https://github.com/google/blockly.git"; //////////////////////////////////////////////////////////// // Build // @@ -779,7 +780,7 @@ function syncBranch(branchName) { return function(done) { execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); execSync('git checkout ' + branchName, { stdio: 'inherit' }); - execSync('git pull https://github.com/google/blockly.git ' + branchName, + execSync('git pull ' + upstream_url + ' ' + branchName, { stdio: 'inherit' }); execSync('git push origin ' + branchName, { stdio: 'inherit' }); done(); @@ -809,6 +810,15 @@ function getRCBranchName() { return 'rc_' + yyyy + '_' + mm; }; +// Helper function: get a minor version number for the day. Format: yyyymmdd. +function getNewMinorVersionNumber() { + var date = new Date(); + var mm = date.getMonth() + 1; // Month, 0-11 + var dd = date.getDate(); // Day of the month, 1-31 + var yyyy = date.getFullYear(); + return yyyy + '' + mm + '' + dd; +}; + // Recompile and push to origin. gulp.task('recompile', gulp.series([ 'git-sync-develop', @@ -838,9 +848,34 @@ gulp.task('git-create-rc', gulp.series([ function(done) { var branchName = getRCBranchName(); execSync('git checkout -b ' + branchName, { stdio: 'inherit' }); - execSync('git push https://github.com/google/blockly.git ' + branchName, + execSync('git push ' + upstream_url + ' ' + branchName, { stdio: 'inherit' }); done(); }, ]) ); + +// See https://docs.npmjs.com/cli/version. +gulp.task('preversion', gulp.series([ + 'git-sync-master', + function(done) { + // Create a branch named bump_version for the bump and rebuild. + execSync('git checkout -b bump_version', { stdio: 'inherit' }); + done(); + }, + ]) +); + +// See https://docs.npmjs.com/cli/version +gulp.task('postversion', gulp.series([ + function(done) { + // Push both the branch and tag to google/blockly. + execSync('git push ' + upstream_url + ' bump_version', + { stdio: 'inherit' }); + var tagName = 'v' + packageJson.version; + execSync('git push ' + upstream_url + ' ' + tagName, + { stdio: 'inherit' }); + done(); + } + ]) +); diff --git a/package.json b/package.json index 7e25ac26a..e7b9d8b9a 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,10 @@ "scripts": { "build": "gulp build", "build:debug": "gulp build-core --verbose > build-debug.log 2>&1 && tail -3 -r build-debug.log", + "bump": "npm version 3.$(date +'%Y%m%d').0", + "version": "gulp build && git add -A", + "preversion": "gulp preversion", + "postversion": "gulp postversion", "lint": "eslint .", "package": "gulp package", "prepare": "npm run package", From e716283191148f5978174e7a17573ff25f34b3a5 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 18 Oct 2019 10:56:47 -0700 Subject: [PATCH 074/343] Revert "3.20191018.0-develop" This reverts commit ff87c135eedbf7576d5d78dcef214faca8590f46. --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2bdeb72e1..e149f20aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "3.20191018.0-develop", + "version": "2.20190722.0-develop", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e7b9d8b9a..02fbdbb10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "3.20191018.0-develop", + "version": "3.20191014.0-develop", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" From 3556f69233b8631c7b4a527d9922e21d79205d38 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Sat, 19 Oct 2019 23:19:37 -0700 Subject: [PATCH 075/343] Messages are no longer compiled in. --- tests/compile/compile.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/compile/compile.sh b/tests/compile/compile.sh index f6136a9bc..94d1e5b18 100755 --- a/tests/compile/compile.sh +++ b/tests/compile/compile.sh @@ -77,7 +77,6 @@ COMPILATION_COMMAND="java -jar $COMPILER --js='$BLOCKLY_ROOT/tests/compile/main. --js='$tempPath/**.js' \ --js='$BLOCKLY_ROOT/blocks/**.js' \ --js='$BLOCKLY_ROOT/generators/**.js' \ - --js='$BLOCKLY_ROOT/msg/js/**.js' \ --generate_exports \ --externs $BLOCKLY_ROOT/externs/svg-externs.js \ --compilation_level ADVANCED_OPTIMIZATIONS \ From a58b2d81e0d46da181191f5cc7233583192641f2 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 21 Oct 2019 16:55:38 +0200 Subject: [PATCH 076/343] Localisation updates from https://translatewiki.net. --- msg/json/fi.json | 1 + 1 file changed, 1 insertion(+) diff --git a/msg/json/fi.json b/msg/json/fi.json index 5c7c01fdd..a05b7141c 100644 --- a/msg/json/fi.json +++ b/msg/json/fi.json @@ -17,6 +17,7 @@ ] }, "VARIABLES_DEFAULT_NAME": "kohde", + "UNNAMED_KEY": "nimetön", "TODAY": "Tänään", "DUPLICATE_BLOCK": "Kaksoiskappale", "ADD_COMMENT": "Lisää kommentti", From 1e2eb6bd602c45831a589cb3e996745a29671a47 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 21 Oct 2019 10:46:34 -0700 Subject: [PATCH 077/343] Review cleanup --- gulpfile.js | 9 --------- package.json | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index f31e784f9..ce232b7c0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -810,15 +810,6 @@ function getRCBranchName() { return 'rc_' + yyyy + '_' + mm; }; -// Helper function: get a minor version number for the day. Format: yyyymmdd. -function getNewMinorVersionNumber() { - var date = new Date(); - var mm = date.getMonth() + 1; // Month, 0-11 - var dd = date.getDate(); // Day of the month, 1-31 - var yyyy = date.getFullYear(); - return yyyy + '' + mm + '' + dd; -}; - // Recompile and push to origin. gulp.task('recompile', gulp.series([ 'git-sync-develop', diff --git a/package.json b/package.json index 02fbdbb10..612470f57 100644 --- a/package.json +++ b/package.json @@ -20,19 +20,19 @@ "build": "gulp build", "build:debug": "gulp build-core --verbose > build-debug.log 2>&1 && tail -3 -r build-debug.log", "bump": "npm version 3.$(date +'%Y%m%d').0", - "version": "gulp build && git add -A", - "preversion": "gulp preversion", - "postversion": "gulp postversion", "lint": "eslint .", "package": "gulp package", + "postversion": "gulp postversion", "prepare": "npm run package", + "preversion": "gulp preversion", "release": "gulp release", "test": "concurrently 'npm run test:prepare' 'sleep 5 && npm run test:run'", - "test:run": "tests/run_all_tests.sh", "test:prepare": "npm run test:setupselenium && npm run test:startselenium", + "test:run": "tests/run_all_tests.sh", "test:setupselenium": "selenium-standalone install --config=./tests/scripts/selenium-config.js", "test:startselenium": "selenium-standalone start --config=./tests/scripts/selenium-config.js", - "typings": "gulp typings" + "typings": "gulp typings", + "version": "gulp build && git add -A" }, "main": "./index.js", "umd": "./blockly.min.js", From 42552b5b220e0cf4cfa0a80cbeed49cbf157f4e0 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 21 Oct 2019 17:49:38 -0400 Subject: [PATCH 078/343] Fix 6 warnings related to rendering. (#3292) --- closure/goog/base.js | 22 ++++++++++++++++++++++ core/block_svg.js | 14 ++++++++++++++ core/renderers/common/debugger.js | 6 +++++- core/renderers/common/info.js | 2 +- core/renderers/common/path_object.js | 1 - core/renderers/common/renderer.js | 3 +++ core/renderers/geras/measurables/inputs.js | 4 ++-- core/renderers/measurables/connections.js | 2 +- core/renderers/measurables/types.js | 1 - 9 files changed, 48 insertions(+), 7 deletions(-) diff --git a/closure/goog/base.js b/closure/goog/base.js index 73db18742..52a15dbcb 100644 --- a/closure/goog/base.js +++ b/closure/goog/base.js @@ -250,6 +250,28 @@ goog.require = function(namespace) { return null; }; +/** + * Requires a symbol for its type information. This is an indication to the + * compiler that the symbol may appear in type annotations, yet it is not + * referenced at runtime. + * + * When called within a goog.module or ES6 module file, the return value may be + * assigned to or destructured into a variable, but it may not be otherwise used + * in code outside of a type annotation. + * + * Note that all calls to goog.requireType will be stripped by the compiler. + * + * @param {string} namespace Namespace (as was given in goog.provide, + * goog.module, or goog.declareModuleId) in the form + * "goog.package.part". + * @return {?} + */ +goog.requireType = function(namespace) { + // Return an empty object so that single-level destructuring of the return + // value doesn't crash at runtime when using the debug loader. Multi-level + // destructuring isn't supported. + return {}; +}; /** * Path for included scripts. diff --git a/core/block_svg.js b/core/block_svg.js index bfc5c7bb7..9d18f68ed 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -100,6 +100,13 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { /** @type {!Blockly.WorkspaceSvg} */ this.workspace = workspace; + /** @type {Blockly.RenderedConnection} */ + this.outputConnection = null; + /** @type {Blockly.RenderedConnection} */ + this.nextConnection = null; + /** @type {Blockly.RenderedConnection} */ + this.previousConnection = null; + /** * Whether to move the block to the drag surface when it is dragged. * True if it should move, false if it should be translated directly. @@ -239,6 +246,13 @@ Blockly.BlockSvg.prototype.decompose; */ Blockly.BlockSvg.prototype.compose; +/** + * An property used internally to reference the block's rendering debugger. + * @type {?Blockly.blockRendering.Debug} + * @package + */ +Blockly.BlockSvg.prototype.renderingDebugger; + /** * Create and initialize the SVG representation of the block. * May be called more than once. diff --git a/core/renderers/common/debugger.js b/core/renderers/common/debugger.js index a405fc650..fbc876f0d 100644 --- a/core/renderers/common/debugger.js +++ b/core/renderers/common/debugger.js @@ -42,6 +42,7 @@ Blockly.blockRendering.Debug = function() { /** * An array of SVG elements that have been created by this object. * @type {Array.} + * @private */ this.debugElements_ = []; @@ -49,6 +50,7 @@ Blockly.blockRendering.Debug = function() { * The SVG root of the block that is being rendered. Debug elements will * be attached to this root. * @type {SVGElement} + * @private */ this.svgRoot_ = null; }; @@ -178,6 +180,8 @@ Blockly.blockRendering.Debug.prototype.drawRenderedElem = function(elem, isRtl) * share the same colours, as do previous and next. When positioned correctly * a connected pair will look like a bullseye. * @param {Blockly.RenderedConnection} conn The connection to circle. + * @suppress {visibility} Suppress visibility of conn.offsetInBlock_ since this + * is a debug module. * @package */ Blockly.blockRendering.Debug.prototype.drawConnection = function(conn) { @@ -273,7 +277,7 @@ Blockly.blockRendering.Debug.prototype.drawRowWithElements = function(row, curso for (var i = 0, elem; (elem = row.elements[i]); i++) { if (Blockly.blockRendering.Types.isSpacer(elem)) { this.drawSpacerElem( - /** @type {Blockly.blockRendering.InRowSpacer} */ (elem), + /** @type {!Blockly.blockRendering.InRowSpacer} */ (elem), row.height, isRtl); } else { this.drawRenderedElem(elem, isRtl); diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index f39cc9187..ccd046978 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -654,7 +654,7 @@ Blockly.blockRendering.RenderInfo.prototype.getElemCenterline_ = function(row, * Record final position information on elements on the given row, for use in * drawing. At minimum this records xPos and centerline on each element. * @param {!Blockly.blockRendering.Row} row The row containing the elements. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.recordElemPositions_ = function( row) { diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 81370fcdf..07b1aa343 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -32,7 +32,6 @@ goog.require('Blockly.utils.dom'); * An interface for a block's path object. * @param {!SVGElement} _root The root SVG element. * @interface - * @package */ Blockly.blockRendering.IPathObject = function(_root) {}; diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index bd16cef4d..49a83943a 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -30,6 +30,8 @@ goog.require('Blockly.blockRendering.PathObject'); goog.require('Blockly.blockRendering.RenderInfo'); goog.require('Blockly.CursorSvg'); +goog.requireType('Blockly.blockRendering.Debug'); + /** * The base class for a block renderer. @@ -89,6 +91,7 @@ Blockly.blockRendering.Renderer.prototype.makeDrawer_ = function(block, info) { /** * Create a new instance of the renderer's debugger. * @return {!Blockly.blockRendering.Debug} The renderer debugger. + * @suppress {strictModuleDepCheck} Debug renderer only included in playground. * @protected */ Blockly.blockRendering.Renderer.prototype.makeDebugger_ = function() { diff --git a/core/renderers/geras/measurables/inputs.js b/core/renderers/geras/measurables/inputs.js index 441b7550f..de7254f10 100644 --- a/core/renderers/geras/measurables/inputs.js +++ b/core/renderers/geras/measurables/inputs.js @@ -37,7 +37,7 @@ goog.require('Blockly.utils.object'); * information for. * @package * @constructor - * @extends {Blockly.blockRendering.InputConnection} + * @extends {Blockly.blockRendering.InlineInput} */ Blockly.geras.InlineInput = function(constants, input) { Blockly.geras.InlineInput.superClass_.constructor.call( @@ -62,7 +62,7 @@ Blockly.utils.object.inherits(Blockly.geras.InlineInput, * information for. * @package * @constructor - * @extends {Blockly.blockRendering.InputConnection} + * @extends {Blockly.blockRendering.StatementInput} */ Blockly.geras.StatementInput = function(constants, input) { Blockly.geras.StatementInput.superClass_.constructor.call( diff --git a/core/renderers/measurables/connections.js b/core/renderers/measurables/connections.js index d514a6439..ca81f5c30 100644 --- a/core/renderers/measurables/connections.js +++ b/core/renderers/measurables/connections.js @@ -36,7 +36,7 @@ goog.require('Blockly.utils.object'); * the block. * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering * constants provider. - * @param {Blockly.RenderedConnection} connectionModel The connection object on + * @param {!Blockly.RenderedConnection} connectionModel The connection object on * the block that this represents. * @package * @constructor diff --git a/core/renderers/measurables/types.js b/core/renderers/measurables/types.js index 02c3c48f6..d31ea79ba 100644 --- a/core/renderers/measurables/types.js +++ b/core/renderers/measurables/types.js @@ -28,7 +28,6 @@ goog.provide('Blockly.blockRendering.Types'); /** * Types of rendering elements. * @enum {number} - * @package */ Blockly.blockRendering.Types = { NONE: 0, // None From d48859e338808805d3557b9c13f7e25bd6a8df91 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 21 Oct 2019 15:35:53 -0700 Subject: [PATCH 079/343] Fix #3191 --- core/renderers/common/info.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index ccd046978..4e2915ba0 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -531,6 +531,9 @@ Blockly.blockRendering.RenderInfo.prototype.addAlignmentPadding_ = function(row, if (lastSpacer) { lastSpacer.width += missingSpace; row.width += missingSpace; + if (row.hasExternalInput || row.hasStatement) { + row.widthWithConnectedBlocks += missingSpace; + } } }; From 6d8f22f39a2c21b3933f2eaa0c116b3ec0eb7381 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 21 Oct 2019 21:26:26 -0400 Subject: [PATCH 080/343] Add a lint plugin to ensure we only use ES5 syntax. (#3160) * Add a lint plugin to ensure we only use ES5 only syntax. --- .eslintrc.json | 8 ++++++-- core/utils/object.js | 2 ++ gulpfile.js | 1 + package-lock.json | 6 ++++++ package.json | 1 + tests/compile/compile.sh | 2 ++ tests/node/run_node_test.js | 34 +++++++++++++++++----------------- 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index e474d8566..3df051d4a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -74,7 +74,8 @@ "balanced": true }, "exceptions": ["*"] - }] + }], + "es5/no-es6-methods": ["warn"] }, "env": { "browser": true @@ -83,5 +84,8 @@ "Blockly": true, "goog": true }, - "extends": "eslint:recommended" + "extends": [ + "eslint:recommended", + "plugin:es5/no-es2015" + ] } diff --git a/core/utils/object.js b/core/utils/object.js index f8b6a55ba..2a9b848a9 100644 --- a/core/utils/object.js +++ b/core/utils/object.js @@ -55,7 +55,9 @@ Blockly.utils.object.mixin = function(target, source) { */ Blockly.utils.object.values = function(obj) { if (Object.values) { + /* eslint-disable es5/no-es6-methods */ return Object.values(obj); + /* eslint-enable es5/no-es6-methods */ } // Fallback for IE. return Object.keys(obj).map(function(e) { diff --git a/gulpfile.js b/gulpfile.js index ce232b7c0..8959fbc42 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -88,6 +88,7 @@ function compile(compilerOptions, opt_verbose) { if (!compilerOptions) compilerOptions = {}; compilerOptions.compilation_level = 'SIMPLE_OPTIMIZATIONS'; compilerOptions.warning_level = opt_verbose ? 'VERBOSE' : 'DEFAULT'; + compilerOptions.language_in = 'ECMASCRIPT5_STRICT'; compilerOptions.language_out = 'ECMASCRIPT5_STRICT'; compilerOptions.rewrite_polyfills = false; compilerOptions.hide_warnings_for = 'node_modules'; diff --git a/package-lock.json b/package-lock.json index e149f20aa..fcf27e0d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1612,6 +1612,12 @@ "text-table": "^0.2.0" } }, + "eslint-plugin-es5": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es5/-/eslint-plugin-es5-1.4.1.tgz", + "integrity": "sha512-kktkmkF2O7pnSZYgrMiYMbt3wCKRIiXePwILv8USDG95YgP0PzhIxSIROLLKmiQQ/Z6LuhDGWTHK04gnbXBvkg==", + "dev": true + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", diff --git a/package.json b/package.json index 612470f57..d03df46a2 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "chai": "^4.2.0", "concurrently": "^4.1.2", "eslint": "^5.13.0", + "eslint-plugin-es5": "^1.4.1", "fs": "0.0.1-security", "google-closure-compiler": "^20190618.0.0", "google-closure-library": "^20190618.0.0", diff --git a/tests/compile/compile.sh b/tests/compile/compile.sh index 94d1e5b18..66486303c 100755 --- a/tests/compile/compile.sh +++ b/tests/compile/compile.sh @@ -80,6 +80,8 @@ COMPILATION_COMMAND="java -jar $COMPILER --js='$BLOCKLY_ROOT/tests/compile/main. --generate_exports \ --externs $BLOCKLY_ROOT/externs/svg-externs.js \ --compilation_level ADVANCED_OPTIMIZATIONS \ + --language_in ECMASCRIPT5_STRICT \ + --language_out ECMASCRIPT5_STRICT \ --dependency_mode=STRICT --entry_point=Main \ --js_output_file $BLOCKLY_ROOT/tests/compile/main_compressed.js" echo "$COMPILATION_COMMAND" diff --git a/tests/node/run_node_test.js b/tests/node/run_node_test.js index 7e2530662..2c3890348 100644 --- a/tests/node/run_node_test.js +++ b/tests/node/run_node_test.js @@ -22,28 +22,28 @@ var assert = require('chai').assert; var Blockly = require('../../dist/'); -var xmlText = ` - - - - Hello from Blockly! - - - -`; +var xmlText = '\n' + +' \n' + +' \n' + +' \n' + +' Hello from Blockly!\n' + +' \n' + +' \n' + +' \n' + +''; suite('Test Node.js', function() { test('Import XML', function() { - const xml = Blockly.Xml.textToDom(xmlText); + var xml = Blockly.Xml.textToDom(xmlText); // Create workspace and import the XML - const workspace = new Blockly.Workspace(); + var workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(xml, workspace); }); test('Roundtrip XML', function() { - const xml = Blockly.Xml.textToDom(xmlText); + var xml = Blockly.Xml.textToDom(xmlText); - const workspace = new Blockly.Workspace(); + var workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(xml, workspace); var headlessXml = Blockly.Xml.workspaceToDom(workspace, true); @@ -52,17 +52,17 @@ suite('Test Node.js', function() { assert.equal(headlessText, xmlText, 'equal'); }); test('Generate Code', function() { - const xml = Blockly.Xml.textToDom(xmlText); + var xml = Blockly.Xml.textToDom(xmlText); // Create workspace and import the XML - const workspace = new Blockly.Workspace(); + var workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(xml, workspace); // Convert code - const code = Blockly.JavaScript.workspaceToCode(workspace); + var code = Blockly.JavaScript.workspaceToCode(workspace); // Check output - assert.equal(`window.alert('Hello from Blockly!');`, code.trim(), 'equal'); + assert.equal('window.alert(\'Hello from Blockly!\');', code.trim(), 'equal'); }); }); From c00ee908e4a01b204f1881fb7ff39e3513454511 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 21 Oct 2019 18:51:04 -0700 Subject: [PATCH 081/343] Removed positionNewBlock (#3300) * Removed positionNewBlock --- core/block_svg.js | 35 +++++--------------------------- core/insertion_marker_manager.js | 4 ++-- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 9d18f68ed..850657ea6 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1694,10 +1694,11 @@ Blockly.BlockSvg.prototype.scheduleSnapAndBump = function() { * 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.Connection} sourceConnection The connection on the moving - * block's stack. - * @param {!Blockly.Connection} targetConnection The connection that should stay - * stationary as this block is positioned. + * @param {!Blockly.RenderedConnection} sourceConnection The connection on the + * moving block's stack. + * @param {!Blockly.RenderedConnection} targetConnection The connection that + * should stay stationary as this block is positioned. + * @package */ Blockly.BlockSvg.prototype.positionNearConnection = function(sourceConnection, targetConnection) { @@ -1837,32 +1838,6 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { return {height: height, width: width}; }; -/** - * Position a new block correctly, so that it doesn't move the existing block - * when connected to it. - * @param {!Blockly.Block} newBlock The block to position - either the first - * block in a dragged stack or an insertion marker. - * @param {!Blockly.Connection} newConnection The connection on the new block's - * stack - either a connection on newBlock, or the last NEXT_STATEMENT - * connection on the stack if the stack's being dropped before another - * block. - * @param {!Blockly.Connection} existingConnection The connection on the - * existing block, which newBlock should line up with. - * @package - */ -Blockly.BlockSvg.prototype.positionNewBlock = function(newBlock, newConnection, - existingConnection) { - // 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 (newConnection.type == Blockly.NEXT_STATEMENT || - newConnection.type == Blockly.INPUT_VALUE) { - var dx = existingConnection.x_ - newConnection.x_; - var dy = existingConnection.y_ - newConnection.y_; - - newBlock.moveBy(dx, dy); - } -}; - /** * Visual effect to show that if the dragging block is dropped, this block will * be replaced. If a shadow block, it will disappear. Otherwise it will bump. diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 3e9c234f0..1159ad4a8 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -668,8 +668,8 @@ Blockly.InsertionMarkerManager.prototype.connectMarker_ = function() { imBlock.rendered = true; imBlock.getSvgRoot().setAttribute('visibility', 'visible'); - // Position based on the calculated connection locations. - imBlock.positionNewBlock(imBlock, imConn, closest); + // Position so that the existing block doesn't move. + imBlock.positionNearConnection(imConn, closest); // Connect() also renders the insertion marker. imConn.connect(closest); From a9cd25f2a4413da3f3928d0aa2003c7a4b472183 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 21 Oct 2019 22:20:04 -0400 Subject: [PATCH 082/343] Fix 6 warnings related to generators. (#3293) --- core/generator.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/core/generator.js b/core/generator.js index 7ae832e1e..053095f27 100644 --- a/core/generator.js +++ b/core/generator.js @@ -374,6 +374,28 @@ Blockly.Generator.prototype.addReservedWords = function(words) { */ Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}'; +/** + * A dictionary of definitions to be printed before the code. + * @type {Object} + * @protected + */ +Blockly.Generator.prototype.definitions_; + +/** + * A dictionary mapping desired function names in definitions_ to actual + * function names (to avoid collisions with user functions). + * @type {Object} + * @protected + */ +Blockly.Generator.prototype.functionNames_; + +/** + * A database of variable names. + * @type {Blockly.Names} + * @protected + */ +Blockly.Generator.prototype.variableDB_; + /** * Define a function to be included in the generated code. * The first time this is called with a given desiredName, the code is @@ -394,7 +416,7 @@ Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}'; Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) { if (!this.definitions_[desiredName]) { var functionName = this.variableDB_.getDistinctName(desiredName, - Blockly.Procedures.NAME_TYPE); + Blockly.PROCEDURE_CATEGORY_NAME); this.functionNames_[desiredName] = functionName; var codeText = code.join('\n').replace( this.FUNCTION_NAME_PLACEHOLDER_REGEXP_, functionName); From b19e6a5fbf1bcbbc8bca3481f957d4ded373b74f Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Tue, 22 Oct 2019 04:33:13 -0500 Subject: [PATCH 083/343] Remove deprectaed use of Blockly.Procedures.NAME_TYPE (#3301) --- generators/dart/procedures.js | 4 ++-- generators/javascript/procedures.js | 4 ++-- generators/lua/procedures.js | 4 ++-- generators/php/procedures.js | 4 ++-- generators/python/procedures.js | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index b9c628607..84fe8f759 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -29,7 +29,7 @@ goog.require('Blockly.Dart'); Blockly.Dart['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), - Blockly.Procedures.NAME_TYPE); + Blockly.PROCEDURE_CATEGORY_NAME); var xfix1 = ''; if (Blockly.Dart.STATEMENT_PREFIX) { xfix1 += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block); @@ -78,7 +78,7 @@ Blockly.Dart['procedures_defnoreturn'] = Blockly.Dart['procedures_defreturn']; Blockly.Dart['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), - Blockly.Procedures.NAME_TYPE); + Blockly.PROCEDURE_CATEGORY_NAME); var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.Dart.valueToCode(block, 'ARG' + i, diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index 6225f14c3..262c844c7 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -29,7 +29,7 @@ goog.require('Blockly.JavaScript'); Blockly.JavaScript['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var xfix1 = ''; if (Blockly.JavaScript.STATEMENT_PREFIX) { xfix1 += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, @@ -80,7 +80,7 @@ Blockly.JavaScript['procedures_defnoreturn'] = Blockly.JavaScript['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.JavaScript.valueToCode(block, 'ARG' + i, diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 3bf01e07f..d838130c7 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -29,7 +29,7 @@ goog.require('Blockly.Lua'); Blockly.Lua['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.Lua.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var xfix1 = ''; if (Blockly.Lua.STATEMENT_PREFIX) { xfix1 += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block); @@ -80,7 +80,7 @@ Blockly.Lua['procedures_defnoreturn'] = Blockly.Lua['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.Lua.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.Lua.valueToCode(block, 'ARG' + i, diff --git a/generators/php/procedures.js b/generators/php/procedures.js index ec70ace1a..c4b216201 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -50,7 +50,7 @@ Blockly.PHP['procedures_defreturn'] = function(block) { Blockly.PHP.INDENT + 'global ' + globals.join(', ') + ';\n' : ''; var funcName = Blockly.PHP.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var xfix1 = ''; if (Blockly.PHP.STATEMENT_PREFIX) { xfix1 += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block); @@ -99,7 +99,7 @@ Blockly.PHP['procedures_defnoreturn'] = Blockly.PHP['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.PHP.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.PHP.valueToCode(block, 'ARG' + i, diff --git a/generators/python/procedures.js b/generators/python/procedures.js index 38559bbe9..ee4152b38 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -51,7 +51,7 @@ Blockly.Python['procedures_defreturn'] = function(block) { globals = globals.length ? Blockly.Python.INDENT + 'global ' + globals.join(', ') + '\n' : ''; var funcName = Blockly.Python.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); + block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); var xfix1 = ''; if (Blockly.Python.STATEMENT_PREFIX) { xfix1 += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); @@ -102,7 +102,7 @@ Blockly.Python['procedures_defnoreturn'] = Blockly.Python['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'), - Blockly.Procedures.NAME_TYPE); + Blockly.PROCEDURE_CATEGORY_NAME); var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.Python.valueToCode(block, 'ARG' + i, From 36d7e4ff8cddc972969e323ba9fc1781b6b41665 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 08:49:17 -0400 Subject: [PATCH 084/343] Suppress workspace comment module not included while Workspace comments are not bundled in. (#3303) --- core/contextmenu.js | 6 ++++++ core/workspace_svg.js | 2 ++ core/xml.js | 2 ++ 3 files changed, 10 insertions(+) diff --git a/core/contextmenu.js b/core/contextmenu.js index 5d19bd0f7..e1eee486b 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -300,6 +300,8 @@ Blockly.ContextMenu.blockCommentOption = function(block) { * right-click originated. * @return {!Object} A menu option, containing text, enabled, and a callback. * @package + * @suppress {checkTypes} Suppress checks while workspace comments are not + * bundled in. */ Blockly.ContextMenu.commentDeleteOption = function(comment) { var deleteOption = { @@ -320,6 +322,8 @@ Blockly.ContextMenu.commentDeleteOption = function(comment) { * right-click originated. * @return {!Object} A menu option, containing text, enabled, and a callback. * @package + * @suppress {checkTypes} Suppress checks while workspace comments are not + * bundled in. */ Blockly.ContextMenu.commentDuplicateOption = function(comment) { var duplicateOption = { @@ -339,6 +343,8 @@ Blockly.ContextMenu.commentDuplicateOption = function(comment) { * @param {!Event} e The right-click mouse event. * @return {!Object} A menu option, containing text, enabled, and a callback. * @package + * @suppress {strictModuleDepCheck,checkTypes} Suppress checks while workspace + * comments are not bundled in. */ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { if (!Blockly.WorkspaceCommentSvg) { diff --git a/core/workspace_svg.js b/core/workspace_svg.js index fd9fba79a..a88339f39 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1261,6 +1261,8 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { * Paste the provided comment onto the workspace. * @param {!Element} xmlComment XML workspace comment element. * @private + * @suppress {checkTypes} Suppress checks while workspace comments are not + * bundled in. */ Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { Blockly.Events.disable(); diff --git a/core/xml.js b/core/xml.js index 1125e1a7f..f581da08f 100644 --- a/core/xml.js +++ b/core/xml.js @@ -371,6 +371,8 @@ Blockly.Xml.clearWorkspaceAndLoadFromXml = function(xml, workspace) { * @param {!Element} xml XML DOM. * @param {!Blockly.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) { From b977280566bd570e9ab20d3449294491a9ad8c23 Mon Sep 17 00:00:00 2001 From: Shannon Kao Date: Tue, 22 Oct 2019 11:15:05 -0700 Subject: [PATCH 085/343] Handle 0x hex values in color parsing --- core/utils/colour.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/utils/colour.js b/core/utils/colour.js index 849737448..c64da4aef 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -37,6 +37,7 @@ goog.require('Blockly.utils'); * .parse('red') -> '#ff0000' * .parse('#f00') -> '#ff0000' * .parse('#ff0000') -> '#ff0000' + * .parse('0xff0000') -> '#ff0000' * .parse('rgb(255, 0, 0)') -> '#ff0000' * @param {string} str Colour in some CSS format. * @return {string|null} A string containing a hex representation of the colour, @@ -49,7 +50,8 @@ Blockly.utils.colour.parse = function(str) { // e.g. 'red' return hex; } - hex = str[0] == '#' ? str : '#' + str; + hex = str.substring(0, 2) == '0x' ? '#' + str.substring(2) : str; + hex = hex[0] == '#' ? hex : '#' + hex; if (/^#[0-9a-f]{6}$/.test(hex)) { // e.g. '#00ff88' return hex; @@ -92,7 +94,12 @@ Blockly.utils.colour.rgbToHex = function(r, g, b) { * @return {!Array.} RGB representation of the colour. */ Blockly.utils.colour.hexToRgb = function(hexColour) { - var rgb = parseInt(hexColour.substr(1), 16); + var hex = Blockly.utils.colour.parse(hexColour); + if (!hex) { + return [0, 0, 0]; + } + + var rgb = parseInt(hex.substr(1), 16); var r = rgb >> 16; var g = (rgb >> 8) & 255; var b = rgb & 255; From 4f02ceeba0b7bd042ee80e7845b620b58b638457 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 14:20:26 -0400 Subject: [PATCH 086/343] Make Blockly options an interface (#3312) * Make workspace options an interface so it can be extended in the d.ts. --- core/flyout_horizontal.js | 6 ++++-- core/flyout_vertical.js | 6 ++++-- core/inject.js | 5 +++-- core/options.js | 13 +++++++++++-- core/toolbox.js | 4 ++-- core/trashcan.js | 4 ++-- core/workspace_svg.js | 6 +++--- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index cf76bff3d..23bcb918b 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -34,12 +34,14 @@ goog.require('Blockly.WidgetDiv'); /** * Class for a flyout. - * @param {!Object} workspaceOptions Dictionary of options for the workspace. + * @param {!Blockly.Options} workspaceOptions Dictionary of options for the + * workspace. * @extends {Blockly.Flyout} * @constructor */ Blockly.HorizontalFlyout = function(workspaceOptions) { - workspaceOptions.getMetrics = this.getMetrics_.bind(this); + workspaceOptions.getMetrics = /** @type {function():!Object} */ ( + this.getMetrics_.bind(this)); workspaceOptions.setMetrics = this.setMetrics_.bind(this); Blockly.HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions); diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index ac380f303..0e8eb0a19 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -35,12 +35,14 @@ goog.require('Blockly.WidgetDiv'); /** * Class for a flyout. - * @param {!Object} workspaceOptions Dictionary of options for the workspace. + * @param {!Blockly.Options} workspaceOptions Dictionary of options for the + * workspace. * @extends {Blockly.Flyout} * @constructor */ Blockly.VerticalFlyout = function(workspaceOptions) { - workspaceOptions.getMetrics = this.getMetrics_.bind(this); + workspaceOptions.getMetrics = /** @type {function():!Object} */ ( + this.getMetrics_.bind(this)); workspaceOptions.setMetrics = this.setMetrics_.bind(this); Blockly.VerticalFlyout.superClass_.constructor.call(this, workspaceOptions); diff --git a/core/inject.js b/core/inject.js index 1d9b72f8b..456a35af5 100644 --- a/core/inject.js +++ b/core/inject.js @@ -43,7 +43,7 @@ goog.require('Blockly.WorkspaceSvg'); * Inject a Blockly editor into the specified container element (usually a div). * @param {Element|string} container Containing element, or its ID, * or a CSS selector. - * @param {Object=} opt_options Optional dictionary of options. + * @param {Blockly.BlocklyOptions=} opt_options Optional dictionary of options. * @return {!Blockly.WorkspaceSvg} Newly created main workspace. */ Blockly.inject = function(container, opt_options) { @@ -57,7 +57,8 @@ Blockly.inject = function(container, opt_options) { if (!container || !Blockly.utils.dom.containsNode(document, container)) { throw Error('Error: container is not in current document.'); } - var options = new Blockly.Options(opt_options || {}); + var options = new Blockly.Options(opt_options || + (/** @type {!Blockly.BlocklyOptions} */ ({}))); var subContainer = document.createElement('div'); subContainer.className = 'injectionDiv'; container.appendChild(subContainer); diff --git a/core/options.js b/core/options.js index c02b44cc7..68884d608 100644 --- a/core/options.js +++ b/core/options.js @@ -30,8 +30,8 @@ goog.require('Blockly.Xml'); /** * Parse the user-specified options, using reasonable defaults where behaviour * is unspecified. - * @param {!Object} options Dictionary of options. Specification: - * https://developers.google.com/blockly/guides/get-started/web#configuration + * @param {!Blockly.BlocklyOptions} options Dictionary of options. + * Specification: https://developers.google.com/blockly/guides/get-started/web#configuration * @constructor */ Blockly.Options = function(options) { @@ -146,6 +146,13 @@ Blockly.Options = function(options) { this.renderer = renderer; }; +/** + * Blockly options. + * This interface is further described in `typings/blockly-interfaces.d.ts`. + * @interface + */ +Blockly.BlocklyOptions = function() {}; + /** * The parent of the current workspace, or null if there is no parent workspace. * @type {Blockly.Workspace} @@ -154,6 +161,8 @@ Blockly.Options.prototype.parentWorkspace = null; /** * If set, sets the translation of the workspace to match the scrollbars. + * @param {!Object} xyRatio Contains an x and/or y property which is a float + * between 0 and 1 specifying the degree of scrolling. * @return {void} */ Blockly.Options.prototype.setMetrics; diff --git a/core/toolbox.js b/core/toolbox.js index 448eded68..f8914d894 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -178,7 +178,7 @@ Blockly.Toolbox.prototype.init = function() { } Blockly.Touch.clearTouchIdentifier(); // Don't block future drags. }, /* opt_noCaptureIdentifier */ false, /* opt_noPreventDefault */ true); - var workspaceOptions = { + var workspaceOptions = /** @type {!Blockly.Options} */ ({ disabledPatternId: workspace.options.disabledPatternId, parentWorkspace: workspace, RTL: workspace.RTL, @@ -186,7 +186,7 @@ Blockly.Toolbox.prototype.init = function() { horizontalLayout: workspace.horizontalLayout, toolboxPosition: workspace.options.toolboxPosition, renderer: workspace.options.renderer - }; + }); if (workspace.horizontalLayout) { if (!Blockly.HorizontalFlyout) { throw Error('Missing require for Blockly.HorizontalFlyout'); diff --git a/core/trashcan.js b/core/trashcan.js index fecc23a06..0032e4712 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -60,14 +60,14 @@ Blockly.Trashcan = function(workspace) { return; } // Create flyout options. - var flyoutWorkspaceOptions = { + var flyoutWorkspaceOptions = /** @type {!Blockly.Options} */ ({ scrollbars: true, disabledPatternId: this.workspace_.options.disabledPatternId, parentWorkspace: this.workspace_, RTL: this.workspace_.RTL, oneBasedIndex: this.workspace_.options.oneBasedIndex, renderer: this.workspace_.options.renderer - }; + }); // Create vertical or horizontal flyout. if (this.workspace_.horizontalLayout) { flyoutWorkspaceOptions.toolboxPosition = diff --git a/core/workspace_svg.js b/core/workspace_svg.js index a88339f39..0e4ad2eab 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -62,7 +62,7 @@ Blockly.WorkspaceSvg = function(options, /** @type {function():!Object} */ this.getMetrics = options.getMetrics || Blockly.WorkspaceSvg.getTopLevelWorkspaceMetrics_; - /** @type {function(!Object)} */ + /** @type {function(!Object):void} */ this.setMetrics = options.setMetrics || Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_; @@ -804,7 +804,7 @@ Blockly.WorkspaceSvg.prototype.addZoomControls = function() { * @package */ Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { - var workspaceOptions = { + var workspaceOptions = /** @type {!Blockly.Options} */ ({ disabledPatternId: this.options.disabledPatternId, parentWorkspace: this, RTL: this.RTL, @@ -812,7 +812,7 @@ Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { horizontalLayout: this.horizontalLayout, toolboxPosition: this.options.toolboxPosition, renderer: this.options.renderer - }; + }); if (this.horizontalLayout) { if (!Blockly.HorizontalFlyout) { throw Error('Missing require for Blockly.HorizontalFlyout'); From 91717854c0564b4500d5484c26f15f460e6c1dc9 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 14:20:42 -0400 Subject: [PATCH 087/343] Fix warnings related to insertion markers. (#3309) --- core/block_svg.js | 50 ++++++++++++++++++++++++++++++++ core/insertion_marker_manager.js | 30 ++++++++++--------- core/rendered_connection.js | 20 +++++++++++++ 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 850657ea6..9c0b68279 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1612,6 +1612,35 @@ Blockly.BlockSvg.prototype.getConnections_ = function(all) { return myConnections; }; +/** + * Walks down a stack of blocks and finds the last next connection on the stack. + * @return {Blockly.RenderedConnection} The last next connection on the stack, + * or null. + * @package + * @override + */ +Blockly.BlockSvg.prototype.lastConnectionInStack = function() { + return /** @type {Blockly.RenderedConnection} */ ( + Blockly.BlockSvg.superClass_.lastConnectionInStack.call(this)); +}; + +/** + * 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, + * or null. + * @package + * @override + */ +Blockly.BlockSvg.prototype.getMatchingConnection = function(otherBlock, conn) { + return /** @type {Blockly.RenderedConnection} */ ( + Blockly.BlockSvg.superClass_.getMatchingConnection.call(this, + otherBlock, conn)); +}; + /** * Create a connection of the specified type. * @param {number} type The type of the connection to create. @@ -1713,6 +1742,27 @@ 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 that holds the current block. + * @override + */ +Blockly.BlockSvg.prototype.getParent = function() { + return /** @type {!Blockly.BlockSvg} */ ( + Blockly.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. + * @override + */ +Blockly.BlockSvg.prototype.getRootBlock = function() { + return /** @type {!Blockly.BlockSvg} */ ( + Blockly.BlockSvg.superClass_.getRootBlock.call(this)); +}; + /** * Render the block. * Lays out and reflows a block based on its contents and settings. diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 1159ad4a8..602d0dae3 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -40,7 +40,7 @@ Blockly.InsertionMarkerManager = function(block) { /** * The top block in the stack being dragged. * Does not change during a drag. - * @type {!Blockly.Block} + * @type {!Blockly.BlockSvg} * @private */ this.topBlock_ = block; @@ -293,7 +293,7 @@ Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function() if (lastOnStack && lastOnStack != this.topBlock_.nextConnection) { available.push(lastOnStack); this.lastOnStack_ = lastOnStack; - this.lastMarker_ = this.createMarkerBlock_(lastOnStack.sourceBlock_); + this.lastMarker_ = this.createMarkerBlock_(lastOnStack.getSourceBlock()); } return available; }; @@ -419,7 +419,7 @@ Blockly.InsertionMarkerManager.prototype.shouldReplace_ = function() { // Connecting to a statement input of c-block is an insertion, even if that // c-block is terminal (e.g. forever). - if (local == local.sourceBlock_.getFirstStatementConnection()) { + if (local == local.getSourceBlock().getFirstStatementConnection()) { return false; // Insert. } @@ -482,7 +482,7 @@ Blockly.InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) // Something went wrong and we're trying to connect to an invalid connection. if (closest == this.closestConnection_ || - closest.sourceBlock_.isInsertionMarker()) { + closest.getSourceBlock().isInsertionMarker()) { console.log('Trying to connect to an insertion marker'); return; } @@ -569,9 +569,9 @@ Blockly.InsertionMarkerManager.prototype.highlightBlock_ = function() { this.highlightedBlock_ = closest.targetBlock(); closest.targetBlock().highlightForReplacement(true); } else if (local.type == Blockly.OUTPUT_VALUE) { - this.highlightedBlock_ = closest.sourceBlock_; + this.highlightedBlock_ = closest.getSourceBlock(); // TODO: remove? - closest.sourceBlock_.highlightShapeForInput(closest, true); + closest.getSourceBlock().highlightShapeForInput(closest, true); } this.highlightingBlock_ = true; }; @@ -605,7 +605,7 @@ Blockly.InsertionMarkerManager.prototype.disconnectMarker_ = function() { } var imConn = this.markerConnection_; - var imBlock = imConn.sourceBlock_; + var imBlock = imConn.getSourceBlock(); var markerNext = imBlock.nextConnection; var markerPrev = imBlock.previousConnection; var markerOutput = imBlock.outputConnection; @@ -623,7 +623,7 @@ Blockly.InsertionMarkerManager.prototype.disconnectMarker_ = function() { // Inside of a C-block, first statement connection. else if (imConn.type == Blockly.NEXT_STATEMENT && imConn != markerNext) { var innerConnection = imConn.targetConnection; - innerConnection.sourceBlock_.unplug(false); + innerConnection.getSourceBlock().unplug(false); var previousBlockNextConnection = markerPrev ? markerPrev.targetConnection : null; @@ -655,7 +655,7 @@ Blockly.InsertionMarkerManager.prototype.connectMarker_ = function() { var isLastInStack = this.lastOnStack_ && local == this.lastOnStack_; var imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_; - var imConn = imBlock.getMatchingConnection(local.sourceBlock_, local); + var imConn = imBlock.getMatchingConnection(local.getSourceBlock(), local); if (imConn == this.markerConnection_) { throw Error('Made it to connectMarker_ even though the marker isn\'t ' + @@ -668,11 +668,15 @@ Blockly.InsertionMarkerManager.prototype.connectMarker_ = function() { imBlock.rendered = true; imBlock.getSvgRoot().setAttribute('visibility', 'visible'); - // Position so that the existing block doesn't move. - imBlock.positionNearConnection(imConn, closest); + if (imConn && closest) { + // Position so that the existing block doesn't move. + imBlock.positionNearConnection(imConn, closest); + } + if (closest) { + // Connect() also renders the insertion marker. + imConn.connect(closest); + } - // Connect() also renders the insertion marker. - imConn.connect(closest); this.markerConnection_ = imConn; }; diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 55ac387ad..1bf5a1bb0 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -86,6 +86,26 @@ Blockly.RenderedConnection.prototype.dispose = function() { } }; +/** + * Get the source block for this connection. + * @return {!Blockly.BlockSvg} The source block. + * @override + */ +Blockly.RenderedConnection.prototype.getSourceBlock = function() { + return /** @type {!Blockly.BlockSvg} */ ( + Blockly.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. + * @override + */ +Blockly.RenderedConnection.prototype.targetBlock = function() { + return /** @type {Blockly.BlockSvg} */ ( + Blockly.RenderedConnection.superClass_.targetBlock.call(this)); +}; + /** * Returns the distance between this connection and another connection in * workspace units. From 270781113da0e46fb57435b82abd980ea43ac60b Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 14:21:00 -0400 Subject: [PATCH 088/343] Fix warnings related to gestures and drag. (#3307) * Fix warnings related to gestures and drag. --- core/block_dragger.js | 2 +- core/block_svg.js | 8 ++++---- core/bubble.js | 4 ++-- core/gesture.js | 25 ++++++++++++++----------- core/touch_gesture.js | 12 ++++++++---- core/workspace_comment_svg.js | 6 +++--- core/workspace_svg.js | 4 ++-- 7 files changed, 34 insertions(+), 27 deletions(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 9b6110f6b..95456e3b2 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -238,7 +238,7 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); - this.draggingBlock_.moveOffDragSurface_(newLoc); + this.draggingBlock_.moveOffDragSurface(newLoc); var deleted = this.maybeDeleteBlock_(); if (!deleted) { diff --git a/core/block_svg.js b/core/block_svg.js index 9c0b68279..7fa053a5b 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -520,9 +520,9 @@ Blockly.BlockSvg.prototype.moveTo = function(xy) { * Does nothing if useDragSurface_ is false. * @param {!Blockly.utils.Coordinate} newXY The position the block should take on * on the workspace canvas, in workspace coordinates. - * @private + * @package */ -Blockly.BlockSvg.prototype.moveOffDragSurface_ = function(newXY) { +Blockly.BlockSvg.prototype.moveOffDragSurface = function(newXY) { if (!this.useDragSurface_) { return; } @@ -868,9 +868,9 @@ Blockly.BlockSvg.prototype.generateContextMenu = function() { /** * Show the context menu for this block. * @param {!Event} e Mouse event. - * @private + * @package */ -Blockly.BlockSvg.prototype.showContextMenu_ = function(e) { +Blockly.BlockSvg.prototype.showContextMenu = function(e) { var menuOptions = this.generateContextMenu(); if (menuOptions && menuOptions.length) { diff --git a/core/bubble.js b/core/bubble.js index a319efcba..388e7ceb8 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -306,9 +306,9 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { /** * Show the context menu for this bubble. * @param {!Event} _e Mouse event. - * @private + * @package */ -Blockly.Bubble.prototype.showContextMenu_ = function(_e) { +Blockly.Bubble.prototype.showContextMenu = function(_e) { // NOP on bubbles, but used by the bubble dragger to pass events to // workspace comments. }; diff --git a/core/gesture.js b/core/gesture.js index c0071aaf9..e7efa7fd9 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -117,7 +117,7 @@ Blockly.Gesture = function(e, creatorWorkspace) { * to the gesture, which will need to be cleared at deletion. * This may be different from the start workspace. For instance, a flyout is * a workspace, but its parent workspace manages gestures for it. - * @type {Blockly.WorkspaceSvg} + * @type {!Blockly.WorkspaceSvg} * @private */ this.creatorWorkspace_ = creatorWorkspace; @@ -288,7 +288,7 @@ Blockly.Gesture.prototype.updateFromEvent_ = function(e) { */ Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) { this.currentDragDeltaXY_ = Blockly.utils.Coordinate.difference(currentXY, - this.mouseDownXY_); + /** @type {!Blockly.utils.Coordinate} */ (this.mouseDownXY_)); if (!this.hasExceededDragRadius_) { var currentDragDelta = Blockly.utils.Coordinate.magnitude( @@ -404,7 +404,8 @@ Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() { if (this.flyout_) { this.workspaceDragger_ = new Blockly.FlyoutDragger(this.flyout_); } else { - this.workspaceDragger_ = new Blockly.WorkspaceDragger(this.startWorkspace_); + this.workspaceDragger_ = new Blockly.WorkspaceDragger( + /** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_)); } this.isDraggingWorkspace_ = true; @@ -441,8 +442,9 @@ Blockly.Gesture.prototype.updateIsDragging_ = function() { * @private */ Blockly.Gesture.prototype.startDraggingBlock_ = function() { - this.blockDragger_ = new Blockly.BlockDragger(this.targetBlock_, - this.startWorkspace_); + this.blockDragger_ = new Blockly.BlockDragger( + /** @type {!Blockly.BlockSvg} */ (this.targetBlock_), + /** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_)); this.blockDragger_.startBlockDrag(this.currentDragDeltaXY_, this.healStack_); this.blockDragger_.dragBlock(this.mostRecentEvent_, this.currentDragDeltaXY_); @@ -454,8 +456,9 @@ Blockly.Gesture.prototype.startDraggingBlock_ = function() { */ // TODO (fenichel): Possibly combine this and startDraggingBlock_. Blockly.Gesture.prototype.startDraggingBubble_ = function() { - this.bubbleDragger_ = new Blockly.BubbleDragger(this.startBubble_, - this.startWorkspace_); + this.bubbleDragger_ = new Blockly.BubbleDragger( + /** @type {!Blockly.Bubble} */ (this.startBubble_), + /** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_)); this.bubbleDragger_.startBubbleDrag(); this.bubbleDragger_.dragBubble(this.mostRecentEvent_, this.currentDragDeltaXY_); @@ -625,12 +628,12 @@ Blockly.Gesture.prototype.handleRightClick = function(e) { if (this.targetBlock_) { this.bringBlockToFront_(); Blockly.hideChaff(!!this.flyout_); - this.targetBlock_.showContextMenu_(e); + this.targetBlock_.showContextMenu(e); } else if (this.startBubble_) { - this.startBubble_.showContextMenu_(e); + this.startBubble_.showContextMenu(e); } else if (this.startWorkspace_ && !this.flyout_) { Blockly.hideChaff(); - this.startWorkspace_.showContextMenu_(e); + this.startWorkspace_.showContextMenu(e); } // TODO: Handle right-click on a bubble. @@ -643,7 +646,7 @@ Blockly.Gesture.prototype.handleRightClick = function(e) { /** * Handle a mousedown/touchstart event on a workspace. * @param {!Event} e A mouse down or touch start event. - * @param {!Blockly.Workspace} ws The workspace the event hit. + * @param {!Blockly.WorkspaceSvg} ws The workspace the event hit. * @package */ Blockly.Gesture.prototype.handleWsStart = function(e, ws) { diff --git a/core/touch_gesture.js b/core/touch_gesture.js index 309ff9744..20c838957 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -235,8 +235,10 @@ Blockly.TouchGesture.prototype.handleTouchStart = function(e) { var pointers = Object.keys(this.cachedPoints_); // If two pointers are down, check for pinch gestures if (pointers.length == 2) { - var point0 = this.cachedPoints_[pointers[0]]; - var point1 = this.cachedPoints_[pointers[1]]; + var point0 = /** @type {!Blockly.utils.Coordinate} */ ( + this.cachedPoints_[pointers[0]]); + var point1 = /** @type {!Blockly.utils.Coordinate} */ ( + this.cachedPoints_[pointers[1]]); this.startDistance_ = Blockly.utils.Coordinate.distance(point0, point1); this.isMultiTouch_ = true; e.preventDefault(); @@ -258,8 +260,10 @@ Blockly.TouchGesture.prototype.handleTouchMove = function(e) { // If two pointers are down, check for pinch gestures if (pointers.length == 2) { // Calculate the distance between the two pointers - var point0 = this.cachedPoints_[pointers[0]]; - var point1 = this.cachedPoints_[pointers[1]]; + var point0 = /** @type {!Blockly.utils.Coordinate} */ ( + this.cachedPoints_[pointers[0]]); + var point1 = /** @type {!Blockly.utils.Coordinate} */ ( + this.cachedPoints_[pointers[1]]); var moveDistance = Blockly.utils.Coordinate.distance(point0, point1); var startDistance = this.startDistance_; var scale = this.touchScale_ = moveDistance / startDistance; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 657bae7d8..c0382740c 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -170,9 +170,9 @@ Blockly.WorkspaceCommentSvg.prototype.pathMouseDown_ = function(e) { /** * Show the context menu for this workspace comment. * @param {!Event} e Mouse event. - * @private + * @package */ -Blockly.WorkspaceCommentSvg.prototype.showContextMenu_ = function(e) { +Blockly.WorkspaceCommentSvg.prototype.showContextMenu = function(e) { if (this.workspace.options.readOnly) { return; } @@ -368,7 +368,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface_ = function() { * on the workspace canvas, in workspace coordinates. * @private */ -Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface_ = function(newXY) { +Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface = function(newXY) { if (!this.useDragSurface_) { return; } diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 0e4ad2eab..d5d8143c6 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1579,9 +1579,9 @@ Blockly.WorkspaceSvg.prototype.cleanUp = function() { /** * Show the context menu for the workspace. * @param {!Event} e Mouse event. - * @private + * @package */ -Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) { +Blockly.WorkspaceSvg.prototype.showContextMenu = function(e) { if (this.options.readOnly || this.isFlyout) { return; } From 90ad0789f6beab2d168baa1934a460d5320a155d Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 14:26:59 -0400 Subject: [PATCH 089/343] Fix 11 warnings related to variables and variable_model. (#3278) * Fix 10 warnings related to variables and variable_model. --- core/block.js | 8 ++++++++ core/variable_map.js | 14 +++++++------- core/variables.js | 10 ++++++---- core/variables_dynamic.js | 6 +++--- core/workspace.js | 6 +++--- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/core/block.js b/core/block.js index 9a439349d..25510b8bf 100644 --- a/core/block.js +++ b/core/block.js @@ -300,6 +300,14 @@ Blockly.Block.prototype.domToMutation; */ Blockly.Block.prototype.suppressPrefixSuffix; +/** + * An optional property for declaring developer variables. Return a list of + * variable names for use by generators. Developer variables are never shown to + * the user, but are declared as global variables in the generated code. + * @type {?function():!Array.} + */ +Blockly.Block.prototype.getDeveloperVariables; + /** * Dispose of this block. * @param {boolean} healStack If true, then try to heal any gap by connecting diff --git a/core/variable_map.js b/core/variable_map.js index 76fefb438..f52aba2e2 100644 --- a/core/variable_map.js +++ b/core/variable_map.js @@ -168,7 +168,7 @@ 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 {!Blockly.VariableModel} The newly created variable. */ Blockly.VariableMap.prototype.createVariable = function(name, opt_type, opt_id) { @@ -248,13 +248,13 @@ Blockly.VariableMap.prototype.deleteVariableById = function(id) { replace('%2', variableName); Blockly.confirm(confirmText, function(ok) { - if (ok) { - map.deleteVariableInternal_(variable, uses); + if (ok && variable) { + map.deleteVariableInternal(variable, uses); } }); } else { // No confirmation necessary for a single block. - map.deleteVariableInternal_(variable, uses); + map.deleteVariableInternal(variable, uses); } } else { console.warn("Can't delete non-existent variable: " + id); @@ -266,9 +266,9 @@ Blockly.VariableMap.prototype.deleteVariableById = function(id) { * user for confirmation. * @param {!Blockly.VariableModel} variable Variable to delete. * @param {!Array.} uses An array of uses of the variable. - * @private + * @package */ -Blockly.VariableMap.prototype.deleteVariableInternal_ = function(variable, +Blockly.VariableMap.prototype.deleteVariableInternal = function(variable, uses) { var existingGroup = Blockly.Events.getGroup(); if (!existingGroup) { @@ -292,7 +292,7 @@ Blockly.VariableMap.prototype.deleteVariableInternal_ = function(variable, * Find the variable by the given name and type and return it. Return null if * it is not found. * @param {string} name The name to check for. - * @param {string=} opt_type The type of the variable. If not provided it + * @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 * it was not found. diff --git a/core/variables.js b/core/variables.js index ab85adb6e..f15d92aff 100644 --- a/core/variables.js +++ b/core/variables.js @@ -500,10 +500,11 @@ Blockly.Variables.getOrCreateVariablePackage = function(workspace, id, opt_name, */ Blockly.Variables.getVariable = function(workspace, id, opt_name, opt_type) { var potentialVariableMap = workspace.getPotentialVariableMap(); + var variable = null; // Try to just get the variable, by ID if possible. if (id) { // Look in the real variable map before checking the potential variable map. - var variable = workspace.getVariableById(id); + variable = workspace.getVariableById(id); if (!variable && potentialVariableMap) { variable = potentialVariableMap.getVariableById(id); } @@ -518,7 +519,7 @@ Blockly.Variables.getVariable = function(workspace, id, opt_name, opt_type) { throw Error('Tried to look up a variable by name without a type'); } // Otherwise look up by name and type. - var variable = workspace.getVariable(opt_name, opt_type); + variable = workspace.getVariable(opt_name, opt_type); if (!variable && potentialVariableMap) { variable = potentialVariableMap.getVariable(opt_name, opt_type); } @@ -547,10 +548,11 @@ Blockly.Variables.createVariable_ = function(workspace, id, opt_name, } // Create a potential variable if in the flyout. + var variable = null; if (potentialVariableMap) { - var variable = potentialVariableMap.createVariable(opt_name, opt_type, id); + variable = potentialVariableMap.createVariable(opt_name, opt_type, id); } else { // In the main workspace, create a real variable. - var variable = workspace.createVariable(opt_name, opt_type, id); + variable = workspace.createVariable(opt_name, opt_type, id); } return variable; }; diff --git a/core/variables_dynamic.js b/core/variables_dynamic.js index e07f03eae..0d8d1548a 100644 --- a/core/variables_dynamic.js +++ b/core/variables_dynamic.js @@ -33,15 +33,15 @@ goog.require('Blockly.VariableModel'); Blockly.VariablesDynamic.onCreateVariableButtonClick_String = function(button) { Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), - null, 'String'); + undefined, 'String'); }; Blockly.VariablesDynamic.onCreateVariableButtonClick_Number = function(button) { Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), - null, 'Number'); + undefined, 'Number'); }; Blockly.VariablesDynamic.onCreateVariableButtonClick_Colour = function(button) { Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), - null, 'Colour'); + undefined, 'Colour'); }; /** * Construct the elements (blocks and button) required by the flyout for the diff --git a/core/workspace.js b/core/workspace.js index abb4ab85d..10d5b11ab 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -516,7 +516,7 @@ 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 {!Blockly.VariableModel} The newly created variable. */ Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id) { return this.variableMap_.createVariable(name, opt_type, opt_id); @@ -548,7 +548,7 @@ Blockly.Workspace.prototype.deleteVariableById = function(id) { * @private */ Blockly.Workspace.prototype.deleteVariableInternal_ = function(variable, uses) { - this.variableMap_.deleteVariableInternal_(variable, uses); + this.variableMap_.deleteVariableInternal(variable, uses); }; /** @@ -593,7 +593,7 @@ 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) { From 18fea2adb322aaf044248229b0fb2a60dea13ced Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 14:28:17 -0400 Subject: [PATCH 090/343] Fix 8 warnings related to utils. (#3294) --- core/keyboard_nav/cursor.js | 2 +- core/ui_menu_utils.js | 2 +- core/utils.js | 5 +++-- core/utils/colour.js | 18 +++++++++++++----- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/core/keyboard_nav/cursor.js b/core/keyboard_nav/cursor.js index 01ed5b737..be9e2d48c 100644 --- a/core/keyboard_nav/cursor.js +++ b/core/keyboard_nav/cursor.js @@ -31,7 +31,7 @@ goog.provide('Blockly.Cursor'); * @constructor */ Blockly.Cursor = function() { - /* + /** * The current location of the cursor. * @type {Blockly.ASTNode} * @private diff --git a/core/ui_menu_utils.js b/core/ui_menu_utils.js index 35907e381..bd77bf750 100644 --- a/core/ui_menu_utils.js +++ b/core/ui_menu_utils.js @@ -39,7 +39,7 @@ goog.require('Blockly.utils.style'); */ Blockly.utils.uiMenu.getSize = function(menu) { var menuDom = menu.getElement(); - var menuSize = Blockly.utils.style.getSize(menuDom); + var menuSize = Blockly.utils.style.getSize(/** @type {!Element} */ (menuDom)); // Recalculate height for the total content, not only box height. menuSize.height = menuDom.scrollHeight; return menuSize; diff --git a/core/utils.js b/core/utils.js index 48f91e64e..f633f6c35 100644 --- a/core/utils.js +++ b/core/utils.js @@ -121,7 +121,7 @@ Blockly.utils.getInjectionDivXY_ = function(element) { if ((' ' + classes + ' ').indexOf(' injectionDiv ') != -1) { break; } - element = element.parentNode; + element = /** @type {!Element} */ (element.parentNode); } return new Blockly.utils.Coordinate(x, y); }; @@ -190,6 +190,7 @@ Blockly.utils.mouseToSvg = function(e, svg, matrix) { Blockly.utils.getScrollDeltaPixels = function(e) { switch (e.deltaMode) { case 0x00: // Pixel mode. + default: return { x: e.deltaX, y: e.deltaY @@ -236,7 +237,7 @@ Blockly.utils.replaceMessageReferences = function(message) { var interpolatedResult = Blockly.utils.tokenizeInterpolation_(message, false); // When parseInterpolationTokens == false, interpolatedResult should be at // most length 1. - return interpolatedResult.length ? interpolatedResult[0] : ''; + return interpolatedResult.length ? String(interpolatedResult[0]) : ''; }; /** diff --git a/core/utils/colour.js b/core/utils/colour.js index 849737448..928fc935b 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -38,8 +38,8 @@ goog.require('Blockly.utils'); * .parse('#f00') -> '#ff0000' * .parse('#ff0000') -> '#ff0000' * .parse('rgb(255, 0, 0)') -> '#ff0000' - * @param {string} str Colour in some CSS format. - * @return {string|null} A string containing a hex representation of the colour, + * @param {string|number} str Colour in some CSS format. + * @return {?string} A string containing a hex representation of the colour, * or null if can't be parsed. */ Blockly.utils.colour.parse = function(str) { @@ -166,11 +166,19 @@ Blockly.utils.colour.hsvToHex = function(h, s, v) { * @param {string} colour2 Second colour. * @param {number} factor The weight to be given to colour1 over colour2. * Values should be in the range [0, 1]. - * @return {string} Combined colour represented in hex. + * @return {?string} Combined colour represented in hex. */ Blockly.utils.colour.blend = function(colour1, colour2, factor) { - var rgb1 = Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(colour1)); - var rgb2 = Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(colour2)); + var hex1 = Blockly.utils.colour.parse(colour1); + if (!hex1) { + return null; + } + var hex2 = Blockly.utils.colour.parse(colour2); + if (!hex2) { + return null; + } + var rgb1 = Blockly.utils.colour.hexToRgb(hex1); + var rgb2 = Blockly.utils.colour.hexToRgb(hex2); var r = Math.round(rgb2[0] + factor * (rgb1[0] - rgb2[0])); var g = Math.round(rgb2[1] + factor * (rgb1[1] - rgb2[1])); var b = Math.round(rgb2[2] + factor * (rgb1[2] - rgb2[2])); From c0c9c0e3d4bc548b89dd60020b3dc5f3e03a7a78 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 22 Oct 2019 15:52:30 -0400 Subject: [PATCH 091/343] Fix scrollbar warnings. (#3310) --- core/scrollbar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/scrollbar.js b/core/scrollbar.js index 92ae14164..538cbb394 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -254,7 +254,7 @@ Blockly.Scrollbar.prototype.origin_ = new Blockly.utils.Coordinate(0, 0); * Units are CSS pixels, with (0, 0) at the top left of the browser window. * For a horizontal scrollbar this is the x coordinate of the mouse down event; * for a vertical scrollbar it's the y coordinate of the mouse down event. - * @type {Blockly.utils.Coordinate} + * @type {number} * @private */ Blockly.Scrollbar.prototype.startDragMouse_ = 0; @@ -306,9 +306,9 @@ if (Blockly.Touch.TOUCH_ENABLED) { } /** - * @param {!Object} first An object containing computed measurements of a + * @param {Object} first An object containing computed measurements of a * workspace. - * @param {!Object} second Another object containing computed measurements of a + * @param {Object} second Another object containing computed measurements of a * workspace. * @return {boolean} Whether the two sets of metrics are equivalent. * @private From ad2c5f69ce2347facd3582425c7cc444c534c947 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 23 Oct 2019 13:07:04 -0400 Subject: [PATCH 092/343] Fix for #3313 (#3316) * Account for output connection with when aligning statement row --- core/renderers/common/info.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 4e2915ba0..5c2ae6fda 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -546,7 +546,7 @@ Blockly.blockRendering.RenderInfo.prototype.addAlignmentPadding_ = function(row, Blockly.blockRendering.RenderInfo.prototype.alignStatementRow_ = function(row) { var statementInput = row.getLastInput(); var currentWidth = row.width - statementInput.width; - var desiredWidth = this.statementEdge - this.startX; + var desiredWidth = this.statementEdge; // Add padding before the statement input. var missingSpace = desiredWidth - currentWidth; if (missingSpace) { From d11b7228c2318f5bb4e7e442719298e61e9d26c9 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 21 Oct 2019 17:21:44 -0700 Subject: [PATCH 093/343] Fix #3228 by only using the dark path offset in Geras. --- core/renderers/common/info.js | 2 +- core/renderers/geras/info.js | 22 ++++++++++++++++++++++ core/renderers/measurables/inputs.js | 3 ++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 4e2915ba0..62841a838 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -309,7 +309,7 @@ Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() { if (followsStatement) { this.bottomRow.minHeight = this.constants_.LARGE_PADDING; } else { - this.bottomRow.minHeight = this.constants_.MEDIUM_PADDING - 1; + this.bottomRow.minHeight = this.constants_.MEDIUM_PADDING; } var leftSquareCorner = this.bottomRow.hasLeftSquareCorner(this.block_); diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 90f1d8238..31b99e6b7 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -73,6 +73,28 @@ Blockly.geras.RenderInfo.prototype.getRenderer = function() { return /** @type {!Blockly.geras.Renderer} */ (this.renderer_); }; +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.populateBottomRow_ = function() { + Blockly.geras.RenderInfo.superClass_.populateBottomRow_.call(this); + + var followsStatement = + this.block_.inputList.length && + this.block_.inputList[this.block_.inputList.length - 1] + .type == Blockly.NEXT_STATEMENT; + + // The minimum height of the bottom row is smaller in Geras than in other + // renderers, because the dark path adds a pixel. + // If one of the row's elements has a greater height this will be overwritten + // in the compute pass. + if (!followsStatement) { + this.bottomRow.minHeight = + this.constants_.MEDIUM_PADDING - this.constants_.DARK_PATH_OFFSET; + } + +}; + /** * @override */ diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index 2d44fd02b..90e6706fb 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -154,7 +154,8 @@ Blockly.blockRendering.ExternalValueInput = function(constants, input) { this.height = this.shape.height; } else { this.height = - this.connectedBlockHeight - 2 * this.constants_.TAB_OFFSET_FROM_TOP; + this.connectedBlockHeight - this.constants_.TAB_OFFSET_FROM_TOP - + this.constants_.MEDIUM_PADDING; } this.width = this.shape.width + this.constants_.EXTERNAL_VALUE_INPUT_PADDING; From fdc9074540057e825ecabf15e39d43c00246b0e3 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Wed, 23 Oct 2019 14:23:37 -0700 Subject: [PATCH 094/343] Color blind themes (#3322) * Add themes for deuteranopia, protanopia, and tritanopia --- blockly_uncompressed.js | 16 +++--- core/requires.js | 4 +- core/theme/deuteranopia.js | 114 +++++++++++++++++++++++++++++++++++++ core/theme/tritanopia.js | 113 ++++++++++++++++++++++++++++++++++++ tests/playground.html | 14 ++++- 5 files changed, 250 insertions(+), 11 deletions(-) create mode 100644 core/theme/deuteranopia.js create mode 100644 core/theme/tritanopia.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 2165245fa..43ec6e9f2 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -24,7 +24,7 @@ this.BLOCKLY_BOOT = function(root) { goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.colour', 'Blockly.utils.object', 'Blockly.fieldRegistry', 'Blockly.utils.string', 'Blockly.Workspace']); goog.addDependency("../../core/block_animations.js", ['Blockly.blockAnimations'], ['Blockly.utils.dom']); goog.addDependency("../../core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); -goog.addDependency("../../core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.blockAnimations', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.InsertionMarkerManager', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); +goog.addDependency("../../core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.blockAnimations', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Ui', 'Blockly.InsertionMarkerManager', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Warning']); goog.addDependency("../../core/blockly.js", ['Blockly'], ['Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.inject', 'Blockly.navigation', 'Blockly.Procedures', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); @@ -39,7 +39,7 @@ goog.addDependency("../../core/components/tree/basenode.js", ['Blockly.tree.Base goog.addDependency("../../core/components/tree/treecontrol.js", ['Blockly.tree.TreeControl'], ['Blockly.tree.TreeNode', 'Blockly.tree.BaseNode', 'Blockly.utils.aria', 'Blockly.utils.object', 'Blockly.utils.style']); goog.addDependency("../../core/components/tree/treenode.js", ['Blockly.tree.TreeNode'], ['Blockly.tree.BaseNode', 'Blockly.utils.object', 'Blockly.utils.KeyCodes']); goog.addDependency("../../core/connection.js", ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml']); -goog.addDependency("../../core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']); +goog.addDependency("../../core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.RenderedConnection']); goog.addDependency("../../core/constants.js", ['Blockly.constants'], []); goog.addDependency("../../core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.Msg', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.uiMenu', 'Blockly.utils.userAgent', 'Blockly.Xml']); goog.addDependency("../../core/css.js", ['Blockly.Css'], []); @@ -52,12 +52,12 @@ goog.addDependency("../../core/field_angle.js", ['Blockly.FieldAngle'], ['Blockl goog.addDependency("../../core/field_checkbox.js", ['Blockly.FieldCheckbox'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Size']); goog.addDependency("../../core/field_colour.js", ['Blockly.FieldColour'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.navigation', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.IdGenerator', 'Blockly.utils.KeyCodes', 'Blockly.utils.object', 'Blockly.utils.Size']); goog.addDependency("../../core/field_date.js", ['Blockly.FieldDate'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.string', 'goog.date', 'goog.date.DateTime', 'goog.events', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_he', 'goog.ui.DatePicker']); -goog.addDependency("../../core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Size', 'Blockly.utils.string', 'Blockly.utils.userAgent']); +goog.addDependency("../../core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Size', 'Blockly.utils.string', 'Blockly.utils.userAgent']); goog.addDependency("../../core/field_image.js", ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Size']); goog.addDependency("../../core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Size']); goog.addDependency("../../core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.object']); -goog.addDependency("../../core/field_multilineinput.js", ['Blockly.FieldMultilineInput'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.KeyCodes', 'Blockly.utils.object', 'Blockly.utils.userAgent']); -goog.addDependency("../../core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.fieldRegistry', 'Blockly.FieldTextInput', 'Blockly.utils.object']); +goog.addDependency("../../core/field_multilineinput.js", ['Blockly.FieldMultilineInput'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.KeyCodes', 'Blockly.utils.object', 'Blockly.utils.userAgent']); +goog.addDependency("../../core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.fieldRegistry', 'Blockly.FieldTextInput', 'Blockly.utils.aria', 'Blockly.utils.object']); goog.addDependency("../../core/field_registry.js", ['Blockly.fieldRegistry'], []); goog.addDependency("../../core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.Msg', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.KeyCodes', 'Blockly.utils.object', 'Blockly.utils.Size', 'Blockly.utils.userAgent']); goog.addDependency("../../core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.fieldRegistry', 'Blockly.Msg', 'Blockly.utils', 'Blockly.utils.object', 'Blockly.utils.Size', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml']); @@ -119,13 +119,15 @@ goog.addDependency("../../core/renderers/zelos/drawer.js", ['Blockly.zelos.Drawe goog.addDependency("../../core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow', 'Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow']); goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.RenderInfo']); -goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Modern']); +goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/theme.js", ['Blockly.Theme'], []); goog.addDependency("../../core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); goog.addDependency("../../core/theme/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Theme']); +goog.addDependency("../../core/theme/deuteranopia.js", ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']); goog.addDependency("../../core/theme/highcontrast.js", ['Blockly.Themes.HighContrast'], ['Blockly.Theme']); goog.addDependency("../../core/theme/modern.js", ['Blockly.Themes.Modern'], ['Blockly.Theme']); +goog.addDependency("../../core/theme/tritanopia.js", ['Blockly.Themes.Tritanopia'], ['Blockly.Theme']); goog.addDependency("../../core/theme_manager.js", ['Blockly.ThemeManager'], ['Blockly.Theme']); goog.addDependency("../../core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.navigation', 'Blockly.Touch', 'Blockly.tree.TreeControl', 'Blockly.tree.TreeNode', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']); goog.addDependency("../../core/tooltip.js", ['Blockly.Tooltip'], ['Blockly.utils.string']); @@ -165,7 +167,7 @@ goog.addDependency("../../core/workspace_comment_render_svg.js", ['Blockly.Works goog.addDependency("../../core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WorkspaceComment']); goog.addDependency("../../core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']); -goog.addDependency("../../core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.utils.object']); +goog.addDependency("../../core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.utils.object']); goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); goog.addDependency("../../core/xml.js", ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.xml']); diff --git a/core/requires.js b/core/requires.js index 46a61706a..77f80d7c2 100644 --- a/core/requires.js +++ b/core/requires.js @@ -88,5 +88,7 @@ goog.require('Blockly.geras.Renderer'); // Classic is the default theme. goog.require('Blockly.Themes.Classic'); goog.require('Blockly.Themes.Dark'); +goog.require('Blockly.Themes.Deuteranopia'); goog.require('Blockly.Themes.HighContrast'); -goog.require('Blockly.Themes.Modern'); +goog.require('Blockly.Themes.Tritanopia'); +// goog.require('Blockly.Themes.Modern'); diff --git a/core/theme/deuteranopia.js b/core/theme/deuteranopia.js new file mode 100644 index 000000000..a2c18ab84 --- /dev/null +++ b/core/theme/deuteranopia.js @@ -0,0 +1,114 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Deuteranopia theme. + * A color palette for people that have deuteranopia(the inability to perceive + * green light). This can also be used for people that have protanopia(the + * inability to perceive red light). + */ +'use strict'; + +goog.provide('Blockly.Themes.Deuteranopia'); + +goog.require('Blockly.Theme'); + + +// Temporary holding object. +Blockly.Themes.Deuteranopia = {}; + +Blockly.Themes.Deuteranopia.defaultBlockStyles = { + "colour_blocks": { + "colourPrimary": "#f2a72c", + "colourSecondary": "#f1c17", + "colourTertiary": "#da921c" + }, + "list_blocks": { + "colourPrimary": "#7d65ab", + "colourSecondary": "#a88be0", + "colourTertiary": "#66518e" + }, + "logic_blocks": { + "colourPrimary": "#9fd2f1", + "colourSecondary": "#c0e0f4", + "colourTertiary": "#74bae5" + }, + "loop_blocks": { + "colourPrimary": "#795a07", + "colourSecondary": "#ac8726", + "colourTertiary": "#c4a03f" + }, + "math_blocks": { + "colourPrimary": "#e6da39", + "colourSecondary": "#f3ec8e", + "colourTertiary": "#f2eeb7" + }, + "procedure_blocks": { + "colourPrimary": "#590721", + "colourSecondary": "#8c475d", + "colourTertiary": "#885464" + }, + "text_blocks": { + "colourPrimary": "#058863", + "colourSecondary": "#5ecfaf", + "colourTertiary": "#04684c" + }, + "variable_blocks": { + "colourPrimary": "#47025a", + "colourSecondary": "#820fa1", + "colourTertiary": "#8e579d" + }, + "variable_dynamic_blocks": { + "colourPrimary": "#47025a", + "colourSecondary": "#820fa1", + "colourTertiary": "#8e579d" + } +}; + +Blockly.Themes.Deuteranopia.categoryStyles = { + "colour_category": { + "colour": "#f2a72c" + }, + "list_category": { + "colour": "#7d65ab" + }, + "logic_category": { + "colour": "#9fd2f1" + }, + "loop_category": { + "colour": "#795a07" + }, + "math_category": { + "colour": "#e6da39" + }, + "procedure_category": { + "colour": "#590721" + }, + "text_category": { + "colour": "#058863" + }, + "variable_category": { + "colour": "#47025a" + }, + "variable_dynamic_category": { + "colour": "#47025a" + } +}; + +Blockly.Themes.Deuteranopia = + new Blockly.Theme(Blockly.Themes.Deuteranopia.defaultBlockStyles, + Blockly.Themes.Deuteranopia.categoryStyles); diff --git a/core/theme/tritanopia.js b/core/theme/tritanopia.js new file mode 100644 index 000000000..c12fec728 --- /dev/null +++ b/core/theme/tritanopia.js @@ -0,0 +1,113 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Tritanopia theme. + * A color palette for people that have tritanopia(the inability to perceive + * blue light). + */ +'use strict'; + +goog.provide('Blockly.Themes.Tritanopia'); + +goog.require('Blockly.Theme'); + + +// Temporary holding object. +Blockly.Themes.Tritanopia = {}; + +Blockly.Themes.Tritanopia.defaultBlockStyles = { + "colour_blocks": { + "colourPrimary": "#05427f", + "colourSecondary": "#2974c0", + "colourTertiary": "#2d74bb" + }, + "list_blocks": { + "colourPrimary": "#b69ce8", + "colourSecondary": "#ccbaef", + "colourTertiary": "#9176c5" + }, + "logic_blocks": { + "colourPrimary": "#9fd2f1", + "colourSecondary": "#c0e0f4", + "colourTertiary": "#74bae5" + }, + "loop_blocks": { + "colourPrimary": "#aa1846", + "colourSecondary": "#d36185", + "colourTertiary": "#7c1636" + }, + "math_blocks": { + "colourPrimary": "#e6da39", + "colourSecondary": "#f3ec8e", + "colourTertiary": "#f2eeb7" + }, + "procedure_blocks": { + "colourPrimary": "#590721", + "colourSecondary": "#8c475d", + "colourTertiary": "#885464" + }, + "text_blocks": { + "colourPrimary": "#058863", + "colourSecondary": "#5ecfaf", + "colourTertiary": "#04684c" + }, + "variable_blocks": { + "colourPrimary": "#4b2d84", + "colourSecondary": "#816ea7", + "colourTertiary": "#83759e" + }, + "variable_dynamic_blocks": { + "colourPrimary": "#4b2d84", + "colourSecondary": "#816ea7", + "colourTertiary": "#83759e" + } +}; + +Blockly.Themes.Tritanopia.categoryStyles = { + "colour_category": { + "colour": "#05427f" + }, + "list_category": { + "colour": "#b69ce8" + }, + "logic_category": { + "colour": "#9fd2f1" + }, + "loop_category": { + "colour": "#aa1846" + }, + "math_category": { + "colour": "#e6da39" + }, + "procedure_category": { + "colour": "#590721" + }, + "text_category": { + "colour": "#058863" + }, + "variable_category": { + "colour": "#4b2d84" + }, + "variable_dynamic_category": { + "colour": "#4b2d84" + } +}; + +Blockly.Themes.Tritanopia = + new Blockly.Theme(Blockly.Themes.Tritanopia.defaultBlockStyles, + Blockly.Themes.Tritanopia.categoryStyles); diff --git a/tests/playground.html b/tests/playground.html index be4b9b29d..931431a26 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -71,6 +71,7 @@ // Custom requires for the playground. goog.require('Blockly.blockRendering.Debug'); goog.require('Blockly.minimalist.Renderer'); +goog.require('Blockly.Themes.Modern'); goog.require('Blockly.thrasos.Renderer'); goog.require('Blockly.zelos.Renderer'); @@ -320,12 +321,17 @@ function addRenderDebugOptionsCheckboxes() { function changeTheme() { var theme = document.getElementById('themeChanger'); - if (theme.value === "modern") { - Blockly.getMainWorkspace().setTheme(Blockly.Themes.Modern); - } else if (theme.value === "dark") { + + if (theme.value === "dark") { Blockly.getMainWorkspace().setTheme(Blockly.Themes.Dark); } else if (theme.value === "high_contrast") { Blockly.getMainWorkspace().setTheme(Blockly.Themes.HighContrast); + } else if (theme.value === "deuteranopia") { + Blockly.getMainWorkspace().setTheme(Blockly.Themes.Deuteranopia); + } else if (theme.value === "tritanopia") { + Blockly.getMainWorkspace().setTheme(Blockly.Themes.Tritanopia); + } else if (theme.value === "modern") { + Blockly.getMainWorkspace().setTheme(Blockly.Themes.Modern); } else { Blockly.getMainWorkspace().setTheme(Blockly.Themes.Classic); } @@ -587,6 +593,8 @@ var spaghettiXml = [ + +

From 730dee7acafede010d81d7c0b73fbfd2c1afb33b Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 23 Oct 2019 17:51:24 -0400 Subject: [PATCH 095/343] Fix warnings in procedures. (#3304) --- core/names.js | 6 +++--- core/procedures.js | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/core/names.js b/core/names.js index 263ef81ef..c18f5ab34 100644 --- a/core/names.js +++ b/core/names.js @@ -116,7 +116,7 @@ Blockly.Names.prototype.getNameForUserVariable_ = function(id) { * @suppress {deprecated} Suppress deprecated Blockly.Variables.NAME_TYPE. */ Blockly.Names.prototype.getName = function(name, type) { - if (type == Blockly.Variables.NAME_TYPE) { + if (type == Blockly.VARIABLE_CATEGORY_NAME) { var varName = this.getNameForUserVariable_(name); if (varName) { name = varName; @@ -124,7 +124,7 @@ Blockly.Names.prototype.getName = function(name, type) { } var normalized = name.toLowerCase() + '_' + type; - var isVarType = type == Blockly.Variables.NAME_TYPE || + var isVarType = type == Blockly.VARIABLE_CATEGORY_NAME || type == Blockly.Names.DEVELOPER_VARIABLE_TYPE; var prefix = isVarType ? this.variablePrefix_ : ''; @@ -156,7 +156,7 @@ Blockly.Names.prototype.getDistinctName = function(name, type) { } safeName += i; this.dbReverse_[safeName] = true; - var isVarType = type == Blockly.Variables.NAME_TYPE || + var isVarType = type == Blockly.VARIABLE_CATEGORY_NAME || type == Blockly.Names.DEVELOPER_VARIABLE_TYPE; var prefix = isVarType ? this.variablePrefix_ : ''; return prefix + safeName; diff --git a/core/procedures.js b/core/procedures.js index 5388bf943..6023dbe9c 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -46,6 +46,16 @@ goog.require('Blockly.Xml'); */ Blockly.Procedures.NAME_TYPE = Blockly.PROCEDURE_CATEGORY_NAME; +/** + * Procedure block type. + * @typedef {{ + * getProcedureCall: function():string, + * renameProcedure: function(string,string), + * getProcedureDef: function():!Array + * }} + */ +Blockly.Procedures.ProcedureBlock; + /** * Find all user-created procedure definitions in a workspace. * @param {!Blockly.Workspace} root Root workspace. @@ -60,7 +70,9 @@ Blockly.Procedures.allProcedures = function(root) { var proceduresNoReturn = []; for (var i = 0; i < blocks.length; i++) { if (blocks[i].getProcedureDef) { - var tuple = blocks[i].getProcedureDef(); + var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( + blocks[i]); + var tuple = procedureBlock.getProcedureDef(); if (tuple) { if (tuple[2]) { proceduresReturn.push(tuple); @@ -143,7 +155,9 @@ Blockly.Procedures.isNameUsed = function(name, workspace, opt_exclude) { continue; } if (blocks[i].getProcedureDef) { - var procName = blocks[i].getProcedureDef(); + var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( + blocks[i]); + var procName = procedureBlock.getProcedureDef(); if (Blockly.Names.equals(procName[0], name)) { return true; } @@ -162,14 +176,18 @@ Blockly.Procedures.rename = function(name) { // Strip leading and trailing whitespace. Beyond this, all names are legal. name = name.trim(); - var legalName = Blockly.Procedures.findLegalName(name, this.getSourceBlock()); + var legalName = Blockly.Procedures.findLegalName(name, + /** @type {!Blockly.Block} */ (this.getSourceBlock())); var 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++) { if (blocks[i].renameProcedure) { - blocks[i].renameProcedure(oldName, legalName); + var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( + blocks[i]); + procedureBlock.renameProcedure( + /** @type {string} */ (oldName), legalName); } } } @@ -265,7 +283,9 @@ Blockly.Procedures.getCallers = function(name, workspace) { // Iterate through every block and check the name. for (var i = 0; i < blocks.length; i++) { if (blocks[i].getProcedureCall) { - var procName = blocks[i].getProcedureCall(); + var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( + blocks[i]); + var procName = procedureBlock.getProcedureCall(); // Procedure name may be null if the block is only half-built. if (procName && Blockly.Names.equals(procName, name)) { callers.push(blocks[i]); @@ -282,7 +302,9 @@ Blockly.Procedures.getCallers = function(name, workspace) { */ Blockly.Procedures.mutateCallers = function(defBlock) { var oldRecordUndo = Blockly.Events.recordUndo; - var name = defBlock.getProcedureDef()[0]; + 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++) { @@ -314,7 +336,9 @@ Blockly.Procedures.getDefinition = function(name, workspace) { var blocks = workspace.getTopBlocks(false); for (var i = 0; i < blocks.length; i++) { if (blocks[i].getProcedureDef) { - var tuple = blocks[i].getProcedureDef(); + var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ ( + blocks[i]); + var tuple = procedureBlock.getProcedureDef(); if (tuple && Blockly.Names.equals(tuple[0], name)) { return blocks[i]; } From 83e7ebb228523255ca070eb8e8fc960486c29419 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 23 Oct 2019 17:54:12 -0400 Subject: [PATCH 096/343] calcdeps doesn't understand requireType, strip it out for the online compile (#3323) --- build.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.py b/build.py index a26d1a78c..6dcfd4593 100755 --- a/build.py +++ b/build.py @@ -202,6 +202,8 @@ class Gen_compressed(threading.Thread): if filename == "core/blockly.js": code = code.replace("Blockly.VERSION = 'uncompiled';", "Blockly.VERSION = '%s';" % blocklyVersion) + # Strip out all requireType calls. + code = re.sub(r"goog.requireType(.*)", "", code) params.append(("js_code", code.encode("utf-8"))) f.close() From 52bef4463c295e8bbb692af75dc5c10a3898c785 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 23 Oct 2019 17:56:52 -0400 Subject: [PATCH 097/343] Fix warnings related to connections. (#3306) * Fix warnings related to connections. --- blocks/logic.js | 4 +- core/block.js | 6 +-- core/block_dragger.js | 2 +- core/block_svg.js | 28 +++++++------- core/connection.js | 55 +++++++++++++++++---------- core/connection_db.js | 40 ++++++++++---------- core/insertion_marker_manager.js | 6 +-- core/keyboard_nav/navigation.js | 2 +- core/rendered_connection.js | 63 ++++++++++++++++--------------- tests/mocha/connection_db_test.js | 30 +++++++-------- tests/mocha/connection_test.js | 12 +++--- 11 files changed, 132 insertions(+), 116 deletions(-) diff --git a/blocks/logic.js b/blocks/logic.js index 4c20bc687..89f2b2097 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -554,7 +554,7 @@ Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = { var blockB = this.getInputTargetBlock('B'); // Disconnect blocks that existed prior to this change if they don't match. if (blockA && blockB && - !blockA.outputConnection.checkType_(blockB.outputConnection)) { + !blockA.outputConnection.checkType(blockB.outputConnection)) { // Mismatch between two inputs. Revert the block connections, // bumping away the newly connected block(s). Blockly.Events.setGroup(e.group); @@ -621,7 +621,7 @@ Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN = { if ((blockA || blockB) && parentConnection) { for (var i = 0; i < 2; i++) { var block = (i == 1) ? blockA : blockB; - if (block && !block.outputConnection.checkType_(parentConnection)) { + if (block && !block.outputConnection.checkType(parentConnection)) { // Ensure that any disconnections are grouped with the causing event. Blockly.Events.setGroup(e.group); if (parentConnection === this.prevParentConnection_) { diff --git a/core/block.js b/core/block.js index 25510b8bf..dc1edd6ce 100644 --- a/core/block.js +++ b/core/block.js @@ -441,7 +441,7 @@ Blockly.Block.prototype.unplugFromRow_ = function(opt_healStack) { // Disconnect the child block. childConnection.disconnect(); // Connect child to the parent if possible, otherwise bump away. - if (childConnection.checkType_(parentConnection)) { + if (childConnection.checkType(parentConnection)) { parentConnection.connect(childConnection); } else { childConnection.onFailedConnect(parentConnection); @@ -493,7 +493,7 @@ Blockly.Block.prototype.unplugFromStack_ = function(opt_healStack) { // Disconnect the next statement. var nextTarget = this.nextConnection.targetConnection; nextTarget.disconnect(); - if (previousTarget && previousTarget.checkType_(nextTarget)) { + if (previousTarget && previousTarget.checkType(nextTarget)) { // Attach the next statement to the previous statement. previousTarget.connect(nextTarget); } @@ -1880,7 +1880,7 @@ Blockly.Block.prototype.moveBy = function(dx, dy) { * 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. - * @private + * @protected */ Blockly.Block.prototype.makeConnection_ = function(type) { return new Blockly.Connection(this, type); diff --git a/core/block_dragger.js b/core/block_dragger.js index 95456e3b2..2eb62a60d 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -243,7 +243,7 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { var deleted = this.maybeDeleteBlock_(); if (!deleted) { // These are expensive and don't need to be done if we're deleting. - this.draggingBlock_.moveConnections_(delta.x, delta.y); + this.draggingBlock_.moveConnections(delta.x, delta.y); this.draggingBlock_.setDragging(false); this.fireMoveEvent_(); if (this.draggedConnectionManager_.wouldConnectBlock()) { diff --git a/core/block_svg.js b/core/block_svg.js index 7fa053a5b..92a7735c7 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -398,7 +398,7 @@ Blockly.BlockSvg.prototype.setParent = function(newParent) { newParent.getSvgRoot().appendChild(svgRoot); var newXY = this.getRelativeToSurfaceXY(); // Move the connections to match the child's new position. - this.moveConnections_(newXY.x - oldXY.x, newXY.y - oldXY.y); + this.moveConnections(newXY.x - oldXY.x, newXY.y - oldXY.y); } // If we are losing a parent, we want to move our DOM element to the // root of the workspace. @@ -462,7 +462,7 @@ Blockly.BlockSvg.prototype.moveBy = function(dx, dy) { } var xy = this.getRelativeToSurfaceXY(); this.translate(xy.x + dx, xy.y + dy); - this.moveConnections_(dx, dy); + this.moveConnections(dx, dy); if (eventsEnabled) { event.recordNew(); Blockly.Events.fire(event); @@ -886,9 +886,9 @@ Blockly.BlockSvg.prototype.showContextMenu = function(e) { * units. * @param {number} dy Vertical offset from current location, in workspace * units. - * @private + * @package */ -Blockly.BlockSvg.prototype.moveConnections_ = function(dx, dy) { +Blockly.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. @@ -905,7 +905,7 @@ Blockly.BlockSvg.prototype.moveConnections_ = function(dx, dy) { // Recurse through all blocks attached under this one. for (var i = 0; i < this.childBlocks_.length; i++) { - this.childBlocks_[i].moveConnections_(dx, dy); + this.childBlocks_[i].moveConnections(dx, dy); } }; @@ -1586,7 +1586,7 @@ Blockly.BlockSvg.prototype.startTrackingConnections = function() { * @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) { @@ -1645,7 +1645,7 @@ Blockly.BlockSvg.prototype.getMatchingConnection = function(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. - * @private + * @protected */ Blockly.BlockSvg.prototype.makeConnection_ = function(type) { return new Blockly.RenderedConnection(this, type); @@ -1675,7 +1675,7 @@ Blockly.BlockSvg.prototype.bumpNeighbours = function() { connection.targetBlock().bumpNeighbours(); } - var neighbours = connection.neighbours_(Blockly.SNAP_RADIUS); + var neighbours = connection.neighbours(Blockly.SNAP_RADIUS); for (var j = 0, otherConnection; otherConnection = neighbours[j]; j++) { // If both connections are connected, that's probably fine. But if @@ -1686,9 +1686,9 @@ Blockly.BlockSvg.prototype.bumpNeighbours = function() { // Always bump the inferior block. if (connection.isSuperior()) { - otherConnection.bumpAwayFrom_(connection); + otherConnection.bumpAwayFrom(connection); } else { - connection.bumpAwayFrom_(otherConnection); + connection.bumpAwayFrom(otherConnection); } } } @@ -1735,8 +1735,8 @@ Blockly.BlockSvg.prototype.positionNearConnection = function(sourceConnection, // otherwise its position is set by the previous block. if (sourceConnection.type == Blockly.NEXT_STATEMENT || sourceConnection.type == Blockly.INPUT_VALUE) { - var dx = targetConnection.x_ - sourceConnection.x_; - var dy = targetConnection.y_ - sourceConnection.y_; + var dx = targetConnection.x - sourceConnection.x; + var dy = targetConnection.y - sourceConnection.y; this.moveBy(dx, dy); } @@ -1817,7 +1817,7 @@ Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() { if (conn) { conn.moveToOffset(blockTL); if (conn.isConnected()) { - conn.tighten_(); + conn.tighten(); } } } @@ -1825,7 +1825,7 @@ Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() { if (this.nextConnection) { this.nextConnection.moveToOffset(blockTL); if (this.nextConnection.isConnected()) { - this.nextConnection.tighten_(); + this.nextConnection.tighten(); } } }; diff --git a/core/connection.js b/core/connection.js index c8a4d2879..91227f424 100644 --- a/core/connection.js +++ b/core/connection.js @@ -85,16 +85,16 @@ Blockly.Connection.prototype.shadowDom_ = null; /** * Horizontal location of this connection. * @type {number} - * @protected + * @package */ -Blockly.Connection.prototype.x_ = 0; +Blockly.Connection.prototype.x = 0; /** * Vertical location of this connection. * @type {number} - * @protected + * @package */ -Blockly.Connection.prototype.y_ = 0; +Blockly.Connection.prototype.y = 0; /** * Connect two connections together. This is the connection on the superior @@ -132,7 +132,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) { // Attempt to reattach the orphan at the end of the newly inserted // block. Since this block may be a row, walk down to the end // or to the first (and only) shadow block. - var connection = Blockly.Connection.lastConnectionInRow_( + var connection = Blockly.Connection.lastConnectionInRow( childBlock, orphanBlock); if (connection) { orphanBlock.outputConnection.connect(connection); @@ -153,7 +153,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) { if (nextBlock && !nextBlock.isShadow()) { newBlock = nextBlock; } else { - if (orphanBlock.previousConnection.checkType_( + if (orphanBlock.previousConnection.checkType( newBlock.nextConnection)) { newBlock.nextConnection.connect(orphanBlock.previousConnection); orphanBlock = null; @@ -272,7 +272,7 @@ Blockly.Connection.prototype.canConnectWithReason = function(target) { return Blockly.Connection.REASON_WRONG_TYPE; } else if (blockA && blockB && blockA.workspace !== blockB.workspace) { return Blockly.Connection.REASON_DIFFERENT_WORKSPACES; - } else if (!this.checkType_(target)) { + } else if (!this.checkType(target)) { return Blockly.Connection.REASON_CHECKS_FAILED; } else if (blockA.isShadow() && !blockB.isShadow()) { return Blockly.Connection.REASON_SHADOW_PARENT; @@ -414,7 +414,7 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) { /** * Behavior after a connection attempt fails. - * @param {Blockly.Connection} _otherConnection Connection that this connection + * @param {!Blockly.Connection} _otherConnection Connection that this connection * failed to connect to. * @package */ @@ -473,11 +473,11 @@ Blockly.Connection.connectReciprocally_ = function(first, second) { * @private */ Blockly.Connection.singleConnection_ = function(block, orphanBlock) { - var connection = false; + var connection = null; for (var i = 0; i < block.inputList.length; i++) { var thisConnection = block.inputList[i].connection; if (thisConnection && thisConnection.type == Blockly.INPUT_VALUE && - orphanBlock.outputConnection.checkType_(thisConnection)) { + orphanBlock.outputConnection.checkType(thisConnection)) { if (connection) { return null; // More than one connection. } @@ -497,9 +497,9 @@ Blockly.Connection.singleConnection_ = function(block, orphanBlock) { * @param {!Blockly.Block} orphanBlock The block that is looking for a home. * @return {Blockly.Connection} The suitable connection point on the chain * of blocks, or null. - * @private + * @package */ -Blockly.Connection.lastConnectionInRow_ = function(startBlock, orphanBlock) { +Blockly.Connection.lastConnectionInRow = function(startBlock, orphanBlock) { var newBlock = startBlock; var connection; while (connection = Blockly.Connection.singleConnection_( @@ -606,9 +606,9 @@ Blockly.Connection.prototype.targetBlock = function() { * value type system. E.g. square_root("Hello") is not compatible. * @param {!Blockly.Connection} otherConnection Connection to compare against. * @return {boolean} True if the connections share a type. - * @protected + * @package */ -Blockly.Connection.prototype.checkType_ = function(otherConnection) { +Blockly.Connection.prototype.checkType = function(otherConnection) { if (!this.check_ || !otherConnection.check_) { // One or both sides are promiscuous enough that anything will fit. return true; @@ -624,12 +624,27 @@ Blockly.Connection.prototype.checkType_ = function(otherConnection) { }; /** - * Function to be called when this connection's compatible types have changed. + * Is this connection compatible with another connection with respect to the + * value type system. E.g. square_root("Hello") is not compatible. + * @param {!Blockly.Connection} otherConnection Connection to compare against. + * @return {boolean} True if the connections share a type. * @private + * @deprecated October 2019, use connection.checkType instead. + */ +Blockly.Connection.prototype.checkType_ = function(otherConnection) { + console.warn('Deprecated call to Blockly.Connection.prototype.checkType_, ' + + 'use Blockly.Connection.prototype.checkType instead.'); + return this.checkType(otherConnection); +}; + +/** + * Function to be called when this connection's compatible types have changed. + * @protected */ Blockly.Connection.prototype.onCheckChanged_ = function() { // The new value type may not be compatible with the existing connection. - if (this.isConnected() && !this.checkType_(this.targetConnection)) { + if (this.isConnected() && (!this.targetConnection || + !this.checkType(this.targetConnection))) { var child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_; child.unplug(); } @@ -637,8 +652,8 @@ Blockly.Connection.prototype.onCheckChanged_ = function() { /** * Change a connection's compatibility. - * @param {string|!Array} check Compatible value type or list of value - * types. Null if all types are compatible. + * @param {?(string|!Array)} check Compatible value type or list of + * value types. Null if all types are compatible. * @return {!Blockly.Connection} The connection being modified * (to allow chaining). */ @@ -692,9 +707,9 @@ Blockly.Connection.prototype.getShadowDom = function() { * computed from the rendered positioning. * @param {number} _maxLimit The maximum radius to another connection. * @return {!Array.} List of connections. - * @private + * @package */ -Blockly.Connection.prototype.neighbours_ = function(_maxLimit) { +Blockly.Connection.prototype.neighbours = function(_maxLimit) { return []; }; diff --git a/core/connection_db.js b/core/connection_db.js index f9baa3f46..8ff7c7683 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -77,11 +77,11 @@ Blockly.ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) { return -1; } - var yPos = conn.y_; + yPos = conn.y; // Walk forward and back on the y axis looking for the connection. var pointerMin = bestGuess; var pointerMax = bestGuess; - while (pointerMin >= 0 && this.connections_[pointerMin].y_ == yPos) { + while (pointerMin >= 0 && this.connections_[pointerMin].y == yPos) { if (this.connections_[pointerMin] == conn) { return pointerMin; } @@ -89,7 +89,7 @@ Blockly.ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) { } while (pointerMax < this.connections_.length && - this.connections_[pointerMax].y_ == yPos) { + this.connections_[pointerMax].y == yPos) { if (this.connections_[pointerMax] == conn) { return pointerMax; } @@ -113,9 +113,9 @@ Blockly.ConnectionDB.prototype.calculateIndexForYPos_ = function(yPos) { var pointerMax = this.connections_.length; while (pointerMin < pointerMax) { var pointerMid = Math.floor((pointerMin + pointerMax) / 2); - if (this.connections_[pointerMid].y_ < yPos) { + if (this.connections_[pointerMid].y < yPos) { pointerMin = pointerMid + 1; - } else if (this.connections_[pointerMid].y_ > yPos) { + } else if (this.connections_[pointerMid].y > yPos) { pointerMax = pointerMid; } else { pointerMin = pointerMid; @@ -149,15 +149,15 @@ Blockly.ConnectionDB.prototype.removeConnection = function(connection, yPos) { */ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) { var db = this.connections_; - var currentX = connection.x_; - var currentY = connection.y_; + var currentX = connection.x; + var currentY = connection.y; // Binary search to find the closest y location. var pointerMin = 0; var pointerMax = db.length - 2; var pointerMid = pointerMax; while (pointerMin < pointerMid) { - if (db[pointerMid].y_ < currentY) { + if (db[pointerMid].y < currentY) { pointerMin = pointerMid; } else { pointerMax = pointerMid; @@ -175,8 +175,8 @@ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) { * the other connection is less than the allowed radius. */ function checkConnection_(yIndex) { - var dx = currentX - db[yIndex].x_; - var dy = currentY - db[yIndex].y_; + var dx = currentX - db[yIndex].x; + var dy = currentY - db[yIndex].y; var r = Math.sqrt(dx * dx + dy * dy); if (r <= maxRadius) { neighbours.push(db[yIndex]); @@ -209,7 +209,7 @@ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) { * @private */ Blockly.ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) { - return (Math.abs(this.connections_[index].y_ - baseY) <= maxRadius); + return (Math.abs(this.connections_[index].y - baseY) <= maxRadius); }; /** @@ -232,16 +232,16 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, } // Stash the values of x and y from before the drag. - var baseY = conn.y_; - var baseX = conn.x_; + var baseY = conn.y; + var baseX = conn.x; - conn.x_ = baseX + dxy.x; - conn.y_ = baseY + dxy.y; + conn.x = baseX + dxy.x; + conn.y = baseY + dxy.y; // calculateIndexForYPos_ finds an index for insertion, which is always // after any block with the same y index. We want to search both forward // and back, so search on both sides of the index. - var closestIndex = this.calculateIndexForYPos_(conn.y_); + var closestIndex = this.calculateIndexForYPos_(conn.y); var bestConnection = null; var bestRadius = maxRadius; @@ -249,7 +249,7 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, // Walk forward and back on the y axis looking for the closest x,y point. var pointerMin = closestIndex - 1; - while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y_, maxRadius)) { + while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y, maxRadius)) { temp = this.connections_[pointerMin]; if (conn.isConnectionAllowed(temp, bestRadius)) { bestConnection = temp; @@ -260,7 +260,7 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, var pointerMax = closestIndex; while (pointerMax < this.connections_.length && - this.isInYRange_(pointerMax, conn.y_, maxRadius)) { + this.isInYRange_(pointerMax, conn.y, maxRadius)) { temp = this.connections_[pointerMax]; if (conn.isConnectionAllowed(temp, bestRadius)) { bestConnection = temp; @@ -270,8 +270,8 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, } // Reset the values of x and y. - conn.x_ = baseX; - conn.y_ = baseY; + conn.x = baseX; + conn.y = baseY; // If there were no valid connections, bestConnection will be null. return {connection: bestConnection, radius: bestRadius}; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 602d0dae3..bdf208181 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -324,8 +324,8 @@ 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 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); // Slightly prefer the existing preview over a new preview. return !(candidateClosest && radius > curDistance - @@ -409,7 +409,7 @@ Blockly.InsertionMarkerManager.prototype.shouldReplace_ = function() { if (local.type == Blockly.OUTPUT_VALUE) { // Insert the dragged block into the stack if possible. if (!closest.isConnected() || - Blockly.Connection.lastConnectionInRow_(this.topBlock_, + Blockly.Connection.lastConnectionInRow(this.topBlock_, closest.targetConnection.getSourceBlock())) { return false; // Insert. } diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index aad1c5204..6d397abf3 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -548,7 +548,7 @@ Blockly.navigation.disconnectBlocks_ = function() { return; } superiorConnection.disconnect(); - inferiorConnection.bumpAwayFrom_(superiorConnection); + inferiorConnection.bumpAwayFrom(superiorConnection); var rootBlock = superiorConnection.getSourceBlock().getRootBlock(); rootBlock.bringToFront(); diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 1bf5a1bb0..acce573ad 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -82,7 +82,7 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); Blockly.RenderedConnection.prototype.dispose = function() { Blockly.RenderedConnection.superClass_.dispose.call(this); if (this.tracked_) { - this.db_.removeConnection(this, this.y_); + this.db_.removeConnection(this, this.y); } }; @@ -114,8 +114,8 @@ Blockly.RenderedConnection.prototype.targetBlock = function() { * @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_; + var xDiff = this.x - otherConnection.x; + var yDiff = this.y - otherConnection.y; return Math.sqrt(xDiff * xDiff + yDiff * yDiff); }; @@ -124,9 +124,9 @@ Blockly.RenderedConnection.prototype.distanceFrom = function(otherConnection) { * visually interfere with the specified connection. * @param {!Blockly.Connection} staticConnection The connection to move away * from. - * @private + * @package */ -Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) { +Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) { if (this.sourceBlock_.workspace.isDragging()) { // Don't move blocks around while the user is doing the same. return; @@ -152,17 +152,17 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) // Raise it to the top for extra visibility. var selected = Blockly.selected == rootBlock; selected || rootBlock.addSelect(); - var dx = (staticConnection.x_ + Blockly.SNAP_RADIUS + - Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x_; - var dy = (staticConnection.y_ + Blockly.SNAP_RADIUS + - Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.y_; + var dx = (staticConnection.x + Blockly.SNAP_RADIUS + + Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x; + var dy = (staticConnection.y + Blockly.SNAP_RADIUS + + Math.floor(Math.random() * Blockly.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.SNAP_RADIUS - - Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x_; + dx = (staticConnection.x - Blockly.SNAP_RADIUS - + Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x; } rootBlock.moveBy(dx, dy); selected || rootBlock.removeSelect(); @@ -175,11 +175,11 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) */ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { if (this.tracked_) { - this.db_.removeConnection(this, this.y_); + this.db_.removeConnection(this, this.y); this.db_.addConnection(this, y); } - this.x_ = x; - this.y_ = y; + this.x = x; + this.y = y; }; /** @@ -188,7 +188,7 @@ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { * @param {number} dy Change to y coordinate, in workspace units. */ Blockly.RenderedConnection.prototype.moveBy = function(dx, dy) { - this.moveTo(this.x_ + dx, this.y_ + dy); + this.moveTo(this.x + dx, this.y + dy); }; /** @@ -223,11 +223,11 @@ Blockly.RenderedConnection.prototype.getOffsetInBlock = function() { /** * Move the blocks on either side of this connection right next to each other. - * @private + * @package */ -Blockly.RenderedConnection.prototype.tighten_ = function() { - var dx = this.targetConnection.x_ - this.x_; - var dy = this.targetConnection.y_ - this.y_; +Blockly.RenderedConnection.prototype.tighten = function() { + var dx = this.targetConnection.x - this.x; + var dy = this.targetConnection.y - this.y; if (dx != 0 || dy != 0) { var block = this.targetBlock(); var svgRoot = block.getSvgRoot(); @@ -238,7 +238,7 @@ Blockly.RenderedConnection.prototype.tighten_ = function() { var xy = Blockly.utils.getRelativeXY(svgRoot); block.getSvgRoot().setAttribute('transform', 'translate(' + (xy.x - dx) + ',' + (xy.y - dy) + ')'); - block.moveConnections_(-dx, -dy); + block.moveConnections(-dx, -dy); } }; @@ -280,8 +280,8 @@ Blockly.RenderedConnection.prototype.highlight = function() { Blockly.utils.svgPaths.lineOnAxis('h', xLen); } var xy = this.sourceBlock_.getRelativeToSurfaceXY(); - var x = this.x_ - xy.x; - var y = this.y_ - xy.y; + var x = this.x - xy.x; + var y = this.y - xy.y; Blockly.Connection.highlightedPath_ = Blockly.utils.dom.createSvgElement( 'path', { @@ -315,9 +315,9 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { return; } if (doTracking) { - this.db_.addConnection(this, this.y_); + this.db_.addConnection(this, this.y); } else { - this.db_.removeConnection(this, this.y_); + this.db_.removeConnection(this, this.y); } this.tracked_ = doTracking; }; @@ -409,13 +409,13 @@ Blockly.RenderedConnection.prototype.isConnectionAllowed = function(candidate, /** * Behavior after a connection attempt fails. - * @param {Blockly.Connection} otherConnection Connection that this connection + * @param {!Blockly.Connection} otherConnection Connection that this connection * failed to connect to. * @package */ Blockly.RenderedConnection.prototype.onFailedConnect = function( otherConnection) { - this.bumpAwayFrom_(otherConnection); + this.bumpAwayFrom(otherConnection); }; @@ -468,9 +468,9 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() { * @param {number} maxLimit The maximum radius to another connection, in * workspace units. * @return {!Array.} List of connections. - * @private + * @package */ -Blockly.RenderedConnection.prototype.neighbours_ = function(maxLimit) { +Blockly.RenderedConnection.prototype.neighbours = function(maxLimit) { return this.dbOpposite_.getNeighbours(this, maxLimit); }; @@ -478,7 +478,7 @@ Blockly.RenderedConnection.prototype.neighbours_ = function(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. - * @private + * @protected */ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) { Blockly.RenderedConnection.superClass_.connect_.call(this, childConnection); @@ -509,11 +509,12 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) { /** * Function to be called when this connection's compatible types have changed. - * @private + * @protected */ Blockly.RenderedConnection.prototype.onCheckChanged_ = function() { // The new value type may not be compatible with the existing connection. - if (this.isConnected() && !this.checkType_(this.targetConnection)) { + if (this.isConnected() && (!this.targetConnection || + !this.checkType(this.targetConnection))) { var child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_; child.unplug(); // Bump away. diff --git a/tests/mocha/connection_db_test.js b/tests/mocha/connection_db_test.js index fe9940d59..9c9c1a242 100644 --- a/tests/mocha/connection_db_test.js +++ b/tests/mocha/connection_db_test.js @@ -22,8 +22,8 @@ suite('Connection Database', function() { this.assertOrder = function() { var length = this.database.connections_.length; for (var i = 1; i < length; i++) { - chai.assert.isAtMost(this.database.connections_[i - 1].y_, - this.database.connections_[i].y_); + chai.assert.isAtMost(this.database.connections_[i - 1].y, + this.database.connections_[i].y); } }; this.createConnection = function(x, y, type, opt_database) { @@ -33,8 +33,8 @@ suite('Connection Database', function() { workspace.connectionDBList[type] = opt_database || this.database; var connection = new Blockly.RenderedConnection( {workspace: workspace}, type); - connection.x_ = x; - connection.y_ = y; + connection.x = x; + connection.y = y; return connection; }; this.createSimpleTestConnections = function() { @@ -45,11 +45,11 @@ suite('Connection Database', function() { }; }); test('Add Connection', function() { - var y2 = {y_: 2}; - var y4 = {y_: 4}; - var y1 = {y_: 1}; - var y3a = {y_: 3}; - var y3b = {y_: 3}; + var y2 = {y: 2}; + var y4 = {y: 4}; + var y1 = {y: 1}; + var y3a = {y: 3}; + var y3b = {y: 3}; this.database.addConnection(y2, 2); chai.assert.sameOrderedMembers( @@ -73,12 +73,12 @@ suite('Connection Database', function() { }); test('Remove Connection', function() { - var y2 = {y_: 2}; - var y4 = {y_: 4}; - var y1 = {y_: 1}; - var y3a = {y_: 3}; - var y3b = {y_: 3}; - var y3c = {y_: 3}; + var y2 = {y: 2}; + var y4 = {y: 4}; + var y1 = {y: 1}; + var y3a = {y: 3}; + var y3b = {y: 3}; + var y3c = {y: 3}; this.database.addConnection(y2, 2); this.database.addConnection(y4, 4); diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js index 6a7faaf97..5ea5d99f0 100644 --- a/tests/mocha/connection_test.js +++ b/tests/mocha/connection_test.js @@ -168,31 +168,31 @@ suite('Connections', function() { this.con2 = new Blockly.Connection({}, Blockly.NEXT_STATEMENT); }); test('No Types', function() { - chai.assert.isTrue(this.con1.checkType_(this.con2)); + chai.assert.isTrue(this.con1.checkType((this.con2))); }); test('Same Type', function() { this.con1.setCheck('type1'); this.con2.setCheck('type1'); - chai.assert.isTrue(this.con1.checkType_(this.con2)); + chai.assert.isTrue(this.con1.checkType((this.con2))); }); test('Same Types', function() { this.con1.setCheck(['type1', 'type2']); this.con2.setCheck(['type1', 'type2']); - chai.assert.isTrue(this.con1.checkType_(this.con2)); + chai.assert.isTrue(this.con1.checkType((this.con2))); }); test('Single Same Type', function() { this.con1.setCheck(['type1', 'type2']); this.con2.setCheck(['type1', 'type3']); - chai.assert.isTrue(this.con1.checkType_(this.con2)); + chai.assert.isTrue(this.con1.checkType((this.con2))); }); test('One Typed, One Promiscuous', function() { this.con1.setCheck('type1'); - chai.assert.isTrue(this.con1.checkType_(this.con2)); + chai.assert.isTrue(this.con1.checkType((this.con2))); }); test('No Compatible Types', function() { this.con1.setCheck('type1'); this.con2.setCheck('type2'); - chai.assert.isFalse(this.con1.checkType_(this.con2)); + chai.assert.isFalse(this.con1.checkType((this.con2))); }); }); }); From 3d6eb489370839bbfaddeb8e73d75b3051d4fb4b Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 23 Oct 2019 21:58:18 -0400 Subject: [PATCH 098/343] Render a notch after a statement input in zelos (#3326) --- core/renderers/common/constants.js | 3 +++ core/renderers/common/info.js | 3 ++- core/renderers/zelos/constants.js | 9 +++++++++ core/renderers/zelos/drawer.js | 32 ++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index b300d7de1..9817ef531 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -74,6 +74,9 @@ Blockly.blockRendering.ConstantProvider = function() { this.STATEMENT_INPUT_PADDING_LEFT = 20; this.BETWEEN_STATEMENT_PADDING_Y = 4; + // The minimum height of the bottom row following a statement input. + this.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT = this.LARGE_PADDING; + // This is the max width of a bottom row that follows a statement input and // has inputs inline. this.MAX_BOTTOM_WIDTH = 66.5; diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 3e1bb7074..4ca93c78e 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -307,7 +307,8 @@ Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() { // 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. if (followsStatement) { - this.bottomRow.minHeight = this.constants_.LARGE_PADDING; + this.bottomRow.minHeight = + this.constants_.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT; } else { this.bottomRow.minHeight = this.constants_.MEDIUM_PADDING; } diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 9a7e5f415..4ac5429c2 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -70,6 +70,15 @@ Blockly.zelos.ConstantProvider = function() { */ this.TAB_OFFSET_FROM_TOP = 0; + /** + * @override + */ + this.STATEMENT_BOTTOM_SPACER = -this.NOTCH_HEIGHT; + + /** + * @override + */ + this.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT = this.LARGE_PADDING * 2; }; Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider, Blockly.blockRendering.ConstantProvider); diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index 584c3d286..58d190463 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -211,3 +211,35 @@ Blockly.zelos.Drawer.prototype.drawInlineInput_ = function(input) { // Don't draw an inline input. this.positionInlineInputConnection_(input); }; + +/** + * @override + */ +Blockly.zelos.Drawer.prototype.drawStatementInput_ = function(row) { + var input = row.getLastInput(); + // Where to start drawing the notch, which is on the right side in LTR. + var x = input.xPos + input.notchOffset + input.shape.width; + + var innerTopLeftCorner = + input.shape.pathRight + + Blockly.utils.svgPaths.lineOnAxis('h', + -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) + + this.constants_.INSIDE_CORNERS.pathTop; + + var innerHeight = + row.height - (2 * this.constants_.INSIDE_CORNERS.height); + + var innerBottomLeftCorner = + this.constants_.INSIDE_CORNERS.pathBottom + + Blockly.utils.svgPaths.lineOnAxis('h', + (input.notchOffset - this.constants_.INSIDE_CORNERS.width)) + + input.shape.pathLeft; + + this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('H', x) + + innerTopLeftCorner + + Blockly.utils.svgPaths.lineOnAxis('v', innerHeight) + + innerBottomLeftCorner + + Blockly.utils.svgPaths.lineOnAxis('H', row.xPos + row.width); + + this.positionStatementInputConnection_(row); +}; From 06b5bb19456a145e4e654c290d32c0307e604ccf Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 23 Oct 2019 21:58:43 -0400 Subject: [PATCH 099/343] Might right corner support to common. Making it so there's always a right corner element, square by default. (#3311) --- core/renderers/common/constants.js | 24 ++++++++- core/renderers/common/drawer.js | 23 ++++++--- core/renderers/common/info.js | 20 ++++++++ core/renderers/measurables/rows.js | 34 +++++++++++++ core/renderers/zelos/constants.js | 46 ----------------- core/renderers/zelos/drawer.js | 65 ------------------------ core/renderers/zelos/info.js | 42 --------------- core/renderers/zelos/measurables/rows.js | 12 ++--- 8 files changed, 97 insertions(+), 169 deletions(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 9817ef531..1ec8c8fdc 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -340,12 +340,34 @@ Blockly.blockRendering.ConstantProvider.prototype.makeOutsideCorners = function( Blockly.utils.svgPaths.arc('a', '0 0,1', radius, Blockly.utils.svgPaths.point(radius, -radius)); + /** + * SVG path for drawing the rounded top-right corner. + * @const + */ + var topRight = + Blockly.utils.svgPaths.arc('a', '0 0,1', radius, + Blockly.utils.svgPaths.point(radius, radius)); + + /** + * SVG path for drawing the rounded bottom-left corner. + * @const + */ var bottomLeft = Blockly.utils.svgPaths.arc('a', '0 0,1', radius, Blockly.utils.svgPaths.point(-radius, -radius)); + /** + * SVG path for drawing the rounded bottom-right corner. + * @const + */ + var bottomRight = Blockly.utils.svgPaths.arc('a', '0 0,1', radius, + Blockly.utils.svgPaths.point(-radius, radius)); + return { topLeft: topLeft, - bottomLeft: bottomLeft + topRight: topRight, + bottomRight: bottomRight, + bottomLeft: bottomLeft, + rightHeight: radius }; }; diff --git a/core/renderers/common/drawer.js b/core/renderers/common/drawer.js index 5887fa767..3b36a9477 100644 --- a/core/renderers/common/drawer.js +++ b/core/renderers/common/drawer.js @@ -144,6 +144,9 @@ Blockly.blockRendering.Drawer.prototype.drawTop_ = function() { if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) { this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topLeft; + } else if (Blockly.blockRendering.Types.isRightRoundedCorner(elem)) { + this.outlinePath_ += + this.constants_.OUTSIDE_CORNERS.topRight; } else if (Blockly.blockRendering.Types.isPreviousConnection(elem)) { this.outlinePath_ += elem.shape.pathLeft; } else if (Blockly.blockRendering.Types.isHat(elem)) { @@ -242,20 +245,26 @@ Blockly.blockRendering.Drawer.prototype.drawBottom_ = function() { var elems = bottomRow.elements; this.positionNextConnection_(); - this.outlinePath_ += - Blockly.utils.svgPaths.lineOnAxis('V', bottomRow.baseline); - + var rightCornerYOffset = 0; + var outlinePath = ''; for (var i = elems.length - 1, elem; (elem = elems[i]); i--) { if (Blockly.blockRendering.Types.isNextConnection(elem)) { - this.outlinePath_ += elem.shape.pathRight; + outlinePath += elem.shape.pathRight; } else if (Blockly.blockRendering.Types.isLeftSquareCorner(elem)) { - this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('H', bottomRow.xPos); + outlinePath += Blockly.utils.svgPaths.lineOnAxis('H', bottomRow.xPos); } else if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) { - this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.bottomLeft; + outlinePath += this.constants_.OUTSIDE_CORNERS.bottomLeft; + } else if (Blockly.blockRendering.Types.isRightRoundedCorner(elem)) { + outlinePath += this.constants_.OUTSIDE_CORNERS.bottomRight; + rightCornerYOffset = this.constants_.OUTSIDE_CORNERS.rightHeight; } else if (Blockly.blockRendering.Types.isSpacer(elem)) { - this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('h', elem.width * -1); + outlinePath += Blockly.utils.svgPaths.lineOnAxis('h', elem.width * -1); } } + + this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('V', + bottomRow.baseline - rightCornerYOffset); + this.outlinePath_ += outlinePath; }; /** diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 4ca93c78e..f47b8c136 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -290,6 +290,16 @@ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() { } else { this.topRow.minHeight = this.constants_.MEDIUM_PADDING; } + + var rightSquareCorner = this.topRow.hasRightSquareCorner(this.block_); + + if (rightSquareCorner) { + this.topRow.elements.push( + new Blockly.blockRendering.SquareCorner(this.constants_, 'right')); + } else { + this.topRow.elements.push( + new Blockly.blockRendering.RoundCorner(this.constants_, 'right')); + } }; /** @@ -329,6 +339,16 @@ Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() { /** @type {Blockly.RenderedConnection} */ (this.block_.nextConnection)); this.bottomRow.elements.push(this.bottomRow.connection); } + + var rightSquareCorner = this.bottomRow.hasRightSquareCorner(this.block_); + + if (rightSquareCorner) { + this.bottomRow.elements.push( + new Blockly.blockRendering.SquareCorner(this.constants_, 'right')); + } else { + this.bottomRow.elements.push( + new Blockly.blockRendering.RoundCorner(this.constants_, 'right')); + } }; /** diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index 5f17f96ce..e4b47b4f5 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -291,6 +291,16 @@ Blockly.blockRendering.TopRow.prototype.hasLeftSquareCorner = function(block) { hasHat || (prevBlock ? prevBlock.getNextBlock() == block : false); }; +/** + * Returns whether or not the top row has a right square corner. + * @param {!Blockly.BlockSvg} _block The block whose top row this represents. + * @return {boolean} Whether or not the top row has a right square corner. + */ +Blockly.blockRendering.TopRow.prototype.hasRightSquareCorner = function( + _block) { + return true; +}; + /** * @override */ @@ -322,6 +332,13 @@ Blockly.blockRendering.TopRow.prototype.startsWithElemSpacer = function() { return false; }; +/** + * @override + */ +Blockly.blockRendering.TopRow.prototype.endsWithElemSpacer = function() { + return false; +}; + /** * An object containing information about what elements are in the bottom row of * a block as well as spacing information for the top row. @@ -380,6 +397,16 @@ Blockly.blockRendering.BottomRow.prototype.hasLeftSquareCorner = function( return !!block.outputConnection || !!block.getNextBlock(); }; +/** + * Returns whether or not the bottom row has a right square corner. + * @param {!Blockly.BlockSvg} _block The block whose bottom row this represents. + * @return {boolean} Whether or not the bottom row has a right square corner. + */ +Blockly.blockRendering.BottomRow.prototype.hasRightSquareCorner = function( + _block) { + return true; +}; + /** * @override */ @@ -412,6 +439,13 @@ Blockly.blockRendering.BottomRow.prototype.startsWithElemSpacer = function() { return false; }; +/** + * @override + */ +Blockly.blockRendering.BottomRow.prototype.endsWithElemSpacer = function() { + return false; +}; + /** * An object containing information about a spacer between two rows. * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 4ac5429c2..6de86b3a4 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -261,52 +261,6 @@ Blockly.zelos.ConstantProvider.prototype.makeNotch = function() { }; }; -/** - * @return {!Object} An object containing sizing and path information about - * outside corners. - * @package - */ -Blockly.zelos.ConstantProvider.prototype.makeOutsideCorners = function() { - var radius = this.CORNER_RADIUS; - /** - * SVG path for drawing the rounded top-left corner. - * @const - */ - var topLeft = - Blockly.utils.svgPaths.moveBy(0, radius) + - Blockly.utils.svgPaths.arc('a', '0 0,1', radius, - Blockly.utils.svgPaths.point(radius, -radius)); - - /** - * SVG path for drawing the rounded top-right corner. - * @const - */ - var topRight = - Blockly.utils.svgPaths.arc('a', '0 0,1', radius, - Blockly.utils.svgPaths.point(radius, radius)); - - /** - * SVG path for drawing the rounded bottom-left corner. - * @const - */ - var bottomLeft = Blockly.utils.svgPaths.arc('a', '0 0,1', radius, - Blockly.utils.svgPaths.point(-radius, -radius)); - - /** - * SVG path for drawing the rounded bottom-right corner. - * @const - */ - var bottomRight = Blockly.utils.svgPaths.arc('a', '0 0,1', radius, - Blockly.utils.svgPaths.point(-radius, radius)); - - return { - topLeft: topLeft, - topRight: topRight, - bottomRight: bottomRight, - bottomLeft: bottomLeft - }; -}; - /** * @override */ diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index 58d190463..d8b81b90b 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -61,71 +61,6 @@ Blockly.zelos.Drawer.prototype.drawOutline_ = function() { } }; -/** - * Add steps for the top corner of the block, taking into account - * details such as hats and rounded corners. - * @protected - */ -Blockly.zelos.Drawer.prototype.drawTop_ = function() { - var topRow = this.info_.topRow; - var elements = topRow.elements; - - this.positionPreviousConnection_(); - this.outlinePath_ += - Blockly.utils.svgPaths.moveBy(topRow.xPos, this.info_.startY); - for (var i = 0, elem; (elem = elements[i]); i++) { - if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) { - this.outlinePath_ += - this.constants_.OUTSIDE_CORNERS.topLeft; - } else if (Blockly.blockRendering.Types.isRightRoundedCorner(elem)) { - this.outlinePath_ += - this.constants_.OUTSIDE_CORNERS.topRight; - } else if (Blockly.blockRendering.Types.isPreviousConnection(elem)) { - this.outlinePath_ += elem.shape.pathLeft; - } else if (Blockly.blockRendering.Types.isHat(elem)) { - this.outlinePath_ += this.constants_.START_HAT.path; - } else if (Blockly.blockRendering.Types.isSpacer(elem)) { - this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('h', elem.width); - } - // No branch for a square corner because it's a no-op. - } - this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('v', topRow.height); -}; - - -/** - * Add steps for the bottom edge of a block, possibly including a notch - * for the next connection - * @protected - */ -Blockly.zelos.Drawer.prototype.drawBottom_ = function() { - var bottomRow = this.info_.bottomRow; - var elems = bottomRow.elements; - this.positionNextConnection_(); - - var rightCornerYOffset = 0; - var outlinePath = ''; - for (var i = elems.length - 1, elem; (elem = elems[i]); i--) { - if (Blockly.blockRendering.Types.isNextConnection(elem)) { - outlinePath += elem.shape.pathRight; - } else if (Blockly.blockRendering.Types.isLeftSquareCorner(elem)) { - outlinePath += Blockly.utils.svgPaths.lineOnAxis('H', bottomRow.xPos); - } else if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) { - outlinePath += this.constants_.OUTSIDE_CORNERS.bottomLeft; - } else if (Blockly.blockRendering.Types.isRightRoundedCorner(elem)) { - outlinePath += this.constants_.OUTSIDE_CORNERS.bottomRight; - rightCornerYOffset = this.constants_.INSIDE_CORNERS.rightHeight; - } else if (Blockly.blockRendering.Types.isSpacer(elem)) { - outlinePath += Blockly.utils.svgPaths.lineOnAxis('h', elem.width * -1); - } - } - - this.outlinePath_ += - Blockly.utils.svgPaths.lineOnAxis('V', - bottomRow.baseline - rightCornerYOffset); - this.outlinePath_ += outlinePath; -}; - /** * Add steps for the right side of a row that does not have value or * statement input connections. diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index c852afb70..36dac61f8 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -90,44 +90,6 @@ Blockly.zelos.RenderInfo.prototype.getRenderer = function() { return /** @type {!Blockly.zelos.Renderer} */ (this.renderer_); }; -/** - * Create all non-spacer elements that belong on the top row. - * @package - * @override - */ -Blockly.zelos.RenderInfo.prototype.populateTopRow_ = function() { - Blockly.zelos.RenderInfo.superClass_.populateTopRow_.call(this); - - var rightSquareCorner = this.topRow.hasRightSquareCorner(this.block_); - - if (rightSquareCorner) { - this.topRow.elements.push( - new Blockly.blockRendering.SquareCorner(this.constants_, 'right')); - } else { - this.topRow.elements.push( - new Blockly.blockRendering.RoundCorner(this.constants_, 'right')); - } -}; - -/** - * Create all non-spacer elements that belong on the bottom row. - * @package - * @override - */ -Blockly.zelos.RenderInfo.prototype.populateBottomRow_ = function() { - Blockly.zelos.RenderInfo.superClass_.populateBottomRow_.call(this); - - var rightSquareCorner = this.bottomRow.hasRightSquareCorner(this.block_); - - if (rightSquareCorner) { - this.bottomRow.elements.push( - new Blockly.blockRendering.SquareCorner(this.constants_, 'right')); - } else { - this.bottomRow.elements.push( - new Blockly.blockRendering.RoundCorner(this.constants_, 'right')); - } -}; - /** * @override */ @@ -176,10 +138,6 @@ Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { if (Blockly.blockRendering.Types.isLeftRoundedCorner(prev)) { return this.constants_.MIN_BLOCK_WIDTH; } - // Between a right rounded corner and the end of the row. - if (Blockly.blockRendering.Types.isRightRoundedCorner(prev)) { - return this.constants_.NO_PADDING; - } // Between a jagged edge and the end of the row. if (Blockly.blockRendering.Types.isJaggedEdge(prev)) { return this.constants_.NO_PADDING; diff --git a/core/renderers/zelos/measurables/rows.js b/core/renderers/zelos/measurables/rows.js index 8fa9e495d..f28729ad2 100644 --- a/core/renderers/zelos/measurables/rows.js +++ b/core/renderers/zelos/measurables/rows.js @@ -68,12 +68,10 @@ Blockly.zelos.TopRow.prototype.hasLeftSquareCorner = function(block) { }; /** - * Returns whether or not the top row has a right square corner. - * @param {!Blockly.BlockSvg} block The block whose top row this represents. - * @return {boolean} Whether or not the top row has a left square corner. + * Render a round corner unless the block has an output connection. + * @override */ Blockly.zelos.TopRow.prototype.hasRightSquareCorner = function(block) { - // Render a round corner unless the block has an output connection. return !!block.outputConnection; }; @@ -110,12 +108,10 @@ Blockly.zelos.BottomRow.prototype.hasLeftSquareCorner = function(block) { }; /** - * Returns whether or not the bottom row has a right square corner. - * @param {!Blockly.BlockSvg} block The block whose bottom row this represents. - * @return {boolean} Whether or not the bottom row has a left square corner. + * Render a round corner unless the block has an output connection. + * @override */ Blockly.zelos.BottomRow.prototype.hasRightSquareCorner = function(block) { - // Render a round corner unless the block has an output connection. return !!block.outputConnection; }; From 6170b770274df0823a8df274fc2e06b5cacb1a72 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 24 Oct 2019 11:11:03 -0400 Subject: [PATCH 100/343] Add langfiles build task in gulp (#3331) * Add build-langfiles to gulp, and add uncompressed + langfiles to build when building all --- gulpfile.js | 44 ++++++++++++++++++++++++++++++++++++++------ package.json | 4 ++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 8959fbc42..f57d6a33c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -238,7 +238,7 @@ gulp.task('build-dart', function() { * blockly_uncompressed.js */ gulp.task('build-uncompressed', function() { - const header = `// Do not edit this file; automatically generated by build.py. + const header = `// Do not edit this file; automatically generated by gulp. 'use strict'; this.IS_NODE_JS = !!(typeof module !== 'undefined' && module.exports); @@ -272,9 +272,6 @@ if (this.IS_NODE_JS) { this.BLOCKLY_BOOT(this); module.exports = Blockly; } else { - // Delete any existing Closure (e.g. Soy's nogoog_shim). - document.write(''); - // Load fresh Closure Library. document.write(''); document.write(''); @@ -286,13 +283,15 @@ if (this.IS_NODE_JS) { --root_with_prefix="./core ../core" > ${file}`; execSync(cmd, { stdio: 'inherit' }); - const requires = `\n// Load Blockly.\ngoog.require('Blockly.requires');\n`; + const requires = `goog.addDependency("base.js", [], []);\n\n// Load Blockly.\ngoog.require('Blockly.requires')\n`; return gulp.src(file) // Remove comments so we're compatible with the build.py script .pipe(gulp.replace(/\/\/.*\n/gm, '')) // Replace quotes to be compatible with build.py .pipe(gulp.replace(/\'(.*\.js)\'/gm, '"$1"')) + // Remove last parameter to be compatible with build.py + .pipe(gulp.replace(/, \{\}\);/gm, ');')) // Find the Blockly directory name and replace it with a JS variable. // This allows blockly_uncompressed.js to be compiled on one computer and be // used on another, even if the directory name differs. @@ -301,6 +300,35 @@ if (this.IS_NODE_JS) { .pipe(gulp.dest('./')); }); +/** + * This task builds Blockly's lang files. + * msg/*.js + */ +gulp.task('build-langfiles', function(done) { + // Run js_to_json.py + const jsToJsonCmd = `python ./i18n/js_to_json.py \ +--input_file ${path.join('msg', 'messages.js')} \ +--output_dir ${path.join('msg', 'json')} \ +--quiet`; + execSync(jsToJsonCmd, { stdio: 'inherit' }); + + // Run create_messages.py + let json_files = fs.readdirSync(path.join('msg', 'json')); + json_files = json_files.filter(file => file.endsWith('json') && + !(new RegExp(/(keys|synonyms|qqq|constants)\.json$/).test(file))); + json_files = json_files.map(file => path.join('msg', 'json', file)); + const createMessagesCmd = `python ./i18n/create_messages.py \ + --source_lang_file ${path.join('msg', 'json', 'en.json')} \ + --source_synonym_file ${path.join('msg', 'json', 'synonyms.json')} \ + --source_constants_file ${path.join('msg', 'json', 'constants.json')} \ + --key_file ${path.join('msg', 'json', 'keys.json')} \ + --output_dir ${path.join('msg', 'js')} \ + --quiet ${json_files.join(' ')}`; + execSync(createMessagesCmd, { stdio: 'inherit' }); + + done(); +}); + /** * This task builds all of Blockly: * blockly_compressed.js @@ -310,6 +338,8 @@ if (this.IS_NODE_JS) { * php_compressed.js * lua_compressed.js * dart_compressed.js + * blockly_uncompressed.js + * msg/json/*.js */ gulp.task('build', gulp.parallel( 'build-core', @@ -318,7 +348,9 @@ gulp.task('build', gulp.parallel( 'build-python', 'build-php', 'build-lua', - 'build-dart' + 'build-dart', + 'build-uncompressed', + 'build-langfiles' )); //////////////////////////////////////////////////////////// diff --git a/package.json b/package.json index d03df46a2..da8364912 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,11 @@ }, "scripts": { "build": "gulp build", + "build:blocks": "gulp build-blocks", + "build:core": "gulp build-core", "build:debug": "gulp build-core --verbose > build-debug.log 2>&1 && tail -3 -r build-debug.log", + "build:langfiles": "gulp build-langfiles", + "build:uncompressed": "gulp build-uncompressed", "bump": "npm version 3.$(date +'%Y%m%d').0", "lint": "eslint .", "package": "gulp package", From 649dc116ede69c39991b78bf74f33c64d9ddce42 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 24 Oct 2019 13:02:32 -0400 Subject: [PATCH 101/343] Using a HTML canvas for computing the text width (#3000) * Use a helper HTML canvas element to measure text width for better performance --- core/field.js | 17 ++++++++++-- core/field_dropdown.js | 8 ++++-- core/field_multilineinput.js | 2 +- core/field_textinput.js | 7 +---- core/utils/dom.js | 54 ++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 12 deletions(-) diff --git a/core/field.js b/core/field.js index e089adc3b..27c0b6220 100644 --- a/core/field.js +++ b/core/field.js @@ -257,6 +257,18 @@ Blockly.Field.prototype.EDITABLE = true; */ Blockly.Field.prototype.SERIALIZABLE = false; +/** + * Point size of text. Should match blocklyText's font-size in CSS. + * @const {string} + */ +Blockly.Field.FONTSIZE = 11; + +/** + * Text font family. Should match blocklyText's font-family in CSS. + * @const {string} + */ +Blockly.Field.FONTFAMILY = 'sans-serif'; + /** * Process the configuration map passed to the field. * @param {!Object} config A map of options used to configure the field. See @@ -641,8 +653,9 @@ Blockly.Field.prototype.updateWidth = function() { * @protected */ Blockly.Field.prototype.updateSize_ = function() { - var textWidth = Blockly.utils.dom.getTextWidth( - /** @type {!SVGTextElement} */ (this.textElement_)); + var textWidth = Blockly.utils.dom.getFastTextWidth( + /** @type {!SVGTextElement} */ (this.textElement_), + Blockly.Field.FONTSIZE, Blockly.Field.FONTFAMILY); var totalWidth = textWidth; if (this.borderRect_) { totalWidth += Blockly.Field.X_PADDING; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 3f38b3a6d..3a67f6be4 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -514,8 +514,9 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { this.imageElement_.setAttribute('height', imageJson.height); this.imageElement_.setAttribute('width', imageJson.width); - var arrowWidth = Blockly.utils.dom.getTextWidth( - /** @type {!SVGTSpanElement} */ (this.arrow_)); + var arrowWidth = Blockly.utils.dom.getFastTextWidth( + /** @type {!SVGTSpanElement} */ (this.arrow_), + Blockly.Field.FONTSIZE, Blockly.Field.FONTFAMILY); var imageHeight = Number(imageJson.height); var imageWidth = Number(imageJson.width); @@ -549,7 +550,8 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { this.textElement_.setAttribute('x', Blockly.Field.DEFAULT_TEXT_OFFSET); // Height and width include the border rect. this.size_.height = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT; - this.size_.width = Blockly.utils.dom.getTextWidth(this.textElement_) + + this.size_.width = Blockly.utils.dom.getFastTextWidth(this.textElement_, + Blockly.Field.FONTSIZE, Blockly.Field.FONTFAMILY) + Blockly.Field.X_PADDING; }; diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 26ba0a34c..9ecf70bf5 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -245,7 +245,7 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() { var htmlInput = /** @type {HTMLTextAreaElement} */ (document.createElement('textarea')); htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput'; htmlInput.setAttribute('spellcheck', this.spellcheck_); - var fontSize = (Blockly.FieldTextInput.FONTSIZE * scale) + 'pt'; + var fontSize = (Blockly.Field.FONTSIZE * scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px'; diff --git a/core/field_textinput.js b/core/field_textinput.js index 004348309..631923a71 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -107,11 +107,6 @@ Blockly.FieldTextInput.fromJson = function(options) { */ Blockly.FieldTextInput.prototype.SERIALIZABLE = true; -/** - * Point size of text. Should match blocklyText's font-size in CSS. - */ -Blockly.FieldTextInput.FONTSIZE = 11; - /** * Pixel size of input border radius. * Should match blocklyText's border-radius in CSS. @@ -291,7 +286,7 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { htmlInput.className = 'blocklyHtmlInput'; htmlInput.setAttribute('spellcheck', this.spellcheck_); var fontSize = - (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt'; + (Blockly.Field.FONTSIZE * this.workspace_.scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; var borderRadius = diff --git a/core/utils/dom.js b/core/utils/dom.js index 045cc17ad..dfacc4188 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -76,6 +76,13 @@ Blockly.utils.dom.cacheWidths_ = null; */ Blockly.utils.dom.cacheReference_ = 0; +/** + * A HTML canvas context used for computing text width. + * @type {CanvasRenderingContext2D} + * @private + */ +Blockly.utils.dom.canvasContext_ = null; + /** * Helper method for creating SVG elements. * @param {string} name Element's tag name. @@ -271,3 +278,50 @@ Blockly.utils.dom.getTextWidth = function(textElement) { } return width; }; + +/** + * Gets the width of a text element using a faster method than `getTextWidth`. + * This method requires that we know the text element's font family and size in + * advance. Similar to `getTextWidth`, we cache the width we compute. + * @param {!Element} textElement An SVG 'text' element. + * @param {string} fontSize The font size to use. + * @param {string} fontFamily The font family to use. + * @return {number} Width of element. + */ +Blockly.utils.dom.getFastTextWidth = function(textElement, + fontSize, fontFamily) { + var text = textElement.textContent; + var key = text + '\n' + textElement.className.baseVal; + var width; + + // Return the cached width if it exists. + if (Blockly.utils.dom.cacheWidths_) { + width = Blockly.utils.dom.cacheWidths_[key]; + if (width) { + return width; + } + } + + if (!Blockly.utils.dom.canvasContext_) { + // Inject the canvas element used for computing text widths. + var 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'); + } + // Set the desired font size and family. + Blockly.utils.dom.canvasContext_.font = fontSize + 'pt ' + fontFamily; + + // Measure the text width using the helper canvas context. + width = Blockly.utils.dom.canvasContext_.measureText(text).width; + + // Cache the computed width and return. + if (Blockly.utils.dom.cacheWidths_) { + Blockly.utils.dom.cacheWidths_[key] = width; + } + return width; +}; From bfe62f98ca5727fcfbcf9a8b95e4b3ff4e96e7a2 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 24 Oct 2019 15:47:42 -0400 Subject: [PATCH 102/343] Dispose makes the types we use inconsistent. Suppress checkTypes in dispose. (#3336) --- core/block.js | 1 + core/block_svg.js | 1 + core/bubble_dragger.js | 1 + core/flyout_base.js | 1 + core/grid.js | 1 + core/input.js | 1 + core/trashcan.js | 1 + core/workspace_dragger.js | 1 + core/workspace_svg.js | 1 + 9 files changed, 9 insertions(+) diff --git a/core/block.js b/core/block.js index dc1edd6ce..15f106d3d 100644 --- a/core/block.js +++ b/core/block.js @@ -313,6 +313,7 @@ Blockly.Block.prototype.getDeveloperVariables; * @param {boolean} healStack If true, then try to heal any gap by connecting * the next statement with the previous statement. Otherwise, dispose of * all children of this block. + * @suppress {checkTypes} */ Blockly.Block.prototype.dispose = function(healStack) { if (!this.workspace) { diff --git a/core/block_svg.js b/core/block_svg.js index 92a7735c7..06bf90cd7 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1009,6 +1009,7 @@ Blockly.BlockSvg.prototype.getSvgRoot = function() { * the next statement with the previous statement. Otherwise, dispose of * all children of this block. * @param {boolean=} animate If true, show a disposal animation and sound. + * @suppress {checkTypes} */ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { if (!this.workspace) { diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index c4cc6910d..9864f61af 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -92,6 +92,7 @@ Blockly.BubbleDragger = function(bubble, workspace) { /** * Sever all links from this object. * @package + * @suppress {checkTypes} */ Blockly.BubbleDragger.prototype.dispose = function() { this.draggingBubble_ = null; diff --git a/core/flyout_base.js b/core/flyout_base.js index 349322715..61202150e 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -276,6 +276,7 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) { /** * Dispose of this flyout. * Unlink from all DOM elements to prevent memory leaks. + * @suppress {checkTypes} */ Blockly.Flyout.prototype.dispose = function() { this.hide(); diff --git a/core/grid.js b/core/grid.js index 3311264c4..3b036f493 100644 --- a/core/grid.js +++ b/core/grid.js @@ -92,6 +92,7 @@ Blockly.Grid.prototype.scale_ = 1; /** * Dispose of this grid and unlink from the DOM. * @package + * @suppress {checkTypes} */ Blockly.Grid.prototype.dispose = function() { this.gridPattern_ = null; diff --git a/core/input.js b/core/input.js index 22278605b..9326d05de 100644 --- a/core/input.js +++ b/core/input.js @@ -258,6 +258,7 @@ Blockly.Input.prototype.init = function() { /** * Sever all links to this input. + * @suppress {checkTypes} */ Blockly.Input.prototype.dispose = function() { for (var i = 0, field; field = this.fieldRow[i]; i++) { diff --git a/core/trashcan.js b/core/trashcan.js index 0032e4712..e6e577a3a 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -303,6 +303,7 @@ Blockly.Trashcan.prototype.init = function(verticalSpacing) { /** * Dispose of this trash can. * Unlink from all DOM elements to prevent memory leaks. + * @suppress {checkTypes} */ Blockly.Trashcan.prototype.dispose = function() { if (this.svgGroup_) { diff --git a/core/workspace_dragger.js b/core/workspace_dragger.js index 01b97955f..8d4d10568 100644 --- a/core/workspace_dragger.js +++ b/core/workspace_dragger.js @@ -55,6 +55,7 @@ Blockly.WorkspaceDragger = function(workspace) { /** * Sever all links from this object. * @package + * @suppress {checkTypes} */ Blockly.WorkspaceDragger.prototype.dispose = function() { this.workspace_ = null; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index d5d8143c6..aee610986 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -680,6 +680,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { /** * Dispose of this workspace. * Unlink from all DOM elements to prevent memory leaks. + * @suppress {checkTypes} */ Blockly.WorkspaceSvg.prototype.dispose = function() { // Stop rerendering. From d387841db2c16e183a71b9906e831d26b15a2682 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 24 Oct 2019 19:13:51 -0400 Subject: [PATCH 103/343] Resolve remaining compiler warnings with visibility issues (#3335) --- core/block.js | 4 ++-- core/block_dragger.js | 2 +- core/block_svg.js | 8 ++++---- core/blockly.js | 4 ++-- core/contextmenu.js | 6 +++--- core/gesture.js | 2 +- core/touch.js | 4 ++-- core/workspace.js | 19 +++++++++++++++++++ core/workspace_comment_svg.js | 4 ++-- 9 files changed, 36 insertions(+), 17 deletions(-) diff --git a/core/block.js b/core/block.js index 15f106d3d..dd44dce1d 100644 --- a/core/block.js +++ b/core/block.js @@ -63,7 +63,7 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { /** @type {string} */ this.id = (opt_id && !workspace.getBlockById(opt_id)) ? opt_id : Blockly.utils.genUid(); - workspace.blockDB_[this.id] = this; + workspace.setBlockById(this.id, this); /** @type {Blockly.Connection} */ this.outputConnection = null; /** @type {Blockly.Connection} */ @@ -343,7 +343,7 @@ Blockly.Block.prototype.dispose = function(healStack) { this.workspace.removeTopBlock(this); this.workspace.removeTypedBlock(this); // Remove from block database. - delete this.workspace.blockDB_[this.id]; + this.workspace.removeBlockById(this.id); this.workspace = null; } diff --git a/core/block_dragger.js b/core/block_dragger.js index 2eb62a60d..9e881c6b3 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -178,7 +178,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, // For future consideration: we may be able to put moveToDragSurface inside // the block dragger, which would also let the block not track the block drag // surface. - this.draggingBlock_.moveToDragSurface_(); + this.draggingBlock_.moveToDragSurface(); var toolbox = this.workspace_.getToolbox(); if (toolbox) { diff --git a/core/block_svg.js b/core/block_svg.js index 06bf90cd7..7119d7d23 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -485,9 +485,9 @@ Blockly.BlockSvg.prototype.translate = function(x, y) { * Move this block to its workspace's drag surface, accounting for positioning. * Generally should be called at the same time as setDragging_(true). * Does nothing if useDragSurface_ is false. - * @private + * @package */ -Blockly.BlockSvg.prototype.moveToDragSurface_ = function() { +Blockly.BlockSvg.prototype.moveToDragSurface = function() { if (!this.useDragSurface_) { return; } @@ -757,9 +757,9 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { /** * Load the block's help page in a new window. - * @private + * @package */ -Blockly.BlockSvg.prototype.showHelp_ = function() { +Blockly.BlockSvg.prototype.showHelp = function() { var url = (typeof this.helpUrl == 'function') ? this.helpUrl() : this.helpUrl; if (url) { window.open(url); diff --git a/core/blockly.js b/core/blockly.js index e37078bb5..02966ed09 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -303,9 +303,9 @@ Blockly.copy_ = function(toCopy) { * Duplicate this block and its children, or a workspace comment. * @param {!Blockly.Block | !Blockly.WorkspaceComment} toDuplicate Block or * Workspace Comment to be copied. - * @private + * @package */ -Blockly.duplicate_ = function(toDuplicate) { +Blockly.duplicate = function(toDuplicate) { // Save the clipboard. var clipboardXml = Blockly.clipboardXml_; var clipboardSource = Blockly.clipboardSource_; diff --git a/core/contextmenu.js b/core/contextmenu.js index e1eee486b..10330e9ff 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -243,7 +243,7 @@ Blockly.ContextMenu.blockHelpOption = function(block) { enabled: !!url, text: Blockly.Msg['HELP'], callback: function() { - block.showHelp_(); + block.showHelp(); } }; return helpOption; @@ -261,7 +261,7 @@ Blockly.ContextMenu.blockDuplicateOption = function(block) { text: Blockly.Msg['DUPLICATE_BLOCK'], enabled: enabled, callback: function() { - Blockly.duplicate_(block); + Blockly.duplicate(block); } }; return duplicateOption; @@ -330,7 +330,7 @@ Blockly.ContextMenu.commentDuplicateOption = function(comment) { text: Blockly.Msg.DUPLICATE_COMMENT, enabled: true, callback: function() { - Blockly.duplicate_(comment); + Blockly.duplicate(comment); } }; return duplicateOption; diff --git a/core/gesture.js b/core/gesture.js index e7efa7fd9..ade6a2c86 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -509,7 +509,7 @@ Blockly.Gesture.prototype.doStart = function(e) { if ((e.type.toLowerCase() == 'touchstart' || e.type.toLowerCase() == 'pointerdown') && e.pointerType != 'mouse') { - Blockly.longStart_(e, this); + Blockly.longStart(e, this); } this.mouseDownXY_ = new Blockly.utils.Coordinate(e.clientX, e.clientY); diff --git a/core/touch.js b/core/touch.js index 7e6d097ea..2c5094ae6 100644 --- a/core/touch.js +++ b/core/touch.js @@ -92,9 +92,9 @@ Blockly.longPid_ = 0; * if the touch event terminates early. * @param {!Event} e Touch start event. * @param {Blockly.Gesture} gesture The gesture that triggered this longStart. - * @private + * @package */ -Blockly.longStart_ = function(e, gesture) { +Blockly.longStart = function(e, gesture) { Blockly.longStop_(); // Punt on multitouch events. if (e.changedTouches && e.changedTouches.length != 1) { diff --git a/core/workspace.js b/core/workspace.js index 10d5b11ab..59a5e845a 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -793,6 +793,25 @@ Blockly.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. + * @package + */ +Blockly.Workspace.prototype.setBlockById = function(id, block) { + this.blockDB_[id] = block; +}; + +/** + * Delete a block off this workspace with the specified ID. + * @param {string} id ID of block to delete. + * @package + */ +Blockly.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. diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index c0382740c..7b9c41268 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -343,9 +343,9 @@ Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) { * Move this comment to its workspace's drag surface, accounting for * positioning. Generally should be called at the same time as * setDragging(true). Does nothing if useDragSurface_ is false. - * @private + * @package */ -Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface_ = function() { +Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface = function() { if (!this.useDragSurface_) { return; } From 7fc733b81f6d70ac43e1883dbb9041e8850874f2 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 24 Oct 2019 21:42:44 -0400 Subject: [PATCH 104/343] Wrap dummy inputs in a measurable so that it can be aligned appropriately. (#3337) --- core/renderers/common/info.js | 4 ++-- core/renderers/geras/info.js | 4 ++-- core/renderers/measurables/inputs.js | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index f47b8c136..541eac5ce 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -374,8 +374,8 @@ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRo new Blockly.blockRendering.ExternalValueInput(this.constants_, input)); activeRow.hasExternalInput = true; } else if (input.type == Blockly.DUMMY_INPUT) { - // Dummy inputs have no visual representation, but the information is still - // important. + activeRow.elements.push( + new Blockly.blockRendering.DummyInput(this.constants_, input)); activeRow.hasDummyInput = true; } }; diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 31b99e6b7..186b48eba 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -113,8 +113,8 @@ Blockly.geras.RenderInfo.prototype.addInput_ = function(input, activeRow) { new Blockly.blockRendering.ExternalValueInput(this.constants_, input)); activeRow.hasExternalInput = true; } else if (input.type == Blockly.DUMMY_INPUT) { - // Dummy inputs have no visual representation, but the information is still - // important. + activeRow.elements.push( + new Blockly.blockRendering.DummyInput(this.constants_, input)); activeRow.hasDummyInput = true; } }; diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index 90e6706fb..a816844b9 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -70,6 +70,27 @@ Blockly.blockRendering.InputConnection = function(constants, input) { Blockly.utils.object.inherits(Blockly.blockRendering.InputConnection, Blockly.blockRendering.Connection); +/** + * An object containing information about the space a dummy 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.Measurable} + */ +Blockly.blockRendering.DummyInput = function(constants, input) { + Blockly.blockRendering.DummyInput.superClass_.constructor.call(this, + constants); + this.type |= Blockly.blockRendering.Types.INPUT; + this.input = input; + this.align = input.align; +}; +Blockly.utils.object.inherits(Blockly.blockRendering.DummyInput, + Blockly.blockRendering.Measurable); + /** * An object containing information about the space an inline input takes up * during rendering From a79ea1652a2c03f9c832028d6d4ca68825c15509 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Fri, 25 Oct 2019 00:33:53 -0400 Subject: [PATCH 105/343] [Zelos] Fix dynamic connection shape size (#3324) * Better reporting of connection height and width for dynamic connections --- core/renderers/geras/measurables/inputs.js | 2 +- core/renderers/measurables/connections.js | 23 ++++++--- core/renderers/measurables/inputs.js | 58 ++++++++++++++++------ core/renderers/measurables/rows.js | 3 +- core/renderers/zelos/constants.js | 16 ++++-- core/renderers/zelos/drawer.js | 2 +- core/renderers/zelos/info.js | 58 ++++++++++++++++------ 7 files changed, 117 insertions(+), 45 deletions(-) diff --git a/core/renderers/geras/measurables/inputs.js b/core/renderers/geras/measurables/inputs.js index de7254f10..f662b2969 100644 --- a/core/renderers/geras/measurables/inputs.js +++ b/core/renderers/geras/measurables/inputs.js @@ -25,9 +25,9 @@ goog.provide('Blockly.geras.InlineInput'); goog.provide('Blockly.geras.StatementInput'); -goog.require('Blockly.blockRendering.Connection'); goog.require('Blockly.utils.object'); + /** * An object containing information about the space an inline input takes up * during rendering diff --git a/core/renderers/measurables/connections.js b/core/renderers/measurables/connections.js index ca81f5c30..098c3f5d7 100644 --- a/core/renderers/measurables/connections.js +++ b/core/renderers/measurables/connections.js @@ -47,6 +47,7 @@ Blockly.blockRendering.Connection = function(constants, connectionModel) { constants); this.connectionModel = connectionModel; this.shape = this.constants_.shapeFor(connectionModel); + this.isDynamicShape = !!this.shape.isDynamic; this.type |= Blockly.blockRendering.Types.CONNECTION; }; Blockly.utils.object.inherits(Blockly.blockRendering.Connection, @@ -67,21 +68,27 @@ Blockly.blockRendering.OutputConnection = function(constants, connectionModel) { Blockly.blockRendering.OutputConnection.superClass_.constructor.call(this, constants, connectionModel); this.type |= Blockly.blockRendering.Types.OUTPUT_CONNECTION; - this.height = this.shape.height; - this.width = this.shape.width; + + this.setShapeDimensions( + !this.isDynamicShape ? this.shape.height : 0, + !this.isDynamicShape ? this.shape.width : 0); + this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; - this.startX = this.width; }; Blockly.utils.object.inherits(Blockly.blockRendering.OutputConnection, Blockly.blockRendering.Connection); + /** - * Whether or not the connection shape is dynamic. Dynamic shapes get their - * height from the block. - * @return {boolean} True if the connection shape is dynamic. + * Sets properties that depend on the connection shape dimensions. + * @param {number} height Height of the connection shape. + * @param {number} width Width of the connection shape. */ -Blockly.blockRendering.OutputConnection.prototype.isDynamic = function() { - return this.shape.isDynamic; +Blockly.blockRendering.OutputConnection.prototype.setShapeDimensions = function( + height, width) { + this.height = height; + this.width = width; + this.startX = this.width; }; /** diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index a816844b9..8b53ea4a6 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -107,9 +107,26 @@ Blockly.blockRendering.InlineInput = function(constants, input) { constants, input); this.type |= Blockly.blockRendering.Types.INLINE_INPUT; + this.setShapeDimensions( + !this.isDynamicShape ? this.shape.height : 0, + !this.isDynamicShape ? this.shape.width : 0); + + this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; +}; +Blockly.utils.object.inherits(Blockly.blockRendering.InlineInput, + Blockly.blockRendering.InputConnection); + + +/** + * Sets properties that depend on the connection shape dimensions. + * @param {number} height Height of the connection shape. + * @param {number} width Width of the connection shape. + */ +Blockly.blockRendering.InlineInput.prototype.setShapeDimensions = function( + height, width) { if (!this.connectedBlock) { this.height = this.constants_.EMPTY_INLINE_INPUT_HEIGHT; - this.width = this.shape.width + + this.width = width + this.constants_.EMPTY_INLINE_INPUT_PADDING; } else { // We allow the dark path to show on the parent block so that the child @@ -117,13 +134,9 @@ Blockly.blockRendering.InlineInput = function(constants, input) { this.width = this.connectedBlockWidth; this.height = this.connectedBlockHeight; } - - this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; - this.connectionHeight = this.shape.height; - this.connectionWidth = this.shape.width; + this.connectionHeight = height; + this.connectionWidth = width; }; -Blockly.utils.object.inherits(Blockly.blockRendering.InlineInput, - Blockly.blockRendering.InputConnection); /** * An object containing information about the space a statement input takes up @@ -149,8 +162,7 @@ Blockly.blockRendering.StatementInput = function(constants, input) { this.height = this.connectedBlockHeight + this.constants_.STATEMENT_BOTTOM_SPACER; } - this.width = this.constants_.NOTCH_OFFSET_LEFT + - this.shape.width; + this.width = this.constants_.NOTCH_OFFSET_LEFT + this.shape.width; }; Blockly.utils.object.inherits(Blockly.blockRendering.StatementInput, Blockly.blockRendering.InputConnection); @@ -171,19 +183,33 @@ Blockly.blockRendering.ExternalValueInput = function(constants, input) { constants, input); this.type |= Blockly.blockRendering.Types.EXTERNAL_VALUE_INPUT; + this.setShapeDimensions( + !this.isDynamicShape ? this.shape.height : 0, + !this.isDynamicShape ? this.shape.width : 0); + + this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; +}; +Blockly.utils.object.inherits(Blockly.blockRendering.ExternalValueInput, + Blockly.blockRendering.InputConnection); + + +/** + * Sets properties that depend on the connection shape dimensions. + * @param {number} height Height of the connection shape. + * @param {number} width Width of the connection shape. + */ +Blockly.blockRendering.ExternalValueInput.prototype.setShapeDimensions = function( + height, width) { if (!this.connectedBlock) { - this.height = this.shape.height; + this.height = height; } else { this.height = this.connectedBlockHeight - this.constants_.TAB_OFFSET_FROM_TOP - this.constants_.MEDIUM_PADDING; } - this.width = this.shape.width + + this.width = 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; + this.connectionHeight = height; + this.connectionWidth = width; }; -Blockly.utils.object.inherits(Blockly.blockRendering.ExternalValueInput, - Blockly.blockRendering.InputConnection); diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index e4b47b4f5..c2c977a14 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -515,7 +515,8 @@ Blockly.blockRendering.InputRow.prototype.measure = function() { connectedBlockWidths += elem.connectedBlockWidth; } else if (Blockly.blockRendering.Types.isExternalInput(elem) && elem.connectedBlockWidth != 0) { - connectedBlockWidths += (elem.connectedBlockWidth - elem.connectionWidth); + connectedBlockWidths += (elem.connectedBlockWidth - + elem.connectionWidth); } } if (!(Blockly.blockRendering.Types.isSpacer(elem))) { diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 6de86b3a4..8e17d9d69 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -111,9 +111,13 @@ Blockly.zelos.ConstantProvider.prototype.makeHexagonal = function() { } return { - width: 0, - height: 0, isDynamic: true, + width: function(height) { + return height / 2; + }, + height: function(height) { + return height; + }, pathDown: function(height) { return makeMainPath(height, false, false); }, @@ -145,9 +149,13 @@ Blockly.zelos.ConstantProvider.prototype.makeRounded = function() { } return { - width: 0, - height: 0, isDynamic: true, + width: function(height) { + return height / 2; + }, + height: function(height) { + return height; + }, pathDown: function(height) { return makeMainPath(height, false, false); }, diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index d8b81b90b..193665a72 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -51,7 +51,7 @@ Blockly.utils.object.inherits(Blockly.zelos.Drawer, */ Blockly.zelos.Drawer.prototype.drawOutline_ = function() { if (this.info_.outputConnection && - this.info_.outputConnection.isDynamic()) { + this.info_.outputConnection.isDynamicShape) { this.drawFlatTop_(); this.drawRightDynamicConnection_(); this.drawFlatBottom_(); diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index 36dac61f8..9ddc7fc51 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -77,6 +77,11 @@ Blockly.zelos.RenderInfo = function(renderer, block) { * @override */ this.bottomRow = new Blockly.zelos.BottomRow(this.constants_); + + /** + * @override + */ + this.isInline = true; }; Blockly.utils.object.inherits(Blockly.zelos.RenderInfo, Blockly.blockRendering.RenderInfo); @@ -90,6 +95,20 @@ Blockly.zelos.RenderInfo.prototype.getRenderer = function() { return /** @type {!Blockly.zelos.Renderer} */ (this.renderer_); }; +/** + * @override + */ +Blockly.zelos.RenderInfo.prototype.computeBounds_ = function() { + Blockly.zelos.RenderInfo.superClass_.computeBounds_.call(this); + + if (this.outputConnection && this.outputConnection.isDynamicShape) { + // Add right connection width. + var rightConnectionWidth = this.outputConnection.width; + this.width += rightConnectionWidth; + this.widthWithChildren += rightConnectionWidth; + } +}; + /** * @override */ @@ -97,7 +116,7 @@ Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { if (!prev || !next) { // No need for padding at the beginning or end of the row if the // output shape is dynamic. - if (this.outputConnection && this.outputConnection.isDynamic()) { + if (this.outputConnection && this.outputConnection.isDynamicShape) { return this.constants_.NO_PADDING; } } @@ -314,30 +333,41 @@ Blockly.zelos.RenderInfo.prototype.finalize_ = function() { row.yPos = yCursor; yCursor += row.height; } - // Dynamic output connections depend on the height of the block. Adjust the - // height and width of the connection, and then adjust the startX and width of the - // block accordingly. - var outputConnectionWidth = 0; - if (this.outputConnection && !this.outputConnection.height) { - this.outputConnection.height = yCursor; - outputConnectionWidth = yCursor; // Twice the width to account for the right side. - this.outputConnection.width = outputConnectionWidth / 2; + this.height = yCursor; + + if (this.outputConnection && this.outputConnection.isDynamicShape) { + // Dynamic output connections depend on the height of the block. Adjust the + // height of the connection. + this.outputConnection.setShapeDimensions( + this.outputConnection.shape.height(this.height), + this.outputConnection.shape.width(this.height)); + + // Recompute the bounds as we now know the output connection dimensions. + this.computeBounds_(); } - this.startX += outputConnectionWidth / 2; - this.width += outputConnectionWidth; var widestRowWithConnectedBlocks = 0; for (var i = 0, row; (row = this.rows[i]); i++) { row.xPos = this.startX; + for (var j = 0, elem; (elem = row.elements[j]); j++) { + if (Blockly.blockRendering.Types.isInlineInput(elem) || + Blockly.blockRendering.Types.isExternalInput(elem)) { + if (elem.isDynamicShape) { + elem.setShapeDimensions(elem.shape.height(elem.height), + elem.shape.width(elem.height)); + } + } + } + widestRowWithConnectedBlocks = Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); this.recordElemPositions_(row); } - this.widthWithChildren = widestRowWithConnectedBlocks + this.startX; + this.widthWithChildren = Math.max(this.widthWithChildren, + widestRowWithConnectedBlocks + this.startX); - this.height = yCursor; this.startY = this.topRow.capline; - this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight; + this.bottomRow.baseline = this.height - this.bottomRow.descenderHeight; }; From 100da4a66c555569745c54843ee86fea20ed8630 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 24 Oct 2019 21:53:30 -0700 Subject: [PATCH 106/343] Revert "Wrap dummy inputs in a measurable so that it can be aligned appropriately. (#3337)" This reverts commit 7fc733b81f6d70ac43e1883dbb9041e8850874f2. --- core/renderers/common/info.js | 4 ++-- core/renderers/geras/info.js | 4 ++-- core/renderers/measurables/inputs.js | 21 --------------------- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 541eac5ce..f47b8c136 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -374,8 +374,8 @@ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRo new Blockly.blockRendering.ExternalValueInput(this.constants_, input)); activeRow.hasExternalInput = true; } else if (input.type == Blockly.DUMMY_INPUT) { - activeRow.elements.push( - new Blockly.blockRendering.DummyInput(this.constants_, input)); + // Dummy inputs have no visual representation, but the information is still + // important. activeRow.hasDummyInput = true; } }; diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 186b48eba..31b99e6b7 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -113,8 +113,8 @@ Blockly.geras.RenderInfo.prototype.addInput_ = function(input, activeRow) { new Blockly.blockRendering.ExternalValueInput(this.constants_, input)); activeRow.hasExternalInput = true; } else if (input.type == Blockly.DUMMY_INPUT) { - activeRow.elements.push( - new Blockly.blockRendering.DummyInput(this.constants_, input)); + // Dummy inputs have no visual representation, but the information is still + // important. activeRow.hasDummyInput = true; } }; diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index 8b53ea4a6..754c624a7 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -70,27 +70,6 @@ Blockly.blockRendering.InputConnection = function(constants, input) { Blockly.utils.object.inherits(Blockly.blockRendering.InputConnection, Blockly.blockRendering.Connection); -/** - * An object containing information about the space a dummy 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.Measurable} - */ -Blockly.blockRendering.DummyInput = function(constants, input) { - Blockly.blockRendering.DummyInput.superClass_.constructor.call(this, - constants); - this.type |= Blockly.blockRendering.Types.INPUT; - this.input = input; - this.align = input.align; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.DummyInput, - Blockly.blockRendering.Measurable); - /** * An object containing information about the space an inline input takes up * during rendering From ae1a41fd20cb4044ed9fdfc1192502502d2d0519 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Fri, 25 Oct 2019 10:55:24 -0700 Subject: [PATCH 107/343] Fire UI events when cursor moves or a marker is added (#3338) * Fire UI events when cursor moves or a marker is added --- core/keyboard_nav/ast_node.js | 17 +++++++++++++++++ core/keyboard_nav/cursor.js | 3 ++- core/keyboard_nav/cursor_svg.js | 21 ++++++++++++++++++++- core/keyboard_nav/navigation.js | 28 +++------------------------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index b1ee7c70f..ed74df6a7 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -470,6 +470,23 @@ Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) { return null; }; +/** + * Finds the source block of the location of this node. + * @return {Blockly.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) { + return null; + } else { + return 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, diff --git a/core/keyboard_nav/cursor.js b/core/keyboard_nav/cursor.js index be9e2d48c..f7550273e 100644 --- a/core/keyboard_nav/cursor.js +++ b/core/keyboard_nav/cursor.js @@ -78,9 +78,10 @@ Blockly.Cursor.prototype.getCurNode = function() { * @param {Blockly.ASTNode} newNode The new location of the cursor. */ Blockly.Cursor.prototype.setCurNode = function(newNode) { + var oldNode = this.curNode_; this.curNode_ = newNode; if (this.drawer_) { - this.drawer_.draw(this.getCurNode()); + this.drawer_.draw(oldNode, this.curNode_); } }; diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index 13a5e4a8d..329059ba7 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -483,10 +483,11 @@ Blockly.CursorSvg.prototype.hide = function() { /** * Update the cursor. + * @param {Blockly.ASTNode} oldNode The previous node the cursor was on or null. * @param {Blockly.ASTNode} curNode The node that we want to draw the cursor for. * @package */ -Blockly.CursorSvg.prototype.draw = function(curNode) { +Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) { if (!curNode) { this.hide(); return; @@ -513,6 +514,8 @@ Blockly.CursorSvg.prototype.draw = function(curNode) { this.showWithStack_(curNode); } + this.fireCursorEvent_(oldNode, curNode); + // Ensures the cursor will be visible immediately after the move. var animate = this.currentCursorSvg.childNodes[0]; if (animate !== undefined) { @@ -520,6 +523,22 @@ Blockly.CursorSvg.prototype.draw = function(curNode) { } }; +/** + * Fire event for the cursor or marker. + * @param {Blockly.ASTNode} oldNode The old node the cursor used to be on. + * @param {!Blockly.ASTNode} curNode The new node the cursor is currently on. + * @private + */ +Blockly.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) { + var curBlock = curNode.getSourceBlock(); + var eventType = this.isMarker_ ? 'markedNode' : 'cursorMove'; + var event = new Blockly.Events.Ui(curBlock, eventType, oldNode, curNode); + if (curNode.getType() == Blockly.ASTNode.types.WORKSPACE) { + event.workspaceId = curNode.getLocation().id; + } + Blockly.Events.fire(event); +}; + /** * Create the cursor SVG. * @return {Element} The SVG node created. diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 6d397abf3..90319cb9b 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -336,7 +336,7 @@ Blockly.navigation.modify_ = function() { markerLoc = /** @type {!Blockly.Connection} */ (markerLoc); return Blockly.navigation.insertBlock(cursorLoc, markerLoc); } else if (markerType == Blockly.ASTNode.types.WORKSPACE) { - var block = Blockly.navigation.getSourceBlock_(cursorNode); + var block = cursorNode ? cursorNode.getSourceBlock() : null; return Blockly.navigation.moveBlockToWorkspace_(block, markerNode); } Blockly.navigation.warn_('Unexpected state in Blockly.navigation.modify_.'); @@ -589,28 +589,6 @@ Blockly.navigation.setState = function(newState) { Blockly.navigation.currentState_ = newState; }; -/** - * Finds the source block of the location on a given node. - * @param {Blockly.ASTNode} node The node to find the source block on. - * @return {Blockly.Block} The source block of the location on the given node, - * or null if the node is of type workspace. - * @private - */ -Blockly.navigation.getSourceBlock_ = function(node) { - if (!node) { - return null; - } - if (node.getType() === Blockly.ASTNode.types.BLOCK) { - return /** @type {Blockly.Block} */ (node.getLocation()); - } else if (node.getType() === Blockly.ASTNode.types.STACK) { - return /** @type {Blockly.Block} */ (node.getLocation()); - } else if (node.getType() === Blockly.ASTNode.types.WORKSPACE) { - return null; - } else { - return node.getLocation().getSourceBlock(); - } -}; - /** * Gets the top node on a block. * This is either the previous connection, output connection or the block. @@ -642,7 +620,7 @@ Blockly.navigation.moveCursorOnBlockDelete = function(deletedBlock) { var cursor = workspace.getCursor(); if (cursor) { var curNode = cursor.getCurNode(); - var block = Blockly.navigation.getSourceBlock_(curNode); + var block = curNode ? curNode.getSourceBlock() : null; if (block === deletedBlock) { // If the block has a parent move the cursor to their connection point. @@ -676,7 +654,7 @@ Blockly.navigation.moveCursorOnBlockMutation = function(mutatedBlock) { var cursor = Blockly.getMainWorkspace().getCursor(); if (cursor) { var curNode = cursor.getCurNode(); - var block = Blockly.navigation.getSourceBlock_(curNode); + var block = curNode ? curNode.getSourceBlock() : null; if (block === mutatedBlock) { cursor.setCurNode(Blockly.ASTNode.createBlockNode(block)); From 759875a6c0777c3248a34e84def9daa26bbb6861 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Fri, 25 Oct 2019 19:07:17 -0400 Subject: [PATCH 108/343] Resolve remaining compiler type warnings (#3334) * Resolve remaining compiler warnings with inconsistent types. --- core/block.js | 2 +- core/block_drag_surface.js | 8 ++++---- core/block_svg.js | 6 +++--- core/blockly.js | 4 ++-- core/contextmenu.js | 2 +- core/events.js | 2 +- core/extensions.js | 9 +++++---- core/grid.js | 7 ++++--- core/keyboard_nav/ast_node.js | 5 +++-- core/workspace.js | 14 ++++++++------ core/workspace_audio.js | 1 - core/workspace_svg.js | 9 +++++---- 12 files changed, 37 insertions(+), 32 deletions(-) diff --git a/core/block.js b/core/block.js index dd44dce1d..895c77c1b 100644 --- a/core/block.js +++ b/core/block.js @@ -1814,7 +1814,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. + * @return {?string} Block's comment. */ Blockly.Block.prototype.getCommentText = function() { return this.commentModel.text; diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index ffdf54729..5c33b5273 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -173,7 +173,7 @@ Blockly.BlockDragSurfaceSvg.prototype.translateSurface = function(x, y) { * @return {!Blockly.utils.Coordinate} Current translation of the surface. */ Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() { - var xy = Blockly.utils.getRelativeXY(this.SVG_); + var xy = Blockly.utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); return new Blockly.utils.Coordinate(xy.x / this.scale_, xy.y / this.scale_); }; @@ -189,11 +189,11 @@ Blockly.BlockDragSurfaceSvg.prototype.getGroup = function() { /** * Get the current blocks on the drag surface, if any (primarily * for BlockSvg.getRelativeToSurfaceXY). - * @return {!Element|undefined} Drag surface block DOM element, or undefined - * if no blocks exist. + * @return {Element} Drag surface block DOM element, or undefined if no blocks + * exist. */ Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock = function() { - return this.dragGroup_.firstChild; + return /** @type {Element} */ (this.dragGroup_.firstChild); }; /** diff --git a/core/block_svg.js b/core/block_svg.js index 7119d7d23..5c34f64ae 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -56,7 +56,7 @@ goog.require('Blockly.Warning'); Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { // Create core elements for the block. /** - * @type {SVGElement} + * @type {!SVGElement} * @private */ this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); @@ -440,7 +440,7 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { x += surfaceTranslation.x; y += surfaceTranslation.y; } - element = element.parentNode; + element = /** @type {!SVGElement} */ (element.parentNode); } while (element && element != this.workspace.getCanvas() && element != dragSurfaceGroup); } @@ -997,7 +997,7 @@ Blockly.BlockSvg.prototype.setInsertionMarker = function(insertionMarker) { /** * Return the root node of the SVG or null if none exists. - * @return {SVGElement} The root SVG node (probably a group). + * @return {!SVGElement} The root SVG node (probably a group). */ Blockly.BlockSvg.prototype.getSvgRoot = function() { return this.svgGroup_; diff --git a/core/blockly.js b/core/blockly.js index 02966ed09..11513dddc 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -363,7 +363,7 @@ Blockly.hideChaff = function(opt_allowToolbox) { * @return {!Blockly.Workspace} The main workspace. */ Blockly.getMainWorkspace = function() { - return Blockly.mainWorkspace; + return /** @type {!Blockly.Workspace} */ (Blockly.mainWorkspace); }; /** @@ -396,7 +396,7 @@ Blockly.confirm = function(message, callback) { * recommend testing mobile when overriding this. * @param {string} message The message to display to the user. * @param {string} defaultValue The value to initialize the prompt with. - * @param {!function(string)} callback The callback for handling user response. + * @param {!function(?string)} callback The callback for handling user response. */ Blockly.prompt = function(message, defaultValue, callback) { callback(prompt(message, defaultValue)); diff --git a/core/contextmenu.js b/core/contextmenu.js index 10330e9ff..48aa337ea 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -279,7 +279,7 @@ Blockly.ContextMenu.blockCommentOption = function(block) { enabled: !Blockly.utils.userAgent.IE }; // If there's already a comment, add an option to delete it. - if (block.comment) { + if (block.getCommentIcon()) { commentOption.text = Blockly.Msg['REMOVE_COMMENT']; commentOption.callback = function() { block.setCommentText(null); diff --git a/core/events.js b/core/events.js index f52a838c2..d58771afa 100644 --- a/core/events.js +++ b/core/events.js @@ -391,7 +391,7 @@ Blockly.Events.fromJson = function(json, workspace) { event = new Blockly.Events.CommentDelete(null); break; case Blockly.Events.FINISHED_LOADING: - event = new Blockly.Events.FinishedLoading(null); + event = new Blockly.Events.FinishedLoading(workspace); break; default: throw Error('Unknown event type.'); diff --git a/core/extensions.js b/core/extensions.js index 3f43a3ca8..c410bb3e9 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -87,7 +87,7 @@ Blockly.Extensions.registerMixin = function(name, mixinObj) { * @param {!Object} mixinObj The values to mix in. * @param {(function())=} opt_helperFn An optional function to apply after * mixing in the object. - * @param {Array.=} opt_blockList A list of blocks to appear in the + * @param {!Array.=} opt_blockList A list of blocks to appear in the * flyout of the mutator dialog. * @throws {Error} if the mutation is invalid or can't be applied to the block. */ @@ -114,7 +114,7 @@ Blockly.Extensions.registerMutator = function(name, mixinObj, opt_helperFn, if (!Blockly.Mutator) { throw Error(errorPrefix + 'Missing require for Blockly.Mutator'); } - this.setMutator(new Blockly.Mutator(opt_blockList)); + this.setMutator(new Blockly.Mutator(opt_blockList || [])); } // Mixin the object. this.mixin(mixinObj); @@ -165,7 +165,8 @@ Blockly.Extensions.apply = function(name, block, isMutator) { var errorPrefix = 'Error after applying mutator "' + name + '": '; Blockly.Extensions.checkBlockHasMutatorProperties_(errorPrefix, block); } else { - if (!Blockly.Extensions.mutatorPropertiesMatch_(mutatorProperties, block)) { + if (!Blockly.Extensions.mutatorPropertiesMatch_( + /** @type {!Array.} */ (mutatorProperties), block)) { throw Error('Error when applying extension "' + name + '": ' + 'mutation properties changed when applying a non-mutator extension.'); } @@ -359,7 +360,7 @@ Blockly.Extensions.buildTooltipForDropdown = function(dropdownName, } this.setTooltip(function() { - var value = this.getFieldValue(dropdownName); + var value = String(this.getFieldValue(dropdownName)); var tooltip = lookupTable[value]; if (tooltip == null) { if (blockTypesChecked.indexOf(this.type) == -1) { diff --git a/core/grid.js b/core/grid.js index 3b036f493..72367c10b 100644 --- a/core/grid.js +++ b/core/grid.js @@ -64,14 +64,15 @@ Blockly.Grid = function(pattern, options) { * @type {SVGElement} * @private */ - this.line1_ = pattern.firstChild; + this.line1_ = /** @type {SVGElement} */ (pattern.firstChild); /** * The vertical grid line, if it exists. * @type {SVGElement} * @private */ - this.line2_ = this.line1_ && this.line1_.nextSibling; + this.line2_ = this.line1_ && + (/** @type {SVGElement} */ (this.line1_.nextSibling)); /** * Whether blocks should snap to the grid. @@ -154,7 +155,7 @@ Blockly.Grid.prototype.update = function(scale) { /** * Set the attributes on one of the lines in the grid. Use this to update the * length and stroke width of the grid lines. - * @param {!SVGElement} line Which line to update. + * @param {SVGElement} line Which line to update. * @param {number} width The new stroke size (in px). * @param {number} x1 The new x start position of the line (in px). * @param {number} x2 The new x end position of the line (in px). diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index ed74df6a7..2721b8c4e 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -293,7 +293,7 @@ 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(input); + 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; @@ -347,7 +347,8 @@ 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(parentInput); + 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--) { if (input.connection && input !== parentInput) { diff --git a/core/workspace.js b/core/workspace.js index 59a5e845a..2119c8d17 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -109,7 +109,7 @@ Blockly.Workspace = function(opt_options) { * A FieldVariable must always refer to a Blockly.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 {Blockly.VariableMap} * @private */ this.potentialVariableMap_ = null; @@ -246,9 +246,11 @@ Blockly.Workspace.prototype.refreshTheme = function() { Blockly.Workspace.prototype.updateBlockStyles_ = function(blocks) { for (var i = 0, block; block = blocks[i]; i++) { var blockStyleName = block.getStyleName(); - block.setStyle(blockStyleName); - if (block.mutator) { - block.mutator.updateBlockStyle(blockStyleName); + if (blockStyleName) { + block.setStyle(blockStyleName); + if (block.mutator) { + block.mutator.updateBlockStyle(); + } } } }; @@ -861,7 +863,7 @@ Blockly.Workspace.prototype.createPotentialVariableMap = function() { /** * Return the map of all variables on the workspace. - * @return {Blockly.VariableMap} The variable map. + * @return {!Blockly.VariableMap} The variable map. */ Blockly.Workspace.prototype.getVariableMap = function() { return this.variableMap_; @@ -869,7 +871,7 @@ Blockly.Workspace.prototype.getVariableMap = function() { /** * Set the map of all variables on the workspace. - * @param {Blockly.VariableMap} variableMap The variable map. + * @param {!Blockly.VariableMap} variableMap The variable map. * @package */ Blockly.Workspace.prototype.setVariableMap = function(variableMap) { diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 256cd5166..1c24f742b 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -48,7 +48,6 @@ Blockly.WorkspaceAudio = function(parentWorkspace) { /** * Database of pre-loaded sounds. * @private - * @const */ this.SOUNDS_ = Object.create(null); }; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index aee610986..8c676431a 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -531,7 +531,7 @@ Blockly.WorkspaceSvg.prototype.isVisible = function() { * Return the absolute coordinates of the top-left corner of this element, * 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 {!Element} element Element to find the coordinates of. + * @param {!SVGElement} element SVG element to find the coordinates of. * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. * @package */ @@ -554,7 +554,7 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { } x += xy.x * scale; y += xy.y * scale; - element = /** @type {!Element} */ (element.parentNode); + element = /** @type {!SVGElement} */ (element.parentNode); } while (element && element != this.getParentSvg()); return new Blockly.utils.Coordinate(x, y); }; @@ -1335,7 +1335,7 @@ 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 {!Blockly.VariableModel} The newly created variable. * @package */ Blockly.WorkspaceSvg.prototype.createVariable = function(name, @@ -1420,7 +1420,8 @@ Blockly.WorkspaceSvg.prototype.moveDrag = function(e) { // Fix scale of mouse event. point.x /= this.scale; point.y /= this.scale; - return Blockly.utils.Coordinate.sum(this.dragDeltaXY_, point); + return Blockly.utils.Coordinate.sum( + /** @type {!Blockly.utils.Coordinate} */ (this.dragDeltaXY_), point); }; /** From 3b25c514c266f68f6d5b3d34b96a0b0f7fcfc2df Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Fri, 25 Oct 2019 19:14:26 -0400 Subject: [PATCH 109/343] Fix warnings related to icons and bubbles (#3308) * Fix warnings related to bubbles. --- core/bubble.js | 6 +++--- core/comment.js | 7 ++++--- core/icon.js | 4 ++-- core/mutator.js | 10 +++++++--- core/warning.js | 5 +++-- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/core/bubble.js b/core/bubble.js index 388e7ceb8..0ec5ad9c6 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -328,7 +328,7 @@ Blockly.Bubble.prototype.isDeletable = function() { * @private */ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { - this.promote_(); + this.promote(); Blockly.Bubble.unbindDragEvents_(); if (Blockly.utils.isRightButton(e)) { // No right-click. @@ -374,9 +374,9 @@ Blockly.Bubble.prototype.registerResizeEvent = function(callback) { /** * Move this bubble to the top of the stack. * @return {boolean} Whether or not the bubble has been moved. - * @private + * @package */ -Blockly.Bubble.prototype.promote_ = function() { +Blockly.Bubble.prototype.promote = function() { var svgGroup = this.bubbleGroup_.parentNode; if (svgGroup.lastChild !== this.bubbleGroup_) { svgGroup.appendChild(this.bubbleGroup_); diff --git a/core/comment.js b/core/comment.js index 803e1459c..31f3942bc 100644 --- a/core/comment.js +++ b/core/comment.js @@ -241,8 +241,9 @@ Blockly.Comment.prototype.createBubble_ = function() { Blockly.Comment.prototype.createEditableBubble_ = function() { this.bubble_ = new Blockly.Bubble( /** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace), - this.createEditor_(), this.block_.svgPath_, - this.iconXY_, this.model_.size.width, this.model_.size.height); + this.createEditor_(), this.block_.pathObject.svgPath, + /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_), + this.model_.size.width, this.model_.size.height); // Expose this comment's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); this.bubble_.registerResizeEvent(this.onBubbleResize_.bind(this)); @@ -286,7 +287,7 @@ Blockly.Comment.prototype.disposeBubble_ = function() { * @private */ Blockly.Comment.prototype.startEdit_ = function(_e) { - if (this.bubble_.promote_()) { + if (this.bubble_.promote()) { // Since the act of moving this node within the DOM causes a loss of focus, // we need to reapply the focus. this.textarea_.focus(); diff --git a/core/icon.js b/core/icon.js index cd76e888c..bf2c9043a 100644 --- a/core/icon.js +++ b/core/icon.js @@ -174,8 +174,8 @@ Blockly.Icon.prototype.computeIconLocation = function() { /** * Returns the center of the block's icon relative to the surface. - * @return {!Blockly.utils.Coordinate} Object with x and y properties in workspace - * coordinates. + * @return {Blockly.utils.Coordinate} Object with x and y properties in + * workspace coordinates. */ Blockly.Icon.prototype.getIconLocation = function() { return this.iconXY_; diff --git a/core/mutator.js b/core/mutator.js index af5d9e0b9..649e1fe5e 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -257,7 +257,8 @@ Blockly.Mutator.prototype.setVisible = function(visible) { // Create the bubble. this.bubble_ = new Blockly.Bubble( /** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace), - this.createEditor_(), this.block_.svgPath_, this.iconXY_, null, null); + this.createEditor_(), this.block_.pathObject.svgPath, + /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_), null, null); // Expose this mutator's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); var tree = this.workspace_.options.languageTree; @@ -289,9 +290,12 @@ Blockly.Mutator.prototype.setVisible = function(visible) { // Save the initial connections, then listen for further changes. if (this.block_.saveConnections) { var thisMutator = this; - this.block_.saveConnections(this.rootBlock_); + var mutatorBlock = + /** @type {{saveConnections: function(!Blockly.Block)}} */ ( + this.block_); + mutatorBlock.saveConnections(this.rootBlock_); this.sourceListener_ = function() { - thisMutator.block_.saveConnections(thisMutator.rootBlock_); + mutatorBlock.saveConnections(thisMutator.rootBlock_); }; this.block_.workspace.addChangeListener(this.sourceListener_); } diff --git a/core/warning.js b/core/warning.js index e6d3dcc71..fe9f8c4f7 100644 --- a/core/warning.js +++ b/core/warning.js @@ -134,7 +134,8 @@ Blockly.Warning.prototype.createBubble = function() { this.paragraphElement_ = Blockly.Warning.textToDom_(this.getText()); this.bubble_ = new Blockly.Bubble( /** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace), - this.paragraphElement_, this.block_.svgPath_, this.iconXY_, null, null); + this.paragraphElement_, this.block_.pathObject.svgPath, + /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_), null, null); // Expose this warning's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); if (this.block_.RTL) { @@ -171,7 +172,7 @@ Blockly.Warning.prototype.disposeBubble = function() { */ Blockly.Warning.prototype.bodyFocus_ = function(_e) { - this.bubble_.promote_(); + this.bubble_.promote(); }; /** From 7e82d0d2019fca427d646abf3d280eba1030efe6 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Fri, 25 Oct 2019 19:15:27 -0400 Subject: [PATCH 110/343] Remove @deprecated annotation on Blockly.bindEvent_ (#3333) --- core/blockly.js | 5 ++--- core/components/tree/treecontrol.js | 1 - core/flyout_base.js | 1 - core/inject.js | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index 11513dddc..e220741b8 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -522,9 +522,8 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, /** * Bind an event to a function call. Handles multitouch events by using the * coordinates of the first changed touch, and doesn't do any safety checks for - * simultaneous event processing. - * @deprecated in favor of bindEventWithChecks_, but preserved for external - * users. + * simultaneous event processing. In most cases prefer is to use + * `Blockly.bindEventWithChecks_`. * @param {!EventTarget} node Node upon which to listen. * @param {string} name Event name to listen to (e.g. 'mousedown'). * @param {Object} thisObject The value of 'this' in the function. diff --git a/core/components/tree/treecontrol.js b/core/components/tree/treecontrol.js index 7e9a58659..a498b6938 100644 --- a/core/components/tree/treecontrol.js +++ b/core/components/tree/treecontrol.js @@ -263,7 +263,6 @@ Blockly.tree.TreeControl.prototype.exitDocument = function() { /** * Adds the event listeners to the tree. * @private - * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.tree.TreeControl.prototype.attachEvents_ = function() { var el = this.getElement(); diff --git a/core/flyout_base.js b/core/flyout_base.js index 61202150e..90ad2357d 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -579,7 +579,6 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() { * @param {!SVGElement} rect The invisible rectangle under the block that acts * as a mat for that block. * @protected - * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) { this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mousedown', null, diff --git a/core/inject.js b/core/inject.js index 456a35af5..45c638627 100644 --- a/core/inject.js +++ b/core/inject.js @@ -456,7 +456,6 @@ Blockly.init_ = function(mainWorkspace) { * Also, 'keydown' has to be on the whole document since the browser doesn't * understand a concept of focus on the SVG image. * @private - * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.inject.bindDocumentEvents_ = function() { if (!Blockly.documentEventsBound_) { From 17af987de0de726528033f24a5916418b82acb54 Mon Sep 17 00:00:00 2001 From: Monica Kozbial Date: Fri, 25 Oct 2019 16:45:55 -0700 Subject: [PATCH 111/343] Adding pinch zoom config option. (#3317) * Adding pinch zoom config option. --- core/options.js | 5 ++++ core/touch_gesture.js | 67 +++++++++++++++++++++++++++---------------- core/workspace_svg.js | 16 ++++------- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/core/options.js b/core/options.js index 68884d608..6c054dd27 100644 --- a/core/options.js +++ b/core/options.js @@ -247,6 +247,11 @@ Blockly.Options.parseZoomOptions_ = function(options) { } else { zoomOptions.scaleSpeed = Number(zoom['scaleSpeed']); } + if (zoom['pinch'] === undefined) { + zoomOptions.pinch = zoomOptions.wheel || zoomOptions.controls; + } else { + zoomOptions.pinch = !!zoom['pinch']; + } return zoomOptions; }; diff --git a/core/touch_gesture.js b/core/touch_gesture.js index 20c838957..00b15d979 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -85,6 +85,14 @@ Blockly.TouchGesture = function(e, creatorWorkspace) { * @private */ this.onStartWrapper_ = null; + + /** + * Boolean for whether or not the workspace supports pinch-zoom. + * @type {boolean} + * @private + */ + this.isPinchZoomEnabled_ = this.startWorkspace_.options.zoomOptions && + this.startWorkspace_.options.zoomOptions.pinch; }; Blockly.utils.object.inherits(Blockly.TouchGesture, Blockly.Gesture); @@ -233,7 +241,7 @@ Blockly.TouchGesture.prototype.handleTouchStart = function(e) { // store the pointerId in the current list of pointers this.cachedPoints_[pointerId] = this.getTouchPoint(e); var pointers = Object.keys(this.cachedPoints_); - // If two pointers are down, check for pinch gestures + // If two pointers are down, store info if (pointers.length == 2) { var point0 = /** @type {!Blockly.utils.Coordinate} */ ( this.cachedPoints_[pointers[0]]); @@ -257,32 +265,43 @@ Blockly.TouchGesture.prototype.handleTouchMove = function(e) { this.cachedPoints_[pointerId] = this.getTouchPoint(e); var pointers = Object.keys(this.cachedPoints_); - // If two pointers are down, check for pinch gestures - if (pointers.length == 2) { - // Calculate the distance between the two pointers - var point0 = /** @type {!Blockly.utils.Coordinate} */ ( - this.cachedPoints_[pointers[0]]); - var point1 = /** @type {!Blockly.utils.Coordinate} */ ( - this.cachedPoints_[pointers[1]]); - var moveDistance = Blockly.utils.Coordinate.distance(point0, point1); - var startDistance = this.startDistance_; - var scale = this.touchScale_ = moveDistance / startDistance; - - if (this.previousScale_ > 0 && this.previousScale_ < Infinity) { - var gestureScale = scale - this.previousScale_; - var delta = gestureScale > 0 ? - gestureScale * Blockly.TouchGesture.ZOOM_IN_MULTIPLIER : - gestureScale * Blockly.TouchGesture.ZOOM_OUT_MULTIPLIER; - var workspace = this.startWorkspace_; - var position = Blockly.utils.mouseToSvg( - e, workspace.getParentSvg(), workspace.getInverseScreenCTM()); - workspace.zoom(position.x, position.y, delta); - } - this.previousScale_ = scale; - e.preventDefault(); + if (this.isPinchZoomEnabled_ && pointers.length === 2) { + this.handlePinch_(e); + } else { + Blockly.TouchGesture.superClass_.handleMove.call(this, e); } }; +/** +* Handle pinch zoom gesture. +* @param {!Event} e A touch move, or pointer move event. +* @private +*/ +Blockly.TouchGesture.prototype.handlePinch_ = function(e) { + var pointers = Object.keys(this.cachedPoints_); + // Calculate the distance between the two pointers + var point0 = /** @type {!Blockly.utils.Coordinate} */ ( + this.cachedPoints_[pointers[0]]); + var point1 = /** @type {!Blockly.utils.Coordinate} */ ( + this.cachedPoints_[pointers[1]]); + var moveDistance = Blockly.utils.Coordinate.distance(point0, point1); + var scale = moveDistance / this.startDistance_; + + if (this.previousScale_ > 0 && this.previousScale_ < Infinity) { + var gestureScale = scale - this.previousScale_; + var delta = gestureScale > 0 ? + gestureScale * Blockly.TouchGesture.ZOOM_IN_MULTIPLIER : + gestureScale * Blockly.TouchGesture.ZOOM_OUT_MULTIPLIER; + var workspace = this.startWorkspace_; + var position = Blockly.utils.mouseToSvg( + e, workspace.getParentSvg(), workspace.getInverseScreenCTM()); + workspace.zoom(position.x, position.y, delta); + } + this.previousScale_ = this.touchScale_; + e.preventDefault(); +}; + + /** * Handle a touch end or pointer end event and end the gesture. * @param {!Event} e A touch end, or pointer end event. diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 8c676431a..a79cc05bf 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1452,7 +1452,8 @@ Blockly.WorkspaceSvg.prototype.isContentBounded = function() { (this.options.moveOptions && this.options.moveOptions.wheel) || (this.options.moveOptions && this.options.moveOptions.drag) || (this.options.zoomOptions && this.options.zoomOptions.controls) || - (this.options.zoomOptions && this.options.zoomOptions.wheel); + (this.options.zoomOptions && this.options.zoomOptions.wheel) || + (this.options.zoomOptions && this.options.zoomOptions.pinch); }; /** @@ -1460,8 +1461,8 @@ Blockly.WorkspaceSvg.prototype.isContentBounded = function() { * * This means the user can reposition the X Y coordinates of the workspace * through input. This can be through scrollbars, scroll wheel, dragging, or - * through zooming with the scroll wheel (since the zoom is centered on the - * mouse position). This does not include zooming with the zoom controls + * through zooming with the scroll wheel or pinch (since the zoom is centered on + * the mouse position). This does not include zooming with the zoom controls * since the X Y coordinates are decided programmatically. * @return {boolean} True if the workspace is movable, false otherwise. * @package @@ -1470,7 +1471,8 @@ Blockly.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) || - (this.options.zoomOptions && this.options.zoomOptions.wheel); + (this.options.zoomOptions && this.options.zoomOptions.wheel) || + (this.options.zoomOptions && this.options.zoomOptions.pinch); }; /** @@ -1813,12 +1815,6 @@ Blockly.WorkspaceSvg.prototype.setBrowserFocus = function() { * amount values zoom in. */ Blockly.WorkspaceSvg.prototype.zoom = function(x, y, amount) { - // TODO (#2782): Consider removing once pinch understands zoom configuration - // Mutators and flyouts don't support zooming, and pinch doesn't understand - // that. - if (this.isFlyout || this.isMutator) { - return; - } // Scale factor. var speed = this.options.zoomOptions.scaleSpeed; var scaleChange = Math.pow(speed, amount); From fa5f256a3f30d42d847eb9641bc4ee0a5d775aef Mon Sep 17 00:00:00 2001 From: zochris <20927697+zochris@users.noreply.github.com> Date: Mon, 28 Oct 2019 17:26:27 +0100 Subject: [PATCH 112/343] Fix 'add test variable' button not working (#3346) --- tests/playground.html | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/playground.html b/tests/playground.html index 931431a26..d9969cc1b 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -241,7 +241,6 @@ function addToolboxButtonCallbacks() { } }; var addVariables = function(button) { - workspace.createVariable('1a', '', '1A'); workspace.createVariable('1b', '', '1B'); workspace.createVariable('1c', '', '1C'); workspace.createVariable('2a', '', '2A'); From 64c52efb5ba52f91c566cd53132efc8cd40b5c24 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 28 Oct 2019 09:35:40 -0700 Subject: [PATCH 113/343] Resolve warnings in generator code (#3350) --- generators/dart.js | 4 ++-- generators/dart/lists.js | 10 +++++----- generators/dart/loops.js | 14 +++++++------- generators/dart/math.js | 2 +- generators/dart/procedures.js | 2 +- generators/dart/text.js | 2 +- generators/dart/variables.js | 4 ++-- generators/javascript.js | 4 ++-- generators/javascript/lists.js | 4 ++-- generators/javascript/loops.js | 18 +++++++++--------- generators/javascript/math.js | 2 +- generators/javascript/procedures.js | 2 +- generators/javascript/text.js | 2 +- generators/javascript/variables.js | 4 ++-- generators/lua/lists.js | 4 ++-- generators/lua/loops.js | 8 ++++---- generators/lua/math.js | 2 +- generators/lua/procedures.js | 2 +- generators/lua/text.js | 2 +- generators/lua/variables.js | 4 ++-- generators/php.js | 4 ++-- generators/php/lists.js | 4 ++-- generators/php/loops.js | 14 +++++++------- generators/php/math.js | 2 +- generators/php/procedures.js | 4 ++-- generators/php/text.js | 2 +- generators/php/variables.js | 4 ++-- generators/python.js | 5 +++-- generators/python/lists.js | 4 ++-- generators/python/loops.js | 8 ++++---- generators/python/math.js | 2 +- generators/python/procedures.js | 4 ++-- generators/python/text.js | 4 ++-- generators/python/variables.js | 4 ++-- 34 files changed, 81 insertions(+), 80 deletions(-) diff --git a/generators/dart.js b/generators/dart.js index c5eadde41..444709d91 100644 --- a/generators/dart.js +++ b/generators/dart.js @@ -114,7 +114,7 @@ Blockly.Dart.init = function(workspace) { var variables = Blockly.Variables.allUsedVarModels(workspace); for (var i = 0; i < variables.length; i++) { defvars.push(Blockly.Dart.variableDB_.getName(variables[i].getId(), - Blockly.Variables.NAME_TYPE)); + Blockly.VARIABLE_CATEGORY_NAME)); } // Declare all of the variables. @@ -226,7 +226,7 @@ Blockly.Dart.scrub_ = function(block, code, opt_thisOnly) { if (block.inputList[i].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[i].connection.targetBlock(); if (childBlock) { - var comment = Blockly.Dart.allNestedComments(childBlock); + comment = Blockly.Dart.allNestedComments(childBlock); if (comment) { commentCode += Blockly.Dart.prefixLines(comment, '// '); } diff --git a/generators/dart/lists.js b/generators/dart/lists.js index 19ad8871b..37f780de7 100644 --- a/generators/dart/lists.js +++ b/generators/dart/lists.js @@ -95,7 +95,7 @@ Blockly.Dart['lists_getIndex'] = function(block) { // Closure, which accesses and modifies 'list'. function cacheList() { var listVar = Blockly.Dart.variableDB_.getDistinctName( - 'tmp_list', Blockly.Variables.NAME_TYPE); + 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); var code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -112,7 +112,7 @@ Blockly.Dart['lists_getIndex'] = function(block) { // We can use multiple statements. var code = cacheList(); var xVar = Blockly.Dart.variableDB_.getDistinctName( - 'tmp_x', Blockly.Variables.NAME_TYPE); + 'tmp_x', Blockly.VARIABLE_CATEGORY_NAME); code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; code += list + '.removeAt(' + xVar + ');\n'; @@ -211,7 +211,7 @@ Blockly.Dart['lists_getIndex'] = function(block) { if (mode == 'REMOVE') { // We can use multiple statements. var xVar = Blockly.Dart.variableDB_.getDistinctName( - 'tmp_x', Blockly.Variables.NAME_TYPE); + 'tmp_x', Blockly.VARIABLE_CATEGORY_NAME); var code = 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; code += list + '.removeAt(' + xVar + ');\n'; @@ -259,7 +259,7 @@ Blockly.Dart['lists_setIndex'] = function(block) { return ''; } var listVar = Blockly.Dart.variableDB_.getDistinctName( - 'tmp_list', Blockly.Variables.NAME_TYPE); + 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); var code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -308,7 +308,7 @@ Blockly.Dart['lists_setIndex'] = function(block) { 'import \'dart:math\' as Math;'; var code = cacheList(); var xVar = Blockly.Dart.variableDB_.getDistinctName( - 'tmp_x', Blockly.Variables.NAME_TYPE); + 'tmp_x', Blockly.VARIABLE_CATEGORY_NAME); code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; if (mode == 'SET') { diff --git a/generators/dart/loops.js b/generators/dart/loops.js index 63a5dbb7c..3f362162b 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -40,11 +40,11 @@ Blockly.Dart['controls_repeat_ext'] = function(block) { branch = Blockly.Dart.addLoopTrap(branch, block); var code = ''; var loopVar = Blockly.Dart.variableDB_.getDistinctName( - 'count', Blockly.Variables.NAME_TYPE); + 'count', Blockly.VARIABLE_CATEGORY_NAME); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { var endVar = Blockly.Dart.variableDB_.getDistinctName( - 'repeat_end', Blockly.Variables.NAME_TYPE); + 'repeat_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } code += 'for (int ' + loopVar + ' = 0; ' + @@ -73,7 +73,7 @@ Blockly.Dart['controls_whileUntil'] = function(block) { Blockly.Dart['controls_for'] = function(block) { // For loop. var variable0 = Blockly.Dart.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.Dart.valueToCode(block, 'FROM', Blockly.Dart.ORDER_ASSIGNMENT) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'TO', @@ -103,19 +103,19 @@ Blockly.Dart['controls_for'] = function(block) { var startVar = argument0; if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) { var startVar = Blockly.Dart.variableDB_.getDistinctName( - variable0 + '_start', Blockly.Variables.NAME_TYPE); + variable0 + '_start', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { var endVar = Blockly.Dart.variableDB_.getDistinctName( - variable0 + '_end', Blockly.Variables.NAME_TYPE); + variable0 + '_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. var incVar = Blockly.Dart.variableDB_.getDistinctName( - variable0 + '_inc', Blockly.Variables.NAME_TYPE); + variable0 + '_inc', Blockly.VARIABLE_CATEGORY_NAME); code += 'num ' + incVar + ' = '; if (Blockly.isNumber(increment)) { code += Math.abs(increment) + ';\n'; @@ -138,7 +138,7 @@ Blockly.Dart['controls_for'] = function(block) { Blockly.Dart['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.Dart.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.Dart.valueToCode(block, 'LIST', Blockly.Dart.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.Dart.statementToCode(block, 'DO'); diff --git a/generators/dart/math.js b/generators/dart/math.js index 09b36f0e7..95645887e 100644 --- a/generators/dart/math.js +++ b/generators/dart/math.js @@ -252,7 +252,7 @@ Blockly.Dart['math_change'] = function(block) { var argument0 = Blockly.Dart.valueToCode(block, 'DELTA', Blockly.Dart.ORDER_ADDITIVE) || '0'; var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = (' + varName + ' is num ? ' + varName + ' : 0) + ' + argument0 + ';\n'; }; diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index 84fe8f759..d21fdfd81 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -61,7 +61,7 @@ Blockly.Dart['procedures_defreturn'] = function(block) { var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.Dart.variableDB_.getName(block.arguments_[i], - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); } var code = returnType + ' ' + funcName + '(' + args.join(', ') + ') {\n' + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; diff --git a/generators/dart/text.js b/generators/dart/text.js index bb8c41860..b53eddf2b 100644 --- a/generators/dart/text.js +++ b/generators/dart/text.js @@ -64,7 +64,7 @@ Blockly.Dart['text_join'] = function(block) { Blockly.Dart['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); var value = Blockly.Dart.valueToCode(block, 'TEXT', Blockly.Dart.ORDER_NONE) || '\'\''; return varName + ' = [' + varName + ', ' + value + '].join();\n'; diff --git a/generators/dart/variables.js b/generators/dart/variables.js index 5c8db1b21..dd4d7cf92 100644 --- a/generators/dart/variables.js +++ b/generators/dart/variables.js @@ -29,7 +29,7 @@ goog.require('Blockly.Dart'); Blockly.Dart['variables_get'] = function(block) { // Variable getter. var code = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return [code, Blockly.Dart.ORDER_ATOMIC]; }; @@ -38,6 +38,6 @@ Blockly.Dart['variables_set'] = function(block) { var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_ASSIGNMENT) || '0'; var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = ' + argument0 + ';\n'; }; diff --git a/generators/javascript.js b/generators/javascript.js index 29bc0373c..68cdbbd74 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -156,7 +156,7 @@ Blockly.JavaScript.init = function(workspace) { var variables = Blockly.Variables.allUsedVarModels(workspace); for (var i = 0; i < variables.length; i++) { defvars.push(Blockly.JavaScript.variableDB_.getName(variables[i].getId(), - Blockly.Variables.NAME_TYPE)); + Blockly.VARIABLE_CATEGORY_NAME)); } // Declare all of the variables. @@ -251,7 +251,7 @@ Blockly.JavaScript.scrub_ = function(block, code, opt_thisOnly) { if (block.inputList[i].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[i].connection.targetBlock(); if (childBlock) { - var comment = Blockly.JavaScript.allNestedComments(childBlock); + comment = Blockly.JavaScript.allNestedComments(childBlock); if (comment) { commentCode += Blockly.JavaScript.prefixLines(comment, '// '); } diff --git a/generators/javascript/lists.js b/generators/javascript/lists.js index 6f9e1a4b3..84e0cfea6 100644 --- a/generators/javascript/lists.js +++ b/generators/javascript/lists.js @@ -186,7 +186,7 @@ Blockly.JavaScript['lists_setIndex'] = function(block) { return ''; } var listVar = Blockly.JavaScript.variableDB_.getDistinctName( - 'tmpList', Blockly.Variables.NAME_TYPE); + 'tmpList', Blockly.VARIABLE_CATEGORY_NAME); var code = 'var ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -232,7 +232,7 @@ Blockly.JavaScript['lists_setIndex'] = function(block) { case ('RANDOM'): var code = cacheList(); var xVar = Blockly.JavaScript.variableDB_.getDistinctName( - 'tmpX', Blockly.Variables.NAME_TYPE); + 'tmpX', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + xVar + ' = Math.floor(Math.random() * ' + list + '.length);\n'; if (mode == 'SET') { diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index f408ca1e4..711d8904e 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -40,11 +40,11 @@ Blockly.JavaScript['controls_repeat_ext'] = function(block) { branch = Blockly.JavaScript.addLoopTrap(branch, block); var code = ''; var loopVar = Blockly.JavaScript.variableDB_.getDistinctName( - 'count', Blockly.Variables.NAME_TYPE); + 'count', Blockly.VARIABLE_CATEGORY_NAME); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { var endVar = Blockly.JavaScript.variableDB_.getDistinctName( - 'repeat_end', Blockly.Variables.NAME_TYPE); + 'repeat_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } code += 'for (var ' + loopVar + ' = 0; ' + @@ -74,7 +74,7 @@ Blockly.JavaScript['controls_whileUntil'] = function(block) { Blockly.JavaScript['controls_for'] = function(block) { // For loop. var variable0 = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.JavaScript.valueToCode(block, 'FROM', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'TO', @@ -104,19 +104,19 @@ Blockly.JavaScript['controls_for'] = function(block) { var startVar = argument0; if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) { startVar = Blockly.JavaScript.variableDB_.getDistinctName( - variable0 + '_start', Blockly.Variables.NAME_TYPE); + variable0 + '_start', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { var endVar = Blockly.JavaScript.variableDB_.getDistinctName( - variable0 + '_end', Blockly.Variables.NAME_TYPE); + variable0 + '_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. var incVar = Blockly.JavaScript.variableDB_.getDistinctName( - variable0 + '_inc', Blockly.Variables.NAME_TYPE); + variable0 + '_inc', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + incVar + ' = '; if (Blockly.isNumber(increment)) { code += Math.abs(increment) + ';\n'; @@ -139,7 +139,7 @@ Blockly.JavaScript['controls_for'] = function(block) { Blockly.JavaScript['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); @@ -149,11 +149,11 @@ Blockly.JavaScript['controls_forEach'] = function(block) { var listVar = argument0; if (!argument0.match(/^\w+$/)) { listVar = Blockly.JavaScript.variableDB_.getDistinctName( - variable0 + '_list', Blockly.Variables.NAME_TYPE); + variable0 + '_list', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + listVar + ' = ' + argument0 + ';\n'; } var indexVar = Blockly.JavaScript.variableDB_.getDistinctName( - variable0 + '_index', Blockly.Variables.NAME_TYPE); + variable0 + '_index', Blockly.VARIABLE_CATEGORY_NAME); branch = Blockly.JavaScript.INDENT + variable0 + ' = ' + listVar + '[' + indexVar + '];\n' + branch; code += 'for (var ' + indexVar + ' in ' + listVar + ') {\n' + branch + '}\n'; diff --git a/generators/javascript/math.js b/generators/javascript/math.js index 935c2e4f5..337a01d69 100644 --- a/generators/javascript/math.js +++ b/generators/javascript/math.js @@ -219,7 +219,7 @@ Blockly.JavaScript['math_change'] = function(block) { var argument0 = Blockly.JavaScript.valueToCode(block, 'DELTA', Blockly.JavaScript.ORDER_ADDITION) || '0'; var varName = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = (typeof ' + varName + ' == \'number\' ? ' + varName + ' : 0) + ' + argument0 + ';\n'; }; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index 262c844c7..8874fcead 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -62,7 +62,7 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.JavaScript.variableDB_.getName(block.arguments_[i], - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); } var code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; diff --git a/generators/javascript/text.js b/generators/javascript/text.js index 4e89b9591..8b1c162c5 100644 --- a/generators/javascript/text.js +++ b/generators/javascript/text.js @@ -92,7 +92,7 @@ Blockly.JavaScript['text_join'] = function(block) { Blockly.JavaScript['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var value = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_NONE) || '\'\''; return varName + ' += ' + Blockly.JavaScript.text.forceString_(value) + ';\n'; diff --git a/generators/javascript/variables.js b/generators/javascript/variables.js index 99c63e448..df596cc29 100644 --- a/generators/javascript/variables.js +++ b/generators/javascript/variables.js @@ -29,7 +29,7 @@ goog.require('Blockly.JavaScript'); Blockly.JavaScript['variables_get'] = function(block) { // Variable getter. var code = Blockly.JavaScript.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; @@ -38,6 +38,6 @@ Blockly.JavaScript['variables_set'] = function(block) { var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; var varName = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = ' + argument0 + ';\n'; }; diff --git a/generators/lua/lists.js b/generators/lua/lists.js index 93bc1b090..24dbf2c76 100644 --- a/generators/lua/lists.js +++ b/generators/lua/lists.js @@ -151,7 +151,7 @@ Blockly.Lua['lists_getIndex'] = function(block) { Blockly.Lua.ORDER_NONE; var at = Blockly.Lua.valueToCode(block, 'AT', atOrder) || '1'; var listVar = Blockly.Lua.variableDB_.getDistinctName( - 'tmp_list', Blockly.Variables.NAME_TYPE); + 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); at = getIndex_(listVar, where, at); var code = listVar + ' = ' + list + '\n' + 'table.remove(' + listVar + ', ' + at + ')\n'; @@ -230,7 +230,7 @@ Blockly.Lua['lists_setIndex'] = function(block) { // `list` is an expression, so we may not evaluate it more than once. // We can use multiple statements. var listVar = Blockly.Lua.variableDB_.getDistinctName( - 'tmp_list', Blockly.Variables.NAME_TYPE); + 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); code = listVar + ' = ' + list + '\n'; list = listVar; } diff --git a/generators/lua/loops.js b/generators/lua/loops.js index 58edb130b..063aa2ba0 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.js @@ -72,7 +72,7 @@ Blockly.Lua['controls_repeat_ext'] = function(block) { branch = Blockly.Lua.addLoopTrap(branch, block); branch = Blockly.Lua.addContinueLabel_(branch); var loopVar = Blockly.Lua.variableDB_.getDistinctName( - 'count', Blockly.Variables.NAME_TYPE); + 'count', Blockly.VARIABLE_CATEGORY_NAME); var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n'; return code; @@ -98,7 +98,7 @@ Blockly.Lua['controls_whileUntil'] = function(block) { Blockly.Lua['controls_for'] = function(block) { // For loop. var variable0 = Blockly.Lua.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var startVar = Blockly.Lua.valueToCode(block, 'FROM', Blockly.Lua.ORDER_NONE) || '0'; var endVar = Blockly.Lua.valueToCode(block, 'TO', @@ -121,7 +121,7 @@ Blockly.Lua['controls_for'] = function(block) { // Determine loop direction at start, in case one of the bounds // changes during loop execution. incValue = Blockly.Lua.variableDB_.getDistinctName( - variable0 + '_inc', Blockly.Variables.NAME_TYPE); + variable0 + '_inc', Blockly.VARIABLE_CATEGORY_NAME); code += incValue + ' = '; if (Blockly.isNumber(increment)) { code += Math.abs(increment) + '\n'; @@ -141,7 +141,7 @@ Blockly.Lua['controls_for'] = function(block) { Blockly.Lua['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.Lua.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.Lua.valueToCode(block, 'LIST', Blockly.Lua.ORDER_NONE) || '{}'; var branch = Blockly.Lua.statementToCode(block, 'DO'); diff --git a/generators/lua/math.js b/generators/lua/math.js index 47332a88b..a61f3185b 100644 --- a/generators/lua/math.js +++ b/generators/lua/math.js @@ -208,7 +208,7 @@ Blockly.Lua['math_change'] = function(block) { var argument0 = Blockly.Lua.valueToCode(block, 'DELTA', Blockly.Lua.ORDER_ADDITIVE) || '0'; var varName = Blockly.Lua.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = ' + varName + ' + ' + argument0 + '\n'; }; diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index d838130c7..fd7b3b311 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -62,7 +62,7 @@ Blockly.Lua['procedures_defreturn'] = function(block) { var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.Lua.variableDB_.getName(block.arguments_[i], - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); } var code = 'function ' + funcName + '(' + args.join(', ') + ')\n' + xfix1 + loopTrap + branch + xfix2 + returnValue + 'end\n'; diff --git a/generators/lua/text.js b/generators/lua/text.js index 2c6bdb2e5..cb74d7cbb 100644 --- a/generators/lua/text.js +++ b/generators/lua/text.js @@ -68,7 +68,7 @@ Blockly.Lua['text_join'] = function(block) { Blockly.Lua['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.Lua.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var value = Blockly.Lua.valueToCode(block, 'TEXT', Blockly.Lua.ORDER_CONCATENATION) || '\'\''; return varName + ' = ' + varName + ' .. ' + value + '\n'; diff --git a/generators/lua/variables.js b/generators/lua/variables.js index f08fc3621..3cb2d1888 100644 --- a/generators/lua/variables.js +++ b/generators/lua/variables.js @@ -29,7 +29,7 @@ goog.require('Blockly.Lua'); Blockly.Lua['variables_get'] = function(block) { // Variable getter. var code = Blockly.Lua.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return [code, Blockly.Lua.ORDER_ATOMIC]; }; @@ -38,6 +38,6 @@ Blockly.Lua['variables_set'] = function(block) { var argument0 = Blockly.Lua.valueToCode(block, 'VALUE', Blockly.Lua.ORDER_NONE) || '0'; var varName = Blockly.Lua.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = ' + argument0 + '\n'; }; diff --git a/generators/php.js b/generators/php.js index 702eb7790..5c4ebcd3f 100644 --- a/generators/php.js +++ b/generators/php.js @@ -161,7 +161,7 @@ Blockly.PHP.init = function(workspace) { var variables = Blockly.Variables.allUsedVarModels(workspace); for (var i = 0, variable; variable = variables[i]; i++) { defvars.push(Blockly.PHP.variableDB_.getName(variable.getId(), - Blockly.Variables.NAME_TYPE) + ';'); + Blockly.VARIABLE_CATEGORY_NAME) + ';'); } // Declare all of the variables. @@ -248,7 +248,7 @@ Blockly.PHP.scrub_ = function(block, code, opt_thisOnly) { if (block.inputList[i].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[i].connection.targetBlock(); if (childBlock) { - var comment = Blockly.PHP.allNestedComments(childBlock); + comment = Blockly.PHP.allNestedComments(childBlock); if (comment) { commentCode += Blockly.PHP.prefixLines(comment, '// '); } diff --git a/generators/php/lists.js b/generators/php/lists.js index a1d90b59f..1facc35f5 100644 --- a/generators/php/lists.js +++ b/generators/php/lists.js @@ -269,7 +269,7 @@ Blockly.PHP['lists_setIndex'] = function(block) { return ''; } var listVar = Blockly.PHP.variableDB_.getDistinctName( - 'tmp_list', Blockly.Variables.NAME_TYPE); + 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); var code = listVar + ' = &' + list + ';\n'; list = listVar; return code; @@ -340,7 +340,7 @@ Blockly.PHP['lists_setIndex'] = function(block) { Blockly.PHP.ORDER_REFERENCE) || 'array()'; var code = cacheList(); var xVar = Blockly.PHP.variableDB_.getDistinctName( - 'tmp_x', Blockly.Variables.NAME_TYPE); + 'tmp_x', Blockly.VARIABLE_CATEGORY_NAME); code += xVar + ' = rand(0, count(' + list + ')-1);\n'; if (mode == 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; diff --git a/generators/php/loops.js b/generators/php/loops.js index f87a80813..bbd2c6695 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -40,11 +40,11 @@ Blockly.PHP['controls_repeat_ext'] = function(block) { branch = Blockly.PHP.addLoopTrap(branch, block); var code = ''; var loopVar = Blockly.PHP.variableDB_.getDistinctName( - 'count', Blockly.Variables.NAME_TYPE); + 'count', Blockly.VARIABLE_CATEGORY_NAME); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { var endVar = Blockly.PHP.variableDB_.getDistinctName( - 'repeat_end', Blockly.Variables.NAME_TYPE); + 'repeat_end', Blockly.VARIABLE_CATEGORY_NAME); code += endVar + ' = ' + repeats + ';\n'; } code += 'for (' + loopVar + ' = 0; ' + @@ -73,7 +73,7 @@ Blockly.PHP['controls_whileUntil'] = function(block) { Blockly.PHP['controls_for'] = function(block) { // For loop. var variable0 = Blockly.PHP.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.PHP.valueToCode(block, 'FROM', Blockly.PHP.ORDER_ASSIGNMENT) || '0'; var argument1 = Blockly.PHP.valueToCode(block, 'TO', @@ -103,19 +103,19 @@ Blockly.PHP['controls_for'] = function(block) { var startVar = argument0; if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) { startVar = Blockly.PHP.variableDB_.getDistinctName( - variable0 + '_start', Blockly.Variables.NAME_TYPE); + variable0 + '_start', Blockly.VARIABLE_CATEGORY_NAME); code += startVar + ' = ' + argument0 + ';\n'; } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { var endVar = Blockly.PHP.variableDB_.getDistinctName( - variable0 + '_end', Blockly.Variables.NAME_TYPE); + variable0 + '_end', Blockly.VARIABLE_CATEGORY_NAME); code += endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. var incVar = Blockly.PHP.variableDB_.getDistinctName( - variable0 + '_inc', Blockly.Variables.NAME_TYPE); + variable0 + '_inc', Blockly.VARIABLE_CATEGORY_NAME); code += incVar + ' = '; if (Blockly.isNumber(increment)) { code += Math.abs(increment) + ';\n'; @@ -138,7 +138,7 @@ Blockly.PHP['controls_for'] = function(block) { Blockly.PHP['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.PHP.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.PHP.valueToCode(block, 'LIST', Blockly.PHP.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.PHP.statementToCode(block, 'DO'); diff --git a/generators/php/math.js b/generators/php/math.js index e9b637b73..a0b36c88e 100644 --- a/generators/php/math.js +++ b/generators/php/math.js @@ -217,7 +217,7 @@ Blockly.PHP['math_change'] = function(block) { var argument0 = Blockly.PHP.valueToCode(block, 'DELTA', Blockly.PHP.ORDER_ADDITION) || '0'; var varName = Blockly.PHP.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); return varName + ' += ' + argument0 + ';\n'; }; diff --git a/generators/php/procedures.js b/generators/php/procedures.js index c4b216201..be811c6df 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -37,7 +37,7 @@ Blockly.PHP['procedures_defreturn'] = function(block) { varName = variable.name; if (block.arguments_.indexOf(varName) == -1) { globals.push(Blockly.PHP.variableDB_.getName(varName, - Blockly.Variables.NAME_TYPE)); + Blockly.VARIABLE_CATEGORY_NAME)); } } // Add developer variables. @@ -81,7 +81,7 @@ Blockly.PHP['procedures_defreturn'] = function(block) { var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.PHP.variableDB_.getName(block.arguments_[i], - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); } var code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + globals + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; diff --git a/generators/php/text.js b/generators/php/text.js index a3eb618d2..a9d08137e 100644 --- a/generators/php/text.js +++ b/generators/php/text.js @@ -68,7 +68,7 @@ Blockly.PHP['text_join'] = function(block) { Blockly.PHP['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.PHP.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var value = Blockly.PHP.valueToCode(block, 'TEXT', Blockly.PHP.ORDER_ASSIGNMENT) || '\'\''; return varName + ' .= ' + value + ';\n'; diff --git a/generators/php/variables.js b/generators/php/variables.js index 61b162edb..5be864eea 100644 --- a/generators/php/variables.js +++ b/generators/php/variables.js @@ -29,7 +29,7 @@ goog.require('Blockly.PHP'); Blockly.PHP['variables_get'] = function(block) { // Variable getter. var code = Blockly.PHP.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return [code, Blockly.PHP.ORDER_ATOMIC]; }; @@ -38,6 +38,6 @@ Blockly.PHP['variables_set'] = function(block) { var argument0 = Blockly.PHP.valueToCode(block, 'VALUE', Blockly.PHP.ORDER_ASSIGNMENT) || '0'; var varName = Blockly.PHP.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = ' + argument0 + ';\n'; }; diff --git a/generators/python.js b/generators/python.js index 544cd29a2..829101490 100644 --- a/generators/python.js +++ b/generators/python.js @@ -139,6 +139,7 @@ Blockly.Python.ORDER_OVERRIDES = [ /** * Initialise the database of variable names. * @param {!Blockly.Workspace} workspace Workspace to generate code from. + * @this {Blockly.Generator} */ Blockly.Python.init = function(workspace) { /** @@ -172,7 +173,7 @@ Blockly.Python.init = function(workspace) { var variables = Blockly.Variables.allUsedVarModels(workspace); for (var i = 0; i < variables.length; i++) { defvars.push(Blockly.Python.variableDB_.getName(variables[i].getId(), - Blockly.Variables.NAME_TYPE) + ' = None'); + Blockly.VARIABLE_CATEGORY_NAME) + ' = None'); } Blockly.Python.definitions_['variables'] = defvars.join('\n'); @@ -276,7 +277,7 @@ Blockly.Python.scrub_ = function(block, code, opt_thisOnly) { if (block.inputList[i].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[i].connection.targetBlock(); if (childBlock) { - var comment = Blockly.Python.allNestedComments(childBlock); + comment = Blockly.Python.allNestedComments(childBlock); if (comment) { commentCode += Blockly.Python.prefixLines(comment, '# '); } diff --git a/generators/python/lists.js b/generators/python/lists.js index a31ec2769..3321880c0 100644 --- a/generators/python/lists.js +++ b/generators/python/lists.js @@ -199,7 +199,7 @@ Blockly.Python['lists_setIndex'] = function(block) { return ''; } var listVar = Blockly.Python.variableDB_.getDistinctName( - 'tmp_list', Blockly.Variables.NAME_TYPE); + 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); var code = listVar + ' = ' + list + '\n'; list = listVar; return code; @@ -240,7 +240,7 @@ Blockly.Python['lists_setIndex'] = function(block) { Blockly.Python.definitions_['import_random'] = 'import random'; var code = cacheList(); var xVar = Blockly.Python.variableDB_.getDistinctName( - 'tmp_x', Blockly.Variables.NAME_TYPE); + 'tmp_x', Blockly.VARIABLE_CATEGORY_NAME); code += xVar + ' = int(random.random() * len(' + list + '))\n'; if (mode == 'SET') { code += list + '[' + xVar + '] = ' + value + '\n'; diff --git a/generators/python/loops.js b/generators/python/loops.js index 21a32c4f8..71a7f304b 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -44,7 +44,7 @@ Blockly.Python['controls_repeat_ext'] = function(block) { var branch = Blockly.Python.statementToCode(block, 'DO'); branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; var loopVar = Blockly.Python.variableDB_.getDistinctName( - 'count', Blockly.Variables.NAME_TYPE); + 'count', Blockly.VARIABLE_CATEGORY_NAME); var code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; return code; }; @@ -68,7 +68,7 @@ Blockly.Python['controls_whileUntil'] = function(block) { Blockly.Python['controls_for'] = function(block) { // For loop. var variable0 = Blockly.Python.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.Python.valueToCode(block, 'FROM', Blockly.Python.ORDER_NONE) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'TO', @@ -155,7 +155,7 @@ Blockly.Python['controls_for'] = function(block) { } else { // It's complicated. var varName = Blockly.Python.variableDB_.getDistinctName( - variable0 + suffix, Blockly.Variables.NAME_TYPE); + variable0 + suffix, Blockly.VARIABLE_CATEGORY_NAME); code += varName + ' = float(' + arg + ')\n'; arg = varName; } @@ -183,7 +183,7 @@ Blockly.Python['controls_for'] = function(block) { Blockly.Python['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.Python.variableDB_.getName( - block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); var argument0 = Blockly.Python.valueToCode(block, 'LIST', Blockly.Python.ORDER_RELATIONAL) || '[]'; var branch = Blockly.Python.statementToCode(block, 'DO'); diff --git a/generators/python/math.js b/generators/python/math.js index 71fd50e6f..bc7b379ec 100644 --- a/generators/python/math.js +++ b/generators/python/math.js @@ -238,7 +238,7 @@ Blockly.Python['math_change'] = function(block) { var argument0 = Blockly.Python.valueToCode(block, 'DELTA', Blockly.Python.ORDER_ADDITIVE) || '0'; var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = (' + varName + ' if isinstance(' + varName + ', Number) else 0) + ' + argument0 + '\n'; }; diff --git a/generators/python/procedures.js b/generators/python/procedures.js index ee4152b38..d69fae692 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -38,7 +38,7 @@ Blockly.Python['procedures_defreturn'] = function(block) { varName = variable.name; if (block.arguments_.indexOf(varName) == -1) { globals.push(Blockly.Python.variableDB_.getName(varName, - Blockly.Variables.NAME_TYPE)); + Blockly.VARIABLE_CATEGORY_NAME)); } } // Add developer variables. @@ -84,7 +84,7 @@ Blockly.Python['procedures_defreturn'] = function(block) { var args = []; for (var i = 0; i < block.arguments_.length; i++) { args[i] = Blockly.Python.variableDB_.getName(block.arguments_[i], - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); } var code = 'def ' + funcName + '(' + args.join(', ') + '):\n' + globals + xfix1 + loopTrap + branch + xfix2 + returnValue; diff --git a/generators/python/text.js b/generators/python/text.js index 0089d5fc9..94241ed2c 100644 --- a/generators/python/text.js +++ b/generators/python/text.js @@ -86,7 +86,7 @@ Blockly.Python['text_join'] = function(block) { Blockly.Python.ORDER_NONE) || '\'\''; } var tempVar = Blockly.Python.variableDB_.getDistinctName('x', - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); var code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' + elements.join(', ') + ']])'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; @@ -96,7 +96,7 @@ Blockly.Python['text_join'] = function(block) { Blockly.Python['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); var value = Blockly.Python.valueToCode(block, 'TEXT', Blockly.Python.ORDER_NONE) || '\'\''; return varName + ' = str(' + varName + ') + ' + diff --git a/generators/python/variables.js b/generators/python/variables.js index 3c9d7cffc..7567b29fa 100644 --- a/generators/python/variables.js +++ b/generators/python/variables.js @@ -29,7 +29,7 @@ goog.require('Blockly.Python'); Blockly.Python['variables_get'] = function(block) { // Variable getter. var code = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return [code, Blockly.Python.ORDER_ATOMIC]; }; @@ -38,6 +38,6 @@ Blockly.Python['variables_set'] = function(block) { var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '0'; var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), - Blockly.Variables.NAME_TYPE); + Blockly.VARIABLE_CATEGORY_NAME); return varName + ' = ' + argument0 + '\n'; }; From cbc79444f68e609838723840116dbf8c38122f0c Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 28 Oct 2019 12:11:35 -0700 Subject: [PATCH 114/343] Fix touch gesture code (#3351) --- core/touch_gesture.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/touch_gesture.js b/core/touch_gesture.js index 00b15d979..8cfa68351 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -55,10 +55,10 @@ Blockly.TouchGesture = function(e, creatorWorkspace) { /** * A map of cached points used for tracking multi-touch gestures. - * @type {Object} + * @type {!Object} * @private */ - this.cachedPoints_ = {}; + this.cachedPoints_ = Object.create(null); /** * This is the ratio between the starting distance between the touch points @@ -88,11 +88,10 @@ Blockly.TouchGesture = function(e, creatorWorkspace) { /** * Boolean for whether or not the workspace supports pinch-zoom. - * @type {boolean} + * @type {?boolean} * @private */ - this.isPinchZoomEnabled_ = this.startWorkspace_.options.zoomOptions && - this.startWorkspace_.options.zoomOptions.pinch; + this.isPinchZoomEnabled_ = null; }; Blockly.utils.object.inherits(Blockly.TouchGesture, Blockly.Gesture); @@ -115,6 +114,8 @@ Blockly.TouchGesture.ZOOM_OUT_MULTIPLIER = 6; * @package */ Blockly.TouchGesture.prototype.doStart = function(e) { + this.isPinchZoomEnabled_ = this.startWorkspace_.options.zoomOptions && + this.startWorkspace_.options.zoomOptions.pinch; Blockly.TouchGesture.superClass_.doStart.call(this, e); if (!this.isEnding_ && Blockly.Touch.isTouchEvent(e)) { this.handleTouchStart(e); @@ -297,7 +298,7 @@ Blockly.TouchGesture.prototype.handlePinch_ = function(e) { e, workspace.getParentSvg(), workspace.getInverseScreenCTM()); workspace.zoom(position.x, position.y, delta); } - this.previousScale_ = this.touchScale_; + this.previousScale_ = scale; e.preventDefault(); }; @@ -313,7 +314,7 @@ Blockly.TouchGesture.prototype.handleTouchEnd = function(e) { delete this.cachedPoints_[pointerId]; } if (Object.keys(this.cachedPoints_).length < 2) { - this.cachedPoints_ = {}; + this.cachedPoints_ = Object.create(null); this.previousScale_ = 0; } }; From cbf867f4416cd82e131e03b038dcfc0a0a8b1eaf Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 28 Oct 2019 12:53:51 -0700 Subject: [PATCH 115/343] Add keyboard navigation support for multiple workspaces (#3352) * Add keyboard navigation support for multiple workspaces --- core/block.js | 2 +- core/block_svg.js | 2 +- core/blockly.js | 9 +++------ core/gesture.js | 2 +- core/inject.js | 12 ++++++++++++ core/keyboard_nav/navigation.js | 10 +++++----- core/mutator.js | 3 ++- core/toolbox.js | 4 ++-- core/workspace.js | 7 +++++++ core/workspace_svg.js | 2 +- msg/json/en.json | 3 ++- msg/json/qqq.json | 10 +--------- msg/messages.js | 5 +++++ tests/mocha/gesture_test.js | 4 ++-- tests/mocha/navigation_test.js | 12 ++++++------ 15 files changed, 51 insertions(+), 36 deletions(-) diff --git a/core/block.js b/core/block.js index 895c77c1b..194c48b86 100644 --- a/core/block.js +++ b/core/block.js @@ -325,7 +325,7 @@ Blockly.Block.prototype.dispose = function(healStack) { this.workspace.removeChangeListener(this.onchangeWrapper_); } - if (Blockly.keyboardAccessibilityMode) { + if (this.workspace.keyboardAccessibilityMode) { // No-op if this is called from the block_svg class. Blockly.navigation.moveCursorOnBlockDelete(this); } diff --git a/core/block_svg.js b/core/block_svg.js index 5c34f64ae..4a575b89e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1031,7 +1031,7 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { Blockly.ContextMenu.hide(); } - if (Blockly.keyboardAccessibilityMode) { + if (this.workspace.keyboardAccessibilityMode) { Blockly.navigation.moveCursorOnBlockDelete(this); } diff --git a/core/blockly.js b/core/blockly.js index e220741b8..fd75b34a6 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -72,12 +72,6 @@ Blockly.selected = null; */ Blockly.cursor = null; -/** - * Whether or not we're currently in keyboard accessibility mode. - * @type {boolean} - */ -Blockly.keyboardAccessibilityMode = false; - /** * All of the connections on blocks that are currently being dragged. * @type {!Array.} @@ -183,6 +177,9 @@ Blockly.svgResize = function(workspace) { // are multiple workspaces and non-main workspaces are able to accept input. Blockly.onKeyDown = function(e) { var mainWorkspace = Blockly.mainWorkspace; + if (!mainWorkspace) { + return; + } if (Blockly.utils.isTargetInput(e) || (mainWorkspace.rendered && !mainWorkspace.isVisible())) { diff --git a/core/gesture.js b/core/gesture.js index ade6a2c86..c07a19bef 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -657,7 +657,7 @@ Blockly.Gesture.prototype.handleWsStart = function(e, ws) { this.setStartWorkspace_(ws); this.mostRecentEvent_ = e; this.doStart(e); - if (Blockly.keyboardAccessibilityMode) { + if (this.startWorkspace_.keyboardAccessibilityMode) { Blockly.navigation.setState(Blockly.navigation.STATE_WS); } }; diff --git a/core/inject.js b/core/inject.js index 45c638627..ee07595e9 100644 --- a/core/inject.js +++ b/core/inject.js @@ -61,6 +61,10 @@ Blockly.inject = function(container, opt_options) { (/** @type {!Blockly.BlocklyOptions} */ ({}))); var subContainer = document.createElement('div'); subContainer.className = 'injectionDiv'; + subContainer.tabIndex = 0; + Blockly.utils.aria.setState(subContainer, + Blockly.utils.aria.State.LABEL, Blockly.Msg['WORKSPACE_ARIA_LABEL']); + container.appendChild(subContainer); var svg = Blockly.createDom_(subContainer, options); @@ -78,6 +82,14 @@ Blockly.inject = function(container, opt_options) { Blockly.svgResize(workspace); + subContainer.addEventListener('focus', function() { + Blockly.mainWorkspace = workspace; + }); + + subContainer.addEventListener('blur', function() { + Blockly.mainWorkspace = null; + }); + return workspace; }; diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 90319cb9b..7f6523554 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -666,8 +666,8 @@ Blockly.navigation.moveCursorOnBlockMutation = function(mutatedBlock) { * Enable accessibility mode. */ Blockly.navigation.enableKeyboardAccessibility = function() { - if (!Blockly.keyboardAccessibilityMode) { - Blockly.keyboardAccessibilityMode = true; + if (!Blockly.getMainWorkspace().keyboardAccessibilityMode) { + Blockly.getMainWorkspace().keyboardAccessibilityMode = true; Blockly.navigation.focusWorkspace_(); } }; @@ -676,9 +676,9 @@ Blockly.navigation.enableKeyboardAccessibility = function() { * Disable accessibility mode. */ Blockly.navigation.disableKeyboardAccessibility = function() { - if (Blockly.keyboardAccessibilityMode) { + if (Blockly.getMainWorkspace().keyboardAccessibilityMode) { var workspace = Blockly.getMainWorkspace(); - Blockly.keyboardAccessibilityMode = false; + Blockly.getMainWorkspace().keyboardAccessibilityMode = false; workspace.getCursor().hide(); workspace.getMarker().hide(); if (Blockly.navigation.getFlyoutCursor_()) { @@ -758,7 +758,7 @@ Blockly.navigation.onBlocklyAction = function(action) { var readOnly = Blockly.getMainWorkspace().options.readOnly; var actionHandled = false; - if (Blockly.keyboardAccessibilityMode) { + if (Blockly.getMainWorkspace().keyboardAccessibilityMode) { if (!readOnly) { actionHandled = Blockly.navigation.handleActions_(action); // If in readonly mode only handle valid actions. diff --git a/core/mutator.js b/core/mutator.js index 649e1fe5e..390696ddf 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -378,7 +378,8 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) { block.render(); } - if (oldMutation != newMutation && Blockly.keyboardAccessibilityMode) { + if (oldMutation != newMutation && + this.workspace_.keyboardAccessibilityMode) { Blockly.navigation.moveCursorOnBlockMutation(block); } // Don't update the bubble until the drag has ended, to avoid moving blocks diff --git a/core/toolbox.js b/core/toolbox.js index f8914d894..d68bec94c 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -296,13 +296,13 @@ Blockly.Toolbox.prototype.handleAfterTreeSelected_ = function( if (this.lastCategory_ != newNode) { this.flyout_.scrollToStart(); } - if (Blockly.keyboardAccessibilityMode) { + if (this.workspace_.keyboardAccessibilityMode) { Blockly.navigation.setState(Blockly.navigation.STATE_TOOLBOX); } } else { // Hide the flyout. this.flyout_.hide(); - if (Blockly.keyboardAccessibilityMode && + if (this.workspace_.keyboardAccessibilityMode && !(newNode instanceof Blockly.Toolbox.TreeSeparator)) { Blockly.navigation.setState(Blockly.navigation.STATE_WS); } diff --git a/core/workspace.js b/core/workspace.js index 2119c8d17..0f7b74c9b 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -138,6 +138,13 @@ Blockly.Workspace = function(opt_options) { new Blockly.ThemeManager(this.options.theme || Blockly.Themes.Classic); this.themeManager_.subscribeWorkspace(this); + + /** + * True if keyboard accessibility mode is on, false otherwise. + * @type {boolean} + * @package + */ + this.keyboardAccessibilityMode = false; }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index a79cc05bf..a4af7e3c8 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1198,7 +1198,7 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { // Handle paste for keyboard navigation var markedNode = this.getMarker().getCurNode(); - if (Blockly.keyboardAccessibilityMode && markedNode && + if (this.keyboardAccessibilityMode && markedNode && markedNode.isConnection()) { var markedLocation = /** @type {!Blockly.Connection} */ (markedNode.getLocation()); diff --git a/msg/json/en.json b/msg/json/en.json index 1a9b1d043..b4552c430 100644 --- a/msg/json/en.json +++ b/msg/json/en.json @@ -1,7 +1,7 @@ { "@metadata": { "author": "Ellen Spertus ", - "lastupdated": "2019-10-04 13:16:14.900805", + "lastupdated": "2019-10-28 11:09:19.411955", "locale": "en", "messagedocumentation" : "qqq" }, @@ -403,5 +403,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Warning: This block may be used only within a function definition.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Say something...", + "WORKSPACE_ARIA_LABEL": "Blockly Workspace", "COLLAPSED_WARNINGS_WARNING": "Collapsed blocks contain warnings." } diff --git a/msg/json/qqq.json b/msg/json/qqq.json index c6c5d401a..f2b7d1723 100644 --- a/msg/json/qqq.json +++ b/msg/json/qqq.json @@ -1,13 +1,4 @@ { - "@metadata": { - "authors": [ - "Espertus", - "Liuxinyu970226", - "Metalhead64", - "Robby", - "Shirayuki" - ] - }, "VARIABLES_DEFAULT_NAME": "default name - A simple, general default name for a variable, preferably short. For more context, see [[Translating:Blockly#infrequent_message_types]].\n{{Identical|Item}}", "UNNAMED_KEY": "default name - A simple, default name for an unnamed function or variable. Preferably indicates that the item is unnamed.", "TODAY": "button text - Button that sets a calendar to today's date.\n{{Identical|Today}}", @@ -406,5 +397,6 @@ "PROCEDURES_IFRETURN_HELPURL": "{{Optional}} url - Information about guard clauses.", "PROCEDURES_IFRETURN_WARNING": "warning - This appears if the user tries to use this block outside of a function definition.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "comment text - This text appears in a new workspace comment, to hint that the user can type here.", + "WORKSPACE_ARIA_LABEL": "workspace - This text is read out when a user navigates to the workspace while using a screen reader.", "COLLAPSED_WARNINGS_WARNING": "warning - This appears if the user collapses a block, and blocks inside that block have warnings attached to them. It should inform the user that the block they collapsed contains blocks that have warnings." } diff --git a/msg/messages.js b/msg/messages.js index 2cb5c3ed8..ef3f46bd1 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -1629,6 +1629,11 @@ Blockly.Msg.PROCEDURES_IFRETURN_WARNING = 'Warning: This block may be used only /// the user can type here. Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT = 'Say something...'; +/** @type {string} */ +/// workspace - This text is read out when a user navigates to the workspace while +/// using a screen reader. +Blockly.Msg.WORKSPACE_ARIA_LABEL = 'Blockly Workspace'; + /** @type {string} */ /// warning - This appears if the user collapses a block, and blocks inside /// that block have warnings attached to them. It should inform the user that the diff --git a/tests/mocha/gesture_test.js b/tests/mocha/gesture_test.js index 460e885da..680bc0bc6 100644 --- a/tests/mocha/gesture_test.js +++ b/tests/mocha/gesture_test.js @@ -90,8 +90,8 @@ suite('Gesture', function() { }; var ws = Blockly.inject('blocklyDiv', {}); var gesture = new Blockly.Gesture(this.e, ws); - assertFalse(Blockly.keyboardAccessibilityMode); + assertFalse(Blockly.getMainWorkspace().keyboardAccessibilityMode); gesture.doWorkspaceClick_(event); - assertTrue(Blockly.keyboardAccessibilityMode); + assertTrue(Blockly.getMainWorkspace().keyboardAccessibilityMode); }); }); diff --git a/tests/mocha/navigation_test.js b/tests/mocha/navigation_test.js index f4ed06978..b2c2b501a 100644 --- a/tests/mocha/navigation_test.js +++ b/tests/mocha/navigation_test.js @@ -349,7 +349,7 @@ suite('Navigation', function() { this.workspace = new Blockly.Workspace({readOnly: false}); Blockly.user.keyMap.setKeyMap(Blockly.user.keyMap.createDefaultKeyMap()); Blockly.mainWorkspace = this.workspace; - Blockly.keyboardAccessibilityMode = true; + Blockly.getMainWorkspace().keyboardAccessibilityMode = true; Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS; this.mockEvent = { @@ -407,24 +407,24 @@ suite('Navigation', function() { test('Toggle Action Off', function() { this.mockEvent.keyCode = 'Control75'; sinon.spy(Blockly.navigation, 'onBlocklyAction'); - Blockly.keyboardAccessibilityMode = true; + Blockly.getMainWorkspace().keyboardAccessibilityMode = true; var isHandled = Blockly.navigation.onKeyPress(this.mockEvent); chai.assert.isTrue(isHandled); chai.assert.isTrue(Blockly.navigation.onBlocklyAction.calledOnce); - chai.assert.isFalse(Blockly.keyboardAccessibilityMode); + chai.assert.isFalse(Blockly.getMainWorkspace().keyboardAccessibilityMode); Blockly.navigation.onBlocklyAction.restore(); }); test('Toggle Action On', function() { this.mockEvent.keyCode = 'Control75'; sinon.stub(Blockly.navigation, 'focusWorkspace_'); - Blockly.keyboardAccessibilityMode = false; + Blockly.getMainWorkspace().keyboardAccessibilityMode = false; var isHandled = Blockly.navigation.onKeyPress(this.mockEvent); chai.assert.isTrue(isHandled); chai.assert.isTrue(Blockly.navigation.focusWorkspace_.calledOnce); - chai.assert.isTrue(Blockly.keyboardAccessibilityMode); + chai.assert.isTrue(Blockly.getMainWorkspace().keyboardAccessibilityMode); Blockly.navigation.focusWorkspace_.restore(); this.workspace.dispose(); }); @@ -459,7 +459,7 @@ suite('Navigation', function() { this.workspace = new Blockly.Workspace({readOnly: true}); this.workspace.setCursor(new Blockly.Cursor()); Blockly.mainWorkspace = this.workspace; - Blockly.keyboardAccessibilityMode = true; + Blockly.getMainWorkspace().keyboardAccessibilityMode = true; Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS; this.fieldBlock1 = this.workspace.newBlock('field_block'); From 72c6aa8699482f398ce5508ef0ccbc240bca976c Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 28 Oct 2019 16:20:25 -0700 Subject: [PATCH 116/343] Block generator warnings (#3353) --- core/generator.js | 6 +++--- core/names.js | 5 ++--- generators/dart/loops.js | 6 +++--- generators/javascript/lists.js | 2 +- generators/javascript/loops.js | 4 ++-- generators/javascript/text.js | 2 +- generators/lua/lists.js | 4 ++-- generators/php/loops.js | 4 ++-- generators/python/math.js | 2 +- 9 files changed, 17 insertions(+), 18 deletions(-) diff --git a/core/generator.js b/core/generator.js index 053095f27..e73adfe52 100644 --- a/core/generator.js +++ b/core/generator.js @@ -351,7 +351,7 @@ Blockly.Generator.prototype.injectId = function(msg, block) { /** * Comma-separated list of reserved words. * @type {string} - * @private + * @protected */ Blockly.Generator.prototype.RESERVED_WORDS_ = ''; @@ -370,7 +370,7 @@ Blockly.Generator.prototype.addReservedWords = function(words) { * legitimately appear in a function definition (or comment), and it must * not confuse the regular expression parser. * @type {string} - * @private + * @protected */ Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}'; @@ -411,7 +411,7 @@ Blockly.Generator.prototype.variableDB_; * @param {!Array.} code A list of statements. Use ' ' for indents. * @return {string} The actual name of the new function. This may differ * from desiredName if the former has already been taken by the user. - * @private + * @protected */ Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) { if (!this.definitions_[desiredName]) { diff --git a/core/names.js b/core/names.js index c18f5ab34..daa7edb73 100644 --- a/core/names.js +++ b/core/names.js @@ -76,7 +76,6 @@ 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. - * @package */ Blockly.Names.prototype.setVariableMap = function(map) { this.variableMap_ = map; @@ -84,7 +83,8 @@ Blockly.Names.prototype.setVariableMap = function(map) { /** * Get the name for a user-defined variable, based on its ID. - * This should only be used for variables of type Blockly.Variables.NAME_TYPE. + * This should only be used for variables of type + * Blockly.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. @@ -113,7 +113,6 @@ Blockly.Names.prototype.getNameForUserVariable_ = function(id) { * @param {string} type The type of entity in Blockly * ('VARIABLE', 'PROCEDURE', 'BUILTIN', etc...). * @return {string} An entity name that is legal in the exported language. - * @suppress {deprecated} Suppress deprecated Blockly.Variables.NAME_TYPE. */ Blockly.Names.prototype.getName = function(name, type) { if (type == Blockly.VARIABLE_CATEGORY_NAME) { diff --git a/generators/dart/loops.js b/generators/dart/loops.js index 3f362162b..9d10afd8e 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -43,7 +43,7 @@ Blockly.Dart['controls_repeat_ext'] = function(block) { 'count', Blockly.VARIABLE_CATEGORY_NAME); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { - var endVar = Blockly.Dart.variableDB_.getDistinctName( + endVar = Blockly.Dart.variableDB_.getDistinctName( 'repeat_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } @@ -102,13 +102,13 @@ Blockly.Dart['controls_for'] = function(block) { // Cache non-trivial values to variables to prevent repeated look-ups. var startVar = argument0; if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) { - var startVar = Blockly.Dart.variableDB_.getDistinctName( + startVar = Blockly.Dart.variableDB_.getDistinctName( variable0 + '_start', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { - var endVar = Blockly.Dart.variableDB_.getDistinctName( + endVar = Blockly.Dart.variableDB_.getDistinctName( variable0 + '_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } diff --git a/generators/javascript/lists.js b/generators/javascript/lists.js index 84e0cfea6..d799f6331 100644 --- a/generators/javascript/lists.js +++ b/generators/javascript/lists.js @@ -252,7 +252,7 @@ Blockly.JavaScript['lists_setIndex'] = function(block) { * @param {string} listName Name of the list, used to calculate length. * @param {string} where The method of indexing, selected by dropdown in Blockly * @param {string=} opt_at The optional offset when indexing from start/end. - * @return {string} Index expression. + * @return {string|undefined} Index expression. * @private */ Blockly.JavaScript.lists.getIndex_ = function(listName, where, opt_at) { diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index 711d8904e..9f0068087 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -43,7 +43,7 @@ Blockly.JavaScript['controls_repeat_ext'] = function(block) { 'count', Blockly.VARIABLE_CATEGORY_NAME); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { - var endVar = Blockly.JavaScript.variableDB_.getDistinctName( + endVar = Blockly.JavaScript.variableDB_.getDistinctName( 'repeat_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } @@ -109,7 +109,7 @@ Blockly.JavaScript['controls_for'] = function(block) { } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { - var endVar = Blockly.JavaScript.variableDB_.getDistinctName( + endVar = Blockly.JavaScript.variableDB_.getDistinctName( variable0 + '_end', Blockly.VARIABLE_CATEGORY_NAME); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } diff --git a/generators/javascript/text.js b/generators/javascript/text.js index 8b1c162c5..d81dd15f4 100644 --- a/generators/javascript/text.js +++ b/generators/javascript/text.js @@ -171,7 +171,7 @@ Blockly.JavaScript['text_charAt'] = function(block) { * @param {string} stringName Name of the string, used to calculate length. * @param {string} where The method of indexing, selected by dropdown in Blockly * @param {string=} opt_at The optional offset when indexing from start/end. - * @return {string} Index expression. + * @return {string|undefined} Index expression. * @private */ Blockly.JavaScript.text.getIndex_ = function(stringName, where, opt_at) { diff --git a/generators/lua/lists.js b/generators/lua/lists.js index 24dbf2c76..d56141a8f 100644 --- a/generators/lua/lists.js +++ b/generators/lua/lists.js @@ -114,7 +114,7 @@ Blockly.Lua['lists_indexOf'] = function(block) { * @param {string} listName Name of the list, used to calculate length. * @param {string} where The method of indexing, selected by dropdown in Blockly * @param {string=} opt_at The optional offset when indexing from start/end. - * @return {string} Index expression. + * @return {string|undefined} Index expression. * @private */ Blockly.Lua.lists.getIndex_ = function(listName, where, opt_at) { @@ -374,6 +374,6 @@ Blockly.Lua['lists_reverse'] = function(block) { ' end', ' return reversed', 'end']); - var code = 'list_reverse(' + list + ')'; + var code = functionName + '(' + list + ')'; return [code, Blockly.Lua.ORDER_HIGH]; }; diff --git a/generators/php/loops.js b/generators/php/loops.js index bbd2c6695..dc8a1d241 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -43,7 +43,7 @@ Blockly.PHP['controls_repeat_ext'] = function(block) { 'count', Blockly.VARIABLE_CATEGORY_NAME); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { - var endVar = Blockly.PHP.variableDB_.getDistinctName( + endVar = Blockly.PHP.variableDB_.getDistinctName( 'repeat_end', Blockly.VARIABLE_CATEGORY_NAME); code += endVar + ' = ' + repeats + ';\n'; } @@ -108,7 +108,7 @@ Blockly.PHP['controls_for'] = function(block) { } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { - var endVar = Blockly.PHP.variableDB_.getDistinctName( + endVar = Blockly.PHP.variableDB_.getDistinctName( variable0 + '_end', Blockly.VARIABLE_CATEGORY_NAME); code += endVar + ' = ' + argument1 + ';\n'; } diff --git a/generators/python/math.js b/generators/python/math.js index bc7b379ec..1a003c479 100644 --- a/generators/python/math.js +++ b/generators/python/math.js @@ -76,7 +76,7 @@ Blockly.Python['math_single'] = function(block) { var arg; if (operator == 'NEG') { // Negation is a special case given its different operator precedence. - var code = Blockly.Python.valueToCode(block, 'NUM', + code = Blockly.Python.valueToCode(block, 'NUM', Blockly.Python.ORDER_UNARY_SIGN) || '0'; return ['-' + code, Blockly.Python.ORDER_UNARY_SIGN]; } From e7752e6ea2a255a3afceff9fea67ae99e9f4949a Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 28 Oct 2019 16:20:54 -0700 Subject: [PATCH 117/343] Dummy input right alignment (#3342) * Fix dummy input alignment in geras. --- core/renderers/common/constants.js | 6 +++ core/renderers/common/info.js | 3 ++ core/renderers/geras/info.js | 71 ++++++++++++++++++++------ core/renderers/thrasos/info.js | 69 ++++++++++++++++++------- tests/blocks/test_blocks.js | 81 ++++++++++++++++++++++++++++++ tests/playground.html | 7 +++ 6 files changed, 205 insertions(+), 32 deletions(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 1ec8c8fdc..bfc753f09 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -60,6 +60,12 @@ Blockly.blockRendering.ConstantProvider = function() { this.EMPTY_BLOCK_SPACER_HEIGHT = 16; + /** + * The minimum height of a dummy input row. + * @type {number} + */ + this.DUMMY_INPUT_MIN_HEIGHT = this.TAB_HEIGHT; + /** * Rounded corner radius. * @type {number} diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index f47b8c136..eed3591f1 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -376,8 +376,11 @@ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRo } else if (input.type == Blockly.DUMMY_INPUT) { // 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.hasDummyInput = true; } + activeRow.align = input.align; }; /** diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 31b99e6b7..3df571bf2 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -115,8 +115,49 @@ Blockly.geras.RenderInfo.prototype.addInput_ = function(input, activeRow) { } else if (input.type == Blockly.DUMMY_INPUT) { // 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.hasDummyInput = true; } + activeRow.align = input.align; +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.addElemSpacing_ = function() { + var hasExternalInputs = false; + for (var 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; + 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( + this.constants_, this.getInRowSpacing_(null, oldElems[0]))); + } + for (var 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)); + } + row.elements.push(oldElems[oldElems.length - 1]); + if (row.endsWithElemSpacer()) { + var 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)); + } + } }; /** @@ -274,22 +315,19 @@ Blockly.geras.RenderInfo.prototype.addAlignmentPadding_ = function(row, missingS row.widthWithConnectedBlocks += missingSpace; } - var input = row.getLastInput(); - if (input) { - // Decide where the extra padding goes. - if (input.align == Blockly.ALIGN_LEFT) { - // Add padding to the end of the row. - lastSpacer.width += missingSpace; - } else if (input.align == Blockly.ALIGN_CENTRE) { - // Split the padding between the beginning and end of the row. - firstSpacer.width += missingSpace / 2; - lastSpacer.width += missingSpace / 2; - } else if (input.align == Blockly.ALIGN_RIGHT) { - // Add padding at the beginning of the row. - firstSpacer.width += missingSpace; - } + // Decide where the extra padding goes. + if (row.align == Blockly.ALIGN_LEFT) { + // Add padding to the end of the row. + lastSpacer.width += missingSpace; + } else if (row.align == Blockly.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 == Blockly.ALIGN_RIGHT) { + // Add padding at the beginning of the row. + firstSpacer.width += missingSpace; } else { - // Default to left-aligning if there's no input to say where to align. + // Default to left-aligning. lastSpacer.width += missingSpace; } row.width += missingSpace; @@ -321,6 +359,9 @@ Blockly.geras.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { if (!prev.hasStatement && next.hasDummyInput) { return this.constants_.LARGE_PADDING; } + if (prev.hasDummyInput) { + return this.constants_.LARGE_PADDING; + } return this.constants_.MEDIUM_PADDING; }; diff --git a/core/renderers/thrasos/info.js b/core/renderers/thrasos/info.js index 48ed1f9ed..b8772cbb9 100644 --- a/core/renderers/thrasos/info.js +++ b/core/renderers/thrasos/info.js @@ -70,6 +70,44 @@ Blockly.thrasos.RenderInfo.prototype.getRenderer = function() { return /** @type {!Blockly.thrasos.Renderer} */ (this.renderer_); }; +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.addElemSpacing_ = function() { + var hasExternalInputs = false; + for (var 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; + 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( + this.constants_, this.getInRowSpacing_(null, oldElems[0]))); + } + for (var 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)); + } + row.elements.push(oldElems[oldElems.length - 1]); + if (row.endsWithElemSpacer()) { + var 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)); + } + } +}; + /** * @override */ @@ -211,23 +249,20 @@ Blockly.thrasos.RenderInfo.prototype.addAlignmentPadding_ = function(row, missin if (row.hasExternalInput || row.hasStatement) { row.widthWithConnectedBlocks += missingSpace; } - - var input = row.getLastInput(); - if (input) { - // Decide where the extra padding goes. - if (input.align == Blockly.ALIGN_LEFT) { - // Add padding to the end of the row. - lastSpacer.width += missingSpace; - } else if (input.align == Blockly.ALIGN_CENTRE) { - // Split the padding between the beginning and end of the row. - firstSpacer.width += missingSpace / 2; - lastSpacer.width += missingSpace / 2; - } else if (input.align == Blockly.ALIGN_RIGHT) { - // Add padding at the beginning of the row. - firstSpacer.width += missingSpace; - } + + // Decide where the extra padding goes. + if (row.align == Blockly.ALIGN_LEFT) { + // Add padding to the end of the row. + lastSpacer.width += missingSpace; + } else if (row.align == Blockly.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 == Blockly.ALIGN_RIGHT) { + // Add padding at the beginning of the row. + firstSpacer.width += missingSpace; } else { - // Default to left-aligning if there's no input to say where to align. + // Default to left-aligning. lastSpacer.width += missingSpace; } row.width += missingSpace; @@ -257,7 +292,7 @@ Blockly.thrasos.RenderInfo.prototype.getSpacerRowHeight_ = function( if (prev.hasStatement && next.hasStatement) { return this.constants_.LARGE_PADDING; } - if (next.hasDummyInput) { + if (prev.hasDummyInput || next.hasDummyInput) { return this.constants_.LARGE_PADDING; } return this.constants_.MEDIUM_PADDING; diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index 537adb0f5..6f9e0af33 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -31,6 +31,29 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "nextStatement": null, "style": "math_blocks" }, + { + "type": "test_basic_dummy", + "message0": "dummy input %1", + "args0": [ + { + "type": "input_dummy" + } + ], + "style": "math_blocks" + }, + { + "type": "test_basic_multiple_dummy", + "message0": "first dummy %1 second dummy %2", + "args0": [ + { + "type": "input_dummy" + }, + { + "type": "input_dummy" + } + ], + "style": "math_blocks" + }, { "type": "test_basic_row", "message0": "row block %1", @@ -124,6 +147,64 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "colour": 200, "tooltip": "Hello world." }, + { + "type": "test_align_dummy_right", + "message0": "text %1 long text %2", + "args0": [ + { + "type": "input_dummy", + "align": "RIGHT", + }, + { + "type": "input_dummy", + "align": "RIGHT", + }, + ], + "style": "math_blocks" + }, + { + "type": "test_align_all", + "message0": "text %1 long text %2 text %3 much longer text", + "args0": [ + { + "type": "input_dummy", + "align": "LEFT", + }, + { + "type": "input_dummy", + "align": "CENTRE", + }, + { + "type": "input_dummy", + "align": "RIGHT", + }, + ], + "style": "math_blocks" + }, + { + "type": "test_align_with_external_input", + "message0": "text %1 long text %2 text %3 much longer text %4", + "args0": [ + { + "type": "input_dummy", + "align": "RIGHT", + }, + { + "type": "input_dummy", + "align": "CENTRE", + }, + { + "type": "input_dummy", + "align": "LEFT", + }, + { + "type": "input_value", + "name": "VALUE" + }, + ], + "inputsInline": false, + "style": "math_blocks" + }, { "type": "test_dropdowns_long", "message0": "long: %1", diff --git a/tests/playground.html b/tests/playground.html index d9969cc1b..742b5858f 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -1359,6 +1359,8 @@ var spaghettiXml = [ + + @@ -1367,6 +1369,11 @@ var spaghettiXml = [ + + + + + From 6df85b9ff334fc9eaec67f28d65ba4183fb3d453 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 29 Oct 2019 09:10:43 -0700 Subject: [PATCH 118/343] Update mutator workspace delete areas when bubble is moved. (#3355) * Update mutator workspace delete areas when its moved --- core/block_svg.js | 2 +- core/bubble.js | 40 +++++++++++++++++++++++++++++++++------- core/bubble_dragger.js | 1 + core/mutator.js | 20 ++++++++++++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 4a575b89e..18f09d5d0 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1291,7 +1291,7 @@ Blockly.BlockSvg.prototype.setMutator = function(mutator) { this.mutator.dispose(); } if (mutator) { - mutator.block_ = this; + mutator.setBlock(this); this.mutator = mutator; mutator.createIcon(); } diff --git a/core/bubble.js b/core/bubble.js index 0ec5ad9c6..4253afd7f 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -81,6 +81,20 @@ Blockly.Bubble = function(workspace, content, shape, anchorXY, this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); } } + + /** + * Method to call on resize of bubble. + * @type {?function()} + * @private + */ + this.resizeCallback_ = null; + + /** + * Method to call on move of bubble. + * @type {?function()} + * @private + */ + this.moveCallback_ = null; }; /** @@ -123,13 +137,6 @@ Blockly.Bubble.onMouseUpWrapper_ = null; */ Blockly.Bubble.onMouseMoveWrapper_ = null; -/** - * Function to call on resize of bubble. - * @type {Function} - * @private - */ -Blockly.Bubble.prototype.resizeCallback_ = null; - /** * Stop binding to the global mouseup and mousemove events. * @private @@ -371,6 +378,14 @@ Blockly.Bubble.prototype.registerResizeEvent = function(callback) { this.resizeCallback_ = 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) { + this.moveCallback_ = callback; +}; + /** * Move this bubble to the top of the stack. * @return {boolean} Whether or not the bubble has been moved. @@ -620,6 +635,17 @@ Blockly.Bubble.prototype.moveTo = function(x, y) { this.bubbleGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')'); }; +/** + * Triggers a move callback if one exists at the end of a drag. + * @param {boolean} adding True if adding, false if removing. + * @package + */ +Blockly.Bubble.prototype.setDragging = function(adding) { + if (!adding && this.moveCallback_) { + this.moveCallback_(); + } +}; + /** * Get the dimensions of this bubble. * @return {!Blockly.utils.Size} The height and width of the bubble. diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index 9864f61af..9a26c73c6 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -267,6 +267,7 @@ Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { } return result; }; + /** * Move the bubble onto the drag surface at the beginning of a drag. Move the * drag surface to preserve the apparent location of the bubble. diff --git a/core/mutator.js b/core/mutator.js index 390696ddf..46ed7070d 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -62,6 +62,15 @@ Blockly.Mutator.prototype.workspaceWidth_ = 0; */ Blockly.Mutator.prototype.workspaceHeight_ = 0; +/** + * Set the block this mutator is associated with. + * @param {Blockly.BlockSvg} block The block associated with this mutator. + * @package + */ +Blockly.Mutator.prototype.setBlock = function(block) { + this.block_ = block; +}; + /** * Draw the mutator icon. * @param {!Element} group The icon group. @@ -242,6 +251,16 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { this.workspace_.resize(); }; +/** + * A method handler for when the bubble is moved. + * @private + */ +Blockly.Mutator.prototype.onBubbleMove_ = function() { + if (this.workspace_) { + this.workspace_.recordDeleteAreas(); + } +}; + /** * Show or hide the mutator bubble. * @param {boolean} visible True if the bubble should be visible. @@ -261,6 +280,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) { /** @type {!Blockly.utils.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(); if (tree) { From 942068314fff3cb3faee6404ca5b599355178fa6 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 29 Oct 2019 11:45:30 -0700 Subject: [PATCH 119/343] Accept lowercase alignment (#3359) * Accept lowercase alignment --- core/block.js | 18 ++++++++++++++---- core/renderers/common/info.js | 4 +++- core/renderers/geras/info.js | 4 +++- core/renderers/measurables/rows.js | 7 +++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/core/block.js b/core/block.js index 194c48b86..827887e1d 100644 --- a/core/block.js +++ b/core/block.js @@ -1454,7 +1454,7 @@ Blockly.Block.prototype.jsonInit = function(json) { var i = 0; while (json['message' + i] !== undefined) { this.interpolate_(json['message' + i], json['args' + i] || [], - json['lastDummyAlign' + i]); + json['lastDummyAlign' + i], warningPrefix); i++; } @@ -1578,9 +1578,11 @@ Blockly.Block.prototype.mixin = function(mixinObj, opt_disableCheck) { * @param {!Array} args Array of arguments to be interpolated. * @param {string|undefined} lastDummyAlign If a dummy input is added at the * end, how should it be aligned? + * @param {string} warningPrefix Warning prefix string identifying block. * @private */ -Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign) { +Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign, + warningPrefix) { var tokens = Blockly.utils.tokenizeInterpolation(message); // Interpolate the arguments. Build a list of elements. var indexDup = []; @@ -1625,7 +1627,8 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign) { var alignmentLookup = { 'LEFT': Blockly.ALIGN_LEFT, 'RIGHT': Blockly.ALIGN_RIGHT, - 'CENTRE': Blockly.ALIGN_CENTRE + 'CENTRE': Blockly.ALIGN_CENTRE, + 'CENTER': Blockly.ALIGN_CENTRE }; // Populate block with inputs and fields. var fieldStack = []; @@ -1673,7 +1676,14 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign) { input.setCheck(element['check']); } if (element['align']) { - input.setAlign(alignmentLookup[element['align']]); + var align = !!element['align'] && element['align'].toUpperCase(); + var alignment = alignmentLookup[align]; + if (alignment != undefined) { + input.setAlign(alignment); + } else { + console.warn(warningPrefix + 'Illegal align value: ', + element['align']); + } } for (var j = 0; j < fieldStack.length; j++) { input.appendField(fieldStack[j][0], fieldStack[j][1]); diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index eed3591f1..664a20c98 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -380,7 +380,9 @@ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRo this.constants_.DUMMY_INPUT_MIN_HEIGHT); activeRow.hasDummyInput = true; } - activeRow.align = input.align; + if (activeRow.align == null) { + activeRow.align = input.align; + } }; /** diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 3df571bf2..cb929766a 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -119,7 +119,9 @@ Blockly.geras.RenderInfo.prototype.addInput_ = function(input, activeRow) { this.constants_.DUMMY_INPUT_MIN_HEIGHT); activeRow.hasDummyInput = true; } - activeRow.align = input.align; + if (activeRow.align == null) { + activeRow.align = input.align; + } }; /** diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index c2c977a14..1cf09ddcf 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -154,6 +154,13 @@ Blockly.blockRendering.Row = function(constants) { this.constants_ = constants; this.notchOffset = this.constants_.NOTCH_OFFSET_LEFT; + + /** + * Alignment of the row. + * @package + * @type {?number} + */ + this.align = null; }; /** From c32c835088e59e19a1c58eaea12ee76d0b4cef0d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 29 Oct 2019 15:31:40 -0700 Subject: [PATCH 120/343] Fixed programmatically added connections not being added to the connection db (#3318) * Fixed programmatically added connections not getting added to the connection db. --- core/block_svg.js | 58 +- core/keyboard_nav/navigation.js | 8 +- core/rendered_connection.js | 45 +- core/xml.js | 4 +- tests/mocha/block_test.js | 1831 ++++++++++++++++--------------- 5 files changed, 1024 insertions(+), 922 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 18f09d5d0..a1fb14f09 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -140,14 +140,6 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @private */ this.markerSvg_ = null; - - /** - * Should the block tell its connections to start tracking inside the render - * method? - * @type {boolean} - * @private - */ - this.callTrackConnections_ = true; }; Blockly.utils.object.inherits(Blockly.BlockSvg, Blockly.Block); @@ -1525,58 +1517,45 @@ Blockly.BlockSvg.prototype.appendInput_ = function(type, name) { }; /** - * Tell the block to wait for an outside source to call - * startTrackingConnections, rather than starting connection - * tracking automatically. + * Sets whether this block's connections are tracked in the database or not. * - * Also tells children of this block to wait. + * Used by the deserializer to be more efficient. Setting a connection's + * tracked_ value to false keeps it from adding itself to the db when it + * gets its first moveTo call, saving expensive ops for later. + * @param {boolean} track If true, start tracking. If false, stop tracking. * @package */ -Blockly.BlockSvg.prototype.waitToTrackConnections = function() { - this.callTrackConnections_ = false; - var children = this.getChildren(false); - for (var i = 0, child; child = children[i]; i++) { - child.waitToTrackConnections(); - } -}; - -/** - * Tell this block's connections to add themselves to the connection - * database (i.e. start tracking). - * - * All following/next blocks will be told to start tracking. Inner blocks - * (i.e. blocks attached to value/statement inputs) will be told to start - * tracking if this block is not collapsed. - * @package - */ -Blockly.BlockSvg.prototype.startTrackingConnections = function() { +Blockly.BlockSvg.prototype.setConnectionTracking = function(track) { if (this.previousConnection) { - this.previousConnection.setTracking(true); + this.previousConnection.setTracking(track); } if (this.outputConnection) { - this.outputConnection.setTracking(true); + this.outputConnection.setTracking(track); } if (this.nextConnection) { - this.nextConnection.setTracking(true); + this.nextConnection.setTracking(track); var child = this.nextConnection.targetBlock(); if (child) { - child.startTrackingConnections(); + child.setConnectionTracking(track); } } if (this.collapsed_) { + // When track is true, we don't want to start tracking collapsed + // connections. When track is false, we're already not tracking + // collapsed connections, so no need to update. return; } for (var i = 0; i < this.inputList.length; i++) { var conn = this.inputList[i].connection; if (conn) { - conn.setTracking(true); + conn.setTracking(track); // Pass tracking on down the chain. var block = conn.targetBlock(); if (block) { - block.startTrackingConnections(); + block.setConnectionTracking(track); } } } @@ -1776,13 +1755,6 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { (/** @type {!Blockly.WorkspaceSvg} */ (this.workspace)).getRenderer().render(this); // No matter how we rendered, connection locations should now be correct. this.updateConnectionLocations_(); - // TODO: This should be handled inside a robust init method, because it would - // make it a lot cleaner, but for now it's handled here for backwards - // compatibility. - if (this.callTrackConnections_) { - this.startTrackingConnections(); - this.callTrackConnections_ = false; - } if (opt_bubble !== false) { // Render all blocks above this one (propagate a reflow). var parentBlock = this.getParent(); diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 7f6523554..b5d4aaa08 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -202,10 +202,10 @@ Blockly.navigation.insertFromFlyout = function() { var newBlock = flyout.createBlock(curBlock); // Render to get the sizing right. newBlock.render(); - // Connections are hidden when the block is first created. Normally there's - // enough time for them to become unhidden in the user's mouse movements, - // but not here. - newBlock.startTrackingConnections(); + // Connections are not tracked when the block is first created. Normally + // there's enough time for them to become tracked in the user's mouse + // movements, but not here. + newBlock.setConnectionTracking(true); workspace.getCursor().setCurNode( Blockly.ASTNode.createBlockNode(newBlock)); if (!Blockly.navigation.modify_()) { diff --git a/core/rendered_connection.js b/core/rendered_connection.js index acce573ad..67129772e 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -65,14 +65,32 @@ Blockly.RenderedConnection = function(source, type) { this.offsetInBlock_ = new Blockly.utils.Coordinate(0, 0); /** - * Whether this connections is tracked in the database or not. - * @type {boolean} + * Describes the state of this connection's tracked-ness. + * @type {Blockly.RenderedConnection.TrackedState} * @private */ - this.tracked_ = false; + this.trackedState_ = Blockly.RenderedConnection.TrackedState.WILL_TRACK; }; Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); +/** + * Enum for different kinds of tracked states. + * + * WILL_TRACK means that this connection will add itself to + * the db on the next moveTo call it receives. + * + * UNTRACKED means that this connection will not add + * itself to the database until setTracking(true) is explicitly called. + * + * TRACKED means that this connection is currently being tracked. + * @enum {number} + */ +Blockly.RenderedConnection.TrackedState = { + WILL_TRACK: -1, + UNTRACKED: 0, + TRACKED: 1 +}; + /** * Dispose of this connection. Remove it from the database (if it is * tracked) and call the super-function to deal with connected blocks. @@ -81,7 +99,7 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection); */ Blockly.RenderedConnection.prototype.dispose = function() { Blockly.RenderedConnection.superClass_.dispose.call(this); - if (this.tracked_) { + if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); } }; @@ -174,7 +192,11 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) { * @param {number} y New absolute y coordinate, in workspace coordinates. */ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { - if (this.tracked_) { + if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.WILL_TRACK) { + this.db_.addConnection(this, y); + this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED; + } else if (this.trackedState_ == Blockly.RenderedConnection + .TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); this.db_.addConnection(this, y); } @@ -307,7 +329,10 @@ Blockly.RenderedConnection.prototype.unhighlight = function() { * @package */ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { - if (doTracking == this.tracked_) { + if ((doTracking && this.trackedState_ == + Blockly.RenderedConnection.TrackedState.TRACKED) || + (!doTracking && this.trackedState_ == + Blockly.RenderedConnection.TrackedState.UNTRACKED)) { return; } if (this.sourceBlock_.isInFlyout) { @@ -316,10 +341,14 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { } if (doTracking) { this.db_.addConnection(this, this.y); - } else { + this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED; + return; + } + if (this.trackedState_ == Blockly.RenderedConnection + .TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); } - this.tracked_ = doTracking; + this.trackedState_ = Blockly.RenderedConnection.TrackedState.UNTRACKED; }; /** diff --git a/core/xml.js b/core/xml.js index f581da08f..f146b7761 100644 --- a/core/xml.js +++ b/core/xml.js @@ -545,7 +545,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { var blocks = topBlock.getDescendants(false); if (workspace.rendered) { // Wait to track connections to speed up assembly. - topBlock.waitToTrackConnections(); + topBlock.setConnectionTracking(false); // Render each block. for (var i = blocks.length - 1; i >= 0; i--) { blocks[i].initSvg(); @@ -557,7 +557,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { // blocks have rendered. setTimeout(function() { if (!topBlock.disposed) { - topBlock.startTrackingConnections(); + topBlock.setConnectionTracking(true); } }, 1); topBlock.updateDisabled(); diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index d0cc4f1a8..27b496fcb 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -19,6 +19,10 @@ suite('Blocks', function() { setup(function() { this.workspace = new Blockly.Workspace(); Blockly.defineBlocksWithJsonArray([ + { + "type": "empty_block", + "message0": "" + }, { "type": "stack_block", "message0": "", @@ -56,914 +60,1011 @@ suite('Blocks', function() { delete Blockly.Blocks['statement_block']; }); - suite('Connection Management', function() { - suite('Unplug', function() { - function assertUnpluggedNoheal(blocks) { - // A has nothing connected to it. - assertEquals(0, blocks.A.getChildren().length); - // B and C are still connected. - assertEquals(blocks.B, blocks.C.getParent()); - // B is the top of its stack. - assertNull(blocks.B.getParent()); - } - function assertUnpluggedHealed(blocks) { - // A and C are connected. - assertEquals(1, blocks.A.getChildren().length); - assertEquals(blocks.A, blocks.C.getParent()); - // B has nothing connected to it. - assertEquals(0, blocks.B.getChildren().length); - // B is the top of its stack. - assertNull(blocks.B.getParent()); - } - function assertUnpluggedHealFailed(blocks) { - // A has nothing connected to it. - assertEquals(0, blocks.A.getChildren().length); - // B has nothing connected to it. - assertEquals(0, blocks.B.getChildren().length); - // B is the top of its stack. - assertNull(blocks.B.getParent()); - // C is the top of its stack. - assertNull(blocks.C.getParent()); - } + suite('Unplug', function() { + function assertUnpluggedNoheal(blocks) { + // A has nothing connected to it. + assertEquals(0, blocks.A.getChildren().length); + // B and C are still connected. + assertEquals(blocks.B, blocks.C.getParent()); + // B is the top of its stack. + assertNull(blocks.B.getParent()); + } + function assertUnpluggedHealed(blocks) { + // A and C are connected. + assertEquals(1, blocks.A.getChildren().length); + assertEquals(blocks.A, blocks.C.getParent()); + // B has nothing connected to it. + assertEquals(0, blocks.B.getChildren().length); + // B is the top of its stack. + assertNull(blocks.B.getParent()); + } + function assertUnpluggedHealFailed(blocks) { + // A has nothing connected to it. + assertEquals(0, blocks.A.getChildren().length); + // B has nothing connected to it. + assertEquals(0, blocks.B.getChildren().length); + // B is the top of its stack. + assertNull(blocks.B.getParent()); + // C is the top of its stack. + assertNull(blocks.C.getParent()); + } - suite('Row', function() { - setup(function() { - var blockA = this.workspace.newBlock('row_block'); - var blockB = this.workspace.newBlock('row_block'); - var blockC = this.workspace.newBlock('row_block'); - - blockA.inputList[0].connection.connect(blockB.outputConnection); - blockB.inputList[0].connection.connect(blockC.outputConnection); - - assertEquals(blockB, blockC.getParent()); - - this.blocks = { - A: blockA, - B: blockB, - C: blockC - }; - }); - - test('Don\'t heal', function() { - this.blocks.B.unplug(false); - assertUnpluggedNoheal(this.blocks); - }); - test('Heal', function() { - this.blocks.B.unplug(true); - // Each block has only one input, and the types work. - assertUnpluggedHealed(this.blocks); - }); - test('Heal with bad checks', function() { - var blocks = this.blocks; - - // A and C can't connect, but both can connect to B. - blocks.A.inputList[0].connection.setCheck('type1'); - blocks.C.outputConnection.setCheck('type2'); - - // Each block has only one input, but the types don't work. - blocks.B.unplug(true); - assertUnpluggedHealFailed(blocks); - }); - test('A has multiple inputs', function() { - var blocks = this.blocks; - // Add extra input to parent - blocks.A.appendValueInput("INPUT").setCheck(null); - blocks.B.unplug(true); - assertUnpluggedHealed(blocks); - }); - test('B has multiple inputs', function() { - var blocks = this.blocks; - // Add extra input to middle block - blocks.B.appendValueInput("INPUT").setCheck(null); - blocks.B.unplug(true); - assertUnpluggedHealed(blocks); - }); - test('C has multiple inputs', function() { - var blocks = this.blocks; - // Add extra input to child block - blocks.C.appendValueInput("INPUT").setCheck(null); - // Child block input count doesn't matter. - blocks.B.unplug(true); - assertUnpluggedHealed(blocks); - }); - test('C is Shadow', function() { - var blocks = this.blocks; - blocks.C.setShadow(true); - blocks.B.unplug(true); - // Even though we're asking to heal, it will appear as if it has not - // healed because shadows always stay with the parent. - assertUnpluggedNoheal(blocks); - }); - }); - suite('Stack', function() { - setup(function() { - var blockA = this.workspace.newBlock('stack_block'); - var blockB = this.workspace.newBlock('stack_block'); - var blockC = this.workspace.newBlock('stack_block'); - - blockA.nextConnection.connect(blockB.previousConnection); - blockB.nextConnection.connect(blockC.previousConnection); - - assertEquals(blockB, blockC.getParent()); - - this.blocks = { - A: blockA, - B: blockB, - C: blockC - }; - }); - - test('Don\'t heal', function() { - this.blocks.B.unplug(); - assertUnpluggedNoheal(this.blocks); - }); - test('Heal', function() { - this.blocks.B.unplug(true); - assertUnpluggedHealed(this.blocks); - }); - test('Heal with bad checks', function() { - var blocks = this.blocks; - // A and C can't connect, but both can connect to B. - blocks.A.nextConnection.setCheck('type1'); - blocks.C.previousConnection.setCheck('type2'); - - // The types don't work. - blocks.B.unplug(true); - - assertUnpluggedHealFailed(blocks); - }); - test('C is Shadow', function() { - var blocks = this.blocks; - blocks.C.setShadow(true); - blocks.B.unplug(true); - // Even though we're asking to heal, it will appear as if it has not - // healed because shadows always stay with the parent. - assertUnpluggedNoheal(blocks); - }); - }); - }); - suite('Dispose', function() { - function assertDisposedNoheal(blocks) { - chai.assert.isFalse(blocks.A.disposed); - // A has nothing connected to it. - chai.assert.equal(0, blocks.A.getChildren().length); - // B is disposed. - chai.assert.isTrue(blocks.B.disposed); - // And C is disposed. - chai.assert.isTrue(blocks.C.disposed); - } - function assertDisposedHealed(blocks) { - chai.assert.isFalse(blocks.A.disposed); - chai.assert.isFalse(blocks.C.disposed); - // A and C are connected. - assertEquals(1, blocks.A.getChildren().length); - assertEquals(blocks.A, blocks.C.getParent()); - // B is disposed. - chai.assert.isTrue(blocks.B.disposed); - } - function assertDisposedHealFailed(blocks) { - chai.assert.isFalse(blocks.A.disposed); - chai.assert.isFalse(blocks.C.disposed); - // A has nothing connected to it. - chai.assert.equal(0, blocks.A.getChildren().length); - // B is disposed. - chai.assert.isTrue(blocks.B.disposed); - // C is the top of its stack. - assertNull(blocks.C.getParent()); - } - - suite('Row', function() { - setup(function() { - var blockA = this.workspace.newBlock('row_block'); - var blockB = this.workspace.newBlock('row_block'); - var blockC = this.workspace.newBlock('row_block'); - - blockA.inputList[0].connection.connect(blockB.outputConnection); - blockB.inputList[0].connection.connect(blockC.outputConnection); - - assertEquals(blockB, blockC.getParent()); - - this.blocks = { - A: blockA, - B: blockB, - C: blockC - }; - }); - - test('Don\'t heal', function() { - this.blocks.B.dispose(false); - assertDisposedNoheal(this.blocks); - }); - test('Heal', function() { - this.blocks.B.dispose(true); - // Each block has only one input, and the types work. - assertDisposedHealed(this.blocks); - }); - test('Heal with bad checks', function() { - var blocks = this.blocks; - - // A and C can't connect, but both can connect to B. - blocks.A.inputList[0].connection.setCheck('type1'); - blocks.C.outputConnection.setCheck('type2'); - - // Each block has only one input, but the types don't work. - blocks.B.dispose(true); - assertDisposedHealFailed(blocks); - }); - test('A has multiple inputs', function() { - var blocks = this.blocks; - // Add extra input to parent - blocks.A.appendValueInput("INPUT").setCheck(null); - blocks.B.dispose(true); - assertDisposedHealed(blocks); - }); - test('B has multiple inputs', function() { - var blocks = this.blocks; - // Add extra input to middle block - blocks.B.appendValueInput("INPUT").setCheck(null); - blocks.B.dispose(true); - assertDisposedHealed(blocks); - }); - test('C has multiple inputs', function() { - var blocks = this.blocks; - // Add extra input to child block - blocks.C.appendValueInput("INPUT").setCheck(null); - // Child block input count doesn't matter. - blocks.B.dispose(true); - assertDisposedHealed(blocks); - }); - test('C is Shadow', function() { - var blocks = this.blocks; - blocks.C.setShadow(true); - blocks.B.dispose(true); - // Even though we're asking to heal, it will appear as if it has not - // healed because shadows always get destroyed. - assertDisposedNoheal(blocks); - }); - }); - suite('Stack', function() { - setup(function() { - var blockA = this.workspace.newBlock('stack_block'); - var blockB = this.workspace.newBlock('stack_block'); - var blockC = this.workspace.newBlock('stack_block'); - - blockA.nextConnection.connect(blockB.previousConnection); - blockB.nextConnection.connect(blockC.previousConnection); - - assertEquals(blockB, blockC.getParent()); - - this.blocks = { - A: blockA, - B: blockB, - C: blockC - }; - }); - - test('Don\'t heal', function() { - this.blocks.B.dispose(); - assertDisposedNoheal(this.blocks); - }); - test('Heal', function() { - this.blocks.B.dispose(true); - assertDisposedHealed(this.blocks); - }); - test('Heal with bad checks', function() { - var blocks = this.blocks; - // A and C can't connect, but both can connect to B. - blocks.A.nextConnection.setCheck('type1'); - blocks.C.previousConnection.setCheck('type2'); - - // The types don't work. - blocks.B.dispose(true); - - assertDisposedHealFailed(blocks); - }); - test('C is Shadow', function() { - var blocks = this.blocks; - blocks.C.setShadow(true); - blocks.B.dispose(true); - // Even though we're asking to heal, it will appear as if it has not - // healed because shadows always get destroyed. - assertDisposedNoheal(blocks); - }); - }); - }); - suite('Remove Input', function() { + suite('Row', function() { setup(function() { - Blockly.defineBlocksWithJsonArray([ - { - "type": "value_block", - "message0": "%1", - "args0": [ - { - "type": "input_value", - "name": "VALUE" - } - ] - }, - { - "type": "statement_block", - "message0": "%1", - "args0": [ - { - "type": "input_statement", - "name": "STATEMENT" - } - ] - }, - ]); - }); - teardown(function() { - delete Blockly.Blocks['value_block']; - delete Blockly.Blocks['statement_block']; + var blockA = this.workspace.newBlock('row_block'); + var blockB = this.workspace.newBlock('row_block'); + var blockC = this.workspace.newBlock('row_block'); + + blockA.inputList[0].connection.connect(blockB.outputConnection); + blockB.inputList[0].connection.connect(blockC.outputConnection); + + assertEquals(blockB, blockC.getParent()); + + this.blocks = { + A: blockA, + B: blockB, + C: blockC + }; }); - suite('Value', function() { - setup(function() { - this.blockA = this.workspace.newBlock('value_block'); - }); - - test('No Connected', function() { - this.blockA.removeInput('VALUE'); - chai.assert.isNull(this.blockA.getInput('VALUE')); - }); - test('Block Connected', function() { - var blockB = this.workspace.newBlock('row_block'); - this.blockA.getInput('VALUE').connection - .connect(blockB.outputConnection); - - this.blockA.removeInput('VALUE'); - chai.assert.isFalse(blockB.disposed); - chai.assert.equal(this.blockA.getChildren().length, 0); - }); - test('Shadow Connected', function() { - var blockB = this.workspace.newBlock('row_block'); - blockB.setShadow(true); - this.blockA.getInput('VALUE').connection - .connect(blockB.outputConnection); - - this.blockA.removeInput('VALUE'); - chai.assert.isTrue(blockB.disposed); - chai.assert.equal(this.blockA.getChildren().length, 0); - }); + test('Don\'t heal', function() { + this.blocks.B.unplug(false); + assertUnpluggedNoheal(this.blocks); }); - suite('Statement', function() { - setup(function() { - this.blockA = this.workspace.newBlock('statement_block'); - }); + test('Heal', function() { + this.blocks.B.unplug(true); + // Each block has only one input, and the types work. + assertUnpluggedHealed(this.blocks); + }); + test('Heal with bad checks', function() { + var blocks = this.blocks; - test('No Connected', function() { - this.blockA.removeInput('STATEMENT'); - chai.assert.isNull(this.blockA.getInput('STATEMENT')); - }); - test('Block Connected', function() { - var blockB = this.workspace.newBlock('stack_block'); - this.blockA.getInput('STATEMENT').connection - .connect(blockB.previousConnection); + // A and C can't connect, but both can connect to B. + blocks.A.inputList[0].connection.setCheck('type1'); + blocks.C.outputConnection.setCheck('type2'); - this.blockA.removeInput('STATEMENT'); - chai.assert.isFalse(blockB.disposed); - chai.assert.equal(this.blockA.getChildren().length, 0); - }); - test('Shadow Connected', function() { - var blockB = this.workspace.newBlock('stack_block'); - blockB.setShadow(true); - this.blockA.getInput('STATEMENT').connection - .connect(blockB.previousConnection); - - this.blockA.removeInput('STATEMENT'); - chai.assert.isTrue(blockB.disposed); - chai.assert.equal(this.blockA.getChildren().length, 0); - }); + // Each block has only one input, but the types don't work. + blocks.B.unplug(true); + assertUnpluggedHealFailed(blocks); + }); + test('A has multiple inputs', function() { + var blocks = this.blocks; + // Add extra input to parent + blocks.A.appendValueInput("INPUT").setCheck(null); + blocks.B.unplug(true); + assertUnpluggedHealed(blocks); + }); + test('B has multiple inputs', function() { + var blocks = this.blocks; + // Add extra input to middle block + blocks.B.appendValueInput("INPUT").setCheck(null); + blocks.B.unplug(true); + assertUnpluggedHealed(blocks); + }); + test('C has multiple inputs', function() { + var blocks = this.blocks; + // Add extra input to child block + blocks.C.appendValueInput("INPUT").setCheck(null); + // Child block input count doesn't matter. + blocks.B.unplug(true); + assertUnpluggedHealed(blocks); + }); + test('C is Shadow', function() { + var blocks = this.blocks; + blocks.C.setShadow(true); + blocks.B.unplug(true); + // Even though we're asking to heal, it will appear as if it has not + // healed because shadows always stay with the parent. + assertUnpluggedNoheal(blocks); }); }); - suite('Connection Tracking', function() { + suite('Stack', function() { setup(function() { - this.workspace.dispose(); - // The new rendered workspace will get disposed by the parent teardown. - this.workspace = Blockly.inject('blocklyDiv'); + var blockA = this.workspace.newBlock('stack_block'); + var blockB = this.workspace.newBlock('stack_block'); + var blockC = this.workspace.newBlock('stack_block'); - this.getInputs = function() { - return this.workspace - .connectionDBList[Blockly.INPUT_VALUE].connections_; - }; - this.getOutputs = function() { - return this.workspace - .connectionDBList[Blockly.OUTPUT_VALUE].connections_; - }; - this.getNext = function() { - return this.workspace - .connectionDBList[Blockly.NEXT_STATEMENT].connections_; - }; - this.getPrevious = function() { - return this.workspace - .connectionDBList[Blockly.PREVIOUS_STATEMENT].connections_; - }; + blockA.nextConnection.connect(blockB.previousConnection); + blockB.nextConnection.connect(blockC.previousConnection); - this.assertConnectionsEmpty = function() { - chai.assert.isEmpty(this.getInputs()); - chai.assert.isEmpty(this.getOutputs()); - chai.assert.isEmpty(this.getNext()); - chai.assert.isEmpty(this.getPrevious()); - }; + assertEquals(blockB, blockC.getParent()); - this.clock = sinon.useFakeTimers(); + this.blocks = { + A: blockA, + B: blockB, + C: blockC + }; }); - teardown(function() { - this.clock.restore(); + + test('Don\'t heal', function() { + this.blocks.B.unplug(); + assertUnpluggedNoheal(this.blocks); }); - suite('Deserialization', function() { - test('Stack', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); - }); - test('Multi-Stack', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 3); - }); - test('Collapsed Stack', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); - }); - test('Collapsed Multi-Stack', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 3); - }); - test('Row', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 1); - }); - test('Multi-Row', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); - }); - test('Collapsed Row', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 0); - }); - test('Collapsed Multi-Row', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 0); - }); - test('Collapsed Multi-Row Middle', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 2); - chai.assert.equal(this.getInputs().length, 1); - }); - test('Statement', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 2); - }); - test('Multi-Statement', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); - }); - test('Collapsed Statement', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); - }); - test('Collapsed Multi-Statement', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); - }); - test('Collapsed Multi-Statement Middle', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 2); - chai.assert.equal(this.getNext().length, 3); - }); + test('Heal', function() { + this.blocks.B.unplug(true); + assertUnpluggedHealed(this.blocks); }); - suite('Programmatic Block Creation', function() { - test('Stack', function() { - var block = this.workspace.newBlock('stack_block'); - this.assertConnectionsEmpty(); - block.initSvg(); - block.render(); + test('Heal with bad checks', function() { + var blocks = this.blocks; + // A and C can't connect, but both can connect to B. + blocks.A.nextConnection.setCheck('type1'); + blocks.C.previousConnection.setCheck('type2'); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); - }); - test('Row', function() { - var block = this.workspace.newBlock('row_block'); - this.assertConnectionsEmpty(); - block.initSvg(); - block.render(); + // The types don't work. + blocks.B.unplug(true); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 1); - }); - test('Statement', function() { - var block = this.workspace.newBlock('statement_block'); - this.assertConnectionsEmpty(); - block.initSvg(); - block.render(); - - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 2); - }); + assertUnpluggedHealFailed(blocks); }); - suite('setCollapsed', function() { - test('Stack', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' - ), this.workspace); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); + test('C is Shadow', function() { + var blocks = this.blocks; + blocks.C.setShadow(true); + blocks.B.unplug(true); + // Even though we're asking to heal, it will appear as if it has not + // healed because shadows always stay with the parent. + assertUnpluggedNoheal(blocks); + }); + }); + }); + suite('Dispose', function() { + function assertDisposedNoheal(blocks) { + chai.assert.isFalse(blocks.A.disposed); + // A has nothing connected to it. + chai.assert.equal(0, blocks.A.getChildren().length); + // B is disposed. + chai.assert.isTrue(blocks.B.disposed); + // And C is disposed. + chai.assert.isTrue(blocks.C.disposed); + } + function assertDisposedHealed(blocks) { + chai.assert.isFalse(blocks.A.disposed); + chai.assert.isFalse(blocks.C.disposed); + // A and C are connected. + assertEquals(1, blocks.A.getChildren().length); + assertEquals(blocks.A, blocks.C.getParent()); + // B is disposed. + chai.assert.isTrue(blocks.B.disposed); + } + function assertDisposedHealFailed(blocks) { + chai.assert.isFalse(blocks.A.disposed); + chai.assert.isFalse(blocks.C.disposed); + // A has nothing connected to it. + chai.assert.equal(0, blocks.A.getChildren().length); + // B is disposed. + chai.assert.isTrue(blocks.B.disposed); + // C is the top of its stack. + assertNull(blocks.C.getParent()); + } - block.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); + suite('Row', function() { + setup(function() { + var blockA = this.workspace.newBlock('row_block'); + var blockB = this.workspace.newBlock('row_block'); + var blockC = this.workspace.newBlock('row_block'); - block.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); - }); - test('Multi-Stack', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 3); + blockA.inputList[0].connection.connect(blockB.outputConnection); + blockB.inputList[0].connection.connect(blockC.outputConnection); - block.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 3); + assertEquals(blockB, blockC.getParent()); - block.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 3); - }); - test('Row', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' - ), this.workspace); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 1); + this.blocks = { + A: blockA, + B: blockB, + C: blockC + }; + }); - block.setCollapsed(true); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 0); + test('Don\'t heal', function() { + this.blocks.B.dispose(false); + assertDisposedNoheal(this.blocks); + }); + test('Heal', function() { + this.blocks.B.dispose(true); + // Each block has only one input, and the types work. + assertDisposedHealed(this.blocks); + }); + test('Heal with bad checks', function() { + var blocks = this.blocks; - block.setCollapsed(false); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 1); - }); - test('Multi-Row', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); + // A and C can't connect, but both can connect to B. + blocks.A.inputList[0].connection.setCheck('type1'); + blocks.C.outputConnection.setCheck('type2'); - block.setCollapsed(true); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 0); + // Each block has only one input, but the types don't work. + blocks.B.dispose(true); + assertDisposedHealFailed(blocks); + }); + test('A has multiple inputs', function() { + var blocks = this.blocks; + // Add extra input to parent + blocks.A.appendValueInput("INPUT").setCheck(null); + blocks.B.dispose(true); + assertDisposedHealed(blocks); + }); + test('B has multiple inputs', function() { + var blocks = this.blocks; + // Add extra input to middle block + blocks.B.appendValueInput("INPUT").setCheck(null); + blocks.B.dispose(true); + assertDisposedHealed(blocks); + }); + test('C has multiple inputs', function() { + var blocks = this.blocks; + // Add extra input to child block + blocks.C.appendValueInput("INPUT").setCheck(null); + // Child block input count doesn't matter. + blocks.B.dispose(true); + assertDisposedHealed(blocks); + }); + test('C is Shadow', function() { + var blocks = this.blocks; + blocks.C.setShadow(true); + blocks.B.dispose(true); + // Even though we're asking to heal, it will appear as if it has not + // healed because shadows always get destroyed. + assertDisposedNoheal(blocks); + }); + }); + suite('Stack', function() { + setup(function() { + var blockA = this.workspace.newBlock('stack_block'); + var blockB = this.workspace.newBlock('stack_block'); + var blockC = this.workspace.newBlock('stack_block'); - block.setCollapsed(false); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); - }); - test('Multi-Row Middle', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); + blockA.nextConnection.connect(blockB.previousConnection); + blockB.nextConnection.connect(blockC.previousConnection); - block = block.getInputTargetBlock('INPUT'); - block.setCollapsed(true); - chai.assert.equal(this.getOutputs().length, 2); - chai.assert.equal(this.getInputs().length, 1); + assertEquals(blockB, blockC.getParent()); - block.setCollapsed(false); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); - }); - test('Multi-Row Double Collapse', function() { - // Collapse middle -> Collapse top -> - // Uncollapse top -> Uncollapse middle - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.clock.tick(1); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); + this.blocks = { + A: blockA, + B: blockB, + C: blockC + }; + }); - var middleBlock = block.getInputTargetBlock('INPUT'); - middleBlock.setCollapsed(true); - chai.assert.equal(this.getOutputs().length, 2); - chai.assert.equal(this.getInputs().length, 1); + test('Don\'t heal', function() { + this.blocks.B.dispose(); + assertDisposedNoheal(this.blocks); + }); + test('Heal', function() { + this.blocks.B.dispose(true); + assertDisposedHealed(this.blocks); + }); + test('Heal with bad checks', function() { + var blocks = this.blocks; + // A and C can't connect, but both can connect to B. + blocks.A.nextConnection.setCheck('type1'); + blocks.C.previousConnection.setCheck('type2'); - block.setCollapsed(true); - chai.assert.equal(this.getOutputs().length, 1); - chai.assert.equal(this.getInputs().length, 0); + // The types don't work. + blocks.B.dispose(true); - block.setCollapsed(false); - chai.assert.equal(this.getOutputs().length, 2); - chai.assert.equal(this.getInputs().length, 1); + assertDisposedHealFailed(blocks); + }); + test('C is Shadow', function() { + var blocks = this.blocks; + blocks.C.setShadow(true); + blocks.B.dispose(true); + // Even though we're asking to heal, it will appear as if it has not + // healed because shadows always get destroyed. + assertDisposedNoheal(blocks); + }); + }); + }); + suite('Remove Input', function() { + setup(function() { + Blockly.defineBlocksWithJsonArray([ + { + "type": "value_block", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "VALUE" + } + ] + }, + { + "type": "statement_block", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "STATEMENT" + } + ] + }, + ]); + }); + teardown(function() { + delete Blockly.Blocks['value_block']; + delete Blockly.Blocks['statement_block']; + }); - middleBlock.setCollapsed(false); - chai.assert.equal(this.getOutputs().length, 3); - chai.assert.equal(this.getInputs().length, 3); - }); - test('Statement', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' - ), this.workspace); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 2); + suite('Value', function() { + setup(function() { + this.blockA = this.workspace.newBlock('value_block'); + }); - block.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); + test('No Connected', function() { + this.blockA.removeInput('VALUE'); + chai.assert.isNull(this.blockA.getInput('VALUE')); + }); + test('Block Connected', function() { + var blockB = this.workspace.newBlock('row_block'); + this.blockA.getInput('VALUE').connection + .connect(blockB.outputConnection); - block.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 2); - }); - test('Multi-Statement', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); + this.blockA.removeInput('VALUE'); + chai.assert.isFalse(blockB.disposed); + chai.assert.equal(this.blockA.getChildren().length, 0); + }); + test('Shadow Connected', function() { + var blockB = this.workspace.newBlock('row_block'); + blockB.setShadow(true); + this.blockA.getInput('VALUE').connection + .connect(blockB.outputConnection); - block.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); + this.blockA.removeInput('VALUE'); + chai.assert.isTrue(blockB.disposed); + chai.assert.equal(this.blockA.getChildren().length, 0); + }); + }); + suite('Statement', function() { + setup(function() { + this.blockA = this.workspace.newBlock('statement_block'); + }); - block.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); - }); - test('Multi-Statement Middle', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); + test('No Connected', function() { + this.blockA.removeInput('STATEMENT'); + chai.assert.isNull(this.blockA.getInput('STATEMENT')); + }); + test('Block Connected', function() { + var blockB = this.workspace.newBlock('stack_block'); + this.blockA.getInput('STATEMENT').connection + .connect(blockB.previousConnection); - block = block.getInputTargetBlock('STATEMENT'); - block.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 2); - chai.assert.equal(this.getNext().length, 3); + this.blockA.removeInput('STATEMENT'); + chai.assert.isFalse(blockB.disposed); + chai.assert.equal(this.blockA.getChildren().length, 0); + }); + test('Shadow Connected', function() { + var blockB = this.workspace.newBlock('stack_block'); + blockB.setShadow(true); + this.blockA.getInput('STATEMENT').connection + .connect(blockB.previousConnection); - block.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); - }); - test('Multi-Statement Double Collapse', function() { - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' - ), this.workspace); - this.assertConnectionsEmpty(); - this.clock.tick(1); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); + this.blockA.removeInput('STATEMENT'); + chai.assert.isTrue(blockB.disposed); + chai.assert.equal(this.blockA.getChildren().length, 0); + }); + }); + }); + suite('Connection Tracking', function() { + setup(function() { + this.workspace.dispose(); + // The new rendered workspace will get disposed by the parent teardown. + this.workspace = Blockly.inject('blocklyDiv'); - var middleBlock = block.getInputTargetBlock('STATEMENT'); - middleBlock.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 2); - chai.assert.equal(this.getNext().length, 3); + this.getInputs = function() { + return this.workspace + .connectionDBList[Blockly.INPUT_VALUE].connections_; + }; + this.getOutputs = function() { + return this.workspace + .connectionDBList[Blockly.OUTPUT_VALUE].connections_; + }; + this.getNext = function() { + return this.workspace + .connectionDBList[Blockly.NEXT_STATEMENT].connections_; + }; + this.getPrevious = function() { + return this.workspace + .connectionDBList[Blockly.PREVIOUS_STATEMENT].connections_; + }; - block.setCollapsed(true); - chai.assert.equal(this.getPrevious().length, 1); - chai.assert.equal(this.getNext().length, 1); + this.assertConnectionsEmpty = function() { + chai.assert.isEmpty(this.getInputs()); + chai.assert.isEmpty(this.getOutputs()); + chai.assert.isEmpty(this.getNext()); + chai.assert.isEmpty(this.getPrevious()); + }; - block.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 2); - chai.assert.equal(this.getNext().length, 3); + this.clock = sinon.useFakeTimers(); + }); + teardown(function() { + this.clock.restore(); + }); + suite('Deserialization', function() { + test('Stack', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + test('Multi-Stack', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 3); + }); + test('Collapsed Stack', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + test('Collapsed Multi-Stack', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 3); + }); + test('Row', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 1); + }); + test('Multi-Row', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + }); + test('Collapsed Row', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 0); + }); + test('Collapsed Multi-Row', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 0); + }); + test('Collapsed Multi-Row Middle', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 2); + chai.assert.equal(this.getInputs().length, 1); + }); + test('Statement', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 2); + }); + test('Multi-Statement', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + }); + test('Collapsed Statement', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + test('Collapsed Multi-Statement', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + test('Collapsed Multi-Statement Middle', function() { + Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 2); + chai.assert.equal(this.getNext().length, 3); + }); + }); + suite('Programmatic Block Creation', function() { + test('Stack', function() { + var block = this.workspace.newBlock('stack_block'); + this.assertConnectionsEmpty(); + block.initSvg(); + block.render(); - middleBlock.setCollapsed(false); - chai.assert.equal(this.getPrevious().length, 3); - chai.assert.equal(this.getNext().length, 6); - }); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + test('Row', function() { + var block = this.workspace.newBlock('row_block'); + this.assertConnectionsEmpty(); + block.initSvg(); + block.render(); + + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 1); + }); + test('Statement', function() { + var block = this.workspace.newBlock('statement_block'); + this.assertConnectionsEmpty(); + block.initSvg(); + block.render(); + + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 2); + }); + }); + suite('setCollapsed', function() { + test('Stack', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), this.workspace); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + + block.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + + block.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + test('Multi-Stack', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 3); + + block.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 3); + + block.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 3); + }); + test('Row', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), this.workspace); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 1); + + block.setCollapsed(true); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 0); + + block.setCollapsed(false); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 1); + }); + test('Multi-Row', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + + block.setCollapsed(true); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 0); + + block.setCollapsed(false); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + }); + test('Multi-Row Middle', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + + block = block.getInputTargetBlock('INPUT'); + block.setCollapsed(true); + chai.assert.equal(this.getOutputs().length, 2); + chai.assert.equal(this.getInputs().length, 1); + + block.setCollapsed(false); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + }); + test('Multi-Row Double Collapse', function() { + // Collapse middle -> Collapse top -> + // Uncollapse top -> Uncollapse middle + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.clock.tick(1); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + + var middleBlock = block.getInputTargetBlock('INPUT'); + middleBlock.setCollapsed(true); + chai.assert.equal(this.getOutputs().length, 2); + chai.assert.equal(this.getInputs().length, 1); + + block.setCollapsed(true); + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 0); + + block.setCollapsed(false); + chai.assert.equal(this.getOutputs().length, 2); + chai.assert.equal(this.getInputs().length, 1); + + middleBlock.setCollapsed(false); + chai.assert.equal(this.getOutputs().length, 3); + chai.assert.equal(this.getInputs().length, 3); + }); + test('Statement', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), this.workspace); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 2); + + block.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + + block.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 2); + }); + test('Multi-Statement', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + + block.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + + block.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + }); + test('Multi-Statement Middle', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + + block = block.getInputTargetBlock('STATEMENT'); + block.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 2); + chai.assert.equal(this.getNext().length, 3); + + block.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + }); + test('Multi-Statement Double Collapse', function() { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), this.workspace); + this.assertConnectionsEmpty(); + this.clock.tick(1); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + + var middleBlock = block.getInputTargetBlock('STATEMENT'); + middleBlock.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 2); + chai.assert.equal(this.getNext().length, 3); + + block.setCollapsed(true); + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + + block.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 2); + chai.assert.equal(this.getNext().length, 3); + + middleBlock.setCollapsed(false); + chai.assert.equal(this.getPrevious().length, 3); + chai.assert.equal(this.getNext().length, 6); + }); + }); + suite('Remove Connections Programmatically', function() { + test('Output', function() { + var block = this.workspace.newBlock('row_block'); + block.initSvg(); + block.render(); + + block.setOutput(false); + + chai.assert.equal(this.getOutputs().length, 0); + chai.assert.equal(this.getInputs().length, 1); + }); + test('Value', function() { + var block = this.workspace.newBlock('row_block'); + block.initSvg(); + block.render(); + + block.removeInput('INPUT'); + + chai.assert.equal(this.getOutputs().length, 1); + chai.assert.equal(this.getInputs().length, 0); + }); + test('Previous', function() { + var block = this.workspace.newBlock('stack_block'); + block.initSvg(); + block.render(); + + block.setPreviousStatement(false); + + chai.assert.equal(this.getPrevious().length, 0); + chai.assert.equal(this.getNext().length, 1); + }); + test('Next', function() { + var block = this.workspace.newBlock('stack_block'); + block.initSvg(); + block.render(); + + block.setNextStatement(false); + + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 0); + }); + test('Statement', function() { + var block = this.workspace.newBlock('statement_block'); + block.initSvg(); + block.render(); + + block.removeInput('STATEMENT'); + + chai.assert.equal(this.getPrevious().length, 1); + chai.assert.equal(this.getNext().length, 1); + }); + }); + suite('Add Connections Programmatically', function() { + test('Output', function() { + var block = this.workspace.newBlock('empty_block'); + block.initSvg(); + block.render(); + + block.setOutput(true); + + chai.assert.equal(this.getOutputs().length, 1); + }); + test('Value', function() { + var block = this.workspace.newBlock('empty_block'); + block.initSvg(); + block.render(); + + block.appendValueInput('INPUT'); + + chai.assert.equal(this.getInputs().length, 1); + }); + test('Previous', function() { + var block = this.workspace.newBlock('empty_block'); + block.initSvg(); + block.render(); + + block.setPreviousStatement(true); + + chai.assert.equal(this.getPrevious().length, 1); + }); + test('Next', function() { + var block = this.workspace.newBlock('empty_block'); + block.initSvg(); + block.render(); + + block.setNextStatement(true); + + chai.assert.equal(this.getNext().length, 1); + }); + test('Statement', function() { + var block = this.workspace.newBlock('empty_block'); + block.initSvg(); + block.render(); + + block.appendStatementInput('STATEMENT'); + + chai.assert.equal(this.getNext().length, 1); }); }); }); From 7d174727b00eb3deb9a7695483c49fe52eb824e5 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 08:11:18 -0700 Subject: [PATCH 121/343] Fix warnings for code used by blocks (#3362) --- core/block.js | 14 ++++++++++++++ core/block_svg.js | 6 ++++++ core/connection.js | 1 - core/contextmenu.js | 12 ++++-------- core/field.js | 2 +- core/keyboard_nav/ast_node.js | 2 ++ core/renderers/measurables/connections.js | 2 +- core/renderers/zelos/info.js | 6 +----- core/utils/dom.js | 2 +- core/workspace_svg.js | 10 ++++------ 10 files changed, 34 insertions(+), 23 deletions(-) diff --git a/core/block.js b/core/block.js index 827887e1d..c61bc1280 100644 --- a/core/block.js +++ b/core/block.js @@ -279,6 +279,20 @@ Blockly.Block.prototype.colourTertiary_ = null; */ Blockly.Block.prototype.styleName_ = null; +/** + * An optional method called during initialization. + * @type {?function()} + */ +Blockly.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)} + */ +Blockly.Block.prototype.onchange; + /** * An optional serialization method for defining how to serialize the * mutation state. This must be coupled with defining `domToMutation`. diff --git a/core/block_svg.js b/core/block_svg.js index a1fb14f09..ebbba039c 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -238,6 +238,12 @@ Blockly.BlockSvg.prototype.decompose; */ Blockly.BlockSvg.prototype.compose; +/** + * An optional method for defining custom block context menu items. + * @type {?function(!Array.)} + */ +Blockly.BlockSvg.prototype.customContextMenu; + /** * An property used internally to reference the block's rendering debugger. * @type {?Blockly.blockRendering.Debug} diff --git a/core/connection.js b/core/connection.js index 91227f424..fabc9fff6 100644 --- a/core/connection.js +++ b/core/connection.js @@ -606,7 +606,6 @@ Blockly.Connection.prototype.targetBlock = function() { * value type system. E.g. square_root("Hello") is not compatible. * @param {!Blockly.Connection} otherConnection Connection to compare against. * @return {boolean} True if the connections share a type. - * @package */ Blockly.Connection.prototype.checkType = function(otherConnection) { if (!this.check_ || !otherConnection.check_) { diff --git a/core/contextmenu.js b/core/contextmenu.js index 48aa337ea..efbf0c981 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -300,12 +300,10 @@ Blockly.ContextMenu.blockCommentOption = function(block) { * right-click originated. * @return {!Object} A menu option, containing text, enabled, and a callback. * @package - * @suppress {checkTypes} Suppress checks while workspace comments are not - * bundled in. */ Blockly.ContextMenu.commentDeleteOption = function(comment) { var deleteOption = { - text: Blockly.Msg.REMOVE_COMMENT, + text: Blockly.Msg['REMOVE_COMMENT'], enabled: true, callback: function() { Blockly.Events.setGroup(true); @@ -322,12 +320,10 @@ Blockly.ContextMenu.commentDeleteOption = function(comment) { * right-click originated. * @return {!Object} A menu option, containing text, enabled, and a callback. * @package - * @suppress {checkTypes} Suppress checks while workspace comments are not - * bundled in. */ Blockly.ContextMenu.commentDuplicateOption = function(comment) { var duplicateOption = { - text: Blockly.Msg.DUPLICATE_COMMENT, + text: Blockly.Msg['DUPLICATE_COMMENT'], enabled: true, callback: function() { Blockly.duplicate(comment); @@ -354,7 +350,7 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { // location of the mouse event. var addWsComment = function() { var comment = new Blockly.WorkspaceCommentSvg( - ws, Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT, + ws, Blockly.Msg['WORKSPACE_COMMENT_DEFAULT_TEXT'], Blockly.WorkspaceCommentSvg.DEFAULT_SIZE, Blockly.WorkspaceCommentSvg.DEFAULT_SIZE); @@ -394,7 +390,7 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { // that they won't be able to edit. enabled: !Blockly.utils.userAgent.IE }; - wsCommentOption.text = Blockly.Msg.ADD_COMMENT; + wsCommentOption.text = Blockly.Msg['ADD_COMMENT']; wsCommentOption.callback = function() { addWsComment(); }; diff --git a/core/field.js b/core/field.js index 27c0b6220..ee7cc7d17 100644 --- a/core/field.js +++ b/core/field.js @@ -259,7 +259,7 @@ Blockly.Field.prototype.SERIALIZABLE = false; /** * Point size of text. Should match blocklyText's font-size in CSS. - * @const {string} + * @const {number} */ Blockly.Field.FONTSIZE = 11; diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index 2721b8c4e..da885b59f 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -23,6 +23,8 @@ goog.provide('Blockly.ASTNode'); +goog.require('Blockly.utils.Coordinate'); + /** * Class for an AST node. diff --git a/core/renderers/measurables/connections.js b/core/renderers/measurables/connections.js index 098c3f5d7..abcc75070 100644 --- a/core/renderers/measurables/connections.js +++ b/core/renderers/measurables/connections.js @@ -47,7 +47,7 @@ Blockly.blockRendering.Connection = function(constants, connectionModel) { constants); this.connectionModel = connectionModel; this.shape = this.constants_.shapeFor(connectionModel); - this.isDynamicShape = !!this.shape.isDynamic; + this.isDynamicShape = !!this.shape['isDynamic']; this.type |= Blockly.blockRendering.Types.CONNECTION; }; Blockly.utils.object.inherits(Blockly.blockRendering.Connection, diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index 9ddc7fc51..b8a2dfd90 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -252,11 +252,7 @@ Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { }; /** - * Create a spacer row to go between prev and next, and set its size. - * @param {?Blockly.blockRendering.Row} prev The previous row, or null. - * @param {?Blockly.blockRendering.Row} next The next row, or null. - * @return {!Blockly.blockRendering.SpacerRow} The newly created spacer row. - * @protected + * @override */ Blockly.zelos.RenderInfo.prototype.makeSpacerRow_ = function(prev, next) { var height = this.getSpacerRowHeight_(prev, next); diff --git a/core/utils/dom.js b/core/utils/dom.js index dfacc4188..a659cfe08 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -284,7 +284,7 @@ Blockly.utils.dom.getTextWidth = function(textElement) { * This method requires that we know the text element's font family and size in * advance. Similar to `getTextWidth`, we cache the width we compute. * @param {!Element} textElement An SVG 'text' element. - * @param {string} fontSize The font size to use. + * @param {number} fontSize The font size to use. * @param {string} fontFamily The font family to use. * @return {number} Width of element. */ diff --git a/core/workspace_svg.js b/core/workspace_svg.js index a4af7e3c8..9efe86b06 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -44,6 +44,8 @@ goog.require('Blockly.WorkspaceAudio'); goog.require('Blockly.WorkspaceDragSurfaceSvg'); goog.require('Blockly.Xml'); +goog.requireType('Blockly.blockRendering.Renderer'); + /** * Class for a workspace. This is an onscreen area with optional trashcan, @@ -1308,7 +1310,6 @@ Blockly.WorkspaceSvg.prototype.refreshToolboxSelection = function() { * flyout to show the renamed variable immediately. * @param {string} id ID of the variable to rename. * @param {string} newName New variable name. - * @package */ Blockly.WorkspaceSvg.prototype.renameVariableById = function(id, newName) { Blockly.WorkspaceSvg.superClass_.renameVariableById.call(this, id, newName); @@ -1319,7 +1320,6 @@ Blockly.WorkspaceSvg.prototype.renameVariableById = function(id, newName) { * Delete a variable by the passed in ID. Update the flyout to show * immediately that the variable is deleted. * @param {string} id ID of variable to delete. - * @package */ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) { Blockly.WorkspaceSvg.superClass_.deleteVariableById.call(this, id); @@ -1336,7 +1336,6 @@ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) { * @param {?string=} opt_id The unique ID of the variable. This will default to * a UUID. * @return {!Blockly.VariableModel} The newly created variable. - * @package */ Blockly.WorkspaceSvg.prototype.createVariable = function(name, opt_type, opt_id) { @@ -1465,7 +1464,6 @@ Blockly.WorkspaceSvg.prototype.isContentBounded = function() { * the mouse position). This does not include zooming with the zoom controls * since the X Y coordinates are decided programmatically. * @return {boolean} True if the workspace is movable, false otherwise. - * @package */ Blockly.WorkspaceSvg.prototype.isMovable = function() { return (this.options.moveOptions && this.options.moveOptions.scrollbars) || @@ -2265,7 +2263,7 @@ Blockly.WorkspaceSvg.getContentDimensionsBounded_ = function(ws, svgSize) { * @return {!Object} Contains size and position metrics of a top level * workspace. * @private - * @this Blockly.WorkspaceSvg + * @this {Blockly.WorkspaceSvg} */ Blockly.WorkspaceSvg.getTopLevelWorkspaceMetrics_ = function() { @@ -2347,7 +2345,7 @@ Blockly.WorkspaceSvg.getTopLevelWorkspaceMetrics_ = function() { * @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 {Blockly.WorkspaceSvg} */ Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { var metrics = this.getMetrics(); From f3d978d5536f95492665308478e787a41a761335 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 09:53:36 -0700 Subject: [PATCH 122/343] Add an RLM after Flyout button text for RTL languages (#3366) * Add an RLM after Flyout button text for RTL languages --- core/flyout_button.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/flyout_button.js b/core/flyout_button.js index 700933a06..84898cf37 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -152,7 +152,12 @@ Blockly.FlyoutButton.prototype.createDom = function() { 'text-anchor': 'middle' }, this.svgGroup_); - svgText.textContent = Blockly.utils.replaceMessageReferences(this.text_); + var text = Blockly.utils.replaceMessageReferences(this.text_); + if (this.workspace_.RTL) { + // Force text to be RTL by adding an RLM. + text += '\u200F'; + } + svgText.textContent = text; if (this.isLabel_) { this.svgText_ = svgText; this.workspace_.getThemeManager().subscribe(this.svgText_, 'flyoutText', 'fill'); From f79740c087adf3f9d4b17bc8bb76d50fca3d2946 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 10:59:24 -0700 Subject: [PATCH 123/343] Use zero height / width for compute canvas (#3369) * Make the blockly compute canvas have no height or width --- core/css.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/css.js b/core/css.js index 8eca3fe0c..a59640bae 100644 --- a/core/css.js +++ b/core/css.js @@ -772,6 +772,12 @@ Blockly.Css.CONTENT = [ '.blocklyDropDownDiv .goog-menuitem-rtl .goog-menuitem-icon {', 'float: right;', 'margin-right: -24px;', - '}' + '}', + + '.blocklyComputeCanvas {', + 'position: absolute;', + 'width: 0;', + 'height: 0;', + '}', /* eslint-enable indent */ ]; From cd412b678e5abe0c69004e2ea6df41b0d5779229 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 11:44:05 -0700 Subject: [PATCH 124/343] Remove firefox workaround that is no longer needed (#3349) --- core/flyout_vertical.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 0e8eb0a19..9a6b52e38 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -333,30 +333,6 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { var width = flyoutRect.width; return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width); } else { // Right - // Firefox sometimes reports the wrong value for the client rect. - // See https://github.com/google/blockly/issues/1425 and - // https://bugzilla.mozilla.org/show_bug.cgi?id=1066435 - if (Blockly.utils.userAgent.GECKO && - this.targetWorkspace_ && this.targetWorkspace_.isMutator) { - // The position of the left side of the mutator workspace in pixels - // relative to the window origin. - var targetWsLeftPixels = - this.targetWorkspace_.svgGroup_.getBoundingClientRect().x; - // The client rect is in pixels relative to the window origin. When the - // browser gets the wrong value it reports that the flyout left is the - // same as the mutator workspace left. - // We know that in a mutator workspace with the flyout on the right, the - // visible area of the workspace should be more than ten pixels wide. If - // the browser reports that the flyout is within ten pixels of the left - // side of the workspace, ignore it and manually calculate the value. - if (Math.abs(targetWsLeftPixels - left) < 10) { - // If we're in a mutator, its scale is always 1, purely because of some - // oddities in our rendering optimizations. The actual scale is the - // same as the scale on the parent workspace. - var scale = this.targetWorkspace_.options.parentWorkspace.scale; - left += this.leftEdge_ * scale; - } - } return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM); } }; From eb50bb33e74a6f5c0b9e1fb33465a6fc67f21b96 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 12:41:04 -0700 Subject: [PATCH 125/343] Use a cursor to tab between tab navigable fields. (#3365) * Use a cursor to tab between tab navigable fields. --- blockly_uncompressed.js | 5 +- core/block_svg.js | 49 +----- core/keyboard_nav/tab_navigate_cursor.js | 183 +++++++++++++++++++++++ 3 files changed, 194 insertions(+), 43 deletions(-) create mode 100644 core/keyboard_nav/tab_navigate_cursor.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 43ec6e9f2..c3b5961e8 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -26,7 +26,7 @@ goog.addDependency("../../core/block_animations.js", ['Blockly.blockAnimations'] goog.addDependency("../../core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.blockAnimations', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Ui', 'Blockly.InsertionMarkerManager', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); -goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Warning']); +goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Warning']); goog.addDependency("../../core/blockly.js", ['Blockly'], ['Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.inject', 'Blockly.navigation', 'Blockly.Procedures', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/blocks.js", ['Blockly.Blocks'], []); goog.addDependency("../../core/bubble.js", ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent', 'Blockly.Workspace']); @@ -81,6 +81,7 @@ goog.addDependency("../../core/keyboard_nav/flyout_cursor.js", ['Blockly.FlyoutC goog.addDependency("../../core/keyboard_nav/key_map.js", ['Blockly.user.keyMap'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object']); goog.addDependency("../../core/keyboard_nav/marker_cursor.js", ['Blockly.MarkerCursor'], ['Blockly.Cursor', 'Blockly.utils.object']); goog.addDependency("../../core/keyboard_nav/navigation.js", ['Blockly.navigation'], ['Blockly.Action', 'Blockly.ASTNode', 'Blockly.utils.Coordinate', 'Blockly.user.keyMap']); +goog.addDependency("../../core/keyboard_nav/tab_navigate_cursor.js", ['Blockly.TabNavigateCursor'], ['Blockly.ASTNode', 'Blockly.Cursor', 'Blockly.utils.object']); 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.Ui', 'Blockly.Icon', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.xml', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/names.js", ['Blockly.Names'], ['Blockly.Msg']); @@ -99,7 +100,7 @@ goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawe goog.addDependency("../../core/renderers/geras/highlight_constants.js", ['Blockly.geras.HighlightConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/geras/highlighter.js", ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']); -goog.addDependency("../../core/renderers/geras/measurables/inputs.js", ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.blockRendering.Connection', 'Blockly.utils.object']); +goog.addDependency("../../core/renderers/geras/measurables/inputs.js", ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.utils.dom']); 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']); diff --git a/core/block_svg.js b/core/block_svg.js index ebbba039c..b404e27fb 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -32,6 +32,7 @@ goog.require('Blockly.Events.Ui'); goog.require('Blockly.Events.BlockMove'); goog.require('Blockly.Msg'); goog.require('Blockly.RenderedConnection'); +goog.require('Blockly.TabNavigateCursor'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); @@ -693,52 +694,18 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { /** * Open the next (or previous) FieldTextInput. - * @param {Blockly.Field|Blockly.Block} start Current location. + * @param {!Blockly.Field} start Current field. * @param {boolean} forward If true go forward, otherwise backward. */ Blockly.BlockSvg.prototype.tab = function(start, forward) { - var list = this.createTabList_(); - var i = start != null ? list.indexOf(start) : -1; - if (i == -1) { - // No start location, start at the beginning or end. - i = forward ? -1 : list.length; - } - var target = list[forward ? i + 1 : i - 1]; - if (!target) { - // Ran off of list. - var parent = this.getParent(); - if (parent) { - parent.tab(this, forward); - } - } else if (target instanceof Blockly.Field) { - target.showEditor(); - } else { - target.tab(null, forward); - } -}; + var tabCursor = new Blockly.TabNavigateCursor(); + tabCursor.setCurNode(Blockly.ASTNode.createFieldNode(start)); -/** - * Create an ordered list of all text fields and connected inputs. - * @return {!Array.} The ordered list. - * @private - */ -Blockly.BlockSvg.prototype.createTabList_ = function() { - // This function need not be efficient since it runs once on a keypress. - var list = []; - for (var i = 0, input; input = this.inputList[i]; i++) { - for (var j = 0, field; field = input.fieldRow[j]; j++) { - if (field.isTabNavigable() && field.isVisible()) { - list.push(field); - } - } - if (input.connection) { - var block = input.connection.targetBlock(); - if (block) { - list.push(block); - } - } + var nextNode = forward ? tabCursor.next() : tabCursor.prev(); + if (nextNode) { + var nextField = /** @type {!Blockly.Field} */ (nextNode.getLocation()); + nextField.showEditor(); } - return list; }; /** diff --git a/core/keyboard_nav/tab_navigate_cursor.js b/core/keyboard_nav/tab_navigate_cursor.js new file mode 100644 index 000000000..f6cf9435e --- /dev/null +++ b/core/keyboard_nav/tab_navigate_cursor.js @@ -0,0 +1,183 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview The class representing a cursor that is used to navigate + * between tab navigable fields. + * @author samelh@google.com (Sam El-Husseini) + */ +'use strict'; + +goog.provide('Blockly.TabNavigateCursor'); + +goog.require('Blockly.ASTNode'); +goog.require('Blockly.Cursor'); +goog.require('Blockly.utils.object'); + + +/** + * A cursor for navigating between tab navigable fields. + * @constructor + * @extends {Blockly.Cursor} + */ +Blockly.TabNavigateCursor = function() { + Blockly.TabNavigateCursor.superClass_.constructor.call(this); +}; +Blockly.utils.object.inherits(Blockly.TabNavigateCursor, Blockly.Cursor); + + +/** + * Find the next node in the pre order traversal. + * @override + */ +Blockly.TabNavigateCursor.prototype.next = function() { + var curNode = this.getCurNode(); + if (!curNode) { + return null; + } + var newNode = this.getNextNode_(curNode); + + if (newNode) { + this.setCurNode(newNode); + } + return newNode; +}; + +/** + * Find the previous node in the pre order traversal. + * @override + */ +Blockly.TabNavigateCursor.prototype.prev = function() { + var curNode = this.getCurNode(); + if (!curNode) { + return null; + } + var newNode = this.getPreviousNode_(curNode); + + if (newNode) { + this.setCurNode(newNode); + } + return newNode; +}; + +/** + * Skip all nodes except for tab navigable fields. + * @param {Blockly.ASTNode} node The AST node to check whether it is valid. + * @return {boolean} True if the node should be visited, false otherwise. + * @private + */ +Blockly.TabNavigateCursor.prototype.validNode_ = function(node) { + var isValid = false; + var type = node && node.getType(); + if (node) { + var location = node.getLocation(); + if (type == Blockly.ASTNode.types.FIELD && + location && location.isTabNavigable() && + (/** @type {!Blockly.Field} */ (location)).isClickable()) { + isValid = true; + } + } + return isValid; +}; + +/** + * From a given node find either the next valid sibling or parent. + * @param {Blockly.ASTNode} node The current position in the AST. + * @return {Blockly.ASTNode} The parent AST node or null if there are no + * valid parents. + * @private + */ +Blockly.TabNavigateCursor.prototype.findSiblingOrParent_ = function(node) { + if (!node) { + return null; + } + var nextNode = node.next(); + if (nextNode) { + return nextNode; + } + return this.findSiblingOrParent_(node.out()); +}; + +/** + * Navigate the Blockly AST using pre-order traversal. + * @param {Blockly.ASTNode} node The current position in the AST. + * @return {Blockly.ASTNode} The next node in the traversal. + * @private + */ +Blockly.TabNavigateCursor.prototype.getNextNode_ = function(node) { + if (!node) { + return null; + } + var newNode = node.in() || node.next(); + if (this.validNode_(newNode)) { + return newNode; + } else if (newNode) { + return this.getNextNode_(newNode); + } + var siblingOrParent = this.findSiblingOrParent_(node.out()); + if (this.validNode_(siblingOrParent)) { + return siblingOrParent; + } else if (siblingOrParent) { + return this.getNextNode_(siblingOrParent); + } + return null; +}; + +/** + * Get the right most child of a node. + * @param {Blockly.ASTNode} node The node to find the right most child of. + * @return {Blockly.ASTNode} The right most child of the given node, or the node + * if no child exists. + * @private + */ +Blockly.TabNavigateCursor.prototype.getRightMostChild_ = function(node) { + if (!node.in()) { + return node; + } + var newNode = node.in(); + while (newNode.next()) { + newNode = newNode.next(); + } + return this.getRightMostChild_(newNode); + +}; + +/** + * Use reverse pre-order traversal in order to find the previous node. + * @param {Blockly.ASTNode} node The current position in the AST. + * @return {Blockly.ASTNode} The previous node in the traversal or null if no + * previous node exists. + * @private + */ +Blockly.TabNavigateCursor.prototype.getPreviousNode_ = function(node) { + if (!node) { + return null; + } + var newNode = node.prev(); + + if (newNode) { + newNode = this.getRightMostChild_(newNode); + } else { + newNode = node.out(); + } + if (this.validNode_(newNode)) { + return newNode; + } else if (newNode) { + return this.getPreviousNode_(newNode); + } + return null; +}; From 6367d5f27afe4ed65a01689cdfb03b494008bae3 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 14:15:54 -0700 Subject: [PATCH 126/343] Fix RTL bubble drag (#3356) --- core/bubble.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/bubble.js b/core/bubble.js index 4253afd7f..c3713d4f8 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -823,7 +823,9 @@ Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) { */ Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() { return new Blockly.utils.Coordinate( - this.anchorXY_.x + this.relativeLeft_, + this.workspace_.RTL ? + -this.relativeLeft_ + this.anchorXY_.x - this.width_ : + this.anchorXY_.x + this.relativeLeft_, this.anchorXY_.y + this.relativeTop_); }; From 85c4db5a10cf74c63aabd7467fd5f41e0737522a Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 25 Oct 2019 15:28:00 -0700 Subject: [PATCH 127/343] First pass at colourers --- blockly_uncompressed.js | 6 +- core/block.js | 95 ++-------------------- core/block_svg.js | 96 ++++++++++------------ core/comment.js | 2 +- core/field.js | 4 +- core/field_angle.js | 6 +- core/field_date.js | 6 +- core/field_dropdown.js | 6 +- core/icon.js | 4 +- core/mutator.js | 2 +- core/renderers/common/colourer.js | 131 ++++++++++++++++++++++++++++++ core/renderers/common/renderer.js | 14 ++++ core/renderers/geras/colourer.js | 119 +++++++++++++++++++++++++++ core/renderers/geras/renderer.js | 13 +++ core/warning.js | 2 +- 15 files changed, 349 insertions(+), 157 deletions(-) create mode 100644 core/renderers/common/colourer.js create mode 100644 core/renderers/geras/colourer.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index c3b5961e8..ab92a378d 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -89,12 +89,14 @@ goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.utils goog.addDependency("../../core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.utils.xml', 'Blockly.Workspace', 'Blockly.Xml']); goog.addDependency("../../core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.utils.object']); +goog.addDependency("../../core/renderers/common/colourer.js", ['Blockly.blockRendering.Colourer', 'Blockly.blockRendering.IColourer'], ['Blockly.blockRendering.IPathObject']); goog.addDependency("../../core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/common/debugger.js", ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); goog.addDependency("../../core/renderers/common/drawer.js", ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/common/info.js", ['Blockly.blockRendering.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject'], ['Blockly.utils.dom']); -goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.CursorSvg']); +goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.IColourer', 'Blockly.CursorSvg']); +goog.addDependency("../../core/renderers/geras/colourer.js", ['Blockly.geras.Colourer'], ['Blockly.geras.PathObject']); goog.addDependency("../../core/renderers/geras/constants.js", ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.PathObject', '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']); @@ -102,7 +104,7 @@ goog.addDependency("../../core/renderers/geras/highlighter.js", ['Blockly.geras. goog.addDependency("../../core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/measurables/inputs.js", ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.utils.dom']); -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/geras/renderer.js", ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Colourer', '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/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.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); diff --git a/core/block.js b/core/block.js index c61bc1280..2b0ce8d34 100644 --- a/core/block.js +++ b/core/block.js @@ -905,63 +905,10 @@ Blockly.Block.prototype.setTooltip = function(newTip) { * @return {string} #RRGGBB string. */ Blockly.Block.prototype.getColour = function() { + // TODO: Can we remove this? return this.colour_; }; -/** - * Get the secondary colour of a block. - * @return {?string} #RRGGBB string. - */ -Blockly.Block.prototype.getColourSecondary = function() { - return this.colourSecondary_; -}; - -/** - * Get the tertiary colour of a block. - * @return {?string} #RRGGBB string. - */ -Blockly.Block.prototype.getColourTertiary = function() { - return this.colourTertiary_; -}; - -/** - * Get the shadow colour of a block. - * @return {?string} #RRGGBB string. - */ -Blockly.Block.prototype.getColourShadow = function() { - var colourSecondary = this.getColourSecondary(); - if (colourSecondary) { - return colourSecondary; - } - return Blockly.utils.colour.blend('#fff', this.getColour(), 0.6); -}; - -/** - * Get the border colour(s) of a block. - * @return {{colourDark, colourLight, colourBorder}} An object containing - * colour values for the border(s) of the block. If the block is using a - * style the colourBorder will be defined and equal to the tertiary colour - * of the style (#RRGGBB string). Otherwise the colourDark and colourLight - * attributes will be defined (#RRGGBB strings). - * @package - */ -Blockly.Block.prototype.getColourBorder = function() { - var colourTertiary = this.getColourTertiary(); - if (colourTertiary) { - return { - colourBorder: colourTertiary, - colourLight: null, - colourDark: null - }; - } - var colour = this.getColour(); - return { - colourBorder: null, - colourLight: Blockly.utils.colour.blend('#fff', colour, 0.3), - colourDark: Blockly.utils.colour.blend('#000', colour, 0.2) - }; -}; - /** * Get the name of the block style. * @return {?string} Name of the block style. @@ -984,48 +931,20 @@ Blockly.Block.prototype.getHue = function() { * or a message reference string pointing to one of those two values. */ Blockly.Block.prototype.setColour = function(colour) { - var dereferenced = (typeof colour == 'string') ? - Blockly.utils.replaceMessageReferences(colour) : colour; - - var hue = Number(dereferenced); - if (!isNaN(hue) && 0 <= hue && hue <= 360) { - this.hue_ = hue; - this.colour_ = Blockly.hueToHex(hue); - } else { - var hex = Blockly.utils.colour.parse(dereferenced); - if (hex) { - this.colour_ = hex; - // Only store hue if colour is set as a hue. - this.hue_ = null; - } else { - var errorMsg = 'Invalid colour: "' + dereferenced + '"'; - if (colour != dereferenced) { - errorMsg += ' (from "' + colour + '")'; - } - throw Error(errorMsg); - } - } + // Set colour just stores these as properties on the block, but never uses + // them again. + // TODO: see if we can just get rid of these properties on the block. + var parsed = Blockly.blockRendering.Colourer.parseColour(colour); + this.hue_ = parsed.hue; + this.colour_ = parsed.colour; }; /** * Set the style and colour values of a block. * @param {string} blockStyleName Name of the block style - * @throws {Error} if the block style does not exist. */ Blockly.Block.prototype.setStyle = function(blockStyleName) { - var theme = this.workspace.getTheme(); - var blockStyle = theme.getBlockStyle(blockStyleName); this.styleName_ = blockStyleName; - - if (blockStyle) { - this.colourSecondary_ = blockStyle['colourSecondary']; - this.colourTertiary_ = blockStyle['colourTertiary']; - this.hat = blockStyle.hat; - // Set colour will trigger an updateColour() on a block_svg - this.setColour(blockStyle['colourPrimary']); - } else { - throw Error('Invalid style name: ' + blockStyleName); - } }; /** diff --git a/core/block_svg.js b/core/block_svg.js index b404e27fb..8af8b9e66 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -71,6 +71,14 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { this.pathObject = workspace.getRenderer().makePathObject(this.svgGroup_); + /** + * [colourer description] + * @type {[type]} + * @package + */ + this.colourer = + workspace.getRenderer().makeColourer(this, this.pathObject); + // The next three paths are set only for backwards compatibility reasons. /** * The dark path of the block. @@ -267,7 +275,7 @@ Blockly.BlockSvg.prototype.initSvg = function() { for (var i = 0; i < icons.length; i++) { icons[i].createIcon(); } - this.updateColour(); + this.applyColour(); this.updateMovable(); var svg = this.getSvgRoot(); if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) { @@ -939,7 +947,7 @@ Blockly.BlockSvg.prototype.setEditable = function(editable) { */ Blockly.BlockSvg.prototype.setShadow = function(shadow) { Blockly.BlockSvg.superClass_.setShadow.call(this, shadow); - this.updateColour(); + this.applyColour(); }; /** @@ -1033,69 +1041,30 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { /** * Change the colour of a block. + * @package */ -Blockly.BlockSvg.prototype.updateColour = function() { +Blockly.BlockSvg.prototype.applyColour = function() { if (!this.isEnabled()) { // Disabled blocks don't have colour. return; } - if (this.isShadow()) { - this.setShadowColour_(); - } else { - this.setBorderColour_(); - this.svgPath_.setAttribute('fill', this.getColour()); - } + this.colourer.applyColour(this.isShadow()); var icons = this.getIcons(); for (var i = 0; i < icons.length; i++) { - icons[i].updateColour(); + // TODO: Decide whether to make icon and field applyColour take in a + // colourer object. + icons[i].applyColour(); } for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { - field.updateColour(); + field.applyColour(); } } }; -/** - * Sets the colour of the border. - * Removes the light and dark paths if a border colour is defined. - * @private - */ -Blockly.BlockSvg.prototype.setBorderColour_ = function() { - var borderColours = this.getColourBorder(); - if (borderColours.colourBorder) { - this.svgPathLight_.style.display = 'none'; - this.svgPathDark_.style.display = 'none'; - - this.svgPath_.setAttribute('stroke', borderColours.colourBorder); - } else { - this.svgPathLight_.style.display = ''; - this.svgPathDark_.style.display = ''; - this.svgPath_.setAttribute('stroke', 'none'); - - this.svgPathLight_.setAttribute('stroke', borderColours.colourLight); - this.svgPathDark_.setAttribute('fill', borderColours.colourDark); - } -}; - -/** - * Sets the colour of shadow blocks. - * @return {?string} The background colour of the block. - * @private - */ -Blockly.BlockSvg.prototype.setShadowColour_ = function() { - var shadowColour = this.getColourShadow() || ''; - - this.svgPathLight_.style.display = 'none'; - this.svgPathDark_.setAttribute('fill', shadowColour); - this.svgPath_.setAttribute('stroke', 'none'); - this.svgPath_.setAttribute('fill', shadowColour); - return shadowColour; -}; - /** * Enable or disable a block. */ @@ -1111,7 +1080,7 @@ Blockly.BlockSvg.prototype.updateDisabled = function() { var removed = Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (removed) { - this.updateColour(); + this.applyColour(); } } var children = this.getChildren(false); @@ -1340,15 +1309,40 @@ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { // Overrides of functions on Blockly.Block that take into account whether the // block has been rendered. +/** + * Get the colour of a block. + * @return {string} #RRGGBB string. + */ +Blockly.BlockSvg.prototype.getColour = function() { + return this.colourer.getColour(); +}; + /** * 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); + this.colourer.setColour(colour); + this.applyColour(); +}; - if (this.rendered) { - this.updateColour(); +/** + * Set the style and colour values of a block. + * @param {string} blockStyleName Name of the block style + * @throws {Error} if the block style does not exist. + */ +Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) { + var theme = this.workspace.getTheme(); + var blockStyle = theme.getBlockStyle(blockStyleName); + this.styleName_ = blockStyleName; + + if (blockStyle) { + this.hat = blockStyle.hat; + this.colourer.setFromStyle(blockStyle); + this.applyColour(); + } else { + throw Error('Invalid style name: ' + blockStyleName); } }; diff --git a/core/comment.js b/core/comment.js index 31f3942bc..680b6ca95 100644 --- a/core/comment.js +++ b/core/comment.js @@ -247,7 +247,7 @@ Blockly.Comment.prototype.createEditableBubble_ = function() { // Expose this comment's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); this.bubble_.registerResizeEvent(this.onBubbleResize_.bind(this)); - this.updateColour(); + this.applyColour(); }; /** diff --git a/core/field.js b/core/field.js index ee7cc7d17..0b13b7bdb 100644 --- a/core/field.js +++ b/core/field.js @@ -603,10 +603,10 @@ Blockly.Field.prototype.getSvgRoot = function() { /** * Updates the field to match the colour/style of the block. Should only be - * called by BlockSvg.updateColour(). + * called by BlockSvg.applyColour(). * @package */ -Blockly.Field.prototype.updateColour = function() { +Blockly.Field.prototype.applyColour = function() { // Non-abstract sub-classes may wish to implement this. See FieldDropdown. }; diff --git a/core/field_angle.js b/core/field_angle.js index eb26c4597..1025824e6 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -269,9 +269,9 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { var editor = this.dropdownCreate_(); Blockly.DropDownDiv.getContentDiv().appendChild(editor); - var border = this.sourceBlock_.getColourBorder(); - border = border.colourBorder || border.colourLight; - Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); + var colourer = this.sourceBlock_.colourer; + Blockly.DropDownDiv.setColour(colourer.getColour(), + colourer.getBorderColour()); Blockly.DropDownDiv.showPositionedByField( this, this.dropdownDispose_.bind(this)); diff --git a/core/field_date.js b/core/field_date.js index ebbfbc562..9ed4f68bd 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -129,9 +129,9 @@ Blockly.FieldDate.prototype.render_ = function() { * Updates the field's colours to match those of the block. * @package */ -Blockly.FieldDate.prototype.updateColour = function() { - this.todayColour_ = this.sourceBlock_.getColour(); - this.selectedColour_ = this.sourceBlock_.getColourShadow(); +Blockly.FieldDate.prototype.applyColour = function() { + this.todayColour_ = this.sourceBlock_.colourer.getColour(); + this.selectedColour_ = this.sourceBlock_.colourer.getShadowColour(); this.updateEditor_(); }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 3a67f6be4..9c59069f3 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -468,13 +468,13 @@ Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) { * Updates the dropdown arrow to match the colour/style of the block. * @package */ -Blockly.FieldDropdown.prototype.updateColour = function() { +Blockly.FieldDropdown.prototype.applyColour = function() { // Update arrow's colour. if (this.sourceBlock_ && this.arrow_) { if (this.sourceBlock_.isShadow()) { - this.arrow_.style.fill = this.sourceBlock_.getColourShadow(); + this.arrow_.style.fill = this.sourceBlock_.colourer.getColourShadow(); } else { - this.arrow_.style.fill = this.sourceBlock_.getColour(); + this.arrow_.style.fill = this.sourceBlock_.colourer.getColour(); } } }; diff --git a/core/icon.js b/core/icon.js index bf2c9043a..5b3a28a23 100644 --- a/core/icon.js +++ b/core/icon.js @@ -139,9 +139,9 @@ Blockly.Icon.prototype.iconClick_ = function(e) { /** * Change the colour of the associated bubble to match its block. */ -Blockly.Icon.prototype.updateColour = function() { +Blockly.Icon.prototype.applyColour = function() { if (this.isVisible()) { - this.bubble_.setColour(this.block_.getColour()); + this.bubble_.setColour(this.block_.colourer.getColour()); } }; diff --git a/core/mutator.js b/core/mutator.js index 46ed7070d..061420dbc 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -322,7 +322,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) { this.resizeBubble_(); // When the mutator's workspace changes, update the source block. this.workspace_.addChangeListener(this.workspaceChanged_.bind(this)); - this.updateColour(); + this.applyColour(); } else { // Dispose of the bubble. this.svgDialog_ = null; diff --git a/core/renderers/common/colourer.js b/core/renderers/common/colourer.js new file mode 100644 index 000000000..563c0fec3 --- /dev/null +++ b/core/renderers/common/colourer.js @@ -0,0 +1,131 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.provide('Blockly.blockRendering.Colourer'); +goog.provide('Blockly.blockRendering.IColourer'); + +goog.require('Blockly.blockRendering.IPathObject'); + +/** + * An interface for a block's colourer object. + * @param {!SVGElement} _root The root SVG element. + * @interface + */ +Blockly.blockRendering.IColourer = function(block, pathObject) {}; + +/** + * ) + * @param {[type]} block [description] + * @param {[type]} pathObject [description] + * @implements {Blockly.blockRendering.IColourer} + * @constructor + */ +Blockly.blockRendering.Colourer = function(block, pathObject) { + this.block = block; + /** + * The renderer's path object. + * @type {Blockly.blockRendering.IPathObject} + * @package + */ + this.pathObject = /** {Blockly.BlockRender.PathObject} */ (pathObject); + + this.svgPath = this.pathObject.svgPath; + + this.hue_; + this.colour_; + this.colourSecondary_; + this.colourTertiary_; +}; + +Blockly.blockRendering.Colourer.prototype.applyColours = function(isShadow) { + if (isShadow) { + this.svgPath.setAttribute('stroke', 'none'); + this.svgPath.setAttribute('fill', this.colourSecondary_); + } else { + this.svgPath.setAttribute('stroke', this.colourTertiary_); + this.svgPath.setAttribute('fill', this.colour_); + } +}; + +/** + * Change the colour of a block. + * @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.blockRendering.Colourer.prototype.setColour = function(colour) { + console.log('todo: set colour'); + // this.colour_ = colour; + // this.colourSecondary_ = Blockly.utils.colour.blend('#fff', this.colour, 0.6); + // this.colourTertiary_ = Blockly.utils.colour.blend('#fff', this.colour, 0.3); +}; + +Blockly.blockRendering.Colourer.prototype.setFromStyle = function(blockStyle) { + this.parseColour(blockStyle['colourPrimary']); + this.colourSecondary_ = blockStyle['colourSecondary'] || + Blockly.utils.colour.blend('#fff', this.colour_, 0.6); + this.colourTertiary_ = blockStyle['colourTertiary'] || + Blockly.utils.colour.blend('#fff', this.colour_, 0.3); +}; + +Blockly.blockRendering.Colourer.prototype.getBorderColour = function() { + return this.colourTertiary_; +}; + +Blockly.blockRendering.Colourer.prototype.getShadowColour = function() { + return this.colourSecondary_; +}; + +/** + * Change the colour of a block. + * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, + * or a message reference string pointing to one of those two values. + * @return {{hue: ?number, colour: string}} An object containing the colour as + * a #RRGGBB string, and the hue if the input was an HSV hue value. + */ +Blockly.blockRendering.Colourer.parseColour = function(colour) { + var dereferenced = (typeof colour == 'string') ? + Blockly.utils.replaceMessageReferences(colour) : colour; + + var hue = Number(dereferenced); + if (!isNaN(hue) && 0 <= hue && hue <= 360) { + return { + hue: hue, + colour: Blockly.hueToHex(hue) + }; + } else { + var hex = Blockly.utils.colour.parse(dereferenced); + if (hex) { + // Only store hue if colour is set as a hue. + return { + hue: null, + colour: hex + }; + } else { + var errorMsg = 'Invalid colour: "' + dereferenced + '"'; + if (colour != dereferenced) { + errorMsg += ' (from "' + colour + '")'; + } + throw Error(errorMsg); + } + } +}; diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index 49a83943a..c9d19902e 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -28,6 +28,8 @@ goog.require('Blockly.blockRendering.Drawer'); goog.require('Blockly.blockRendering.IPathObject'); goog.require('Blockly.blockRendering.PathObject'); goog.require('Blockly.blockRendering.RenderInfo'); +goog.require('Blockly.blockRendering.IColourer'); +goog.require('Blockly.blockRendering.Colourer'); goog.require('Blockly.CursorSvg'); goog.requireType('Blockly.blockRendering.Debug'); @@ -125,6 +127,18 @@ Blockly.blockRendering.Renderer.prototype.makePathObject = function(root) { return new Blockly.blockRendering.PathObject(root); }; +/** + * Create a new instance of a renderer path object. + * @param {!Blockly.BlockSvg} block The root SVG element. + * @param {!Blockly.blockRendering.IPathObject} pathObject [description] + * @return {!Blockly.blockRendering.IColourer} The renderer path object. + * @package + */ +Blockly.blockRendering.Renderer.prototype.makeColourer = function(block, + pathObject) { + return new Blockly.blockRendering.Colourer(block, pathObject); +}; + /** * Get the current renderer's constant provider. We assume that when this is * called, the renderer has already been initialized. diff --git a/core/renderers/geras/colourer.js b/core/renderers/geras/colourer.js new file mode 100644 index 000000000..eb8548cd7 --- /dev/null +++ b/core/renderers/geras/colourer.js @@ -0,0 +1,119 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.provide('Blockly.geras.Colourer'); + +goog.require('Blockly.geras.PathObject'); + + +/** + * ) + * @param {[type]} block [description] + * @param {[type]} pathObject [description] + * @implements {Blockly.blockRendering.IColourer} + * @constructor + */ +Blockly.geras.Colourer = function(block, pathObject) { + /** + * The renderer's path object. + * @type {Blockly.geras.PathObject} + * @package + */ + this.pathObject = /** {Blockly.geras.PathObject} */ (pathObject); + + this.svgPath = this.pathObject.svgPath; + this.svgPathLight = this.pathObject.svgPathLight; + this.svgPathDark = this.pathObject.svgPathDark; + this.svgPath.setAttribute('stroke', 'none'); + this.svgPathLight.style.display = ''; + this.svgPathDark.setAttribute('display', ''); + + this.colour_; + this.colourTertiary_; + this.colourDark_; + this.colourSecondary_; + this.styleName_; +}; + +Blockly.geras.Colourer.prototype.applyColour = function(isShadow) { + if (isShadow) { + this.svgPathLight.style.display = 'none'; + this.svgPathDark.setAttribute('fill', this.colourSecondary_); + this.svgPath.setAttribute('stroke', 'none'); + this.svgPath.setAttribute('fill', this.colourSecondary_); + } else { + this.svgPathLight.style.display = ''; + this.svgPathDark.style.display = ''; + this.svgPath.setAttribute('stroke', 'none'); + this.svgPathLight.setAttribute('stroke', this.colourTertiary_); + this.svgPathDark.setAttribute('fill', this.colourDark_); + this.svgPath.setAttribute('fill', this.colour_); + } +}; + +/** + * Get the colour of a block. + * @return {string} #RRGGBB string. + */ +Blockly.geras.Colourer.prototype.getColour = function() { + return this.colour_; +}; + +Blockly.geras.Colourer.prototype.getShadowColour = function() { + return this.colourSecondary_; +}; + +Blockly.geras.Colourer.prototype.getBorderColour = function() { + return this.colourTertiary_; +}; + +Blockly.geras.Colourer.prototype.setColourFromTriplet = function(primary, + secondary, tertiary) { + this.colour_ = primary; + this.colourSecondary_ = secondary || + Blockly.utils.colour.blend('#fff', primary, 0.6); + this.colourTertiary_ = tertiary || + Blockly.utils.colour.blend('#fff', primary, 0.3); + this.colourDark_ = tertiary || + Blockly.utils.colour.blend('#000', primary, 0.2); +}; + +/** + * Change the colour of a block. + * @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.geras.Colourer.prototype.setColour = function(colour) { + var primary = Blockly.blockRendering.Colourer.parseColour(colour).colour; + this.setColourFromTriplet(primary, null, null); +}; + +Blockly.geras.Colourer.prototype.setFromStyle = function(blockStyle) { + var primary = + Blockly.blockRendering.Colourer.parseColour(blockStyle['colourPrimary']) + .colour; + this.setColourFromTriplet(primary, + blockStyle['colourSecondary'], + blockStyle['colourTertiary']); +}; + diff --git a/core/renderers/geras/renderer.js b/core/renderers/geras/renderer.js index fcd5e516d..f5745e361 100644 --- a/core/renderers/geras/renderer.js +++ b/core/renderers/geras/renderer.js @@ -26,6 +26,7 @@ goog.provide('Blockly.geras.Renderer'); goog.require('Blockly.blockRendering'); goog.require('Blockly.blockRendering.Renderer'); goog.require('Blockly.geras.ConstantProvider'); +goog.require('Blockly.geras.Colourer'); goog.require('Blockly.geras.Drawer'); goog.require('Blockly.geras.HighlightConstantProvider'); goog.require('Blockly.geras.PathObject'); @@ -106,6 +107,18 @@ Blockly.geras.Renderer.prototype.makePathObject = function(root) { return new Blockly.geras.PathObject(root); }; +/** + * Create a new instance of a renderer path object. + * @param {!Blockly.BlockSvg} block The root SVG element. + * @param {!Blockly.geras.IPathObject} pathObject [description] + * @return {!Blockly.geras.Colourer} The renderer path object. + * @package + */ +Blockly.geras.Renderer.prototype.makeColourer = function(block, + pathObject) { + return new Blockly.geras.Colourer(block, pathObject); +}; + /** * Create a new instance of the renderer's highlight constant provider. * @return {!Blockly.geras.HighlightConstantProvider} The highlight constant diff --git a/core/warning.js b/core/warning.js index fe9f8c4f7..fde0bd50c 100644 --- a/core/warning.js +++ b/core/warning.js @@ -149,7 +149,7 @@ Blockly.Warning.prototype.createBubble = function() { textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); } } - this.updateColour(); + this.applyColour(); }; /** From 6f520335ea8f9ac8a445f4b222704f64db5ab31f Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 28 Oct 2019 14:57:36 -0700 Subject: [PATCH 128/343] Cleanup of colouring code, and move it into path_object. --- core/block.js | 4 +- core/block_svg.js | 29 ++---- core/field_angle.js | 6 +- core/field_date.js | 4 +- core/field_dropdown.js | 4 +- core/icon.js | 2 +- core/renderers/common/colourer.js | 131 --------------------------- core/renderers/common/path_object.js | 70 ++++++++++++++ core/renderers/common/renderer.js | 14 --- core/renderers/geras/colourer.js | 119 ------------------------ core/renderers/geras/path_object.js | 43 +++++++++ core/renderers/geras/renderer.js | 12 --- core/utils/colour.js | 36 ++++++++ tests/blocks/test_blocks.js | 2 +- 14 files changed, 166 insertions(+), 310 deletions(-) delete mode 100644 core/renderers/common/colourer.js delete mode 100644 core/renderers/geras/colourer.js diff --git a/core/block.js b/core/block.js index 2b0ce8d34..f462c2f29 100644 --- a/core/block.js +++ b/core/block.js @@ -934,9 +934,9 @@ Blockly.Block.prototype.setColour = function(colour) { // Set colour just stores these as properties on the block, but never uses // them again. // TODO: see if we can just get rid of these properties on the block. - var parsed = Blockly.blockRendering.Colourer.parseColour(colour); + var parsed = Blockly.utils.colour.parseBlockColour(colour); this.hue_ = parsed.hue; - this.colour_ = parsed.colour; + this.colour_ = parsed.hex; }; /** diff --git a/core/block_svg.js b/core/block_svg.js index 8af8b9e66..98228c024 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -68,25 +68,9 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @type {Blockly.blockRendering.IPathObject} * @package */ - this.pathObject = - workspace.getRenderer().makePathObject(this.svgGroup_); - - /** - * [colourer description] - * @type {[type]} - * @package - */ - this.colourer = - workspace.getRenderer().makeColourer(this, this.pathObject); - - // The next three paths are set only for backwards compatibility reasons. - /** - * The dark path of the block. - * @type {SVGElement} - * @private - */ - this.svgPathDark_ = this.pathObject.svgPathDark || null; + this.pathObject = workspace.getRenderer().makePathObject(this.svgGroup_); + // The next two paths are set only for backwards compatibility reasons. /** * The primary path of the block. * @type {SVGElement} @@ -1035,7 +1019,6 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { this.svgGroup_ = null; this.svgPath_ = null; this.svgPathLight_ = null; - this.svgPathDark_ = null; Blockly.utils.dom.stopTextWidthCache(); }; @@ -1049,7 +1032,7 @@ Blockly.BlockSvg.prototype.applyColour = function() { return; } - this.colourer.applyColour(this.isShadow()); + this.pathObject.applyColour(this.isShadow()); var icons = this.getIcons(); for (var i = 0; i < icons.length; i++) { @@ -1314,7 +1297,7 @@ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { * @return {string} #RRGGBB string. */ Blockly.BlockSvg.prototype.getColour = function() { - return this.colourer.getColour(); + return this.pathObject.primaryColour; }; /** @@ -1323,7 +1306,7 @@ Blockly.BlockSvg.prototype.getColour = function() { */ Blockly.BlockSvg.prototype.setColour = function(colour) { Blockly.BlockSvg.superClass_.setColour.call(this, colour); - this.colourer.setColour(colour); + this.pathObject.setColour(colour); this.applyColour(); }; @@ -1339,7 +1322,7 @@ Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) { if (blockStyle) { this.hat = blockStyle.hat; - this.colourer.setFromStyle(blockStyle); + this.pathObject.setFromStyle(blockStyle); this.applyColour(); } else { throw Error('Invalid style name: ' + blockStyleName); diff --git a/core/field_angle.js b/core/field_angle.js index 1025824e6..dafed3810 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -269,9 +269,9 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { var editor = this.dropdownCreate_(); Blockly.DropDownDiv.getContentDiv().appendChild(editor); - var colourer = this.sourceBlock_.colourer; - Blockly.DropDownDiv.setColour(colourer.getColour(), - colourer.getBorderColour()); + var pathObject = this.sourceBlock_.pathObject; + Blockly.DropDownDiv.setColour(pathObject.primaryColour, + pathObject.tertiaryColour); Blockly.DropDownDiv.showPositionedByField( this, this.dropdownDispose_.bind(this)); diff --git a/core/field_date.js b/core/field_date.js index 9ed4f68bd..b6fff8f2c 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -130,8 +130,8 @@ Blockly.FieldDate.prototype.render_ = function() { * @package */ Blockly.FieldDate.prototype.applyColour = function() { - this.todayColour_ = this.sourceBlock_.colourer.getColour(); - this.selectedColour_ = this.sourceBlock_.colourer.getShadowColour(); + this.todayColour_ = this.sourceBlock_.pathObject.primaryColour; + this.selectedColour_ = this.sourceBlock_.pathObject.secondaryColour; this.updateEditor_(); }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 9c59069f3..179f98e23 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -472,9 +472,9 @@ Blockly.FieldDropdown.prototype.applyColour = function() { // Update arrow's colour. if (this.sourceBlock_ && this.arrow_) { if (this.sourceBlock_.isShadow()) { - this.arrow_.style.fill = this.sourceBlock_.colourer.getColourShadow(); + this.arrow_.style.fill = this.sourceBlock_.pathObject.secondaryColour; } else { - this.arrow_.style.fill = this.sourceBlock_.colourer.getColour(); + this.arrow_.style.fill = this.sourceBlock_.pathObject.primaryColour; } } }; diff --git a/core/icon.js b/core/icon.js index 5b3a28a23..f703beea2 100644 --- a/core/icon.js +++ b/core/icon.js @@ -141,7 +141,7 @@ Blockly.Icon.prototype.iconClick_ = function(e) { */ Blockly.Icon.prototype.applyColour = function() { if (this.isVisible()) { - this.bubble_.setColour(this.block_.colourer.getColour()); + this.bubble_.setColour(this.block_.pathObject.primaryColour); } }; diff --git a/core/renderers/common/colourer.js b/core/renderers/common/colourer.js deleted file mode 100644 index 563c0fec3..000000000 --- a/core/renderers/common/colourer.js +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview - * @author fenichel@google.com (Rachel Fenichel) - */ -'use strict'; - -goog.provide('Blockly.blockRendering.Colourer'); -goog.provide('Blockly.blockRendering.IColourer'); - -goog.require('Blockly.blockRendering.IPathObject'); - -/** - * An interface for a block's colourer object. - * @param {!SVGElement} _root The root SVG element. - * @interface - */ -Blockly.blockRendering.IColourer = function(block, pathObject) {}; - -/** - * ) - * @param {[type]} block [description] - * @param {[type]} pathObject [description] - * @implements {Blockly.blockRendering.IColourer} - * @constructor - */ -Blockly.blockRendering.Colourer = function(block, pathObject) { - this.block = block; - /** - * The renderer's path object. - * @type {Blockly.blockRendering.IPathObject} - * @package - */ - this.pathObject = /** {Blockly.BlockRender.PathObject} */ (pathObject); - - this.svgPath = this.pathObject.svgPath; - - this.hue_; - this.colour_; - this.colourSecondary_; - this.colourTertiary_; -}; - -Blockly.blockRendering.Colourer.prototype.applyColours = function(isShadow) { - if (isShadow) { - this.svgPath.setAttribute('stroke', 'none'); - this.svgPath.setAttribute('fill', this.colourSecondary_); - } else { - this.svgPath.setAttribute('stroke', this.colourTertiary_); - this.svgPath.setAttribute('fill', this.colour_); - } -}; - -/** - * Change the colour of a block. - * @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.blockRendering.Colourer.prototype.setColour = function(colour) { - console.log('todo: set colour'); - // this.colour_ = colour; - // this.colourSecondary_ = Blockly.utils.colour.blend('#fff', this.colour, 0.6); - // this.colourTertiary_ = Blockly.utils.colour.blend('#fff', this.colour, 0.3); -}; - -Blockly.blockRendering.Colourer.prototype.setFromStyle = function(blockStyle) { - this.parseColour(blockStyle['colourPrimary']); - this.colourSecondary_ = blockStyle['colourSecondary'] || - Blockly.utils.colour.blend('#fff', this.colour_, 0.6); - this.colourTertiary_ = blockStyle['colourTertiary'] || - Blockly.utils.colour.blend('#fff', this.colour_, 0.3); -}; - -Blockly.blockRendering.Colourer.prototype.getBorderColour = function() { - return this.colourTertiary_; -}; - -Blockly.blockRendering.Colourer.prototype.getShadowColour = function() { - return this.colourSecondary_; -}; - -/** - * Change the colour of a block. - * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, - * or a message reference string pointing to one of those two values. - * @return {{hue: ?number, colour: string}} An object containing the colour as - * a #RRGGBB string, and the hue if the input was an HSV hue value. - */ -Blockly.blockRendering.Colourer.parseColour = function(colour) { - var dereferenced = (typeof colour == 'string') ? - Blockly.utils.replaceMessageReferences(colour) : colour; - - var hue = Number(dereferenced); - if (!isNaN(hue) && 0 <= hue && hue <= 360) { - return { - hue: hue, - colour: Blockly.hueToHex(hue) - }; - } else { - var hex = Blockly.utils.colour.parse(dereferenced); - if (hex) { - // Only store hue if colour is set as a hue. - return { - hue: null, - colour: hex - }; - } else { - var errorMsg = 'Invalid colour: "' + dereferenced + '"'; - if (colour != dereferenced) { - errorMsg += ' (from "' + colour + '")'; - } - throw Error(errorMsg); - } - } -}; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 07b1aa343..34d65733b 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -74,6 +74,12 @@ Blockly.blockRendering.PathObject = function(root) { this.svgPathDark = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, this.svgRoot); + + + this.hue_; + this.primaryColour; + this.secondaryColour; + this.tertiaryColour; }; /** @@ -95,3 +101,67 @@ Blockly.blockRendering.PathObject.prototype.flipRTL = function() { // Mirror the block's path. this.svgPath.setAttribute('transform', 'scale(-1 1)'); }; + +/** + * Apply the stored colours to the block's path, taking into account whether + * the paths belong to a shadow block. + * @param {boolean} isShadow True if the block is a shadow block. + * @package + */ +Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) { + if (isShadow) { + this.svgPath.setAttribute('stroke', 'none'); + this.svgPath.setAttribute('fill', this.secondaryColour); + } else { + this.svgPath.setAttribute('stroke', this.tertiaryColour); + this.svgPath.setAttribute('fill', this.primaryColour); + } +}; + +/** + * Update colour properties based on a triplet of colours. + * @param {string} primary The primary colour. + * @param {string} secondary The secondary colour, or null to have the colourer + * generate it. + * @param {string} tertiary The tertiary colour, or null to have the colourer + * generate it. + * @package + */ +Blockly.blockRendering.PathObject.prototype.setColourFromTriplet = function( + primary, secondary, tertiary) { + this.primaryColour = primary; + this.secondaryColour = secondary || + Blockly.utils.colour.blend('#fff', primary, 0.6); + this.tertiaryColour = tertiary || + Blockly.utils.colour.blend('#fff', primary, 0.3); +}; + +/** + * Update colour properties based on a single colour value. + * @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.blockRendering.PathObject.prototype.setColour = function(colour) { + var parsed = Blockly.utils.colour.parseBlockColour(colour); + if (parsed.hue) { + this.hue_ = parsed.hue; + } + this.setColourFromTriplet(parsed.hex, null, null); +}; + +/** + * Update colour properties based on a block style. + * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. + * @package + */ +Blockly.blockRendering.PathObject.prototype.setFromStyle = function( + blockStyle) { + var parsed = + Blockly.utils.colour.parseBlockColour(blockStyle['colourPrimary']); + if (parsed.hue) { + this.hue_ = parsed.hue; + } + this.setColourFromTriplet(parsed.hex, + blockStyle['colourSecondary'], + blockStyle['colourTertiary']); +}; diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index c9d19902e..49a83943a 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -28,8 +28,6 @@ goog.require('Blockly.blockRendering.Drawer'); goog.require('Blockly.blockRendering.IPathObject'); goog.require('Blockly.blockRendering.PathObject'); goog.require('Blockly.blockRendering.RenderInfo'); -goog.require('Blockly.blockRendering.IColourer'); -goog.require('Blockly.blockRendering.Colourer'); goog.require('Blockly.CursorSvg'); goog.requireType('Blockly.blockRendering.Debug'); @@ -127,18 +125,6 @@ Blockly.blockRendering.Renderer.prototype.makePathObject = function(root) { return new Blockly.blockRendering.PathObject(root); }; -/** - * Create a new instance of a renderer path object. - * @param {!Blockly.BlockSvg} block The root SVG element. - * @param {!Blockly.blockRendering.IPathObject} pathObject [description] - * @return {!Blockly.blockRendering.IColourer} The renderer path object. - * @package - */ -Blockly.blockRendering.Renderer.prototype.makeColourer = function(block, - pathObject) { - return new Blockly.blockRendering.Colourer(block, pathObject); -}; - /** * Get the current renderer's constant provider. We assume that when this is * called, the renderer has already been initialized. diff --git a/core/renderers/geras/colourer.js b/core/renderers/geras/colourer.js deleted file mode 100644 index eb8548cd7..000000000 --- a/core/renderers/geras/colourer.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview - * @author fenichel@google.com (Rachel Fenichel) - */ -'use strict'; - -goog.provide('Blockly.geras.Colourer'); - -goog.require('Blockly.geras.PathObject'); - - -/** - * ) - * @param {[type]} block [description] - * @param {[type]} pathObject [description] - * @implements {Blockly.blockRendering.IColourer} - * @constructor - */ -Blockly.geras.Colourer = function(block, pathObject) { - /** - * The renderer's path object. - * @type {Blockly.geras.PathObject} - * @package - */ - this.pathObject = /** {Blockly.geras.PathObject} */ (pathObject); - - this.svgPath = this.pathObject.svgPath; - this.svgPathLight = this.pathObject.svgPathLight; - this.svgPathDark = this.pathObject.svgPathDark; - this.svgPath.setAttribute('stroke', 'none'); - this.svgPathLight.style.display = ''; - this.svgPathDark.setAttribute('display', ''); - - this.colour_; - this.colourTertiary_; - this.colourDark_; - this.colourSecondary_; - this.styleName_; -}; - -Blockly.geras.Colourer.prototype.applyColour = function(isShadow) { - if (isShadow) { - this.svgPathLight.style.display = 'none'; - this.svgPathDark.setAttribute('fill', this.colourSecondary_); - this.svgPath.setAttribute('stroke', 'none'); - this.svgPath.setAttribute('fill', this.colourSecondary_); - } else { - this.svgPathLight.style.display = ''; - this.svgPathDark.style.display = ''; - this.svgPath.setAttribute('stroke', 'none'); - this.svgPathLight.setAttribute('stroke', this.colourTertiary_); - this.svgPathDark.setAttribute('fill', this.colourDark_); - this.svgPath.setAttribute('fill', this.colour_); - } -}; - -/** - * Get the colour of a block. - * @return {string} #RRGGBB string. - */ -Blockly.geras.Colourer.prototype.getColour = function() { - return this.colour_; -}; - -Blockly.geras.Colourer.prototype.getShadowColour = function() { - return this.colourSecondary_; -}; - -Blockly.geras.Colourer.prototype.getBorderColour = function() { - return this.colourTertiary_; -}; - -Blockly.geras.Colourer.prototype.setColourFromTriplet = function(primary, - secondary, tertiary) { - this.colour_ = primary; - this.colourSecondary_ = secondary || - Blockly.utils.colour.blend('#fff', primary, 0.6); - this.colourTertiary_ = tertiary || - Blockly.utils.colour.blend('#fff', primary, 0.3); - this.colourDark_ = tertiary || - Blockly.utils.colour.blend('#000', primary, 0.2); -}; - -/** - * Change the colour of a block. - * @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.geras.Colourer.prototype.setColour = function(colour) { - var primary = Blockly.blockRendering.Colourer.parseColour(colour).colour; - this.setColourFromTriplet(primary, null, null); -}; - -Blockly.geras.Colourer.prototype.setFromStyle = function(blockStyle) { - var primary = - Blockly.blockRendering.Colourer.parseColour(blockStyle['colourPrimary']) - .colour; - this.setColourFromTriplet(primary, - blockStyle['colourSecondary'], - blockStyle['colourTertiary']); -}; - diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 416cb54a9..5fafb4ff3 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -34,6 +34,7 @@ goog.require('Blockly.utils.dom'); * @param {!SVGElement} root The root SVG element. * @constructor * @implements {Blockly.blockRendering.IPathObject} + * @extends {Blockly.blockRendering.PathObject} * @package */ Blockly.geras.PathObject = function(root) { @@ -66,7 +67,16 @@ Blockly.geras.PathObject = function(root) { */ this.svgPathLight = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPathLight'}, this.svgRoot); + + + this.hue_; + this.primaryColour; + this.secondaryColour; + this.tertiaryColour; + this.darkColour; }; +Blockly.utils.object.inherits(Blockly.geras.PathObject, + Blockly.blockRendering.PathObject); /** * Set each of the paths generated by the renderer onto the respective SVG element. @@ -90,3 +100,36 @@ Blockly.geras.PathObject.prototype.flipRTL = function() { this.svgPathLight.setAttribute('transform', 'scale(-1 1)'); this.svgPathDark.setAttribute('transform', 'translate(1,1) scale(-1 1)'); }; + +/** + * Apply the stored colours to the block's path, taking into account whether + * the paths belong to a shadow block. + * @param {boolean} isShadow True if the block is a shadow block. + * @package + */ +Blockly.geras.PathObject.prototype.applyColour = function(isShadow) { + if (isShadow) { + this.svgPathLight.style.display = 'none'; + this.svgPathDark.setAttribute('fill', this.secondaryColour); + this.svgPath.setAttribute('stroke', 'none'); + this.svgPath.setAttribute('fill', this.secondaryColour); + } else { + this.svgPathLight.style.display = ''; + this.svgPathDark.style.display = ''; + this.svgPath.setAttribute('stroke', 'none'); + this.svgPathLight.setAttribute('stroke', this.tertiaryColour); + this.svgPathDark.setAttribute('fill', this.darkColour); + this.svgPath.setAttribute('fill', this.primaryColour); + } +}; + +/** + * @override + */ +Blockly.geras.PathObject.prototype.setColourFromTriplet = function(primary, + secondary, tertiary) { + Blockly.geras.PathObject.superClass_.setColourFromTriplet.call(this, primary, + secondary, tertiary); + this.darkColour = tertiary || + Blockly.utils.colour.blend('#000', primary, 0.2); +}; diff --git a/core/renderers/geras/renderer.js b/core/renderers/geras/renderer.js index f5745e361..b01597ffd 100644 --- a/core/renderers/geras/renderer.js +++ b/core/renderers/geras/renderer.js @@ -26,7 +26,6 @@ goog.provide('Blockly.geras.Renderer'); goog.require('Blockly.blockRendering'); goog.require('Blockly.blockRendering.Renderer'); goog.require('Blockly.geras.ConstantProvider'); -goog.require('Blockly.geras.Colourer'); goog.require('Blockly.geras.Drawer'); goog.require('Blockly.geras.HighlightConstantProvider'); goog.require('Blockly.geras.PathObject'); @@ -107,17 +106,6 @@ Blockly.geras.Renderer.prototype.makePathObject = function(root) { return new Blockly.geras.PathObject(root); }; -/** - * Create a new instance of a renderer path object. - * @param {!Blockly.BlockSvg} block The root SVG element. - * @param {!Blockly.geras.IPathObject} pathObject [description] - * @return {!Blockly.geras.Colourer} The renderer path object. - * @package - */ -Blockly.geras.Renderer.prototype.makeColourer = function(block, - pathObject) { - return new Blockly.geras.Colourer(block, pathObject); -}; /** * Create a new instance of the renderer's highlight constant provider. diff --git a/core/utils/colour.js b/core/utils/colour.js index 928fc935b..08aeae89b 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -211,3 +211,39 @@ Blockly.utils.colour.names = { 'white': '#ffffff', 'yellow': '#ffff00' }; + +/** + * Parse a block colour from a number or string, as provided in a block + * definition. + * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, + * or a message reference string pointing to one of those two values. + * @return {{hue: ?number, colour: string}} An object containing the colour as + * a #RRGGBB string, and the hue if the input was an HSV hue value. + */ +Blockly.utils.colour.parseBlockColour = function(colour) { + var dereferenced = (typeof colour == 'string') ? + Blockly.utils.replaceMessageReferences(colour) : colour; + + var hue = Number(dereferenced); + if (!isNaN(hue) && 0 <= hue && hue <= 360) { + return { + hue: hue, + hex: Blockly.hueToHex(hue) + }; + } else { + var hex = Blockly.utils.colour.parse(dereferenced); + if (hex) { + // Only store hue if colour is set as a hue. + return { + hue: null, + hex: hex + }; + } else { + var errorMsg = 'Invalid colour: "' + dereferenced + '"'; + if (colour != dereferenced) { + errorMsg += ' (from "' + colour + '")'; + } + throw Error(errorMsg); + } + } +}; diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index 6f9e0af33..bf79c2f9d 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -29,7 +29,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "message0": "stack block", "previousStatement": null, "nextStatement": null, - "style": "math_blocks" + "colour": "120" }, { "type": "test_basic_dummy", From ecef3467fdd310c46f33f41d2b1377f025958e87 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 28 Oct 2019 15:16:59 -0700 Subject: [PATCH 129/343] Colourer/path_object cleanup --- core/block_svg.js | 2 +- core/renderers/common/i_path_object.js | 63 ++++++++++++++++++++++++++ core/renderers/common/path_object.js | 49 ++++++++++---------- core/renderers/geras/path_object.js | 38 +++++++++++++--- 4 files changed, 121 insertions(+), 31 deletions(-) create mode 100644 core/renderers/common/i_path_object.js diff --git a/core/block_svg.js b/core/block_svg.js index 98228c024..364e8808b 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1322,7 +1322,7 @@ Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) { if (blockStyle) { this.hat = blockStyle.hat; - this.pathObject.setFromStyle(blockStyle); + this.pathObject.setColourFromStyle(blockStyle); this.applyColour(); } else { throw Error('Invalid style name: ' + blockStyleName); diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js new file mode 100644 index 000000000..4cbd940ac --- /dev/null +++ b/core/renderers/common/i_path_object.js @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview The interface for an object that owns a block's rendering SVG + * elements. + * @author fenichel@google.com (Rachel Fenichel) + */ + +'use strict'; + +goog.provide('Blockly.blockRendering.IPathObject'); + + +/** + * An interface for a block's path object. + * @param {!SVGElement} _root The root SVG element. + * @interface + */ +Blockly.blockRendering.IPathObject = function(_root) {}; + +/** + * Apply the stored colours to the block's path, taking into account whether + * the paths belong to a shadow block. + * @param {boolean} isShadow True if the block is a shadow block. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.applyColour; + +/** + * Update colour properties based on a single colour value. + * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, + * or a message reference string pointing to one of those two values. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.setColour; + +/** + * Update colour properties based on a block style. + * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.setColourFromStyle; + +/** + * Flip the SVG paths in RTL. + * @package + */ +Blockly.geras.PathObject.prototype.flipRTL; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 34d65733b..015e2af52 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -22,19 +22,12 @@ 'use strict'; -goog.provide('Blockly.blockRendering.IPathObject'); goog.provide('Blockly.blockRendering.PathObject'); +goog.require('Blockly.blockRendering.IPathObject'); goog.require('Blockly.utils.dom'); -/** - * An interface for a block's path object. - * @param {!SVGElement} _root The root SVG element. - * @interface - */ -Blockly.blockRendering.IPathObject = function(_root) {}; - /** * An object that handles creating and setting each of the SVG elements * used by the renderer. @@ -75,11 +68,26 @@ Blockly.blockRendering.PathObject = function(root) { {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, this.svgRoot); + /** + * Primary colour of the block in '#RRGGBB' format. + * @type {string} + * @package + */ + this.primaryColour = '#000000'; - this.hue_; - this.primaryColour; - this.secondaryColour; - this.tertiaryColour; + /** + * Secondary colour of the block in '#RRGGBB' format. + * @type {string} + * @package + */ + this.secondaryColour = '#000000'; + + /** + * Tertiary colour of the block in '#RRGGBB' format. + * @type {string} + * @package + */ + this.tertiaryColour = '#000000'; }; /** @@ -125,9 +133,9 @@ Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) { * generate it. * @param {string} tertiary The tertiary colour, or null to have the colourer * generate it. - * @package + * @protected */ -Blockly.blockRendering.PathObject.prototype.setColourFromTriplet = function( +Blockly.blockRendering.PathObject.prototype.setColourFromTriplet_ = function( primary, secondary, tertiary) { this.primaryColour = primary; this.secondaryColour = secondary || @@ -140,13 +148,11 @@ Blockly.blockRendering.PathObject.prototype.setColourFromTriplet = function( * Update colour properties based on a single colour value. * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, * or a message reference string pointing to one of those two values. + * @package */ Blockly.blockRendering.PathObject.prototype.setColour = function(colour) { var parsed = Blockly.utils.colour.parseBlockColour(colour); - if (parsed.hue) { - this.hue_ = parsed.hue; - } - this.setColourFromTriplet(parsed.hex, null, null); + this.setColourFromTriplet_(parsed.hex, null, null); }; /** @@ -154,14 +160,11 @@ Blockly.blockRendering.PathObject.prototype.setColour = function(colour) { * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. * @package */ -Blockly.blockRendering.PathObject.prototype.setFromStyle = function( +Blockly.blockRendering.PathObject.prototype.setColourFromStyle = function( blockStyle) { var parsed = Blockly.utils.colour.parseBlockColour(blockStyle['colourPrimary']); - if (parsed.hue) { - this.hue_ = parsed.hue; - } - this.setColourFromTriplet(parsed.hex, + this.setColourFromTriplet_(parsed.hex, blockStyle['colourSecondary'], blockStyle['colourTertiary']); }; diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 5fafb4ff3..e1e90b51f 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -69,11 +69,35 @@ Blockly.geras.PathObject = function(root) { {'class': 'blocklyPathLight'}, this.svgRoot); - this.hue_; - this.primaryColour; - this.secondaryColour; - this.tertiaryColour; - this.darkColour; + /** + * Primary colour of the block in '#RRGGBB' format. + * @type {string} + * @package + */ + this.primaryColour = '#000000'; + + /** + * Secondary colour of the block in '#RRGGBB' format. + * Used for the body of a shadow block in Geras. + * @type {string} + * @package + */ + this.secondaryColour = '#000000'; + + /** + * Tertiary colour of the block in '#RRGGBB' format. + * Used for the light path (highlight) in Geras. + * @type {string} + * @package + */ + this.tertiaryColour = '#000000'; + + /** + * The colour of the dark path on the block in '#RRGGBB' format. + * @type {string} + * @package + */ + this.darkColour = '#000000'; }; Blockly.utils.object.inherits(Blockly.geras.PathObject, Blockly.blockRendering.PathObject); @@ -126,9 +150,9 @@ Blockly.geras.PathObject.prototype.applyColour = function(isShadow) { /** * @override */ -Blockly.geras.PathObject.prototype.setColourFromTriplet = function(primary, +Blockly.geras.PathObject.prototype.setColourFromTriplet_ = function(primary, secondary, tertiary) { - Blockly.geras.PathObject.superClass_.setColourFromTriplet.call(this, primary, + Blockly.geras.PathObject.superClass_.setColourFromTriplet_.call(this, primary, secondary, tertiary); this.darkColour = tertiary || Blockly.utils.colour.blend('#000', primary, 0.2); From 7e84dcd3c475d9cdb639afeaa286a45c1ee01e9a Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 28 Oct 2019 15:18:32 -0700 Subject: [PATCH 130/343] Remove colourSecondary/tertiary from block. --- core/block.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/core/block.js b/core/block.js index f462c2f29..b896ac84b 100644 --- a/core/block.js +++ b/core/block.js @@ -256,22 +256,6 @@ Blockly.Block.prototype.hue_ = null; */ Blockly.Block.prototype.colour_ = '#000000'; -/** - * Secondary colour of the block. - * Colour of shadow blocks. - * @type {?string} - * @private - */ -Blockly.Block.prototype.colourSecondary_ = null; - -/** - * Tertiary colour of the block. - * Colour of the block's border. - * @type {?string} - * @private - */ -Blockly.Block.prototype.colourTertiary_ = null; - /** * Name of the block style. * @type {?string} From f4bbeb0688d77bdd55e36c00c588023b846cac1d Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 28 Oct 2019 15:27:01 -0700 Subject: [PATCH 131/343] Fix bad function definition. --- core/renderers/common/i_path_object.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index 4cbd940ac..e23faa262 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -60,4 +60,4 @@ Blockly.blockRendering.IPathObject.prototype.setColourFromStyle; * Flip the SVG paths in RTL. * @package */ -Blockly.geras.PathObject.prototype.flipRTL; +Blockly.blockRendering.IPathObject.prototype.flipRTL; From ca1e49bf8ead42976ecc3e392c526828a6dc9e68 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 28 Oct 2019 17:34:15 -0700 Subject: [PATCH 132/343] Fields now go through blockSvg for colours. --- core/block.js | 4 ---- core/block_svg.js | 18 +++++++++++++++++- core/field_angle.js | 5 ++--- core/field_date.js | 4 ++-- core/field_dropdown.js | 4 ++-- core/renderers/common/path_object.js | 4 ++-- core/renderers/geras/path_object.js | 1 + core/renderers/geras/renderer.js | 1 - core/utils/colour.js | 3 ++- 9 files changed, 28 insertions(+), 16 deletions(-) diff --git a/core/block.js b/core/block.js index b896ac84b..65e054b31 100644 --- a/core/block.js +++ b/core/block.js @@ -889,7 +889,6 @@ Blockly.Block.prototype.setTooltip = function(newTip) { * @return {string} #RRGGBB string. */ Blockly.Block.prototype.getColour = function() { - // TODO: Can we remove this? return this.colour_; }; @@ -915,9 +914,6 @@ Blockly.Block.prototype.getHue = function() { * or a message reference string pointing to one of those two values. */ Blockly.Block.prototype.setColour = function(colour) { - // Set colour just stores these as properties on the block, but never uses - // them again. - // TODO: see if we can just get rid of these properties on the block. var parsed = Blockly.utils.colour.parseBlockColour(colour); this.hue_ = parsed.hue; this.colour_ = parsed.hex; diff --git a/core/block_svg.js b/core/block_svg.js index 364e8808b..523f771d2 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1289,9 +1289,9 @@ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { } }; + // Overrides of functions on Blockly.Block that take into account whether the // block has been rendered. - /** * Get the colour of a block. * @return {string} #RRGGBB string. @@ -1300,6 +1300,22 @@ Blockly.BlockSvg.prototype.getColour = function() { return this.pathObject.primaryColour; }; +/** + * Get the secondary colour of a block. + * @return {string} #RRGGBB string. + */ +Blockly.BlockSvg.prototype.getSecondaryColour = function() { + return this.pathObject.primaryColour; +}; + +/** + * Get the tertiary colour of a block. + * @return {string} #RRGGBB string. + */ +Blockly.BlockSvg.prototype.getTertiaryColour = function() { + return this.pathObject.primaryColour; +}; + /** * Change the colour of a block. * @param {number|string} colour HSV hue value, or #RRGGBB string. diff --git a/core/field_angle.js b/core/field_angle.js index dafed3810..7076d5760 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -269,9 +269,8 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { var editor = this.dropdownCreate_(); Blockly.DropDownDiv.getContentDiv().appendChild(editor); - var pathObject = this.sourceBlock_.pathObject; - Blockly.DropDownDiv.setColour(pathObject.primaryColour, - pathObject.tertiaryColour); + Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), + this.sourceBlock_.getTertiaryColour()); Blockly.DropDownDiv.showPositionedByField( this, this.dropdownDispose_.bind(this)); diff --git a/core/field_date.js b/core/field_date.js index b6fff8f2c..e22c9a6f0 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -130,8 +130,8 @@ Blockly.FieldDate.prototype.render_ = function() { * @package */ Blockly.FieldDate.prototype.applyColour = function() { - this.todayColour_ = this.sourceBlock_.pathObject.primaryColour; - this.selectedColour_ = this.sourceBlock_.pathObject.secondaryColour; + this.todayColour_ = this.sourceBlock_.getColour(); + this.selectedColour_ = this.sourceBlock_.getSecondaryColour(); this.updateEditor_(); }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 179f98e23..fe5866de1 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -472,9 +472,9 @@ Blockly.FieldDropdown.prototype.applyColour = function() { // Update arrow's colour. if (this.sourceBlock_ && this.arrow_) { if (this.sourceBlock_.isShadow()) { - this.arrow_.style.fill = this.sourceBlock_.pathObject.secondaryColour; + this.arrow_.style.fill = this.sourceBlock_.getSecondaryColour(); } else { - this.arrow_.style.fill = this.sourceBlock_.pathObject.primaryColour; + this.arrow_.style.fill = this.sourceBlock_.getColour(); } } }; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 015e2af52..64eede105 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -129,9 +129,9 @@ Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) { /** * Update colour properties based on a triplet of colours. * @param {string} primary The primary colour. - * @param {string} secondary The secondary colour, or null to have the colourer + * @param {?string} secondary The secondary colour, or null to have the colourer * generate it. - * @param {string} tertiary The tertiary colour, or null to have the colourer + * @param {?string} tertiary The tertiary colour, or null to have the colourer * generate it. * @protected */ diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index e1e90b51f..134b52999 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -26,6 +26,7 @@ goog.provide('Blockly.geras.PathObject'); goog.require('Blockly.blockRendering.IPathObject'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.object'); /** diff --git a/core/renderers/geras/renderer.js b/core/renderers/geras/renderer.js index b01597ffd..fcd5e516d 100644 --- a/core/renderers/geras/renderer.js +++ b/core/renderers/geras/renderer.js @@ -106,7 +106,6 @@ Blockly.geras.Renderer.prototype.makePathObject = function(root) { return new Blockly.geras.PathObject(root); }; - /** * Create a new instance of the renderer's highlight constant provider. * @return {!Blockly.geras.HighlightConstantProvider} The highlight constant diff --git a/core/utils/colour.js b/core/utils/colour.js index 08aeae89b..1a0f50dd0 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -217,8 +217,9 @@ Blockly.utils.colour.names = { * definition. * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, * or a message reference string pointing to one of those two values. - * @return {{hue: ?number, colour: string}} An object containing the colour as + * @return {{hue: ?number, hex: string}} An object containing the colour as * a #RRGGBB string, and the hue if the input was an HSV hue value. + * @throws {Error} If If the colour cannot be parsed. */ Blockly.utils.colour.parseBlockColour = function(colour) { var dereferenced = (typeof colour == 'string') ? From 5ef08fc0d4d2d2622495c0bc898d8a44207da116 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 30 Oct 2019 14:22:35 -0700 Subject: [PATCH 133/343] Switch to using the style object in the path object. --- core/block.js | 4 +- core/block_svg.js | 41 +++++++------ core/field_angle.js | 4 +- core/field_date.js | 4 +- core/field_dropdown.js | 4 +- core/renderers/common/i_path_object.js | 14 ++--- core/renderers/common/path_object.js | 79 ++++--------------------- core/renderers/geras/path_object.js | 58 ++++++------------ core/theme.js | 82 ++++++++++++++++++++++++-- core/utils/colour.js | 3 +- 10 files changed, 141 insertions(+), 152 deletions(-) diff --git a/core/block.js b/core/block.js index 65e054b31..9c1cdb38f 100644 --- a/core/block.js +++ b/core/block.js @@ -252,14 +252,14 @@ Blockly.Block.prototype.hue_ = null; /** * Colour of the block in '#RRGGBB' format. * @type {string} - * @private + * @protected */ Blockly.Block.prototype.colour_ = '#000000'; /** * Name of the block style. * @type {?string} - * @private + * @protected */ Blockly.Block.prototype.styleName_ = null; diff --git a/core/block_svg.js b/core/block_svg.js index 523f771d2..510220a89 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -63,6 +63,13 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); this.svgGroup_.translate_ = ''; + /** + * A block style object. + * @type {!Blockly.Theme.BlockStyle} + * @public + */ + this.style = workspace.getTheme().getBlockStyle(null); + /** * The renderer's path object. * @type {Blockly.blockRendering.IPathObject} @@ -1297,23 +1304,7 @@ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { * @return {string} #RRGGBB string. */ Blockly.BlockSvg.prototype.getColour = function() { - return this.pathObject.primaryColour; -}; - -/** - * Get the secondary colour of a block. - * @return {string} #RRGGBB string. - */ -Blockly.BlockSvg.prototype.getSecondaryColour = function() { - return this.pathObject.primaryColour; -}; - -/** - * Get the tertiary colour of a block. - * @return {string} #RRGGBB string. - */ -Blockly.BlockSvg.prototype.getTertiaryColour = function() { - return this.pathObject.primaryColour; + return this.style.colourPrimary; }; /** @@ -1322,7 +1313,12 @@ Blockly.BlockSvg.prototype.getTertiaryColour = function() { */ Blockly.BlockSvg.prototype.setColour = function(colour) { Blockly.BlockSvg.superClass_.setColour.call(this, colour); - this.pathObject.setColour(colour); + var styleObj = this.workspace.getTheme().getBlockStyleForColour(this.colour_); + + this.pathObject.setStyle(styleObj.style); + this.style = styleObj.style; + this.styleName_ = styleObj.name; + this.applyColour(); }; @@ -1332,13 +1328,16 @@ Blockly.BlockSvg.prototype.setColour = function(colour) { * @throws {Error} if the block style does not exist. */ Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) { - var theme = this.workspace.getTheme(); - var blockStyle = theme.getBlockStyle(blockStyleName); + var blockStyle = this.workspace.getTheme().getBlockStyle(blockStyleName); this.styleName_ = blockStyleName; if (blockStyle) { this.hat = blockStyle.hat; - this.pathObject.setColourFromStyle(blockStyle); + this.pathObject.setStyle(blockStyle); + // Set colour to match Block. + this.colour_ = blockStyle.colourPrimary; + this.style = blockStyle; + this.applyColour(); } else { throw Error('Invalid style name: ' + blockStyleName); diff --git a/core/field_angle.js b/core/field_angle.js index 7076d5760..3a550bcbb 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -269,8 +269,8 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { var editor = this.dropdownCreate_(); Blockly.DropDownDiv.getContentDiv().appendChild(editor); - Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), - this.sourceBlock_.getTertiaryColour()); + Blockly.DropDownDiv.setColour(this.sourceBlock_.style.colourPrimary, + this.sourceBlock_.style.colourTertiary); Blockly.DropDownDiv.showPositionedByField( this, this.dropdownDispose_.bind(this)); diff --git a/core/field_date.js b/core/field_date.js index e22c9a6f0..a39ca849e 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -130,8 +130,8 @@ Blockly.FieldDate.prototype.render_ = function() { * @package */ Blockly.FieldDate.prototype.applyColour = function() { - this.todayColour_ = this.sourceBlock_.getColour(); - this.selectedColour_ = this.sourceBlock_.getSecondaryColour(); + this.todayColour_ = this.sourceBlock_.style.colourPrimary; + this.selectedColour_ = this.sourceBlock_.style.colourSecondary; this.updateEditor_(); }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index fe5866de1..5693d107c 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -472,9 +472,9 @@ Blockly.FieldDropdown.prototype.applyColour = function() { // Update arrow's colour. if (this.sourceBlock_ && this.arrow_) { if (this.sourceBlock_.isShadow()) { - this.arrow_.style.fill = this.sourceBlock_.getSecondaryColour(); + this.arrow_.style.fill = this.sourceBlock_.style.colourSecondary; } else { - this.arrow_.style.fill = this.sourceBlock_.getColour(); + this.arrow_.style.fill = this.sourceBlock_.style.colourPrimary; } } }; diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index e23faa262..fd81f8e03 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -25,6 +25,8 @@ goog.provide('Blockly.blockRendering.IPathObject'); +goog.requireType('Blockly.Theme'); + /** * An interface for a block's path object. @@ -42,19 +44,11 @@ Blockly.blockRendering.IPathObject = function(_root) {}; Blockly.blockRendering.IPathObject.prototype.applyColour; /** - * Update colour properties based on a single colour value. - * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, - * or a message reference string pointing to one of those two values. - * @package - */ -Blockly.blockRendering.IPathObject.prototype.setColour; - -/** - * Update colour properties based on a block style. + * Update the style. * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. * @package */ -Blockly.blockRendering.IPathObject.prototype.setColourFromStyle; +Blockly.blockRendering.IPathObject.prototype.setStyle; /** * Flip the SVG paths in RTL. diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 64eede105..e24f60a14 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -25,6 +25,7 @@ goog.provide('Blockly.blockRendering.PathObject'); goog.require('Blockly.blockRendering.IPathObject'); +goog.require('Blockly.Theme'); goog.require('Blockly.utils.dom'); @@ -60,34 +61,11 @@ Blockly.blockRendering.PathObject = function(root) { {'class': 'blocklyPathLight'}, this.svgRoot); /** - * The dark path of the block. - * @type {SVGElement} - * @package + * The style object to use when colouring block paths. + * @type {!Blockly.Theme.BlockStyle} + * @public */ - this.svgPathDark = Blockly.utils.dom.createSvgElement('path', - {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, - this.svgRoot); - - /** - * Primary colour of the block in '#RRGGBB' format. - * @type {string} - * @package - */ - this.primaryColour = '#000000'; - - /** - * Secondary colour of the block in '#RRGGBB' format. - * @type {string} - * @package - */ - this.secondaryColour = '#000000'; - - /** - * Tertiary colour of the block in '#RRGGBB' format. - * @type {string} - * @package - */ - this.tertiaryColour = '#000000'; + this.style = Blockly.Theme.createBlockStyle('#0000000'); }; /** @@ -98,7 +76,6 @@ Blockly.blockRendering.PathObject = function(root) { Blockly.blockRendering.PathObject.prototype.setPaths = function(pathString) { this.svgPath.setAttribute('d', pathString); this.svgPathLight.style.display = 'none'; - this.svgPathDark.style.display = 'none'; }; /** @@ -119,52 +96,18 @@ Blockly.blockRendering.PathObject.prototype.flipRTL = function() { Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) { if (isShadow) { this.svgPath.setAttribute('stroke', 'none'); - this.svgPath.setAttribute('fill', this.secondaryColour); + this.svgPath.setAttribute('fill', this.style.colourSecondary); } else { - this.svgPath.setAttribute('stroke', this.tertiaryColour); - this.svgPath.setAttribute('fill', this.primaryColour); + this.svgPath.setAttribute('stroke', this.style.colourTertiary); + this.svgPath.setAttribute('fill', this.style.colourPrimary); } }; /** - * Update colour properties based on a triplet of colours. - * @param {string} primary The primary colour. - * @param {?string} secondary The secondary colour, or null to have the colourer - * generate it. - * @param {?string} tertiary The tertiary colour, or null to have the colourer - * generate it. - * @protected - */ -Blockly.blockRendering.PathObject.prototype.setColourFromTriplet_ = function( - primary, secondary, tertiary) { - this.primaryColour = primary; - this.secondaryColour = secondary || - Blockly.utils.colour.blend('#fff', primary, 0.6); - this.tertiaryColour = tertiary || - Blockly.utils.colour.blend('#fff', primary, 0.3); -}; - -/** - * Update colour properties based on a single colour value. - * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, - * or a message reference string pointing to one of those two values. - * @package - */ -Blockly.blockRendering.PathObject.prototype.setColour = function(colour) { - var parsed = Blockly.utils.colour.parseBlockColour(colour); - this.setColourFromTriplet_(parsed.hex, null, null); -}; - -/** - * Update colour properties based on a block style. + * Set the style. * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. * @package */ -Blockly.blockRendering.PathObject.prototype.setColourFromStyle = function( - blockStyle) { - var parsed = - Blockly.utils.colour.parseBlockColour(blockStyle['colourPrimary']); - this.setColourFromTriplet_(parsed.hex, - blockStyle['colourSecondary'], - blockStyle['colourTertiary']); +Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) { + this.style = blockStyle; }; diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 134b52999..8c63b4eb0 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -35,7 +35,6 @@ goog.require('Blockly.utils.object'); * @param {!SVGElement} root The root SVG element. * @constructor * @implements {Blockly.blockRendering.IPathObject} - * @extends {Blockly.blockRendering.PathObject} * @package */ Blockly.geras.PathObject = function(root) { @@ -69,39 +68,20 @@ Blockly.geras.PathObject = function(root) { this.svgPathLight = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPathLight'}, this.svgRoot); - - /** - * Primary colour of the block in '#RRGGBB' format. - * @type {string} - * @package - */ - this.primaryColour = '#000000'; - - /** - * Secondary colour of the block in '#RRGGBB' format. - * Used for the body of a shadow block in Geras. - * @type {string} - * @package - */ - this.secondaryColour = '#000000'; - - /** - * Tertiary colour of the block in '#RRGGBB' format. - * Used for the light path (highlight) in Geras. - * @type {string} - * @package - */ - this.tertiaryColour = '#000000'; - /** * The colour of the dark path on the block in '#RRGGBB' format. * @type {string} * @package */ this.darkColour = '#000000'; + + /** + * The style object to use when colouring block paths. + * @type {!Blockly.Theme.BlockStyle} + * @public + */ + this.style = Blockly.Theme.createBlockStyle('#0000000'); }; -Blockly.utils.object.inherits(Blockly.geras.PathObject, - Blockly.blockRendering.PathObject); /** * Set each of the paths generated by the renderer onto the respective SVG element. @@ -135,26 +115,26 @@ Blockly.geras.PathObject.prototype.flipRTL = function() { Blockly.geras.PathObject.prototype.applyColour = function(isShadow) { if (isShadow) { this.svgPathLight.style.display = 'none'; - this.svgPathDark.setAttribute('fill', this.secondaryColour); + this.svgPathDark.setAttribute('fill', this.style.colourSecondary); this.svgPath.setAttribute('stroke', 'none'); - this.svgPath.setAttribute('fill', this.secondaryColour); + this.svgPath.setAttribute('fill', this.style.colourSecondary); } else { this.svgPathLight.style.display = ''; this.svgPathDark.style.display = ''; this.svgPath.setAttribute('stroke', 'none'); - this.svgPathLight.setAttribute('stroke', this.tertiaryColour); - this.svgPathDark.setAttribute('fill', this.darkColour); - this.svgPath.setAttribute('fill', this.primaryColour); + this.svgPathLight.setAttribute('stroke', this.style.colourTertiary); + this.svgPathDark.setAttribute('fill', this.colourDark); + this.svgPath.setAttribute('fill', this.style.colourPrimary); } }; /** - * @override + * Set the style. + * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. + * @package */ -Blockly.geras.PathObject.prototype.setColourFromTriplet_ = function(primary, - secondary, tertiary) { - Blockly.geras.PathObject.superClass_.setColourFromTriplet_.call(this, primary, - secondary, tertiary); - this.darkColour = tertiary || - Blockly.utils.colour.blend('#000', primary, 0.2); +Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) { + this.style = blockStyle; + this.colourDark = + Blockly.utils.colour.blend('#000', this.style.colourPrimary, 0.2); }; diff --git a/core/theme.js b/core/theme.js index 58adea0e2..dbae4f453 100644 --- a/core/theme.js +++ b/core/theme.js @@ -22,6 +22,7 @@ goog.provide('Blockly.Theme'); +goog.require('Blockly.utils.colour'); /** * Class for a theme. @@ -40,7 +41,10 @@ Blockly.Theme = function(blockStyles, categoryStyles, opt_componentStyles) { * @type {!Object.} * @private */ - this.blockStyles_ = blockStyles; + this.blockStyles_ = {}; + + // Make sure all styles are valid before insterting them into the map. + this.setAllBlockStyles(blockStyles); /** * The category styles map. @@ -97,22 +101,90 @@ Blockly.Theme.prototype.getAllBlockStyles = function() { /** * Gets the BlockStyle for the given block style name. - * @param {string} blockStyleName The name of the block style. - * @return {Blockly.Theme.BlockStyle|undefined} The named block style. + * @param {?string} blockStyleName The name of the block style. + * @return {!Blockly.Theme.BlockStyle} The named block style, or a default style + * if no style with the given name was found. */ Blockly.Theme.prototype.getBlockStyle = function(blockStyleName) { - return this.blockStyles_[blockStyleName]; + var defaultStyle = Blockly.Theme.createBlockStyle('#000000'); + if (blockStyleName == null) { + return defaultStyle; + } + return this.blockStyles_[blockStyleName] || defaultStyle; }; /** * 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. -*/ + * @package + */ Blockly.Theme.prototype.setBlockStyle = function(blockStyleName, blockStyle) { + blockStyle = Blockly.Theme.validatedBlockStyle(blockStyle); this.blockStyles_[blockStyleName] = blockStyle; }; +/** + * Get or create a block style based on a single colour value. Generate a name + * for the style based on the colour. + * @param {string} colour #RRGGBB colour string. + * @return {{style: !Blockly.Theme.BlockStyle, name: string}} An object + * containing the style and an autogenerated name for that style. + * @package + */ +Blockly.Theme.prototype.getBlockStyleForColour = function(colour) { + var name = 'auto_' + colour; + if (!this.blockStyles_[name]) { + this.blockStyles_[name] = Blockly.Theme.createBlockStyle(colour); + } + return {style: this.blockStyles_[name], name: name}; +}; + +/** + * Create a block style object based on the given colour. + * @param {string} colour #RRGGBB colour string. + * @return {!Blockly.Theme.BlockStyle} A populated block style based on the + * given colour. + * @package + */ +Blockly.Theme.createBlockStyle = function(colour) { + return { + colourPrimary: colour, + colourSecondary: Blockly.utils.colour.blend('#fff', colour, 0.6) || colour, + colourTertiary: Blockly.utils.colour.blend('#fff', colour, 0.3) || colour, + hat: '' + }; +}; + +/** + * Get a full block style object based on the input style object. Populate + * any missing values. + * @param {!Blockly.Theme.BlockStyle} blockStyle A full or partial block + * style object. + * @return {!Blockly.Theme.BlockStyle} A full block style object, with all + * required properties populated. + * @package + */ +Blockly.Theme.validatedBlockStyle = function(blockStyle) { + // Make a new object with all of the same properties. + var valid = {}; + Blockly.utils.object.mixin(valid, blockStyle); + + // Validate required properties. + var parsedColour = Blockly.utils.colour.parseBlockColour( + valid.colourPrimary || '#000000'); + valid.colourPrimary = parsedColour.hex; + valid.colourSecondary = valid.colourSecondary || + Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6) || + valid.colourPrimary; + valid.colourTertiary = valid.colourTertiary || + Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3) || + valid.colourPrimary; + + valid.hat = valid.hat || ''; + return valid; +}; + /** * Gets the CategoryStyle for the given category style name. * @param {string} categoryStyleName The name of the category style. diff --git a/core/utils/colour.js b/core/utils/colour.js index 1a0f50dd0..48f56576f 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -229,7 +229,8 @@ Blockly.utils.colour.parseBlockColour = function(colour) { if (!isNaN(hue) && 0 <= hue && hue <= 360) { return { hue: hue, - hex: Blockly.hueToHex(hue) + hex: Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION, + Blockly.HSV_VALUE * 255) }; } else { var hex = Blockly.utils.colour.parse(dereferenced); From e91304ede1ccdd797785c293e071db9554cec40f Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 30 Oct 2019 14:25:48 -0700 Subject: [PATCH 134/343] Fix bad reference --- core/icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/icon.js b/core/icon.js index f703beea2..5fb7cf9c7 100644 --- a/core/icon.js +++ b/core/icon.js @@ -141,7 +141,7 @@ Blockly.Icon.prototype.iconClick_ = function(e) { */ Blockly.Icon.prototype.applyColour = function() { if (this.isVisible()) { - this.bubble_.setColour(this.block_.pathObject.primaryColour); + this.bubble_.setColour(this.block_.style.colourPrimary); } }; From dd33d772f79276a1c7e92c39ba137482d6a6064e Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 30 Oct 2019 14:48:02 -0700 Subject: [PATCH 135/343] Rebuild --- blockly_uncompressed.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index ab92a378d..5426d79fa 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -74,7 +74,7 @@ goog.addDependency("../../core/inject.js", ['Blockly.inject'], ['Blockly.BlockDr goog.addDependency("../../core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.blockAnimations', 'Blockly.Events']); goog.addDependency("../../core/keyboard_nav/action.js", ['Blockly.Action'], []); -goog.addDependency("../../core/keyboard_nav/ast_node.js", ['Blockly.ASTNode'], []); +goog.addDependency("../../core/keyboard_nav/ast_node.js", ['Blockly.ASTNode'], ['Blockly.utils.Coordinate']); goog.addDependency("../../core/keyboard_nav/cursor.js", ['Blockly.Cursor'], []); goog.addDependency("../../core/keyboard_nav/cursor_svg.js", ['Blockly.CursorSvg'], ['Blockly.Cursor', 'Blockly.utils.object']); goog.addDependency("../../core/keyboard_nav/flyout_cursor.js", ['Blockly.FlyoutCursor'], ['Blockly.Cursor', 'Blockly.utils.object']); @@ -89,22 +89,21 @@ goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.utils goog.addDependency("../../core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.utils.xml', 'Blockly.Workspace', 'Blockly.Xml']); goog.addDependency("../../core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.utils.object']); -goog.addDependency("../../core/renderers/common/colourer.js", ['Blockly.blockRendering.Colourer', 'Blockly.blockRendering.IColourer'], ['Blockly.blockRendering.IPathObject']); goog.addDependency("../../core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/common/debugger.js", ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); goog.addDependency("../../core/renderers/common/drawer.js", ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); +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.Hat', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); -goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject'], ['Blockly.utils.dom']); -goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.IColourer', 'Blockly.CursorSvg']); -goog.addDependency("../../core/renderers/geras/colourer.js", ['Blockly.geras.Colourer'], ['Blockly.geras.PathObject']); +goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.Theme', 'Blockly.utils.dom']); +goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.CursorSvg']); goog.addDependency("../../core/renderers/geras/constants.js", ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.PathObject', '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']); goog.addDependency("../../core/renderers/geras/highlighter.js", ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/measurables/inputs.js", ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.utils.object']); -goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.utils.dom']); -goog.addDependency("../../core/renderers/geras/renderer.js", ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Colourer', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object']); +goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.IPathObject', '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/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.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); @@ -124,7 +123,7 @@ goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.z goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); -goog.addDependency("../../core/theme.js", ['Blockly.Theme'], []); +goog.addDependency("../../core/theme.js", ['Blockly.Theme'], ['Blockly.utils.colour']); goog.addDependency("../../core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); goog.addDependency("../../core/theme/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Theme']); goog.addDependency("../../core/theme/deuteranopia.js", ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']); From 46fad66ab183799d19bf81ab2aa29593a149ebba Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 30 Oct 2019 15:58:53 -0700 Subject: [PATCH 136/343] Review feedback. --- core/block_svg.js | 2 -- core/renderers/common/path_object.js | 4 ++-- core/renderers/geras/path_object.js | 7 ++++--- core/theme.js | 20 +++++++++----------- core/utils/colour.js | 2 +- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 510220a89..fe2b0b705 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1043,8 +1043,6 @@ Blockly.BlockSvg.prototype.applyColour = function() { var icons = this.getIcons(); for (var i = 0; i < icons.length; i++) { - // TODO: Decide whether to make icon and field applyColour take in a - // colourer object. icons[i].applyColour(); } diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index e24f60a14..493245289 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -63,9 +63,9 @@ Blockly.blockRendering.PathObject = function(root) { /** * The style object to use when colouring block paths. * @type {!Blockly.Theme.BlockStyle} - * @public + * @package */ - this.style = Blockly.Theme.createBlockStyle('#0000000'); + this.style = Blockly.Theme.createBlockStyle('#000000'); }; /** diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 8c63b4eb0..42e995b85 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -25,6 +25,7 @@ goog.provide('Blockly.geras.PathObject'); goog.require('Blockly.blockRendering.IPathObject'); +goog.require('Blockly.Theme'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.object'); @@ -73,14 +74,14 @@ Blockly.geras.PathObject = function(root) { * @type {string} * @package */ - this.darkColour = '#000000'; + this.colourDark = '#000000'; /** * The style object to use when colouring block paths. * @type {!Blockly.Theme.BlockStyle} - * @public + * @package */ - this.style = Blockly.Theme.createBlockStyle('#0000000'); + this.style = Blockly.Theme.createBlockStyle('#000000'); }; /** diff --git a/core/theme.js b/core/theme.js index dbae4f453..a46f1af15 100644 --- a/core/theme.js +++ b/core/theme.js @@ -38,12 +38,12 @@ goog.require('Blockly.utils.colour'); Blockly.Theme = function(blockStyles, categoryStyles, opt_componentStyles) { /** * The block styles map. - * @type {!Object.} + * @type {!Object.} * @private */ this.blockStyles_ = {}; - // Make sure all styles are valid before insterting them into the map. + // Make sure all styles are valid before inserting them into the map. this.setAllBlockStyles(blockStyles); /** @@ -106,18 +106,14 @@ Blockly.Theme.prototype.getAllBlockStyles = function() { * if no style with the given name was found. */ Blockly.Theme.prototype.getBlockStyle = function(blockStyleName) { - var defaultStyle = Blockly.Theme.createBlockStyle('#000000'); - if (blockStyleName == null) { - return defaultStyle; - } - return this.blockStyles_[blockStyleName] || defaultStyle; + return this.blockStyles_[blockStyleName || ''] || + Blockly.Theme.createBlockStyle('#000000'); }; /** * 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. - * @package */ Blockly.Theme.prototype.setBlockStyle = function(blockStyleName, blockStyle) { blockStyle = Blockly.Theme.validatedBlockStyle(blockStyle); @@ -159,7 +155,7 @@ Blockly.Theme.createBlockStyle = function(colour) { /** * Get a full block style object based on the input style object. Populate * any missing values. - * @param {!Blockly.Theme.BlockStyle} blockStyle A full or partial block + * @param {Blockly.Theme.BlockStyle} blockStyle A full or partial block * style object. * @return {!Blockly.Theme.BlockStyle} A full block style object, with all * required properties populated. @@ -168,11 +164,13 @@ Blockly.Theme.createBlockStyle = function(colour) { Blockly.Theme.validatedBlockStyle = function(blockStyle) { // Make a new object with all of the same properties. var valid = {}; - Blockly.utils.object.mixin(valid, blockStyle); + if (blockStyle) { + Blockly.utils.object.mixin(valid, blockStyle); + } // Validate required properties. var parsedColour = Blockly.utils.colour.parseBlockColour( - valid.colourPrimary || '#000000'); + valid.colourPrimary || '#000'); valid.colourPrimary = parsedColour.hex; valid.colourSecondary = valid.colourSecondary || Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6) || diff --git a/core/utils/colour.js b/core/utils/colour.js index 48f56576f..810bd5637 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -219,7 +219,7 @@ Blockly.utils.colour.names = { * or a message reference string pointing to one of those two values. * @return {{hue: ?number, hex: string}} An object containing the colour as * a #RRGGBB string, and the hue if the input was an HSV hue value. - * @throws {Error} If If the colour cannot be parsed. + * @throws {Error} If the colour cannot be parsed. */ Blockly.utils.colour.parseBlockColour = function(colour) { var dereferenced = (typeof colour == 'string') ? From 5634ff5de0134f8b9734dc734a30d8a626143c5f Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 30 Oct 2019 16:07:41 -0700 Subject: [PATCH 137/343] Remove extra annotation --- core/block_svg.js | 1 - 1 file changed, 1 deletion(-) diff --git a/core/block_svg.js b/core/block_svg.js index fe2b0b705..2a2a83c9c 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -66,7 +66,6 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { /** * A block style object. * @type {!Blockly.Theme.BlockStyle} - * @public */ this.style = workspace.getTheme().getBlockStyle(null); From 207e0ebe7b11d195f9c4b63eafe14d44ce30afe8 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 30 Oct 2019 17:24:03 -0700 Subject: [PATCH 138/343] Add tests and better validation for block styles --- core/theme.js | 12 +-- core/theme/deuteranopia.js | 2 +- tests/jsunit/block_test.js | 22 ------ tests/jsunit/theme_test.js | 153 ------------------------------------- tests/mocha/block_test.js | 62 +++++++++++++++ tests/mocha/theme_test.js | 139 ++++++++++++++++++++++++++++++--- 6 files changed, 198 insertions(+), 192 deletions(-) delete mode 100644 tests/jsunit/theme_test.js diff --git a/core/theme.js b/core/theme.js index a46f1af15..c086d3714 100644 --- a/core/theme.js +++ b/core/theme.js @@ -172,12 +172,12 @@ Blockly.Theme.validatedBlockStyle = function(blockStyle) { var parsedColour = Blockly.utils.colour.parseBlockColour( valid.colourPrimary || '#000'); valid.colourPrimary = parsedColour.hex; - valid.colourSecondary = valid.colourSecondary || - Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6) || - valid.colourPrimary; - valid.colourTertiary = valid.colourTertiary || - Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3) || - valid.colourPrimary; + valid.colourSecondary = valid.colourSecondary ? + Blockly.utils.colour.parseBlockColour(valid.colourSecondary).hex : + Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6); + valid.colourTertiary = valid.colourTertiary ? + Blockly.utils.colour.parseBlockColour(valid.colourTertiary).hex : + Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3); valid.hat = valid.hat || ''; return valid; diff --git a/core/theme/deuteranopia.js b/core/theme/deuteranopia.js index a2c18ab84..05b4c9664 100644 --- a/core/theme/deuteranopia.js +++ b/core/theme/deuteranopia.js @@ -34,7 +34,7 @@ Blockly.Themes.Deuteranopia = {}; Blockly.Themes.Deuteranopia.defaultBlockStyles = { "colour_blocks": { "colourPrimary": "#f2a72c", - "colourSecondary": "#f1c17", + "colourSecondary": "#f1c170", "colourTertiary": "#da921c" }, "list_blocks": { diff --git a/tests/jsunit/block_test.js b/tests/jsunit/block_test.js index f8fba5bed..a6588c353 100644 --- a/tests/jsunit/block_test.js +++ b/tests/jsunit/block_test.js @@ -253,28 +253,6 @@ function test_block_row_unplug_multi_inputs_child() { } } -function test_set_style() { - blockTest_setUp(); - var styleStub = { - getBlockStyle: function() { - return { - "colourPrimary": "#ffffff", - "colourSecondary": "#aabbcc", - "colourTertiary": "#ddeeff" - }; - } - }; - mockControl_ = setUpMockMethod(workspace, 'getTheme', null, [styleStub]); - var blockA = workspace.newBlock('row_block'); - blockA.setStyle('styleOne'); - - assertEquals('#ffffff', blockA.colour_); - assertEquals('#aabbcc', blockA.colourSecondary_); - assertEquals('#ddeeff', blockA.colourTertiary_); - - blockTest_tearDown(); -} - function test_set_style_throw_exception() { blockTest_setUp(); var styleStub = { diff --git a/tests/jsunit/theme_test.js b/tests/jsunit/theme_test.js deleted file mode 100644 index 22ba32c2e..000000000 --- a/tests/jsunit/theme_test.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @license - * Copyright 2018 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /** - * @fileoverview Tests for Blockly.Style - * @author aschmiedt@google.com (Abby Schmiedt) - */ -'use strict'; - -function defineThemeTestBlocks() { - Blockly.defineBlocksWithJsonArray([{ - "type": "stack_block", - "message0": "", - "previousStatement": null, - "nextStatement": null - }, - { - "type": "row_block", - "message0": "%1", - "args0": [ - { - "type": "input_value", - "name": "INPUT" - } - ], - "output": null - }]); -}; - -function undefineThemeTestBlocks() { - delete Blockly.Blocks['stack_block']; - delete Blockly.Blocks['row_block']; -} - - -function createBlockStyles() { - return { - "styleOne": { - "colourPrimary": "colour1", - "colourSecondary":"colour2", - "colourTertiary":"colour3" - } - }; -} - -function createMultipleBlockStyles() { - return { - "styleOne": { - "colourPrimary": "colour1", - "colourSecondary":"colour2", - "colourTertiary":"colour3" - }, - "styleTwo": { - "colourPrimary": "colour1", - "colourSecondary":"colour2", - "colourTertiary":"colour3" - } - }; -} - -function test_setAllBlockStyles() { - var theme = new Blockly.Theme(createBlockStyles()); - stringifyAndCompare(createBlockStyles(), theme.blockStyles_); - theme.setAllBlockStyles(createMultipleBlockStyles()); - stringifyAndCompare(createMultipleBlockStyles(), theme.blockStyles_); -} - -function test_getAllBlockStyles() { - var theme = new Blockly.Theme(createMultipleBlockStyles()); - var allBlocks = theme.getAllBlockStyles(); - stringifyAndCompare(createMultipleBlockStyles(), allBlocks); - -} - -function test_getBlockStyles() { - var theme = new Blockly.Theme(createBlockStyles()); - var blockStyle = theme.getBlockStyle('styleOne'); - - stringifyAndCompare(blockStyle, createBlockStyles().styleOne); -} - -function test_setBlockStyleUpdate() { - var theme = new Blockly.Theme(createBlockStyles()); - var blockStyle = createBlockStyles(); - blockStyle.styleOne.colourPrimary = 'somethingElse'; - - theme.setBlockStyle('styleOne', blockStyle.styleOne); - - stringifyAndCompare(theme.blockStyles_, blockStyle); -} - -function test_setBlockStyleAdd() { - var theme = new Blockly.Theme(createBlockStyles()); - var blockStyle = createMultipleBlockStyles(); - - theme.setBlockStyle('styleTwo', blockStyle.styleTwo); - - stringifyAndCompare(theme.blockStyles_, blockStyle); -} - -function test_setTheme() { - defineThemeTestBlocks(); - var blockStyles = createBlockStyles(); - var workspace = new Blockly.WorkspaceSvg({}); - var blockA = workspace.newBlock('stack_block'); - var blocks = [blockA]; - - blockA.setStyle = function() {this.styleName_ = 'styleTwo'}; - var callCount = 1; - workspace.refreshToolboxSelection = function() { - return ++callCount; - }; - blockA.styleName_ = 'styleOne'; - - var mockControl_ = setUpMockMethod(Blockly, 'getMainWorkspace', null, [workspace]); - - workspace.setTheme(blockStyles); - - //Checks that the theme was set correctly on Blockly namespace - stringifyAndCompare(workspace.getTheme(), blockStyles); - - //Checks that the setTheme function was called on the block - assertEquals(blockA.getStyleName(), 'styleTwo'); - - //check that the toolbox refreshed method was called - assertEquals(workspace.refreshToolboxSelection(), 3); - - assertEquals(Blockly.Events.FIRE_QUEUE_.pop().element, 'theme'); - - undefineThemeTestBlocks(); - - mockControl_.restore(); -} - -function stringifyAndCompare(val1, val2) { - var stringVal1 = JSON.stringify(val1); - var stringVal2 = JSON.stringify(val2); - assertEquals(stringVal1, stringVal2); -} diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index 27b496fcb..b01e96989 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -1249,4 +1249,66 @@ suite('Blocks', function() { }); }); }); + + suite('Style', function() { + suite('Headless', function() { + setup(function() { + this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), this.workspace); + }); + test('Set colour', function() { + this.block.setColour('20'); + assertEquals(this.block.getColour(), '#a5745b'); + assertEquals(this.block.colour_, this.block.getColour()); + assertEquals(this.block.hue_, '20'); + }); + test('Set style', function() { + this.block.setStyle('styleOne'); + assertEquals(this.block.getStyleName(), 'styleOne'); + assertEquals(this.block.hue_, null); + // Calling setStyle does not update the colour on a headless block. + assertEquals(this.block.getColour(), '#000000'); + }); + }); + suite('Rendered', function() { + setup(function() { + this.workspace = Blockly.inject('blocklyDiv', {}); + this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), this.workspace); + this.workspace.setTheme(new Blockly.Theme({ + "styleOne" : { + "colourPrimary": "#000000", + "colourSecondary": "#999999", + "colourTertiary": "#4d4d4d", + "hat": '' + } + }), {}); + }); + teardown(function() { + this.workspace.dispose(); + }); + test('Set colour hue', function() { + this.block.setColour('20'); + assertEquals(this.block.getStyleName(), 'auto_#a5745b'); + assertEquals(this.block.getColour(), '#a5745b'); + assertEquals(this.block.colour_, this.block.getColour()); + assertEquals(this.block.hue_, '20'); + }); + test('Set colour hex', function() { + this.block.setColour('#000000'); + assertEquals(this.block.getStyleName(), 'auto_#000000'); + assertEquals(this.block.getColour(), '#000000'); + assertEquals(this.block.colour_, this.block.getColour()); + assertEquals(this.block.hue_, null); + }); + test('Set style', function() { + this.block.setStyle('styleOne'); + assertEquals(this.block.getStyleName(), 'styleOne'); + assertEquals(this.block.getColour(), '#000000'); + assertEquals(this.block.colour_, this.block.getColour()); + }); + }); + }); }); diff --git a/tests/mocha/theme_test.js b/tests/mocha/theme_test.js index 4f17b730b..e6d5f7592 100644 --- a/tests/mocha/theme_test.js +++ b/tests/mocha/theme_test.js @@ -52,9 +52,10 @@ suite('Theme', function() { function createBlockStyles() { return { "styleOne": { - "colourPrimary": "colour1", - "colourSecondary":"colour2", - "colourTertiary":"colour3" + "colourPrimary": "#aaaaaa", + "colourSecondary": "#bbbbbb", + "colourTertiary": "#cccccc", + "hat": 'cap' } }; } @@ -62,14 +63,16 @@ suite('Theme', function() { function createMultipleBlockStyles() { return { "styleOne": { - "colourPrimary": "colour1", - "colourSecondary":"colour2", - "colourTertiary":"colour3" + "colourPrimary": "#aaaaaa", + "colourSecondary": "#bbbbbb", + "colourTertiary": "#cccccc", + "hat": 'cap' }, "styleTwo": { - "colourPrimary": "colour1", - "colourSecondary":"colour2", - "colourTertiary":"colour3" + "colourPrimary": "#000000", + "colourSecondary": "#999999", + "colourTertiary": "#4d4d4d", + "hat": '' } }; } @@ -103,7 +106,7 @@ suite('Theme', function() { test('Set BlockStyle Update', function() { var theme = new Blockly.Theme(createBlockStyles()); var blockStyle = createBlockStyles(); - blockStyle.styleOne.colourPrimary = 'somethingElse'; + blockStyle.styleOne.colourPrimary = '#00ff00'; theme.setBlockStyle('styleOne', blockStyle.styleOne); @@ -152,4 +155,120 @@ suite('Theme', function() { stub.restore(); }); + suite('Validate block styles', function() { + test('Null', function() { + var inputStyle = null; + var expectedOutput = { + "colourPrimary": "#000000", + "colourSecondary": "#999999", + "colourTertiary": "#4d4d4d", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Empty', function() { + var inputStyle = {}; + var expectedOutput = { + "colourPrimary": "#000000", + "colourSecondary": "#999999", + "colourTertiary": "#4d4d4d", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Incomplete hex', function() { + var inputStyle = { + "colourPrimary": "#012345" + }; + var expectedOutput = { + "colourPrimary": "#012345", + "colourSecondary": "#99a7b5", + "colourTertiary": "#4d657d", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Complete hex', function() { + var inputStyle = { + "colourPrimary": "#aaaaaa", + "colourSecondary": "#bbbbbb", + "colourTertiary": "#cccccc", + "hat": 'cap' + }; + var expectedOutput = { + "colourPrimary": "#aaaaaa", + "colourSecondary": "#bbbbbb", + "colourTertiary": "#cccccc", + "hat": 'cap' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Complete hue', function() { + var inputStyle = { + "colourPrimary": "20", + "colourSecondary": "40", + "colourTertiary": "60", + }; + var expectedOutput = { + "colourPrimary": "#a5745b", + "colourSecondary": "#a58c5b", + "colourTertiary": "#a5a55b", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Incomplete hue', function() { + var inputStyle = { + "colourPrimary": "20", + }; + var expectedOutput = { + "colourPrimary": "#a5745b", + "colourSecondary": "#dbc7bd", + "colourTertiary": "#c09e8c", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Complete css colour name', function() { + var inputStyle = { + "colourPrimary": "red", + "colourSecondary": "white", + "colourTertiary": "blue" + }; + var expectedOutput = { + "colourPrimary": "#ff0000", + "colourSecondary": "#ffffff", + "colourTertiary": "#0000ff", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + + test('Incomplete css colour name', function() { + var inputStyle = { + "colourPrimary": "black", + }; + var expectedOutput = { + "colourPrimary": "#000000", + "colourSecondary": "#999999", + "colourTertiary": "#4d4d4d", + "hat": '' + }; + stringifyAndCompare( + Blockly.Theme.validatedBlockStyle(inputStyle), expectedOutput); + }); + }); }); From 91e211e87c5de715f61bcbffd73e04924f8fd4e8 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 30 Oct 2019 17:36:48 -0700 Subject: [PATCH 139/343] Remove tests that have been converted into mocha (#3373) * Remove tests that have been converted into mocha --- tests/jsunit/gesture_test.js | 89 ------------------------ tests/jsunit/index.html | 4 -- tests/jsunit/metrics_test.js | 129 ----------------------------------- tests/jsunit/names_test.js | 59 ---------------- 4 files changed, 281 deletions(-) delete mode 100644 tests/jsunit/gesture_test.js delete mode 100644 tests/jsunit/metrics_test.js delete mode 100644 tests/jsunit/names_test.js diff --git a/tests/jsunit/gesture_test.js b/tests/jsunit/gesture_test.js deleted file mode 100644 index 9140ab6ff..000000000 --- a/tests/jsunit/gesture_test.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /** - * @fileoverview Tests for gesture. - * @author marisaleung@google.com (Marisa Leung) - */ -'use strict'; - -var e; -var workspace; - - -function gestureTest_setUp() { - workspace = new Blockly.Workspace(); - e = {}; -} - -function gestureTest_tearDown() { - e = null; - workspace.dispose(); -} - -function test_gestureConstructor() { - var gesture = new Blockly.Gesture(e, workspace); - assertEquals(gesture.mostRecentEvent_, e); - assertEquals(gesture.creatorWorkspace_, workspace); -} - -function test_gestureIsField_ClickInWorkspace() { - gestureTest_setUp(); - var block = new Blockly.Block(workspace); - var field = new Blockly.Field(); - field.setSourceBlock(block); - field.showEditor_ = function() {}; - var gesture = new Blockly.Gesture(e, workspace); - gesture.setStartField(field); - - var isFieldClick = gesture.isFieldClick_(); - assertEquals(isFieldClick, true); - gestureTest_tearDown(); -} - -function gestureIsFieldClick_InFlyoutHelper(flyout, expectedResult){ - // Assign workspace flyout - workspace.flyout_ = flyout; - // Create a Field inside of a Block - var block = new Blockly.Block(workspace); - var field = new Blockly.Field(); - field.setSourceBlock(block); - field.showEditor_ = function() {}; - // Create gesture from the flyout - var gesture = new Blockly.Gesture(e, workspace.flyout_); - // Populate gesture with click start information - gesture.setStartField(field); - gesture.setStartFlyout_(workspace.flyout_); - - var isFieldClick = gesture.isFieldClick_(); - assertEquals(isFieldClick, expectedResult); -} - -function test_gestureIsFieldClick_AutoCloseFlyout() { - gestureTest_setUp(); - var flyout = new Blockly.VerticalFlyout({}); - gestureIsFieldClick_InFlyoutHelper(flyout, false); - gestureTest_tearDown(); -} - -function test_gestureIsFieldClick_AlwaysOpenFlyout() { - gestureTest_setUp(); - var flyout = new Blockly.VerticalFlyout({}); - flyout.autoClose = false; - gestureIsFieldClick_InFlyoutHelper(flyout, true); - gestureTest_tearDown(); -} diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index 095593cb4..d7d36a7d6 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -21,11 +21,7 @@ - - - - diff --git a/tests/jsunit/metrics_test.js b/tests/jsunit/metrics_test.js deleted file mode 100644 index 870dc5446..000000000 --- a/tests/jsunit/metrics_test.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * @license - * Copyright 2018 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -'use strict'; - -function assertDimensionsMatch(toCheck, left, top, width, height) { - assertEquals('Top did not match.', top, toCheck.top); - assertEquals('Left did not match.', left, toCheck.left); - assertEquals('Width did not match.', width, toCheck.width); - assertEquals('Height did not match.', height, toCheck.height); -} - -/** - * Make a mock workspace object with two properties: getBlocksBoundingBox and - * scale. - */ -function makeMockWs(scale, x, y, width, height) { - return { - getBlocksBoundingBox: function() { - return { - top: y, - bottom: y + height, - left: x, - right: x + width - } - }, - scale: scale - }; -} - -// Empty workspace. -var test_GetContentDimensionsExact_empty = function() { - var ws = makeMockWs(1, 0, 0, 0, 0) - var defaultZoom = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - assertDimensionsMatch(defaultZoom, 0, 0, 0, 0); -} - -var test_GetContentDimensionsExact_emptyZoomIn = function() { - var ws = makeMockWs(2, 0, 0, 0, 0) - var zoomIn = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - assertDimensionsMatch(zoomIn, 0, 0, 0, 0); -} - -var test_GetContentDimensionsExact_emptyZoomOut = function() { - var ws = makeMockWs(.5, 0, 0, 0, 0) - var zoomOut = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - assertDimensionsMatch(zoomOut, 0, 0, 0, 0); -} - -// Non-empty workspace, with top-left corner at ws origin. -var test_GetContentDimensionsExact_nonEmptyAtOrigin = function() { - var ws = makeMockWs(1, 0, 0, 100, 100) - var defaultZoom = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // Pixel and ws units are the same at default zoom. - assertDimensionsMatch(defaultZoom, 0, 0, 100, 100); -} - -var test_GetContentDimensionsExact_nonEmptyAtOriginZoomIn = function() { - var ws = makeMockWs(2, 0, 0, 100, 100) - var zoomIn = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // 1 ws unit = 2 pixels at this zoom level. - assertDimensionsMatch(zoomIn, 0, 0, 200, 200); -} - -var test_GetContentDimensionsExact_nonEmptyAtOriginZoomOut = function() { - var ws = makeMockWs(.5, 0, 0, 100, 100) - var zoomOut = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // 1 ws unit = 0.5 pixels at this zoom level. - assertDimensionsMatch(zoomOut, 0, 0, 50, 50); -} - -// Non-empty workspace, with top-left corner in positive ws coordinates. -var test_GetContentDimensionsExact_nonEmptyPositiveOrigin = function() { - var ws = makeMockWs(1, 10, 10, 100, 100) - var defaultZoom = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // Pixel and ws units are the same at default zoom. - assertDimensionsMatch(defaultZoom, 10, 10, 100, 100); -} - -// Changing zoom will change both width/height and origin location in pixels. -var test_GetContentDimensionsExact_nonEmptyPositiveOriginZoomIn = function() { - var ws = makeMockWs(2, 10, 10, 100, 100) - var zoomIn = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // 1 ws unit = 2 pixels at this zoom level. - assertDimensionsMatch(zoomIn, 20, 20, 200, 200); -} - -var test_GetContentDimensionsExact_nonEmptyPositiveOriginZoomOut = function() { - var ws = makeMockWs(.5, 10, 10, 100, 100) - var zoomOut = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // 1 ws unit = 0.5 pixels at this zoom level. - assertDimensionsMatch(zoomOut, 5, 5, 50, 50); -} - -// Non-empty workspace, with top-left corner in negative ws coordinates. -var test_GetContentDimensionsExact_nonEmptyNegativeOrigin = function() { - var ws = makeMockWs(1, -10, -10, 100, 100) - var defaultZoom = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // Pixel and ws units are the same at default zoom. - assertDimensionsMatch(defaultZoom, -10, -10, 100, 100); -} - -// Changing zoom will change both width/height and origin location in pixels. -var test_GetContentDimensionsExact_nonEmptyNegativeOriginZoomIn = function() { - var ws = makeMockWs(2, -10, -10, 100, 100) - var zoomIn = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // 1 ws unit = 2 pixels at this zoom level. - assertDimensionsMatch(zoomIn, -20, -20, 200, 200); -} - -var test_GetContentDimensionsExact_nonEmptyNegativeOriginZoomOut = function() { - var ws = makeMockWs(.5, -10, -10, 100, 100) - var zoomOut = Blockly.WorkspaceSvg.getContentDimensionsExact_(ws); - // 1 ws unit = 0.5 pixels at this zoom level. - assertDimensionsMatch(zoomOut, -5, -5, 50, 50); -} diff --git a/tests/jsunit/names_test.js b/tests/jsunit/names_test.js deleted file mode 100644 index 45dfafaa9..000000000 --- a/tests/jsunit/names_test.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @license - * Copyright 2012 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -'use strict'; - -function test_safeName() { - var varDB = new Blockly.Names('window,door'); - assertEquals('SafeName empty.', 'unnamed', varDB.safeName_('')); - assertEquals('SafeName ok.', 'foobar', varDB.safeName_('foobar')); - assertEquals('SafeName number start.', 'my_9lives', - varDB.safeName_('9lives')); - assertEquals('SafeName number end.', 'lives9', varDB.safeName_('lives9')); - assertEquals('SafeName special chars.', '____', varDB.safeName_('!@#$')); - assertEquals('SafeName reserved.', 'door', varDB.safeName_('door')); -} - -function test_getName() { - var varDB = new Blockly.Names('window,door'); - assertEquals('Name add #1.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); - assertEquals('Name get #1.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); - assertEquals('Name add #2.', 'Foo_bar2', varDB.getName('Foo bar', 'var')); - assertEquals('Name get #2.', 'Foo_bar2', varDB.getName('foo BAR', 'var')); - assertEquals('Name add #3.', 'door2', varDB.getName('door', 'var')); - assertEquals('Name add #4.', 'Foo_bar3', varDB.getName('Foo.bar', 'proc')); - assertEquals('Name get #1b.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); - assertEquals('Name get #4.', 'Foo_bar3', varDB.getName('Foo.bar', 'proc')); -} - -function test_getDistinctName() { - var varDB = new Blockly.Names('window,door'); - assertEquals('Name distinct #1.', 'Foo_bar', - varDB.getDistinctName('Foo.bar', 'var')); - assertEquals('Name distinct #2.', 'Foo_bar2', - varDB.getDistinctName('Foo.bar', 'var')); - assertEquals('Name distinct #3.', 'Foo_bar3', - varDB.getDistinctName('Foo.bar', 'proc')); - varDB.reset(); - assertEquals('Name distinct #4.', 'Foo_bar', - varDB.getDistinctName('Foo.bar', 'var')); -} - -function test_nameEquals() { - assertTrue('Name equals #1.', Blockly.Names.equals('Foo.bar', 'Foo.bar')); - assertFalse('Name equals #2.', Blockly.Names.equals('Foo.bar', 'Foo_bar')); - assertTrue('Name equals #3.', Blockly.Names.equals('Foo.bar', 'FOO.BAR')); -} From eece280d928612fd74f01394d34d623d719c3c6b Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Thu, 31 Oct 2019 09:04:10 -0700 Subject: [PATCH 140/343] Fix colour (#3374) --- core/theme/deuteranopia.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/theme/deuteranopia.js b/core/theme/deuteranopia.js index 05b4c9664..dc6d2e21f 100644 --- a/core/theme/deuteranopia.js +++ b/core/theme/deuteranopia.js @@ -34,7 +34,7 @@ Blockly.Themes.Deuteranopia = {}; Blockly.Themes.Deuteranopia.defaultBlockStyles = { "colour_blocks": { "colourPrimary": "#f2a72c", - "colourSecondary": "#f1c170", + "colourSecondary": "#f1c172", "colourTertiary": "#da921c" }, "list_blocks": { From 857f86da631d26b4fdb4661fe7183b96c93d811c Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 31 Oct 2019 18:26:08 +0100 Subject: [PATCH 141/343] Localisation updates from https://translatewiki.net. --- msg/json/ar.json | 1 + msg/json/bg.json | 1 + msg/json/fr.json | 55 ++++++++++++++++++++++--------------------- msg/json/he.json | 6 +++-- msg/json/pms.json | 1 + msg/json/qqq.json | 9 +++++++ msg/json/ru.json | 1 + msg/json/sr.json | 4 +++- msg/json/sv.json | 1 + msg/json/tr.json | 1 + msg/json/uk.json | 3 ++- msg/json/zh-hant.json | 1 + 12 files changed, 53 insertions(+), 31 deletions(-) diff --git a/msg/json/ar.json b/msg/json/ar.json index 98d256fbb..0d059ac6b 100644 --- a/msg/json/ar.json +++ b/msg/json/ar.json @@ -368,5 +368,6 @@ "PROCEDURES_IFRETURN_TOOLTIP": "إذا كانت القيمة صحيحة ، اذان قم بارجاع القيمة الثانية.", "PROCEDURES_IFRETURN_WARNING": "تحذير:هذه القطعة تستخدم فقط داخل تعريف دالة.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "قل شيئا...", + "WORKSPACE_ARIA_LABEL": "مساحة عمل بلوكلي", "COLLAPSED_WARNINGS_WARNING": "الكتل المطوية تحتوي على تحذيرات." } diff --git a/msg/json/bg.json b/msg/json/bg.json index 4d9f498c3..c0da91de2 100644 --- a/msg/json/bg.json +++ b/msg/json/bg.json @@ -352,5 +352,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Предупреждение: Този блок може да се използва само във функция.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Коментирайте нещо...", + "WORKSPACE_ARIA_LABEL": "Работна област на Blockly", "COLLAPSED_WARNINGS_WARNING": "Свитите блокове съдържат предупреждения." } diff --git a/msg/json/fr.json b/msg/json/fr.json index bad9356f1..cba61801a 100644 --- a/msg/json/fr.json +++ b/msg/json/fr.json @@ -280,11 +280,11 @@ "LISTS_INLIST": "dans la liste", "LISTS_INDEX_OF_FIRST": "trouver la première occurrence de l’élément", "LISTS_INDEX_OF_LAST": "trouver la dernière occurrence de l’élément", - "LISTS_INDEX_OF_TOOLTIP": "Renvoie l’index de la première/dernière occurrence de l’élément dans la liste. Renvoie %1 si l'élément n'est pas trouvé.", + "LISTS_INDEX_OF_TOOLTIP": "Renvoie l’index de la première/dernière occurrence de l’élément dans la liste. Renvoie %1 si l’élément n’est pas trouvé.", "LISTS_GET_INDEX_GET": "obtenir", "LISTS_GET_INDEX_GET_REMOVE": "obtenir et supprimer", "LISTS_GET_INDEX_REMOVE": "supprimer", - "LISTS_GET_INDEX_FROM_END": "# depuis la fin", + "LISTS_GET_INDEX_FROM_END": "n° depuis la fin", "LISTS_GET_INDEX_FIRST": "premier", "LISTS_GET_INDEX_LAST": "dernier", "LISTS_GET_INDEX_RANDOM": "aléatoire", @@ -305,19 +305,19 @@ "LISTS_SET_INDEX_SET": "mettre", "LISTS_SET_INDEX_INSERT": "insérer en", "LISTS_SET_INDEX_INPUT_TO": "comme", - "LISTS_SET_INDEX_TOOLTIP_SET_FROM": "Met à jour l’élément à la position indiquée dans une liste.", - "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Fixe le premier élément dans une liste.", - "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Fixe le dernier élément dans une liste.", - "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Fixe un élément au hasard dans une liste.", + "LISTS_SET_INDEX_TOOLTIP_SET_FROM": "Définit l’élément à la position indiquée dans une liste.", + "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Définit le premier élément dans une liste.", + "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Définit le dernier élément dans une liste.", + "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Définit un élément au hasard dans une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM": "Insère l’élément à la position indiquée dans une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Insère l’élément au début d’une liste.", - "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Ajouter l’élément à la fin d’une liste.", + "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Ajoute l’élément à la fin d’une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Insère l’élément au hasard dans une liste.", - "LISTS_GET_SUBLIST_START_FROM_START": "obtenir la sous-liste depuis #", - "LISTS_GET_SUBLIST_START_FROM_END": "obtenir la sous-liste depuis # depuis la fin", + "LISTS_GET_SUBLIST_START_FROM_START": "obtenir la sous-liste depuis le n°", + "LISTS_GET_SUBLIST_START_FROM_END": "obtenir la sous-liste depuis le n° depuis la fin", "LISTS_GET_SUBLIST_START_FIRST": "obtenir la sous-liste depuis le début", - "LISTS_GET_SUBLIST_END_FROM_START": "jusqu’à #", - "LISTS_GET_SUBLIST_END_FROM_END": "jusqu’à # depuis la fin", + "LISTS_GET_SUBLIST_END_FROM_START": "jusqu’au n°", + "LISTS_GET_SUBLIST_END_FROM_END": "jusqu’au n° depuis la fin", "LISTS_GET_SUBLIST_END_LAST": "jusqu’à la fin", "LISTS_GET_SUBLIST_TOOLTIP": "Crée une copie de la partie spécifiée d’une liste.", "LISTS_SORT_HELPURL": "https://github.com/google/blockly/wiki/Lists#sorting-a-list", @@ -333,38 +333,39 @@ "LISTS_SPLIT_TEXT_FROM_LIST": "créer un texte depuis la liste", "LISTS_SPLIT_WITH_DELIMITER": "avec séparateur", "LISTS_SPLIT_TOOLTIP_SPLIT": "Couper un texte en une liste de textes, en coupant à chaque séparateur.", - "LISTS_SPLIT_TOOLTIP_JOIN": "Réunir une liste de textes en un seul, en les séparant par un séparateur.", + "LISTS_SPLIT_TOOLTIP_JOIN": "Réunir une liste de textes en un seul, en les joignant par un séparateur.", "LISTS_REVERSE_HELPURL": "https://github.com/google/blockly/wiki/Lists#reversing-a-list", "LISTS_REVERSE_MESSAGE0": "inverser %1", "LISTS_REVERSE_TOOLTIP": "Inverser la copie d’une liste.", "VARIABLES_GET_TOOLTIP": "Renvoie la valeur de cette variable.", - "VARIABLES_GET_CREATE_SET": "Créer 'fixer %1'", - "VARIABLES_SET": "fixer %1 à %2", - "VARIABLES_SET_TOOLTIP": "Fixe cette variable pour qu’elle soit égale à la valeur de l’entrée.", - "VARIABLES_SET_CREATE_GET": "Créer 'obtenir %1'", + "VARIABLES_GET_CREATE_SET": "Créer « définir %1 »", + "VARIABLES_SET": "définir %1 à %2", + "VARIABLES_SET_TOOLTIP": "Définit cette variable pour qu’elle soit égale à la valeur de l’entrée.", + "VARIABLES_SET_CREATE_GET": "Créer « obtenir %1 »", "PROCEDURES_DEFNORETURN_TITLE": "pour", "PROCEDURES_DEFNORETURN_PROCEDURE": "faire quelque chose", - "PROCEDURES_BEFORE_PARAMS": "avec :", - "PROCEDURES_CALL_BEFORE_PARAMS": "avec :", + "PROCEDURES_BEFORE_PARAMS": "avec :", + "PROCEDURES_CALL_BEFORE_PARAMS": "avec :", "PROCEDURES_DEFNORETURN_TOOLTIP": "Crée une fonction sans sortie.", - "PROCEDURES_DEFNORETURN_COMMENT": "Décrire cette fonction…", - "PROCEDURES_DEFRETURN_RETURN": "retour", + "PROCEDURES_DEFNORETURN_COMMENT": "Décrivez cette fonction...", + "PROCEDURES_DEFRETURN_RETURN": "retourner", "PROCEDURES_DEFRETURN_TOOLTIP": "Crée une fonction avec une sortie.", "PROCEDURES_ALLOW_STATEMENTS": "autoriser les ordres", - "PROCEDURES_DEF_DUPLICATE_WARNING": "Attention : Cette fonction a des paramètres en double.", + "PROCEDURES_DEF_DUPLICATE_WARNING": "Attention : cette fonction a des paramètres en double.", "PROCEDURES_CALLNORETURN_HELPURL": "https://fr.wikipedia.org/wiki/Sous-programme", - "PROCEDURES_CALLNORETURN_TOOLTIP": "Exécuter la fonction '%1' définie par l’utilisateur.", + "PROCEDURES_CALLNORETURN_TOOLTIP": "Exécuter la fonction « %1 » définie par l’utilisateur.", "PROCEDURES_CALLRETURN_HELPURL": "https://fr.wikipedia.org/wiki/Sous-programme", - "PROCEDURES_CALLRETURN_TOOLTIP": "Exécuter la fonction '%1' définie par l’utilisateur et utiliser son résultat.", + "PROCEDURES_CALLRETURN_TOOLTIP": "Exécuter la fonction « %1 » définie par l’utilisateur et utiliser son résultat.", "PROCEDURES_MUTATORCONTAINER_TITLE": "entrées", "PROCEDURES_MUTATORCONTAINER_TOOLTIP": "Ajouter, supprimer, ou réarranger les entrées de cette fonction.", - "PROCEDURES_MUTATORARG_TITLE": "nom de l’entrée :", + "PROCEDURES_MUTATORARG_TITLE": "nom de l’entrée :", "PROCEDURES_MUTATORARG_TOOLTIP": "Ajouter une entrée à la fonction.", "PROCEDURES_HIGHLIGHT_DEF": "Surligner la définition de la fonction", - "PROCEDURES_CREATE_DO": "Créer '%1'", + "PROCEDURES_CREATE_DO": "Créer « %1 »", "PROCEDURES_IFRETURN_TOOLTIP": "Si une valeur est vraie, alors renvoyer une seconde valeur.", "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", - "PROCEDURES_IFRETURN_WARNING": "Attention : Ce bloc pourrait n’être utilisé que dans une définition de fonction.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Dire quelque chose…", + "PROCEDURES_IFRETURN_WARNING": "Attention : ce bloc pourrait n’être utilisé que dans une définition de fonction.", + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Expliquez quelque chose...", + "WORKSPACE_ARIA_LABEL": "Espace de travail de Blocky", "COLLAPSED_WARNINGS_WARNING": "Les blocs repliés contiennent des avertissements." } diff --git a/msg/json/he.json b/msg/json/he.json index 87b7056d8..8a862023c 100644 --- a/msg/json/he.json +++ b/msg/json/he.json @@ -15,7 +15,8 @@ "Deborahjay", "נדב ס", "Motife", - "Steeve815" + "Steeve815", + "דגש חזק" ] }, "VARIABLES_DEFAULT_NAME": "פריט", @@ -313,5 +314,6 @@ "PROCEDURES_CREATE_DO": "ליצור '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "אם ערך נכון, אז להחזיר ערך שני.", "PROCEDURES_IFRETURN_WARNING": "אזהרה: בלוק זה עשוי לשמש רק בתוך הגדרה של פונקציה.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "נא להזין הערה..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "נא להזין הערה...", + "WORKSPACE_ARIA_LABEL": "סביבת העבודה חסומה" } diff --git a/msg/json/pms.json b/msg/json/pms.json index ef19621e5..c89b503fc 100644 --- a/msg/json/pms.json +++ b/msg/json/pms.json @@ -347,5 +347,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Atension: Ës blòch a podria esse dovrà mach an na definission ëd fonsion.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Dì cheicòs...", + "WORKSPACE_ARIA_LABEL": "Spassi ëd travaj ëd Blockly", "COLLAPSED_WARNINGS_WARNING": "Ij blòch sarà a conten-o dj'avertense." } diff --git a/msg/json/qqq.json b/msg/json/qqq.json index f2b7d1723..596ea55ad 100644 --- a/msg/json/qqq.json +++ b/msg/json/qqq.json @@ -1,4 +1,13 @@ { + "@metadata": { + "authors": [ + "Espertus", + "Liuxinyu970226", + "Metalhead64", + "Robby", + "Shirayuki" + ] + }, "VARIABLES_DEFAULT_NAME": "default name - A simple, general default name for a variable, preferably short. For more context, see [[Translating:Blockly#infrequent_message_types]].\n{{Identical|Item}}", "UNNAMED_KEY": "default name - A simple, default name for an unnamed function or variable. Preferably indicates that the item is unnamed.", "TODAY": "button text - Button that sets a calendar to today's date.\n{{Identical|Today}}", diff --git a/msg/json/ru.json b/msg/json/ru.json index b4840c9b6..ef98c709a 100644 --- a/msg/json/ru.json +++ b/msg/json/ru.json @@ -361,5 +361,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Предупреждение: Этот блок может использоваться только внутри определения функции.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Напишите здесь что-нибудь...", + "WORKSPACE_ARIA_LABEL": "Рабочая область Blockly", "COLLAPSED_WARNINGS_WARNING": "Свёрнутые блоки содержат предупреждения." } diff --git a/msg/json/sr.json b/msg/json/sr.json index 1dea9cef4..36c8888cb 100644 --- a/msg/json/sr.json +++ b/msg/json/sr.json @@ -8,10 +8,12 @@ "Obsuser", "Acamicamacaraca", "BadDog", - "Милан Јелисавчић" + "Милан Јелисавчић", + "Zoranzoki21" ] }, "VARIABLES_DEFAULT_NAME": "ставка", + "UNNAMED_KEY": "неименовано", "TODAY": "Данас", "DUPLICATE_BLOCK": "Дуплирај", "ADD_COMMENT": "Додај коментар", diff --git a/msg/json/sv.json b/msg/json/sv.json index e6a718ff6..65aa0a9b0 100644 --- a/msg/json/sv.json +++ b/msg/json/sv.json @@ -372,5 +372,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Varning: Detta block får användas endast i en funktionsdefinition.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Säg någonting...", + "WORKSPACE_ARIA_LABEL": "Blocklys arbetsyta", "COLLAPSED_WARNINGS_WARNING": "Hopfällda block innehåller varningar." } diff --git a/msg/json/tr.json b/msg/json/tr.json index cd0f99098..ca24a1115 100644 --- a/msg/json/tr.json +++ b/msg/json/tr.json @@ -386,5 +386,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Uyarı: Bu blok yalnızca bir fonksiyon tanımı içinde kullanılır.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Bir şeyler söyle...", + "WORKSPACE_ARIA_LABEL": "Blockly Çalışma Alanı", "COLLAPSED_WARNINGS_WARNING": "Daraltılmış bloklar uyarı içerir." } diff --git a/msg/json/uk.json b/msg/json/uk.json index d9446aa1b..9b2e02d0f 100644 --- a/msg/json/uk.json +++ b/msg/json/uk.json @@ -25,7 +25,7 @@ "DELETE_BLOCK": "Видалити блок", "DELETE_X_BLOCKS": "Видалити %1 блоків", "DELETE_ALL_BLOCKS": "Вилучити всі блоки %1?", - "CLEAN_UP": "Вирівняти блоки", + "CLEAN_UP": "Очистити блоки", "COLLAPSE_BLOCK": "Згорнути блок", "COLLAPSE_ALL": "Згорнути блоки", "EXPAND_BLOCK": "Розгорнути блок", @@ -367,5 +367,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Попередження: цей блок може використовуватися лише в межах визначення функції.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Скажіть щось...", + "WORKSPACE_ARIA_LABEL": "Робоча область Blockly", "COLLAPSED_WARNINGS_WARNING": "Звернуті блоки містять попередження." } diff --git a/msg/json/zh-hant.json b/msg/json/zh-hant.json index 547c22e57..e87fea7b9 100644 --- a/msg/json/zh-hant.json +++ b/msg/json/zh-hant.json @@ -357,5 +357,6 @@ "PROCEDURES_IFRETURN_TOOLTIP": "如果值為 true,則返回第二個值。", "PROCEDURES_IFRETURN_WARNING": "警告:這個區塊只可以在定義函式時使用。", "WORKSPACE_COMMENT_DEFAULT_TEXT": "來說些事情...", + "WORKSPACE_ARIA_LABEL": "Blockly 工作區", "COLLAPSED_WARNINGS_WARNING": "收合含有警告的區塊。" } From 123f436e04e70a99cc95fe889d1f5423036b2454 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 31 Oct 2019 15:17:35 -0700 Subject: [PATCH 142/343] Add parens around inline assignments (#3381) --- .eslintrc.json | 2 - blocks/procedures.js | 6 +- blocks/text.js | 4 +- core/block.js | 74 +++++++++++------------- core/block_dragger.js | 2 +- core/block_events.js | 4 +- core/block_svg.js | 22 +++---- core/blockly.js | 10 ++-- core/connection.js | 9 ++- core/contextmenu.js | 2 +- core/events.js | 12 ++-- core/field_dropdown.js | 4 +- core/field_multilineinput.js | 2 +- core/flyout_base.js | 12 ++-- core/flyout_vertical.js | 6 +- core/generator.js | 2 +- core/gesture.js | 2 +- core/inject.js | 2 +- core/input.js | 8 +-- core/keyboard_nav/ast_node.js | 18 +++--- core/keyboard_nav/key_map.js | 6 +- core/keyboard_nav/tab_navigate_cursor.js | 4 +- core/mutator.js | 6 +- core/procedures.js | 2 +- core/rendered_connection.js | 7 +-- core/theme_manager.js | 2 +- core/toolbox.js | 6 +- core/trashcan.js | 2 +- core/utils.js | 2 +- core/variable_map.js | 8 +-- core/variables.js | 8 +-- core/variables_dynamic.js | 2 +- core/warning.js | 2 +- core/workspace.js | 12 ++-- core/workspace_svg.js | 8 +-- core/xml.js | 24 ++++---- tests/mocha/procedures_test.js | 4 +- tests/mocha/xml_procedures_test.js | 2 +- tests/mocha/xml_test.js | 4 +- 39 files changed, 152 insertions(+), 162 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 3df051d4a..63bfb43b7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -61,8 +61,6 @@ "space-infix-ops": ["error"], "_comment": "Blockly uses 'use strict' in files", "strict": ["off"], - "_comment": "Blockly often uses cond-assignment in loops", - "no-cond-assign": ["off"], "_comment": "Closure style allows redeclarations", "no-redeclare": ["off"], "valid-jsdoc": ["error", {"requireReturn": false}], diff --git a/blocks/procedures.js b/blocks/procedures.js index 4b6e44975..7487a0c92 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -139,7 +139,7 @@ Blockly.Blocks['procedures_defnoreturn'] = { domToMutation: function(xmlElement) { this.arguments_ = []; this.argumentVarModels_ = []; - for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) { + for (var i = 0, childNode; (childNode = xmlElement.childNodes[i]); i++) { if (childNode.nodeName.toLowerCase() == 'arg') { var varName = childNode.getAttribute('name'); var varId = childNode.getAttribute('varid') || childNode.getAttribute('varId'); @@ -354,7 +354,7 @@ Blockly.Blocks['procedures_defnoreturn'] = { // Update the mutator's variables if the mutator is open. if (this.mutator && this.mutator.isVisible()) { var blocks = this.mutator.workspace_.getAllBlocks(false); - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { if (block.type == 'procedures_mutatorarg' && Blockly.Names.equals(oldName, block.getFieldValue('NAME'))) { block.setFieldValue(newName, 'NAME'); @@ -859,7 +859,7 @@ Blockly.Blocks['procedures_callnoreturn'] = { this.renameProcedure(this.getProcedureCall(), name); var args = []; var paramIds = []; - for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) { + for (var i = 0, childNode; (childNode = xmlElement.childNodes[i]); i++) { if (childNode.nodeName.toLowerCase() == 'arg') { args.push(childNode.getAttribute('name')); paramIds.push(childNode.getAttribute('paramId')); diff --git a/blocks/text.js b/blocks/text.js index 21a4e4df5..fe4b9c97f 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -638,8 +638,8 @@ Blockly.Constants.Text.QUOTE_IMAGE_MIXIN = { * @this {Blockly.Block} */ quoteField_: function(fieldName) { - for (var i = 0, input; input = this.inputList[i]; i++) { - for (var j = 0, field; field = input.fieldRow[j]; j++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { if (fieldName == field.name) { input.insertFieldAt(j, this.newQuote_(true)); input.insertFieldAt(j + 2, this.newQuote_(false)); diff --git a/core/block.js b/core/block.js index 9c1cdb38f..46893575a 100644 --- a/core/block.js +++ b/core/block.js @@ -359,13 +359,13 @@ Blockly.Block.prototype.dispose = function(healStack) { } // Then dispose of myself. // Dispose of all inputs and their fields. - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var 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++) { + for (var i = 0, connection; (connection = connections[i]); i++) { connection.dispose(); } } finally { @@ -384,8 +384,8 @@ Blockly.Block.prototype.dispose = function(healStack) { * @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++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { if (field.initModel) { field.initModel(); } @@ -516,7 +516,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 (var i = 0, input; (input = this.inputList[i]); i++) { if (input.connection) { myConnections.push(input.connection); } @@ -567,7 +567,7 @@ Blockly.Block.prototype.getParent = function() { * @return {Blockly.Input} The input that connects to the specified block. */ Blockly.Block.prototype.getInputWithBlock = function(block) { - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { if (input.connection && input.connection.targetBlock() == block) { return input; } @@ -618,7 +618,7 @@ Blockly.Block.prototype.getPreviousBlock = function() { * @package */ Blockly.Block.prototype.getFirstStatementConnection = function() { - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { if (input.connection && input.connection.type == Blockly.NEXT_STATEMENT) { return input.connection; } @@ -669,7 +669,7 @@ Blockly.Block.prototype.getChildren = function(ordered) { return this.childBlocks_; } var blocks = []; - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { if (input.connection) { var child = input.connection.targetBlock(); if (child) { @@ -732,7 +732,7 @@ Blockly.Block.prototype.setParent = function(newParent) { Blockly.Block.prototype.getDescendants = function(ordered) { var blocks = [this]; var childBlocks = this.getChildren(ordered); - for (var child, i = 0; child = childBlocks[i]; i++) { + for (var child, i = 0; (child = childBlocks[i]); i++) { blocks.push.apply(blocks, child.getDescendants(ordered)); } return blocks; @@ -836,8 +836,8 @@ Blockly.Block.prototype.isEditable = function() { */ Blockly.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 (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { field.updateEditable(); } } @@ -956,8 +956,8 @@ Blockly.Block.prototype.setOnChange = function(onchangeFn) { * @return {Blockly.Field} Named field, or null if field does not exist. */ Blockly.Block.prototype.getField = function(name) { - for (var i = 0, input; input = this.inputList[i]; i++) { - for (var j = 0, field; field = input.fieldRow[j]; j++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { if (field.name == name) { return field; } @@ -973,8 +973,8 @@ Blockly.Block.prototype.getField = function(name) { */ 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++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { if (field.referencesVariables()) { vars.push(field.getValue()); } @@ -990,8 +990,8 @@ Blockly.Block.prototype.getVars = function() { */ 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++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { if (field.referencesVariables()) { var model = this.workspace.getVariableById( /** @type {string} */ (field.getValue())); @@ -1013,8 +1013,8 @@ Blockly.Block.prototype.getVarModels = function() { * @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++) { + 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()) { field.refreshVariableName(); @@ -1031,8 +1031,8 @@ Blockly.Block.prototype.updateVarName = function(variable) { * 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++) { + 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()) { field.setValue(newId); @@ -1277,8 +1277,8 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) { if (this.collapsed_) { text.push(this.getInput('_TEMP_COLLAPSED_INPUT').fieldRow[0].getText()); } else { - for (var i = 0, input; input = this.inputList[i]; i++) { - for (var j = 0, field; field = input.fieldRow[j]; j++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { text.push(field.getText()); } if (input.connection) { @@ -1573,11 +1573,9 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign, field = Blockly.fieldRegistry.fromJson(element); // Unknown field. - if (!field) { - if (element['alt']) { - element = element['alt']; - altRepeat = true; - } + if (!field && element['alt']) { + element = element['alt']; + altRepeat = true; } } } @@ -1589,13 +1587,12 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign, input.setCheck(element['check']); } if (element['align']) { - var align = !!element['align'] && element['align'].toUpperCase(); - var alignment = alignmentLookup[align]; - if (alignment != undefined) { - input.setAlign(alignment); - } else { + var alignment = alignmentLookup[element['align'].toUpperCase()]; + if (alignment === undefined) { console.warn(warningPrefix + 'Illegal align value: ', element['align']); + } else { + input.setAlign(alignment); } } for (var j = 0; j < fieldStack.length; j++) { @@ -1640,7 +1637,7 @@ Blockly.Block.prototype.moveInputBefore = function(name, refName) { // Find both inputs. var inputIndex = -1; var refIndex = refName ? -1 : this.inputList.length; - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { if (input.name == name) { inputIndex = i; if (refIndex != -1) { @@ -1693,11 +1690,10 @@ 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 error if input is not present. - * @throws {Error} if the input is not present and - * opt_quiet is not 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++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { if (input.name == name) { input.dispose(); this.inputList.splice(i, 1); @@ -1715,7 +1711,7 @@ Blockly.Block.prototype.removeInput = function(name, opt_quiet) { * @return {Blockly.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++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { if (input.name == name) { return input; } @@ -1827,7 +1823,7 @@ 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 (var i = 0, input; (input = this.inputList[i]); i++) { if (!input.connection) { continue; } diff --git a/core/block_dragger.js b/core/block_dragger.js index 9e881c6b3..fb1a78e28 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -120,7 +120,7 @@ Blockly.BlockDragger.initIconData_ = function(block) { // Build a list of icons that need to be moved and where they started. var dragIconData = []; var descendants = block.getDescendants(false); - for (var i = 0, descendant; descendant = descendants[i]; i++) { + for (var i = 0, descendant; (descendant = descendants[i]); i++) { var icons = descendant.getIcons(); for (var j = 0; j < icons.length; j++) { var data = { diff --git a/core/block_events.js b/core/block_events.js index 7c80dfca7..beff260af 100644 --- a/core/block_events.js +++ b/core/block_events.js @@ -273,7 +273,7 @@ Blockly.Events.Create.prototype.run = function(forward) { xml.appendChild(this.xml); Blockly.Xml.domToWorkspace(xml, workspace); } else { - for (var i = 0, id; id = this.ids[i]; i++) { + for (var i = 0, id; (id = this.ids[i]); i++) { var block = workspace.getBlockById(id); if (block) { block.dispose(false); @@ -349,7 +349,7 @@ Blockly.Events.Delete.prototype.fromJson = function(json) { Blockly.Events.Delete.prototype.run = function(forward) { var workspace = this.getEventWorkspace_(); if (forward) { - for (var i = 0, id; id = this.ids[i]; i++) { + for (var i = 0, id; (id = this.ids[i]); i++) { var block = workspace.getBlockById(id); if (block) { block.dispose(false); diff --git a/core/block_svg.js b/core/block_svg.js index 2a2a83c9c..d568207fd 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -258,7 +258,7 @@ Blockly.BlockSvg.prototype.initSvg = function() { if (!this.workspace.rendered) { throw TypeError('Workspace is headless.'); } - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { input.init(); } var icons = this.getIcons(); @@ -621,7 +621,7 @@ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { * A dirty field is a field that needs to be re-rendererd. */ Blockly.BlockSvg.prototype.markDirty = function() { - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { input.markDirty(); } }; @@ -636,7 +636,7 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { } var renderList = []; // Show/hide the inputs. - for (var i = 0, input; input = this.inputList[i]; i++) { + for (var i = 0, input; (input = this.inputList[i]); i++) { renderList.push.apply(renderList, input.setVisible(!collapsed)); } @@ -656,7 +656,7 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { var index = descendants.indexOf(nextBlock); descendants.splice(index, descendants.length - index); } - for (var i = 1, block; block = descendants[i]; i++) { + for (var i = 1, block; (block = descendants[i]); i++) { if (block.warning) { this.setWarningText(Blockly.Msg['COLLAPSED_WARNINGS_WARNING'], Blockly.BlockSvg.COLLAPSED_WARNING_ID); @@ -680,7 +680,7 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) { renderList[0] = this; } if (this.rendered) { - for (var i = 0, block; block = renderList[i]; i++) { + for (var i = 0, block; (block = renderList[i]); i++) { block.render(); } // Don't bump neighbours. @@ -1045,8 +1045,8 @@ Blockly.BlockSvg.prototype.applyColour = function() { icons[i].applyColour(); } - for (var x = 0, input; input = this.inputList[x]; x++) { - for (var y = 0, field; field = input.fieldRow[y]; y++) { + for (var x = 0, input; (input = this.inputList[x]); x++) { + for (var y = 0, field; (field = input.fieldRow[y]); y++) { field.applyColour(); } } @@ -1071,7 +1071,7 @@ Blockly.BlockSvg.prototype.updateDisabled = function() { } } var children = this.getChildren(false); - for (var i = 0, child; child = children[i]; i++) { + for (var i = 0, child; (child = children[i]); i++) { child.updateDisabled(); } }; @@ -1544,7 +1544,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 (var i = 0, input; (input = this.inputList[i]); i++) { if (input.connection) { myConnections.push(input.connection); } @@ -1610,7 +1610,7 @@ Blockly.BlockSvg.prototype.bumpNeighbours = function() { } // Loop through every connection on this block. var myConnections = this.getConnections_(false); - for (var i = 0, connection; connection = myConnections[i]; i++) { + for (var i = 0, connection; (connection = myConnections[i]); i++) { // Spider down from this block bumping all sub-blocks. if (connection.isConnected() && connection.isSuperior()) { @@ -1618,7 +1618,7 @@ Blockly.BlockSvg.prototype.bumpNeighbours = function() { } var neighbours = connection.neighbours(Blockly.SNAP_RADIUS); - for (var j = 0, otherConnection; otherConnection = neighbours[j]; j++) { + for (var 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. diff --git a/core/blockly.js b/core/blockly.js index fd75b34a6..5f707a500 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -470,7 +470,7 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, // 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++) { + for (var i = 0, event; (event = events[i]); i++) { if (captureIdentifier && !Blockly.Touch.shouldHandleEvent(event)) { continue; } @@ -487,7 +487,7 @@ Blockly.bindEventWithChecks_ = 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++) { + for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); } @@ -506,7 +506,7 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, e.preventDefault(); } }; - for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) { + for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { node.addEventListener(type, touchWrapFunc, false); bindData.push([node, type, touchWrapFunc]); } @@ -539,7 +539,7 @@ Blockly.bindEvent_ = 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++) { + for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); } @@ -562,7 +562,7 @@ Blockly.bindEvent_ = 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 (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) { node.addEventListener(type, touchWrapFunc, false); bindData.push([node, type, touchWrapFunc]); } diff --git a/core/connection.js b/core/connection.js index fabc9fff6..4bc0e40b7 100644 --- a/core/connection.js +++ b/core/connection.js @@ -496,15 +496,14 @@ Blockly.Connection.singleConnection_ = function(block, orphanBlock) { * @param {!Blockly.Block} startBlock The block on which to start the search. * @param {!Blockly.Block} orphanBlock The block that is looking for a home. * @return {Blockly.Connection} The suitable connection point on the chain - * of blocks, or null. + * of blocks, or null. * @package */ Blockly.Connection.lastConnectionInRow = function(startBlock, orphanBlock) { var newBlock = startBlock; var connection; - while (connection = Blockly.Connection.singleConnection_( - /** @type {!Blockly.Block} */ (newBlock), orphanBlock)) { - // '=' is intentional in line above. + while ((connection = Blockly.Connection.singleConnection_( + /** @type {!Blockly.Block} */ (newBlock), orphanBlock))) { newBlock = connection.targetBlock(); if (!newBlock || newBlock.isShadow()) { return connection; @@ -749,7 +748,7 @@ Blockly.Connection.prototype.toString = function() { msg = 'Next Connection of '; } else { var parentInput = null; - for (var i = 0, input; input = block.inputList[i]; i++) { + for (var i = 0, input; (input = block.inputList[i]); i++) { if (input.connection == this) { parentInput = input; break; diff --git a/core/contextmenu.js b/core/contextmenu.js index efbf0c981..9feee57d8 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -89,7 +89,7 @@ Blockly.ContextMenu.populate_ = function(options, rtl) { */ var menu = new Blockly.Menu(); menu.setRightToLeft(rtl); - for (var i = 0, option; option = options[i]; i++) { + for (var i = 0, option; (option = options[i]); i++) { var menuItem = new Blockly.MenuItem(option.text); menuItem.setRightToLeft(rtl); menu.addChild(menuItem, true); diff --git a/core/events.js b/core/events.js index d58771afa..7ebd9caa6 100644 --- a/core/events.js +++ b/core/events.js @@ -194,7 +194,7 @@ Blockly.Events.fire = function(event) { Blockly.Events.fireNow_ = function() { var queue = Blockly.Events.filter(Blockly.Events.FIRE_QUEUE_, true); Blockly.Events.FIRE_QUEUE_.length = 0; - for (var i = 0, event; event = queue[i]; i++) { + for (var i = 0, event; (event = queue[i]); i++) { if (!event.workspaceId) { continue; } @@ -220,7 +220,7 @@ Blockly.Events.filter = function(queueIn, forward) { var mergedQueue = []; var hash = Object.create(null); // Merge duplicates. - for (var i = 0, event; event = queue[i]; i++) { + for (var i = 0, event; (event = queue[i]); i++) { if (!event.isNull()) { var key = [event.type, event.blockId, event.workspaceId].join(' '); @@ -266,7 +266,7 @@ Blockly.Events.filter = function(queueIn, forward) { } // Move mutation events to the top of the queue. // Intentionally skip first event. - for (var i = 1, event; event = queue[i]; i++) { + for (var i = 1, event; (event = queue[i]); i++) { if (event.type == Blockly.Events.CHANGE && event.element == 'mutation') { queue.unshift(queue.splice(i, 1)[0]); @@ -280,7 +280,7 @@ Blockly.Events.filter = function(queueIn, forward) { * in the undo stack. Called by Blockly.Workspace.clearUndo. */ Blockly.Events.clearPendingUndo = function() { - for (var i = 0, event; event = Blockly.Events.FIRE_QUEUE_[i]; i++) { + for (var i = 0, event; (event = Blockly.Events.FIRE_QUEUE_[i]); i++) { event.recordUndo = false; } }; @@ -338,7 +338,7 @@ Blockly.Events.setGroup = function(state) { Blockly.Events.getDescendantIds = function(block) { var ids = []; var descendants = block.getDescendants(false); - for (var i = 0, descendant; descendant = descendants[i]; i++) { + for (var i = 0, descendant; (descendant = descendants[i]); i++) { ids[i] = descendant.id; } return ids; @@ -420,7 +420,7 @@ Blockly.Events.disableOrphans = function(event) { var parent = block.getParent(); if (parent && parent.isEnabled()) { var children = block.getDescendants(false); - for (var i = 0, child; child = children[i]; i++) { + for (var i = 0, child; (child = children[i]); i++) { child.setEnabled(true); } } else if ((block.outputConnection || block.previousConnection) && diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 5693d107c..379516720 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -430,7 +430,7 @@ Blockly.FieldDropdown.prototype.getOptions = function(opt_useCache) { Blockly.FieldDropdown.prototype.doClassValidation_ = function(opt_newValue) { var isValueValid = false; var options = this.getOptions(true); - for (var i = 0, option; option = options[i]; i++) { + for (var i = 0, option; (option = options[i]); i++) { // Options are tuples of human-readable text and language-neutral values. if (option[1] == opt_newValue) { isValueValid = true; @@ -457,7 +457,7 @@ Blockly.FieldDropdown.prototype.doClassValidation_ = function(opt_newValue) { Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) { Blockly.FieldDropdown.superClass_.doValueUpdate_.call(this, newValue); var options = this.getOptions(true); - for (var i = 0, option; option = options[i]; i++) { + for (var i = 0, option; (option = options[i]); i++) { if (option[1] == this.value_) { this.selectedIndex_ = i; } diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 9ecf70bf5..3b07937cc 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -146,7 +146,7 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() { Blockly.FieldMultilineInput.prototype.render_ = function() { // Remove all text group children. var currentChild; - while (currentChild = this.textGroup_.firstChild) { + while ((currentChild = this.textGroup_.firstChild)) { this.textGroup_.removeChild(currentChild); } diff --git a/core/flyout_base.js b/core/flyout_base.js index 90ad2357d..c5e9e7236 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -422,7 +422,7 @@ Blockly.Flyout.prototype.hide = function() { } this.setVisible(false); // Delete all the event listeners. - for (var i = 0, listen; listen = this.listeners_[i]; i++) { + for (var i = 0, listen; (listen = this.listeners_[i]); i++) { Blockly.unbindEvent_(listen); } this.listeners_.length = 0; @@ -466,7 +466,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { var gaps = []; this.permanentlyDisabled_.length = 0; var default_gap = this.horizontalLayout_ ? this.GAP_X : this.GAP_Y; - for (var i = 0, xml; xml = xmlList[i]; i++) { + for (var i = 0, xml; (xml = xmlList[i]); i++) { if (!xml.tagName) { continue; } @@ -517,7 +517,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { // When the mouse is over the background, deselect all blocks. var deselectAll = function() { var topBlocks = this.workspace_.getTopBlocks(false); - for (var i = 0, block; block = topBlocks[i]; i++) { + for (var i = 0, block; (block = topBlocks[i]); i++) { block.removeSelect(); } }; @@ -549,7 +549,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { Blockly.Flyout.prototype.clearOldBlocks_ = function() { // Delete any blocks from a previous showing. var oldBlocks = this.workspace_.getTopBlocks(false); - for (var i = 0, block; block = oldBlocks[i]; i++) { + for (var i = 0, block; (block = oldBlocks[i]); i++) { if (block.workspace == this.workspace_) { block.dispose(false, false); } @@ -563,7 +563,7 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() { } this.mats_.length = 0; // Delete any buttons from a previous showing. - for (var i = 0, button; button = this.buttons_[i]; i++) { + for (var i = 0, button; (button = this.buttons_[i]); i++) { button.dispose(); } this.buttons_.length = 0; @@ -756,7 +756,7 @@ Blockly.Flyout.prototype.moveRectToBlock_ = function(rect, block) { */ Blockly.Flyout.prototype.filterForCapacity_ = function() { var blocks = this.workspace_.getTopBlocks(false); - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { if (this.permanentlyDisabled_.indexOf(block) == -1) { var enable = this.targetWorkspace_ .isCapacityAvailable(Blockly.utils.getBlockTypeCounts(block)); diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 9a6b52e38..0404ff205 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -259,11 +259,11 @@ Blockly.VerticalFlyout.prototype.layout_ = function(contents, gaps) { var cursorX = this.RTL ? margin : margin + this.tabWidth_; var cursorY = margin; - for (var i = 0, item; item = contents[i]; i++) { + for (var i = 0, item; (item = contents[i]); i++) { if (item.type == 'block') { var block = item.block; var allBlocks = block.getDescendants(false); - for (var j = 0, child; child = allBlocks[j]; j++) { + for (var j = 0, child; (child = allBlocks[j]); j++) { // Mark blocks as being inside a flyout. This is used to detect and // prevent the closure of the flyout if the user right-clicks on such a // block. @@ -361,7 +361,7 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() { flyoutWidth += Blockly.Scrollbar.scrollbarThickness; if (this.width_ != flyoutWidth) { - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { if (this.RTL) { // With the flyoutWidth known, right-align the blocks. var oldX = block.getRelativeToSurfaceXY().x; diff --git a/core/generator.js b/core/generator.js index e73adfe52..8a73d5f8c 100644 --- a/core/generator.js +++ b/core/generator.js @@ -101,7 +101,7 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) { var code = []; this.init(workspace); var blocks = workspace.getTopBlocks(true); - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { var line = this.blockToCode(block); if (Array.isArray(line)) { // Value blocks return tuples of code and operator order. diff --git a/core/gesture.js b/core/gesture.js index c07a19bef..758aad0e8 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -972,7 +972,7 @@ Blockly.Gesture.prototype.getInsertionMarkers = function() { */ Blockly.Gesture.inProgress = function() { var workspaces = Blockly.Workspace.getAll(); - for (var i = 0, workspace; workspace = workspaces[i]; i++) { + for (var i = 0, workspace; (workspace = workspaces[i]); i++) { if (workspace.currentGesture_) { return true; } diff --git a/core/inject.js b/core/inject.js index ee07595e9..805200e75 100644 --- a/core/inject.js +++ b/core/inject.js @@ -473,7 +473,7 @@ Blockly.inject.bindDocumentEvents_ = function() { if (!Blockly.documentEventsBound_) { Blockly.bindEventWithChecks_(document, 'scroll', null, function() { var workspaces = Blockly.Workspace.getAll(); - for (var i = 0, workspace; workspace = workspaces[i]; i++) { + for (var i = 0, workspace; (workspace = workspaces[i]); i++) { if (workspace.updateInverseScreenCTM) { workspace.updateInverseScreenCTM(); } diff --git a/core/input.js b/core/input.js index 9326d05de..b8fd2e944 100644 --- a/core/input.js +++ b/core/input.js @@ -144,7 +144,7 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) { * @throws {Error} if the field is not present. */ Blockly.Input.prototype.removeField = function(name) { - for (var i = 0, field; field = this.fieldRow[i]; i++) { + for (var i = 0, field; (field = this.fieldRow[i]); i++) { if (field.name === name) { field.dispose(); this.fieldRow.splice(i, 1); @@ -185,7 +185,7 @@ Blockly.Input.prototype.setVisible = function(visible) { this.visible_ = visible; var display = visible ? 'block' : 'none'; - for (var y = 0, field; field = this.fieldRow[y]; y++) { + for (var y = 0, field; (field = this.fieldRow[y]); y++) { field.setVisible(visible); } if (this.connection) { @@ -211,7 +211,7 @@ Blockly.Input.prototype.setVisible = function(visible) { * @package */ Blockly.Input.prototype.markDirty = function() { - for (var y = 0, field; field = this.fieldRow[y]; y++) { + for (var y = 0, field; (field = this.fieldRow[y]); y++) { field.markDirty(); } }; @@ -261,7 +261,7 @@ Blockly.Input.prototype.init = function() { * @suppress {checkTypes} */ Blockly.Input.prototype.dispose = function() { - for (var i = 0, field; field = this.fieldRow[i]; i++) { + for (var i = 0, field; (field = this.fieldRow[i]); i++) { field.dispose(); } if (this.connection) { diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index da885b59f..133591a6b 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -269,9 +269,9 @@ Blockly.ASTNode.prototype.findNextForInput_ = function() { var parentInput = this.location_.getParentInput(); var block = parentInput.getSourceBlock(); var curIdx = block.inputList.indexOf(parentInput); - for (var i = curIdx + 1, input; input = block.inputList[i]; i++) { + for (var i = curIdx + 1, input; (input = block.inputList[i]); i++) { var fieldRow = input.fieldRow; - for (var j = 0, field; field = fieldRow[j]; j++) { + for (var j = 0, field; (field = fieldRow[j]); j++) { if (field.EDITABLE) { return Blockly.ASTNode.createFieldNode(field); } @@ -297,7 +297,7 @@ Blockly.ASTNode.prototype.findNextForField_ = function() { 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++) { + for (var i = curIdx, newInput; (newInput = block.inputList[i]); i++) { var fieldRow = newInput.fieldRow; while (fieldIdx < fieldRow.length) { if (fieldRow[fieldIdx].EDITABLE) { @@ -325,12 +325,12 @@ Blockly.ASTNode.prototype.findPrevForInput_ = function() { var location = this.location_.getParentInput(); var block = location.getSourceBlock(); var curIdx = block.inputList.indexOf(location); - for (var i = curIdx, input; input = block.inputList[i]; i--) { + for (var i = curIdx, input; (input = block.inputList[i]); i--) { if (input.connection && input !== location) { return Blockly.ASTNode.createInputNode(input); } var fieldRow = input.fieldRow; - for (var j = fieldRow.length - 1, field; field = fieldRow[j]; j--) { + for (var j = fieldRow.length - 1, field; (field = fieldRow[j]); j--) { if (field.EDITABLE) { return Blockly.ASTNode.createFieldNode(field); } @@ -352,7 +352,7 @@ Blockly.ASTNode.prototype.findPrevForField_ = function() { 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--) { + for (var i = curIdx, input; (input = block.inputList[i]); i--) { if (input.connection && input !== parentInput) { return Blockly.ASTNode.createInputNode(input); } @@ -388,7 +388,7 @@ Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) { } var curRoot = curLocation.getRootBlock(); var topBlocks = curRoot.workspace.getTopBlocks(true); - for (var i = 0, topBlock; topBlock = topBlocks[i]; i++) { + for (var i = 0, topBlock; (topBlock = topBlocks[i]); i++) { if (curRoot.id == topBlock.id) { var offset = forward ? 1 : -1; var resultIndex = i + offset; @@ -459,9 +459,9 @@ Blockly.ASTNode.prototype.getOutAstNodeForBlock_ = function(block) { */ Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) { var inputs = block.inputList; - for (var i = 0, input; input = inputs[i]; i++) { + for (var i = 0, input; (input = inputs[i]); i++) { var fieldRow = input.fieldRow; - for (var j = 0, field; field = fieldRow[j]; j++) { + for (var j = 0, field; (field = fieldRow[j]); j++) { if (field.EDITABLE) { return Blockly.ASTNode.createFieldNode(field); } diff --git a/core/keyboard_nav/key_map.js b/core/keyboard_nav/key_map.js index e8bc32c54..81f92eb59 100644 --- a/core/keyboard_nav/key_map.js +++ b/core/keyboard_nav/key_map.js @@ -104,7 +104,7 @@ Blockly.user.keyMap.getActionByKeyCode = function(keyCode) { */ Blockly.user.keyMap.getKeyByAction = function(action) { var keys = Object.keys(Blockly.user.keyMap.map_); - for (var i = 0, key; key = keys[i]; i++) { + for (var i = 0, key; (key = keys[i]); i++) { if (Blockly.user.keyMap.map_[key].name === action.name) { return key; } @@ -120,7 +120,7 @@ Blockly.user.keyMap.getKeyByAction = function(action) { Blockly.user.keyMap.serializeKeyEvent = function(e) { var modifiers = Blockly.utils.object.values(Blockly.user.keyMap.modifierKeys); var key = ''; - for (var i = 0, keyName; keyName = modifiers[i]; i++) { + for (var i = 0, keyName; (keyName = modifiers[i]); i++) { if (e.getModifierState(keyName)) { key += keyName; } @@ -139,7 +139,7 @@ Blockly.user.keyMap.serializeKeyEvent = function(e) { Blockly.user.keyMap.createSerializedKey = function(keyCode, modifiers) { var key = ''; var validModifiers = Blockly.utils.object.values(Blockly.user.keyMap.modifierKeys); - for (var i = 0, keyName; keyName = modifiers[i]; i++) { + for (var i = 0, keyName; (keyName = modifiers[i]); i++) { if (validModifiers.indexOf(keyName) > -1) { key += keyName; } else { diff --git a/core/keyboard_nav/tab_navigate_cursor.js b/core/keyboard_nav/tab_navigate_cursor.js index f6cf9435e..0bf65500d 100644 --- a/core/keyboard_nav/tab_navigate_cursor.js +++ b/core/keyboard_nav/tab_navigate_cursor.js @@ -39,7 +39,6 @@ Blockly.TabNavigateCursor = function() { }; Blockly.utils.object.inherits(Blockly.TabNavigateCursor, Blockly.Cursor); - /** * Find the next node in the pre order traversal. * @override @@ -67,7 +66,7 @@ Blockly.TabNavigateCursor.prototype.prev = function() { return null; } var newNode = this.getPreviousNode_(curNode); - + if (newNode) { this.setCurNode(newNode); } @@ -153,7 +152,6 @@ Blockly.TabNavigateCursor.prototype.getRightMostChild_ = function(node) { newNode = newNode.next(); } return this.getRightMostChild_(newNode); - }; /** diff --git a/core/mutator.js b/core/mutator.js index 061420dbc..3b1a1ff4b 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -142,7 +142,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { // Convert the list of names into a list of XML objects for the flyout. if (this.quarkNames_.length) { var quarkXml = Blockly.utils.xml.createElement('xml'); - for (var i = 0, quarkName; quarkName = this.quarkNames_[i]; i++) { + for (var i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) { var element = Blockly.utils.xml.createElement('block'); element.setAttribute('type', quarkName); quarkXml.appendChild(element); @@ -290,7 +290,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) { this.rootBlock_ = this.block_.decompose(this.workspace_); var blocks = this.rootBlock_.getDescendants(false); - for (var i = 0, child; child = blocks[i]; i++) { + for (var i = 0, child; (child = blocks[i]); i++) { child.render(); } // The root block should not be dragable or deletable. @@ -356,7 +356,7 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) { if (!this.workspace_.isDragging()) { var blocks = this.workspace_.getTopBlocks(false); var MARGIN = 20; - for (var b = 0, block; block = blocks[b]; b++) { + for (var b = 0, block; (block = blocks[b]); b++) { var blockXY = block.getRelativeToSurfaceXY(); var blockHW = block.getHeightWidth(); if (blockXY.y + blockHW.height < MARGIN) { diff --git a/core/procedures.js b/core/procedures.js index 6023dbe9c..5205f09f5 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -307,7 +307,7 @@ Blockly.Procedures.mutateCallers = function(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++) { + for (var i = 0, caller; (caller = callers[i]); i++) { var oldMutationDom = caller.mutationToDom(); var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); caller.domToMutation(xmlElement); diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 67129772e..f5d55ab1b 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -216,8 +216,8 @@ Blockly.RenderedConnection.prototype.moveBy = function(dx, 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 corner - * of the block, in workspace coordinates. + * @param {!Blockly.utils.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, @@ -344,8 +344,7 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) { this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED; return; } - if (this.trackedState_ == Blockly.RenderedConnection - .TrackedState.TRACKED) { + if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.TRACKED) { this.db_.removeConnection(this, this.y); } this.trackedState_ = Blockly.RenderedConnection.TrackedState.UNTRACKED; diff --git a/core/theme_manager.js b/core/theme_manager.js index d53e9cba6..3d6e09d7e 100644 --- a/core/theme_manager.js +++ b/core/theme_manager.js @@ -96,7 +96,7 @@ Blockly.ThemeManager.prototype.setTheme = function(theme) { // Refresh all registered Blockly UI components. for (var i = 0, keys = Object.keys(this.componentDB_), - key; key = keys[i]; i++) { + key; (key = keys[i]); i++) { for (var j = 0, component; (component = this.componentDB_[key][j]); j++) { var element = component.element; var propertyName = component.propertyName; diff --git a/core/toolbox.js b/core/toolbox.js index d68bec94c..59d2c2044 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -433,7 +433,7 @@ Blockly.Toolbox.prototype.position = function() { Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) { var openNode = null; var lastElement = null; - for (var i = 0, childIn; childIn = treeIn.childNodes[i]; i++) { + for (var i = 0, childIn; (childIn = treeIn.childNodes[i]); i++) { if (!childIn.tagName) { // Skip over text. continue; @@ -574,7 +574,7 @@ Blockly.Toolbox.prototype.updateColourFromTheme_ = function(opt_tree) { var tree = opt_tree || this.tree_; if (tree) { var children = tree.getChildren(false); - for (var i = 0, child; child = children[i]; i++) { + for (var i = 0, child; (child = children[i]); i++) { if (child.styleName) { this.setColourFromStyle_(child.styleName, child, ''); this.addColour_(); @@ -621,7 +621,7 @@ Blockly.Toolbox.prototype.updateSelectedItemColour_ = function(tree) { Blockly.Toolbox.prototype.addColour_ = function(opt_tree) { var tree = opt_tree || this.tree_; var children = tree.getChildren(false); - for (var i = 0, child; child = children[i]; i++) { + for (var i = 0, child; (child = children[i]); i++) { var element = child.getRowElement(); if (element) { if (this.hasColours_) { diff --git a/core/trashcan.js b/core/trashcan.js index e6e577a3a..b676626a2 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -430,7 +430,7 @@ Blockly.Trashcan.prototype.click = function() { } var xml = []; - for (var i = 0, text; text = this.contents_[i]; i++) { + for (var i = 0, text; (text = this.contents_[i]); i++) { xml[i] = Blockly.Xml.textToDom(text); } this.flyout.show(xml); diff --git a/core/utils.js b/core/utils.js index f633f6c35..371568b80 100644 --- a/core/utils.js +++ b/core/utils.js @@ -574,7 +574,7 @@ Blockly.utils.getBlockTypeCounts = function(block, opt_stripFollowing) { descendants.splice(index, descendants.length - index); } } - for (var i = 0, checkBlock; checkBlock = descendants[i]; i++) { + for (var i = 0, checkBlock; (checkBlock = descendants[i]); i++) { if (typeCountsMap[checkBlock.type]) { typeCountsMap[checkBlock.type]++; } else { diff --git a/core/variable_map.js b/core/variable_map.js index f52aba2e2..cb2d8d7d9 100644 --- a/core/variable_map.js +++ b/core/variable_map.js @@ -208,7 +208,7 @@ Blockly.VariableMap.prototype.createVariable = function(name, */ Blockly.VariableMap.prototype.deleteVariable = function(variable) { var variableList = this.variableMap_[variable.type]; - for (var i = 0, tempVar; tempVar = variableList[i]; i++) { + for (var i = 0, tempVar; (tempVar = variableList[i]); i++) { if (tempVar.getId() == variable.getId()) { variableList.splice(i, 1); Blockly.Events.fire(new Blockly.Events.VarDelete(variable)); @@ -228,7 +228,7 @@ Blockly.VariableMap.prototype.deleteVariableById = function(id) { // 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++) { + for (var i = 0, block; (block = uses[i]); i++) { if (block.type == 'procedures_defnoreturn' || block.type == 'procedures_defreturn') { var procedureName = block.getFieldValue('NAME'); @@ -301,7 +301,7 @@ Blockly.VariableMap.prototype.getVariable = function(name, opt_type) { var type = opt_type || ''; var list = this.variableMap_[type]; if (list) { - for (var j = 0, variable; variable = list[j]; j++) { + for (var j = 0, variable; (variable = list[j]); j++) { if (Blockly.Names.equals(variable.name, name)) { return variable; } @@ -320,7 +320,7 @@ 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++) { + for (var j = 0, variable; (variable = this.variableMap_[key][j]); j++) { if (variable.getId() == id) { return variable; } diff --git a/core/variables.js b/core/variables.js index f15d92aff..d6ec0c8af 100644 --- a/core/variables.js +++ b/core/variables.js @@ -107,7 +107,7 @@ Blockly.Variables.ALL_DEVELOPER_VARS_WARNINGS_BY_BLOCK_TYPE_ = {}; Blockly.Variables.allDeveloperVariables = function(workspace) { var blocks = workspace.getAllBlocks(false); var variableHash = Object.create(null); - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { var getDeveloperVariables = block.getDeveloperVariables; if (!getDeveloperVariables && block.getDeveloperVars) { // August 2018: getDeveloperVars() was deprecated and renamed @@ -194,7 +194,7 @@ Blockly.Variables.flyoutCategoryBlocks = function(workspace) { if (Blockly.Blocks['variables_get']) { variableModelList.sort(Blockly.VariableModel.compareByName); - for (var i = 0, variable; variable = variableModelList[i]; i++) { + for (var i = 0, variable; (variable = variableModelList[i]); i++) { var block = Blockly.utils.xml.createElement('block'); block.setAttribute('type', 'variables_get'); block.setAttribute('gap', 8); @@ -411,7 +411,7 @@ Blockly.Variables.nameUsedWithOtherType_ = function(name, type, workspace) { var allVariables = workspace.getVariableMap().getAllVariables(); name = name.toLowerCase(); - for (var i = 0, variable; variable = allVariables[i]; i++) { + for (var i = 0, variable; (variable = allVariables[i]); i++) { if (variable.name.toLowerCase() == name && variable.type != type) { return variable; } @@ -432,7 +432,7 @@ Blockly.Variables.nameUsedWithAnyType_ = function(name, workspace) { var allVariables = workspace.getVariableMap().getAllVariables(); name = name.toLowerCase(); - for (var i = 0, variable; variable = allVariables[i]; i++) { + for (var i = 0, variable; (variable = allVariables[i]); i++) { if (variable.name.toLowerCase() == name) { return variable; } diff --git a/core/variables_dynamic.js b/core/variables_dynamic.js index 0d8d1548a..e7490dd19 100644 --- a/core/variables_dynamic.js +++ b/core/variables_dynamic.js @@ -98,7 +98,7 @@ Blockly.VariablesDynamic.flyoutCategoryBlocks = function(workspace) { } if (Blockly.Blocks['variables_get_dynamic']) { variableModelList.sort(Blockly.VariableModel.compareByName); - for (var i = 0, variable; variable = variableModelList[i]; i++) { + for (var i = 0, variable; (variable = variableModelList[i]); i++) { var block = Blockly.utils.xml.createElement('block'); block.setAttribute('type', 'variables_get_dynamic'); block.setAttribute('gap', 8); diff --git a/core/warning.js b/core/warning.js index fde0bd50c..ba3cf3ced 100644 --- a/core/warning.js +++ b/core/warning.js @@ -143,7 +143,7 @@ Blockly.Warning.prototype.createBubble = function() { // This cannot be done until the bubble is rendered on screen. var maxWidth = this.paragraphElement_.getBBox().width; for (var i = 0, textElement; - textElement = this.paragraphElement_.childNodes[i]; i++) { + (textElement = this.paragraphElement_.childNodes[i]); i++) { textElement.setAttribute('text-anchor', 'end'); textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); diff --git a/core/workspace.js b/core/workspace.js index 0f7b74c9b..350229224 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -136,7 +136,7 @@ Blockly.Workspace = function(opt_options) { this.themeManager_ = this.options.parentWorkspace ? this.options.parentWorkspace.getThemeManager() : new Blockly.ThemeManager(this.options.theme || Blockly.Themes.Classic); - + this.themeManager_.subscribeWorkspace(this); /** @@ -251,7 +251,7 @@ Blockly.Workspace.prototype.refreshTheme = function() { * @private */ Blockly.Workspace.prototype.updateBlockStyles_ = function(blocks) { - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { var blockStyleName = block.getStyleName(); if (blockStyleName) { block.setStyle(blockStyleName); @@ -731,13 +731,13 @@ Blockly.Workspace.prototype.undo = function(redo) { events.push(inputStack.pop()); } // Push these popped events on the opposite stack. - for (var i = 0, event; event = events[i]; i++) { + for (var i = 0, event; (event = events[i]); i++) { outputStack.push(event); } events = Blockly.Events.filter(events, redo); Blockly.Events.recordUndo = false; try { - for (var i = 0, event; event = events[i]; i++) { + for (var i = 0, event; (event = events[i]); i++) { event.run(redo); } } finally { @@ -788,7 +788,7 @@ Blockly.Workspace.prototype.fireChangeListener = function(event) { this.undoStack_.shift(); } } - for (var i = 0, func; func = this.listeners_[i]; i++) { + for (var i = 0, func; (func = this.listeners_[i]); i++) { func(event); } }; @@ -842,7 +842,7 @@ Blockly.Workspace.prototype.getCommentById = function(id) { Blockly.Workspace.prototype.allInputsFilled = function( opt_shadowBlocksAreFilled) { var blocks = this.getTopBlocks(false); - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { if (!block.allInputsFilled(opt_shadowBlocksAreFilled)) { return false; } diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 9efe86b06..4876dd0e0 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1150,7 +1150,7 @@ Blockly.WorkspaceSvg.prototype.traceOn = function() { Blockly.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 (var i = 0, block; (block = this.highlightedBlocks_[i]); i++) { block.setHighlighted(false); } this.highlightedBlocks_.length = 0; @@ -1220,7 +1220,7 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { do { var collide = false; var allBlocks = this.getAllBlocks(false); - for (var i = 0, otherBlock; otherBlock = allBlocks[i]; i++) { + for (var i = 0, otherBlock; (otherBlock = allBlocks[i]); i++) { var otherXY = otherBlock.getRelativeToSurfaceXY(); if (Math.abs(blockX - otherXY.x) <= 1 && Math.abs(blockY - otherXY.y) <= 1) { @@ -1231,7 +1231,7 @@ 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++) { + for (var i = 0, connection; (connection = connections[i]); i++) { var neighbour = connection.closest(Blockly.SNAP_RADIUS, new Blockly.utils.Coordinate(blockX, blockY)); if (neighbour.connection) { @@ -1564,7 +1564,7 @@ Blockly.WorkspaceSvg.prototype.cleanUp = function() { Blockly.Events.setGroup(true); var topBlocks = this.getTopBlocks(true); var cursorY = 0; - for (var i = 0, block; block = topBlocks[i]; i++) { + for (var i = 0, block; (block = topBlocks[i]); i++) { if (!block.isMovable()) { continue; } diff --git a/core/xml.js b/core/xml.js index f146b7761..9d0092c10 100644 --- a/core/xml.js +++ b/core/xml.js @@ -51,11 +51,11 @@ Blockly.Xml.workspaceToDom = function(workspace, opt_noId) { xml.appendChild(variablesElement); } var comments = workspace.getTopComments(true); - for (var i = 0, comment; comment = comments[i]; i++) { + for (var i = 0, comment; (comment = comments[i]); i++) { xml.appendChild(comment.toXmlWithXY(opt_noId)); } var blocks = workspace.getTopBlocks(true); - for (var i = 0, block; block = blocks[i]; i++) { + for (var i = 0, block; (block = blocks[i]); i++) { xml.appendChild(Blockly.Xml.blockToDomWithXY(block, opt_noId)); } return xml; @@ -69,7 +69,7 @@ Blockly.Xml.workspaceToDom = function(workspace, opt_noId) { */ Blockly.Xml.variablesToDom = function(variableList) { var variables = Blockly.utils.xml.createElement('variables'); - for (var i = 0, variable; variable = variableList[i]; i++) { + for (var i = 0, variable; (variable = variableList[i]); i++) { var element = Blockly.utils.xml.createElement('variable'); element.appendChild(Blockly.utils.xml.createTextNode(variable.name)); if (variable.type) { @@ -125,8 +125,8 @@ Blockly.Xml.fieldToDom_ = function(field) { * @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++) { + 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); if (fieldDom) { element.appendChild(fieldDom); @@ -178,7 +178,7 @@ Blockly.Xml.blockToDom = function(block, opt_noId) { element.appendChild(dataElement); } - for (var i = 0, input; input = block.inputList[i]; i++) { + for (var i = 0, input; (input = block.inputList[i]); i++) { var container; var empty = true; if (input.type == Blockly.DUMMY_INPUT) { @@ -402,7 +402,7 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) { } var variablesFirst = true; try { - for (var i = 0, xmlChild; xmlChild = xml.childNodes[i]; i++) { + for (var i = 0, xmlChild; (xmlChild = xml.childNodes[i]); i++) { var name = xmlChild.nodeName.toLowerCase(); var xmlChildElement = /** @type {!Element} */ (xmlChild); if (name == 'block' || @@ -595,7 +595,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { * should be added. */ Blockly.Xml.domToVariables = function(xmlVariables, workspace) { - for (var i = 0, xmlChild; xmlChild = xmlVariables.childNodes[i]; i++) { + for (var i = 0, xmlChild; (xmlChild = xmlVariables.childNodes[i]); i++) { if (xmlChild.nodeType != Blockly.utils.dom.Node.ELEMENT_NODE) { continue; // Skip text nodes. } @@ -625,7 +625,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { block = workspace.newBlock(prototypeName, id); var blockChild = null; - for (var i = 0, xmlChild; xmlChild = xmlBlock.childNodes[i]; i++) { + for (var i = 0, xmlChild; (xmlChild = xmlBlock.childNodes[i]); i++) { if (xmlChild.nodeType == Blockly.utils.dom.Node.TEXT_NODE) { // Ignore any text at the level. It's all whitespace anyway. continue; @@ -635,7 +635,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { // Find any enclosed blocks or shadows in this tag. var childBlockElement = null; var childShadowElement = null; - for (var j = 0, grandchild; grandchild = xmlChild.childNodes[j]; j++) { + for (var j = 0, grandchild; (grandchild = xmlChild.childNodes[j]); j++) { if (grandchild.nodeType == Blockly.utils.dom.Node.ELEMENT_NODE) { if (grandchild.nodeName.toLowerCase() == 'block') { childBlockElement = /** @type {!Element} */ (grandchild); @@ -771,7 +771,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { 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++) { + for (var i = 0, child; (child = children[i]); i++) { if (!child.isShadow()) { throw TypeError('Shadow block not allowed non-shadow child.'); } @@ -807,7 +807,7 @@ Blockly.Xml.domToField_ = function(block, fieldName, xml) { * @param {!Element} xmlBlock XML block element. */ Blockly.Xml.deleteNext = function(xmlBlock) { - for (var i = 0, child; child = xmlBlock.childNodes[i]; i++) { + for (var i = 0, child; (child = xmlBlock.childNodes[i]); i++) { if (child.nodeName.toLowerCase() == 'next') { xmlBlock.removeChild(child); break; diff --git a/tests/mocha/procedures_test.js b/tests/mocha/procedures_test.js index 85adf8c8d..c973600b2 100644 --- a/tests/mocha/procedures_test.js +++ b/tests/mocha/procedures_test.js @@ -33,7 +33,7 @@ suite('Procedures', function() { ['procedures_defreturn', 'procedures_callreturn'] ]; - for (var i = 0, types; types = typesArray[i]; i++) { + for (var i = 0, types; (types = typesArray[i]); i++) { var context = Object.create(null); context.workspace = this.workspace; context.defType = types[0]; @@ -392,7 +392,7 @@ suite('Procedures', function() { // TODO: Update this for typed vars. var variables = this.workspace.getVariablesOfType(''); var variableMap = this.workspace.getVariableMap(); - for (var i = 0, variable; variable = variables[i]; i++) { + for (var i = 0, variable; (variable = variables[i]); i++) { variableMap.deleteVariable(variable); } } diff --git a/tests/mocha/xml_procedures_test.js b/tests/mocha/xml_procedures_test.js index 5af798c9e..b8d871c80 100644 --- a/tests/mocha/xml_procedures_test.js +++ b/tests/mocha/xml_procedures_test.js @@ -34,7 +34,7 @@ suite('Procedures XML', function() { ['procedures_defreturn', 'procedures_callreturn'] ]; - for (var i = 0, types; types = typesArray[i]; i++) { + for (var i = 0, types; (types = typesArray[i]); i++) { var context = Object.create(null); context.workspace = this.workspace; context.defType = types[0]; diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index 84f767c31..200ba304f 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -442,7 +442,7 @@ suite('XML', function() { this.workspace.createVariable('name1', '', 'id1'); var blocksArray = Blockly.Variables.flyoutCategoryBlocks(this.workspace); try { - for (var i = 0, xml; xml = blocksArray[i]; i++) { + for (var i = 0, xml; (xml = blocksArray[i]); i++) { Blockly.Xml.domToBlock(xml, this.workspace); } } finally { @@ -509,7 +509,7 @@ suite('XML', function() { var blocksArray = Blockly.VariablesDynamic .flyoutCategoryBlocks(this.workspace); try { - for (var i = 0, xml; xml = blocksArray[i]; i++) { + for (var i = 0, xml; (xml = blocksArray[i]); i++) { Blockly.Xml.domToBlock(xml, this.workspace); } } finally { From 93755fef532ee34a957c29df6167e42e1d16360a Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 31 Oct 2019 15:49:28 -0700 Subject: [PATCH 143/343] Treat compiler warnings as errors and run on travis (#3378) * Enable compiler warnings as errors and run on travis --- core/field_variable.js | 3 +- core/insertion_marker_manager.js | 7 +-- core/renderers/geras/path_object.js | 3 +- core/theme.js | 8 ++-- gulpfile.js | 68 +++++++++++++++++++++++++++-- package.json | 3 +- tests/run_all_tests.sh | 5 ++- 7 files changed, 83 insertions(+), 14 deletions(-) diff --git a/core/field_variable.js b/core/field_variable.js index 5ac85d736..850e2c378 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -63,7 +63,8 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes, /** * An array of options for a dropdown list, * or a function which generates these options. - * @type {!function(this:Blockly.FieldVariable): !Array.} + * @type {(!Array.| + * !function(this:Blockly.FieldDropdown): !Array.)} * @protected */ this.menuGenerator_ = Blockly.FieldVariable.dropdownCreate; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index bdf208181..2be5213a0 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -570,8 +570,8 @@ Blockly.InsertionMarkerManager.prototype.highlightBlock_ = function() { closest.targetBlock().highlightForReplacement(true); } else if (local.type == Blockly.OUTPUT_VALUE) { this.highlightedBlock_ = closest.getSourceBlock(); - // TODO: remove? - closest.getSourceBlock().highlightShapeForInput(closest, true); + // TODO: Bring this back for zelos rendering. + // closest.getSourceBlock().highlightShapeForInput(closest, true); } this.highlightingBlock_ = true; }; @@ -585,7 +585,8 @@ Blockly.InsertionMarkerManager.prototype.unhighlightBlock_ = function() { // If there's no block in place, but we're still connecting to a value input, // then we must have been highlighting an input shape. if (closest.type == Blockly.INPUT_VALUE && !closest.isConnected()) { - this.highlightedBlock_.highlightShapeForInput(closest, false); + // TODO: Bring this back for zelos rendering. + // this.highlightedBlock_.highlightShapeForInput(closest, false); } else { this.highlightedBlock_.highlightForReplacement(false); } diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 42e995b85..701bc324a 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -137,5 +137,6 @@ Blockly.geras.PathObject.prototype.applyColour = function(isShadow) { Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) { this.style = blockStyle; this.colourDark = - Blockly.utils.colour.blend('#000', this.style.colourPrimary, 0.2); + Blockly.utils.colour.blend('#000', this.style.colourPrimary, 0.2) || + this.colourDark; }; diff --git a/core/theme.js b/core/theme.js index c086d3714..bad41cffb 100644 --- a/core/theme.js +++ b/core/theme.js @@ -163,7 +163,7 @@ Blockly.Theme.createBlockStyle = function(colour) { */ Blockly.Theme.validatedBlockStyle = function(blockStyle) { // Make a new object with all of the same properties. - var valid = {}; + var valid = /** @type {!Blockly.Theme.BlockStyle} */ ({}); if (blockStyle) { Blockly.utils.object.mixin(valid, blockStyle); } @@ -174,10 +174,12 @@ Blockly.Theme.validatedBlockStyle = function(blockStyle) { valid.colourPrimary = parsedColour.hex; valid.colourSecondary = valid.colourSecondary ? Blockly.utils.colour.parseBlockColour(valid.colourSecondary).hex : - Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6); + Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6) || + valid.colourPrimary; valid.colourTertiary = valid.colourTertiary ? Blockly.utils.colour.parseBlockColour(valid.colourTertiary).hex : - Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3); + Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3) || + valid.colourPrimary; valid.hat = valid.hat || ''; return valid; diff --git a/gulpfile.js b/gulpfile.js index f57d6a33c..645efb57f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -79,12 +79,71 @@ function prependHeader() { return gulp.insert.prepend(`// Do not edit this file; automatically generated by gulp.\n`); } +/** + * Closure compiler warning groups used to treat warnings as errors. + */ +var JSCOMP_ERROR = [ + 'accessControls', + 'ambiguousFunctionDecl', + 'checkPrototypalTypes', + 'checkRegExp', + 'checkTypes', + 'checkVars', + 'conformanceViolations', + 'const', + 'constantProperty', + 'deprecated', + 'deprecatedAnnotations', + 'duplicateMessage', + // 'es3', + 'es5Strict', + 'externsValidation', + 'fileoverviewTags', + 'functionParams', + 'globalThis', + 'internetExplorerChecks', + 'invalidCasts', + 'misplacedTypeAnnotation', + 'missingGetCssName', + // 'missingOverride', + 'missingPolyfill', + 'missingProperties', + 'missingProvide', + 'missingRequire', + 'missingReturn', + // 'missingSourcesWarnings', + 'moduleLoad', + 'msgDescriptions', + 'newCheckTypes', + 'nonStandardJsDocs', + // 'polymer', + // 'reportUnknownTypes', + // 'strictCheckTypes', + // 'strictMissingProperties', + 'strictModuleDepCheck', + // 'strictPrimitiveOperators', + 'suspiciousCode', + 'typeInvalidation', + 'undefinedNames', + 'undefinedVars', + 'underscore', + 'unknownDefines', + 'unusedLocalVariables', + // 'unusedPrivateMembers', + 'useOfGoogBase', + 'uselessCode', + 'untranspilableFeatures', + 'visibility' +]; + /** * Helper method for calling the Closure compiler. * @param {*} compilerOptions * @param {boolean=} opt_verbose Optional option for verbose logging + * @param {boolean=} opt_warnings_as_error Optional option for treating warnings + * as errors. */ -function compile(compilerOptions, opt_verbose) { +function compile(compilerOptions, opt_verbose, opt_warnings_as_error) { if (!compilerOptions) compilerOptions = {}; compilerOptions.compilation_level = 'SIMPLE_OPTIMIZATIONS'; compilerOptions.warning_level = opt_verbose ? 'VERBOSE' : 'DEFAULT'; @@ -92,6 +151,7 @@ function compile(compilerOptions, opt_verbose) { compilerOptions.language_out = 'ECMASCRIPT5_STRICT'; compilerOptions.rewrite_polyfills = false; compilerOptions.hide_warnings_for = 'node_modules'; + if (opt_warnings_as_error) compilerOptions.jscomp_error = JSCOMP_ERROR; const platform = ['native', 'java', 'javascript']; @@ -125,7 +185,7 @@ gulp.task('build-core', function () { js_output_file: 'blockly_compressed.js', externs: './externs/svg-externs.js', define: defines - }, argv.verbose)) + }, argv.verbose, argv.strict)) .pipe(prependHeader()) .pipe(gulp.dest('./')); }); @@ -157,7 +217,7 @@ goog.provide('Blockly.Mutator');`; .pipe(compile({ dependency_mode: 'NONE', js_output_file: 'blocks_compressed.js' - }, argv.verbose)) + }, argv.verbose, argv.strict)) .pipe(gulp.replace('\'use strict\';', '\'use strict\';\n\n\n')) // Remove Blockly.Blocks to be compatible with Blockly. .pipe(gulp.replace(/var Blockly=\{[^;]*\};\n?/, '')) @@ -185,7 +245,7 @@ goog.provide('Blockly.utils.string');`; .pipe(compile({ dependency_mode: 'NONE', js_output_file: `${language}_compressed.js` - }, argv.verbose)) + }, argv.verbose, argv.strict)) .pipe(gulp.replace('\'use strict\';', '\'use strict\';\n\n\n')) // Remove Blockly.Generator and Blockly.utils.string to be compatible with Blockly. .pipe(gulp.replace(/var Blockly=\{[^;]*\};\s*Blockly.utils.global={};\s*Blockly.utils.string={};\n?/, '')) diff --git a/package.json b/package.json index da8364912..98962932a 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "build": "gulp build", "build:blocks": "gulp build-blocks", "build:core": "gulp build-core", - "build:debug": "gulp build-core --verbose > build-debug.log 2>&1 && tail -3 -r build-debug.log", + "build:debug": "gulp build-core --verbose --strict", + "build:debug:log": "npm run build:debug > build-debug.log 2>&1 && tail -3 build-debug.log", "build:langfiles": "gulp build-langfiles", "build:uncompressed": "gulp build-uncompressed", "bump": "npm version 3.$(date +'%Y%m%d').0", diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index cb8349674..dffd9d1cc 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -64,6 +64,9 @@ run_test_command "node" "./node_modules/.bin/mocha tests/node --opts tests/node/ # Run generator tests inside a browser and check the results. run_test_command "generators" "tests/scripts/run_generators.sh" +# Run the closure compiler ensuring there are no errors. +run_test_command "compile" "npm run build:debug" + # Generate TypeScript typings and ensure there are no errors. run_test_command "typings" "tests/scripts/compile_typings.sh" @@ -71,7 +74,7 @@ run_test_command "typings" "tests/scripts/compile_typings.sh" run_test_command "metadata" "tests/scripts/check_metadata.sh" # # Attempt advanced compilation of a Blockly app. -# run_test_command "compile" "tests/compile/compile.sh" +# run_test_command "advanced_compile" "tests/compile/compile.sh" # End of tests. From 0f659b25faf391447df0a9e370d6b0835f4c0d04 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 31 Oct 2019 15:49:48 -0700 Subject: [PATCH 144/343] Support workspace theme option as JSON (#3379) * Allow passing in a theme as JSON --- core/options.js | 21 +++++++++++++++++++-- core/theme.js | 9 +++++++++ typings/parts/blockly-interfaces.d.ts | 7 ++++--- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/core/options.js b/core/options.js index 6c054dd27..c84a4264e 100644 --- a/core/options.js +++ b/core/options.js @@ -23,6 +23,8 @@ goog.provide('Blockly.Options'); +goog.require('Blockly.Theme'); +goog.require('Blockly.Themes.Classic'); goog.require('Blockly.utils.userAgent'); goog.require('Blockly.Xml'); @@ -114,7 +116,6 @@ Blockly.Options = function(options) { } else { var oneBasedIndex = !!options['oneBasedIndex']; } - var theme = options['theme']; var keyMap = options['keyMap'] || Blockly.user.keyMap.createDefaultKeyMap(); var renderer = options['renderer'] || 'geras'; @@ -141,7 +142,7 @@ Blockly.Options = function(options) { this.gridOptions = Blockly.Options.parseGridOptions_(options); this.zoomOptions = Blockly.Options.parseZoomOptions_(options); this.toolboxPosition = toolboxPosition; - this.theme = theme; + this.theme = Blockly.Options.parseThemeOptions_(options); this.keyMap = keyMap; this.renderer = renderer; }; @@ -273,6 +274,22 @@ Blockly.Options.parseGridOptions_ = function(options) { return gridOptions; }; +/** + * 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. + * @private + */ +Blockly.Options.parseThemeOptions_ = function(options) { + var theme = options['theme'] || Blockly.Themes.Classic; + if (theme instanceof Blockly.Theme) { + return /** @type {!Blockly.Theme} */ (theme); + } + return new Blockly.Theme( + theme['blockStyles'], theme['categoryStyles'], theme['componentStyles']); +}; + /** * Parse the provided toolbox tree into a consistent DOM format. * @param {Node|string} tree DOM tree of blocks, or text representation of same. diff --git a/core/theme.js b/core/theme.js index bad41cffb..3deadde3a 100644 --- a/core/theme.js +++ b/core/theme.js @@ -204,6 +204,15 @@ Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName, this.categoryStyles_[categoryStyleName] = categoryStyle; }; +/** + * Gets a map of all the category style names. + * @return {!Object.} Map of category + * styles. + */ +Blockly.Theme.prototype.getAllCategoryStyles = function() { + return this.categoryStyles_; +}; + /** * Gets the style for a given Blockly UI component. If the style value is a * string, we attempt to find the value of any named references. diff --git a/typings/parts/blockly-interfaces.d.ts b/typings/parts/blockly-interfaces.d.ts index a7a7879bb..760f97fcb 100644 --- a/typings/parts/blockly-interfaces.d.ts +++ b/typings/parts/blockly-interfaces.d.ts @@ -16,7 +16,7 @@ declare module Blockly { css?: boolean; oneBasedIndex?: boolean; media?: string; - theme?: Blockly.BlocklyTheme; + theme?: Blockly.Theme | BlocklyThemeOptions; move?: { scrollbars?: boolean; drag?: boolean; @@ -38,9 +38,10 @@ declare module Blockly { }; } - interface BlocklyTheme { - defaultBlockStyles?: {[blocks: string]: Blockly.Theme.BlockStyle;}; + interface BlocklyThemeOptions { + blockStyles?: {[blocks: string]: Blockly.Theme.BlockStyle;}; categoryStyles?: {[category: string]: Blockly.Theme.CategoryStyle;}; + componentStyles?: {[component: string]: any;}; } interface Metrics { From 22c1eba546666fd4d65d8d4478b4306457abb401 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 31 Oct 2019 22:26:27 -0700 Subject: [PATCH 145/343] Make warnings an optional module. --- blocks/loops.js | 1 + blocks/procedures.js | 1 + build.py | 1 + core/block_svg.js | 6 ++-- core/renderers/measurables/types.js | 44 ++++++++++++++--------------- core/requires.js | 1 + gulpfile.js | 3 +- 7 files changed, 32 insertions(+), 25 deletions(-) diff --git a/blocks/loops.js b/blocks/loops.js index 3e95ed685..6ec71900b 100644 --- a/blocks/loops.js +++ b/blocks/loops.js @@ -35,6 +35,7 @@ goog.require('Blockly.FieldDropdown'); goog.require('Blockly.FieldLabel'); goog.require('Blockly.FieldNumber'); goog.require('Blockly.FieldVariable'); +goog.require('Blockly.Warning'); /** diff --git a/blocks/procedures.js b/blocks/procedures.js index 7487a0c92..d9111057d 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -30,6 +30,7 @@ goog.require('Blockly.FieldCheckbox'); goog.require('Blockly.FieldLabel'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.Mutator'); +goog.require('Blockly.Warning'); Blockly.Blocks['procedures_defnoreturn'] = { diff --git a/build.py b/build.py index 6dcfd4593..906d96e08 100755 --- a/build.py +++ b/build.py @@ -237,6 +237,7 @@ goog.provide('Blockly.FieldNumber'); goog.provide('Blockly.FieldTextInput'); goog.provide('Blockly.FieldVariable'); goog.provide('Blockly.Mutator'); +goog.provide('Blockly.Warning'); """)) # Read in all the source files. filenames = glob.glob(os.path.join("blocks", "*.js")) diff --git a/core/block_svg.js b/core/block_svg.js index d568207fd..c8ac13956 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -40,7 +40,6 @@ goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.object'); goog.require('Blockly.utils.Rect'); -goog.require('Blockly.Warning'); /** @@ -1107,7 +1106,7 @@ Blockly.BlockSvg.prototype.setCommentText = function(text) { } if (shouldHaveComment) { this.commentIcon_ = new Blockly.Comment(this); - this.comment = this.commentIcon_; // For backwards compatibility. + this.comment = this.commentIcon_; // For backwards compatibility. } else { this.commentIcon_.dispose(); this.commentIcon_ = null; @@ -1127,6 +1126,9 @@ Blockly.BlockSvg.prototype.setCommentText = function(text) { * maintain multiple warnings. */ Blockly.BlockSvg.prototype.setWarningText = function(text, opt_id) { + if (!Blockly.Warning) { + throw Error('Missing require for Blockly.Warning'); + } if (!this.warningTextDb_) { // Create a database of warning PIDs. // Only runs once per block (and only those with warnings). diff --git a/core/renderers/measurables/types.js b/core/renderers/measurables/types.js index d31ea79ba..c15f7d4fb 100644 --- a/core/renderers/measurables/types.js +++ b/core/renderers/measurables/types.js @@ -30,31 +30,31 @@ goog.provide('Blockly.blockRendering.Types'); * @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. + 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. + 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. + 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, // Bototm Row. - INPUT_ROW: 1 << 23, // Input Row. + 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. }; /** diff --git a/core/requires.js b/core/requires.js index 77f80d7c2..d80533c8f 100644 --- a/core/requires.js +++ b/core/requires.js @@ -62,6 +62,7 @@ goog.require('Blockly.ZoomControls'); // None of these should be required when using advanced compilation since // individual block files should include the requirements they depend on. goog.require('Blockly.Mutator'); +goog.require('Blockly.Warning'); goog.require('Blockly.FieldAngle'); goog.require('Blockly.FieldCheckbox'); goog.require('Blockly.FieldColour'); diff --git a/gulpfile.js b/gulpfile.js index 645efb57f..1b1ffad39 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -208,7 +208,8 @@ goog.provide('Blockly.FieldMultilineInput'); goog.provide('Blockly.FieldNumber'); goog.provide('Blockly.FieldTextInput'); goog.provide('Blockly.FieldVariable'); -goog.provide('Blockly.Mutator');`; +goog.provide('Blockly.Mutator'); +goog.provide('Blockly.Warning');`; return gulp.src('blocks/*.js', {base: './'}) // Add Blockly.Blocks to be compatible with the compiler. .pipe(gulp.replace(`goog.provide('Blockly.Constants.Colour');`, From 0aea33d8a6d7d7aa5420dea71edb67c7ccb63f5f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Fri, 1 Nov 2019 12:21:05 -0700 Subject: [PATCH 146/343] Make theme validate style method work with advanced compilation (#3384) --- core/theme.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/theme.js b/core/theme.js index 3deadde3a..d4b7ef70c 100644 --- a/core/theme.js +++ b/core/theme.js @@ -170,18 +170,18 @@ Blockly.Theme.validatedBlockStyle = function(blockStyle) { // Validate required properties. var parsedColour = Blockly.utils.colour.parseBlockColour( - valid.colourPrimary || '#000'); + valid['colourPrimary'] || '#000'); valid.colourPrimary = parsedColour.hex; - valid.colourSecondary = valid.colourSecondary ? - Blockly.utils.colour.parseBlockColour(valid.colourSecondary).hex : + valid.colourSecondary = valid['colourSecondary'] ? + Blockly.utils.colour.parseBlockColour(valid['colourSecondary']).hex : Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6) || valid.colourPrimary; valid.colourTertiary = valid.colourTertiary ? - Blockly.utils.colour.parseBlockColour(valid.colourTertiary).hex : + Blockly.utils.colour.parseBlockColour(valid['colourTertiary']).hex : Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3) || valid.colourPrimary; - valid.hat = valid.hat || ''; + valid.hat = valid['hat'] || ''; return valid; }; From 46f323971a8000c4fa9a5f0186c6d22ae387a51e Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 1 Nov 2019 13:32:17 -0700 Subject: [PATCH 147/343] Move filter and pattern creation from inject into constants. --- core/block_svg.js | 6 ++- core/inject.js | 67 ----------------------- core/renderers/common/constants.js | 86 ++++++++++++++++++++++++++++++ core/workspace_svg.js | 1 + 4 files changed, 91 insertions(+), 69 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index d568207fd..4c5902ed5 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1061,7 +1061,8 @@ Blockly.BlockSvg.prototype.updateDisabled = function() { /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (added) { this.svgPath_.setAttribute('fill', - 'url(#' + this.workspace.options.disabledPatternId + ')'); + 'url(#' + + this.workspace.getRenderer().getConstants().disabledPatternId + ')'); } } else { var removed = Blockly.utils.dom.removeClass( @@ -1253,7 +1254,8 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { } if (highlighted) { this.svgPath_.setAttribute('filter', - 'url(#' + this.workspace.options.embossFilterId + ')'); + 'url(#' + + this.workspace.getRenderer().getConstants().embossFilterId + ')'); this.svgPathLight_.style.display = 'none'; } else { this.svgPath_.setAttribute('filter', 'none'); diff --git a/core/inject.js b/core/inject.js index 805200e75..be46c684c 100644 --- a/core/inject.js +++ b/core/inject.js @@ -139,73 +139,6 @@ Blockly.createDom_ = function(container, options) { // instances on a page. Browser behaviour becomes undefined otherwise. // https://neil.fraser.name/news/2015/11/01/ var rnd = String(Math.random()).substring(2); - /* - - - - - - - - - */ - var embossFilter = Blockly.utils.dom.createSvgElement('filter', - {'id': 'blocklyEmbossFilter' + rnd}, defs); - Blockly.utils.dom.createSvgElement('feGaussianBlur', - {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter); - var feSpecularLighting = Blockly.utils.dom.createSvgElement('feSpecularLighting', - { - 'in': 'blur', - 'surfaceScale': 1, - 'specularConstant': 0.5, - 'specularExponent': 10, - 'lighting-color': 'white', - 'result': 'specOut' - }, - embossFilter); - Blockly.utils.dom.createSvgElement('fePointLight', - {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting); - Blockly.utils.dom.createSvgElement('feComposite', - { - 'in': 'specOut', - 'in2': 'SourceAlpha', - 'operator': 'in', - 'result': 'specOut' - }, embossFilter); - Blockly.utils.dom.createSvgElement('feComposite', - { - 'in': 'SourceGraphic', - 'in2': 'specOut', - 'operator': 'arithmetic', - 'k1': 0, - 'k2': 1, - 'k3': 1, - 'k4': 0 - }, embossFilter); - options.embossFilterId = embossFilter.id; - /* - - - - - */ - var disabledPattern = Blockly.utils.dom.createSvgElement('pattern', - { - 'id': 'blocklyDisabledPattern' + rnd, - 'patternUnits': 'userSpaceOnUse', - 'width': 10, - 'height': 10 - }, defs); - Blockly.utils.dom.createSvgElement('rect', - {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern); - Blockly.utils.dom.createSvgElement('path', - {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern); - options.disabledPatternId = disabledPattern.id; options.gridPattern = Blockly.Grid.createDom(rnd, options.gridOptions, defs); return svg; diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index bfc753f09..fedfd85a7 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -398,3 +398,89 @@ Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function( throw Error('Unknown connection type'); } }; + +/** + * Create any DOM elements that this renderer needs (filters, patterns, etc). + * @param {!SVGElement} svg The root of the workspace's SVG. + * @package + */ +Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg) { + /* + + ... filters go here ... + + */ + var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg); + // Each filter/pattern needs a unique ID for the case of multiple Blockly + // instances on a page. Browser behaviour becomes undefined otherwise. + // https://neil.fraser.name/news/2015/11/01/ + var rnd = String(Math.random()).substring(2); + /* + + + + + + + + + */ + var embossFilter = Blockly.utils.dom.createSvgElement('filter', + {'id': 'blocklyEmbossFilter' + rnd}, defs); + Blockly.utils.dom.createSvgElement('feGaussianBlur', + {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter); + var feSpecularLighting = Blockly.utils.dom.createSvgElement('feSpecularLighting', + { + 'in': 'blur', + 'surfaceScale': 1, + 'specularConstant': 0.5, + 'specularExponent': 10, + 'lighting-color': 'white', + 'result': 'specOut' + }, + embossFilter); + Blockly.utils.dom.createSvgElement('fePointLight', + {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'specOut', + 'in2': 'SourceAlpha', + 'operator': 'in', + 'result': 'specOut' + }, embossFilter); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'SourceGraphic', + 'in2': 'specOut', + 'operator': 'arithmetic', + 'k1': 0, + 'k2': 1, + 'k3': 1, + 'k4': 0 + }, embossFilter); + this.embossFilterId = embossFilter.id; + + /* + + + + + */ + var disabledPattern = Blockly.utils.dom.createSvgElement('pattern', + { + 'id': 'blocklyDisabledPattern' + rnd, + 'patternUnits': 'userSpaceOnUse', + 'width': 10, + 'height': 10 + }, defs); + Blockly.utils.dom.createSvgElement('rect', + {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern); + Blockly.utils.dom.createSvgElement('path', + {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern); + this.disabledPatternId = disabledPattern.id; +}; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 4876dd0e0..9e961d8df 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -676,6 +676,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { var svgMarker = this.marker_.getDrawer().createDom(); this.svgGroup_.appendChild(svgMarker); + this.getRenderer().getConstants().createDom(this.svgGroup_); return this.svgGroup_; }; From 13e4d671c3d42230d397e0b4656d3e02923383d1 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 1 Nov 2019 14:28:51 -0700 Subject: [PATCH 148/343] Moved setHighlighted and setDisabled into the path object. --- core/block_svg.js | 39 ++++------------------ core/bubble.js | 6 ++-- core/mutator.js | 1 - core/renderers/common/constants.js | 45 ++++++++++++++++++++++++++ core/renderers/common/i_path_object.js | 19 ++++++++++- core/renderers/common/path_object.js | 40 ++++++++++++++++++++++- core/renderers/common/renderer.js | 4 ++- core/renderers/geras/path_object.js | 42 +++++++++++++++++++++++- core/renderers/geras/renderer.js | 3 +- core/toolbox.js | 1 - core/trashcan.js | 1 - core/workspace_svg.js | 3 +- 12 files changed, 160 insertions(+), 44 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 4c5902ed5..2527d6756 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -76,23 +76,6 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { */ this.pathObject = workspace.getRenderer().makePathObject(this.svgGroup_); - // The next two paths are set only for backwards compatibility reasons. - /** - * The primary path of the block. - * @type {SVGElement} - * @private - */ - this.svgPath_ = this.pathObject.svgPath || null; - - /** - * The light path of the block. - * @type {SVGElement} - * @private - */ - this.svgPathLight_ = this.pathObject.svgPathLight || null; - - this.svgPath_.tooltip = this; - /** @type {boolean} */ this.rendered = false; @@ -115,7 +98,9 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { this.useDragSurface_ = Blockly.utils.is3dSupported() && !!workspace.getBlockDragSurface(); - Blockly.Tooltip.bindMouseEvents(this.svgPath_); + var svgPath = this.pathObject.svgPath; + svgPath.tooltip = this; + Blockly.Tooltip.bindMouseEvents(svgPath); Blockly.BlockSvg.superClass_.constructor.call(this, workspace, prototypeName, opt_id); @@ -1023,8 +1008,6 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { blockWorkspace.resizeContents(); // Sever JavaScript to DOM connections. this.svgGroup_ = null; - this.svgPath_ = null; - this.svgPathLight_ = null; Blockly.utils.dom.stopTextWidthCache(); }; @@ -1060,15 +1043,13 @@ Blockly.BlockSvg.prototype.updateDisabled = function() { var added = Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (added) { - this.svgPath_.setAttribute('fill', - 'url(#' + - this.workspace.getRenderer().getConstants().disabledPatternId + ')'); + this.pathObject.setDisabled(true, this.isShadow()); } } else { var removed = Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (removed) { - this.applyColour(); + this.pathObject.setDisabled(false, this.isShadow()); } } var children = this.getChildren(false); @@ -1252,15 +1233,7 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { if (!this.rendered) { return; } - if (highlighted) { - this.svgPath_.setAttribute('filter', - 'url(#' + - this.workspace.getRenderer().getConstants().embossFilterId + ')'); - this.svgPathLight_.style.display = 'none'; - } else { - this.svgPath_.setAttribute('filter', 'none'); - this.svgPathLight_.style.display = 'inline'; - } + this.pathObject.setHighlighted(highlighted); }; /** diff --git a/core/bubble.js b/core/bubble.js index c3713d4f8..4e139bdc3 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -232,7 +232,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { */ this.bubbleGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); var filter = - {'filter': 'url(#' + this.workspace_.options.embossFilterId + ')'}; + {'filter': 'url(#' + + this.workspace_.getRenderer().getConstants().embossFilterId + ')'}; if (Blockly.utils.userAgent.JAVA_FX) { // Multiple reports that JavaFX can't handle filters. // https://github.com/google/blockly/issues/99 @@ -240,7 +241,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { } var bubbleEmboss = Blockly.utils.dom.createSvgElement('g', filter, this.bubbleGroup_); - this.bubbleArrow_ = Blockly.utils.dom.createSvgElement('path', {}, bubbleEmboss); + this.bubbleArrow_ = Blockly.utils.dom.createSvgElement('path', {}, + bubbleEmboss); this.bubbleBack_ = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyDraggable', diff --git a/core/mutator.js b/core/mutator.js index 3b1a1ff4b..006aea0b8 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -154,7 +154,6 @@ Blockly.Mutator.prototype.createEditor_ = function() { // If you want to enable disabling, also remove the // event filter from workspaceChanged_ . disable: false, - disabledPatternId: this.block_.workspace.options.disabledPatternId, languageTree: quarkXml, parentWorkspace: this.block_.workspace, pathToMedia: this.block_.workspace.options.pathToMedia, diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index fedfd85a7..6aa0863f6 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -23,6 +23,7 @@ goog.provide('Blockly.blockRendering.ConstantProvider'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.svgPaths'); @@ -134,6 +135,34 @@ Blockly.blockRendering.ConstantProvider = function() { * @const */ this.JAGGED_TEETH_WIDTH = 6; + + /** + * The ID of the emboss filter, or the empty string if no filter is set. + * @type {string} + * @package + */ + this.embossFilterId = ''; + + /** + * The element to use for highlighting, or null if not set. + * @type {SVGElement} + * @private + */ + this.embossFilter_ = null; + + /** + * The ID of the disabled pattern, or the empty string if no pattern is set. + * @type {string} + * @package + */ + this.disabledPatternId = ''; + + /** + * The element to use for disabled blocks, or null if not set. + * @type {SVGElement} + * @private + */ + this.disabledPattern_ = null; }; /** @@ -180,6 +209,20 @@ Blockly.blockRendering.ConstantProvider.prototype.init = function() { this.OUTSIDE_CORNERS = this.makeOutsideCorners(); }; +/** + * Dispose of this constants provider. + * Delete all DOM elements that this provider created. + * @package + */ +Blockly.blockRendering.ConstantProvider.prototype.dispose = function() { + if (this.embossFilter_) { + Blockly.utils.dom.removeNode(this.embossFilter_); + } + if (this.disabledPattern_) { + Blockly.utils.dom.removeNode(this.disabledPattern_); + } +}; + /** * @return {!Object} An object containing sizing and path information about * collapsed block indicators. @@ -463,6 +506,7 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg) { 'k4': 0 }, embossFilter); this.embossFilterId = embossFilter.id; + this.embossFilter_ = embossFilter; /* Date: Fri, 1 Nov 2019 15:06:35 -0700 Subject: [PATCH 149/343] Update jsdoc and parameter to reflect additional colour parsing --- core/utils/colour.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/utils/colour.js b/core/utils/colour.js index c64da4aef..eafb03d06 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -89,12 +89,13 @@ Blockly.utils.colour.rgbToHex = function(r, g, b) { }; /** - * Converts a hex representation of a colour to RGB. - * @param {string} hexColour Colour in '#ff0000' format. + * Converts a colour to RGB. + * @param {string} colour String representing colour in any + * colour format ('#ff0000', 'red', '0xff000', etc). * @return {!Array.} RGB representation of the colour. */ -Blockly.utils.colour.hexToRgb = function(hexColour) { - var hex = Blockly.utils.colour.parse(hexColour); +Blockly.utils.colour.hexToRgb = function(colour) { + var hex = Blockly.utils.colour.parse(colour); if (!hex) { return [0, 0, 0]; } From 67df60dee9bd02f0cb918846222de0dcbc5351f9 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 4 Nov 2019 15:45:31 +0100 Subject: [PATCH 150/343] Localisation updates from https://translatewiki.net. --- msg/json/mk.json | 3 ++- msg/json/pt-br.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/msg/json/mk.json b/msg/json/mk.json index a954feb6a..7e0641398 100644 --- a/msg/json/mk.json +++ b/msg/json/mk.json @@ -161,5 +161,6 @@ "PROCEDURES_DEFRETURN_RETURN": "назад", "PROCEDURES_ALLOW_STATEMENTS": "дозволи тврдења", "PROCEDURES_CALLNORETURN_HELPURL": "https://mk.wikipedia.org/wiki/Потпрограма", - "PROCEDURES_CREATE_DO": "Создај го '%1'" + "PROCEDURES_CREATE_DO": "Создај го '%1'", + "WORKSPACE_ARIA_LABEL": "Работен простор на Blockly" } diff --git a/msg/json/pt-br.json b/msg/json/pt-br.json index b4fd5e797..c331dd2f0 100644 --- a/msg/json/pt-br.json +++ b/msg/json/pt-br.json @@ -367,5 +367,6 @@ "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Atenção: Este bloco só pode ser utilizado dentro da definição de uma função.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Diz algo...", + "WORKSPACE_ARIA_LABEL": "Bloquear espaço de trabalho", "COLLAPSED_WARNINGS_WARNING": "Bloqueios recolhidos contêm avisos." } From 1ce97d1c50779cf9b84a89e0ce06057deb632e80 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 4 Nov 2019 14:41:45 -0800 Subject: [PATCH 151/343] Added checking if the block is disposed before trying to reconnect in logic_compare block. --- blocks/logic.js | 4 ++-- core/block.js | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/blocks/logic.js b/blocks/logic.js index 89f2b2097..813e8f747 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -561,7 +561,7 @@ Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = { var prevA = this.prevBlocks_[0]; if (prevA !== blockA) { blockA.unplug(); - if (prevA && !prevA.isShadow()) { + if (prevA && !prevA.isDisposed() && !prevA.isShadow()) { // The shadow block is automatically replaced during unplug(). this.getInput('A').connection.connect(prevA.outputConnection); } @@ -569,7 +569,7 @@ Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = { var prevB = this.prevBlocks_[1]; if (prevB !== blockB) { blockB.unplug(); - if (prevB && !prevB.isShadow()) { + if (prevB && !prevB.isDisposed() && !prevB.isShadow()) { // The shadow block is automatically replaced during unplug(). this.getInput('B').connection.connect(prevB.outputConnection); } diff --git a/core/block.js b/core/block.js index 46893575a..fcb1da9c1 100644 --- a/core/block.js +++ b/core/block.js @@ -843,6 +843,14 @@ 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() { + return this.disposed; +}; + /** * Find the connection on this block that corresponds to the given connection * on the other block. From 43224afbf783e2550fe3d24edb314e69efbac67f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 4 Nov 2019 22:39:18 -0800 Subject: [PATCH 152/343] Move parseBlockColour into Blockly.utils (#3399) * Move parseBlockColour into utils and add missing require. --- blockly_uncompressed.js | 21 +++++++++++---------- core/block.js | 3 +-- core/theme.js | 8 +++++--- core/utils.js | 40 ++++++++++++++++++++++++++++++++++++++++ core/utils/colour.js | 40 ---------------------------------------- 5 files changed, 57 insertions(+), 55 deletions(-) diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 5426d79fa..1b5dc8c4e 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -21,12 +21,12 @@ this.BLOCKLY_DIR = (function(root) { this.BLOCKLY_BOOT = function(root) { // Execute after Closure has loaded. -goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.colour', 'Blockly.utils.object', 'Blockly.fieldRegistry', 'Blockly.utils.string', 'Blockly.Workspace']); +goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.fieldRegistry', 'Blockly.utils.string', 'Blockly.Workspace']); goog.addDependency("../../core/block_animations.js", ['Blockly.blockAnimations'], ['Blockly.utils.dom']); goog.addDependency("../../core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.blockAnimations', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Ui', 'Blockly.InsertionMarkerManager', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); -goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Warning']); +goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']); goog.addDependency("../../core/blockly.js", ['Blockly'], ['Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.inject', 'Blockly.navigation', 'Blockly.Procedures', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/blocks.js", ['Blockly.Blocks'], []); goog.addDependency("../../core/bubble.js", ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent', 'Blockly.Workspace']); @@ -35,6 +35,7 @@ goog.addDependency("../../core/comment.js", ['Blockly.Comment'], ['Blockly.Bubbl goog.addDependency("../../core/components/component.js", ['Blockly.Component', 'Blockly.Component.Error'], ['Blockly.utils.dom', 'Blockly.utils.IdGenerator', 'Blockly.utils.style']); goog.addDependency("../../core/components/menu/menu.js", ['Blockly.Menu'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/components/menu/menuitem.js", ['Blockly.MenuItem'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); +goog.addDependency("../../core/components/slider/slider.js", ['Blockly.Slider'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/components/tree/basenode.js", ['Blockly.tree.BaseNode'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.object', 'Blockly.utils.KeyCodes', 'Blockly.utils.style']); goog.addDependency("../../core/components/tree/treecontrol.js", ['Blockly.tree.TreeControl'], ['Blockly.tree.TreeNode', 'Blockly.tree.BaseNode', 'Blockly.utils.aria', 'Blockly.utils.object', 'Blockly.utils.style']); goog.addDependency("../../core/components/tree/treenode.js", ['Blockly.tree.TreeNode'], ['Blockly.tree.BaseNode', 'Blockly.utils.object', 'Blockly.utils.KeyCodes']); @@ -85,16 +86,16 @@ goog.addDependency("../../core/keyboard_nav/tab_navigate_cursor.js", ['Blockly.T 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.Ui', 'Blockly.Icon', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.xml', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/names.js", ['Blockly.Names'], ['Blockly.Msg']); -goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.utils.userAgent', 'Blockly.Xml']); +goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.utils.userAgent', 'Blockly.Xml']); goog.addDependency("../../core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.utils.xml', 'Blockly.Workspace', 'Blockly.Xml']); goog.addDependency("../../core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.utils.object']); -goog.addDependency("../../core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.svgPaths']); +goog.addDependency("../../core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.dom', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/common/debugger.js", ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); goog.addDependency("../../core/renderers/common/drawer.js", ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); 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.Hat', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); -goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.Theme', 'Blockly.utils.dom']); +goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.PathObject'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.Theme', 'Blockly.utils.dom']); goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.CursorSvg']); goog.addDependency("../../core/renderers/geras/constants.js", ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object', 'Blockly.utils.svgPaths']); @@ -102,7 +103,7 @@ goog.addDependency("../../core/renderers/geras/highlight_constants.js", ['Blockl goog.addDependency("../../core/renderers/geras/highlighter.js", ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/measurables/inputs.js", ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.utils.object']); -goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.utils.dom', 'Blockly.utils.object']); +goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.geras.ConstantProvider', 'Blockly.Theme', '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/measurables/connections.js", ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); @@ -121,9 +122,9 @@ goog.addDependency("../../core/renderers/zelos/drawer.js", ['Blockly.zelos.Drawe goog.addDependency("../../core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow', 'Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow']); goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.RenderInfo']); -goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); +goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); -goog.addDependency("../../core/theme.js", ['Blockly.Theme'], ['Blockly.utils.colour']); +goog.addDependency("../../core/theme.js", ['Blockly.Theme'], ['Blockly.utils', 'Blockly.utils.colour']); goog.addDependency("../../core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); goog.addDependency("../../core/theme/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Theme']); goog.addDependency("../../core/theme/deuteranopia.js", ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']); @@ -138,9 +139,9 @@ goog.addDependency("../../core/touch_gesture.js", ['Blockly.TouchGesture'], ['Bl goog.addDependency("../../core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.Scrollbar', 'Blockly.utils.dom', 'Blockly.utils.Rect', 'Blockly.Xml']); goog.addDependency("../../core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.utils.object']); goog.addDependency("../../core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], ['Blockly.utils.style']); -goog.addDependency("../../core/utils.js", ['Blockly.utils'], ['Blockly.Msg', 'Blockly.utils.Coordinate', 'Blockly.utils.global', 'Blockly.utils.string', 'Blockly.utils.style', 'Blockly.utils.userAgent']); +goog.addDependency("../../core/utils.js", ['Blockly.utils'], ['Blockly.Msg', 'Blockly.constants', 'Blockly.utils.colour', 'Blockly.utils.Coordinate', 'Blockly.utils.global', 'Blockly.utils.string', 'Blockly.utils.style', 'Blockly.utils.userAgent']); goog.addDependency("../../core/utils/aria.js", ['Blockly.utils.aria'], []); -goog.addDependency("../../core/utils/colour.js", ['Blockly.utils.colour'], ['Blockly.utils']); +goog.addDependency("../../core/utils/colour.js", ['Blockly.utils.colour'], []); goog.addDependency("../../core/utils/coordinate.js", ['Blockly.utils.Coordinate'], []); goog.addDependency("../../core/utils/dom.js", ['Blockly.utils.dom'], ['Blockly.utils.userAgent']); goog.addDependency("../../core/utils/global.js", ['Blockly.utils.global'], []); diff --git a/core/block.js b/core/block.js index 46893575a..c50258fd6 100644 --- a/core/block.js +++ b/core/block.js @@ -34,7 +34,6 @@ goog.require('Blockly.Extensions'); goog.require('Blockly.Input'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.colour'); goog.require('Blockly.utils.object'); goog.require('Blockly.fieldRegistry'); goog.require('Blockly.utils.string'); @@ -914,7 +913,7 @@ Blockly.Block.prototype.getHue = function() { * or a message reference string pointing to one of those two values. */ Blockly.Block.prototype.setColour = function(colour) { - var parsed = Blockly.utils.colour.parseBlockColour(colour); + var parsed = Blockly.utils.parseBlockColour(colour); this.hue_ = parsed.hue; this.colour_ = parsed.hex; }; diff --git a/core/theme.js b/core/theme.js index d4b7ef70c..52c723322 100644 --- a/core/theme.js +++ b/core/theme.js @@ -22,8 +22,10 @@ goog.provide('Blockly.Theme'); +goog.require('Blockly.utils'); goog.require('Blockly.utils.colour'); + /** * Class for a theme. * @param {!Object.} blockStyles A map from @@ -169,15 +171,15 @@ Blockly.Theme.validatedBlockStyle = function(blockStyle) { } // Validate required properties. - var parsedColour = Blockly.utils.colour.parseBlockColour( + var parsedColour = Blockly.utils.parseBlockColour( valid['colourPrimary'] || '#000'); valid.colourPrimary = parsedColour.hex; valid.colourSecondary = valid['colourSecondary'] ? - Blockly.utils.colour.parseBlockColour(valid['colourSecondary']).hex : + Blockly.utils.parseBlockColour(valid['colourSecondary']).hex : Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.6) || valid.colourPrimary; valid.colourTertiary = valid.colourTertiary ? - Blockly.utils.colour.parseBlockColour(valid['colourTertiary']).hex : + Blockly.utils.parseBlockColour(valid['colourTertiary']).hex : Blockly.utils.colour.blend('#fff', valid.colourPrimary, 0.3) || valid.colourPrimary; diff --git a/core/utils.js b/core/utils.js index 371568b80..2bacaee0d 100644 --- a/core/utils.js +++ b/core/utils.js @@ -30,6 +30,8 @@ goog.provide('Blockly.utils'); goog.require('Blockly.Msg'); +goog.require('Blockly.constants'); +goog.require('Blockly.utils.colour'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.global'); goog.require('Blockly.utils.string'); @@ -619,3 +621,41 @@ Blockly.utils.screenToWsCoordinates = function(ws, screenCoordinates) { var finalOffsetMainWs = finalOffsetPixels.scale(1 / ws.scale); return finalOffsetMainWs; }; + +/** + * Parse a block colour from a number or string, as provided in a block + * definition. + * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, + * or a message reference string pointing to one of those two values. + * @return {{hue: ?number, hex: string}} An object containing the colour as + * a #RRGGBB string, and the hue if the input was an HSV hue value. + * @throws {Error} If the colour cannot be parsed. + */ +Blockly.utils.parseBlockColour = function(colour) { + var dereferenced = (typeof colour == 'string') ? + Blockly.utils.replaceMessageReferences(colour) : colour; + + var hue = Number(dereferenced); + if (!isNaN(hue) && 0 <= hue && hue <= 360) { + return { + hue: hue, + hex: Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION, + Blockly.HSV_VALUE * 255) + }; + } else { + var hex = Blockly.utils.colour.parse(dereferenced); + if (hex) { + // Only store hue if colour is set as a hue. + return { + hue: null, + hex: hex + }; + } else { + var errorMsg = 'Invalid colour: "' + dereferenced + '"'; + if (colour != dereferenced) { + errorMsg += ' (from "' + colour + '")'; + } + throw Error(errorMsg); + } + } +}; diff --git a/core/utils/colour.js b/core/utils/colour.js index 810bd5637..0c90d0ef8 100644 --- a/core/utils/colour.js +++ b/core/utils/colour.js @@ -29,8 +29,6 @@ */ goog.provide('Blockly.utils.colour'); -goog.require('Blockly.utils'); - /** * Parses a colour from a string. @@ -211,41 +209,3 @@ Blockly.utils.colour.names = { 'white': '#ffffff', 'yellow': '#ffff00' }; - -/** - * Parse a block colour from a number or string, as provided in a block - * definition. - * @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string, - * or a message reference string pointing to one of those two values. - * @return {{hue: ?number, hex: string}} An object containing the colour as - * a #RRGGBB string, and the hue if the input was an HSV hue value. - * @throws {Error} If the colour cannot be parsed. - */ -Blockly.utils.colour.parseBlockColour = function(colour) { - var dereferenced = (typeof colour == 'string') ? - Blockly.utils.replaceMessageReferences(colour) : colour; - - var hue = Number(dereferenced); - if (!isNaN(hue) && 0 <= hue && hue <= 360) { - return { - hue: hue, - hex: Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION, - Blockly.HSV_VALUE * 255) - }; - } else { - var hex = Blockly.utils.colour.parse(dereferenced); - if (hex) { - // Only store hue if colour is set as a hue. - return { - hue: null, - hex: hex - }; - } else { - var errorMsg = 'Invalid colour: "' + dereferenced + '"'; - if (colour != dereferenced) { - errorMsg += ' (from "' + colour + '")'; - } - throw Error(errorMsg); - } - } -}; From 30343c8cf6e74cf2f8632433fce64a5ed891f3d2 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 5 Nov 2019 10:44:51 -0800 Subject: [PATCH 153/343] Move the theme manager into WorkspaceSvg (#3400) --- core/workspace.js | 86 ----------------------- core/workspace_svg.js | 106 ++++++++++++++++++++++++----- tests/jsunit/block_test.js | 18 ----- tests/mocha/procedures_test.js | 13 +--- tests/mocha/xml_procedures_test.js | 5 -- 5 files changed, 92 insertions(+), 136 deletions(-) diff --git a/core/workspace.js b/core/workspace.js index 350229224..aec9a54bc 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -26,8 +26,6 @@ goog.provide('Blockly.Workspace'); goog.require('Blockly.Cursor'); goog.require('Blockly.MarkerCursor'); goog.require('Blockly.Events'); -goog.require('Blockly.ThemeManager'); -goog.require('Blockly.Themes.Classic'); goog.require('Blockly.utils'); goog.require('Blockly.utils.math'); goog.require('Blockly.VariableMap'); @@ -128,17 +126,6 @@ Blockly.Workspace = function(opt_options) { */ this.marker_ = new Blockly.MarkerCursor(); - /** - * Object in charge of storing and updating the workspace theme. - * @type {!Blockly.ThemeManager} - * @protected - */ - this.themeManager_ = this.options.parentWorkspace ? - this.options.parentWorkspace.getThemeManager() : - new Blockly.ThemeManager(this.options.theme || Blockly.Themes.Classic); - - this.themeManager_.subscribeWorkspace(this); - /** * True if keyboard accessibility mode is on, false otherwise. * @type {boolean} @@ -207,61 +194,6 @@ Blockly.Workspace.prototype.getMarker = function() { return this.marker_; }; -/** - * Get the workspace theme object. - * @return {!Blockly.Theme} The workspace theme object. - */ -Blockly.Workspace.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. - */ -Blockly.Workspace.prototype.setTheme = function(theme) { - if (!theme) { - theme = /** @type {!Blockly.Theme} */ (Blockly.Themes.Classic); - } - this.themeManager_.setTheme(theme); -}; - -/** - * Refresh all blocks on the workspace after a theme update. - * @package - */ -Blockly.Workspace.prototype.refreshTheme = function() { - // Update all blocks in workspace that have a style name. - this.updateBlockStyles_(this.getAllBlocks(false).filter( - function(block) { - return block.getStyleName() !== undefined; - } - )); - - var event = new Blockly.Events.Ui(null, 'theme', null, null); - event.workspaceId = this.id; - Blockly.Events.fire(event); -}; - -/** - * Updates all the blocks with new style. - * @param {!Array.} blocks List of blocks to update the style - * on. - * @private - */ -Blockly.Workspace.prototype.updateBlockStyles_ = function(blocks) { - for (var i = 0, block; (block = blocks[i]); i++) { - var blockStyleName = block.getStyleName(); - if (blockStyleName) { - block.setStyle(blockStyleName); - if (block.mutator) { - block.mutator.updateBlockStyle(); - } - } - } -}; - /** * Dispose of this workspace. * Unlink from all DOM elements to prevent memory leaks. @@ -272,15 +204,6 @@ Blockly.Workspace.prototype.dispose = function() { this.clear(); // Remove from workspace database. delete Blockly.Workspace.WorkspaceDB_[this.id]; - - if (this.themeManager_) { - this.themeManager_.unsubscribeWorkspace(this); - this.themeManager_.unsubscribe(this.svgBackground_); - if (!this.options.parentWorkspace) { - this.themeManager_.dispose(); - this.themeManager_ = null; - } - } }; /** @@ -911,12 +834,3 @@ Blockly.Workspace.getAll = function() { } return workspaces; }; - -/** - * Get the theme manager for this workspace. - * @return {!Blockly.ThemeManager} The theme manager for this workspace. - * @package - */ -Blockly.Workspace.prototype.getThemeManager = function() { - return this.themeManager_; -}; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index bf3f344d6..7a8034026 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -33,6 +33,8 @@ goog.require('Blockly.Gesture'); goog.require('Blockly.Grid'); goog.require('Blockly.Msg'); goog.require('Blockly.Options'); +goog.require('Blockly.ThemeManager'); +goog.require('Blockly.Themes.Classic'); goog.require('Blockly.TouchGesture'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); @@ -134,6 +136,15 @@ Blockly.WorkspaceSvg = function(options, Blockly.Procedures.flyoutCategory); } + /** + * Object in charge of storing and updating the workspace theme. + * @type {!Blockly.ThemeManager} + * @protected + */ + this.themeManager_ = this.options.parentWorkspace ? + this.options.parentWorkspace.getThemeManager() : + new Blockly.ThemeManager(this.options.theme || Blockly.Themes.Classic); + /** * The block renderer used for rendering blocks on this workspace. * @type {!Blockly.blockRendering.Renderer} @@ -147,6 +158,8 @@ Blockly.WorkspaceSvg = function(options, * @private */ this.cachedParentSvg_ = null; + + this.themeManager_.subscribeWorkspace(this); }; Blockly.utils.object.inherits(Blockly.WorkspaceSvg, Blockly.Workspace); @@ -424,6 +437,76 @@ Blockly.WorkspaceSvg.prototype.getRenderer = function() { return this.renderer_; }; +/** + * Get the theme manager for this workspace. + * @return {!Blockly.ThemeManager} The theme manager for this workspace. + * @package + */ +Blockly.WorkspaceSvg.prototype.getThemeManager = function() { + return this.themeManager_; +}; + +/** + * Get the workspace theme object. + * @return {!Blockly.Theme} The workspace theme object. + */ +Blockly.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. + */ +Blockly.WorkspaceSvg.prototype.setTheme = function(theme) { + if (!theme) { + theme = /** @type {!Blockly.Theme} */ (Blockly.Themes.Classic); + } + this.themeManager_.setTheme(theme); +}; + +/** + * Refresh all blocks on the workspace after a theme update. + * @package + */ +Blockly.WorkspaceSvg.prototype.refreshTheme = function() { + // Update all blocks in workspace that have a style name. + this.updateBlockStyles_(this.getAllBlocks(false).filter( + function(block) { + return block.getStyleName() !== undefined; + } + )); + + // Update current toolbox selection. + this.refreshToolboxSelection(); + if (this.toolbox_) { + this.toolbox_.updateColourFromTheme(); + } + + var event = new Blockly.Events.Ui(null, 'theme', null, null); + event.workspaceId = this.id; + Blockly.Events.fire(event); +}; + +/** + * Updates all the blocks with new 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(); + if (blockStyleName) { + block.setStyle(blockStyleName); + if (block.mutator) { + block.mutator.updateBlockStyle(); + } + } + } +}; + /** * Sets the cursor for use with keyboard navigation. * @@ -718,11 +801,11 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { this.zoomControls_ = null; } - if (this.marker_) { + if (this.marker_ && this.marker_.getDrawer()) { this.marker_.getDrawer().dispose(); } - if (this.getCursor()) { + if (this.getCursor() && this.getCursor().getDrawer()) { this.getCursor().getDrawer().dispose(); } @@ -739,7 +822,12 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { this.renderer_.getConstants().dispose(); if (this.themeManager_) { + this.themeManager_.unsubscribeWorkspace(this); this.themeManager_.unsubscribe(this.svgBackground_); + if (!this.options.parentWorkspace) { + this.themeManager_.dispose(); + this.themeManager_ = null; + } } Blockly.WorkspaceSvg.superClass_.dispose.call(this); @@ -2555,17 +2643,3 @@ Blockly.WorkspaceSvg.prototype.getGrid = function() { return this.grid_; }; -/** - * Refresh all blocks on the workspace, toolbox and flyout after a theme update. - * @package - * @override - */ -Blockly.WorkspaceSvg.prototype.refreshTheme = function() { - Blockly.WorkspaceSvg.superClass_.refreshTheme.call(this); - - // Update current toolbox selection. - this.refreshToolboxSelection(); - if (this.toolbox_) { - this.toolbox_.updateColourFromTheme(); - } -}; diff --git a/tests/jsunit/block_test.js b/tests/jsunit/block_test.js index a6588c353..603b4fd14 100644 --- a/tests/jsunit/block_test.js +++ b/tests/jsunit/block_test.js @@ -252,21 +252,3 @@ function test_block_row_unplug_multi_inputs_child() { blockTest_tearDown(); } } - -function test_set_style_throw_exception() { - blockTest_setUp(); - var styleStub = { - getBlockStyle: function() { - return null; - } - }; - mockControl_ = setUpMockMethod(workspace, 'getTheme', null, [styleStub]); - var blockA = workspace.newBlock('row_block'); - try { - blockA.setStyle('styleOne'); - } catch (error) { - assertEquals(error.message, 'Invalid style name: styleOne'); - } finally { - blockTest_tearDown(); - } -} diff --git a/tests/mocha/procedures_test.js b/tests/mocha/procedures_test.js index c973600b2..99b20e6ba 100644 --- a/tests/mocha/procedures_test.js +++ b/tests/mocha/procedures_test.js @@ -21,11 +21,6 @@ goog.require('Blockly.Msg'); suite('Procedures', function() { setup(function() { this.workspace = new Blockly.Workspace(); - this.workspace.setTheme(new Blockly.Theme({ - "procedure_blocks": { - "colourPrimary": "290" - } - })); this.callForAllTypes = function(func, startName) { var typesArray = [ @@ -249,9 +244,7 @@ suite('Procedures', function() { }); test('Multiple Workspaces', function() { this.callForAllTypes(function() { - var workspace = new Blockly.Workspace({ - theme: this.workspace.getTheme() - }); + var workspace = new Blockly.Workspace(); var def2 = new Blockly.Block(workspace, this.defType); def2.setFieldValue('name', 'NAME'); var caller2 = new Blockly.Block(workspace, this.callType); @@ -293,9 +286,7 @@ suite('Procedures', function() { }); test('Multiple Workspaces', function() { this.callForAllTypes(function() { - var workspace = new Blockly.Workspace({ - theme: this.workspace.getTheme() - }); + var workspace = new Blockly.Workspace(); var def2 = new Blockly.Block(workspace, this.defType); def2.setFieldValue('name', 'NAME'); var caller2 = new Blockly.Block(workspace, this.callType); diff --git a/tests/mocha/xml_procedures_test.js b/tests/mocha/xml_procedures_test.js index b8d871c80..fefa72aef 100644 --- a/tests/mocha/xml_procedures_test.js +++ b/tests/mocha/xml_procedures_test.js @@ -22,11 +22,6 @@ suite('Procedures XML', function() { suite('Deserialization', function() { setup(function() { this.workspace = new Blockly.Workspace(); - this.workspace.setTheme(new Blockly.Theme({ - "procedure_blocks": { - "colourPrimary": "290" - } - })); this.callForAllTypes = function(func) { var typesArray = [ From 337cb9c486475e72083b63ff2e03d4f44b7d8f8b Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 5 Nov 2019 16:36:30 -0800 Subject: [PATCH 154/343] Fix path_object inheritance (#3403) * Fix path_object inheritance, add zelos path_object --- blockly_uncompressed.js | 12 +++--- core/renderers/common/drawer.js | 2 +- core/renderers/common/i_path_object.js | 7 ++++ core/renderers/common/path_object.js | 3 +- core/renderers/geras/drawer.js | 8 ++-- core/renderers/geras/path_object.js | 47 +++++++++++------------- core/renderers/geras/renderer.js | 2 +- core/renderers/measurables/inputs.js | 3 +- core/renderers/zelos/path_object.js | 51 ++++++++++++++++++++++++++ core/renderers/zelos/renderer.js | 13 +++++++ core/requires.js | 4 +- 11 files changed, 111 insertions(+), 41 deletions(-) create mode 100644 core/renderers/zelos/path_object.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 1b5dc8c4e..dc06f2b86 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -35,7 +35,6 @@ goog.addDependency("../../core/comment.js", ['Blockly.Comment'], ['Blockly.Bubbl goog.addDependency("../../core/components/component.js", ['Blockly.Component', 'Blockly.Component.Error'], ['Blockly.utils.dom', 'Blockly.utils.IdGenerator', 'Blockly.utils.style']); goog.addDependency("../../core/components/menu/menu.js", ['Blockly.Menu'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/components/menu/menuitem.js", ['Blockly.MenuItem'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); -goog.addDependency("../../core/components/slider/slider.js", ['Blockly.Slider'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/components/tree/basenode.js", ['Blockly.tree.BaseNode'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.object', 'Blockly.utils.KeyCodes', 'Blockly.utils.style']); goog.addDependency("../../core/components/tree/treecontrol.js", ['Blockly.tree.TreeControl'], ['Blockly.tree.TreeNode', 'Blockly.tree.BaseNode', 'Blockly.utils.aria', 'Blockly.utils.object', 'Blockly.utils.style']); goog.addDependency("../../core/components/tree/treenode.js", ['Blockly.tree.TreeNode'], ['Blockly.tree.BaseNode', 'Blockly.utils.object', 'Blockly.utils.KeyCodes']); @@ -103,7 +102,7 @@ goog.addDependency("../../core/renderers/geras/highlight_constants.js", ['Blockl goog.addDependency("../../core/renderers/geras/highlighter.js", ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/geras/measurables/inputs.js", ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.utils.object']); -goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.geras.ConstantProvider', 'Blockly.Theme', 'Blockly.utils.dom', 'Blockly.utils.object']); +goog.addDependency("../../core/renderers/geras/path_object.js", ['Blockly.geras.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.geras.ConstantProvider', 'Blockly.Theme', '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/measurables/connections.js", ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); @@ -121,8 +120,9 @@ goog.addDependency("../../core/renderers/zelos/constants.js", ['Blockly.zelos.Co goog.addDependency("../../core/renderers/zelos/drawer.js", ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow', 'Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow']); goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.utils.object']); -goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.RenderInfo']); -goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); +goog.addDependency("../../core/renderers/zelos/path_object.js", ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.zelos.ConstantProvider', 'Blockly.utils.object']); +goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']); +goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/theme.js", ['Blockly.Theme'], ['Blockly.utils', 'Blockly.utils.colour']); goog.addDependency("../../core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); @@ -163,7 +163,7 @@ goog.addDependency("../../core/variables.js", ['Blockly.Variables'], ['Blockly.B goog.addDependency("../../core/variables_dynamic.js", ['Blockly.VariablesDynamic'], ['Blockly.Variables', 'Blockly.Blocks', 'Blockly.Msg', 'Blockly.utils.xml', 'Blockly.VariableModel']); goog.addDependency("../../core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.utils.style']); -goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.Cursor', 'Blockly.MarkerCursor', 'Blockly.Events', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap']); +goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.Cursor', 'Blockly.MarkerCursor', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap']); goog.addDependency("../../core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.userAgent']); 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.dom']); @@ -171,7 +171,7 @@ goog.addDependency("../../core/workspace_comment_svg.js", ['Blockly.WorkspaceCom goog.addDependency("../../core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']); goog.addDependency("../../core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.utils.object']); -goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']); +goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); goog.addDependency("../../core/xml.js", ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.xml']); goog.addDependency("../../core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Css', 'Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.utils.dom']); diff --git a/core/renderers/common/drawer.js b/core/renderers/common/drawer.js index 3b36a9477..c59a6ca3d 100644 --- a/core/renderers/common/drawer.js +++ b/core/renderers/common/drawer.js @@ -72,7 +72,7 @@ Blockly.blockRendering.Drawer.prototype.draw = function() { this.drawOutline_(); this.drawInternals_(); - this.block_.pathObject.setPaths(this.outlinePath_ + '\n' + this.inlinePath_); + this.block_.pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_); if (this.info_.RTL) { this.block_.pathObject.flipRTL(); } diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index 8905a4bd4..870e5def1 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -38,6 +38,13 @@ goog.requireType('Blockly.Theme'); */ Blockly.blockRendering.IPathObject = function(_root, _constants) {}; +/** + * Set the path generated by the renderer onto the respective SVG element. + * @param {string} pathString The path. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.setPath; + /** * Apply the stored colours to the block's path, taking into account whether * the paths belong to a shadow block. diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index a850686ff..27cac6e04 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -46,6 +46,7 @@ Blockly.blockRendering.PathObject = function(root, constants) { * @type {!Blockly.blockRendering.ConstantProvider} */ this.constants_ = constants; + this.svgRoot = root; /** @@ -81,7 +82,7 @@ Blockly.blockRendering.PathObject = function(root, constants) { * @param {string} pathString The path. * @package */ -Blockly.blockRendering.PathObject.prototype.setPaths = function(pathString) { +Blockly.blockRendering.PathObject.prototype.setPath = function(pathString) { this.svgPath.setAttribute('d', pathString); this.svgPathLight.style.display = 'none'; }; diff --git a/core/renderers/geras/drawer.js b/core/renderers/geras/drawer.js index 61b38826b..4affa11e3 100644 --- a/core/renderers/geras/drawer.js +++ b/core/renderers/geras/drawer.js @@ -57,10 +57,12 @@ Blockly.geras.Drawer.prototype.draw = function() { this.drawOutline_(); this.drawInternals_(); - this.block_.pathObject.setPaths(this.outlinePath_ + '\n' + this.inlinePath_, - this.highlighter_.getPath()); + var pathObject = + /** @type {!Blockly.geras.PathObject} */ (this.block_.pathObject); + pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_); + pathObject.setHighlightPath(this.highlighter_.getPath()); if (this.info_.RTL) { - this.block_.pathObject.flipRTL(); + pathObject.flipRTL(); } if (Blockly.blockRendering.useDebugger) { this.block_.renderingDebugger.drawDebug(this.block_, this.info_); diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index 8225268fc..f09bdb6aa 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -24,8 +24,7 @@ goog.provide('Blockly.geras.PathObject'); -goog.require('Blockly.blockRendering.ConstantProvider'); -goog.require('Blockly.blockRendering.IPathObject'); +goog.require('Blockly.blockRendering.PathObject'); goog.require('Blockly.geras.ConstantProvider'); goog.require('Blockly.Theme'); goog.require('Blockly.utils.dom'); @@ -36,10 +35,9 @@ 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.blockRendering.ConstantProvider} constants The renderer's - * constants. + * @param {!Blockly.geras.ConstantProvider} constants The renderer's constants. * @constructor - * @implements {Blockly.blockRendering.IPathObject} + * @extends {Blockly.blockRendering.PathObject} * @package */ Blockly.geras.PathObject = function(root, constants) { @@ -47,7 +45,7 @@ Blockly.geras.PathObject = function(root, constants) { * The renderer's constant provider. * @type {!Blockly.geras.ConstantProvider} */ - this.constants_ = /** @type {!Blockly.geras.ConstantProvider} */ (constants); + this.constants_ = constants; this.svgRoot = root; @@ -93,22 +91,28 @@ Blockly.geras.PathObject = function(root, constants) { */ this.style = Blockly.Theme.createBlockStyle('#000000'); }; +Blockly.utils.object.inherits(Blockly.geras.PathObject, + Blockly.blockRendering.PathObject); /** - * Set each of the paths generated by the renderer onto the respective SVG element. - * @param {string} mainPath The main path. + * @override + */ +Blockly.geras.PathObject.prototype.setPath = function(mainPath) { + this.svgPath.setAttribute('d', mainPath); + this.svgPathDark.setAttribute('d', mainPath); +}; + +/** + * Set the highlight path generated by the renderer onto the SVG element. * @param {string} highlightPath The highlight path. * @package */ -Blockly.geras.PathObject.prototype.setPaths = function(mainPath, highlightPath) { - this.svgPath.setAttribute('d', mainPath); - this.svgPathDark.setAttribute('d', mainPath); +Blockly.geras.PathObject.prototype.setHighlightPath = function(highlightPath) { this.svgPathLight.setAttribute('d', highlightPath); }; /** - * Flip the SVG paths in RTL. - * @package + * @override */ Blockly.geras.PathObject.prototype.flipRTL = function() { // Mirror the block's path. @@ -118,10 +122,7 @@ Blockly.geras.PathObject.prototype.flipRTL = function() { }; /** - * Apply the stored colours to the block's path, taking into account whether - * the paths belong to a shadow block. - * @param {boolean} isShadow True if the block is a shadow block. - * @package + * @override */ Blockly.geras.PathObject.prototype.applyColour = function(isShadow) { if (isShadow) { @@ -140,9 +141,7 @@ Blockly.geras.PathObject.prototype.applyColour = function(isShadow) { }; /** - * Set the style. - * @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use. - * @package + * @override */ Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) { this.style = blockStyle; @@ -152,9 +151,7 @@ Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) { }; /** - * Set whether the block shows a highlight or not. Block highlighting is - * often used to visually mark blocks currently being executed. - * @param {boolean} highlighted True if highlighted. + * @override */ Blockly.geras.PathObject.prototype.setHighlighted = function(highlighted) { if (highlighted) { @@ -168,9 +165,7 @@ Blockly.geras.PathObject.prototype.setHighlighted = function(highlighted) { }; /** - * Set whether the block shows a disable pattern or not. - * @param {boolean} disabled True if disabled. - * @param {boolean} isShadow True if the block is a shadow block. + * @override */ Blockly.geras.PathObject.prototype.setDisabled = function(disabled, isShadow) { if (disabled) { diff --git a/core/renderers/geras/renderer.js b/core/renderers/geras/renderer.js index 0a43bf18e..0a18191bf 100644 --- a/core/renderers/geras/renderer.js +++ b/core/renderers/geras/renderer.js @@ -113,7 +113,7 @@ Blockly.geras.Renderer.prototype.makePathObject = function(root) { * provider. * @protected */ -Blockly.blockRendering.Renderer.prototype.makeHighlightConstants_ = function() { +Blockly.geras.Renderer.prototype.makeHighlightConstants_ = function() { return new Blockly.geras.HighlightConstantProvider( /** @type {!Blockly.blockRendering.ConstantProvider} */ (this.getConstants())); diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index 754c624a7..ccccb8343 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -63,7 +63,8 @@ Blockly.blockRendering.InputConnection = function(constants, input) { // TODO (#3186): change references to connectionModel, since that's on // Connection. - this.connection = input.connection; + this.connection = + /** @type {!Blockly.RenderedConnection} */ (input.connection); this.connectionOffsetX = 0; this.connectionOffsetY = 0; }; diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js new file mode 100644 index 000000000..8a1383ac6 --- /dev/null +++ b/core/renderers/zelos/path_object.js @@ -0,0 +1,51 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview An object that owns a block's rendering SVG elements. + * @author samelh@google.com (Sam El-Husseini) + */ + +'use strict'; + +goog.provide('Blockly.zelos.PathObject'); + +goog.require('Blockly.blockRendering.PathObject'); +goog.require('Blockly.zelos.ConstantProvider'); +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.zelos.ConstantProvider} constants The renderer's constants. + * @constructor + * @extends {Blockly.blockRendering.PathObject} + * @package + */ +Blockly.zelos.PathObject = function(root, constants) { + Blockly.zelos.PathObject.superClass_.constructor.call(this, root, constants); + + /** + * The renderer's constant provider. + * @type {!Blockly.zelos.ConstantProvider} + */ + this.constants_ = constants; +}; +Blockly.utils.object.inherits(Blockly.zelos.PathObject, + Blockly.blockRendering.PathObject); diff --git a/core/renderers/zelos/renderer.js b/core/renderers/zelos/renderer.js index 576697030..a075e2f13 100644 --- a/core/renderers/zelos/renderer.js +++ b/core/renderers/zelos/renderer.js @@ -28,6 +28,7 @@ goog.require('Blockly.blockRendering.Renderer'); goog.require('Blockly.utils.object'); goog.require('Blockly.zelos.ConstantProvider'); goog.require('Blockly.zelos.Drawer'); +goog.require('Blockly.zelos.PathObject'); goog.require('Blockly.zelos.RenderInfo'); @@ -78,4 +79,16 @@ Blockly.zelos.Renderer.prototype.makeDrawer_ = function(block, info) { /** @type {!Blockly.zelos.RenderInfo} */ (info)); }; +/** + * Create a new instance of a renderer path object. + * @param {!SVGElement} root The root SVG element. + * @return {!Blockly.zelos.PathObject} The renderer path object. + * @package + * @override + */ +Blockly.zelos.Renderer.prototype.makePathObject = function(root) { + return new Blockly.zelos.PathObject(root, + /** @type {!Blockly.zelos.ConstantProvider} */ (this.getConstants())); +}; + Blockly.blockRendering.register('zelos', Blockly.zelos.Renderer); diff --git a/core/requires.js b/core/requires.js index d80533c8f..07cb84efc 100644 --- a/core/requires.js +++ b/core/requires.js @@ -79,8 +79,8 @@ goog.require('Blockly.FieldVariable'); // At least one renderer is mandatory. Geras is the default one. // Others may be chosen using Blockly.inject's "renderer" configuration. goog.require('Blockly.geras.Renderer'); -// goog.require('Blockly.thrasos.Renderer'); -// goog.require('Blockly.zelos.Renderer'); +goog.require('Blockly.thrasos.Renderer'); +goog.require('Blockly.zelos.Renderer'); // The debug renderer, which shows simplified versions of the blocks for // developer use. // goog.require('Blockly.blockRendering.Debug'); From 4aadaeb3ab32796949198e0c767c96d1db61070f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 5 Nov 2019 16:52:56 -0800 Subject: [PATCH 155/343] Add zelos / pxtblockly comparison playground (#3402) * Add zelos / pxtblockly comparison tests --- tests/rendering/zelos/README.md | 19 +++ tests/rendering/zelos/index.html | 204 ++++++++++++++++++++++++++ tests/rendering/zelos/pxtblockly.html | 38 +++++ tests/rendering/zelos/zelos.html | 50 +++++++ 4 files changed, 311 insertions(+) create mode 100644 tests/rendering/zelos/README.md create mode 100644 tests/rendering/zelos/index.html create mode 100644 tests/rendering/zelos/pxtblockly.html create mode 100644 tests/rendering/zelos/zelos.html diff --git a/tests/rendering/zelos/README.md b/tests/rendering/zelos/README.md new file mode 100644 index 000000000..d8cf459df --- /dev/null +++ b/tests/rendering/zelos/README.md @@ -0,0 +1,19 @@ +# Zelos Rendering / PXT-Blockly Comparison Playground + +## Dependencies +``` +npm install -g http-server +``` + +## Running the Playground: + +In Blockly's root directory, run: +``` +http-server ./ +``` + +and browse to: +``` +http://127.0.0.1:8080/tests/rendering/zelos +``` + diff --git a/tests/rendering/zelos/index.html b/tests/rendering/zelos/index.html new file mode 100644 index 000000000..1b85aa938 --- /dev/null +++ b/tests/rendering/zelos/index.html @@ -0,0 +1,204 @@ + + + + + + + + +
+
+
+

Zelos Rendering

+
+
+

PXT-Blockly Rendering

+
+
+
+
+ +
+
+ +
+
+
+ + + + + diff --git a/tests/rendering/zelos/pxtblockly.html b/tests/rendering/zelos/pxtblockly.html new file mode 100644 index 000000000..8e454c255 --- /dev/null +++ b/tests/rendering/zelos/pxtblockly.html @@ -0,0 +1,38 @@ + + + + + + + + + +
+ + + + diff --git a/tests/rendering/zelos/zelos.html b/tests/rendering/zelos/zelos.html new file mode 100644 index 000000000..a01d04dcc --- /dev/null +++ b/tests/rendering/zelos/zelos.html @@ -0,0 +1,50 @@ + + + + + + + + + + + +
+ + + + \ No newline at end of file From e71366259c19b20837e7a3d421365c9c582456a4 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 5 Nov 2019 17:15:26 -0800 Subject: [PATCH 156/343] Move lots of update style functions from block_svg to path_object --- core/block_svg.js | 51 ++++-------------- core/renderers/common/i_path_object.js | 36 ++++++++++++- core/renderers/common/path_object.js | 73 ++++++++++++++++++++++++-- 3 files changed, 111 insertions(+), 49 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 36b9dac54..bb8113813 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -250,7 +250,7 @@ Blockly.BlockSvg.prototype.initSvg = function() { icons[i].createIcon(); } this.applyColour(); - this.updateMovable(); + this.pathObject.updateMovable(this.isMovable()); var svg = this.getSvgRoot(); if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) { Blockly.bindEventWithChecks_( @@ -881,26 +881,13 @@ Blockly.BlockSvg.prototype.setDragging = function(adding) { } }; -/** - * Add or remove the UI indicating if this block is movable or not. - */ -Blockly.BlockSvg.prototype.updateMovable = function() { - if (this.isMovable()) { - Blockly.utils.dom.addClass( - /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); - } else { - Blockly.utils.dom.removeClass( - /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); - } -}; - /** * 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); - this.updateMovable(); + this.pathObject.updateMovable(movable); }; /** @@ -937,8 +924,7 @@ Blockly.BlockSvg.prototype.setInsertionMarker = function(insertionMarker) { this.isInsertionMarker_ = insertionMarker; if (this.isInsertionMarker_) { this.setColour(Blockly.INSERTION_MARKER_COLOUR); - Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgGroup_), - 'blocklyInsertionMarker'); + this.pathObject.updateInsertionMarker(true); } }; @@ -1038,19 +1024,8 @@ Blockly.BlockSvg.prototype.applyColour = function() { * Enable or disable a block. */ Blockly.BlockSvg.prototype.updateDisabled = function() { - if (!this.isEnabled() || this.getInheritedDisabled()) { - var added = Blockly.utils.dom.addClass( - /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); - if (added) { - this.pathObject.setDisabled(true, this.isShadow()); - } - } else { - var removed = Blockly.utils.dom.removeClass( - /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); - if (removed) { - this.pathObject.setDisabled(false, this.isShadow()); - } - } + var isDisabled = !this.isEnabled() || this.getInheritedDisabled(); + this.pathObject.updateDisabled(isDisabled, this.isShadow()); var children = this.getChildren(false); for (var i = 0, child; (child = children[i]); i++) { child.updateDisabled(); @@ -1235,23 +1210,21 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { if (!this.rendered) { return; } - this.pathObject.setHighlighted(highlighted); + this.pathObject.updateHighlighted(highlighted); }; /** * Select this block. Highlight it visually. */ Blockly.BlockSvg.prototype.addSelect = function() { - Blockly.utils.dom.addClass( - /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); + this.pathObject.updateSelected(true); }; /** * Unselect this block. Remove its highlighting. */ Blockly.BlockSvg.prototype.removeSelect = function() { - Blockly.utils.dom.removeClass( - /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); + this.pathObject.updateSelected(false); }; /** @@ -1261,13 +1234,7 @@ Blockly.BlockSvg.prototype.removeSelect = function() { * @package */ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { - if (enable) { - Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgGroup_), - 'blocklyDraggingDelete'); - } else { - Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgGroup_), - 'blocklyDraggingDelete'); - } + this.pathObject.updateDraggingDelete(enable); }; diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index 870e5def1..b7f6b405a 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -70,12 +70,44 @@ Blockly.blockRendering.IPathObject.prototype.flipRTL; * Set whether the block shows a highlight or not. Block highlighting is * often used to visually mark blocks currently being executed. * @param {boolean} highlighted True if highlighted. + * @package */ -Blockly.blockRendering.IPathObject.prototype.setHighlighted; +Blockly.blockRendering.IPathObject.prototype.updateHighlighted; /** * Set whether the block shows a disable pattern or not. * @param {boolean} disabled True if disabled. * @param {boolean} isShadow True if the block is a shadow block. + * @package */ -Blockly.blockRendering.IPathObject.prototype.setDisabled; +Blockly.blockRendering.IPathObject.prototype.updateDisabled; + +/** + * 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; + +/** + * Add or remove styling showing that a block is dragged over a delete area. + * @param {boolean} enable True if the block is being dragged over a delete + * area, false otherwise. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.updateDraggingDelete; + +/** + * Add or remove styling showing that a block is an insertion marker. + * @param {boolean} enable True if the block is an insertion marker, false + * otherwise. + * @package + */ +Blockly.blockRendering.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; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 27cac6e04..8d276cea7 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -44,6 +44,7 @@ Blockly.blockRendering.PathObject = function(root, constants) { /** * The renderer's constant provider. * @type {!Blockly.blockRendering.ConstantProvider} + * @protected */ this.constants_ = constants; @@ -121,14 +122,33 @@ Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) { this.style = blockStyle; }; +/** + * Add or remove the given CSS class on the path object's root SVG element. + * @param {string} className The name of the class to add or remove + * @param {boolean} add True if the class should be added. False if it should + * be removed. + * @protected + */ +Blockly.blockRendering.PathObject.prototype.setClass = function( + className, add) { + if (add) { + Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgRoot), + className); + } else { + Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgRoot), + className); + } +}; + /** * Set whether the block shows a highlight or not. Block highlighting is * often used to visually mark blocks currently being executed. - * @param {boolean} highlighted True if highlighted. + * @param {boolean} enable True if highlighted. + * @package */ -Blockly.blockRendering.PathObject.prototype.setHighlighted = function( - highlighted) { - if (highlighted) { +Blockly.blockRendering.PathObject.prototype.updateHighlighted = function( + enable) { + if (enable) { this.svgPath.setAttribute('filter', 'url(#' + this.constants_.embossFilterId + ')'); } else { @@ -140,9 +160,12 @@ Blockly.blockRendering.PathObject.prototype.setHighlighted = function( * Set whether the block shows a disable pattern or not. * @param {boolean} disabled True if disabled. * @param {boolean} isShadow True if the block is a shadow block. + * @package */ -Blockly.blockRendering.PathObject.prototype.setDisabled = function(disabled, +Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled, isShadow) { + + this.setClass('blocklyDisabled', disabled); if (disabled) { this.svgPath.setAttribute('fill', 'url(#' + this.constants_.disabledPatternId + ')'); @@ -150,3 +173,43 @@ Blockly.blockRendering.PathObject.prototype.setDisabled = function(disabled, this.applyColour(isShadow); } }; + +/** + * Add or remove styling showing that a block is selected. + * @param {boolean} enable True if selection is enabled, false otherwise. + * @package + */ +Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { + this.setClass('blocklySelected', enable); +}; + +/** + * Add or remove styling showing that a block is dragged over a delete area. + * @param {boolean} enable True if the block is being dragged over a delete + * area, false otherwise. + * @package + */ +Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function( + enable) { + this.setClass('blocklyDraggingDelete', enable); +}; + +/** + * Add or remove styling showing that a block is an insertion marker. + * @param {boolean} enable True if the block is an insertion marker, false + * otherwise. + * @package + */ +Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function( + enable) { + this.setClass('blocklyInsertionMarker', enable); +}; + +/** + * Add or remove styling showing that a block is movable. + * @param {boolean} enable True if the block is movable, false otherwise. + * @package + */ +Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) { + this.setClass('blocklyDraggable', enable); +}; From 582461566686c2413f053357fdc69487dcdc737d Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Tue, 5 Nov 2019 19:03:16 -0800 Subject: [PATCH 157/343] Add flag to navigate to all fields (#3404) --- core/keyboard_nav/ast_node.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/core/keyboard_nav/ast_node.js b/core/keyboard_nav/ast_node.js index 133591a6b..509759aaf 100644 --- a/core/keyboard_nav/ast_node.js +++ b/core/keyboard_nav/ast_node.js @@ -82,6 +82,12 @@ Blockly.ASTNode.types = { WORKSPACE: 'workspace' }; +/** + * True to navigate to all fields. False to only navigate to clickable fields. + * @type {boolean} + */ +Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false; + /** * The default y offset to use when moving the cursor from a stack to the * workspace. @@ -272,7 +278,7 @@ Blockly.ASTNode.prototype.findNextForInput_ = function() { 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.EDITABLE) { + if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { return Blockly.ASTNode.createFieldNode(field); } } @@ -300,7 +306,7 @@ Blockly.ASTNode.prototype.findNextForField_ = function() { for (var i = curIdx, newInput; (newInput = block.inputList[i]); i++) { var fieldRow = newInput.fieldRow; while (fieldIdx < fieldRow.length) { - if (fieldRow[fieldIdx].EDITABLE) { + if (fieldRow[fieldIdx].isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { return Blockly.ASTNode.createFieldNode(fieldRow[fieldIdx]); } fieldIdx++; @@ -331,7 +337,7 @@ Blockly.ASTNode.prototype.findPrevForInput_ = function() { } var fieldRow = input.fieldRow; for (var j = fieldRow.length - 1, field; (field = fieldRow[j]); j--) { - if (field.EDITABLE) { + if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { return Blockly.ASTNode.createFieldNode(field); } } @@ -358,7 +364,7 @@ Blockly.ASTNode.prototype.findPrevForField_ = function() { } var fieldRow = input.fieldRow; while (fieldIdx > -1) { - if (fieldRow[fieldIdx].EDITABLE) { + if (fieldRow[fieldIdx].isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { return Blockly.ASTNode.createFieldNode(fieldRow[fieldIdx]); } fieldIdx--; @@ -462,7 +468,7 @@ Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) { for (var i = 0, input; (input = inputs[i]); i++) { var fieldRow = input.fieldRow; for (var j = 0, field; (field = fieldRow[j]); j++) { - if (field.EDITABLE) { + if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) { return Blockly.ASTNode.createFieldNode(field); } } From c9c6fa702c3b7ce265147ee2de5b732e2d08e6b5 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 5 Nov 2019 13:01:49 -0800 Subject: [PATCH 158/343] Update JS-Interpreter to latest version And fix alerting falsy values. --- demos/interpreter/acorn_interpreter.js | 230 +++++++++++-------------- demos/interpreter/step-execution.html | 5 +- 2 files changed, 103 insertions(+), 132 deletions(-) diff --git a/demos/interpreter/acorn_interpreter.js b/demos/interpreter/acorn_interpreter.js index 81e521b07..249bc6cdd 100644 --- a/demos/interpreter/acorn_interpreter.js +++ b/demos/interpreter/acorn_interpreter.js @@ -38,132 +38,104 @@ Pb=RegExp("[\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02 na=/[\n\r\u2028\u2029]/,Y=/\r\n|[\n\r\u2028\u2029]/g,la=a.isIdentifierStart=function(a){return 65>a?36===a:91>a?!0:97>a?95===a:123>a?!0:170<=a&&Za.test(String.fromCharCode(a))},ab=a.isIdentifierChar=function(a){return 48>a?36===a:58>a?!0:65>a?!1:91>a?!0:97>a?95===a:123>a?!0:170<=a&&Pb.test(String.fromCharCode(a))},ca,Ia={kind:"loop"},Ob={kind:"switch"}}; "object"==typeof exports&&"object"==typeof module?mod$$inline_58(exports):"function"==typeof define&&define.amd?define(["exports"],mod$$inline_58):mod$$inline_58(this.acorn||(this.acorn={})); // JS-Interpreter: Copyright 2013 Google LLC, Apache 2.0 -var Interpreter=function(a,b){"string"==typeof a&&(a=acorn.parse(a,Interpreter.PARSE_OPTIONS));this.ast=a;this.initFunc_=b;this.paused_=!1;this.polyfills_=[];this.UNDEFINED=new Interpreter.Primitive(void 0,this);this.NULL=new Interpreter.Primitive(null,this);this.NAN=new Interpreter.Primitive(NaN,this);this.TRUE=new Interpreter.Primitive(!0,this);this.FALSE=new Interpreter.Primitive(!1,this);this.NUMBER_ZERO=new Interpreter.Primitive(0,this);this.NUMBER_ONE=new Interpreter.Primitive(1,this);this.STRING_EMPTY= -new Interpreter.Primitive("",this);b=this.createScope(this.ast,null);this.NAN.parent=this.NUMBER;this.TRUE.parent=this.BOOLEAN;this.FALSE.parent=this.BOOLEAN;this.NUMBER_ZERO.parent=this.NUMBER;this.NUMBER_ONE.parent=this.NUMBER;this.STRING_EMPTY.parent=this.STRING;this.ast=acorn.parse(this.polyfills_.join("\n"),Interpreter.PARSE_OPTIONS);this.polyfills_=void 0;this.stripLocations_(this.ast);this.stateStack=[{node:this.ast,scope:b,thisExpression:b,done:!1}];this.run();this.value=this.UNDEFINED;this.ast= -a;this.stateStack=[{node:this.ast,scope:b,thisExpression:b,done:!1}]};Interpreter.PARSE_OPTIONS={ecmaVersion:5};Interpreter.READONLY_DESCRIPTOR={configurable:!0,enumerable:!0,writable:!1};Interpreter.NONENUMERABLE_DESCRIPTOR={configurable:!0,enumerable:!1,writable:!0};Interpreter.READONLY_NONENUMERABLE_DESCRIPTOR={configurable:!0,enumerable:!1,writable:!1}; -Interpreter.prototype.appendCode=function(a){var b=this.stateStack[this.stateStack.length-1];if(!b||"Program"!=b.node.type)throw Error("Expecting original AST to start with a Program node.");"string"==typeof a&&(a=acorn.parse(a,Interpreter.PARSE_OPTIONS));if(!a||"Program"!=a.type)throw Error("Expecting new AST to start with a Program node.");this.populateScope_(a,b.scope);for(var c=0,d;d=a.body[c];c++)b.node.body.push(d);b.done=!1}; -Interpreter.prototype.step=function(){var a=this.stateStack[0];if(!a||"Program"==a.node.type&&a.done)return!1;if(this.paused_)return!0;this["step"+a.node.type]();return a.node.end?!0:this.step()};Interpreter.prototype.run=function(){for(;!this.paused_&&this.step(););return this.paused_}; -Interpreter.prototype.initGlobalScope=function(a){this.setProperty(a,"Infinity",this.createPrimitive(Infinity),Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"NaN",this.NAN,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"undefined",this.UNDEFINED,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"window",a,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"self",a);this.initFunction(a);this.initObject(a);a.parent=this.OBJECT;this.initArray(a);this.initNumber(a);this.initString(a);this.initBoolean(a); -this.initDate(a);this.initMath(a);this.initRegExp(a);this.initJSON(a);this.initError(a);var b=this,c;c=function(a){a=a||b.UNDEFINED;return b.createPrimitive(isNaN(a.toNumber()))};this.setProperty(a,"isNaN",this.createNativeFunction(c));c=function(a){a=a||b.UNDEFINED;return b.createPrimitive(isFinite(a.toNumber()))};this.setProperty(a,"isFinite",this.createNativeFunction(c));this.setProperty(a,"parseFloat",this.getProperty(this.NUMBER,"parseFloat"));this.setProperty(a,"parseInt",this.getProperty(this.NUMBER, -"parseInt"));c=this.createObject(this.FUNCTION);c.eval=!0;this.setProperty(c,"length",this.NUMBER_ONE,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"eval",c);for(var d=[[escape,"escape"],[unescape,"unescape"],[decodeURI,"decodeURI"],[decodeURIComponent,"decodeURIComponent"],[encodeURI,"encodeURI"],[encodeURIComponent,"encodeURIComponent"]],h=0;ha?Math.max(this.length+a,0):Math.min(a,this.length);d=c(d,Infinity);d=Math.min(d,this.length-a);for(var g=b.createObject(b.ARRAY),h=a;h=a;h--)this.properties[h+arguments.length-2]=this.properties[h];this.length+=arguments.length-2;for(h=2;hh&&(h=this.length+h);h=Math.max(0,Math.min(h,this.length)); -d=c(d,this.length);0>d&&(d=this.length+d);d=Math.max(0,Math.min(d,this.length));for(a=0;hd&&(d=this.length+d);for(d=Math.max(0,d);dd&&(d=this.length+d);for(d=Math.min(d,this.length-1);0<=d;d--){var h=b.getProperty(this,d);if(h.isPrimitive&&a.isPrimitive?h.data===a.data:h===a)return b.createPrimitive(d)}return b.createPrimitive(-1)};this.setNativeFunctionPrototype(this.ARRAY,"lastIndexOf",d);this.polyfills_.push("Object.defineProperty(Array.prototype, 'every', {configurable: true, value:","function(callbackfn, thisArg) {", -"if (this == null || typeof callbackfn !== 'function') throw new TypeError;","var T, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O && !callbackfn.call(T, O[k], k, O)) return false;","k++;","}","return true;","}","});","Object.defineProperty(Array.prototype, 'filter', {configurable: true, value:","function(fun/*, thisArg*/) {","if (this === void 0 || this === null || typeof fun !== 'function') throw new TypeError;", -"var t = Object(this);","var len = t.length >>> 0;","var res = [];","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;","for (var i = 0; i < len; i++) {","if (i in t) {","var val = t[i];","if (fun.call(thisArg, val, i, t)) res.push(val);","}","}","return res;","}","});","Object.defineProperty(Array.prototype, 'forEach', {configurable: true, value:","function(callback, thisArg) {","if (this == null || typeof callback !== 'function') throw new TypeError;","var T, k;","var O = Object(this);", -"var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O) callback.call(T, O[k], k, O);","k++;","}","}","});","Object.defineProperty(Array.prototype, 'map', {configurable: true, value:","function(callback, thisArg) {","if (this == null || typeof callback !== 'function') new TypeError;","var T, A, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","A = new Array(len);","k = 0;","while (k < len) {","if (k in O) A[k] = callback.call(T, O[k], k, O);", -"k++;","}","return A;","}","});","Object.defineProperty(Array.prototype, 'reduce', {configurable: true, value:","function(callback /*, initialValue*/) {","if (this == null || typeof callback !== 'function') throw new TypeError;","var t = Object(this), len = t.length >>> 0, k = 0, value;","if (arguments.length == 2) {","value = arguments[1];","} else {","while (k < len && !(k in t)) k++;","if (k >= len) {","throw new TypeError('Reduce of empty array with no initial value');","}","value = t[k++];", -"}","for (; k < len; k++) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'reduceRight', {configurable: true, value:","function(callback /*, initialValue*/) {","if (null === this || 'undefined' === typeof this || 'function' !== typeof callback) throw new TypeError;","var t = Object(this), len = t.length >>> 0, k = len - 1, value;","if (arguments.length >= 2) {","value = arguments[1];","} else {","while (k >= 0 && !(k in t)) k--;", -"if (k < 0) {","throw new TypeError('Reduce of empty array with no initial value');","}","value = t[k--];","}","for (; k >= 0; k--) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'some', {configurable: true, value:","function(fun/*, thisArg*/) {","if (this == null || typeof fun !== 'function') throw new TypeError;","var t = Object(this);","var len = t.length >>> 0;","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;", -"for (var i = 0; i < len; i++) {","if (i in t && fun.call(thisArg, t[i], i, t)) {","return true;","}","}","return false;","}","});","Object.defineProperty(Array.prototype, 'sort', {configurable: true, value:","function(opt_comp) {","for (var i = 0; i < this.length; i++) {","var changes = 0;","for (var j = 0; j < this.length - i - 1; j++) {","if (opt_comp ?opt_comp(this[j], this[j + 1]) > 0 : this[j] > this[j + 1]) {","var swap = this[j];","this[j] = this[j + 1];","this[j + 1] = swap;","changes++;", -"}","}","if (changes <= 1) break;","}","return this;","}","});","Object.defineProperty(Array.prototype, 'toLocaleString', {configurable: true, value:","function() {","var out = [];","for (var i = 0; i < this.length; i++) {","out[i] = (this[i] === null || this[i] === undefined) ? '' : this[i].toLocaleString();","}","return out.join(',');","}","});","")}; -Interpreter.prototype.initNumber=function(a){var b=this,c;c=function(a){a=a?a.toNumber():0;if(this.parent!=b.NUMBER)return b.createPrimitive(a);this.data=a;return this};this.NUMBER=this.createNativeFunction(c);this.setProperty(a,"Number",this.NUMBER);a=["MAX_VALUE","MIN_VALUE","NaN","NEGATIVE_INFINITY","POSITIVE_INFINITY"];for(c=0;cb?1:0};Interpreter.prototype.arrayIndex=function(a){a=Number(a);return!isFinite(a)||a!=Math.floor(a)||0>a?NaN:a}; -Interpreter.Primitive=function(a,b){var c=typeof a;this.data=a;this.type=c;"number"==c?this.parent=b.NUMBER:"string"==c?this.parent=b.STRING:"boolean"==c&&(this.parent=b.BOOLEAN)};Interpreter.Primitive.prototype.data=void 0;Interpreter.Primitive.prototype.type="undefined";Interpreter.Primitive.prototype.parent=null;Interpreter.Primitive.prototype.isPrimitive=!0;Interpreter.Primitive.prototype.toBoolean=function(){return!!this.data};Interpreter.Primitive.prototype.toNumber=function(){return Number(this.data)}; -Interpreter.Primitive.prototype.toString=function(){return String(this.data)};Interpreter.Primitive.prototype.valueOf=function(){return this.data};Interpreter.prototype.createPrimitive=function(a){return void 0===a?this.UNDEFINED:null===a?this.NULL:!0===a?this.TRUE:!1===a?this.FALSE:0===a?this.NUMBER_ZERO:1===a?this.NUMBER_ONE:""===a?this.STRING_EMPTY:a instanceof RegExp?this.populateRegExp_(this.createObject(this.REGEXP),a):new Interpreter.Primitive(a,this)}; -Interpreter.Object=function(a){this.notConfigurable=Object.create(null);this.notEnumerable=Object.create(null);this.notWritable=Object.create(null);this.getter=Object.create(null);this.setter=Object.create(null);this.properties=Object.create(null);this.parent=a};Interpreter.Object.prototype.type="object";Interpreter.Object.prototype.parent=null;Interpreter.Object.prototype.isPrimitive=!1;Interpreter.Object.prototype.data=void 0;Interpreter.Object.prototype.toBoolean=function(){return!0}; -Interpreter.Object.prototype.toNumber=function(){return Number(void 0===this.data?this.toString():this.data)};Interpreter.Object.prototype.toString=function(){return void 0===this.data?"["+this.type+"]":String(this.data)};Interpreter.Object.prototype.valueOf=function(){return void 0===this.data?this:this.data}; -Interpreter.prototype.createObject=function(a){a=new Interpreter.Object(a);this.isa(a,this.FUNCTION)&&(a.type="function",this.setProperty(a,"prototype",this.createObject(this.OBJECT||null)));this.isa(a,this.ARRAY)&&(a.length=0,a.toString=function(){for(var a=[],c=0;c>="==b.operator)b=d>>h;else if(">>>="==b.operator)b=d>>>h;else if("&="==b.operator)b=d&h;else if("^="==b.operator)b=d^h;else if("|="==b.operator)b=d|h;else throw SyntaxError("Unknown assignment expression: "+b.operator);b=this.createPrimitive(b)}(c=this.setValue(a.leftSide,b))?(a.doneSetter_=b,this.stateStack.unshift({node:{type:"CallExpression"},doneCallee_:!0,funcThis_:a.leftSide[0],func_:c,doneArgs_:!0,arguments:[b]})): -(this.stateStack.shift(),this.stateStack[0].value=b)}else{a.leftSide||(a.leftSide=a.value);a.doneGetter_&&(a.leftValue=a.value);if(!a.doneGetter_&&"="!=b.operator&&(a.leftValue=this.getValue(a.leftSide),a.leftValue.isGetter)){a.leftValue.isGetter=!1;a.doneGetter_=!0;this.stateStack.unshift({node:{type:"CallExpression"},doneCallee_:!0,funcThis_:a.leftSide[0],func_:a.leftValue,doneArgs_:!0,arguments:[]});return}a.doneRight=!0;this.stateStack.unshift({node:b.right})}else a.doneLeft=!0,this.stateStack.unshift({node:b.left, -components:!0})}; -Interpreter.prototype.stepBinaryExpression=function(){var a=this.stateStack[0],b=a.node;if(a.doneLeft)if(a.doneRight){this.stateStack.shift();var c=a.leftValue,a=a.value,d=this.comp(c,a);if("=="==b.operator||"!="==b.operator)c=c.isPrimitive&&a.isPrimitive?c.data==a.data:0===d,"!="==b.operator&&(c=!c);else if("==="==b.operator||"!=="==b.operator)c=c.isPrimitive&&a.isPrimitive?c.data===a.data:c===a,"!=="==b.operator&&(c=!c);else if(">"==b.operator)c=1==d;else if(">="==b.operator)c=1==d||0===d;else if("<"== -b.operator)c=-1==d;else if("<="==b.operator)c=-1==d||0===d;else if("+"==b.operator)c=c.isPrimitive?c.data:c.toString(),a=a.isPrimitive?a.data:a.toString(),c+=a;else if("in"==b.operator)c=this.hasProperty(a,c);else if("instanceof"==b.operator)this.isa(a,this.FUNCTION)||this.throwException(this.TYPE_ERROR,"Expecting a function in instanceof check"),c=this.isa(c,a);else if(c=c.toNumber(),a=a.toNumber(),"-"==b.operator)c-=a;else if("*"==b.operator)c*=a;else if("/"==b.operator)c/=a;else if("%"==b.operator)c%= -a;else if("&"==b.operator)c&=a;else if("|"==b.operator)c|=a;else if("^"==b.operator)c^=a;else if("<<"==b.operator)c<<=a;else if(">>"==b.operator)c>>=a;else if(">>>"==b.operator)c>>>=a;else throw SyntaxError("Unknown binary operator: "+b.operator);this.stateStack[0].value=this.createPrimitive(c)}else a.doneRight=!0,a.leftValue=a.value,this.stateStack.unshift({node:b.right});else a.doneLeft=!0,this.stateStack.unshift({node:b.left})}; -Interpreter.prototype.stepBlockStatement=function(){var a=this.stateStack[0],b=a.node,c=a.n_||0;b.body[c]?(a.done=!1,a.n_=c+1,this.stateStack.unshift({node:b.body[c]})):(a.done=!0,"Program"!=a.node.type&&this.stateStack.shift())}; -Interpreter.prototype.stepBreakStatement=function(){var a=this.stateStack.shift(),a=a.node,b=null;a.label&&(b=a.label.name);for(a=this.stateStack.shift();a&&"CallExpression"!=a.node.type&&"NewExpression"!=a.node.type;){if(b?b==a.label:a.isLoop||a.isSwitch)return;a=this.stateStack.shift()}throw SyntaxError("Illegal break statement");}; -Interpreter.prototype.stepCallExpression=function(){var a=this.stateStack[0],b=a.node;if(a.doneCallee_){if(!a.func_){if("function"==a.value.type)a.func_=a.value;else{a.value.length&&(a.member_=a.value[0]);a.func_=this.getValue(a.value);if(!a.func_)return;if("function"!=a.func_.type){this.throwException(this.TYPE_ERROR,(a.value&&a.value.type)+" is not a function");return}}"NewExpression"==a.node.type?(a.funcThis_=this.createObject(a.func_),a.isConstructor_=!0):a.funcThis_=a.func_.boundThis_?a.func_.boundThis_: -a.value.length?a.value[0]:this.stateStack[this.stateStack.length-1].thisExpression;a.arguments=a.func_.boundArgs_?a.func_.boundArgs_.concat():[];a.n_=0}if(!a.doneArgs_){0!=a.n_&&a.arguments.push(a.value);if(b.arguments[a.n_]){this.stateStack.unshift({node:b.arguments[a.n_]});a.n_++;return}a.doneArgs_=!0}if(a.doneExec_)this.stateStack.shift(),this.stateStack[0].value=a.isConstructor_&&"object"!==a.value.type?a.funcThis_:a.value;else if(a.doneExec_=!0,a.func_.node){for(var b=this.createScope(a.func_.node.body, -a.func_.parentScope),c=0;cc?a.arguments[c]:this.UNDEFINED;this.setProperty(b,d,h)}d=this.createObject(this.ARRAY);for(c=0;c>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O && !callbackfn.call(T, O[k], k, O)) return false;","k++;","}","return true;", +"}","});","Object.defineProperty(Array.prototype, 'filter',","{configurable: true, writable: true, value:","function(fun/*, thisArg*/) {","if (this === void 0 || this === null || typeof fun !== 'function') throw TypeError();","var t = Object(this);","var len = t.length >>> 0;","var res = [];","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;","for (var i = 0; i < len; i++) {","if (i in t) {","var val = t[i];","if (fun.call(thisArg, val, i, t)) res.push(val);","}","}","return res;","}", +"});","Object.defineProperty(Array.prototype, 'forEach',","{configurable: true, writable: true, value:","function(callback, thisArg) {","if (!this || typeof callback !== 'function') throw TypeError();","var T, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O) callback.call(T, O[k], k, O);","k++;","}","}","});","Object.defineProperty(Array.prototype, 'map',","{configurable: true, writable: true, value:","function(callback, thisArg) {", +"if (!this || typeof callback !== 'function') new TypeError;","var T, A, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","A = new Array(len);","k = 0;","while (k < len) {","if (k in O) A[k] = callback.call(T, O[k], k, O);","k++;","}","return A;","}","});","Object.defineProperty(Array.prototype, 'reduce',","{configurable: true, writable: true, value:","function(callback /*, initialValue*/) {","if (!this || typeof callback !== 'function') throw TypeError();", +"var t = Object(this), len = t.length >>> 0, k = 0, value;","if (arguments.length === 2) {","value = arguments[1];","} else {","while (k < len && !(k in t)) k++;","if (k >= len) {","throw TypeError('Reduce of empty array with no initial value');","}","value = t[k++];","}","for (; k < len; k++) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'reduceRight',","{configurable: true, writable: true, value:","function(callback /*, initialValue*/) {", +"if (null === this || 'undefined' === typeof this || 'function' !== typeof callback) throw TypeError();","var t = Object(this), len = t.length >>> 0, k = len - 1, value;","if (arguments.length >= 2) {","value = arguments[1];","} else {","while (k >= 0 && !(k in t)) k--;","if (k < 0) {","throw TypeError('Reduce of empty array with no initial value');","}","value = t[k--];","}","for (; k >= 0; k--) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'some',", +"{configurable: true, writable: true, value:","function(fun/*, thisArg*/) {","if (!this || typeof fun !== 'function') throw TypeError();","var t = Object(this);","var len = t.length >>> 0;","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;","for (var i = 0; i < len; i++) {","if (i in t && fun.call(thisArg, t[i], i, t)) {","return true;","}","}","return false;","}","});","(function() {","var sort_ = Array.prototype.sort;","Array.prototype.sort = function(opt_comp) {","if (typeof opt_comp !== 'function') {", +"return sort_.call(this);","}","for (var i = 0; i < this.length; i++) {","var changes = 0;","for (var j = 0; j < this.length - i - 1; j++) {","if (opt_comp(this[j], this[j + 1]) > 0) {","var swap = this[j];","this[j] = this[j + 1];","this[j + 1] = swap;","changes++;","}","}","if (!changes) break;","}","return this;","};","})();","Object.defineProperty(Array.prototype, 'toLocaleString',","{configurable: true, writable: true, value:","function() {","var out = [];","for (var i = 0; i < this.length; i++) {", +"out[i] = (this[i] === null || this[i] === undefined) ? '' : this[i].toLocaleString();","}","return out.join(',');","}","});","")} +function Eb(a,b){var c=function(e){e=String(e);return vc(a)?(this.data=e,this):e};a.A=a.b(c,!0);a.setProperty(b,"String",a.A);a.setProperty(a.A,"fromCharCode",a.b(String.fromCharCode,!1),A);c="charAt charCodeAt concat indexOf lastIndexOf slice substr substring toLocaleLowerCase toLocaleUpperCase toLowerCase toUpperCase trim".split(" ");for(var d=0;d= 0; i--) {","str = str.substring(0, subs[i][0]) + subs[i][2] + str.substring(subs[i][0] + subs[i][1]);", +"}","} else {","var i = str.indexOf(substr);","if (i !== -1) {","var inject = newSubstr(str.substr(i, substr.length), i, str);","str = str.substring(0, i) + inject + str.substring(i + substr.length);","}","}","return str;","};","})();","")}function Fb(a,b){a.Wa=a.b(function(c){c=!!c;return vc(a)?(this.data=c,this):c},!0);a.setProperty(b,"Boolean",a.Wa)} +function Gb(a,b){var c=function(e){e=Number(e);return vc(a)?(this.data=e,this):e};a.T=a.b(c,!0);a.setProperty(b,"Number",a.T);c=["MAX_VALUE","MIN_VALUE","NaN","NEGATIVE_INFINITY","POSITIVE_INFINITY"];for(var d=0;d>>0;return b===Number(a)?b:NaN}function Tc(a){var b=a>>>0;return String(b)===String(a)&&4294967295!==b?b:NaN}function Oa(a){this.O=Object.create(null);this.R=Object.create(null);this.a=Object.create(null);this.oa=a}p=Oa.prototype;p.oa=null;p.o=!0;p.K="Object";p.data=null; +p.toString=function(){if("Array"===this.K){var a=Ja;a.push(this);try{for(var b=[],c=0;cb.charCodeAt(0)&&T(this,a,this.A)){var c=Tc(b);if(!isNaN(c)&&c>=":d>>=e;break;case ">>>=":d>>>=e;break;case "&=":d&=e;break;case "^=":d^=e;break;case "|=":d|=e;break;default:throw SyntaxError("Unknown assignment expression: "+c.operator);}if(c=Zc(this,b.ua,d))return b.ka=!0,b.Ua=d,bd(this,c,b.ua,d);a.pop();a[a.length-1].value=d}}; +u.prototype.stepBinaryExpression=function(a,b,c){if(!b.Y)return b.Y=!0,new y(c.left,b.scope);if(!b.sa)return b.sa=!0,b.$=b.value,new y(c.right,b.scope);a.pop();var d=b.$;b=b.value;switch(c.operator){case "==":c=d==b;break;case "!=":c=d!=b;break;case "===":c=d===b;break;case "!==":c=d!==b;break;case ">":c=d>b;break;case ">=":c=d>=b;break;case "<":c=d>":c=d>>b;break;case ">>>":c=d>>>b;break;case "in":b&&b.o||J(this,this.h,"'in' expects an object, not '"+b+"'");c=xc(this,b,d);break;case "instanceof":T(this,b,this.C)||J(this,this.h,"Right-hand side of instanceof is not an object");c=d.o?T(this,d,b):!1;break;default:throw SyntaxError("Unknown binary operator: "+c.operator);}a[a.length-1].value=c}; +u.prototype.stepBlockStatement=function(a,b,c){var d=b.s||0;if(c=c.body[d])return b.s=d+1,new y(c,b.scope);a.pop()};u.prototype.stepBreakStatement=function(a,b,c){$c(this,1,void 0,c.label&&c.label.name)}; +u.prototype.stepCallExpression=function(a,b,c){if(!b.ja){b.ja=1;var d=new y(c.callee,b.scope);d.ia=!0;return d}if(1===b.ja){b.ja=2;d=b.value;if(Array.isArray(d)){if(b.Z=Yc(this,d),d[0]===Ba?b.wb="eval"===d[1]:b.J=d[0],(d=b.Z)&&"object"===typeof d&&d.L)return d.L=!1,b.ja=1,ad(this,d,b.value)}else b.Z=d;b.B=[];b.s=0}d=b.Z;if(!b.Oa){0!==b.s&&b.B.push(b.value);if(c.arguments[b.s])return new y(c.arguments[b.s++],b.scope);if("NewExpression"===c.type){d.Fb&&J(this,this.h,d+" is not a constructor");var e= +d.a.prototype;if("object"!==typeof e||null===e)e=this.G;b.J=this.g(e);b.isConstructor=!0}else void 0===b.J&&(b.J=b.scope.H?void 0:this.global);b.Oa=!0}if(b.Pa)a.pop(),a[a.length-1].value=b.isConstructor&&"object"!==typeof b.value?b.J:b.value;else{b.Pa=!0;d&&d.o||J(this,this.h,d+" is not a function");if(a=d.node){c=ia(this,a.body,d.ca);for(var g=0;gg?b.B[g]:void 0);e=this.g(this.ea);for(g=0;g Date: Wed, 6 Nov 2019 11:47:33 -0800 Subject: [PATCH 159/343] Update geras and add underscore to setClass_ --- core/renderers/common/path_object.js | 12 ++++++------ core/renderers/geras/path_object.js | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 8d276cea7..8e82b2be2 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -129,7 +129,7 @@ Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) { * be removed. * @protected */ -Blockly.blockRendering.PathObject.prototype.setClass = function( +Blockly.blockRendering.PathObject.prototype.setClass_ = function( className, add) { if (add) { Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgRoot), @@ -165,7 +165,7 @@ Blockly.blockRendering.PathObject.prototype.updateHighlighted = function( Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled, isShadow) { - this.setClass('blocklyDisabled', disabled); + this.setClass_('blocklyDisabled', disabled); if (disabled) { this.svgPath.setAttribute('fill', 'url(#' + this.constants_.disabledPatternId + ')'); @@ -180,7 +180,7 @@ Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled, * @package */ Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { - this.setClass('blocklySelected', enable); + this.setClass_('blocklySelected', enable); }; /** @@ -191,7 +191,7 @@ Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { */ Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function( enable) { - this.setClass('blocklyDraggingDelete', enable); + this.setClass_('blocklyDraggingDelete', enable); }; /** @@ -202,7 +202,7 @@ Blockly.blockRendering.PathObject.prototype.updateDraggingDelete = function( */ Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function( enable) { - this.setClass('blocklyInsertionMarker', enable); + this.setClass_('blocklyInsertionMarker', enable); }; /** @@ -211,5 +211,5 @@ Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function( * @package */ Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) { - this.setClass('blocklyDraggable', enable); + this.setClass_('blocklyDraggable', enable); }; diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index f09bdb6aa..5572de4ac 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -153,7 +153,7 @@ Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) { /** * @override */ -Blockly.geras.PathObject.prototype.setHighlighted = function(highlighted) { +Blockly.geras.PathObject.prototype.updateHighlighted = function(highlighted) { if (highlighted) { this.svgPath.setAttribute('filter', 'url(#' + this.constants_.embossFilterId + ')'); @@ -167,7 +167,8 @@ Blockly.geras.PathObject.prototype.setHighlighted = function(highlighted) { /** * @override */ -Blockly.geras.PathObject.prototype.setDisabled = function(disabled, isShadow) { +Blockly.geras.PathObject.prototype.updateDisabled = function( + disabled, isShadow) { if (disabled) { this.svgPath.setAttribute('fill', 'url(#' + this.constants_.disabledPatternId + ')'); From d49b3400e616b2ea9da7ddbcfae8c2cddc08664f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 6 Nov 2019 13:47:30 -0800 Subject: [PATCH 160/343] Add zelos selection highlight. (#3390) * zelos selection highlight --- blockly_uncompressed.js | 4 +- core/css.js | 5 -- core/renderers/common/path_object.js | 7 +++ core/renderers/zelos/constants.js | 84 ++++++++++++++++++++++++++++ core/renderers/zelos/path_object.js | 38 +++++++++++++ 5 files changed, 131 insertions(+), 7 deletions(-) diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index dc06f2b86..f0a828915 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -116,11 +116,11 @@ goog.addDependency("../../core/renderers/minimalist/info.js", ['Blockly.minimali goog.addDependency("../../core/renderers/minimalist/renderer.js", ['Blockly.minimalist.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.minimalist.ConstantProvider', 'Blockly.minimalist.Drawer', 'Blockly.minimalist.RenderInfo']); goog.addDependency("../../core/renderers/thrasos/info.js", ['Blockly.thrasos', 'Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/thrasos/renderer.js", ['Blockly.thrasos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.thrasos.RenderInfo', 'Blockly.utils.object']); -goog.addDependency("../../core/renderers/zelos/constants.js", ['Blockly.zelos.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object', 'Blockly.utils.svgPaths']); +goog.addDependency("../../core/renderers/zelos/constants.js", ['Blockly.zelos.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/zelos/drawer.js", ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow', 'Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow']); goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.utils.object']); -goog.addDependency("../../core/renderers/zelos/path_object.js", ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.zelos.ConstantProvider', 'Blockly.utils.object']); +goog.addDependency("../../core/renderers/zelos/path_object.js", ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.zelos.ConstantProvider', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); diff --git a/core/css.js b/core/css.js index a59640bae..761ac9e39 100644 --- a/core/css.js +++ b/core/css.js @@ -254,11 +254,6 @@ Blockly.Css.CONTENT = [ 'stroke-width: 1;', '}', - '.blocklySelected>.blocklyPath {', - 'stroke: #fc3;', - 'stroke-width: 3px;', - '}', - '.blocklySelected>.blocklyPathLight {', 'display: none;', '}', diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 8e82b2be2..1671f3777 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -181,6 +181,13 @@ Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled, */ Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { this.setClass_('blocklySelected', enable); + if (enable) { + this.svgPath.setAttribute('stroke', '#fc3'); + this.svgPath.setAttribute('stroke-width', '3px'); + } else { + this.svgPath.setAttribute('stroke', ''); + this.svgPath.setAttribute('stroke-width', ''); + } }; /** diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 8e17d9d69..f12ea22f2 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -25,6 +25,7 @@ goog.provide('Blockly.zelos.ConstantProvider'); goog.require('Blockly.blockRendering.ConstantProvider'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.object'); goog.require('Blockly.utils.svgPaths'); @@ -79,6 +80,21 @@ Blockly.zelos.ConstantProvider = function() { * @override */ this.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT = this.LARGE_PADDING * 2; + + /** + * The ID of the highlight glow filter, or the empty string if no filter is + * set. + * @type {string} + * @package + */ + this.highlightGlowFilterId = ''; + + /** + * The element to use for a higlight glow, or null if not set. + * @type {SVGElement} + * @private + */ + this.highlightGlowFilter_ = null; }; Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider, Blockly.blockRendering.ConstantProvider); @@ -92,6 +108,16 @@ Blockly.zelos.ConstantProvider.prototype.init = function() { this.ROUNDED = this.makeRounded(); }; +/** + * @override + */ +Blockly.zelos.ConstantProvider.prototype.dispose = function() { + Blockly.zelos.ConstantProvider.superClass_.dispose.call(this); + if (this.highlightGlowFilter_) { + Blockly.utils.dom.removeNode(this.highlightGlowFilter_); + } +}; + /** * @return {!Object} An object containing sizing and path information about * a hexagonal shape for connections. @@ -298,3 +324,61 @@ Blockly.zelos.ConstantProvider.prototype.makeInsideCorners = function() { pathBottomRight: innerBottomRightCorner }; }; + +/** + * @override + */ +Blockly.zelos.ConstantProvider.prototype.createDom = function(svg) { + Blockly.zelos.ConstantProvider.superClass_.createDom.call(this, svg); + /* + + ... filters go here ... + + */ + var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg); + // Each filter/pattern needs a unique ID for the case of multiple Blockly + // instances on a page. Browser behaviour becomes undefined otherwise. + // https://neil.fraser.name/news/2015/11/01/ + var rnd = String(Math.random()).substring(2); + // Using a dilate distorts the block shape. + // Instead use a gaussian blur, and then set all alpha to 1 with a transfer. + var highlightGlowFilter = Blockly.utils.dom.createSvgElement('filter', + { + 'id': 'blocklyHighlightGlowFilter' + rnd, + 'height': '160%', + 'width': '180%', + y: '-30%', + x: '-40%' + }, + defs); + Blockly.utils.dom.createSvgElement('feGaussianBlur', + { + 'in': 'SourceGraphic', + 'stdDeviation': 0.5 // TODO: configure size in theme. + }, + highlightGlowFilter); + // Set all gaussian blur pixels to 1 opacity before applying flood + var componentTransfer = Blockly.utils.dom.createSvgElement( + 'feComponentTransfer', {'result': 'outBlur'}, highlightGlowFilter); + Blockly.utils.dom.createSvgElement('feFuncA', + { + 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' + }, + componentTransfer); + // Color the highlight + Blockly.utils.dom.createSvgElement('feFlood', + { + 'flood-color': '#FFF200', // TODO: configure colour in theme. + 'flood-opacity': 1, + 'result': 'outColor' + }, + highlightGlowFilter); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'outColor', 'in2': 'outBlur', + 'operator': 'in', 'result': 'outGlow' + }, + highlightGlowFilter); + this.highlightGlowFilterId = highlightGlowFilter.id; + this.highlightGlowFilter_ = highlightGlowFilter; +}; diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js index 8a1383ac6..b0b3b2629 100644 --- a/core/renderers/zelos/path_object.js +++ b/core/renderers/zelos/path_object.js @@ -26,6 +26,7 @@ goog.provide('Blockly.zelos.PathObject'); goog.require('Blockly.blockRendering.PathObject'); goog.require('Blockly.zelos.ConstantProvider'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.object'); @@ -46,6 +47,43 @@ Blockly.zelos.PathObject = function(root, constants) { * @type {!Blockly.zelos.ConstantProvider} */ this.constants_ = constants; + + /** + * The selected path of the block. + * @type {SVGElement} + * @private + */ + this.svgPathSelected_ = null; }; Blockly.utils.object.inherits(Blockly.zelos.PathObject, Blockly.blockRendering.PathObject); + +/** + * @override + */ +Blockly.zelos.PathObject.prototype.setPath = function(pathString) { + Blockly.zelos.PathObject.superClass_.setPath.call(this, pathString); + if (this.svgPathSelected_) { + this.svgPathSelected_.setAttribute('d', pathString); + } +}; + +/** + * @override + */ +Blockly.zelos.PathObject.prototype.updateSelected = function(enable) { + this.setClass_('blocklySelected', enable); + if (enable) { + this.svgPathSelected_ = + /** @type {!SVGElement} */ (this.svgPath.cloneNode(true)); + this.svgPathSelected_.setAttribute('fill', 'none'); + this.svgPathSelected_.setAttribute('filter', + 'url(#' + this.constants_.highlightGlowFilterId + ')'); + this.svgRoot.appendChild(this.svgPathSelected_); + } else { + if (this.svgPathSelected_) { + this.svgRoot.removeChild(this.svgPathSelected_); + this.svgPathSelected_ = null; + } + } +}; From 04ddb90680729d5d0a41d615bb45958987cc6aeb Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 6 Nov 2019 14:02:13 -0800 Subject: [PATCH 161/343] Delete two leftover constants in block_svg. --- core/block_svg.js | 34 ++++++---------------------------- core/xml.js | 11 +++-------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index bb8113813..98ea1c63e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -170,13 +170,6 @@ Blockly.BlockSvg.INLINE = -1; Blockly.BlockSvg.COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_'; // Leftover UI constants from block_render_svg.js. -/** - * Vertical space between elements. - * @const - * @package - */ -// TODO (#3142): Remove. -Blockly.BlockSvg.SEP_SPACE_Y = 10; /** * Minimum height of a block. @@ -186,13 +179,6 @@ Blockly.BlockSvg.SEP_SPACE_Y = 10; // TODO (#3142): Remove. Blockly.BlockSvg.MIN_BLOCK_Y = 25; -/** - * Width of horizontal puzzle tab. - * @package - */ -// TODO (#3142): Remove. -Blockly.BlockSvg.TAB_WIDTH = 8; - /** * Do blocks with no previous or output connections have a 'hat' on top? * @const @@ -579,25 +565,17 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { */ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { var blockXY = this.getRelativeToSurfaceXY(); - var tab = this.outputConnection ? Blockly.BlockSvg.TAB_WIDTH : 0; var blockBounds = this.getHeightWidth(); - var top = blockXY.y; - var bottom = blockXY.y + blockBounds.height; var left, right; if (this.RTL) { - // Width has the tab built into it already so subtract it here. - left = blockXY.x - (blockBounds.width - tab); - // Add the width of the tab/puzzle piece knob to the x coordinate - // since X is the corner of the rectangle, not the whole puzzle piece. - right = blockXY.x + tab; + left = blockXY.x - blockBounds.width; + right = blockXY.x; } else { - // Subtract the width of the tab/puzzle piece knob to the x coordinate - // since X is the corner of the rectangle, not the whole puzzle piece. - left = blockXY.x - tab; - // Width has the tab built into it already so subtract it here. - right = blockXY.x + blockBounds.width - tab; + left = blockXY.x; + right = blockXY.x + blockBounds.width; } - return new Blockly.utils.Rect(top, bottom, left, right); + return new Blockly.utils.Rect( + blockXY.y, blockXY.y + blockBounds.height, left, right); }; /** diff --git a/core/xml.js b/core/xml.js index 9d0092c10..21d6996c7 100644 --- a/core/xml.js +++ b/core/xml.js @@ -476,13 +476,7 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { // First check if we have a workspaceSvg, otherwise the blocks have no shape // and the position does not matter. if (workspace.hasOwnProperty('scale')) { - var savetab = Blockly.BlockSvg.TAB_WIDTH; - try { - Blockly.BlockSvg.TAB_WIDTH = 0; - bbox = workspace.getBlocksBoundingBox(); - } finally { - Blockly.BlockSvg.TAB_WIDTH = savetab; - } + 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); @@ -494,6 +488,7 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { // Check position of the new blocks. var newX = Infinity; // x of top corner var newY = Infinity; // y of top corner + var ySeparation = 10; for (var i = 0; i < newBlockIds.length; i++) { var blockXY = workspace.getBlockById(newBlockIds[i]).getRelativeToSurfaceXY(); @@ -504,7 +499,7 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { newX = blockXY.x; } } - offsetY = farY - newY + Blockly.BlockSvg.SEP_SPACE_Y; + offsetY = farY - newY + ySeparation; offsetX = topX - newX; // move the new blocks to append them at the bottom var width; // Not used in LTR. From 729997496b9f34fd902d5351ab04ec9ae90aefc4 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 7 Nov 2019 16:05:06 +0100 Subject: [PATCH 162/343] Localisation updates from https://translatewiki.net. --- msg/json/el.json | 1 + 1 file changed, 1 insertion(+) diff --git a/msg/json/el.json b/msg/json/el.json index c71b9c519..7839e7e2b 100644 --- a/msg/json/el.json +++ b/msg/json/el.json @@ -21,6 +21,7 @@ ] }, "VARIABLES_DEFAULT_NAME": "αντικείμενο", + "UNNAMED_KEY": "χωρίς όνομα", "TODAY": "Σήμερα", "DUPLICATE_BLOCK": "Διπλότυπο", "ADD_COMMENT": "Πρόσθεσε Το Σχόλιο", From ee09aafd571a6bdf63cdba2306d092e86329e189 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 7 Nov 2019 15:15:49 -0800 Subject: [PATCH 163/343] [zelos] Add input outlines on the path object. (#3410) * Add input outlines on the path object. --- core/field.js | 9 ++- core/field_dropdown.js | 6 +- core/renderers/common/path_object.js | 1 + core/renderers/geras/drawer.js | 3 +- core/renderers/measurables/inputs.js | 61 ++++++------------- core/renderers/zelos/constants.js | 12 +++- core/renderers/zelos/drawer.js | 44 +++++++++++++- core/renderers/zelos/info.js | 14 +---- core/renderers/zelos/path_object.js | 91 ++++++++++++++++++++++++++++ core/utils/dom.js | 6 +- tests/rendering/zelos/zelos.html | 7 ++- 11 files changed, 189 insertions(+), 65 deletions(-) diff --git a/core/field.js b/core/field.js index 0b13b7bdb..6a8e21f5b 100644 --- a/core/field.js +++ b/core/field.js @@ -263,6 +263,12 @@ Blockly.Field.prototype.SERIALIZABLE = false; */ Blockly.Field.FONTSIZE = 11; +/** + * Text font weight. Should match blocklyText's font-weight in CSS. + * @const {string} + */ +Blockly.Field.FONTWEIGHT = 'normal'; + /** * Text font family. Should match blocklyText's font-family in CSS. * @const {string} @@ -655,7 +661,8 @@ Blockly.Field.prototype.updateWidth = function() { Blockly.Field.prototype.updateSize_ = function() { var textWidth = Blockly.utils.dom.getFastTextWidth( /** @type {!SVGTextElement} */ (this.textElement_), - Blockly.Field.FONTSIZE, Blockly.Field.FONTFAMILY); + Blockly.Field.FONTSIZE, Blockly.Field.FONTWEIGHT, + Blockly.Field.FONTFAMILY); var totalWidth = textWidth; if (this.borderRect_) { totalWidth += Blockly.Field.X_PADDING; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 379516720..4a3f9c11d 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -516,7 +516,8 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { var arrowWidth = Blockly.utils.dom.getFastTextWidth( /** @type {!SVGTSpanElement} */ (this.arrow_), - Blockly.Field.FONTSIZE, Blockly.Field.FONTFAMILY); + Blockly.Field.FONTSIZE, Blockly.Field.FONTWEIGHT, + Blockly.Field.FONTFAMILY); var imageHeight = Number(imageJson.height); var imageWidth = Number(imageJson.width); @@ -551,7 +552,8 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { // Height and width include the border rect. this.size_.height = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT; this.size_.width = Blockly.utils.dom.getFastTextWidth(this.textElement_, - Blockly.Field.FONTSIZE, Blockly.Field.FONTFAMILY) + + Blockly.Field.FONTSIZE, Blockly.Field.FONTWEIGHT, + Blockly.Field.FONTFAMILY) + Blockly.Field.X_PADDING; }; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 1671f3777..f7ba75373 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -220,3 +220,4 @@ Blockly.blockRendering.PathObject.prototype.updateInsertionMarker = function( Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) { this.setClass_('blocklyDraggable', enable); }; + diff --git a/core/renderers/geras/drawer.js b/core/renderers/geras/drawer.js index 4affa11e3..311bd163f 100644 --- a/core/renderers/geras/drawer.js +++ b/core/renderers/geras/drawer.js @@ -26,11 +26,12 @@ goog.provide('Blockly.geras.Drawer'); goog.require('Blockly.blockRendering.ConstantProvider'); goog.require('Blockly.blockRendering.Drawer'); goog.require('Blockly.geras.Highlighter'); -goog.require('Blockly.geras.PathObject'); goog.require('Blockly.geras.RenderInfo'); goog.require('Blockly.utils.object'); goog.require('Blockly.utils.svgPaths'); +goog.requireType('Blockly.geras.PathObject'); + /** * An object that draws a block based on the given rendering information. diff --git a/core/renderers/measurables/inputs.js b/core/renderers/measurables/inputs.js index ccccb8343..a7a80068d 100644 --- a/core/renderers/measurables/inputs.js +++ b/core/renderers/measurables/inputs.js @@ -87,36 +87,26 @@ Blockly.blockRendering.InlineInput = function(constants, input) { constants, input); this.type |= Blockly.blockRendering.Types.INLINE_INPUT; - this.setShapeDimensions( - !this.isDynamicShape ? this.shape.height : 0, - !this.isDynamicShape ? this.shape.width : 0); - - this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.InlineInput, - Blockly.blockRendering.InputConnection); - - -/** - * Sets properties that depend on the connection shape dimensions. - * @param {number} height Height of the connection shape. - * @param {number} width Width of the connection shape. - */ -Blockly.blockRendering.InlineInput.prototype.setShapeDimensions = function( - height, width) { if (!this.connectedBlock) { this.height = this.constants_.EMPTY_INLINE_INPUT_HEIGHT; - this.width = width + - this.constants_.EMPTY_INLINE_INPUT_PADDING; + 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 = height; - this.connectionWidth = width; + + this.connectionHeight = this.shape.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.constants_.TAB_OFFSET_FROM_TOP; }; +Blockly.utils.object.inherits(Blockly.blockRendering.InlineInput, + Blockly.blockRendering.InputConnection); /** * An object containing information about the space a statement input takes up @@ -162,34 +152,19 @@ Blockly.blockRendering.ExternalValueInput = function(constants, input) { Blockly.blockRendering.ExternalValueInput.superClass_.constructor.call(this, constants, input); this.type |= Blockly.blockRendering.Types.EXTERNAL_VALUE_INPUT; - - this.setShapeDimensions( - !this.isDynamicShape ? this.shape.height : 0, - !this.isDynamicShape ? this.shape.width : 0); - - this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP; -}; -Blockly.utils.object.inherits(Blockly.blockRendering.ExternalValueInput, - Blockly.blockRendering.InputConnection); - - -/** - * Sets properties that depend on the connection shape dimensions. - * @param {number} height Height of the connection shape. - * @param {number} width Width of the connection shape. - */ -Blockly.blockRendering.ExternalValueInput.prototype.setShapeDimensions = function( - height, width) { if (!this.connectedBlock) { - this.height = height; + this.height = this.shape.height; } else { this.height = this.connectedBlockHeight - this.constants_.TAB_OFFSET_FROM_TOP - this.constants_.MEDIUM_PADDING; } - this.width = width + + this.width = this.shape.width + this.constants_.EXTERNAL_VALUE_INPUT_PADDING; - this.connectionHeight = height; - this.connectionWidth = width; + 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/zelos/constants.js b/core/renderers/zelos/constants.js index f12ea22f2..a75255ff4 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -81,6 +81,16 @@ Blockly.zelos.ConstantProvider = function() { */ this.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT = this.LARGE_PADDING * 2; + /** + * @override + */ + this.EMPTY_INLINE_INPUT_PADDING = 4 * this.GRID_UNIT; + + /** + * @override + */ + this.EMPTY_INLINE_INPUT_HEIGHT = 8 * this.GRID_UNIT; + /** * The ID of the highlight glow filter, or the empty string if no filter is * set. @@ -216,7 +226,7 @@ Blockly.zelos.ConstantProvider.prototype.shapeFor = function( if (checks && checks.indexOf('String') != -1) { return this.ROUNDED; } - return this.PUZZLE_TAB; + return this.ROUNDED; case Blockly.PREVIOUS_STATEMENT: case Blockly.NEXT_STATEMENT: return this.NOTCH; diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index 193665a72..f13df6272 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -29,6 +29,8 @@ goog.require('Blockly.blockRendering.Types'); goog.require('Blockly.utils.object'); goog.require('Blockly.zelos.RenderInfo'); +goog.requireType('Blockly.zelos.PathObject'); + /** * An object that draws a block based on the given rendering information. @@ -46,6 +48,28 @@ Blockly.utils.object.inherits(Blockly.zelos.Drawer, Blockly.blockRendering.Drawer); +/** + * @override + */ +Blockly.zelos.Drawer.prototype.draw = function() { + var pathObject = + /** @type {!Blockly.zelos.PathObject} */ (this.block_.pathObject); + pathObject.beginDrawing(); + this.hideHiddenIcons_(); + this.drawOutline_(); + this.drawInternals_(); + + pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_); + if (this.info_.RTL) { + pathObject.flipRTL(); + } + if (Blockly.blockRendering.useDebugger) { + this.block_.renderingDebugger.drawDebug(this.block_, this.info_); + } + this.recordSizeOnBlock_(); + pathObject.endDrawing(); +}; + /** * @override */ @@ -143,8 +167,26 @@ Blockly.zelos.Drawer.prototype.drawFlatBottom_ = function() { * @override */ Blockly.zelos.Drawer.prototype.drawInlineInput_ = function(input) { - // Don't draw an inline input. this.positionInlineInputConnection_(input); + + var inputName = input.input.name; + if (input.connectedBlock || this.info_.isInsertionMarker) { + return; + } + + var width = input.width - (input.connectionWidth * 2); + var height = input.height; + var yPos = input.centerline - height / 2; + + var connectionRight = input.xPos + input.connectionWidth; + + var outlinePath = Blockly.utils.svgPaths.moveTo(connectionRight, yPos) + + Blockly.utils.svgPaths.lineOnAxis('h', width) + + input.shape.pathRightDown(input.height) + + Blockly.utils.svgPaths.lineOnAxis('h', -width) + + input.shape.pathUp(input.height) + + 'z'; + this.block_.pathObject.setOutlinePath(inputName, outlinePath); }; /** diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index b8a2dfd90..e272bea3e 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -182,9 +182,9 @@ Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { // Between an editable field and an input. if (prev.isEditable) { if (Blockly.blockRendering.Types.isInlineInput(next)) { - return this.constants_.SMALL_PADDING; + return this.constants_.MEDIUM_PADDING; } else if (Blockly.blockRendering.Types.isExternalInput(next)) { - return this.constants_.SMALL_PADDING; + return this.constants_.MEDIUM_PADDING; } } else { if (Blockly.blockRendering.Types.isInlineInput(next)) { @@ -346,16 +346,6 @@ Blockly.zelos.RenderInfo.prototype.finalize_ = function() { for (var i = 0, row; (row = this.rows[i]); i++) { row.xPos = this.startX; - for (var j = 0, elem; (elem = row.elements[j]); j++) { - if (Blockly.blockRendering.Types.isInlineInput(elem) || - Blockly.blockRendering.Types.isExternalInput(elem)) { - if (elem.isDynamicShape) { - elem.setShapeDimensions(elem.shape.height(elem.height), - elem.shape.width(elem.height)); - } - } - } - widestRowWithConnectedBlocks = Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); this.recordElemPositions_(row); diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js index b0b3b2629..b2f7ba3c6 100644 --- a/core/renderers/zelos/path_object.js +++ b/core/renderers/zelos/path_object.js @@ -54,6 +54,23 @@ Blockly.zelos.PathObject = function(root, constants) { * @private */ this.svgPathSelected_ = null; + + /** + * The outline paths on the block. + * @type {!Object.} + * @private + */ + this.outlines_ = {}; + + /** + * A set used to determine which outlines were used during a draw pass. The + * set is initialized with a reference to all the outlines in + * `this.outlines_`. Everytime we use an outline during the draw pass, the + * reference is removed from this set. + * @type {Object.} + * @private + */ + this.remainingOutlines_ = null; }; Blockly.utils.object.inherits(Blockly.zelos.PathObject, Blockly.blockRendering.PathObject); @@ -87,3 +104,77 @@ Blockly.zelos.PathObject.prototype.updateSelected = function(enable) { } } }; + +/** + * Method that's called when the drawer is about to draw the block. + * @package + */ +Blockly.zelos.PathObject.prototype.beginDrawing = function() { + this.remainingOutlines_ = {}; + for (var i = 0, keys = Object.keys(this.outlines_), + key; (key = keys[i]); i++) { + // The value set here isn't used anywhere, we are just using the + // object as a Set data structure. + this.remainingOutlines_[key] = 1; + } +}; + +/** + * Method that's called when the drawer is done drawing. + * @package + */ +Blockly.zelos.PathObject.prototype.endDrawing = function() { + // Go through all remaining outlines that were not used this draw pass, and + // remove them. + if (this.remainingOutlines_) { + for (var i = 0, keys = Object.keys(this.remainingOutlines_), + key; (key = keys[i]); i++) { + this.removeOutlinePath_(key); + } + } + this.remainingOutlines_ = null; +}; + +/** + * Set the path generated by the renderer for an outline path on the respective + * outline path SVG element. + * @param {string} name The input name. + * @param {string} pathString The path. + * @package + */ +Blockly.zelos.PathObject.prototype.setOutlinePath = function(name, pathString) { + var outline = this.getOutlinePath_(name); + outline.setAttribute('d', pathString); + outline.setAttribute('fill', this.style.colourTertiary); +}; + +/** + * Create's an outline path for the specified input. + * @param {string} name The input name. + * @return {!SVGElement} The SVG outline path. + * @private + */ +Blockly.zelos.PathObject.prototype.getOutlinePath_ = function(name) { + if (!this.outlines_[name]) { + this.outlines_[name] = Blockly.utils.dom.createSvgElement('path', { + 'class': 'blocklyOutlinePath', + // IE doesn't like paths without the data definition, set empty default + 'd': '' + }, + this.svgRoot); + } + if (this.remainingOutlines_) { + delete this.remainingOutlines_[name]; + } + return this.outlines_[name]; +}; + +/** + * Remove an outline path that is associated with the specified input. + * @param {string} name The input name. + * @private + */ +Blockly.zelos.PathObject.prototype.removeOutlinePath_ = function(name) { + this.outlines_[name].parentNode.removeChild(this.outlines_[name]); + delete this.outlines_[name]; +}; diff --git a/core/utils/dom.js b/core/utils/dom.js index a659cfe08..c2337e595 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -285,11 +285,12 @@ Blockly.utils.dom.getTextWidth = function(textElement) { * advance. Similar to `getTextWidth`, we cache the width we compute. * @param {!Element} textElement An SVG 'text' element. * @param {number} fontSize The font size to use. + * @param {string} fontWeight The font weight to use. * @param {string} fontFamily The font family to use. * @return {number} Width of element. */ Blockly.utils.dom.getFastTextWidth = function(textElement, - fontSize, fontFamily) { + fontSize, fontWeight, fontFamily) { var text = textElement.textContent; var key = text + '\n' + textElement.className.baseVal; var width; @@ -314,7 +315,8 @@ Blockly.utils.dom.getFastTextWidth = function(textElement, Blockly.utils.dom.canvasContext_ = computeCanvas.getContext('2d'); } // Set the desired font size and family. - Blockly.utils.dom.canvasContext_.font = fontSize + 'pt ' + fontFamily; + Blockly.utils.dom.canvasContext_.font = + fontWeight + ' ' + fontSize + 'pt ' + fontFamily; // Measure the text width using the helper canvas context. width = Blockly.utils.dom.canvasContext_.measureText(text).width; diff --git a/tests/rendering/zelos/zelos.html b/tests/rendering/zelos/zelos.html index a01d04dcc..edac39fbb 100644 --- a/tests/rendering/zelos/zelos.html +++ b/tests/rendering/zelos/zelos.html @@ -7,7 +7,7 @@ @@ -145,6 +149,18 @@ +
+
+
+

Zelos Rendering

+ +
+
+

PXT-Blockly Rendering

+ +
+
+
- + \ No newline at end of file diff --git a/tests/rendering/zelos/pxtblockly.html b/tests/rendering/zelos/pxtblockly.html index 8e454c255..77a282ac4 100644 --- a/tests/rendering/zelos/pxtblockly.html +++ b/tests/rendering/zelos/pxtblockly.html @@ -4,6 +4,7 @@ + @@ -12,7 +13,11 @@ var blocklyDiv = document.getElementById('blocklyDiv'); var workspace; window.addEventListener('message', function (msg) { - var xml = msg.data; + var data = msg.data; + if (data.type !== 'post') { + return; + } + var xml = data.xml; try { if (workspace) { workspace.dispose(); @@ -26,13 +31,25 @@ drag: true, wheel: false, }, + zoom: { + wheel: true, + startScale: 2, + } }); try { Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), workspace); + var topBlock = workspace.getTopBlocks()[0]; + workspaceToSvg_(workspace, function (datauri) { + window.parent.postMessage({ + type: 'svg', + from: 'pxtblockly', + text: datauri + }, '*'); + }); } catch { } }); - + \ No newline at end of file diff --git a/tests/rendering/zelos/zelos.html b/tests/rendering/zelos/zelos.html index edac39fbb..d1fd73706 100644 --- a/tests/rendering/zelos/zelos.html +++ b/tests/rendering/zelos/zelos.html @@ -4,13 +4,26 @@ + - @@ -26,7 +39,11 @@ var blocklyDiv = document.getElementById('blocklyDiv'); var workspace; window.addEventListener('message', function (msg) { - var xml = msg.data; + var data = msg.data; + if (data.type !== 'post') { + return; + } + var xml = data.xml; try { if (workspace) { workspace.dispose(); @@ -41,11 +58,25 @@ drag: true, wheel: false, }, + zoom: { + wheel: true, + startScale: 2, + } }); try { Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), workspace); - } catch { } + var topBlock = workspace.getTopBlocks()[0]; + workspaceToSvg_(workspace, function (datauri) { + window.parent.postMessage({ + type: 'svg', + from: 'zelos', + text: datauri + }, '*'); + }, document.getElementById('blocklycss').innerText); + } catch (err) { + console.error(err); + } }); From 5f4a308a404c29f9b4c1300923646a6fe2371ec8 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 11 Nov 2019 14:32:31 -0800 Subject: [PATCH 172/343] Full-block editors for single-field reporters. --- core/field.js | 2 +- core/field_textinput.js | 84 ++++++++++++++++++++++++++++++ core/renderers/common/constants.js | 7 +++ core/renderers/zelos/constants.js | 5 ++ tests/blocks/test_blocks.js | 16 ++++++ tests/playground.html | 1 + 6 files changed, 114 insertions(+), 1 deletion(-) diff --git a/core/field.js b/core/field.js index 6a8e21f5b..ae622802e 100644 --- a/core/field.js +++ b/core/field.js @@ -962,7 +962,7 @@ Blockly.Field.prototype.getClickTarget_ = function() { */ Blockly.Field.prototype.getAbsoluteXY_ = function() { return Blockly.utils.style.getPageOffset( - /** @type {!SVGRectElement} */ (this.borderRect_)); + /** @type {!SVGRectElement} */ (this.getClickTarget_())); }; /** diff --git a/core/field_textinput.js b/core/field_textinput.js index 631923a71..28976de79 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -84,6 +84,13 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { * @private */ this.onKeyInputWrapper_ = null; + + /** + * Whether the field should consider the whole parent block to be its click + * target. + * @type {boolean} + */ + this.fullBlockClickTarget_ = false; }; Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field); @@ -128,6 +135,50 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) { } }; +/** + * Create the block UI for this field. + * @package + */ +Blockly.FieldTextInput.prototype.initView = function() { + var renderer = this.sourceBlock_.workspace.getRenderer(); + if (renderer.getConstants().FULL_BLOCK_FIELDS) { + // Step one: figure out if this is the only field on this block. + // Rendering is quite different in that case. + var nFields = 0; + var nConnections = 0; + + // Count the number of fields, excluding text fields + for (var i = 0, input; (input = this.sourceBlock_.inputList[i]); i++) { + for (var j = 0, field; (field = input.fieldRow[j]); j++) { + if (!(field instanceof Blockly.FieldLabel)) { + nFields ++; + } + } + if (input.connection) { + nConnections++; + } + } + // The special case is when this is the only non-label field on the block + // and it has an output but no inputs. + this.fullBlockClickTarget_ = + nFields <= 1 && this.sourceBlock_.outputConnection && !nConnections; + } else { + this.fullBlockClickTarget_ = false; + } + + if (this.fullBlockClickTarget_) { + // Don't create a border rect. + this.size_.height = + Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT); + this.size_.width = + Math.max(this.size_.width, Blockly.Field.X_PADDING); + this.clickTarget_ = this.sourceBlock_.getSvgRoot(); + } else { + this.createBorderRect_(); + } + this.createTextElement_(); +}; + /** * Ensure that the input value casts to a valid string. * @param {*=} opt_newValue The input value. @@ -297,6 +348,16 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_); htmlInput.untypedDefaultValue_ = this.value_; htmlInput.oldValue_ = null; + + if (this.fullBlockClickTarget_) { + var bBox = this.getScaledBBox(); + var borderRadius = (bBox.bottom - bBox.top) / 2; + htmlInput.style.borderRadius = borderRadius + 'px'; + // Pull stroke colour from the existing shadow block + var strokeColour = this.sourceBlock_.style.colourTertiary; + div.style.borderColor = strokeColour; + } + if (Blockly.utils.userAgent.GECKO) { // In FF, ensure the browser reflows before resizing to avoid issue #2777. setTimeout(this.resizeEditor_.bind(this), 0); @@ -544,4 +605,27 @@ Blockly.FieldTextInput.prototype.getValueFromEditorText_ = function(text) { return text; }; +/** + * @override + */ +Blockly.FieldTextInput.prototype.getScaledBBox = function() { + if (this.fullBlockClickTarget_) { + var heightWidth = this.sourceBlock_.getHeightWidth(); + } else { + var heightWidth = this.borderRect_.getBBox(); + } + + var scale = this.sourceBlock_.workspace.scale; + var xy = this.getAbsoluteXY_(); + var scaledHeight = heightWidth.height * scale; + var scaledWidth = heightWidth.width * scale; + + return { + top: xy.y, + bottom: xy.y + scaledHeight, + left: xy.x, + right: xy.x + scaledWidth + }; +}; + Blockly.fieldRegistry.register('field_input', Blockly.FieldTextInput); diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 6aa0863f6..250ca4e65 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -163,6 +163,13 @@ Blockly.blockRendering.ConstantProvider = function() { * @private */ this.disabledPattern_ = null; + + /** + * Whether text input and colour fields fill up the entire source block. + * @type {boolean} + * @package + */ + this.FULL_BLOCK_FIELDS = false; }; /** diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index a75255ff4..43270431f 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -105,6 +105,11 @@ Blockly.zelos.ConstantProvider = function() { * @private */ this.highlightGlowFilter_ = null; + + /** + * @override + */ + this.FULL_BLOCK_FIELDS = true; }; Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider, Blockly.blockRendering.ConstantProvider); diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index bf79c2f9d..f7dc74ddb 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -350,6 +350,22 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "tooltip": "", "helpUrl": "" }, + { + "type": "test_fields_only_text_input", + "message0": "%1", + "args0": [ + { + "type": "field_input", + "name": "TEXT_INPUT", + "text": "default" + } + ], + "style": "math_blocks", + "tooltip": "", + "helpUrl": "", + "output": "String", + "style": "textInput" + }, { "type": "test_fields_multilinetext", "message0": "code %1", diff --git a/tests/playground.html b/tests/playground.html index 742b5858f..425910213 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -1471,6 +1471,7 @@ var spaghettiXml = [ + From 067fbb44884ad3cd06d17e7702f31b72a230879d Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 11 Nov 2019 15:17:26 -0800 Subject: [PATCH 173/343] Move highlightForReplacement into the path object as well. --- core/block_svg.js | 8 +------- core/renderers/common/i_path_object.js | 9 +++++++++ core/renderers/common/path_object.js | 12 ++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 057f0d60c..cfcb3d6e6 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1756,11 +1756,5 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { * @package */ Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { - if (add) { - Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgGroup_), - 'blocklyReplaceable'); - } else { - Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgGroup_), - 'blocklyReplaceable'); - } + this.pathObject.updateReplacementHighlight(add); }; diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index b7f6b405a..f9c7855fc 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -111,3 +111,12 @@ Blockly.blockRendering.IPathObject.prototype.updateInsertionMarker; * @package */ Blockly.blockRendering.IPathObject.prototype.updateMovable; + +/** + * Add or remove styling that shows that if the dragging block is dropped, this + * block will be replaced. If a shadow block, it will disappear. Otherwise it + * will bump. + * @param {boolean} enable True if styling should be added. + * @package + */ +Blockly.blockRendering.PathObject.prototype.updateReplacementHighlight; diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index f7ba75373..9766b8ff9 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -221,3 +221,15 @@ Blockly.blockRendering.PathObject.prototype.updateMovable = function(enable) { this.setClass_('blocklyDraggable', enable); }; +/** + * Add or remove styling that shows that if the dragging block is dropped, this + * block will be replaced. If a shadow block, it will disappear. Otherwise it + * will bump. + * @param {boolean} enable True if styling should be added. + * @package + */ +Blockly.blockRendering.PathObject.prototype.updateReplacementHighlight = + function(enable) { + /* eslint-disable indent */ + this.setClass_('blocklyReplaceable', enable); +}; /* eslint-enable indent */ From 23635598ec64d9e85c825a8526aaff1212618b1e Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 11 Nov 2019 15:44:11 -0800 Subject: [PATCH 174/343] Update i_path_object.js --- core/renderers/common/i_path_object.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index f9c7855fc..cafb1d537 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -119,4 +119,4 @@ Blockly.blockRendering.IPathObject.prototype.updateMovable; * @param {boolean} enable True if styling should be added. * @package */ -Blockly.blockRendering.PathObject.prototype.updateReplacementHighlight; +Blockly.blockRendering.IPathObject.prototype.updateReplacementHighlight; From 95f2b232b98622a54b866c6b395c31c25e50ba06 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 11 Nov 2019 16:13:50 -0800 Subject: [PATCH 175/343] Field constants (#3423) * Move field text sizing constants to renderer constants --- core/field.js | 33 ++++++++++++----------------- core/field_dropdown.js | 10 +++++---- core/field_multilineinput.js | 2 +- core/field_textinput.js | 2 +- core/renderers/common/constants.js | 21 ++++++++++++++++++ tests/mocha/field_textinput_test.js | 5 +++++ 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/core/field.js b/core/field.js index 6a8e21f5b..8c7dccb57 100644 --- a/core/field.js +++ b/core/field.js @@ -129,6 +129,13 @@ Blockly.Field = function(value, opt_validator, opt_config) { */ this.mouseDownWrapper_ = null; + /** + * Constants associated with the source block's renderer. + * @type {Blockly.blockRendering.ConstantProvider} + * @protected + */ + this.constants_ = null; + opt_config && this.configure_(opt_config); this.setValue(value); opt_validator && this.setValidator(opt_validator); @@ -257,24 +264,6 @@ Blockly.Field.prototype.EDITABLE = true; */ Blockly.Field.prototype.SERIALIZABLE = false; -/** - * Point size of text. Should match blocklyText's font-size in CSS. - * @const {number} - */ -Blockly.Field.FONTSIZE = 11; - -/** - * Text font weight. Should match blocklyText's font-weight in CSS. - * @const {string} - */ -Blockly.Field.FONTWEIGHT = 'normal'; - -/** - * Text font family. Should match blocklyText's font-family in CSS. - * @const {string} - */ -Blockly.Field.FONTFAMILY = 'sans-serif'; - /** * Process the configuration map passed to the field. * @param {!Object} config A map of options used to configure the field. See @@ -303,6 +292,9 @@ Blockly.Field.prototype.setSourceBlock = function(block) { throw Error('Field already bound to a block.'); } this.sourceBlock_ = block; + if (block.workspace.rendered) { + this.constants_ = block.workspace.getRenderer().getConstants(); + } }; /** @@ -661,8 +653,9 @@ Blockly.Field.prototype.updateWidth = function() { Blockly.Field.prototype.updateSize_ = function() { var textWidth = Blockly.utils.dom.getFastTextWidth( /** @type {!SVGTextElement} */ (this.textElement_), - Blockly.Field.FONTSIZE, Blockly.Field.FONTWEIGHT, - Blockly.Field.FONTFAMILY); + this.constants_.FIELD_TEXT_FONTSIZE, + this.constants_.FIELD_TEXT_FONTWEIGHT, + this.constants_.FIELD_TEXT_FONTFAMILY); var totalWidth = textWidth; if (this.borderRect_) { totalWidth += Blockly.Field.X_PADDING; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 4a3f9c11d..8b7e7a93a 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -516,8 +516,9 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { var arrowWidth = Blockly.utils.dom.getFastTextWidth( /** @type {!SVGTSpanElement} */ (this.arrow_), - Blockly.Field.FONTSIZE, Blockly.Field.FONTWEIGHT, - Blockly.Field.FONTFAMILY); + this.constants_.FIELD_TEXT_FONTSIZE, + this.constants_.FIELD_TEXT_FONTWEIGHT, + this.constants_.FIELD_TEXT_FONTFAMILY); var imageHeight = Number(imageJson.height); var imageWidth = Number(imageJson.width); @@ -552,8 +553,9 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { // Height and width include the border rect. this.size_.height = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT; this.size_.width = Blockly.utils.dom.getFastTextWidth(this.textElement_, - Blockly.Field.FONTSIZE, Blockly.Field.FONTWEIGHT, - Blockly.Field.FONTFAMILY) + + this.constants_.FIELD_TEXT_FONTSIZE, + this.constants_.FIELD_TEXT_FONTWEIGHT, + this.constants_.FIELD_TEXT_FONTFAMILY) + Blockly.Field.X_PADDING; }; diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 3b07937cc..11cf73fb1 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -245,7 +245,7 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() { var htmlInput = /** @type {HTMLTextAreaElement} */ (document.createElement('textarea')); htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput'; htmlInput.setAttribute('spellcheck', this.spellcheck_); - var fontSize = (Blockly.Field.FONTSIZE * scale) + 'pt'; + var fontSize = (this.constants_.FIELD_TEXT_FONTSIZE * scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px'; diff --git a/core/field_textinput.js b/core/field_textinput.js index 631923a71..853ec1187 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -286,7 +286,7 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { htmlInput.className = 'blocklyHtmlInput'; htmlInput.setAttribute('spellcheck', this.spellcheck_); var fontSize = - (Blockly.Field.FONTSIZE * this.workspace_.scale) + 'pt'; + (this.constants_.FIELD_TEXT_FONTSIZE * this.workspace_.scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; var borderRadius = diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 6aa0863f6..4f4702430 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -136,6 +136,27 @@ Blockly.blockRendering.ConstantProvider = function() { */ this.JAGGED_TEETH_WIDTH = 6; + /** + * Point size of text. Should match blocklyText's font-size in CSS. + * @type {number} + * @const + */ + this.FIELD_TEXT_FONTSIZE = 11; + + /** + * Text font weight. Should match blocklyText's font-weight in CSS. + * @type {string} + * @const + */ + this.FIELD_TEXT_FONTWEIGHT = 'normal'; + + /** + * Text font family. Should match blocklyText's font-family in CSS. + * @type {string} + * @const + */ + this.FIELD_TEXT_FONTFAMILY = 'sans-serif'; + /** * The ID of the emboss filter, or the empty string if no filter is set. * @type {string} diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js index 7e94da589..e1c9b0206 100644 --- a/tests/mocha/field_textinput_test.js +++ b/tests/mocha/field_textinput_test.js @@ -228,6 +228,11 @@ suite('Text Input Fields', function() { scale: 1 } }; + field.constants_ = { + FIELD_TEXT_FONTSIZE: 11, + FIELD_TEXT_FONTWEIGHT: 'normal', + FIELD_TEXT_FONTFAMILY: 'sans-serif' + }; Blockly.WidgetDiv.DIV = document.createElement('div'); this.stub = sinon.stub(field, 'resizeEditor_'); }; From 40bdfac017c3b2eadcc5a3aea1d8eee4f1664eea Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 11 Nov 2019 16:44:58 -0800 Subject: [PATCH 176/343] Fix setting focus for workspace (#3425) * Fix setting focus for workspace --- core/components/menu/menu.js | 2 +- core/field_colour.js | 4 ++-- core/field_textinput.js | 19 ++++++++++++++++++- core/gesture.js | 6 ++++-- core/inject.js | 12 +++++------- core/workspace_svg.js | 4 ++-- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/core/components/menu/menu.js b/core/components/menu/menu.js index 4386f47ac..6bad647d7 100644 --- a/core/components/menu/menu.js +++ b/core/components/menu/menu.js @@ -73,7 +73,7 @@ Blockly.Menu.prototype.createDom = function() { Blockly.Menu.prototype.focus = function() { var el = this.getElement(); if (el) { - el.focus(); + el.focus({preventScroll:true}); Blockly.utils.dom.addClass(el, 'focused'); } }; diff --git a/core/field_colour.js b/core/field_colour.js index 6878977e6..095f29c72 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -334,7 +334,7 @@ Blockly.FieldColour.prototype.showEditor_ = function() { this, this.dropdownDispose_.bind(this)); // Focus so we can start receiving keyboard events. - this.picker_.focus(); + this.picker_.focus({preventScroll:true}); }; /** @@ -487,7 +487,7 @@ Blockly.FieldColour.prototype.onMouseMove_ = function(e) { * @private */ Blockly.FieldColour.prototype.onMouseEnter_ = function() { - this.picker_.focus(); + this.picker_.focus({preventScroll:true}); }; /** diff --git a/core/field_textinput.js b/core/field_textinput.js index 853ec1187..ff39d69a9 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -269,7 +269,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { this.isBeingEdited_ = true; if (!quietInput) { - this.htmlInput_.focus(); + this.htmlInput_.focus({preventScroll:true}); this.htmlInput_.select(); } }; @@ -349,6 +349,10 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { this.onKeyInputWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'input', this, this.onHtmlInputChange_); + + this.onBlurInputWrapper_ = + Blockly.bindEventWithChecks_( + htmlInput, 'blur', this, this.onHtmlInputBlur_); }; /** @@ -362,6 +366,9 @@ Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() { if (this.onKeyInputWrapper_) { Blockly.unbindEvent_(this.onKeyInputWrapper_); } + if (this.onBlurInputWrapper_) { + Blockly.unbindEvent_(this.onBlurInputWrapper_); + } }; /** @@ -406,6 +413,16 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { } }; +/** + * Handle blur for the editor. + * @param {!Event} _e Focus event. + * @protected + */ +Blockly.FieldTextInput.prototype.onHtmlInputBlur_ = function(_e) { + Blockly.WidgetDiv.hide(); + Blockly.DropDownDiv.hideWithoutAnimation(); +}; + /** * Set the html input value and the field's internal value. The difference * between this and ``setValue`` is that this also updates the html input diff --git a/core/gesture.js b/core/gesture.js index 758aad0e8..536f665fc 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -483,12 +483,14 @@ Blockly.Gesture.prototype.doStart = function(e) { // dragged, the block was moved, the parent workspace zoomed, etc. this.startWorkspace_.resize(); } - this.startWorkspace_.markFocused(); - this.mostRecentEvent_ = e; // Hide chaff also hides the flyout, so don't do it if the click is in a // flyout. Blockly.hideChaff(!!this.flyout_); + + this.startWorkspace_.markFocused(); + this.mostRecentEvent_ = e; + Blockly.Tooltip.block(); if (this.targetBlock_) { diff --git a/core/inject.js b/core/inject.js index 587aca07b..3bec1b7f5 100644 --- a/core/inject.js +++ b/core/inject.js @@ -78,18 +78,16 @@ Blockly.inject = function(container, opt_options) { Blockly.user.keyMap.setKeyMap(options.keyMap); Blockly.init_(workspace); + + // Keep focus on the first workspace so entering keyboard navigation looks correct. Blockly.mainWorkspace = workspace; Blockly.svgResize(workspace); - subContainer.addEventListener('focus', function() { + subContainer.addEventListener('focusin', function() { Blockly.mainWorkspace = workspace; }); - subContainer.addEventListener('blur', function() { - Blockly.mainWorkspace = null; - }); - return workspace; }; @@ -127,7 +125,8 @@ Blockly.createDom_ = function(container, options) { 'xmlns:html': Blockly.utils.dom.HTML_NS, 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, 'version': '1.1', - 'class': 'blocklySvg' + 'class': 'blocklySvg', + 'tabindex': '0' }, container); /* @@ -183,7 +182,6 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, // A null translation will also apply the correct initial scale. mainWorkspace.translate(0, 0); - Blockly.mainWorkspace = mainWorkspace; if (!options.readOnly && !mainWorkspace.isMovable()) { // Helper function for the workspaceChanged callback. diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 01909a3d0..da6eacaf4 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1874,7 +1874,7 @@ Blockly.WorkspaceSvg.prototype.setBrowserFocus = function() { } try { // Focus the workspace SVG - this is for Chrome and Firefox. - this.getParentSvg().focus(); + 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 @@ -1886,7 +1886,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(); + this.getParentSvg().parentNode.focus({preventScroll:true}); } } }; From 8747d5e6b59ba3b86edef78df2bc46cb26444def Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 11 Nov 2019 17:02:17 -0800 Subject: [PATCH 177/343] Fixed comment event listener disposal. (#3427) * Fixed listener disposal for comment icons. * Fixed listener disposal for bubbles. --- core/bubble.js | 76 +++++++++++++++++++++++++++++++------------------ core/comment.js | 76 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 110 insertions(+), 42 deletions(-) diff --git a/core/bubble.js b/core/bubble.js index 4e139bdc3..1e9829e58 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -51,6 +51,34 @@ Blockly.Bubble = function(workspace, content, shape, anchorXY, this.content_ = content; this.shape_ = shape; + /** + * Method to call on resize of bubble. + * @type {?function()} + * @private + */ + this.resizeCallback_ = null; + + /** + * Method to call on move of bubble. + * @type {?function()} + * @private + */ + this.moveCallback_ = null; + + /** + * Mouse down on bubbleBack_ event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseDownBubbleWrapper_ = null; + + /** + * Mouse down on resizeGroup_ event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseDownResizeWrapper_ = null; + var angle = Blockly.Bubble.ARROW_ANGLE; if (this.workspace_.RTL) { angle = -angle; @@ -72,29 +100,6 @@ Blockly.Bubble = function(workspace, content, shape, anchorXY, this.positionBubble_(); this.renderArrow_(); this.rendered_ = true; - - if (!workspace.options.readOnly) { - Blockly.bindEventWithChecks_( - this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_); - if (this.resizeGroup_) { - Blockly.bindEventWithChecks_( - this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); - } - } - - /** - * Method to call on resize of bubble. - * @type {?function()} - * @private - */ - this.resizeCallback_ = null; - - /** - * Method to call on move of bubble. - * @type {?function()} - * @private - */ - this.moveCallback_ = null; }; /** @@ -124,15 +129,15 @@ Blockly.Bubble.ARROW_BEND = 4; Blockly.Bubble.ANCHOR_RADIUS = 8; /** - * Wrapper function called when a mouseUp occurs during a drag operation. - * @type {Array.} + * Mouse up event data. + * @type {?Blockly.EventData} * @private */ Blockly.Bubble.onMouseUpWrapper_ = null; /** - * Wrapper function called when a mouseMove occurs during a drag operation. - * @type {Array.} + * Mouse move event data. + * @type {?Blockly.EventData} * @private */ Blockly.Bubble.onMouseMoveWrapper_ = null; @@ -278,6 +283,15 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { } else { this.resizeGroup_ = null; } + + if (!this.workspace_.options.readOnly) { + this.onMouseDownBubbleWrapper_ = Blockly.bindEventWithChecks_( + this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_); + if (this.resizeGroup_) { + this.onMouseDownResizeWrapper_ = Blockly.bindEventWithChecks_( + this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); + } + } this.bubbleGroup_.appendChild(content); return this.bubbleGroup_; }; @@ -785,6 +799,14 @@ Blockly.Bubble.prototype.dispose = function() { Blockly.Bubble.unbindDragEvents_(); // Dispose of and unlink the bubble. Blockly.utils.dom.removeNode(this.bubbleGroup_); + if (this.onMouseDownBubbleWrapper_) { + Blockly.unbindEvent_(this.onMouseDownBubbleWrapper_); + this.onMouseDownBubbleWrapper_ = null; + } + if (this.onMouseDownResizeWrapper_) { + Blockly.unbindEvent_(this.onMouseDownResizeWrapper_); + this.onMouseDownResizeWrapper_ = null; + } this.bubbleGroup_ = null; this.bubbleArrow_ = null; this.bubbleBack_ = null; diff --git a/core/comment.js b/core/comment.js index 680b6ca95..ce4dbf2bc 100644 --- a/core/comment.js +++ b/core/comment.js @@ -61,6 +61,34 @@ Blockly.Comment = function(block) { */ this.cachedText_ = ''; + /** + * Mouse up event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseUpWrapper_ = null; + + /** + * Wheel event data. + * @type {?Blockly.EventData} + * @private + */ + this.onWheelWrapper_ = null; + + /** + * Change event data. + * @type {?Blockly.EventData} + * @private + */ + this.onChangeWrapper_ = null; + + /** + * Input event data. + * @type {?Blockly.EventData} + * @private + */ + this.onInputWrapper_ = null; + this.createIcon(); }; Blockly.utils.object.inherits(Blockly.Comment, Blockly.Icon); @@ -137,21 +165,24 @@ Blockly.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. - Blockly.bindEventWithChecks_(textarea, 'mouseup', this, this.startEdit_, - true, true); + this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_( + textarea, 'mouseup', this, this.startEdit_, true, true); // Don't zoom with mousewheel. - Blockly.bindEventWithChecks_(textarea, 'wheel', this, function(e) { - e.stopPropagation(); - }); - Blockly.bindEventWithChecks_(textarea, 'change', this, function(_e) { - if (this.cachedText_ != this.model_.text) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.block_, 'comment', null, this.cachedText_, this.model_.text)); - } - }); - Blockly.bindEventWithChecks_(textarea, 'input', this, function(_e) { - this.model_.text = textarea.value; - }); + this.onWheelWrapper_ = Blockly.bindEventWithChecks_( + textarea, 'wheel', this, function(e) { + e.stopPropagation(); + }); + this.onChangeWrapper_ = Blockly.bindEventWithChecks_( + textarea, 'change', this, function(_e) { + if (this.cachedText_ != this.model_.text) { + Blockly.Events.fire(new Blockly.Events.BlockChange( + this.block_, 'comment', null, this.cachedText_, this.model_.text)); + } + }); + this.onInputWrapper_ = Blockly.bindEventWithChecks_( + textarea, 'input', this, function(_e) { + this.model_.text = textarea.value; + }); setTimeout(textarea.focus.bind(textarea), 0); @@ -271,7 +302,22 @@ Blockly.Comment.prototype.disposeBubble_ = function() { Blockly.Warning.prototype.disposeBubble.call(this); return; } - + if (this.onMouseUpWrapper_) { + Blockly.unbindEvent_(this.onMouseUpWrapper_); + this.onMouseUpWrapper_ = null; + } + if (this.onWheelWrapper_) { + Blockly.unbindEvent_(this.onWheelWrapper_); + this.onWheelWrapper_ = null; + } + if (this.onChangeWrapper_) { + Blockly.unbindEvent_(this.onChangeWrapper_); + this.onChangeWrapper_ = null; + } + if (this.onInputWrapper_) { + Blockly.unbindEvent_(this.onInputWrapper_); + this.onInputWrapper_ = null; + } this.bubble_.dispose(); this.bubble_ = null; this.textarea_ = null; From dad8738e75748776be6f3682eea5c51e5c1733b0 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 12 Nov 2019 10:14:31 -0800 Subject: [PATCH 178/343] Cleaned up unbindEvent_ calls (#3429) * Cleaned up unbindEvent_ calls. --- core/components/menu/menu.js | 61 +++++++++++++++++++++--- core/components/tree/treecontrol.js | 50 ++++++++++++++++--- core/contextmenu.js | 1 + core/field_angle.js | 9 +++- core/field_colour.js | 5 ++ core/field_textinput.js | 11 ++++- core/flyout_button.js | 14 +++--- core/gesture.js | 4 +- core/touch_gesture.js | 2 +- core/workspace_comment_svg.js | 15 ++++++ demos/custom-fields/pitch/field_pitch.js | 25 +++++++++- 11 files changed, 170 insertions(+), 27 deletions(-) diff --git a/core/components/menu/menu.js b/core/components/menu/menu.js index 6bad647d7..ab89585db 100644 --- a/core/components/menu/menu.js +++ b/core/components/menu/menu.js @@ -44,6 +44,41 @@ Blockly.Menu = function() { * @private */ this.highlightedIndex_ = -1; + + /** + * Mouse over event data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseOverHandler_ = null; + + /** + * Click event data. + * @type {?Blockly.EventData} + * @private + */ + this.clickHandler_ = null; + + /** + * Mouse enter event data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseEnterHandler_ = null; + + /** + * Mouse leave event data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseLeaveHandler_ = null; + + /** + * Key down event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeyDownWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.Menu, Blockly.Component); @@ -147,7 +182,6 @@ Blockly.Menu.prototype.attachEvents_ = function() { 'mouseenter', this, this.handleMouseEnter_, true); this.mouseLeaveHandler_ = Blockly.bindEventWithChecks_(el, 'mouseleave', this, this.handleMouseLeave_, true); - this.onKeyDownWrapper_ = Blockly.bindEventWithChecks_(el, 'keydown', this, this.handleKeyEvent); }; @@ -157,11 +191,26 @@ Blockly.Menu.prototype.attachEvents_ = function() { * @private */ Blockly.Menu.prototype.detachEvents_ = function() { - Blockly.unbindEvent_(this.mouseOverHandler_); - Blockly.unbindEvent_(this.clickHandler_); - Blockly.unbindEvent_(this.mouseEnterHandler_); - Blockly.unbindEvent_(this.mouseLeaveHandler_); - Blockly.unbindEvent_(this.onKeyDownWrapper_); + if (this.mouseOverHandler_) { + Blockly.unbindEvent_(this.mouseOverHandler_); + this.mouseOverHandler_ = null; + } + if (this.clickHandler_) { + Blockly.unbindEvent_(this.clickHandler_); + this.clickHandler_ = null; + } + if (this.mouseEnterHandler_) { + Blockly.unbindEvent_(this.mouseEnterHandler_); + this.mouseEnterHandler_ = null; + } + if (this.mouseLeaveHandler_) { + Blockly.unbindEvent_(this.mouseLeaveHandler_); + this.mouseLeaveHandler_ = null; + } + if (this.onKeyDownWrapper_) { + Blockly.unbindEvent_(this.onKeyDownWrapper_); + this.onKeyDownWrapper_ = null; + } }; // Child component management. diff --git a/core/components/tree/treecontrol.js b/core/components/tree/treecontrol.js index a498b6938..f42c8089a 100644 --- a/core/components/tree/treecontrol.js +++ b/core/components/tree/treecontrol.js @@ -44,6 +44,34 @@ goog.require('Blockly.utils.style'); Blockly.tree.TreeControl = function(toolbox, config) { this.toolbox_ = toolbox; + /** + * Focus event data. + * @type {?Blockly.EventData} + * @private + */ + this.onFocusWrapper_ = null; + + /** + * Blur event data. + * @type {?Blockly.EventData} + * @private + */ + this.onBlurWrapper_ = null; + + /** + * Click event data. + * @type {?Blockly.EventData} + * @private + */ + this.onClickWrapper_ = null; + + /** + * Key down event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeydownWrapper_ = null; + Blockly.tree.BaseNode.call(this, '', config); // The root is open and selected by default. @@ -272,10 +300,8 @@ Blockly.tree.TreeControl.prototype.attachEvents_ = function() { 'focus', this, this.handleFocus_); this.onBlurWrapper_ = Blockly.bindEvent_(el, 'blur', this, this.handleBlur_); - this.onClickWrapper_ = Blockly.bindEventWithChecks_(el, 'click', this, this.handleMouseEvent_); - this.onKeydownWrapper_ = Blockly.bindEvent_(el, 'keydown', this, this.handleKeyEvent_); }; @@ -285,10 +311,22 @@ Blockly.tree.TreeControl.prototype.attachEvents_ = function() { * @private */ Blockly.tree.TreeControl.prototype.detachEvents_ = function() { - Blockly.unbindEvent_(this.onFocusWrapper_); - Blockly.unbindEvent_(this.onBlurWrapper_); - Blockly.unbindEvent_(this.onClickWrapper_); - Blockly.unbindEvent_(this.onKeydownWrapper_); + if (this.onFocusWrapper_) { + Blockly.unbindEvent_(this.onFocusWrapper_); + this.onFocusWrapper_ = null; + } + if (this.onBlurWrapper_) { + Blockly.unbindEvent_(this.onBlurWrapper_); + this.onBlurWrapper_ = null; + } + if (this.onClickWrapper_) { + Blockly.unbindEvent_(this.onClickWrapper_); + this.onClickWrapper_ = null; + } + if (this.onKeydownWrapper_) { + Blockly.unbindEvent_(this.onKeydownWrapper_); + this.onKeydownWrapper_ = null; + } }; /** diff --git a/core/contextmenu.js b/core/contextmenu.js index 9feee57d8..1c51704f7 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -166,6 +166,7 @@ Blockly.ContextMenu.hide = function() { Blockly.ContextMenu.currentBlock = null; if (Blockly.ContextMenu.eventWrapper_) { Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_); + Blockly.ContextMenu.eventWrapper_ = null; } }; diff --git a/core/field_angle.js b/core/field_angle.js index 3a550bcbb..5b8b75bc3 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -330,9 +330,11 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { // a click handler on the drag surface to update the value if the surface // is clicked. this.clickSurfaceWrapper_ = - Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove_, true, true); + Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove_, + true, true); this.moveSurfaceWrapper_ = - Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove_, true, true); + Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove_, + true, true); return svg; }; @@ -343,12 +345,15 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { Blockly.FieldAngle.prototype.dropdownDispose_ = function() { if (this.clickWrapper_) { Blockly.unbindEvent_(this.clickWrapper_); + this.clickWrapper_ = null; } if (this.clickSurfaceWrapper_) { Blockly.unbindEvent_(this.clickSurfaceWrapper_); + this.clickSurfaceWrapper_ = null; } if (this.moveSurfaceWrapper_) { Blockly.unbindEvent_(this.moveSurfaceWrapper_); + this.moveSurfaceWrapper_ = null; } this.gauge_ = null; this.line_ = null; diff --git a/core/field_colour.js b/core/field_colour.js index 095f29c72..54204553e 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -610,18 +610,23 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { Blockly.FieldColour.prototype.dropdownDispose_ = function() { if (this.onClickWrapper_) { Blockly.unbindEvent_(this.onClickWrapper_); + this.onClickWrapper_ = null; } if (this.onMouseMoveWrapper_) { Blockly.unbindEvent_(this.onMouseMoveWrapper_); + this.onMouseMoveWrapper_ = null; } if (this.onMouseEnterWrapper_) { Blockly.unbindEvent_(this.onMouseEnterWrapper_); + this.onMouseEnterWrapper_ = null; } if (this.onMouseLeaveWrapper_) { Blockly.unbindEvent_(this.onMouseLeaveWrapper_); + this.onMouseLeaveWrapper_ = null; } if (this.onKeyDownWrapper_) { Blockly.unbindEvent_(this.onKeyDownWrapper_); + this.onKeyDownWrapper_ = null; } this.picker_ = null; this.highlightedIndex_ = null; diff --git a/core/field_textinput.js b/core/field_textinput.js index ff39d69a9..98b12f78d 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -84,6 +84,13 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { * @private */ this.onKeyInputWrapper_ = null; + + /** + * Blur input event data. + * @type {?Blockly.EventData} + * @private + */ + this.onBlurInputWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field); @@ -349,7 +356,6 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { this.onKeyInputWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'input', this, this.onHtmlInputChange_); - this.onBlurInputWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'blur', this, this.onHtmlInputBlur_); @@ -362,12 +368,15 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() { if (this.onKeyDownWrapper_) { Blockly.unbindEvent_(this.onKeyDownWrapper_); + this.onKeyDownWrapper_ = null; } if (this.onKeyInputWrapper_) { Blockly.unbindEvent_(this.onKeyInputWrapper_); + this.onKeyInputWrapper_ = null; } if (this.onBlurInputWrapper_) { Blockly.unbindEvent_(this.onBlurInputWrapper_); + this.onBlurInputWrapper_ = null; } }; diff --git a/core/flyout_button.js b/core/flyout_button.js index 84898cf37..a8cd5360d 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -87,6 +87,13 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, xml, isLabel) { * @private */ this.cssClass_ = xml.getAttribute('web-class') || null; + + /** + * Mouse up event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseUpWrapper_ = null; }; /** @@ -106,13 +113,6 @@ Blockly.FlyoutButton.prototype.width = 0; */ Blockly.FlyoutButton.prototype.height = 0; -/** - * Opaque data that can be passed to Blockly.unbindEvent_. - * @type {Array.} - * @private - */ -Blockly.FlyoutButton.prototype.onMouseUpWrapper_ = null; - /** * Create the button elements. * @return {!SVGElement} The button's SVG group. diff --git a/core/gesture.js b/core/gesture.js index 536f665fc..6e25b9051 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -162,7 +162,7 @@ Blockly.Gesture = function(e, creatorWorkspace) { /** * A handle to use to unbind a mouse move listener at the end of a drag. * Opaque data returned from Blockly.bindEventWithChecks_. - * @type {Array.} + * @type {?Blockly.EventData} * @protected */ this.onMoveWrapper_ = null; @@ -170,7 +170,7 @@ Blockly.Gesture = function(e, creatorWorkspace) { /** * A handle to use to unbind a mouse up listener at the end of a drag. * Opaque data returned from Blockly.bindEventWithChecks_. - * @type {Array.} + * @type {?Blockly.EventData} * @protected */ this.onUpWrapper_ = null; diff --git a/core/touch_gesture.js b/core/touch_gesture.js index 8cfa68351..374fdddb5 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -81,7 +81,7 @@ Blockly.TouchGesture = function(e, creatorWorkspace) { * A handle to use to unbind the second touch start or pointer down listener * at the end of a drag. * Opaque data returned from Blockly.bindEventWithChecks_. - * @type {Array.} + * @type {?Blockly.EventData} * @private */ this.onStartWrapper_ = null; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 7b9c41268..d8d79ff00 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -49,6 +49,21 @@ goog.require('Blockly.WorkspaceComment'); */ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width, opt_id) { + + /** + * Mouse up event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseUpWrapper_ = null; + + /** + * Mouse move event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseMoveWrapper_ = null; + // Create core elements for the block. /** * @type {SVGElement} diff --git a/demos/custom-fields/pitch/field_pitch.js b/demos/custom-fields/pitch/field_pitch.js index f5bdf505b..3d3621030 100644 --- a/demos/custom-fields/pitch/field_pitch.js +++ b/demos/custom-fields/pitch/field_pitch.js @@ -39,6 +39,20 @@ var CustomFields = CustomFields || {}; */ CustomFields.FieldPitch = function(text) { CustomFields.FieldPitch.superClass_.constructor.call(this, text); + + /** + * Click event data. + * @type {?Blockly.EventData} + * @private + */ + this.clickWrapper_ = null; + + /** + * Move event data. + * @type {?Blockly.EventData} + * @private + */ + this.moveWrapper_ = null; }; Blockly.utils.object.inherits(CustomFields.FieldPitch, Blockly.FieldTextInput); @@ -112,8 +126,15 @@ CustomFields.FieldPitch.prototype.dropdownCreate_ = function() { * @private */ CustomFields.FieldPitch.prototype.dropdownDispose_ = function() { - Blockly.unbindEvent_(this.clickWrapper_); - Blockly.unbindEvent_(this.moveWrapper_); + if (this.clickWrapper_) { + Blockly.unbindEvent_(this.clickWrapper_); + this.clickWrapper_ = null; + } + if (this.moveWrapper_) { + Blockly.unbindEvent_(this.moveWrapper_); + this.moveWrapper_ = null; + } + this.imageElement_ = null; }; /** From e6e63f456b45cf6ff6d78aaa4bedafc6db41f88a Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 12 Nov 2019 10:15:16 -0800 Subject: [PATCH 179/343] Fixed bubble dispose (#3430) * Fixed bubble dispose. --- core/bubble.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/core/bubble.js b/core/bubble.js index 1e9829e58..883614e77 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -79,6 +79,14 @@ Blockly.Bubble = function(workspace, content, shape, anchorXY, */ this.onMouseDownResizeWrapper_ = null; + /** + * Describes whether this bubble has been disposed of (nodes and event + * listeners removed from the page) or not. + * @type {boolean} + * @package + */ + this.disposed = false; + var angle = Blockly.Bubble.ARROW_ANGLE; if (this.workspace_.RTL) { angle = -angle; @@ -796,24 +804,15 @@ Blockly.Bubble.prototype.setColour = function(hexColour) { * Dispose of this bubble. */ Blockly.Bubble.prototype.dispose = function() { - Blockly.Bubble.unbindDragEvents_(); - // Dispose of and unlink the bubble. - Blockly.utils.dom.removeNode(this.bubbleGroup_); if (this.onMouseDownBubbleWrapper_) { Blockly.unbindEvent_(this.onMouseDownBubbleWrapper_); - this.onMouseDownBubbleWrapper_ = null; } if (this.onMouseDownResizeWrapper_) { Blockly.unbindEvent_(this.onMouseDownResizeWrapper_); - this.onMouseDownResizeWrapper_ = null; } - this.bubbleGroup_ = null; - this.bubbleArrow_ = null; - this.bubbleBack_ = null; - this.resizeGroup_ = null; - this.workspace_ = null; - this.content_ = null; - this.shape_ = null; + Blockly.Bubble.unbindDragEvents_(); + Blockly.utils.dom.removeNode(this.bubbleGroup_); + this.disposed = true; }; /** From e8a294b1389d1d2d505cf54407e680df832d9ebe Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 12 Nov 2019 11:26:20 -0800 Subject: [PATCH 180/343] Use google-closure-deps in local build (#3432) * Use google-closure-deps instead of python script for building in gulpfile (JS) --- gulpfile.js | 50 ++++-- package-lock.json | 432 ++++++++++++++++++++++------------------------ package.json | 3 +- 3 files changed, 241 insertions(+), 244 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 3efa79d0b..18abff83b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -32,8 +32,10 @@ var path = require('path'); var fs = require('fs'); var rimraf = require('rimraf'); var execSync = require('child_process').execSync; +var through2 = require('through2'); var closureCompiler = require('google-closure-compiler').gulp(); +var closureDeps = require('google-closure-deps'); var packageJson = require('./package.json'); var argv = require('yargs').argv; @@ -340,27 +342,37 @@ if (this.IS_NODE_JS) { document.write(''); } `; - const file = 'blockly_uncompressed.js'; - // Run depswriter.py and which scans the core directory and writes out a ``goog.addDependency`` line for each file. - const cmd = `python ./node_modules/google-closure-library/closure/bin/build/depswriter.py \ - --root_with_prefix="./core ../core" > ${file}`; - execSync(cmd, { stdio: 'inherit' }); - const requires = `goog.addDependency("base.js", [], []);\n\n// Load Blockly.\ngoog.require('Blockly.requires')\n`; +let deps = []; +return gulp.src('core/**/**/*.js') + .pipe(through2.obj((file, _enc, cb) => { + deps.push(closureDeps.parser.parseFile(file.path).dependency); + cb(null); + })) + .on('end', () => { + const graph = new closureDeps.depGraph.Graph(deps); + let addDependency = []; + graph.depsByPath.forEach(dep => { + addDependency.push('goog.addDependency(' + [ + '"' + path.relative('./closure/goog', dep.path) + '"', + '[' + dep.closureSymbols + .map(s => `'${s}'`).join(', ') + ']', + '[' + dep.imports + .map(i => i.symOrPath) + .filter(i => i !== 'goog') + .sort() + .map(i => `'${i}'`).join(', ') + ']', + ].join(', ') + ');'); + }); + const requires = ` +goog.addDependency("base.js", [], []); - return gulp.src(file) - // Remove comments so we're compatible with the build.py script - .pipe(gulp.replace(/\/\/.*\n/gm, '')) - // Replace quotes to be compatible with build.py - .pipe(gulp.replace(/\'(.*\.js)\'/gm, '"$1"')) - // Remove last parameter to be compatible with build.py - .pipe(gulp.replace(/, \{\}\);/gm, ');')) - // Find the Blockly directory name and replace it with a JS variable. - // This allows blockly_uncompressed.js to be compiled on one computer and be - // used on another, even if the directory name differs. - .pipe(gulp.replace(/\.\.\/core/gm, `../../core`)) - .pipe(gulp.insert.wrap(header, requires + footer)) - .pipe(gulp.dest('./')); +// Load Blockly. +goog.require('Blockly.requires') +`; + fs.writeFileSync('blockly_uncompressed.js', + header + addDependency.join('\n') + requires + footer); + }); }); /** diff --git a/package-lock.json b/package-lock.json index 17f11ee83..e35c114f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2076,15 +2076,6 @@ "mime-types": "^2.1.12" } }, - "formatio": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", - "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", - "dev": true, - "requires": { - "samsam": "~1.1" - } - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -2114,6 +2105,18 @@ "requires": { "graceful-fs": "^4.1.11", "through2": "^2.0.3" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "fs.realpath": { @@ -2881,13 +2884,111 @@ "dev": true, "optional": true }, - "google-closure-library": { - "version": "20191027.0.1", - "resolved": "https://registry.npmjs.org/google-closure-library/-/google-closure-library-20191027.0.1.tgz", - "integrity": "sha512-qs4lRwIcUF2K7X12NHRs9IDJ65fBX4F6CRCqswQJpuotcPXSZHX95GiFabmhIeIRnD/fMyScEK4S3U+fFv19MQ==", + "google-closure-deps": { + "version": "20190121.0.0", + "resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20190121.0.0.tgz", + "integrity": "sha512-UdFzI/6sQt2q66GFO9M/DRw/F5dk8TY7JRav54jsK+VORRoTfjH99xvHqEva4BOZ2+JdzG9IoTcH0nyIOAbxfQ==", "dev": true, "requires": { - "promises-aplus-tests": "^2.1.2" + "argparse": "^1.0.9", + "google-closure-compiler": "^20181008.0.0", + "yargs": "^12.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "google-closure-compiler": { + "version": "20181008.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20181008.0.0.tgz", + "integrity": "sha512-XmJIasXHyy4kirthlsuDev2LZcXjYXWfOHwHdCLUQnfJH8T2sxWDNjFLQycaCIXwQLOyw2Kem38VgxrYfG0hzg==", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "google-closure-compiler-linux": "^20181008.0.0", + "google-closure-compiler-osx": "^20181008.0.0", + "minimist": "^1.2.0", + "vinyl": "^2.0.1", + "vinyl-sourcemaps-apply": "^0.2.0" + } + }, + "google-closure-compiler-linux": { + "version": "20181008.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20181008.0.0.tgz", + "integrity": "sha512-k8njGfH2uzWJiRPPvUxM7MJB28gPrf4kI2bbuiF0gJk/1arXcWCPGjLD6pzCU0UylMy52MUXLgsIpRorqf2brw==", + "dev": true, + "optional": true + }, + "google-closure-compiler-osx": { + "version": "20181008.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20181008.0.0.tgz", + "integrity": "sha512-xzf/yH/4MXdb6GbP84iHnpcVCOPBbH0gMVOs0JhR/KbrQh+DlJU+Y8Z/DQzTkw9HgD650R2/WZmBknURyg9OTw==", + "dev": true, + "optional": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + } } }, "graceful-fs": { @@ -3075,6 +3176,18 @@ "concat-with-sourcemaps": "^1.0.0", "through2": "^2.0.0", "vinyl": "^2.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "gulp-insert": { @@ -3170,6 +3283,18 @@ "concat-stream": "^1.6.2", "lodash.template": "^4.4.0", "through2": "^2.0.3" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "gulplog": { @@ -3204,6 +3329,23 @@ "function-bind": "^1.1.1" } }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3469,12 +3611,6 @@ } } }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3565,12 +3701,6 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-generator-function": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", - "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", - "dev": true - }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -3720,30 +3850,6 @@ "textextensions": "2" } }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } - } - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4155,18 +4261,6 @@ "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", "dev": true }, - "lolex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", - "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -4723,18 +4817,6 @@ "isobject": "^3.0.0" } }, - "object.entries": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, "object.getownpropertydescriptors": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", @@ -5103,108 +5185,6 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "promises-aplus-tests": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/promises-aplus-tests/-/promises-aplus-tests-2.1.2.tgz", - "integrity": "sha1-drfFY4locghhlpz7zYeVr9J0iFw=", - "dev": true, - "requires": { - "mocha": "^2.5.3", - "sinon": "^1.10.3", - "underscore": "~1.8.3" - }, - "dependencies": { - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true - }, - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - } - }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", - "dev": true, - "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true - }, - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", - "dev": true - } - } - }, "psl": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", @@ -5384,6 +5364,18 @@ "remove-bom-buffer": "^3.0.0", "safe-buffer": "^5.1.0", "through2": "^2.0.3" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "remove-trailing-separator": { @@ -5642,12 +5634,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "samsam": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", - "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", - "dev": true - }, "saxes": { "version": "3.1.11", "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", @@ -5759,30 +5745,12 @@ "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", "dev": true }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "sinon": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", - "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", - "dev": true, - "requires": { - "formatio": "1.1.1", - "lolex": "1.3.2", - "samsam": "1.1.2", - "util": ">=0.10.3 <1" - } - }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -6300,13 +6268,12 @@ "dev": true }, "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "readable-stream": "2 || 3" } }, "through2-filter": { @@ -6317,6 +6284,18 @@ "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "time-stamp": { @@ -6344,12 +6323,6 @@ "is-negated-glob": "^1.0.0" } }, - "to-iso-string": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", - "dev": true - }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -6399,6 +6372,18 @@ "dev": true, "requires": { "through2": "^2.0.3" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "tough-cookie": { @@ -6632,19 +6617,6 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "util": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.1.tgz", - "integrity": "sha512-MREAtYOp+GTt9/+kwf00IYoHZyjM8VU4aVrkzUlejyqaIjd2GztVl5V9hGXKlvBKE3gENn/FMfHE5v6hElXGcQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "object.entries": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6728,6 +6700,18 @@ "value-or-function": "^3.0.0", "vinyl": "^2.0.0", "vinyl-sourcemap": "^1.1.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } } }, "vinyl-sourcemap": { diff --git a/package.json b/package.json index 2f8d69558..9920f9e9a 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "eslint-plugin-es5": "^1.4.1", "fs": "0.0.1-security", "google-closure-compiler": "^20191027.0.0", - "google-closure-library": "^20191027.0.0", + "google-closure-deps": "20190121.0.0", "gulp": "^4.0.2", "gulp-concat": "^2.6.1", "gulp-insert": "^0.5.0", @@ -71,6 +71,7 @@ "pngjs": "^3.4.0", "selenium-standalone": "^6.16.0", "rimraf": "^2.6.3", + "through2": "^3.0.1", "typescript-closure-tools": "^0.0.7", "webdriverio": "^5.11.5", "yargs": "^14.0.0" From 9d6f4c81771e8cd2ad8ca7d1fff31e7df2ccf1b6 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 12 Nov 2019 11:50:34 -0800 Subject: [PATCH 181/343] Fix types and review comments --- core/field.js | 4 ++-- core/field_textinput.js | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/core/field.js b/core/field.js index ae622802e..57e957b91 100644 --- a/core/field.js +++ b/core/field.js @@ -213,7 +213,7 @@ Blockly.Field.prototype.visible_ = true; /** * The element the click handler is bound to. * @type {Element} - * @private + * @protected */ Blockly.Field.prototype.clickTarget_ = null; @@ -958,7 +958,7 @@ Blockly.Field.prototype.getClickTarget_ = function() { * Return the absolute coordinates of the top-left corner of this field. * The origin (0,0) is the top-left corner of the page body. * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. - * @private + * @protected */ Blockly.Field.prototype.getAbsoluteXY_ = function() { return Blockly.utils.style.getPageOffset( diff --git a/core/field_textinput.js b/core/field_textinput.js index 28976de79..659e2107b 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -88,7 +88,7 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { /** * Whether the field should consider the whole parent block to be its click * target. - * @type {boolean} + * @type {?boolean} */ this.fullBlockClickTarget_ = false; }; @@ -136,8 +136,7 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) { }; /** - * Create the block UI for this field. - * @package + * @override */ Blockly.FieldTextInput.prototype.initView = function() { var renderer = this.sourceBlock_.workspace.getRenderer(); @@ -342,6 +341,16 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { htmlInput.style.fontSize = fontSize; var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * this.workspace_.scale) + 'px'; + + if (this.fullBlockClickTarget_) { + var bBox = this.getScaledBBox(); + // Override border radius. + borderRadius = (bBox.bottom - bBox.top) / 2; + // Pull stroke colour from the existing shadow block + var strokeColour = this.sourceBlock_.style.colourTertiary; + div.style.borderColor = strokeColour; + } + htmlInput.style.borderRadius = borderRadius; div.appendChild(htmlInput); @@ -349,14 +358,6 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { htmlInput.untypedDefaultValue_ = this.value_; htmlInput.oldValue_ = null; - if (this.fullBlockClickTarget_) { - var bBox = this.getScaledBBox(); - var borderRadius = (bBox.bottom - bBox.top) / 2; - htmlInput.style.borderRadius = borderRadius + 'px'; - // Pull stroke colour from the existing shadow block - var strokeColour = this.sourceBlock_.style.colourTertiary; - div.style.borderColor = strokeColour; - } if (Blockly.utils.userAgent.GECKO) { // In FF, ensure the browser reflows before resizing to avoid issue #2777. From a9acd532f007f939e605420d77c686e21a1ff63d Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 12 Nov 2019 11:22:38 -0800 Subject: [PATCH 182/343] Pull comment CSS into comment modules. --- core/comment.js | 18 +++++++++ core/css.js | 70 ----------------------------------- core/workspace_comment_svg.js | 65 ++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 70 deletions(-) diff --git a/core/comment.js b/core/comment.js index ce4dbf2bc..8fe065aeb 100644 --- a/core/comment.js +++ b/core/comment.js @@ -413,3 +413,21 @@ Blockly.Comment.prototype.dispose = function() { this.block_.comment = null; Blockly.Icon.prototype.dispose.call(this); }; + +/** + * CSS for block comment. See css.js for use. + */ +Blockly.Css.register([ + /* eslint-disable indent */ + '.blocklyCommentTextarea {', + 'background-color: #fef49c;', + 'border: 0;', + 'outline: 0;', + 'margin: 0;', + 'padding: 3px;', + 'resize: none;', + 'display: block;', + 'overflow: hidden;', + '}' + /* eslint-enable indent */ +]); diff --git a/core/css.js b/core/css.js index 761ac9e39..110d4bd5d 100644 --- a/core/css.js +++ b/core/css.js @@ -412,76 +412,6 @@ Blockly.Css.CONTENT = [ 'padding: 0;', '}', - '.blocklyCommentForeignObject {', - 'position: relative;', - 'z-index: 0;', - '}', - - '.blocklyCommentRect {', - 'fill: #E7DE8E;', - 'stroke: #bcA903;', - 'stroke-width: 1px', - '}', - - '.blocklyCommentTarget {', - 'fill: transparent;', - 'stroke: #bcA903;', - '}', - - '.blocklyCommentTargetFocused {', - 'fill: none;', - '}', - - '.blocklyCommentHandleTarget {', - 'fill: none;', - '}', - - '.blocklyCommentHandleTargetFocused {', - 'fill: transparent;', - '}', - - '.blocklyFocused>.blocklyCommentRect {', - 'fill: #B9B272;', - 'stroke: #B9B272;', - '}', - - '.blocklySelected>.blocklyCommentTarget {', - 'stroke: #fc3;', - 'stroke-width: 3px;', - '}', - - - '.blocklyCommentTextarea {', - 'background-color: #fef49c;', - 'border: 0;', - 'outline: 0;', - 'margin: 0;', - 'padding: 3px;', - 'resize: none;', - 'display: block;', - 'overflow: hidden;', - '}', - - '.blocklyCommentDeleteIcon {', - 'cursor: pointer;', - 'fill: #000;', - 'display: none', - '}', - - '.blocklySelected > .blocklyCommentDeleteIcon {', - 'display: block', - '}', - - '.blocklyDeleteIconShape {', - 'fill: #000;', - 'stroke: #000;', - 'stroke-width: 1px;', - '}', - - '.blocklyDeleteIconShape.blocklyDeleteIconHighlighted {', - 'stroke: #fc3;', - '}', - '.blocklyHtmlInput {', 'border: none;', 'border-radius: 4px;', diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index d8d79ff00..39d7566b2 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -610,3 +610,68 @@ Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) { element.setAttribute('w', this.getWidth()); return element; }; + +/** + * CSS for workspace comment. See css.js for use. + */ +Blockly.Css.register([ + /* eslint-disable indent */ + '.blocklyCommentForeignObject {', + 'position: relative;', + 'z-index: 0;', + '}', + + '.blocklyCommentRect {', + 'fill: #E7DE8E;', + 'stroke: #bcA903;', + 'stroke-width: 1px', + '}', + + '.blocklyCommentTarget {', + 'fill: transparent;', + 'stroke: #bcA903;', + '}', + + '.blocklyCommentTargetFocused {', + 'fill: none;', + '}', + + '.blocklyCommentHandleTarget {', + 'fill: none;', + '}', + + '.blocklyCommentHandleTargetFocused {', + 'fill: transparent;', + '}', + + '.blocklyFocused>.blocklyCommentRect {', + 'fill: #B9B272;', + 'stroke: #B9B272;', + '}', + + '.blocklySelected>.blocklyCommentTarget {', + 'stroke: #fc3;', + 'stroke-width: 3px;', + '}', + + '.blocklyCommentDeleteIcon {', + 'cursor: pointer;', + 'fill: #000;', + 'display: none', + '}', + + '.blocklySelected > .blocklyCommentDeleteIcon {', + 'display: block', + '}', + + '.blocklyDeleteIconShape {', + 'fill: #000;', + 'stroke: #000;', + 'stroke-width: 1px;', + '}', + + '.blocklyDeleteIconShape.blocklyDeleteIconHighlighted {', + 'stroke: #fc3;', + '}' + /* eslint-enable indent */ +]); From a15d9611d0cbc1f8a698d0c67c0b378e8b1e2eb9 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 12 Nov 2019 11:46:27 -0800 Subject: [PATCH 183/343] Add missing requires. --- core/block.js | 3 ++- core/block_svg.js | 2 ++ core/comment.js | 1 + core/gesture.js | 2 ++ core/inject.js | 2 ++ core/keyboard_nav/cursor.js | 1 + core/keyboard_nav/cursor_svg.js | 1 + core/keyboard_nav/flyout_cursor.js | 1 + core/keyboard_nav/key_map.js | 2 ++ core/mutator.js | 1 + core/options.js | 1 + core/workspace_comment_svg.js | 1 + core/workspace_svg.js | 2 +- 13 files changed, 18 insertions(+), 2 deletions(-) diff --git a/core/block.js b/core/block.js index 08a509203..015b2ade6 100644 --- a/core/block.js +++ b/core/block.js @@ -31,11 +31,12 @@ goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.BlockDelete'); goog.require('Blockly.Events.BlockMove'); goog.require('Blockly.Extensions'); +goog.require('Blockly.fieldRegistry'); goog.require('Blockly.Input'); +goog.require('Blockly.navigation'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.object'); -goog.require('Blockly.fieldRegistry'); goog.require('Blockly.utils.string'); goog.require('Blockly.Workspace'); diff --git a/core/block_svg.js b/core/block_svg.js index cfcb3d6e6..d36187234 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -23,6 +23,7 @@ goog.provide('Blockly.BlockSvg'); +goog.require('Blockly.ASTNode'); goog.require('Blockly.Block'); goog.require('Blockly.blockAnimations'); goog.require('Blockly.blockRendering.IPathObject'); @@ -31,6 +32,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Events.BlockMove'); goog.require('Blockly.Msg'); +goog.require('Blockly.navigation'); goog.require('Blockly.RenderedConnection'); goog.require('Blockly.TabNavigateCursor'); goog.require('Blockly.Tooltip'); diff --git a/core/comment.js b/core/comment.js index 8fe065aeb..b2ef69bf7 100644 --- a/core/comment.js +++ b/core/comment.js @@ -24,6 +24,7 @@ goog.provide('Blockly.Comment'); goog.require('Blockly.Bubble'); +goog.require('Blockly.Css'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); diff --git a/core/gesture.js b/core/gesture.js index 6e25b9051..0547fe712 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -24,6 +24,7 @@ goog.provide('Blockly.Gesture'); +goog.require('Blockly.ASTNode'); goog.require('Blockly.blockAnimations'); goog.require('Blockly.BlockDragger'); goog.require('Blockly.BubbleDragger'); @@ -31,6 +32,7 @@ goog.require('Blockly.constants'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.FlyoutDragger'); +goog.require('Blockly.navigation'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); diff --git a/core/inject.js b/core/inject.js index 3bec1b7f5..b7c8d3518 100644 --- a/core/inject.js +++ b/core/inject.js @@ -29,9 +29,11 @@ goog.require('Blockly.Css'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Events'); goog.require('Blockly.Grid'); +goog.require('Blockly.Msg'); goog.require('Blockly.Options'); goog.require('Blockly.ScrollbarPair'); goog.require('Blockly.Tooltip'); +goog.require('Blockly.user.keyMap'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); diff --git a/core/keyboard_nav/cursor.js b/core/keyboard_nav/cursor.js index 8847df3fa..861fe04b5 100644 --- a/core/keyboard_nav/cursor.js +++ b/core/keyboard_nav/cursor.js @@ -24,6 +24,7 @@ goog.provide('Blockly.Cursor'); +goog.require('Blockly.ASTNode'); goog.require('Blockly.navigation'); /** diff --git a/core/keyboard_nav/cursor_svg.js b/core/keyboard_nav/cursor_svg.js index 329059ba7..68c10e6c8 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/keyboard_nav/cursor_svg.js @@ -23,6 +23,7 @@ goog.provide('Blockly.CursorSvg'); +goog.require('Blockly.ASTNode'); goog.require('Blockly.Cursor'); goog.require('Blockly.utils.object'); diff --git a/core/keyboard_nav/flyout_cursor.js b/core/keyboard_nav/flyout_cursor.js index 4fa6c4299..9208a24fe 100644 --- a/core/keyboard_nav/flyout_cursor.js +++ b/core/keyboard_nav/flyout_cursor.js @@ -25,6 +25,7 @@ goog.provide('Blockly.FlyoutCursor'); goog.require('Blockly.Cursor'); +goog.require('Blockly.navigation'); goog.require('Blockly.utils.object'); diff --git a/core/keyboard_nav/key_map.js b/core/keyboard_nav/key_map.js index 81f92eb59..8f3ecbef5 100644 --- a/core/keyboard_nav/key_map.js +++ b/core/keyboard_nav/key_map.js @@ -24,6 +24,8 @@ goog.provide('Blockly.user.keyMap'); +// TODO: Fix circular dependency. +// goog.require('Blockly.navigation'); goog.require('Blockly.utils.KeyCodes'); goog.require('Blockly.utils.object'); diff --git a/core/mutator.js b/core/mutator.js index 006aea0b8..decb81f3a 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -29,6 +29,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); +goog.require('Blockly.navigation'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.global'); diff --git a/core/options.js b/core/options.js index d2596c392..856bd4ce4 100644 --- a/core/options.js +++ b/core/options.js @@ -25,6 +25,7 @@ goog.provide('Blockly.Options'); goog.require('Blockly.Theme'); goog.require('Blockly.Themes.Classic'); +goog.require('Blockly.user.keyMap'); goog.require('Blockly.utils.userAgent'); goog.require('Blockly.Xml'); diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 39d7566b2..80916a837 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -23,6 +23,7 @@ goog.provide('Blockly.WorkspaceCommentSvg'); +goog.require('Blockly.Css'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index da6eacaf4..d1b3aa772 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -32,6 +32,7 @@ goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Gesture'); goog.require('Blockly.Grid'); goog.require('Blockly.Msg'); +goog.require('Blockly.navigation'); goog.require('Blockly.Options'); goog.require('Blockly.ThemeManager'); goog.require('Blockly.Themes.Classic'); @@ -2643,4 +2644,3 @@ Blockly.WorkspaceSvg.prototype.getAudioManager = function() { Blockly.WorkspaceSvg.prototype.getGrid = function() { return this.grid_; }; - From 9dc46ce2924ca5bd58488ae246dde6df8b1caf44 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 12 Nov 2019 16:46:33 -0800 Subject: [PATCH 184/343] Set statement input height to be the max of the default statement input and the row height. (#3436) --- core/renderers/common/info.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index d2f7efe7e..8ebe44a0c 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -590,6 +590,7 @@ Blockly.blockRendering.RenderInfo.prototype.alignStatementRow_ = function(row) { var rightCornerWidth = this.constants_.INSIDE_CORNERS.rightWidth || 0; desiredWidth = this.width - this.startX - rightCornerWidth; statementInput.width += (desiredWidth - currentWidth); + statementInput.height = Math.max(statementInput.height, row.height); row.width += (desiredWidth - currentWidth); row.widthWithConnectedBlocks = Math.max(row.width, this.statementEdge + row.connectedBlockWidths); From ed79ea6d94f5b017246ec881c48d813a330ab7a2 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 13 Nov 2019 10:38:29 -0800 Subject: [PATCH 185/343] Fix zelos input outline rendering in RTL (#3435) --- core/renderers/zelos/path_object.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js index b2f7ba3c6..e840c4efa 100644 --- a/core/renderers/zelos/path_object.js +++ b/core/renderers/zelos/path_object.js @@ -85,6 +85,18 @@ Blockly.zelos.PathObject.prototype.setPath = function(pathString) { } }; +/** + * @override + */ +Blockly.zelos.PathObject.prototype.flipRTL = function() { + Blockly.zelos.PathObject.superClass_.flipRTL.call(this); + // Mirror each input outline path. + for (var i = 0, keys = Object.keys(this.outlines_), + key; (key = keys[i]); i++) { + this.outlines_[key].setAttribute('transform', 'scale(-1 1)'); + } +}; + /** * @override */ From 03e75a100c15bcd6b13e9f50c19b4e3450f21d44 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 13 Nov 2019 11:08:37 -0800 Subject: [PATCH 186/343] Delete unused property. --- core/renderers/common/path_object.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 9766b8ff9..2ff2b29f2 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -58,18 +58,6 @@ Blockly.blockRendering.PathObject = function(root, constants) { this.svgPath = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPath'}, this.svgRoot); - // The light and dark paths need to exist (for now) because there is colouring - // code in block_svg that depends on them. But we will always set them to - // display: none, and eventually we want to remove them entirely. - - /** - * The light path of the block. - * @type {SVGElement} - * @package - */ - this.svgPathLight = Blockly.utils.dom.createSvgElement('path', - {'class': 'blocklyPathLight'}, this.svgRoot); - /** * The style object to use when colouring block paths. * @type {!Blockly.Theme.BlockStyle} @@ -85,7 +73,6 @@ Blockly.blockRendering.PathObject = function(root, constants) { */ Blockly.blockRendering.PathObject.prototype.setPath = function(pathString) { this.svgPath.setAttribute('d', pathString); - this.svgPathLight.style.display = 'none'; }; /** From 6dd07ec44dea25cfd1ed3c77638bc130ead1590d Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 13 Nov 2019 11:23:10 -0800 Subject: [PATCH 187/343] Move cursorSvg and markerSvg to pathObject --- core/block_svg.js | 36 +----------------- core/renderers/common/i_path_object.js | 16 ++++++++ core/renderers/common/path_object.js | 52 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index d36187234..ce1b2e47d 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -109,22 +109,6 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { if (this.svgGroup_.dataset) { this.svgGroup_.dataset['id'] = this.id; } - - /** - * 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} - * @private - */ - this.cursorSvg_ = null; - - /** - * 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} - * @private - */ - this.markerSvg_ = null; }; Blockly.utils.object.inherits(Blockly.BlockSvg, Blockly.Block); @@ -1700,13 +1684,7 @@ Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() { * @package */ Blockly.BlockSvg.prototype.setCursorSvg = function(cursorSvg) { - if (!cursorSvg) { - this.cursorSvg_ = null; - return; - } - - this.svgGroup_.appendChild(cursorSvg); - this.cursorSvg_ = cursorSvg; + this.pathObject.setCursorSvg(cursorSvg); }; /** @@ -1716,17 +1694,7 @@ Blockly.BlockSvg.prototype.setCursorSvg = function(cursorSvg) { * @package */ Blockly.BlockSvg.prototype.setMarkerSvg = function(markerSvg) { - if (!markerSvg) { - this.markerSvg_ = null; - return; - } - - if (this.cursorSvg_) { - this.svgGroup_.insertBefore(markerSvg, this.cursorSvg_); - } else { - this.svgGroup_.appendChild(markerSvg); - } - this.markerSvg_ = markerSvg; + this.pathObject.setMarkerSvg(markerSvg); }; /** diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js index cafb1d537..bc9bc65e6 100644 --- a/core/renderers/common/i_path_object.js +++ b/core/renderers/common/i_path_object.js @@ -66,6 +66,22 @@ Blockly.blockRendering.IPathObject.prototype.setStyle; */ Blockly.blockRendering.IPathObject.prototype.flipRTL; +/** + * Add the cursor svg to this block's svg group. + * @param {SVGElement} cursorSvg The svg root of the cursor to be added to the + * block svg group. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.setCursorSvg; + +/** + * Add the marker svg to this block's svg group. + * @param {SVGElement} markerSvg The svg root of the marker to be added to the + * block svg group. + * @package + */ +Blockly.blockRendering.IPathObject.prototype.setMarkerSvg; + /** * Set whether the block shows a highlight or not. Block highlighting is * often used to visually mark blocks currently being executed. diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 2ff2b29f2..7b6fbe48f 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -64,6 +64,22 @@ Blockly.blockRendering.PathObject = function(root, constants) { * @package */ this.style = Blockly.Theme.createBlockStyle('#000000'); + + /** + * 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} + * @private + */ + this.cursorSvg_ = null; + + /** + * 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} + * @private + */ + this.markerSvg_ = null; }; /** @@ -84,6 +100,42 @@ Blockly.blockRendering.PathObject.prototype.flipRTL = function() { this.svgPath.setAttribute('transform', 'scale(-1 1)'); }; +/** + * Add the cursor svg to this block's svg group. + * @param {SVGElement} cursorSvg The svg root of the cursor to be added to the + * block svg group. + * @package + */ +Blockly.blockRendering.PathObject.prototype.setCursorSvg = function(cursorSvg) { + if (!cursorSvg) { + this.cursorSvg_ = null; + return; + } + + this.svgRoot.appendChild(cursorSvg); + this.cursorSvg_ = cursorSvg; +}; + +/** + * Add the marker svg to this block's svg group. + * @param {SVGElement} markerSvg The svg root of the marker to be added to the + * block svg group. + * @package + */ +Blockly.blockRendering.PathObject.prototype.setMarkerSvg = function(markerSvg) { + if (!markerSvg) { + this.markerSvg_ = null; + return; + } + + if (this.cursorSvg_) { + this.svgRoot.insertBefore(markerSvg, this.cursorSvg_); + } else { + this.svgRoot.appendChild(markerSvg); + } + this.markerSvg_ = markerSvg; +}; + /** * Apply the stored colours to the block's path, taking into account whether * the paths belong to a shadow block. From 7137c1144907d9e7a9265ba500a8a4f258dd0c9f Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 13 Nov 2019 16:27:27 -0800 Subject: [PATCH 188/343] Add Node 12 back to our travis matrix https://github.com/google/blockly/issues/2582 means we should be fine now. Needs travis to run to check. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b5f109f00..643c96a63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ dist: xenial node_js: - 8 - 10 + - 12 addons: chrome: stable firefox: latest From 2dea7038d5b5221791ee3419e6771d9ec60352ba Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 13 Nov 2019 16:41:35 -0800 Subject: [PATCH 189/343] Moves field layout constants into the renderer (#3437) * Add field constants into renderer constants --- core/field.js | 60 +++++----------- core/field_checkbox.js | 19 +---- core/field_colour.js | 28 +------- core/field_dropdown.js | 27 ++++--- core/field_label.js | 13 +--- core/field_multilineinput.js | 9 ++- core/field_textinput.js | 31 ++++---- core/renderers/common/constants.js | 75 ++++++++++++++++++++ core/renderers/geras/constants.js | 5 ++ core/renderers/zelos/constants.js | 15 ++++ demos/custom-fields/turtle/field_turtle.js | 7 +- tests/mocha/field_checkbox_test.js | 4 ++ tests/mocha/field_label_serializable_test.js | 9 +++ tests/mocha/field_label_test.js | 9 +++ 14 files changed, 184 insertions(+), 127 deletions(-) diff --git a/core/field.js b/core/field.js index 3853b26f6..3055d06d0 100644 --- a/core/field.js +++ b/core/field.js @@ -31,9 +31,10 @@ goog.require('Blockly.Gesture'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.Size'); +goog.require('Blockly.utils.style'); goog.require('Blockly.utils.userAgent'); -goog.require('Blockly.utils.style'); +goog.requireType('Blockly.blockRendering.ConstantProvider'); /** @@ -141,41 +142,6 @@ Blockly.Field = function(value, opt_validator, opt_config) { opt_validator && this.setValidator(opt_validator); }; -/** - * The default height of the border rect on any field. - * @type {number} - * @package - */ -Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT = 16; - -/** - * The default height of the text element on any field. - * @type {number} - * @package - */ -Blockly.Field.TEXT_DEFAULT_HEIGHT = 12.5; - -/** - * The padding added to the width by the border rect, if it exists. - * @type {number} - * @package - */ -Blockly.Field.X_PADDING = 10; - -/** - * The padding added to the height by the border rect, if it exists. - * @type {number} - * @package - */ -Blockly.Field.Y_PADDING = 10; - -/** - * The default offset between the left of the text element and the left of the - * border rect, if the border rect exists. - * @type {number} - */ -Blockly.Field.DEFAULT_TEXT_OFFSET = Blockly.Field.X_PADDING / 2; - /** * Name of field. Unique within each block. * Static labels are usually unnamed. @@ -354,9 +320,9 @@ Blockly.Field.prototype.initModel = function() { */ Blockly.Field.prototype.createBorderRect_ = function() { this.size_.height = - Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT); + Math.max(this.size_.height, this.constants_.FIELD_BORDER_RECT_HEIGHT); this.size_.width = - Math.max(this.size_.width, Blockly.Field.X_PADDING); + Math.max(this.size_.width, this.constants_.FIELD_BORDER_RECT_X_PADDING * 2); this.borderRect_ = /** @type {!SVGRectElement} **/ (Blockly.utils.dom.createSvgElement('rect', { @@ -376,15 +342,25 @@ Blockly.Field.prototype.createBorderRect_ = function() { * @protected */ Blockly.Field.prototype.createTextElement_ = function() { - var xOffset = this.borderRect_ ? Blockly.Field.DEFAULT_TEXT_OFFSET : 0; + var xOffset = this.borderRect_ ? + this.constants_.FIELD_BORDER_RECT_X_PADDING : 0; + this.size_.height = Math.max(this.size_.height, + this.constants_.FIELD_TEXT_BASELINE_CENTER ? + this.constants_.FIELD_TEXT_HEIGHT : + this.constants_.FIELD_TEXT_BASELINE_Y); this.textElement_ = /** @type {!SVGTextElement} **/ (Blockly.utils.dom.createSvgElement('text', { 'class': 'blocklyText', - // The y position is the baseline of the text. - 'y': Blockly.Field.TEXT_DEFAULT_HEIGHT, + 'y': this.size_.height / 2, 'x': xOffset }, this.fieldGroup_)); + if (this.constants_.FIELD_TEXT_BASELINE_CENTER) { + this.textElement_.setAttribute('dominant-baseline', 'central'); + } else { + this.textElement_.setAttribute('dy', + this.constants_.FIELD_TEXT_BASELINE_Y - this.size_.height / 2); + } this.textContent_ = document.createTextNode(''); this.textElement_.appendChild(this.textContent_); }; @@ -658,7 +634,7 @@ Blockly.Field.prototype.updateSize_ = function() { this.constants_.FIELD_TEXT_FONTFAMILY); var totalWidth = textWidth; if (this.borderRect_) { - totalWidth += Blockly.Field.X_PADDING; + totalWidth += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; this.borderRect_.setAttribute('width', totalWidth); } this.size_.width = totalWidth; diff --git a/core/field_checkbox.js b/core/field_checkbox.js index e3c83fc78..0d9c362f1 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -91,20 +91,6 @@ Blockly.FieldCheckbox.WIDTH = 15; */ Blockly.FieldCheckbox.CHECK_CHAR = '\u2713'; -/** - * Used to correctly position the check mark. - * @type {number} - * @const - */ -Blockly.FieldCheckbox.CHECK_X_OFFSET = Blockly.Field.DEFAULT_TEXT_OFFSET - 3; - -/** - * Used to correctly position the check mark. - * @type {number} - * @const - */ -Blockly.FieldCheckbox.CHECK_Y_OFFSET = 14; - /** * Serializable fields are saved by the XML renderer, non-serializable fields * are not. Editable fields should also be serializable. @@ -145,8 +131,9 @@ Blockly.FieldCheckbox.prototype.configure_ = function(config) { Blockly.FieldCheckbox.prototype.initView = function() { Blockly.FieldCheckbox.superClass_.initView.call(this); - this.textElement_.setAttribute('x', Blockly.FieldCheckbox.CHECK_X_OFFSET); - this.textElement_.setAttribute('y', Blockly.FieldCheckbox.CHECK_Y_OFFSET); + this.textElement_.setAttribute('x', this.constants_.FIELD_CHECKBOX_X_OFFSET); + this.textElement_.setAttribute('y', this.constants_.FIELD_CHECKBOX_Y_OFFSET); + this.textElement_.removeAttribute('dominant-baseline'); Blockly.utils.dom.addClass(this.textElement_, 'blocklyCheckbox'); this.textContent_.nodeValue = diff --git a/core/field_colour.js b/core/field_colour.js index 54204553e..76701eeb5 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -57,15 +57,6 @@ Blockly.FieldColour = function(opt_value, opt_validator, opt_config) { this, opt_value || Blockly.FieldColour.COLOURS[0], opt_validator, opt_config); - /** - * The size of the area rendered by the field. - * @type {Blockly.utils.Size} - * @protected - * @override - */ - this.size_ = new Blockly.utils.Size(Blockly.FieldColour.DEFAULT_WIDTH, - Blockly.FieldColour.DEFAULT_HEIGHT); - /** * The field's colour picker element. * @type {Element} @@ -128,22 +119,6 @@ Blockly.FieldColour.fromJson = function(options) { return new Blockly.FieldColour(options['colour'], undefined, options); }; -/** - * Default width of a colour field. - * @type {number} - * @private - * @const - */ -Blockly.FieldColour.DEFAULT_WIDTH = 26; - -/** - * Default height of a colour field. - * @type {number} - * @private - * @const - */ -Blockly.FieldColour.DEFAULT_HEIGHT = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT; - /** * Serializable fields are saved by the XML renderer, non-serializable fields * are not. Editable fields should also be serializable. @@ -208,6 +183,9 @@ Blockly.FieldColour.prototype.configure_ = function(config) { * @package */ Blockly.FieldColour.prototype.initView = function() { + this.size_ = new Blockly.utils.Size( + this.constants_.FIELD_COLOUR_DEFAULT_WIDTH, + this.constants_.FIELD_COLOUR_DEFAULT_HEIGHT); this.createBorderRect_(); this.borderRect_.style['fillOpacity'] = '1'; this.borderRect_.style.fill = this.value_; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 8b7e7a93a..be570ad36 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -525,19 +525,20 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { // Height and width include the border rect. this.size_.height = imageHeight + Blockly.FieldDropdown.IMAGE_Y_PADDING; - this.size_.width = imageWidth + arrowWidth + Blockly.Field.X_PADDING; + var xPadding = this.constants_.FIELD_BORDER_RECT_X_PADDING; + this.size_.width = imageWidth + arrowWidth + xPadding * 2; if (this.sourceBlock_.RTL) { - var imageX = Blockly.Field.DEFAULT_TEXT_OFFSET + arrowWidth; - var arrowX = Blockly.Field.DEFAULT_TEXT_OFFSET - 1; + var imageX = xPadding + arrowWidth; + var arrowX = xPadding - 1; this.imageElement_.setAttribute('x', imageX); this.textElement_.setAttribute('x', arrowX); } else { var arrowX = - imageWidth + arrowWidth + Blockly.Field.DEFAULT_TEXT_OFFSET + 1; + imageWidth + arrowWidth + xPadding + 1; this.textElement_.setAttribute('text-anchor', 'end'); this.textElement_.setAttribute('x', arrowX); - this.imageElement_.setAttribute('x', Blockly.Field.DEFAULT_TEXT_OFFSET); + this.imageElement_.setAttribute('x', xPadding); } }; @@ -549,14 +550,24 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { // Retrieves the selected option to display through getText_. this.textContent_.nodeValue = this.getDisplayText_(); this.textElement_.setAttribute('text-anchor', 'start'); - this.textElement_.setAttribute('x', Blockly.Field.DEFAULT_TEXT_OFFSET); + this.textElement_.setAttribute('x', + this.constants_.FIELD_BORDER_RECT_X_PADDING); // Height and width include the border rect. - this.size_.height = Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT; + this.size_.height = Math.max( + this.constants_.FIELD_DROPDOWN_BORDER_RECT_HEIGHT, + this.constants_.FIELD_TEXT_HEIGHT + + this.constants_.FIELD_BORDER_RECT_Y_PADDING * 2); this.size_.width = Blockly.utils.dom.getFastTextWidth(this.textElement_, this.constants_.FIELD_TEXT_FONTSIZE, this.constants_.FIELD_TEXT_FONTWEIGHT, this.constants_.FIELD_TEXT_FONTFAMILY) + - Blockly.Field.X_PADDING; + this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; + + this.textElement_.setAttribute('y', this.size_.height / 2); + if (!this.constants_.FIELD_TEXT_BASELINE_CENTER) { + this.textElement_.setAttribute('dy', + this.constants_.FIELD_TEXT_BASELINE_Y - this.size_.height / 2); + } }; /** diff --git a/core/field_label.js b/core/field_label.js index a7bf7d156..510a457d7 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -60,14 +60,6 @@ Blockly.FieldLabel = function(opt_value, opt_class, opt_config) { if (!opt_config) { // If the config was not passed use old configuration. this.class_ = opt_class || null; } - - /** - * The size of the area rendered by the field. - * @type {Blockly.utils.Size} - * @protected - * @override - */ - this.size_ = new Blockly.utils.Size(0, Blockly.Field.TEXT_DEFAULT_HEIGHT); }; Blockly.utils.object.inherits(Blockly.FieldLabel, Blockly.Field); @@ -105,10 +97,9 @@ Blockly.FieldLabel.prototype.configure_ = function(config) { */ Blockly.FieldLabel.prototype.initView = function() { this.createTextElement_(); - // The y attribute of an SVG text element is the baseline. - this.textElement_.setAttribute('y', this.size_.height); if (this.class_) { - Blockly.utils.dom.addClass(this.textElement_, this.class_); + Blockly.utils.dom.addClass( + /** @type {!SVGTextElement} */ (this.textElement_), this.class_); } }; diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 11cf73fb1..df4293e5b 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -152,13 +152,12 @@ Blockly.FieldMultilineInput.prototype.render_ = function() { // Add in text elements into the group. var lines = this.getDisplayText_().split('\n'); - var yOffset = Blockly.Field.Y_PADDING / 2; var y = 0; for (var i = 0; i < lines.length; i++) { var span = Blockly.utils.dom.createSvgElement('text', { 'class': 'blocklyText blocklyMultilineText', - x: Blockly.Field.DEFAULT_TEXT_OFFSET, - y: y + yOffset, + x: this.constants_.FIELD_BORDER_RECT_X_PADDING, + y: y + this.constants_.FIELD_BORDER_RECT_Y_PADDING, dy: Blockly.FieldMultilineInput.LINE_HEIGHT / 2 }, this.textGroup_); span.appendChild(document.createTextNode(lines[i])); @@ -206,7 +205,7 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() { totalHeight += Blockly.FieldMultilineInput.LINE_HEIGHT; } if (this.borderRect_) { - totalWidth += Blockly.Field.X_PADDING; + totalWidth += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; this.borderRect_.setAttribute('width', totalWidth); this.borderRect_.setAttribute('height', totalHeight); } @@ -250,7 +249,7 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() { htmlInput.style.fontSize = fontSize; var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px'; htmlInput.style.borderRadius = borderRadius; - var padding = Blockly.Field.DEFAULT_TEXT_OFFSET * scale; + var padding = this.constants_.FIELD_BORDER_RECT_X_PADDING * scale; htmlInput.style.paddingLeft = padding + 'px'; htmlInput.style.width = 'calc(100% - ' + padding + 'px)'; htmlInput.style.lineHeight = diff --git a/core/field_textinput.js b/core/field_textinput.js index 4573d3e09..1cd030af5 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -85,19 +85,19 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { */ this.onKeyInputWrapper_ = null; - /** - * Whether the field should consider the whole parent block to be its click - * target. - * @type {?boolean} - */ - this.fullBlockClickTarget_ = false; - /** * Blur input event data. * @type {?Blockly.EventData} * @private */ this.onBlurInputWrapper_ = null; + + /** + * Whether the field should consider the whole parent block to be its click + * target. + * @type {?boolean} + */ + this.fullBlockClickTarget_ = false; }; Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field); @@ -146,8 +146,11 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) { * @override */ Blockly.FieldTextInput.prototype.initView = function() { - var renderer = this.sourceBlock_.workspace.getRenderer(); - if (renderer.getConstants().FULL_BLOCK_FIELDS) { + this.size_.height = Math.max(this.constants_.FIELD_BORDER_RECT_HEIGHT, + this.constants_.FIELD_TEXT_BASELINE_CENTER ? + this.constants_.FIELD_TEXT_HEIGHT : + this.constants_.FIELD_TEXT_BASELINE_Y); + if (this.constants_.FULL_BLOCK_FIELDS) { // Step one: figure out if this is the only field on this block. // Rendering is quite different in that case. var nFields = 0; @@ -173,16 +176,14 @@ Blockly.FieldTextInput.prototype.initView = function() { } if (this.fullBlockClickTarget_) { - // Don't create a border rect. - this.size_.height = - Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT); - this.size_.width = - Math.max(this.size_.width, Blockly.Field.X_PADDING); this.clickTarget_ = this.sourceBlock_.getSvgRoot(); } else { this.createBorderRect_(); } this.createTextElement_(); + if (this.constants_.FIELD_TEXT_BASELINE_CENTER) { + this.textElement_.setAttribute('dominant-baseline', 'central'); + } }; /** @@ -352,7 +353,7 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { if (this.fullBlockClickTarget_) { var bBox = this.getScaledBBox(); // Override border radius. - borderRadius = (bBox.bottom - bBox.top) / 2; + borderRadius = (bBox.bottom - bBox.top) / 2 + 'px'; // Pull stroke colour from the existing shadow block var strokeColour = this.sourceBlock_.style.colourTertiary; div.style.borderColor = strokeColour; diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index e7aa35efe..92eaf8c7d 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -25,6 +25,7 @@ goog.provide('Blockly.blockRendering.ConstantProvider'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.svgPaths'); +goog.require('Blockly.utils.userAgent'); /** @@ -143,6 +144,12 @@ Blockly.blockRendering.ConstantProvider = function() { */ this.FIELD_TEXT_FONTSIZE = 11; + /** + * Height of text. + * @type {number} + */ + this.FIELD_TEXT_HEIGHT = 13; + /** * Text font weight. Should match blocklyText's font-weight in CSS. * @type {string} @@ -157,6 +164,74 @@ Blockly.blockRendering.ConstantProvider = function() { */ this.FIELD_TEXT_FONTFAMILY = 'sans-serif'; + /** + * A field's border rect corner radius. + * @type {number} + */ + this.FIELD_BORDER_RECT_RADIUS = 4; + + /** + * A field's border rect default height. + * @type {number} + */ + this.FIELD_BORDER_RECT_HEIGHT = 16; + + /** + * A field's border rect X padding. + * @type {number} + */ + this.FIELD_BORDER_RECT_X_PADDING = 5; + + /** + * A field's border rect Y padding. + * @type {number} + */ + this.FIELD_BORDER_RECT_Y_PADDING = 3; + + /** + * Field text baseline. This is only used if `FIELD_TEXT_BASELINE_CENTER` is + * set to false. + * @type {number} + */ + this.FIELD_TEXT_BASELINE_Y = 13; + + /** + * A field's text element's dominant baseline. + * @type {boolean} + */ + this.FIELD_TEXT_BASELINE_CENTER = + !Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE; + + /** + * A dropdown field's border rect height. + * @type {number} + */ + this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT; + + /** + * A colour field's default width. + * @type {number} + */ + this.FIELD_COLOUR_DEFAULT_WIDTH = 26; + + /** + * A colour field's default height. + * @type {number} + */ + this.FIELD_COLOUR_DEFAULT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT; + + /** + * A checkbox field's X offset. + * @type {number} + */ + this.FIELD_CHECKBOX_X_OFFSET = this.FIELD_BORDER_RECT_X_PADDING - 3; + + /** + * A checkbox field's Y offset. + * @type {number} + */ + this.FIELD_CHECKBOX_Y_OFFSET = 14; + /** * The ID of the emboss filter, or the empty string if no filter is set. * @type {string} diff --git a/core/renderers/geras/constants.js b/core/renderers/geras/constants.js index fd20f14ba..771a7fb57 100644 --- a/core/renderers/geras/constants.js +++ b/core/renderers/geras/constants.js @@ -37,6 +37,11 @@ goog.require('Blockly.utils.object'); Blockly.geras.ConstantProvider = function() { Blockly.geras.ConstantProvider.superClass_.constructor.call(this); + /** + * @override + */ + this.FIELD_TEXT_BASELINE_CENTER = false; + // The dark/shadow path in classic rendering is the same as the normal block // path, but translated down one and right one. this.DARK_PATH_OFFSET = 1; diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 1e1fb86b9..90f888969 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -127,6 +127,21 @@ Blockly.zelos.ConstantProvider = function() { */ this.DUMMY_INPUT_MIN_HEIGHT = 6 * this.GRID_UNIT; + /** + * @override + */ + this.FIELD_BORDER_RECT_RADIUS = this.CORNER_RADIUS; + + /** + * @override + */ + this.FIELD_BORDER_RECT_X_PADDING = 2 * this.GRID_UNIT; + + /** + * @override + */ + this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = 8 * this.GRID_UNIT; + /** * The ID of the highlight glow filter, or the empty string if no filter is * set. diff --git a/demos/custom-fields/turtle/field_turtle.js b/demos/custom-fields/turtle/field_turtle.js index 8a4a08301..ddce28417 100644 --- a/demos/custom-fields/turtle/field_turtle.js +++ b/demos/custom-fields/turtle/field_turtle.js @@ -88,9 +88,6 @@ CustomFields.FieldTurtle.prototype.CURSOR = 'pointer'; // May change if the turtle gets fancy enough. CustomFields.FieldTurtle.prototype.TEXT_OFFSET_X = 80; -// Padding that the border rect adds around the turtle and its name. -CustomFields.FieldTurtle.prototype.PADDING = Blockly.Field.X_PADDING; - // These are the different options for our turtle. Being declared this way // means they are static, and not translatable. If you want to do something // similar, but make it translatable you should set up your options like a @@ -320,8 +317,8 @@ CustomFields.FieldTurtle.prototype.updateSize_ = function() { var width = bbox.width; var height = bbox.height; if (this.borderRect_) { - width += this.PADDING; - height += this.PADDING; + width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; + height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; this.borderRect_.setAttribute('width', width); this.borderRect_.setAttribute('height', height); } diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js index 76084a63a..d9c3aa899 100644 --- a/tests/mocha/field_checkbox_test.js +++ b/tests/mocha/field_checkbox_test.js @@ -175,6 +175,10 @@ suite('Checkbox Fields', function() { suite('Check Character', function() { function assertCharacter(field, char) { field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + field.constants_ = { + FIELD_CHECKBOX_X_OFFSET: 2, + FIELD_CHECKBOX_Y_OFFSET: 2 + }; field.initView(); chai.assert(field.textContent_.nodeValue, char); } diff --git a/tests/mocha/field_label_serializable_test.js b/tests/mocha/field_label_serializable_test.js index adb0dc06d..911198038 100644 --- a/tests/mocha/field_label_serializable_test.js +++ b/tests/mocha/field_label_serializable_test.js @@ -27,12 +27,18 @@ suite('Label Serializable Fields', function() { } function assertHasClass(labelField, cssClass) { labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.constants_ = { + FIELD_TEXT_BASELINE_Y: 13 + }; labelField.initView(); chai.assert.isTrue(Blockly.utils.dom.hasClass( labelField.textElement_, cssClass)); } function assertDoesNotHaveClass(labelField, cssClass) { labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.constants_ = { + FIELD_TEXT_BASELINE_Y: 13 + }; labelField.initView(); chai.assert.isFalse(Blockly.utils.dom.hasClass( labelField.textElement_, cssClass)); @@ -216,6 +222,9 @@ suite('Label Serializable Fields', function() { test('setClass', function() { var field = new Blockly.FieldLabelSerializable(); field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + field.constants_ = { + FIELD_TEXT_BASELINE_Y: 13 + }; field.initView(); field.setClass('testClass'); // Don't call assertHasClass b/c we don't want to re-initialize. diff --git a/tests/mocha/field_label_test.js b/tests/mocha/field_label_test.js index b707a7252..1e3578eb0 100644 --- a/tests/mocha/field_label_test.js +++ b/tests/mocha/field_label_test.js @@ -27,12 +27,18 @@ suite('Label Fields', function() { } function assertHasClass(labelField, cssClass) { labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.constants_ = { + FIELD_TEXT_BASELINE_Y: 13 + }; labelField.initView(); chai.assert.isTrue(Blockly.utils.dom.hasClass( labelField.textElement_, cssClass)); } function assertDoesNotHaveClass(labelField, cssClass) { labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.constants_ = { + FIELD_TEXT_BASELINE_Y: 13 + }; labelField.initView(); chai.assert.isFalse(Blockly.utils.dom.hasClass( labelField.textElement_, cssClass)); @@ -205,6 +211,9 @@ suite('Label Fields', function() { test('setClass', function() { var field = new Blockly.FieldLabel(); field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + field.constants_ = { + FIELD_TEXT_BASELINE_Y: 13 + }; field.initView(); field.setClass('testClass'); // Don't call assertHasClass b/c we don't want to re-initialize. From f9dcb60f82ebc79a5fc60c35e79d4ad4eb2002ee Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 13 Nov 2019 17:14:28 -0800 Subject: [PATCH 190/343] Zelos replacement highlight (#3431) * Zelos replacement highlight --- core/block_svg.js | 11 +++++ core/css.js | 11 +++-- core/inject.js | 4 +- core/insertion_marker_manager.js | 8 +++- core/renderers/common/path_object.js | 7 --- core/renderers/common/renderer.js | 13 +++++ core/renderers/zelos/constants.js | 71 ++++++++++++++++++++++++++-- core/renderers/zelos/path_object.js | 14 ++++++ core/renderers/zelos/renderer.js | 7 +++ 9 files changed, 129 insertions(+), 17 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index ce1b2e47d..a30725695 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1728,3 +1728,14 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { this.pathObject.updateReplacementHighlight(add); }; + +/** + * Determine whether or not to highlight a connection. + * @param {Blockly.Connection} conn The connection on the input to determine + * whether or not to highlight. + * @return {boolean} Whether or not to highlight the connection. + * @package + */ +Blockly.BlockSvg.prototype.shouldHighlightConnection = function(conn) { + return this.workspace.getRenderer().shouldHighlightConnection(conn); +}; diff --git a/core/css.js b/core/css.js index 110d4bd5d..568adc530 100644 --- a/core/css.js +++ b/core/css.js @@ -254,6 +254,11 @@ Blockly.Css.CONTENT = [ 'stroke-width: 1;', '}', + '.injectionDiv:not(.zelos-renderer) .blocklySelected>.blocklyPath {', + 'stroke: #fc3;', + 'stroke-width: 3px;', + '}', + '.blocklySelected>.blocklyPathLight {', 'display: none;', '}', @@ -320,12 +325,12 @@ Blockly.Css.CONTENT = [ 'stroke: none', '}', - '.blocklyReplaceable .blocklyPath {', + '.injectionDiv:not(.zelos-renderer) .blocklyReplaceable .blocklyPath {', 'fill-opacity: .5;', '}', - '.blocklyReplaceable .blocklyPathLight,', - '.blocklyReplaceable .blocklyPathDark {', + '.injectionDiv:not(.zelos-renderer) .blocklyReplaceable .blocklyPathLight,', + '.injectionDiv:not(.zelos-renderer) .blocklyReplaceable .blocklyPathDark {', 'display: none;', '}', diff --git a/core/inject.js b/core/inject.js index b7c8d3518..f284dd571 100644 --- a/core/inject.js +++ b/core/inject.js @@ -164,7 +164,9 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, mainWorkspace.scale = options.zoomOptions.startScale; svg.appendChild(mainWorkspace.createDom('blocklyMainBackground')); - // Set the theme name on the injection div. + // Set the theme name and renderer name onto the injection div. + Blockly.utils.dom.addClass(mainWorkspace.getInjectionDiv(), + (mainWorkspace.options.renderer || 'geras') + '-renderer'); Blockly.utils.dom.addClass(mainWorkspace.getInjectionDiv(), mainWorkspace.getTheme().name + '-theme'); diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 2be5213a0..7c711991f 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -504,7 +504,9 @@ Blockly.InsertionMarkerManager.prototype.showPreview_ = function() { this.connectMarker_(); } // Also highlight the actual connection, as a nod to previous behaviour. - if (this.closestConnection_) { + if (this.closestConnection_ && this.closestConnection_.targetBlock() && + this.closestConnection_.targetBlock() + .shouldHighlightConnection(this.closestConnection_)) { this.closestConnection_.highlight(); } }; @@ -548,7 +550,9 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) * @private */ Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() { - if (this.closestConnection_) { + if (this.closestConnection_ && this.closestConnection_.targetBlock() && + this.closestConnection_.targetBlock() + .shouldHighlightConnection(this.closestConnection_)) { this.closestConnection_.unhighlight(); } if (this.highlightingBlock_) { diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 7b6fbe48f..7dd517de3 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -220,13 +220,6 @@ Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled, */ Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { this.setClass_('blocklySelected', enable); - if (enable) { - this.svgPath.setAttribute('stroke', '#fc3'); - this.svgPath.setAttribute('stroke-width', '3px'); - } else { - this.svgPath.setAttribute('stroke', ''); - this.svgPath.setAttribute('stroke-width', ''); - } }; /** diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index c6f16677c..a25e52825 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -139,6 +139,19 @@ Blockly.blockRendering.Renderer.prototype.getConstants = function() { (this.constants_)); }; +/** + * Determine whether or not to highlight a connection. + * @param {Blockly.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 */ + return true; +}; /* eslint-enable indent */ + /** * Render the block. * @param {!Blockly.BlockSvg} block The block to render. diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 90f888969..f982a6307 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -127,6 +127,11 @@ Blockly.zelos.ConstantProvider = function() { */ this.DUMMY_INPUT_MIN_HEIGHT = 6 * this.GRID_UNIT; + /** + * @override + */ + this.FULL_BLOCK_FIELDS = true; + /** * @override */ @@ -158,9 +163,19 @@ Blockly.zelos.ConstantProvider = function() { this.highlightGlowFilter_ = null; /** - * @override + * The ID of the highlight glow filter, or the empty string if no filter is + * set. + * @type {string} + * @package */ - this.FULL_BLOCK_FIELDS = true; + this.replacementGlowFilterId = ''; + + /** + * The element to use for a higlight glow, or null if not set. + * @type {SVGElement} + * @private + */ + this.replacementGlowFilter_ = null; }; Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider, Blockly.blockRendering.ConstantProvider); @@ -424,13 +439,13 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg) { }, highlightGlowFilter); // Set all gaussian blur pixels to 1 opacity before applying flood - var componentTransfer = Blockly.utils.dom.createSvgElement( + var highlightComponentTransfer = Blockly.utils.dom.createSvgElement( 'feComponentTransfer', {'result': 'outBlur'}, highlightGlowFilter); Blockly.utils.dom.createSvgElement('feFuncA', { 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' }, - componentTransfer); + highlightComponentTransfer); // Color the highlight Blockly.utils.dom.createSvgElement('feFlood', { @@ -447,4 +462,52 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg) { highlightGlowFilter); this.highlightGlowFilterId = highlightGlowFilter.id; this.highlightGlowFilter_ = highlightGlowFilter; + + // Using a dilate distorts the block shape. + // Instead use a gaussian blur, and then set all alpha to 1 with a transfer. + var replacementGlowFilter = Blockly.utils.dom.createSvgElement('filter', + { + 'id': 'blocklyReplacementGlowFilter' + rnd, + 'height': '160%', + 'width': '180%', + y: '-30%', + x: '-40%' + }, + defs); + Blockly.utils.dom.createSvgElement('feGaussianBlur', + { + 'in': 'SourceGraphic', + 'stdDeviation': 2 // TODO: configure size in theme. + }, + replacementGlowFilter); + // Set all gaussian blur pixels to 1 opacity before applying flood + var replacementComponentTransfer = Blockly.utils.dom.createSvgElement( + 'feComponentTransfer', {'result': 'outBlur'}, replacementGlowFilter); + Blockly.utils.dom.createSvgElement('feFuncA', + { + 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' + }, + replacementComponentTransfer); + // Color the highlight + Blockly.utils.dom.createSvgElement('feFlood', + { + 'flood-color': '#FFF200', // TODO: configure colour in theme. + 'flood-opacity': 1, + 'result': 'outColor' + }, + replacementGlowFilter); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'outColor', 'in2': 'outBlur', + 'operator': 'in', 'result': 'outGlow' + }, + replacementGlowFilter); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'SourceGraphic', 'in2': 'outGlow', + 'operator': 'over', + }, + replacementGlowFilter); + this.replacementGlowFilterId = replacementGlowFilter.id; + this.replacementGlowFilter_ = replacementGlowFilter; }; diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js index e840c4efa..bb4240a34 100644 --- a/core/renderers/zelos/path_object.js +++ b/core/renderers/zelos/path_object.js @@ -117,6 +117,20 @@ Blockly.zelos.PathObject.prototype.updateSelected = function(enable) { } }; +/** + * @override + */ +Blockly.zelos.PathObject.prototype.updateReplacementHighlight = function( + enable) { + this.setClass_('blocklyReplaceable', enable); + if (enable) { + this.svgPath.setAttribute('filter', + 'url(#' + this.constants_.replacementGlowFilterId + ')'); + } else { + this.svgPath.removeAttribute('filter'); + } +}; + /** * Method that's called when the drawer is about to draw the block. * @package diff --git a/core/renderers/zelos/renderer.js b/core/renderers/zelos/renderer.js index a075e2f13..47d4134da 100644 --- a/core/renderers/zelos/renderer.js +++ b/core/renderers/zelos/renderer.js @@ -91,4 +91,11 @@ Blockly.zelos.Renderer.prototype.makePathObject = function(root) { /** @type {!Blockly.zelos.ConstantProvider} */ (this.getConstants())); }; +/** + * @override + */ +Blockly.zelos.Renderer.prototype.shouldHighlightConnection = function(conn) { + return conn.type != Blockly.INPUT_VALUE && conn.type !== Blockly.OUTPUT_VALUE; +}; + Blockly.blockRendering.register('zelos', Blockly.zelos.Renderer); From 09f6b792a6847288929ef39fe2d313cdf7ea814a Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 13 Nov 2019 17:22:21 -0800 Subject: [PATCH 191/343] Move field border radius into a constant (#3434) * Move field border radius into a constant * Drop const. --- core/field.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/field.js b/core/field.js index 3055d06d0..6b68324b7 100644 --- a/core/field.js +++ b/core/field.js @@ -326,8 +326,8 @@ Blockly.Field.prototype.createBorderRect_ = function() { this.borderRect_ = /** @type {!SVGRectElement} **/ (Blockly.utils.dom.createSvgElement('rect', { - 'rx': 4, - 'ry': 4, + 'rx': this.constants_.FIELD_BORDER_RECT_RADIUS, + 'ry': this.constants_.FIELD_BORDER_RECT_RADIUS, 'x': 0, 'y': 0, 'height': this.size_.height, From a6be3f084ec8aa94f28916d779a4ce42594006d5 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 14 Nov 2019 17:09:09 +0100 Subject: [PATCH 192/343] Localisation updates from https://translatewiki.net. --- msg/json/pt.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/msg/json/pt.json b/msg/json/pt.json index 111ca7055..77b92cf50 100644 --- a/msg/json/pt.json +++ b/msg/json/pt.json @@ -16,7 +16,8 @@ "Athena in Wonderland", "McDutchie", "Hamilton Abreu", - "Waldyrious" + "Waldyrious", + "Mansil alfalb" ] }, "VARIABLES_DEFAULT_NAME": "item", @@ -378,5 +379,6 @@ "PROCEDURES_IFRETURN_TOOLTIP": "se o valor é verdadeiro, então retorna um segundo valor.", "PROCEDURES_IFRETURN_WARNING": "Aviso: Este bloco só pode ser utilizado dentro da definição de uma função.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Diz algo...", + "WORKSPACE_ARIA_LABEL": "\"Blockly\" no Espaço de Trabalho", "COLLAPSED_WARNINGS_WARNING": "Os blocos ocultados contêm avisos." } From 564af764d0d725a72c9c4d32a965d9b62c76aaad Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Thu, 14 Nov 2019 13:36:29 -0800 Subject: [PATCH 193/343] Cursor renderer (#3440) * Initial commit for adding the cursor to renderer --- blockly_uncompressed.js | 33 +- core/block_svg.js | 5 + core/keyboard_nav/cursor.js | 16 +- core/renderers/common/constants.js | 50 +++ .../common}/cursor_svg.js | 288 ++++++++---------- core/renderers/common/renderer.js | 6 +- core/renderers/zelos/constants.js | 17 ++ core/renderers/zelos/cursor_svg.js | 152 +++++++++ core/renderers/zelos/renderer.js | 16 + 9 files changed, 401 insertions(+), 182 deletions(-) rename core/{keyboard_nav => renderers/common}/cursor_svg.js (74%) create mode 100644 core/renderers/zelos/cursor_svg.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index f0a828915..687a3731f 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -21,17 +21,17 @@ this.BLOCKLY_DIR = (function(root) { this.BLOCKLY_BOOT = function(root) { // Execute after Closure has loaded. -goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.fieldRegistry', 'Blockly.utils.string', 'Blockly.Workspace']); +goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.fieldRegistry', 'Blockly.Input', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.string', 'Blockly.Workspace']); goog.addDependency("../../core/block_animations.js", ['Blockly.blockAnimations'], ['Blockly.utils.dom']); goog.addDependency("../../core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.blockAnimations', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Ui', 'Blockly.InsertionMarkerManager', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); -goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']); +goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.navigation', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']); goog.addDependency("../../core/blockly.js", ['Blockly'], ['Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.inject', 'Blockly.navigation', 'Blockly.Procedures', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/blocks.js", ['Blockly.Blocks'], []); goog.addDependency("../../core/bubble.js", ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent', 'Blockly.Workspace']); goog.addDependency("../../core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.utils.Coordinate']); -goog.addDependency("../../core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent', 'Blockly.Warning']); +goog.addDependency("../../core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent', 'Blockly.Warning']); goog.addDependency("../../core/components/component.js", ['Blockly.Component', 'Blockly.Component.Error'], ['Blockly.utils.dom', 'Blockly.utils.IdGenerator', 'Blockly.utils.style']); goog.addDependency("../../core/components/menu/menu.js", ['Blockly.Menu'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/components/menu/menuitem.js", ['Blockly.MenuItem'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']); @@ -67,37 +67,37 @@ goog.addDependency("../../core/flyout_dragger.js", ['Blockly.FlyoutDragger'], [' goog.addDependency("../../core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.utils', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WidgetDiv']); goog.addDependency("../../core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.utils', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.utils.userAgent', 'Blockly.WidgetDiv']); goog.addDependency("../../core/generator.js", ['Blockly.Generator'], ['Blockly.Block']); -goog.addDependency("../../core/gesture.js", ['Blockly.Gesture'], ['Blockly.blockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.WorkspaceDragger']); +goog.addDependency("../../core/gesture.js", ['Blockly.Gesture'], ['Blockly.ASTNode', 'Blockly.blockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.navigation', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.WorkspaceDragger']); goog.addDependency("../../core/grid.js", ['Blockly.Grid'], ['Blockly.utils.dom', 'Blockly.utils.userAgent']); goog.addDependency("../../core/icon.js", ['Blockly.Icon'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.Size']); -goog.addDependency("../../core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Component', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.userAgent', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg']); +goog.addDependency("../../core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Component', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.user.keyMap', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.userAgent', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg']); goog.addDependency("../../core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.blockAnimations', 'Blockly.Events']); goog.addDependency("../../core/keyboard_nav/action.js", ['Blockly.Action'], []); goog.addDependency("../../core/keyboard_nav/ast_node.js", ['Blockly.ASTNode'], ['Blockly.utils.Coordinate']); -goog.addDependency("../../core/keyboard_nav/cursor.js", ['Blockly.Cursor'], []); -goog.addDependency("../../core/keyboard_nav/cursor_svg.js", ['Blockly.CursorSvg'], ['Blockly.Cursor', 'Blockly.utils.object']); -goog.addDependency("../../core/keyboard_nav/flyout_cursor.js", ['Blockly.FlyoutCursor'], ['Blockly.Cursor', 'Blockly.utils.object']); +goog.addDependency("../../core/keyboard_nav/cursor.js", ['Blockly.Cursor'], ['Blockly.ASTNode', 'Blockly.navigation']); +goog.addDependency("../../core/keyboard_nav/flyout_cursor.js", ['Blockly.FlyoutCursor'], ['Blockly.Cursor', 'Blockly.navigation', 'Blockly.utils.object']); goog.addDependency("../../core/keyboard_nav/key_map.js", ['Blockly.user.keyMap'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object']); goog.addDependency("../../core/keyboard_nav/marker_cursor.js", ['Blockly.MarkerCursor'], ['Blockly.Cursor', 'Blockly.utils.object']); goog.addDependency("../../core/keyboard_nav/navigation.js", ['Blockly.navigation'], ['Blockly.Action', 'Blockly.ASTNode', 'Blockly.utils.Coordinate', 'Blockly.user.keyMap']); goog.addDependency("../../core/keyboard_nav/tab_navigate_cursor.js", ['Blockly.TabNavigateCursor'], ['Blockly.ASTNode', 'Blockly.Cursor', 'Blockly.utils.object']); 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.Ui', 'Blockly.Icon', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.xml', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); +goog.addDependency("../../core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.xml', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/names.js", ['Blockly.Names'], ['Blockly.Msg']); -goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.utils.userAgent', 'Blockly.Xml']); +goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.user.keyMap', 'Blockly.utils.userAgent', 'Blockly.Xml']); goog.addDependency("../../core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.utils.xml', 'Blockly.Workspace', 'Blockly.Xml']); goog.addDependency("../../core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.utils.object']); goog.addDependency("../../core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.dom', 'Blockly.utils.svgPaths']); +goog.addDependency("../../core/renderers/common/cursor_svg.js", ['Blockly.blockRendering.CursorSvg'], ['Blockly.ASTNode']); goog.addDependency("../../core/renderers/common/debugger.js", ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); goog.addDependency("../../core/renderers/common/drawer.js", ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); 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.Hat', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']); goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.PathObject'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.Theme', 'Blockly.utils.dom']); -goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.CursorSvg']); +goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.CursorSvg']); goog.addDependency("../../core/renderers/geras/constants.js", ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object']); -goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object', 'Blockly.utils.svgPaths']); +goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', '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']); goog.addDependency("../../core/renderers/geras/highlighter.js", ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths']); goog.addDependency("../../core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']); @@ -117,16 +117,17 @@ goog.addDependency("../../core/renderers/minimalist/renderer.js", ['Blockly.mini goog.addDependency("../../core/renderers/thrasos/info.js", ['Blockly.thrasos', 'Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/thrasos/renderer.js", ['Blockly.thrasos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.thrasos.RenderInfo', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/zelos/constants.js", ['Blockly.zelos.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.svgPaths']); +goog.addDependency("../../core/renderers/zelos/cursor_svg.js", ['Blockly.zelos.CursorSvg'], ['Blockly.blockRendering.CursorSvg']); goog.addDependency("../../core/renderers/zelos/drawer.js", ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow', 'Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow']); goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.utils.object']); goog.addDependency("../../core/renderers/zelos/path_object.js", ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.zelos.ConstantProvider', 'Blockly.utils.dom', 'Blockly.utils.object']); -goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']); +goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo', 'Blockly.zelos.CursorSvg']); goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']); goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../core/theme.js", ['Blockly.Theme'], ['Blockly.utils', 'Blockly.utils.colour']); goog.addDependency("../../core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); -goog.addDependency("../../core/theme/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Theme']); +goog.addDependency("../../core/theme/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Css', 'Blockly.Theme']); goog.addDependency("../../core/theme/deuteranopia.js", ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']); goog.addDependency("../../core/theme/highcontrast.js", ['Blockly.Themes.HighContrast'], ['Blockly.Theme']); goog.addDependency("../../core/theme/modern.js", ['Blockly.Themes.Modern'], ['Blockly.Theme']); @@ -167,11 +168,11 @@ goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.C goog.addDependency("../../core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.userAgent']); 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.dom']); -goog.addDependency("../../core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WorkspaceComment']); +goog.addDependency("../../core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WorkspaceComment']); goog.addDependency("../../core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']); goog.addDependency("../../core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.utils.object']); -goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']); +goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.navigation', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']); goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']); goog.addDependency("../../core/xml.js", ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.xml']); goog.addDependency("../../core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Css', 'Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.utils.dom']); diff --git a/core/block_svg.js b/core/block_svg.js index a30725695..e160e4bd0 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1640,6 +1640,11 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { } } Blockly.utils.dom.stopTextWidthCache(); + + var cursor = this.workspace.getCursor(); + if (this.pathObject.cursorSvg_) { + cursor.draw(); + } }; /** diff --git a/core/keyboard_nav/cursor.js b/core/keyboard_nav/cursor.js index 861fe04b5..a129c958e 100644 --- a/core/keyboard_nav/cursor.js +++ b/core/keyboard_nav/cursor.js @@ -42,7 +42,7 @@ Blockly.Cursor = function() { /** * The object in charge of drawing the visual representation of the current node. - * @type {Blockly.CursorSvg} + * @type {Blockly.blockRendering.CursorSvg} * @private */ this.drawer_ = null; @@ -50,7 +50,7 @@ Blockly.Cursor = function() { /** * Sets the object in charge of drawing the cursor. - * @param {Blockly.CursorSvg} drawer The object in charge of drawing the cursor. + * @param {Blockly.blockRendering.CursorSvg} drawer The object in charge of drawing the cursor. */ Blockly.Cursor.prototype.setDrawer = function(drawer) { this.drawer_ = drawer; @@ -58,7 +58,7 @@ Blockly.Cursor.prototype.setDrawer = function(drawer) { /** * Get the current drawer for the cursor. - * @return {Blockly.CursorSvg} The object in charge of drawing the cursor. + * @return {Blockly.blockRendering.CursorSvg} The object in charge of drawing the cursor. */ Blockly.Cursor.prototype.getDrawer = function() { return this.drawer_; @@ -87,6 +87,16 @@ Blockly.Cursor.prototype.setCurNode = function(newNode) { } }; +/** + * Redraw the current cursor. + * @package + */ +Blockly.Cursor.prototype.draw = function() { + if (this.drawer_) { + this.drawer_.draw(this.curNode_, this.curNode_); + } +}; + /** * Hide the cursor SVG. */ diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 92eaf8c7d..d53abadbb 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -261,6 +261,56 @@ Blockly.blockRendering.ConstantProvider = function() { this.disabledPattern_ = null; /** + * Cursor colour. + * @type {string} + * @package + */ + this.CURSOR_COLOUR = '#cc0a0a'; + + /** + * Immovable marker colour. + * @type {string} + * @package + */ + this.MARKER_COLOUR = '#4286f4'; + + /** + * Width of the horizontal cursor. + * @type {number} + * @package + */ + this.CURSOR_WS_WIDTH = 100; + + /** + * Height of the horizontal cursor. + * @type {number} + * @package + */ + this.WS_CURSOR_HEIGHT = 5; + + /** + * Padding around a stack. + * @type {number} + * @package + */ + this.CURSOR_STACK_PADDING = 10; + + /** + * Padding around a block. + * @type {number} + * @package + */ + this.CURSOR_BLOCK_PADDING = 2; + + /** + * Stroke of the cursor. + * @type {number} + * @package + */ + this.CURSOR_STROKE_WIDTH = 4; + + + /* * Whether text input and colour fields fill up the entire source block. * @type {boolean} * @package diff --git a/core/keyboard_nav/cursor_svg.js b/core/renderers/common/cursor_svg.js similarity index 74% rename from core/keyboard_nav/cursor_svg.js rename to core/renderers/common/cursor_svg.js index 68c10e6c8..0bb0edc87 100644 --- a/core/keyboard_nav/cursor_svg.js +++ b/core/renderers/common/cursor_svg.js @@ -21,22 +21,23 @@ */ 'use strict'; -goog.provide('Blockly.CursorSvg'); + +goog.provide('Blockly.blockRendering.CursorSvg'); goog.require('Blockly.ASTNode'); -goog.require('Blockly.Cursor'); -goog.require('Blockly.utils.object'); /** * Class for a cursor. * @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to. - * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used + * @param {!Blockly.blockRendering.ConstantProvider} constants The constants for + * the renderer. + * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used * to save a location and is an immovable cursor. False or undefined if the * cursor is not a marker. * @constructor */ -Blockly.CursorSvg = function(workspace, opt_marker) { +Blockly.blockRendering.CursorSvg = function(workspace, constants, opt_marker) { /** * The workspace the cursor belongs to. * @type {!Blockly.WorkspaceSvg} @@ -48,10 +49,10 @@ Blockly.CursorSvg = function(workspace, opt_marker) { * True if the cursor should be drawn as a marker, false otherwise. * A marker is drawn as a solid blue line, while the cursor is drawns as a * flashing red one. - * @type {boolean|undefined} + * @type {boolean} * @private */ - this.isMarker_ = opt_marker; + this.isMarker_ = !!opt_marker; /** * The workspace, field, or block that the cursor SVG element should be @@ -64,52 +65,28 @@ Blockly.CursorSvg = function(workspace, opt_marker) { /** * The constants necessary to draw the cursor. * @type {Blockly.blockRendering.ConstantProvider} - * @private + * @protected */ - this.constants_ = workspace.getRenderer().getConstants(); + this.constants_ = constants; + + /** + * The current SVG element for the cursor. + * @type {Element} + */ + this.currentCursorSvg = null; }; /** - * Height of the horizontal cursor. - * @type {number} - * @const + * The name of the CSS class for a cursor. + * @const {string} */ -Blockly.CursorSvg.CURSOR_HEIGHT = 5; +Blockly.blockRendering.CursorSvg.CURSOR_CLASS = 'blocklyCursor'; /** - * Width of the horizontal cursor. - * @type {number} - * @const + * The name of the CSS class for a marker. + * @const {string} */ -Blockly.CursorSvg.CURSOR_WIDTH = 100; - -/** - * The start length of the notch. - * @type {number} - * @const - */ -Blockly.CursorSvg.NOTCH_START_LENGTH = 24; - -/** - * Padding around the input. - * @type {number} - * @const - */ -Blockly.CursorSvg.VERTICAL_PADDING = 5; - -/** - * Padding around a stack. - * @type {number} - * @const - */ -Blockly.CursorSvg.STACK_PADDING = 10; - -/** - * Padding around a block. - * @type {number} - * @const - */ -Blockly.CursorSvg.BLOCK_PADDING = 2; +Blockly.blockRendering.CursorSvg.MARKER_CLASS = 'blocklyMarker'; /** * What we multiply the height by to get the height of the cursor. @@ -117,63 +94,42 @@ Blockly.CursorSvg.BLOCK_PADDING = 2; * @type {number} * @const */ -Blockly.CursorSvg.HEIGHT_MULTIPLIER = 3 / 4; - -/** - * Cursor colour. - * @type {string} - * @const - */ -Blockly.CursorSvg.CURSOR_COLOUR = '#cc0a0a'; - -/** - * Immovable marker colour. - * @type {string} - * @const - */ -Blockly.CursorSvg.MARKER_COLOUR = '#4286f4'; - -/** - * The name of the CSS class for a cursor. - * @const {string} - */ -Blockly.CursorSvg.CURSOR_CLASS = 'blocklyCursor'; - -/** - * The name of the CSS class for a marker. - * @const {string} - */ -Blockly.CursorSvg.MARKER_CLASS = 'blocklyMarker'; - -/** - * The current SVG element for the cursor. - * @type {Element} - */ -Blockly.CursorSvg.prototype.currentCursorSvg = null; +Blockly.blockRendering.CursorSvg.HEIGHT_MULTIPLIER = 3 / 4; /** * Return the root node of the SVG or null if none exists. * @return {SVGElement} The root SVG node. */ -Blockly.CursorSvg.prototype.getSvgRoot = function() { +Blockly.blockRendering.CursorSvg.prototype.getSvgRoot = function() { return this.svgGroup_; }; +/** + * True if the cursor should be drawn as a marker, false otherwise. + * A marker is drawn as a solid blue line, while the cursor is drawns as a + * flashing red one. + * @return {boolean} The root SVG node. + */ +Blockly.blockRendering.CursorSvg.prototype.isMarker = function() { + return this.isMarker_; +}; + /** * Create the DOM element for the cursor. * @return {!SVGElement} The cursor controls SVG group. * @package */ -Blockly.CursorSvg.prototype.createDom = function() { - var className = this.isMarker_ ? - Blockly.CursorSvg.MARKER_CLASS : Blockly.CursorSvg.CURSOR_CLASS; +Blockly.blockRendering.CursorSvg.prototype.createDom = function() { + var className = this.isMarker() ? + Blockly.blockRendering.CursorSvg.MARKER_CLASS : + Blockly.blockRendering.CursorSvg.CURSOR_CLASS; this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', { 'class': className }, null); - this.createCursorSvg_(); + this.createDomInternal_(); return this.svgGroup_; }; @@ -182,9 +138,9 @@ Blockly.CursorSvg.prototype.createDom = function() { * @param {!Blockly.WorkspaceSvg|!Blockly.Field|!Blockly.BlockSvg} newParent * The workspace, field, or block that the cursor SVG element should be * attached to. - * @private + * @protected */ -Blockly.CursorSvg.prototype.setParent_ = function(newParent) { +Blockly.blockRendering.CursorSvg.prototype.setParent_ = function(newParent) { if (this.isMarker_) { if (this.parent_) { this.parent_.setMarkerSvg(null); @@ -207,16 +163,16 @@ Blockly.CursorSvg.prototype.setParent_ = function(newParent) { * Show the cursor as a combination of the previous connection and block, * the output connection and block, or just the block. * @param {Blockly.BlockSvg} block The block the cursor is currently on. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) { +Blockly.blockRendering.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) { if (!block) { return; } var width = block.width; var height = block.height; - var cursorHeight = height * Blockly.CursorSvg.HEIGHT_MULTIPLIER; - var cursorOffset = Blockly.CursorSvg.BLOCK_PADDING; + var cursorHeight = height * Blockly.blockRendering.CursorSvg.HEIGHT_MULTIPLIER; + var cursorOffset = this.constants_.CURSOR_BLOCK_PADDING; if (block.previousConnection) { this.positionPrevious_(width, cursorOffset, cursorHeight); @@ -234,18 +190,18 @@ Blockly.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) { * Show the visual representation of a workspace coordinate. * This is a horizontal line. * @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showWithCoordinates_ = function(curNode) { +Blockly.blockRendering.CursorSvg.prototype.showWithCoordinates_ = function(curNode) { var wsCoordinate = curNode.getWsCoordinate(); var x = wsCoordinate.x; var y = wsCoordinate.y; if (this.workspace_.RTL) { - x -= Blockly.CursorSvg.CURSOR_WIDTH; + x -= this.constants_.CURSOR_WS_WIDTH; } - this.positionLine_(x, y, Blockly.CursorSvg.CURSOR_WIDTH); + this.positionLine_(x, y, this.constants_.CURSOR_WS_WIDTH); this.setParent_(this.workspace_); this.showCurrent_(); }; @@ -254,9 +210,9 @@ Blockly.CursorSvg.prototype.showWithCoordinates_ = function(curNode) { * Show the visual representation of a field. * This is a box around the field. * @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showWithField_ = function(curNode) { +Blockly.blockRendering.CursorSvg.prototype.showWithField_ = function(curNode) { var field = /** @type {Blockly.Field} */ (curNode.getLocation()); var width = field.getSize().width; var height = field.getSize().height; @@ -270,9 +226,9 @@ Blockly.CursorSvg.prototype.showWithField_ = function(curNode) { * Show the visual representation of an input. * This is a puzzle piece. * @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showWithInput_ = function(curNode) { +Blockly.blockRendering.CursorSvg.prototype.showWithInput_ = function(curNode) { var connection = /** @type {Blockly.Connection} */ (curNode.getLocation()); var sourceBlock = /** @type {!Blockly.BlockSvg} */ (connection.getSourceBlock()); @@ -287,9 +243,9 @@ Blockly.CursorSvg.prototype.showWithInput_ = function(curNode) { * Show the visual representation of a next connection. * This is a horizontal line. * @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showWithNext_ = function(curNode) { +Blockly.blockRendering.CursorSvg.prototype.showWithNext_ = function(curNode) { var connection = curNode.getLocation(); var targetBlock = /** @type {Blockly.BlockSvg} */ (connection.getSourceBlock()); var x = 0; @@ -307,21 +263,21 @@ Blockly.CursorSvg.prototype.showWithNext_ = function(curNode) { * Show the visual representation of a stack. * This is a box with extra padding around the entire stack of blocks. * @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) { +Blockly.blockRendering.CursorSvg.prototype.showWithStack_ = function(curNode) { var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation()); // Gets the height and width of entire stack. var heightWidth = block.getHeightWidth(); // Add padding so that being on a stack looks different than being on a block. - var width = heightWidth.width + Blockly.CursorSvg.STACK_PADDING; - var height = heightWidth.height + Blockly.CursorSvg.STACK_PADDING; + var width = heightWidth.width + this.constants_.CURSOR_STACK_PADDING; + var height = heightWidth.height + this.constants_.CURSOR_STACK_PADDING; // Shift the rectangle slightly to upper left so padding is equal on all sides. - var xPadding = -Blockly.CursorSvg.STACK_PADDING / 2; - var yPadding = -Blockly.CursorSvg.STACK_PADDING / 2; + var xPadding = -this.constants_.CURSOR_STACK_PADDING / 2; + var yPadding = -this.constants_.CURSOR_STACK_PADDING / 2; var x = xPadding; var y = yPadding; @@ -336,9 +292,9 @@ Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) { /** * Show the current cursor. - * @private + * @protected */ -Blockly.CursorSvg.prototype.showCurrent_ = function() { +Blockly.blockRendering.CursorSvg.prototype.showCurrent_ = function() { this.hide(); this.currentCursorSvg.style.display = ''; }; @@ -355,7 +311,8 @@ Blockly.CursorSvg.prototype.showCurrent_ = function() { * @param {number} cursorHeight The height of the cursor. * @private */ -Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, cursorHeight) { +Blockly.blockRendering.CursorSvg.prototype.positionBlock_ = function( + width, cursorOffset, cursorHeight) { var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) + Blockly.utils.svgPaths.lineOnAxis('V', -cursorOffset) + Blockly.utils.svgPaths.lineOnAxis('H', width + cursorOffset * 2) + @@ -373,7 +330,7 @@ Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, curso * @param {!Blockly.Connection} connection The connection to position cursor around. * @private */ -Blockly.CursorSvg.prototype.positionInput_ = function(connection) { +Blockly.blockRendering.CursorSvg.prototype.positionInput_ = function(connection) { var x = connection.getOffsetInBlock().x; var y = connection.getOffsetInBlock().y; @@ -392,9 +349,9 @@ Blockly.CursorSvg.prototype.positionInput_ = function(connection) { * @param {number} x The new x, in workspace units. * @param {number} y The new y, in workspace units. * @param {number} width The new width, in workspace units. - * @private + * @protected */ -Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) { +Blockly.blockRendering.CursorSvg.prototype.positionLine_ = function(x, y, width) { this.cursorSvgLine_.setAttribute('x', x); this.cursorSvgLine_.setAttribute('y', y); this.cursorSvgLine_.setAttribute('width', width); @@ -408,7 +365,7 @@ Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) { * @param {number} height The height of the block. * @private */ -Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) { +Blockly.blockRendering.CursorSvg.prototype.positionOutput_ = function(width, height) { var cursorPath = Blockly.utils.svgPaths.moveBy(width, 0) + Blockly.utils.svgPaths.lineOnAxis('h', -(width - this.constants_.PUZZLE_TAB.width)) + Blockly.utils.svgPaths.lineOnAxis('v', this.constants_.TAB_OFFSET_FROM_TOP) + @@ -431,7 +388,8 @@ Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) { * @param {number} cursorHeight The height of the cursor. * @private */ -Blockly.CursorSvg.prototype.positionPrevious_ = function(width, cursorOffset, cursorHeight) { +Blockly.blockRendering.CursorSvg.prototype.positionPrevious_ = function( + width, cursorOffset, cursorHeight) { var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) + Blockly.utils.svgPaths.lineOnAxis('V', -cursorOffset) + Blockly.utils.svgPaths.lineOnAxis('H', this.constants_.NOTCH_OFFSET_LEFT) + @@ -452,9 +410,9 @@ Blockly.CursorSvg.prototype.positionPrevious_ = function(width, cursorOffset, cu * @param {number} y The new y, in workspace units. * @param {number} width The new width, in workspace units. * @param {number} height The new height, in workspace units. - * @private + * @protected */ -Blockly.CursorSvg.prototype.positionRect_ = function(x, y, width, height) { +Blockly.blockRendering.CursorSvg.prototype.positionRect_ = function(x, y, width, height) { this.cursorSvgRect_.setAttribute('x', x); this.cursorSvgRect_.setAttribute('y', y); this.cursorSvgRect_.setAttribute('width', width); @@ -467,7 +425,7 @@ Blockly.CursorSvg.prototype.positionRect_ = function(x, y, width, height) { * @param {!SVGElement} cursor The cursor that we want to flip. * @private */ -Blockly.CursorSvg.prototype.flipRtl_ = function(cursor) { +Blockly.blockRendering.CursorSvg.prototype.flipRtl_ = function(cursor) { cursor.setAttribute('transform', 'scale(-1 1)'); }; @@ -475,7 +433,7 @@ Blockly.CursorSvg.prototype.flipRtl_ = function(cursor) { * Hide the cursor. * @package */ -Blockly.CursorSvg.prototype.hide = function() { +Blockly.blockRendering.CursorSvg.prototype.hide = function() { this.cursorSvgLine_.style.display = 'none'; this.cursorSvgRect_.style.display = 'none'; this.cursorInput_.style.display = 'none'; @@ -488,12 +446,30 @@ Blockly.CursorSvg.prototype.hide = function() { * @param {Blockly.ASTNode} curNode The node that we want to draw the cursor for. * @package */ -Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) { +Blockly.blockRendering.CursorSvg.prototype.draw = function(oldNode, curNode) { if (!curNode) { this.hide(); return; } + this.showAtLocation_(curNode); + + this.fireCursorEvent_(oldNode, curNode); + + // Ensures the cursor will be visible immediately after the move. + var animate = this.currentCursorSvg.childNodes[0]; + if (animate !== undefined) { + animate.beginElement && animate.beginElement(); + } +}; + + +/** + * Update the cursor's visible state based on the type of curNode.. + * @param {Blockly.ASTNode} curNode The node that we want to draw the cursor for. + * @protected + */ +Blockly.blockRendering.CursorSvg.prototype.showAtLocation_ = function(curNode) { if (curNode.getType() == Blockly.ASTNode.types.BLOCK) { var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation()); this.showWithBlockPrevOutput_(block); @@ -514,14 +490,6 @@ Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) { } else if (curNode.getType() == Blockly.ASTNode.types.STACK) { this.showWithStack_(curNode); } - - this.fireCursorEvent_(oldNode, curNode); - - // Ensures the cursor will be visible immediately after the move. - var animate = this.currentCursorSvg.childNodes[0]; - if (animate !== undefined) { - animate.beginElement && animate.beginElement(); - } }; /** @@ -530,7 +498,7 @@ Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) { * @param {!Blockly.ASTNode} curNode The new node the cursor is currently on. * @private */ -Blockly.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) { +Blockly.blockRendering.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) { var curBlock = curNode.getSourceBlock(); var eventType = this.isMarker_ ? 'markedNode' : 'cursorMove'; var event = new Blockly.Events.Ui(curBlock, eventType, oldNode, curNode); @@ -540,12 +508,28 @@ Blockly.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) { Blockly.Events.fire(event); }; +/** + * Get the properties to make a cursor blink. + * @return {!Object} The object holding attributes to make the cursor blink. + * @protected + */ +Blockly.blockRendering.CursorSvg.prototype.getBlinkProperties_ = function() { + return { + 'attributeType': 'XML', + 'attributeName': 'fill', + 'dur': '1s', + 'values': this.constants_.CURSOR_COLOUR + ';transparent;transparent;', + 'repeatCount': 'indefinite' + }; +}; + + /** * Create the cursor SVG. * @return {Element} The SVG node created. - * @private + * @protected */ -Blockly.CursorSvg.prototype.createCursorSvg_ = function() { +Blockly.blockRendering.CursorSvg.prototype.createDomInternal_ = function() { /* This markup will be generated and added to the .svgGroup_: @@ -555,22 +539,20 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { */ - var colour = this.isMarker_ ? Blockly.CursorSvg.MARKER_COLOUR : - Blockly.CursorSvg.CURSOR_COLOUR; + var colour = this.isMarker_ ? this.constants_.MARKER_COLOUR : + this.constants_.CURSOR_COLOUR; this.cursorSvg_ = Blockly.utils.dom.createSvgElement('g', { - 'width': Blockly.CursorSvg.CURSOR_WIDTH, - 'height': Blockly.CursorSvg.CURSOR_HEIGHT + 'width': this.constants_.CURSOR_WS_WIDTH, + 'height': this.constants_.WS_CURSOR_HEIGHT }, this.svgGroup_); // A horizontal line used to represent a workspace coordinate or next connection. this.cursorSvgLine_ = Blockly.utils.dom.createSvgElement('rect', { - 'x': 0, - 'y': 0, 'fill': colour, - 'width': Blockly.CursorSvg.CURSOR_WIDTH, - 'height': Blockly.CursorSvg.CURSOR_HEIGHT, + 'width': this.constants_.CURSOR_WS_WIDTH, + 'height': this.constants_.WS_CURSOR_HEIGHT, 'style': 'display: none' }, this.cursorSvg_); @@ -579,8 +561,6 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { this.cursorSvgRect_ = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyVerticalCursor', - 'x': 0, - 'y': 0, 'rx': 10, 'ry': 10, 'style': 'display: none', 'stroke': colour @@ -588,11 +568,8 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { this.cursorSvg_); // A filled in puzzle piece used to represent an input value. - this.cursorInput_ = Blockly.utils.dom.createSvgElement( - 'path', + this.cursorInput_ = Blockly.utils.dom.createSvgElement('path', { - 'width': Blockly.CursorSvg.CURSOR_WIDTH, - 'height': Blockly.CursorSvg.CURSOR_HEIGHT, 'transform': '', 'style': 'display: none', 'fill': colour @@ -601,34 +578,25 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { // A path used to represent a previous connection and a block, an output // connection and a block, or a block. - this.cursorBlock_ = Blockly.utils.dom.createSvgElement( - 'path', + this.cursorBlock_ = Blockly.utils.dom.createSvgElement('path', { - 'width': Blockly.CursorSvg.CURSOR_WIDTH, - 'height': Blockly.CursorSvg.CURSOR_HEIGHT, 'transform': '', 'style': 'display: none', 'fill': 'none', 'stroke': colour, - 'stroke-width': 4 + 'stroke-width': this.constants_.CURSOR_STROKE_WIDTH }, this.cursorSvg_); // Markers and stack cursors don't blink. if (!this.isMarker_) { - var properties = { - 'attributeType': 'XML', - 'attributeName': 'fill', - 'dur': '1s', - 'values': Blockly.CursorSvg.CURSOR_COLOUR + ';transparent;transparent;', - 'repeatCount': 'indefinite' - }; - Blockly.utils.dom.createSvgElement('animate', properties, + var blinkProperties = this.getBlinkProperties_(); + Blockly.utils.dom.createSvgElement('animate', this.getBlinkProperties_(), this.cursorSvgLine_); - Blockly.utils.dom.createSvgElement('animate', properties, + Blockly.utils.dom.createSvgElement('animate', blinkProperties, this.cursorInput_); - properties['attributeName'] = 'stroke'; - Blockly.utils.dom.createSvgElement('animate', properties, + blinkProperties['attributeName'] = 'stroke'; + Blockly.utils.dom.createSvgElement('animate', blinkProperties, this.cursorBlock_); } @@ -639,7 +607,7 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() { * Dispose of this cursor. * @package */ -Blockly.CursorSvg.prototype.dispose = function() { +Blockly.blockRendering.CursorSvg.prototype.dispose = function() { if (this.svgGroup_) { Blockly.utils.dom.removeNode(this.svgGroup_); } diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index a25e52825..35d8bdb60 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -24,11 +24,11 @@ goog.provide('Blockly.blockRendering.Renderer'); goog.require('Blockly.blockRendering.ConstantProvider'); +goog.require('Blockly.blockRendering.CursorSvg'); goog.require('Blockly.blockRendering.Drawer'); goog.require('Blockly.blockRendering.IPathObject'); goog.require('Blockly.blockRendering.PathObject'); goog.require('Blockly.blockRendering.RenderInfo'); -goog.require('Blockly.CursorSvg'); goog.requireType('Blockly.blockRendering.Debug'); @@ -107,12 +107,12 @@ Blockly.blockRendering.Renderer.prototype.makeDebugger_ = function() { * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used * to save a location and is an immovable cursor. False or undefined if the * cursor is not a marker. - * @return {!Blockly.CursorSvg} The cursor drawer. + * @return {!Blockly.blockRendering.CursorSvg} The cursor drawer. * @package */ Blockly.blockRendering.Renderer.prototype.makeCursorDrawer = function( workspace, opt_marker) { - return new Blockly.CursorSvg(workspace, opt_marker); + return new Blockly.blockRendering.CursorSvg(workspace, this.getConstants(), opt_marker); }; /** diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index f982a6307..37fe00172 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -127,6 +127,23 @@ Blockly.zelos.ConstantProvider = function() { */ this.DUMMY_INPUT_MIN_HEIGHT = 6 * this.GRID_UNIT; + /** + * @override + */ + this.CURSOR_WS_WIDTH = 20 * this.GRID_UNIT; + + /** + * @override + */ + this.CURSOR_COLOUR = '#ffa200'; + + /** + * Radius of the cursor for input and output connections. + * @type {number} + * @package + */ + this.CURSOR_RADIUS = 5; + /** * @override */ diff --git a/core/renderers/zelos/cursor_svg.js b/core/renderers/zelos/cursor_svg.js new file mode 100644 index 000000000..dd578bcd6 --- /dev/null +++ b/core/renderers/zelos/cursor_svg.js @@ -0,0 +1,152 @@ +/** + * @license + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Methods for graphically rendering a cursor as SVG. + * @author samelh@microsoft.com (Sam El-Husseini) + */ +'use strict'; + +goog.provide('Blockly.zelos.CursorSvg'); + +goog.require('Blockly.blockRendering.CursorSvg'); + + +/** + * Class for a cursor. + * @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to. + * @param {!Blockly.blockRendering.ConstantProvider} constants The constants for + * the renderer. + * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used + * to save a location and is an immovable cursor. False or undefined if the + * cursor is not a marker. + * @constructor + * @extends {Blockly.blockRendering.CursorSvg} + */ +Blockly.zelos.CursorSvg = function(workspace, constants, opt_marker) { + Blockly.zelos.CursorSvg.superClass_.constructor.call( + this, workspace, constants, opt_marker); +}; +Blockly.utils.object.inherits(Blockly.zelos.CursorSvg, + Blockly.blockRendering.CursorSvg); + +/** + * @override + */ +Blockly.zelos.CursorSvg.prototype.showWithInput_ = function(curNode) { + var block = /** @type {!Blockly.BlockSvg} */ (curNode.getSourceBlock()); + var connection = curNode.getLocation(); + var offsetInBlock = connection.getOffsetInBlock(); + + var y = offsetInBlock.y + this.constants_.CURSOR_RADIUS; + + this.positionCircle_(offsetInBlock.x, y); + this.setParent_(block); + this.showCurrent_(); +}; + +/** + * Draw a rectangle around the block. + * @param {!Blockly.ASTNode} curNode The current node of the cursor. + */ +Blockly.zelos.CursorSvg.prototype.showWithBlock_ = function(curNode) { + var block = /** @type {!Blockly.BlockSvg} */ (curNode.getLocation()); + + // Gets the height and width of entire stack. + var heightWidth = block.getHeightWidth(); + + // Add padding so that being on a stack looks different than being on a block. + this.positionRect_(0, 0, heightWidth.width, heightWidth.height); + this.setParent_(block); + this.showCurrent_(); +}; + +/** + * Position the circle we use for input and output connections. + * @param {number} x The x position of the circle. + * @param {number} y The y position of the circle. + * @private + */ +Blockly.zelos.CursorSvg.prototype.positionCircle_ = function(x, y) { + this.cursorCircle_.setAttribute('cx', x); + this.cursorCircle_.setAttribute('cy', y); + this.currentCursorSvg = this.cursorCircle_; +}; + +/** + * @override + */ +Blockly.zelos.CursorSvg.prototype.showAtLocation_ = function(curNode) { + var handled = false; + if (curNode.getType() == Blockly.ASTNode.types.OUTPUT) { + // Inputs and outputs are drawn the same. + this.showWithInput_(curNode); + handled = true; + } else if (curNode.getType() == Blockly.ASTNode.types.BLOCK) { + this.showWithBlock_(curNode); + handled = true; + } + + if (!handled) { + Blockly.zelos.CursorSvg.superClass_.showAtLocation_.call(this, curNode); + } +}; + +/** + * @override + */ +Blockly.zelos.CursorSvg.prototype.hide = function() { + Blockly.zelos.CursorSvg.superClass_.hide.call(this); + this.cursorCircle_.style.display = 'none'; +}; + +/** + * @override + */ +Blockly.zelos.CursorSvg.prototype.createDomInternal_ = function() { + /* This markup will be generated and added to the .svgGroup_: + + + + + + */ + + Blockly.zelos.CursorSvg.superClass_.createDomInternal_.call(this); + var colour = this.isMarker() ? this.constants_.MARKER_COLOUR : + this.constants_.CURSOR_COLOUR; + + this.cursorCircle_ = Blockly.utils.dom.createSvgElement('circle', { + 'r': this.constants_.CURSOR_RADIUS, + 'style': 'display: none', + 'fill': colour, + 'stroke': colour, + 'stroke-width': this.constants_.CURSOR_STROKE_WIDTH + }, + this.cursorSvg_); + + // Markers and stack cursors don't blink. + if (!this.isMarker()) { + var blinkProperties = this.getBlinkProperties_(); + Blockly.utils.dom.createSvgElement('animate', blinkProperties, + this.cursorCircle_); + } + + return this.cursorSvg_; +}; + diff --git a/core/renderers/zelos/renderer.js b/core/renderers/zelos/renderer.js index 47d4134da..773d51c7f 100644 --- a/core/renderers/zelos/renderer.js +++ b/core/renderers/zelos/renderer.js @@ -30,6 +30,7 @@ goog.require('Blockly.zelos.ConstantProvider'); goog.require('Blockly.zelos.Drawer'); goog.require('Blockly.zelos.PathObject'); goog.require('Blockly.zelos.RenderInfo'); +goog.require('Blockly.zelos.CursorSvg'); /** @@ -79,6 +80,21 @@ Blockly.zelos.Renderer.prototype.makeDrawer_ = function(block, info) { /** @type {!Blockly.zelos.RenderInfo} */ (info)); }; +/** + * Create a new instance of the renderer's cursor drawer. + * @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to. + * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used + * to save a location and is an immovable cursor. False or undefined if the + * cursor is not a marker. + * @return {!Blockly.blockRendering.CursorSvg} The cursor drawer. + * @package + * @override + */ +Blockly.zelos.Renderer.prototype.makeCursorDrawer = function( + workspace, opt_marker) { + return new Blockly.zelos.CursorSvg(workspace, this.getConstants(), opt_marker); +}; + /** * Create a new instance of a renderer path object. * @param {!SVGElement} root The root SVG element. From c868a86bddc54f3fdf46d4b4822b2f075da95fa3 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 14 Nov 2019 15:00:49 -0800 Subject: [PATCH 194/343] Field dropdown with an SVG arrow (#3442) * Add SVG arrow as an option on the dropdown field --- core/field_dropdown.js | 128 +++++++++++++++++++++++------ core/renderers/common/constants.js | 6 ++ core/renderers/zelos/constants.js | 30 +++++++ media/dropdown-arrow.svg | 1 + 4 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 media/dropdown-arrow.svg diff --git a/core/field_dropdown.js b/core/field_dropdown.js index be570ad36..e4f7f8610 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -114,11 +114,18 @@ Blockly.FieldDropdown = function(menuGenerator, opt_validator, opt_config) { this.imageElement_ = null; /** - * SVG arrow element. + * Tspan based arrow element. * @type {SVGTSpanElement} * @private */ this.arrow_ = null; + + /** + * SVG based arrow element. + * @type {SVGElement} + * @private + */ + this.svgArrow_ = null; }; Blockly.utils.object.inherits(Blockly.FieldDropdown, Blockly.Field); @@ -198,14 +205,22 @@ Blockly.FieldDropdown.prototype.initView = function() { Blockly.FieldDropdown.superClass_.initView.call(this); this.imageElement_ = /** @type {!SVGImageElement} */ - (Blockly.utils.dom.createSvgElement('image', - { - 'y': Blockly.FieldDropdown.IMAGE_Y_OFFSET - }, this.fieldGroup_)); + (Blockly.utils.dom.createSvgElement('image', {}, this.fieldGroup_)); + if (this.constants_.FIELD_DROPDOWN_SVG_ARROW) { + this.createSVGArrow_(); + } else { + this.createTextArrow_(); + } +}; + +/** + * Create a tspan based arrow. + * @protected + */ +Blockly.FieldDropdown.prototype.createTextArrow_ = function() { this.arrow_ = /** @type {!SVGTSpanElement} */ - (Blockly.utils.dom.createSvgElement('tspan', - {}, this.textElement_)); + (Blockly.utils.dom.createSvgElement('tspan', {}, this.textElement_)); this.arrow_.appendChild(document.createTextNode( this.sourceBlock_.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : @@ -217,6 +232,19 @@ Blockly.FieldDropdown.prototype.initView = function() { } }; +/** + * Create an SVG based arrow. + * @protected + */ +Blockly.FieldDropdown.prototype.createSVGArrow_ = function() { + this.svgArrow_ = Blockly.utils.dom.createSvgElement('image', { + 'height': this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px', + 'width': this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px' + }, this.fieldGroup_); + this.svgArrow_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', + this.constants_.FIELD_DROPDOWN_SVG_ARROW_DATAURI); +}; + /** * Create a dropdown menu under the text. * @private @@ -242,6 +270,8 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { /** @type {!Element} */ (this.selectedMenuItem_.getElement()), /** @type {!Element} */ (this.menu_.getElement())); } + + this.applyColour(); }; /** @@ -296,6 +326,7 @@ Blockly.FieldDropdown.prototype.dropdownDispose_ = function() { } this.menu_ = null; this.selectedMenuItem_ = null; + this.applyColour(); }; /** @@ -469,6 +500,17 @@ Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) { * @package */ Blockly.FieldDropdown.prototype.applyColour = function() { + if (this.borderRect_) { + this.borderRect_.setAttribute('stroke', + this.sourceBlock_.style.colourTertiary); + if (this.menu_) { + this.borderRect_.setAttribute('fill', + this.sourceBlock_.style.colourTertiary); + } else { + this.borderRect_.setAttribute('fill', + this.sourceBlock_.style.colourPrimary); + } + } // Update arrow's colour. if (this.sourceBlock_ && this.arrow_) { if (this.sourceBlock_.isShadow()) { @@ -514,18 +556,26 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { this.imageElement_.setAttribute('height', imageJson.height); this.imageElement_.setAttribute('width', imageJson.width); - var arrowWidth = Blockly.utils.dom.getFastTextWidth( - /** @type {!SVGTSpanElement} */ (this.arrow_), - this.constants_.FIELD_TEXT_FONTSIZE, - this.constants_.FIELD_TEXT_FONTWEIGHT, - this.constants_.FIELD_TEXT_FONTFAMILY); - var imageHeight = Number(imageJson.height); var imageWidth = Number(imageJson.width); // Height and width include the border rect. - this.size_.height = imageHeight + Blockly.FieldDropdown.IMAGE_Y_PADDING; + this.size_.height = Math.max( + this.constants_.FIELD_DROPDOWN_BORDER_RECT_HEIGHT, + imageHeight + Blockly.FieldDropdown.IMAGE_Y_PADDING); + var halfHeight = this.size_.height / 2; var xPadding = this.constants_.FIELD_BORDER_RECT_X_PADDING; + var arrowWidth = 0; + if (this.svgArrow_) { + arrowWidth = this.positionSVGArrow_(imageWidth + xPadding, halfHeight - + this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE / 2); + } else { + arrowWidth = Blockly.utils.dom.getFastTextWidth( + /** @type {!SVGTSpanElement} */ (this.arrow_), + this.constants_.FIELD_TEXT_FONTSIZE, + this.constants_.FIELD_TEXT_FONTWEIGHT, + this.constants_.FIELD_TEXT_FONTFAMILY); + } this.size_.width = imageWidth + arrowWidth + xPadding * 2; if (this.sourceBlock_.RTL) { @@ -534,12 +584,12 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { this.imageElement_.setAttribute('x', imageX); this.textElement_.setAttribute('x', arrowX); } else { - var arrowX = - imageWidth + arrowWidth + xPadding + 1; + var arrowX = imageWidth + arrowWidth + xPadding + 1; this.textElement_.setAttribute('text-anchor', 'end'); this.textElement_.setAttribute('x', arrowX); this.imageElement_.setAttribute('x', xPadding); } + this.imageElement_.setAttribute('y', halfHeight - imageHeight / 2); }; /** @@ -549,27 +599,55 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) { Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { // Retrieves the selected option to display through getText_. this.textContent_.nodeValue = this.getDisplayText_(); + Blockly.utils.dom.addClass(/** @type {!Element} */ (this.textElement_), + 'blocklyDropdownText'); this.textElement_.setAttribute('text-anchor', 'start'); - this.textElement_.setAttribute('x', - this.constants_.FIELD_BORDER_RECT_X_PADDING); + // Height and width include the border rect. this.size_.height = Math.max( this.constants_.FIELD_DROPDOWN_BORDER_RECT_HEIGHT, - this.constants_.FIELD_TEXT_HEIGHT + - this.constants_.FIELD_BORDER_RECT_Y_PADDING * 2); - this.size_.width = Blockly.utils.dom.getFastTextWidth(this.textElement_, + this.constants_.FIELD_TEXT_HEIGHT); + var halfHeight = this.size_.height / 2; + var textWidth = Blockly.utils.dom.getFastTextWidth(this.textElement_, this.constants_.FIELD_TEXT_FONTSIZE, this.constants_.FIELD_TEXT_FONTWEIGHT, - this.constants_.FIELD_TEXT_FONTFAMILY) + - this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; + this.constants_.FIELD_TEXT_FONTFAMILY); + var xPadding = this.constants_.FIELD_BORDER_RECT_X_PADDING; + var arrowWidth = 0; + if (this.svgArrow_) { + arrowWidth = this.positionSVGArrow_(textWidth + xPadding, halfHeight - + this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE / 2); + } + this.size_.width = textWidth + arrowWidth + xPadding * 2; - this.textElement_.setAttribute('y', this.size_.height / 2); + this.textElement_.setAttribute('x', this.sourceBlock_.RTL ? + this.size_.width - textWidth - xPadding : xPadding); + this.textElement_.setAttribute('y', halfHeight); if (!this.constants_.FIELD_TEXT_BASELINE_CENTER) { this.textElement_.setAttribute('dy', - this.constants_.FIELD_TEXT_BASELINE_Y - this.size_.height / 2); + this.constants_.FIELD_TEXT_BASELINE_Y - halfHeight); } }; +/** + * Position a drop-down arrow at the appropriate location at render-time. + * @param {number} x X position the arrow is being rendered at, in px. + * @param {number} y Y position the arrow is being rendered at, in px. + * @return {number} Amount of space the arrow is taking up, in px. + * @private + */ +Blockly.FieldDropdown.prototype.positionSVGArrow_ = function(x, y) { + if (!this.svgArrow_) { + return 0; + } + var padding = this.constants_.FIELD_BORDER_RECT_X_PADDING; + var svgArrowSize = this.constants_.FIELD_DROPDOWN_SVG_ARROW_SIZE; + var arrowX = this.sourceBlock_.RTL ? padding : x + padding; + this.svgArrow_.setAttribute('transform', + 'translate(' + arrowX + ',' + y + ')'); + return svgArrowSize + padding; +}; + /** * Use the `getText_` developer hook to override the field's text * representation. Get the selected option text. If the selected option is an diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index d53abadbb..cc1bf6edb 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -208,6 +208,12 @@ Blockly.blockRendering.ConstantProvider = function() { */ this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT; + /** + * Whether or not a dropdown field uses a text or SVG arrow. + * @type {boolean} + */ + this.FIELD_DROPDOWN_SVG_ARROW = false; + /** * A colour field's default width. * @type {number} diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 37fe00172..9b1c980a9 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -164,6 +164,36 @@ Blockly.zelos.ConstantProvider = function() { */ this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = 8 * this.GRID_UNIT; + /** + * @override + */ + this.FIELD_DROPDOWN_SVG_ARROW = true; + + /** + * A dropdown field's SVG arrow size. + * @type {number} + * @const + */ + this.FIELD_DROPDOWN_SVG_ARROW_SIZE = 12; + + /** + * A dropdown field's SVG arrow datauri. + * @type {string} + * @const + */ + this.FIELD_DROPDOWN_SVG_ARROW_DATAURI = + 'data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllci' + + 'AxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMi43MSIgaG' + + 'VpZ2h0PSI4Ljc5IiB2aWV3Qm94PSIwIDAgMTIuNzEgOC43OSI+PHRpdGxlPmRyb3Bkb3duLW' + + 'Fycm93PC90aXRsZT48ZyBvcGFjaXR5PSIwLjEiPjxwYXRoIGQ9Ik0xMi43MSwyLjQ0QTIuND' + + 'EsMi40MSwwLDAsMSwxMiw0LjE2TDguMDgsOC4wOGEyLjQ1LDIuNDUsMCwwLDEtMy40NSwwTD' + + 'AuNzIsNC4xNkEyLjQyLDIuNDIsMCwwLDEsMCwyLjQ0LDIuNDgsMi40OCwwLDAsMSwuNzEuNz' + + 'FDMSwwLjQ3LDEuNDMsMCw2LjM2LDBTMTEuNzUsMC40NiwxMiwuNzFBMi40NCwyLjQ0LDAsMC' + + 'wxLDEyLjcxLDIuNDRaIiBmaWxsPSIjMjMxZjIwIi8+PC9nPjxwYXRoIGQ9Ik02LjM2LDcuNz' + + 'lhMS40MywxLjQzLDAsMCwxLTEtLjQyTDEuNDIsMy40NWExLjQ0LDEuNDQsMCwwLDEsMC0yYz' + + 'AuNTYtLjU2LDkuMzEtMC41Niw5Ljg3LDBhMS40NCwxLjQ0LDAsMCwxLDAsMkw3LjM3LDcuMz' + + 'dBMS40MywxLjQzLDAsMCwxLDYuMzYsNy43OVoiIGZpbGw9IiNmZmYiLz48L3N2Zz4='; + /** * The ID of the highlight glow filter, or the empty string if no filter is * set. diff --git a/media/dropdown-arrow.svg b/media/dropdown-arrow.svg new file mode 100644 index 000000000..4e6ce19ec --- /dev/null +++ b/media/dropdown-arrow.svg @@ -0,0 +1 @@ +dropdown-arrow \ No newline at end of file From d8476306f442c5806c646574890025ef171ad78e Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Thu, 14 Nov 2019 16:04:46 -0800 Subject: [PATCH 195/343] Fix up more zelos spacing (#3445) * Fix up more of zelos spacing --- core/renderers/common/constants.js | 25 +++++++++++++++++++++++-- core/renderers/common/info.js | 9 +++++---- core/renderers/zelos/constants.js | 20 +++++++++++++++----- core/renderers/zelos/info.js | 21 +++++++++++++++++++++ tests/rendering/zelos/zelos.html | 7 ++++--- 5 files changed, 68 insertions(+), 14 deletions(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index cc1bf6edb..9bd0f20a4 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -82,8 +82,29 @@ Blockly.blockRendering.ConstantProvider = function() { this.STATEMENT_INPUT_PADDING_LEFT = 20; this.BETWEEN_STATEMENT_PADDING_Y = 4; - // The minimum height of the bottom row following a statement input. - this.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT = this.LARGE_PADDING; + /** + * The top row's minimum height. + * @type {number} + */ + this.TOP_ROW_MIN_HEIGHT = this.MEDIUM_PADDING; + + /** + * The top row's minimum height if it precedes a statement. + * @type {number} + */ + this.TOP_ROW_PRECEDES_STATEMENT_MIN_HEIGHT = this.LARGE_PADDING; + + /** + * The bottom row's minimum height. + * @type {number} + */ + this.BOTTOM_ROW_MIN_HEIGHT = this.MEDIUM_PADDING; + + /** + * The bottom row's minimum height if it follows a statement input. + * @type {number} + */ + this.BOTTOM_ROW_AFTER_STATEMENT_MIN_HEIGHT = this.LARGE_PADDING; // This is the max width of a bottom row that follows a statement input and // has inputs inline. diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index 8ebe44a0c..6a41b470d 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -286,9 +286,10 @@ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() { // 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. if (precedesStatement && !this.block_.isCollapsed()) { - this.topRow.minHeight = this.constants_.LARGE_PADDING; + this.topRow.minHeight = + this.constants_.TOP_ROW_PRECEDES_STATEMENT_MIN_HEIGHT; } else { - this.topRow.minHeight = this.constants_.MEDIUM_PADDING; + this.topRow.minHeight = this.constants_.TOP_ROW_MIN_HEIGHT; } var rightSquareCorner = this.topRow.hasRightSquareCorner(this.block_); @@ -318,9 +319,9 @@ Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() { // greater height it will be overwritten in the compute pass. if (followsStatement) { this.bottomRow.minHeight = - this.constants_.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT; + this.constants_.BOTTOM_ROW_AFTER_STATEMENT_MIN_HEIGHT; } else { - this.bottomRow.minHeight = this.constants_.MEDIUM_PADDING; + this.bottomRow.minHeight = this.constants_.BOTTOM_ROW_MIN_HEIGHT; } var leftSquareCorner = this.bottomRow.hasLeftSquareCorner(this.block_); diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 9b1c980a9..ea12bad23 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -91,6 +91,21 @@ Blockly.zelos.ConstantProvider = function() { */ this.TAB_OFFSET_FROM_TOP = 0; + /** + * @override + */ + this.TOP_ROW_MIN_HEIGHT = this.GRID_UNIT; + + /** + * @override + */ + this.BOTTOM_ROW_MIN_HEIGHT = this.GRID_UNIT; + + /** + * @override + */ + this.BOTTOM_ROW_AFTER_STATEMENT_MIN_HEIGHT = 7 * this.GRID_UNIT; + /** * @override */ @@ -107,11 +122,6 @@ Blockly.zelos.ConstantProvider = function() { */ this.STATEMENT_INPUT_PADDING_LEFT = 4 * this.GRID_UNIT; - /** - * @override - */ - this.AFTER_STATEMENT_BOTTOM_ROW_MIN_HEIGHT = 7 * this.GRID_UNIT; - /** * @override */ diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index 4060fbdbb..4a124580f 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -109,6 +109,27 @@ Blockly.zelos.RenderInfo.prototype.computeBounds_ = function() { } }; +/** + * @override + */ +Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { + if (!prev || !next) { + // No need for padding at the beginning or end of the row if the + // output shape is dynamic. + if (this.outputConnection && this.outputConnection.isDynamicShape) { + return this.constants_.NO_PADDING; + } + } + // Spacing between a rounded corner and a previous or next connection. + if (prev && Blockly.blockRendering.Types.isLeftRoundedCorner(prev) && next) { + if (Blockly.blockRendering.Types.isPreviousConnection(next) || + Blockly.blockRendering.Types.isNextConnection(next)) { + return next.notchOffset - this.constants_.CORNER_RADIUS; + } + } + return this.constants_.MEDIUM_PADDING; +}; + /** * @override */ diff --git a/tests/rendering/zelos/zelos.html b/tests/rendering/zelos/zelos.html index d1fd73706..7aa679e2c 100644 --- a/tests/rendering/zelos/zelos.html +++ b/tests/rendering/zelos/zelos.html @@ -32,9 +32,6 @@ - + + + + + + Scratch-Blocks + +
+
+
+

Zelos Rendering

+
+
+

PXT-Blockly Rendering

+
+
+
+
+ +
+
+ +
+
+
+
+
+

Zelos Rendering

+ +
+
+

PXT-Blockly Rendering

+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/tests/rendering/zelos/pxtblockly/pxtblockly.html b/tests/rendering/zelos/pxtblockly/pxtblockly.html new file mode 100644 index 000000000..8ee2e9560 --- /dev/null +++ b/tests/rendering/zelos/pxtblockly/pxtblockly.html @@ -0,0 +1,68 @@ + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/tests/rendering/zelos/pxtblockly/zelos.html b/tests/rendering/zelos/pxtblockly/zelos.html new file mode 100644 index 000000000..6d00f750e --- /dev/null +++ b/tests/rendering/zelos/pxtblockly/zelos.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/tests/rendering/zelos/scratchblocks/index.html b/tests/rendering/zelos/scratchblocks/index.html new file mode 100644 index 000000000..9814d5eaf --- /dev/null +++ b/tests/rendering/zelos/scratchblocks/index.html @@ -0,0 +1,166 @@ + + + + + + + + + + + PXT-Blockly + +
+
+
+

Zelos Rendering

+
+
+

Scratch-Blocks Rendering

+
+
+
+
+ +
+
+ +
+
+
+
+
+

Zelos Rendering

+ +
+
+

Scratch-Blocks Rendering

+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/tests/rendering/zelos/scratchblocks/scratchblocks.html b/tests/rendering/zelos/scratchblocks/scratchblocks.html new file mode 100644 index 000000000..801123097 --- /dev/null +++ b/tests/rendering/zelos/scratchblocks/scratchblocks.html @@ -0,0 +1,70 @@ + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/tests/rendering/zelos/scratchblocks/zelos.html b/tests/rendering/zelos/scratchblocks/zelos.html new file mode 100644 index 000000000..3cc6810a9 --- /dev/null +++ b/tests/rendering/zelos/scratchblocks/zelos.html @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file From 8013f80251eaddf887c3fff380d49a69b690d48e Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 13 Jan 2020 13:22:49 -0800 Subject: [PATCH 294/343] Start hat support in zelos. (#3580) * Start hat support in zelos. --- core/renderers/common/constants.js | 4 +-- core/renderers/zelos/constants.js | 31 ++++++++++++++++++++++++ core/renderers/zelos/info.js | 5 ++++ core/renderers/zelos/measurables/rows.js | 5 +++- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 8d24c4301..9916a4925 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -194,13 +194,13 @@ Blockly.blockRendering.ConstantProvider = function() { /** * Height of the top hat. - * @private + * @type {number} */ this.START_HAT_HEIGHT = 15; /** * Width of the top hat. - * @private + * @type {number} */ this.START_HAT_WIDTH = 100; diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 17c6f2871..135d61130 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -189,6 +189,16 @@ Blockly.zelos.ConstantProvider = function() { */ this.JAGGED_TEETH_WIDTH = 0; + /** + * @override + */ + this.START_HAT_HEIGHT = 22; + + /** + * @override + */ + this.START_HAT_WIDTH = 96; + /** * @enum {number} * @override @@ -423,6 +433,27 @@ Blockly.zelos.ConstantProvider.prototype.dispose = function() { } }; +/** + * @override + */ +Blockly.zelos.ConstantProvider.prototype.makeStartHat = function() { + var height = this.START_HAT_HEIGHT; + var width = this.START_HAT_WIDTH; + + var mainPath = + Blockly.utils.svgPaths.curve('c', + [ + Blockly.utils.svgPaths.point(25, -height), + Blockly.utils.svgPaths.point(71, -height), + Blockly.utils.svgPaths.point(width, 0) + ]); + return { + height: height, + width: width, + path: mainPath + }; +}; + /** * Create sizing and path information about a hexagonal shape. * @return {!Object} An object containing sizing and path information about diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index cf7d45554..4939fcd06 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -181,6 +181,11 @@ Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { return next.notchOffset - this.constants_.CORNER_RADIUS; } } + // Spacing between a square corner and a hat. + if (prev && Blockly.blockRendering.Types.isLeftSquareCorner(prev) && next && + Blockly.blockRendering.Types.isHat(next)) { + return this.constants_.NO_PADDING; + } return this.constants_.MEDIUM_PADDING; }; diff --git a/core/renderers/zelos/measurables/rows.js b/core/renderers/zelos/measurables/rows.js index 1d1a34dfe..64c5836b8 100644 --- a/core/renderers/zelos/measurables/rows.js +++ b/core/renderers/zelos/measurables/rows.js @@ -62,7 +62,10 @@ Blockly.zelos.TopRow.prototype.endsWithElemSpacer = function() { * @override */ Blockly.zelos.TopRow.prototype.hasLeftSquareCorner = function(block) { - return !!block.outputConnection; + var hasHat = (typeof block.hat !== 'undefined' ? + block.hat === 'cap' : this.constants_.ADD_START_HATS) && + !block.outputConnection && !block.previousConnection; + return !!block.outputConnection || hasHat; }; /** From 7e34d946100a3f8c4d1adb0dd877e45cd69b62ac Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 13 Jan 2020 13:34:29 -0800 Subject: [PATCH 295/343] Fixes blockly games blocks being black (#3579) * Fixes blockly games blocks being black --- core/renderers/common/constants.js | 5 ++--- tests/compile/compile.sh | 2 +- tests/compile/index.html | 1 + tests/compile/main.js | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 9916a4925..e623b18f9 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -593,7 +593,7 @@ Blockly.blockRendering.ConstantProvider.prototype.getBlockStyle = function( Blockly.blockRendering.ConstantProvider.prototype.createBlockStyle_ = function( colour) { return this.validatedBlockStyle_({ - colourPrimary: colour + 'colourPrimary': colour }); }; @@ -619,7 +619,6 @@ Blockly.blockRendering.ConstantProvider.prototype.validatedBlockStyle_ = if (blockStyle) { Blockly.utils.object.mixin(valid, blockStyle); } - // Validate required properties. var parsedColour = Blockly.utils.parseBlockColour( valid['colourPrimary'] || '#000'); @@ -627,7 +626,7 @@ Blockly.blockRendering.ConstantProvider.prototype.validatedBlockStyle_ = valid.colourSecondary = valid['colourSecondary'] ? Blockly.utils.parseBlockColour(valid['colourSecondary']).hex : this.generateSecondaryColour_(valid.colourPrimary); - valid.colourTertiary = valid.colourTertiary ? + valid.colourTertiary = valid['colourTertiary'] ? Blockly.utils.parseBlockColour(valid['colourTertiary']).hex : this.generateTertiaryColour_(valid.colourPrimary); diff --git a/tests/compile/compile.sh b/tests/compile/compile.sh index 0f05f212f..b3251fc48 100755 --- a/tests/compile/compile.sh +++ b/tests/compile/compile.sh @@ -57,7 +57,7 @@ tempPath="$BLOCKLY_ROOT/temp_core" corePath="$BLOCKLY_ROOT/core/*" mkdir $tempPath cp $corePath $tempPath - +cp "$BLOCKLY_ROOT/tests/compile/test_blocks.js" "$tempPath/test_blocks.js" # Copy over all files in core and any subdirectories to the temp_core directory. for dir in "$corePath/" ; do # For all files in the directory and any subdirectories rename them to diff --git a/tests/compile/index.html b/tests/compile/index.html index eb067cee9..1ec1ce85a 100644 --- a/tests/compile/index.html +++ b/tests/compile/index.html @@ -38,6 +38,7 @@ + diff --git a/tests/compile/main.js b/tests/compile/main.js index d0c882114..3f0ec2235 100644 --- a/tests/compile/main.js +++ b/tests/compile/main.js @@ -31,6 +31,7 @@ goog.require('Blockly.Constants.Colour'); goog.require('Blockly.Constants.Variables'); goog.require('Blockly.Constants.VariablesDynamic'); goog.require('Blockly.Blocks.procedures'); +goog.require('Blockly.TestBlocks') Main.init = function() { Blockly.inject('blocklyDiv', { From 4f80bd6cbf5723808921f7ab72e8886116ca075f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 13 Jan 2020 15:47:54 -0800 Subject: [PATCH 296/343] Simplify zelos tight nesting logic (#3583) --- core/renderers/zelos/info.js | 65 +++++++++++++++++------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index 4939fcd06..00e9c1985 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -529,47 +529,44 @@ Blockly.zelos.RenderInfo.prototype.finalizeVerticalAlignment_ = function() { var row = this.rows[i]; var nextSpacer = this.rows[i + 1]; - var hasPrevNotch = i == 2 ? + var firstRow = i == 2; + var hasPrevNotch = firstRow ? !!this.topRow.hasPreviousConnection : !!prevSpacer.followsStatement; var hasNextNotch = i + 2 >= this.rows.length - 1 ? !!this.bottomRow.hasNextConnection : !!nextSpacer.precedesStatement; - - // Apply tight-nesting if we have both a prev and next notch. - if (hasPrevNotch && hasNextNotch && - Blockly.blockRendering.Types.isInputRow(row)) { - // Determine if the input row has non-shadow connected blocks. - var hasNonShadowConnectedBlocks = false; - var hasSingleTextOrImageField = null; - var MIN_VERTICAL_TIGHTNESTING_HEIGHT = 40; - for (var j = 0, elem; (elem = row.elements[j]); j++) { - if (Blockly.blockRendering.Types.isInlineInput(elem) && - elem.connectedBlock && !elem.connectedBlock.isShadow() && - elem.connectedBlock.getHeightWidth().height >= - MIN_VERTICAL_TIGHTNESTING_HEIGHT) { - hasNonShadowConnectedBlocks = true; - hasSingleTextOrImageField = false; - break; - } else if (Blockly.blockRendering.Types.isField(elem) && - (elem.field instanceof Blockly.FieldLabel || - elem.field instanceof Blockly.FieldImage)) { - hasSingleTextOrImageField = - hasSingleTextOrImageField == null ? true : false; - } else if (!Blockly.blockRendering.Types.isSpacer(elem)) { - hasSingleTextOrImageField = false; - } - } - // Reduce the previous and next spacer's height. - if (hasNonShadowConnectedBlocks) { - prevSpacer.height -= this.constants_.SMALL_PADDING; - nextSpacer.height -= this.constants_.SMALL_PADDING; - } else if (i != 2 && hasSingleTextOrImageField) { + + if (hasPrevNotch) { + var hasSingleTextOrImageField = row.elements.length == 3 && + (row.elements[1].field instanceof Blockly.FieldLabel || + row.elements[1].field instanceof Blockly.FieldImage); + if (!firstRow && hasSingleTextOrImageField) { + // Remove some padding if we have a single image or text field. prevSpacer.height -= this.constants_.SMALL_PADDING; nextSpacer.height -= this.constants_.SMALL_PADDING; row.height -= this.constants_.MEDIUM_PADDING; + } else if (!firstRow && !hasNextNotch) { + // Add a small padding so the notch doesn't clash with inputs/fields. + prevSpacer.height += this.constants_.SMALL_PADDING; + } else if (hasNextNotch) { + // Determine if the input row has non-shadow connected blocks. + var hasNonShadowConnectedBlocks = false; + var MIN_VERTICAL_TIGHTNESTING_HEIGHT = 40; + for (var j = 0, elem; (elem = row.elements[j]); j++) { + if (Blockly.blockRendering.Types.isInlineInput(elem) && + elem.connectedBlock && !elem.connectedBlock.isShadow() && + elem.connectedBlock.getHeightWidth().height >= + MIN_VERTICAL_TIGHTNESTING_HEIGHT) { + hasNonShadowConnectedBlocks = true; + break; + } + } + // Apply tight-nesting if we have both a prev and next notch and the + // block has non-shadow connected blocks. + if (hasNonShadowConnectedBlocks) { + prevSpacer.height -= this.constants_.SMALL_PADDING; + nextSpacer.height -= this.constants_.SMALL_PADDING; + } } - } else if (i != 2 && hasPrevNotch && !hasNextNotch) { - // Add a small padding so the notch doesn't interfere with inputs/fields. - prevSpacer.height += this.constants_.SMALL_PADDING; } } }; From 1278cd95eaa617b57bdb584323b12458c0ecc71b Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 13 Jan 2020 15:51:42 -0800 Subject: [PATCH 297/343] test: Added connection test blocks. (#3525) * test: Added connection test blocks. --- tests/blocks/test_blocks.js | 363 ++++++++++++++++++++++++++++++++++++ tests/playground.html | 158 +++++++++++++++- 2 files changed, 517 insertions(+), 4 deletions(-) diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index 501c55b62..d599c316c 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -205,6 +205,369 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "inputsInline": false, "style": "math_blocks" }, + { + "type": "test_connections_row_input", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "NAME", + } + ], + "colour": '#aaaaaa', + "tooltip": "No Checks\n" + + "Can connect to any output connection." + }, + { + "type": "test_connections_row_blue", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "NAME", + "check": "greenRel" + } + ], + "output": "noneOut", + "colour": 230, + "tooltip": "Output: noneOut\n" + + "Input: greenRel\n" + + "Input connection can accept yellow blocks but not red blocks." + }, + { + "type": "test_connections_row_yellow", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "NAME", + "check": [ + "orangeRel", + "yellowRel" + ] + } + ], + "output": [ + "yellowRel", + "greenRel" + ], + "colour": 60, + "tooltip": "Output: yellowRel, greenRel\n" + + "Input: yellowRel, orangeRel\n" + + "Output can connect to yellow blocks and blue blocks, but not red blocks.\n" + + "Input can connect to yellow blocks and red blocks, but not blue blocks." + }, + { + "type": "test_connections_row_red", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "NAME", + "check": "noneIn" + } + ], + "output": "orangeRel", + "colour": 0, + "tooltip": "Output: orangeRel\n" + + "Input: noneIn\n" + + "Output can connect to yellow blocks, but not blue blocks." + }, + { + "type": "test_connections_row_output", + "message0": "", + "output": null, + "colour": '#aaaaaa', + "tooltip": "No Checks\n" + + "Can connect to any input connection." + }, + { + "type": "test_connections_multivalue_1valid", + "message0": "none %1 both %2", + "args0": [ + { + "type": "input_value", + "name": "NAME1", + "align": "RIGHT", + "check": "noneIn" + }, + { + "type": "input_value", + "name": "NAME2", + "align": "RIGHT", + "check": [ + "yellowRel", + "orangeRel" + ] + } + ], + "output": [ + "yellowRel", + "greenRel" + ], + "colour": 60, + "tooltip": "Output: yellowRel, greenRel\n" + + "Input Top: noneIn\n" + + "Input Bottom: yellowRel, orangeRel\n" + + "Output can connect to yellow blocks and blue blocks, but not red blocks.\n" + + "Top Input can connect to nothing, except grey blocks.\n" + + "Bottom Input can connect to yellow blocks and red blocks, but not blue" + + " blocks." + }, + { + "type": "test_connections_multivalue_2valid", + "message0": "both %1 both %2", + "args0": [ + { + "type": "input_value", + "name": "NAME1", + "align": "RIGHT", + "check": [ + "yellowRel", + "orangeRel" + ] + }, + { + "type": "input_value", + "name": "NAME2", + "align": "RIGHT", + "check": [ + "yellowRel", + "orangeRel" + ] + } + ], + "output": [ + "yellowRel", + "greenRel" + ], + "colour": 60, + "tooltip": "Output: yellowRel, greenRel\n" + + "Input Top: yellowRel, orangeRel\n" + + "Input Bottom: yellowRel, orangeRel\n" + + "Output can connect to yellow blocks and blue blocks, but not red blocks.\n" + + "Top Input can connect to yellow blocks and red blocks, but not blue" + + " blocks.\n" + + "Bottom Input can connect to yellow blocks and red blocks, but not blue" + + " blocks." + }, + { + "type": "test_connections_stack_next", + "message0": "", + "nextStatement": null, + "colour": '#aaaaaa', + "tooltip": "No Checks\n" + + "Can connect to any previous connection." + }, + { + "type": "test_connections_stack_blue", + "message0": "", + "previousStatement": "nonePrev", + "nextStatement": "greenRel", + "colour": 230, + "tooltip": "Prev: nonePrev\n" + + "Next: greenRel\n" + + "Next connection can accept yellow blocks but not red blocks." + }, + { + "type": "test_connections_stack_yellow", + "message0": "", + "previousStatement": [ + "greenRel", + "yellowRel" + ], + "nextStatement": [ + "yellowRel", + "orangeRel" + ], + "colour": 60, + "tooltip": "Prev: yellowRel, greenRel\n" + + "Next: yellowRel, orangeRel\n" + + "Prev can connect to yellow blocks and blue blocks, but not red blocks.\n" + + "Next can connect to yellow blocks and red blocks, but not blue blocks." + }, + { + "type": "test_connections_stack_red", + "message0": "", + "previousStatement": "orangeRel", + "nextStatement": "noneNext", + "colour": 0, + "tooltip": "Prev: orangeRel\n" + + "Next: noneNext\n" + + "Prev can connect to yellow blocks, but not blue blocks." + }, + { + "type": "test_connections_stack_prev", + "message0": "", + "previousStatement": null, + "colour": '#aaaaaa', + "tooltip": "No Checks\n" + + "Can connect to any input connection." + }, + { + "type": "test_connections_statement_blue", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "NAME", + "check": "greenRel" + } + ], + "previousStatement": "nonePrev", + "nextStatement": "greenRel", + "colour": 230, + "tooltip": "Prev: nonePrev\n" + + "Next: greenRel\n" + + "Statement: greenRel\n" + + "Next connection can accept yellow blocks but not red blocks.\n" + + "Statement connection can accept yellow blocks but not red blocks." + }, + { + "type": "test_connections_statement_yellow", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "NAME", + "check": [ + "yellowRel", + "orangeRel" + ] + } + ], + "previousStatement": [ + "greenRel", + "yellowRel" + ], + "nextStatement": [ + "yellowRel", + "orangeRel" + ], + "colour": 60, + "tooltip": "Prev: yellowRel, greenRel\n" + + "Next: yellowRel, orangeRel\n" + + "Statement: orangeRel\n" + + "Prev can connect to yellow blocks and blue blocks, but not red" + + " blocks.\n" + + "Next can connect to yellow blocks and red blocks, but not blue" + + " blocks.\n" + + "Statement connection can accept yellow blocks and red blocks but not" + + " blue blocks.\n" + }, + { + "type": "test_connections_statement_red", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "NAME", + "check": "noneNext" + } + ], + "previousStatement": "orangeRel", + "nextStatement": "noneNext", + "colour": 0, + "tooltip": "Prev: orangeRel\n" + + "Next: noneNext\n" + + "Statement: noneNext\n" + + "Prev connection can accept yellow blocks but not blue blocks.\n" + + "Statement connection accepts none." + }, + { + "type": "test_connections_statement_nonext", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "NAME", + "check": [ + "yellowRel", + "orangeRel" + ] + } + ], + "previousStatement": [ + "greenRel", + "yellowRel" + ], + "colour": 60, + "tooltip": "Prev: yellowRel, greenRel\n" + + "Next: yellowRel, orangeRel\n" + + "Statement: orangeRel\n" + + "Prev can connect to yellow blocks and blue blocks, but not red" + + " blocks.\n" + + "Statement connection can accept yellow blocks and red blocks but not" + + " blue blocks.\n" + }, + { + "type": "test_connections_multistatement_1valid", + "message0": "none %1 both %2", + "args0": [ + { + "type": "input_statement", + "name": "NAME", + "check": "noneNext" + }, + { + "type": "input_statement", + "name": "NAME", + "check": [ + "yellowRel", + "orangeRel" + ] + } + ], + "previousStatement": [ + "greenRel", + "yellowRel" + ], + "colour": 60, + "tooltip": "Prev: yellowRel, greenRel\n" + + "Next: yellowRel, orangeRel\n" + + "Statement: orangeRel\n" + + "Prev can connect to yellow blocks and blue blocks, but not red" + + " blocks.\n" + + "Top Statement cannot connect to anything, except grey blocks.\n" + + "Bottom Statement connection can accept yellow blocks and red blocks" + + " but not blue blocks.\n" + }, + { + "type": "test_connections_multistatement_2valid", + "message0": "both %1 both %2", + "args0": [ + { + "type": "input_statement", + "name": "NAME", + "check": [ + "yellowRel", + "orangeRel" + ] + }, + { + "type": "input_statement", + "name": "NAME", + "check": [ + "yellowRel", + "orangeRel" + ] + } + ], + "previousStatement": [ + "greenRel", + "yellowRel" + ], + "colour": 60, + "tooltip": "Prev: yellowRel, greenRel\n" + + "Next: yellowRel, orangeRel\n" + + "Statement: orangeRel\n" + + "Prev can connect to yellow blocks and blue blocks, but not red" + + " blocks.\n" + + "Top Statement connection can accept yellow blocks and red blocks but" + + " not blue blocks.\n" + + "Bottom Statement connection can accept yellow blocks and red blocks" + + " but not blue blocks.\n" + }, { "type": "test_dropdowns_long", "message0": "long: %1", diff --git a/tests/playground.html b/tests/playground.html index d866fd0d6..f3a306dc8 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -249,6 +249,82 @@ function addToolboxButtonCallbacks() { workspace.createVariable('2b', '', '2B'); workspace.createVariable('2c', '', '2C'); }; + var insertConnectionRows = function(button) { + var workspace = button.getTargetWorkspace(); + Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom( + '\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + '' + ), workspace) + }; + var insertConnectionStacks = function(button) { + var workspace = button.getTargetWorkspace(); + Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom( + '\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + '' + ), workspace); + }; + var insertConnectionStatements = function(button) { + var workspace = button.getTargetWorkspace(); + Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom( + '\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + '' + ), workspace); + }; workspace.registerButtonCallback( 'addVariables', addVariables); @@ -272,6 +348,12 @@ function addToolboxButtonCallbacks() { 'addDynamicOption', Blockly.TestBlocks.addDynamicDropdownOption_); workspace.registerButtonCallback( 'removeDynamicOption', Blockly.TestBlocks.removeDynamicDropdownOption_); + workspace.registerButtonCallback( + 'insertConnectionRows', insertConnectionRows); + workspace.registerButtonCallback( + 'insertConnectionStacks', insertConnectionStacks); + workspace.registerButtonCallback( + 'insertConnectionStatements', insertConnectionStatements); } function setRenderDebugOptionCheckboxState(overrideOptions) { @@ -1361,6 +1443,11 @@ var spaghettiXml = [ the standard predefined blocks, and so test alternative block rendering code paths. -->