diff --git a/core/connection.js b/core/connection.js index a4cc160c5..3e5200455 100644 --- a/core/connection.js +++ b/core/connection.js @@ -154,7 +154,8 @@ Blockly.Connection.prototype.isSuperior = function() { /** * Returns the distance between this connection and another connection. - * @param {Blockly.Connection} otherConnection The other connection to measure the distance to. + * @param {!Blockly.Connection} otherConnection The other connection to measure + * the distance to. * @return {number} The distance between connections. */ Blockly.Connection.prototype.distanceFrom = function(otherConnection) { @@ -217,6 +218,60 @@ Blockly.Connection.prototype.checkConnection_ = function(target) { } }; +/** + * Check if the two connections can be dragged to connect to each other. + * @param {Blockly.Connection} candidate A nearby connection to check. + * @param {number} maxRadius The maximum radius allowed for connections. + * @return {boolean} True if the connection is allowed, false otherwise. + */ +Blockly.Connection.prototype.isConnectionAllowed = function(candidate, + maxRadius) { + if (this.distanceFrom(candidate) > maxRadius) { + return false; + } + + // Type checking + var canConnect = this.canConnectWithReason_(candidate); + if (canConnect != Blockly.Connection.CAN_CONNECT + && canConnect != Blockly.Connection.REASON_MUST_DISCONNECT) { + return false; + } + + // Don't offer to connect an already connected left (male) value plug to + // an available right (female) value plug. Don't offer to connect the + // bottom of a statement block to one that's already connected. + if (candidate.type == Blockly.OUTPUT_VALUE + || candidate.type == Blockly.PREVIOUS_STATEMENT) { + if (candidate.targetConnection || this.targetConnection) { + return false; + } + } + + // Offering to connect the left (male) of a value block to an already + // connected value pair is ok, we'll splice it in. + // However, don't offer to splice into an unmovable block. + if (candidate.type == Blockly.INPUT_VALUE && + candidate.targetConnection && + !candidate.targetBlock().isMovable() && + !candidate.targetBlock().isShadow()) { + return false; + } + + // Don't let blocks try to connect to themselves or ones they nest. + var targetSourceBlock = candidate.sourceBlock_; + var sourceBlock = this.sourceBlock_; + if (targetSourceBlock && sourceBlock) { + do { + if (sourceBlock == targetSourceBlock) { + return false; + } + targetSourceBlock = targetSourceBlock.getParent(); + } while (targetSourceBlock); + } + + return true; +}; + /** * Connect this connection to another connection. * @param {!Blockly.Connection} otherConnection Connection to connect to. @@ -513,7 +568,7 @@ Blockly.Connection.prototype.moveTo = function(x, y) { this.y_ = y; // Insert it into its new location in the database. if (!this.hidden_) { - this.db_.addConnection_(this); + this.db_.addConnection(this); } }; @@ -553,13 +608,16 @@ Blockly.Connection.prototype.tighten_ = function() { * in the database and the current location (as a result of dragging). * @param {number} dy Vertical 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.Connection, radius: number}} Contains two + * properties:' connection' which is either another connection or null, + * and 'radius' which is the distance. */ Blockly.Connection.prototype.closest = function(maxLimit, dx, dy) { - var closestConnection = this.dbOpposite_.searchForClosest(this, maxLimit, dx, dy); + var closestConnection = this.dbOpposite_.searchForClosest(this, maxLimit, dx, + dy); if (closestConnection) { - return {connection: closestConnection, radius: this.distanceFrom(closestConnection)}; + return {connection: closestConnection, + radius: this.distanceFrom(closestConnection)}; } return {connection: null, radius: maxLimit}; }; @@ -653,22 +711,6 @@ Blockly.Connection.prototype.neighbours_ = function(maxLimit) { // Appearance or lack thereof. -/** - * Returns a shape enum for this connection. - * @return {number} Enum representing shape. - */ -Blockly.Connection.prototype.getOutputShape = function() { - if (!this.check_) return Blockly.Connection.NUMBER; - if (this.check_.indexOf('Boolean') !== -1) { - return Blockly.Connection.BOOLEAN; - } - if (this.check_.indexOf('String') !== -1) { - return Blockly.Connection.STRING; - } - - return Blockly.Connection.NUMBER; -}; - /** * Set whether this connections is hidden (not tracked in a database) or not. * @param {boolean} hidden True if connection is hidden. @@ -678,7 +720,7 @@ Blockly.Connection.prototype.setHidden = function(hidden) { if (hidden && this.inDB_) { this.db_.removeConnection_(this); } else if (!hidden && !this.inDB_) { - this.db_.addConnection_(this); + this.db_.addConnection(this); } }; @@ -756,10 +798,10 @@ Blockly.Connection.prototype.highlight = function() { if (this.type == Blockly.INPUT_VALUE || this.type == Blockly.OUTPUT_VALUE) { var tabWidth = this.sourceBlock_.RTL ? -Blockly.BlockSvg.TAB_WIDTH : Blockly.BlockSvg.TAB_WIDTH; - steps = 'm 0,0 v 4 ' + Blockly.BlockSvg.NOTCH_PATH_DOWN + ' v 4'; + steps = 'm 0,0 ' + Blockly.BlockSvg.TAB_PATH_DOWN + ' v 5'; } else { - steps = 'm 0,0 v -4 ' + Blockly.BlockSvg.NOTCH_PATH_UP + ' v -4'; + steps = 'm -20,0 h 5 ' + Blockly.BlockSvg.NOTCH_PATH_LEFT + ' h 5'; } var xy = this.sourceBlock_.getRelativeToSurfaceXY(); var x = this.x_ - xy.x; diff --git a/core/connection_db.js b/core/connection_db.js index eb5378c3b..b039b5189 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -50,7 +50,7 @@ Blockly.ConnectionDB.constructor = Blockly.ConnectionDB; * @param {!Blockly.Connection} connection The connection to be added. * @private */ -Blockly.ConnectionDB.prototype.addConnection_ = function(connection) { +Blockly.ConnectionDB.prototype.addConnection = function(connection) { if (connection.inDB_) { throw 'Connection already in database.'; } @@ -65,8 +65,8 @@ Blockly.ConnectionDB.prototype.addConnection_ = function(connection) { /** * Find the given connection. - * Starts by doing a binary search to find the approximate location, then linearly searches - * nearby for the exact connection. + * 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. * @return The index of the connection, or -1 if the connection was not found. */ @@ -103,7 +103,8 @@ 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. + * 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. * @return {number} The candidate index. * @private @@ -148,7 +149,8 @@ Blockly.ConnectionDB.prototype.removeConnection_ = function(connection) { /** * 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.Connection} connection The connection whose neighbours should + * be returned. * @param {number} maxRadius The maximum radius to another connection. * @return {!Array.} List of connections. * @private @@ -212,16 +214,18 @@ 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 mate. + * @param {Blockly.Connection} conn The connection searching for a compatible + * mate. * @param {number} maxRadius The maximum radius to another connection. * @param {number} dx Horizontal offset between this connection's location * in the database and the current location (as a result of dragging). * @param {number} dy Vertical 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 + * @return ?Blockly.Connection the closest valid connection. * another connection or null, and 'radius' which is the distance. */ -Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx, dy) { +Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx, + dy) { // Don't bother. if (this.length == 0) { return null; @@ -234,9 +238,9 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx, conn.x_ = baseX + dx; conn.y_ = baseY + dy; - // findPositionForConnection 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. + // findPositionForConnection 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 bestConnection = null; @@ -245,23 +249,25 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx, // 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)) { - temp = this[pointerMin]; - if (this.isConnectionAllowed(conn, temp, bestRadius)) { - bestConnection = temp; - bestRadius = temp.distanceFrom(conn); - } - pointerMin--; + while (pointerMin >= 0 && + this.isInYRange_(pointerMin, conn.y_, maxRadius)) { + temp = this[pointerMin]; + if (conn.isConnectionAllowed(temp, bestRadius)) { + bestConnection = temp; + bestRadius = temp.distanceFrom(conn); + } + pointerMin--; } var pointerMax = closestIndex; - while (pointerMax < this.length && this.isInYRange_(pointerMax, conn.y_, maxRadius)) { - temp = this[pointerMax]; - if (this.isConnectionAllowed(conn, temp, bestRadius)) { - bestConnection = temp; - bestRadius = temp.distanceFrom(conn); - } - pointerMax++; + while (pointerMax < this.length && this.isInYRange_(pointerMax, conn.y_, + maxRadius)) { + temp = this[pointerMax]; + if (conn.isConnectionAllowed(temp, bestRadius)) { + bestConnection = temp; + bestRadius = temp.distanceFrom(conn); + } + pointerMax++; } // Reset the values of x and y. @@ -270,61 +276,6 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx, return bestConnection; }; -// TODO: fenichel: consider moving this to connection.js -/** - * Check if the two connections can be dragged to connect to each other. - * @param {Blockly.Connection} moving The connection being dragged. - * @param {Blockly.Connection} candidate A nearby connection to check. - * @param {number} maxRadius The maximum radius allowed for connections. - * @return {boolean} True if the connection is allowed, false otherwise. - */ -Blockly.ConnectionDB.prototype.isConnectionAllowed = function(moving, candidate, maxRadius) { - if (moving.distanceFrom(candidate) > maxRadius) { - return false; - } - - // Type checking - var canConnect = moving.canConnectWithReason_(candidate); - if (canConnect != Blockly.Connection.CAN_CONNECT - && canConnect != Blockly.Connection.REASON_MUST_DISCONNECT) { - return false; - } - - // Don't offer to connect an already connected left (male) value plug to - // an available right (female) value plug. Don't offer to connect the - // bottom of a statement block to one that's already connected. - if (candidate.type == Blockly.OUTPUT_VALUE - || candidate.type == Blockly.PREVIOUS_STATEMENT) { - if (candidate.targetConnection) { - return false; - } - } - - // Offering to connect the left (male) of a value block to an already - // connected value pair is ok, we'll splice it in. - // However, don't offer to splice into an unmovable block. - if (candidate.type == Blockly.INPUT_VALUE && - candidate.targetConnection && - !candidate.targetBlock().isMovable() && - !candidate.targetBlock().isShadow()) { - return true; - } - - // Don't let blocks try to connect to themselves or ones they nest. - var targetSourceBlock = candidate.sourceBlock_; - var sourceBlock = moving.sourceBlock_; - if (targetSourceBlock && sourceBlock) { - do { - if (sourceBlock == targetSourceBlock) { - return true; - } - targetSourceBlock = targetSourceBlock.getParent(); - } while (targetSourceBlock); - } - - return true; -}; - /** * Initialize a set of connection DBs for a specified workspace. * @param {!Blockly.Workspace} workspace The workspace this DB is for. diff --git a/tests/jsunit/connection_db_test.js b/tests/jsunit/connection_db_test.js index 99ac3e478..6c76594c8 100644 --- a/tests/jsunit/connection_db_test.js +++ b/tests/jsunit/connection_db_test.js @@ -39,23 +39,23 @@ function verify_DB_(msg, expected, db) { function test_DB_addConnection() { var db = new Blockly.ConnectionDB(); var o2 = {y_: 2, sourceBlock_: {}}; - db.addConnection_(o2); + db.addConnection(o2); verify_DB_('Adding connection #2', [o2], db); var o4 = {y_: 4, sourceBlock_: {}}; - db.addConnection_(o4); + db.addConnection(o4); verify_DB_('Adding connection #4', [o2, o4], db); var o1 = {y_: 1, sourceBlock_: {}}; - db.addConnection_(o1); + db.addConnection(o1); verify_DB_('Adding connection #1', [o1, o2, o4], db); var o3a = {y_: 3, sourceBlock_: {}}; - db.addConnection_(o3a); + db.addConnection(o3a); verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db); var o3b = {y_: 3, sourceBlock_: {}}; - db.addConnection_(o3b); + db.addConnection(o3b); verify_DB_('Adding connection #3b', [o1, o2, o3b, o3a, o4], db); } @@ -67,12 +67,12 @@ function test_DB_removeConnection() { var o3b = {y_: 3, sourceBlock_: {}}; var o3c = {y_: 3, sourceBlock_: {}}; var o4 = {y_: 4, sourceBlock_: {}}; - db.addConnection_(o1); - db.addConnection_(o2); - db.addConnection_(o3c); - db.addConnection_(o3b); - db.addConnection_(o3a); - db.addConnection_(o4); + db.addConnection(o1); + db.addConnection(o2); + db.addConnection(o3c); + db.addConnection(o3b); + db.addConnection(o3a); + db.addConnection(o4); verify_DB_('Adding connections 1-4', [o1, o2, o3a, o3b, o3c, o4], db); db.removeConnection_(o2); @@ -98,143 +98,169 @@ function test_DB_getNeighbours() { var db = new Blockly.ConnectionDB(); // Search an empty list. - assertEquals(helper_getNeighbours(db, 10 /* x */, 10 /* y */, 100 /* radius */).length, 0); + assertEquals(helper_getNeighbours(db, + 10 /* x */, 10 /* y */, 100 /* radius */).length, 0); // Set up some connections. for (var i = 0; i < 10; i++) { - db.addConnection_(helper_createConnection(0, i, Blockly.PREVIOUS_STATEMENT)); + db.addConnection(helper_createConnection(0, i, + Blockly.PREVIOUS_STATEMENT)); } - // Test block belongs at beginning + // Test block belongs at beginning. var result = helper_getNeighbours(db, 0, 0, 4); assertEquals(5, result.length); for (i = 0; i < result.length; i++) { - assertNotEquals(result.indexOf(db[i]), -1); // contains + assertNotEquals(result.indexOf(db[i]), -1); // contains } - // Test block belongs at middle + // Test block belongs at middle. result = helper_getNeighbours(db, 0, 4, 2); assertEquals(5, result.length); for (i = 0; i < result.length; i++) { - assertNotEquals(result.indexOf(db[i + 2]), -1); // contains + assertNotEquals(result.indexOf(db[i + 2]), -1); // contains } - // Test block belongs at end + // Test block belongs at end. result = helper_getNeighbours(db, 0, 9, 4); assertEquals(5, result.length); for (i = 0; i < result.length; i++) { - assertNotEquals(result.indexOf(db[i + 5]), -1); // contains + assertNotEquals(result.indexOf(db[i + 5]), -1); // contains } - // Test block has no neighbours due to being out of range in the x direction + // Test block has no neighbours due to being out of range in the x direction. result = helper_getNeighbours(db, 10, 9, 4); assertEquals(result.length, 0); - // Test block has no neighbours due to being out of range in the y direction + // Test block has no neighbours due to being out of range in the y direction. result = helper_getNeighbours(db, 0, 19, 4); assertEquals(result.length, 0); - // Test block has no neighbours due to being out of range diagonally + // Test block has no neighbours due to being out of range diagonally. result = helper_getNeighbours(db, -2, -2, 2); assertEquals(result.length, 0); } function test_DB_findPositionForConnection() { - var db = new Blockly.ConnectionDB(); - db.addConnection_(helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT)); - db.addConnection_(helper_createConnection(0, 1, Blockly.PREVIOUS_STATEMENT)); - db.addConnection_(helper_createConnection(0, 2, Blockly.PREVIOUS_STATEMENT)); - db.addConnection_(helper_createConnection(0, 4, Blockly.PREVIOUS_STATEMENT)); - db.addConnection_(helper_createConnection(0, 5, Blockly.PREVIOUS_STATEMENT)); + var db = new Blockly.ConnectionDB(); + db.addConnection(helper_createConnection(0, 0, Blockly.PREVIOUS_STATEMENT)); + db.addConnection(helper_createConnection(0, 1, Blockly.PREVIOUS_STATEMENT)); + db.addConnection(helper_createConnection(0, 2, Blockly.PREVIOUS_STATEMENT)); + db.addConnection(helper_createConnection(0, 4, Blockly.PREVIOUS_STATEMENT)); + db.addConnection(helper_createConnection(0, 5, Blockly.PREVIOUS_STATEMENT)); - assertEquals(5, db.length); - var conn = helper_createConnection(0, 3, Blockly.PREVIOUS_STATEMENT); - assertEquals(3, db.findPositionForConnection_(conn)); + assertEquals(5, db.length); + var conn = helper_createConnection(0, 3, Blockly.PREVIOUS_STATEMENT); + assertEquals(3, db.findPositionForConnection_(conn)); } function test_DB_findConnection() { - var db = new Blockly.ConnectionDB(); - for (var i = 0; i < 10; i++) { - db.addConnection_(helper_createConnection(i, 0, Blockly.PREVIOUS_STATEMENT)); - db.addConnection_(helper_createConnection(0, i, Blockly.PREVIOUS_STATEMENT)); - } + var db = new Blockly.ConnectionDB(); + for (var i = 0; i < 10; i++) { + db.addConnection(helper_createConnection(i, 0, + Blockly.PREVIOUS_STATEMENT)); + db.addConnection(helper_createConnection(0, i, + Blockly.PREVIOUS_STATEMENT)); + } - var conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT); - db.addConnection_(conn); - assertEquals(conn, db[db.findConnection(conn)]); + var conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT); + db.addConnection(conn); + assertEquals(conn, db[db.findConnection(conn)]); - conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT); - assertEquals(-1, db.findConnection(conn)); + conn = helper_createConnection(3, 3, Blockly.PREVIOUS_STATEMENT); + assertEquals(-1, db.findConnection(conn)); } function test_DB_ordering() { - var db = new Blockly.ConnectionDB(); - for (var i = 0; i < 10; i++) { - db.addConnection_(helper_createConnection(0, 9 - i, Blockly.PREVIOUS_STATEMENT)); - } + var db = new Blockly.ConnectionDB(); + for (var i = 0; i < 10; i++) { + db.addConnection(helper_createConnection(0, 9 - i, + Blockly.PREVIOUS_STATEMENT)); + } - for (i = 0; i < 10; i++) { - assertEquals(i, db[i].y_); - } + for (i = 0; i < 10; i++) { + assertEquals(i, db[i].y_); + } - // quasi-random - var xCoords = [-29, -47, -77, 2, 43, 34, -59, -52, -90, -36, -91, 38, 87, -20, 60, 4, -57, - 65, -37, -81, 57, 58, -96, 1, 67, -79, 34, 93, -90, -99, -62, 4, 11, -36, -51, -72, - 3, -50, -24, -45, -92, -38, 37, 24, -47, -73, 79, -20, 99, 43, -10, -87, 19, 35, - -62, -36, 49, 86, -24, -47, -89, 33, -44, 25, -73, -91, 85, 6, 0, 89, -94, 36, -35, - 84, -9, 96, -21, 52, 10, -95, 7, -67, -70, 62, 9, -40, -95, -9, -94, 55, 57, -96, - 55, 8, -48, -57, -87, 81, 23, 65]; - var yCoords = [-81, 82, 5, 47, 30, 57, -12, 28, 38, 92, -25, -20, 23, -51, 73, -90, 8, 28, - -51, -15, 81, -60, -6, -16, 77, -62, -42, -24, 35, 95, -46, -7, 61, -16, 14, 91, 57, - -38, 27, -39, 92, 47, -98, 11, -33, -72, 64, 38, -64, -88, -35, -59, -76, -94, 45, - -25, -100, -95, 63, -97, 45, 98, 99, 34, 27, 52, -18, -45, 66, -32, -38, 70, -73, - -23, 5, -2, -13, -9, 48, 74, -97, -11, 35, -79, -16, -77, 83, -57, -53, 35, -44, - 100, -27, -15, 5, 39, 33, -19, -20, -95]; - for (i = 0; i < xCoords.length; i++) { - db.addConnection_(helper_createConnection(xCoords[i], yCoords[i], - Blockly.PREVIOUS_STATEMENT)); - } + // quasi-random + var xCoords = [-29, -47, -77, 2, 43, 34, -59, -52, -90, -36, -91, 38, 87, -20, + 60, 4, -57, 65, -37, -81, 57, 58, -96, 1, 67, -79, 34, 93, -90, -99, -62, + 4, 11, -36, -51, -72, 3, -50, -24, -45, -92, -38, 37, 24, -47, -73, 79, + -20, 99, 43, -10, -87, 19, 35, -62, -36, 49, 86, -24, -47, -89, 33, -44, + 25, -73, -91, 85, 6, 0, 89, -94, 36, -35, 84, -9, 96, -21, 52, 10, -95, 7, + -67, -70, 62, 9, -40, -95, -9, -94, 55, 57, -96, 55, 8, -48, -57, -87, 81, + 23, 65]; + var yCoords = [-81, 82, 5, 47, 30, 57, -12, 28, 38, 92, -25, -20, 23, -51, 73, + -90, 8, 28, -51, -15, 81, -60, -6, -16, 77, -62, -42, -24, 35, 95, -46, + -7, 61, -16, 14, 91, 57, -38, 27, -39, 92, 47, -98, 11, -33, -72, 64, 38, + -64, -88, -35, -59, -76, -94, 45, -25, -100, -95, 63, -97, 45, 98, 99, 34, + 27, 52, -18, -45, 66, -32, -38, 70, -73, -23, 5, -2, -13, -9, 48, 74, -97, + -11, 35, -79, -16, -77, 83, -57, -53, 35, -44, 100, -27, -15, 5, 39, 33, + -19, -20, -95]; + for (i = 0; i < xCoords.length; i++) { + db.addConnection(helper_createConnection(xCoords[i], yCoords[i], + Blockly.PREVIOUS_STATEMENT)); + } - for (i = 1; i < xCoords.length; i++) { - assertTrue(db[i].y_ >= db[i - 1].y_); - } + for (i = 1; i < xCoords.length; i++) { + assertTrue(db[i].y_ >= db[i - 1].y_); + } } -function test_DB_isConnectionAllowed() { - var db = new Blockly.ConnectionDB(); - var sharedWorkspace = {}; - // Two connections of opposite types near each other - var one = helper_createConnection(5 /* x */, 10 /* y */, Blockly.INPUT_VALUE); - one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); +function test_SearchForClosest() { + var db = new Blockly.ConnectionDB(); + var sharedWorkspace = {id: "Shared workspace"}; - var two = helper_createConnection(10 /* x */, 15 /* y */, Blockly.OUTPUT_VALUE); - two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + // search an empty list + assertEquals(null, helper_searchDB(db, 10 /* x */, 10 /* y */, + 100 /* radius */)); - assertTrue(db.isConnectionAllowed(one, two, 20.0)); - // Move connections farther apart - two.x_ = 100; - two.y_ = 100; - assertFalse(db.isConnectionAllowed(one, two, 20.0)); + db.addConnection(helper_createConnection(100, 0, Blockly.PREVIOUS_STATEMENT, + sharedWorkspace)); + assertEquals(null, helper_searchDB(db, 0, 0, 5, sharedWorkspace)); - // Don't offer to connect an already connected left (male) value plug to - // an available right (female) value plug. - var three = helper_createConnection(0, 0, Blockly.OUTPUT_VALUE); - three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + db = new Blockly.ConnectionDB(); + for (var i = 0; i < 10; i++) { + var tempConn = helper_createConnection(0, i, Blockly.PREVIOUS_STATEMENT, + sharedWorkspace); + tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + db.addConnection(tempConn); + } - assertTrue(db.isConnectionAllowed(one, three, 20.0)); - var four = helper_createConnection(0, 0, Blockly.INPUT_VALUE); - four.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + // should be at 0, 9 + var last = db[db.length - 1]; + // correct connection is last in db; many connections in radius + assertEquals(last, helper_searchDB(db, 0, 10, 15, sharedWorkspace)); + // Nothing nearby. + assertEquals(null, helper_searchDB(db, 100, 100, 3, sharedWorkspace)); + // first in db, exact match + assertEquals(db[0], helper_searchDB(db, 0, 0, 0, sharedWorkspace)); - Blockly.Connection.connectReciprocally(three, four); - assertFalse(db.isConnectionAllowed(one, three, 20.0)); + tempConn = helper_createConnection(6, 6, Blockly.PREVIOUS_STATEMENT, + sharedWorkspace); + tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + db.addConnection(tempConn); + tempConn = helper_createConnection(5, 5, Blockly.PREVIOUS_STATEMENT, + sharedWorkspace); + tempConn.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + db.addConnection(tempConn); - // Don't connect two connections on the same block - two.sourceBlock_ = one.sourceBlock_; - assertFalse(db.isConnectionAllowed(one, two, 1000.0)); + var result = helper_searchDB(db, 4, 6, 3, sharedWorkspace); + assertEquals(5, result.x_); + assertEquals(5, result.y_); } + function helper_getNeighbours(db, x, y, radius) { - return db.getNeighbours(helper_createConnection(x, y, Blockly.NEXT_STATEMENT), radius); + return db.getNeighbours(helper_createConnection(x, y, Blockly.NEXT_STATEMENT), + radius); +} + +function helper_searchDB(db, x, y, radius, shared_workspace) { + var tempConn = helper_createConnection(x, y, + Blockly.NEXT_STATEMENT, shared_workspace); + tempConn.sourceBlock_ = helper_makeSourceBlock(shared_workspace); + return db.searchForClosest(tempConn, radius, 0, 0); } function helper_makeSourceBlock(sharedWorkspace) { @@ -247,8 +273,9 @@ function helper_makeSourceBlock(sharedWorkspace) { }; } -function helper_createConnection(x, y, type) { - var conn = new Blockly.Connection({workspace: {}}, type); +function helper_createConnection(x, y, type, opt_shared_workspace) { + var workspace = opt_shared_workspace ? opt_shared_workspace : {}; + var conn = new Blockly.Connection({workspace: workspace}, type); conn.x_ = x; conn.y_ = y; return conn; diff --git a/tests/jsunit/connection_test.js b/tests/jsunit/connection_test.js index b9bcc2b23..b4448b083 100644 --- a/tests/jsunit/connection_test.js +++ b/tests/jsunit/connection_test.js @@ -33,10 +33,14 @@ var dummyWorkspace; function connectionTest_setUp() { dummyWorkspace = {}; - input = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.INPUT_VALUE); - output = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.OUTPUT_VALUE); - previous = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.PREVIOUS_STATEMENT); - next = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.NEXT_STATEMENT); + input = new Blockly.Connection({workspace: dummyWorkspace}, + Blockly.INPUT_VALUE); + output = new Blockly.Connection({workspace: dummyWorkspace}, + Blockly.OUTPUT_VALUE); + previous = new Blockly.Connection({workspace: dummyWorkspace}, + Blockly.PREVIOUS_STATEMENT); + next = new Blockly.Connection({workspace: dummyWorkspace}, + Blockly.NEXT_STATEMENT); } function connectionTest_tearDown() { @@ -48,13 +52,14 @@ function connectionTest_tearDown() { } /** - * These tests check that the reasons for failures to connect are consistent (internal view of - * error states). + * These tests check that the reasons for failures to connect are consistent + * (internal view of error states). */ function testCanConnectWithReason_TargetNull() { connectionTest_setUp(); - assertEquals(Blockly.Connection.REASON_TARGET_NULL, input.canConnectWithReason_(null)); + assertEquals(Blockly.Connection.REASON_TARGET_NULL, + input.canConnectWithReason_(null)); connectionTest_tearDown(); } @@ -62,9 +67,11 @@ function testCanConnectWithReason_TargetNull() { function testCanConnectWithReason_Disconnect() { connectionTest_setUp(); - var tempConnection = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.OUTPUT_VALUE); + var tempConnection = new Blockly.Connection({workspace: dummyWorkspace}, + Blockly.OUTPUT_VALUE); Blockly.Connection.connectReciprocally(input, tempConnection); - assertEquals(Blockly.Connection.REASON_MUST_DISCONNECT, input.canConnectWithReason_(output)); + assertEquals(Blockly.Connection.REASON_MUST_DISCONNECT, + input.canConnectWithReason_(output)); connectionTest_tearDown(); } @@ -73,9 +80,11 @@ function testCanConnectWithReason_DifferentWorkspaces() { connectionTest_setUp(); input = new Blockly.Connection({workspace: {}}, Blockly.INPUT_VALUE); - output = new Blockly.Connection({workspace: dummyWorkspace}, Blockly.OUTPUT_VALUE); + output = new Blockly.Connection({workspace: dummyWorkspace}, + Blockly.OUTPUT_VALUE); - assertEquals(Blockly.Connection.REASON_DIFFERENT_WORKSPACES, input.canConnectWithReason_(output)); + assertEquals(Blockly.Connection.REASON_DIFFERENT_WORKSPACES, + input.canConnectWithReason_(output)); connectionTest_tearDown(); } @@ -86,7 +95,8 @@ function testCanConnectWithReason_Self() { var block = {type_: "test block"}; input.sourceBlock_ = block; - assertEquals(Blockly.Connection.REASON_SELF_CONNECTION, input.canConnectWithReason_(input)); + assertEquals(Blockly.Connection.REASON_SELF_CONNECTION, + input.canConnectWithReason_(input)); connectionTest_tearDown(); } @@ -94,17 +104,25 @@ function testCanConnectWithReason_Self() { function testCanConnectWithReason_Type() { connectionTest_setUp(); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, input.canConnectWithReason_(previous)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, input.canConnectWithReason_(next)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + input.canConnectWithReason_(previous)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + input.canConnectWithReason_(next)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, output.canConnectWithReason_(previous)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, output.canConnectWithReason_(next)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + output.canConnectWithReason_(previous)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + output.canConnectWithReason_(next)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, previous.canConnectWithReason_(input)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, previous.canConnectWithReason_(output)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + previous.canConnectWithReason_(input)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + previous.canConnectWithReason_(output)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, next.canConnectWithReason_(input)); - assertEquals(Blockly.Connection.REASON_WRONG_TYPE, next.canConnectWithReason_(output)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + next.canConnectWithReason_(input)); + assertEquals(Blockly.Connection.REASON_WRONG_TYPE, + next.canConnectWithReason_(output)); connectionTest_tearDown(); } @@ -112,17 +130,21 @@ function testCanConnectWithReason_Type() { function testCanConnectWithReason_CanConnect() { connectionTest_setUp(); - assertEquals(Blockly.Connection.CAN_CONNECT, previous.canConnectWithReason_(next)); - assertEquals(Blockly.Connection.CAN_CONNECT, next.canConnectWithReason_(previous)); - assertEquals(Blockly.Connection.CAN_CONNECT, input.canConnectWithReason_(output)); - assertEquals(Blockly.Connection.CAN_CONNECT, output.canConnectWithReason_(input)); + assertEquals(Blockly.Connection.CAN_CONNECT, + previous.canConnectWithReason_(next)); + assertEquals(Blockly.Connection.CAN_CONNECT, + next.canConnectWithReason_(previous)); + assertEquals(Blockly.Connection.CAN_CONNECT, + input.canConnectWithReason_(output)); + assertEquals(Blockly.Connection.CAN_CONNECT, + output.canConnectWithReason_(input)); connectionTest_tearDown(); } /** - * The next set of tests checks that exceptions are being thrown at the correct times (external - * view of errors). + * The next set of tests checks that exceptions are being thrown at the correct + * times (external view of errors). */ function testCheckConnection_Self() { connectionTest_setUp(); @@ -222,6 +244,40 @@ function testCheckConnection_TypeNextOutput() { connectionTest_tearDown(); } +function test_isConnectionAllowed() { + var sharedWorkspace = {}; + // Two connections of opposite types near each other. + var one = helper_createConnection(5 /* x */, 10 /* y */, + Blockly.INPUT_VALUE); + one.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + + var two = helper_createConnection(10 /* x */, 15 /* y */, + Blockly.OUTPUT_VALUE); + two.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + + assertTrue(one.isConnectionAllowed(two, 20.0)); + // Move connections farther apart. + two.x_ = 100; + two.y_ = 100; + assertFalse(one.isConnectionAllowed(two, 20.0)); + + // Don't offer to connect an already connected left (male) value plug to + // an available right (female) value plug. + var three = helper_createConnection(0, 0, Blockly.OUTPUT_VALUE); + three.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + + assertTrue(one.isConnectionAllowed(three, 20.0)); + var four = helper_createConnection(0, 0, Blockly.INPUT_VALUE); + four.sourceBlock_ = helper_makeSourceBlock(sharedWorkspace); + + Blockly.Connection.connectReciprocally(three, four); + assertFalse(one.isConnectionAllowed(three, 20.0)); + + // Don't connect two connections on the same block. + two.sourceBlock_ = one.sourceBlock_; + assertFalse(one.isConnectionAllowed(two, 1000.0)); +} + function testCheckConnection_Okay() { connectionTest_setUp(); previous.checkConnection_(next);