From d4e0594c2cd1dd5df8962e9638d368133817476f Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 19 Aug 2019 09:24:31 -0700 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 e09a7b8165e8f587fe85fbefbbeaeaef34e3131c Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 5 Oct 2019 12:28:25 -0700 Subject: [PATCH 7/7] 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).