Move isConnectionAllowed to connection; clean up

This commit is contained in:
Rachel Fenichel
2016-02-29 15:04:07 -08:00
parent c177fa5276
commit 7671986734
4 changed files with 303 additions and 227 deletions

View File

@@ -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;

View File

@@ -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.<Blockly.Connection>} 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.

View File

@@ -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;

View File

@@ -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);