diff --git a/core/connection_checker.js b/core/connection_checker.js index 15e044152..d05de79e4 100644 --- a/core/connection_checker.js +++ b/core/connection_checker.js @@ -32,12 +32,14 @@ Blockly.ConnectionChecker = function() { * @param {Blockly.Connection} b Connection to check compatibility with. * @param {boolean} isDragging True if the connection is being made by dragging * a block. + * @param {number=} opt_distance The max allowable distance between the + * connections for drag checks. * @return {boolean} Whether the connection is legal. * @public */ Blockly.ConnectionChecker.prototype.canConnect = function(a, b, - isDragging) { - return this.canConnectWithReason(a, b, isDragging) == + isDragging, opt_distance) { + return this.canConnectWithReason(a, b, isDragging, opt_distance) == Blockly.Connection.CAN_CONNECT; }; @@ -48,12 +50,14 @@ Blockly.ConnectionChecker.prototype.canConnect = function(a, b, * @param {Blockly.Connection} b Connection to check compatibility with. * @param {boolean} isDragging True if the connection is being made by dragging * a block. + * @param {number=} opt_distance The max allowable distance between the + * connections for drag checks. * @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal, * an error code otherwise. * @public */ Blockly.ConnectionChecker.prototype.canConnectWithReason = function( - a, b, isDragging) { + a, b, isDragging, opt_distance) { var safety = this.doSafetyChecks(a, b); if (safety != Blockly.Connection.CAN_CONNECT) { return safety; @@ -66,7 +70,11 @@ Blockly.ConnectionChecker.prototype.canConnectWithReason = function( return Blockly.Connection.REASON_CHECKS_FAILED; } - if (isDragging && this.doDragChecks(connOne, connTwo)) { + if (isDragging && + !this.doDragChecks( + /** @type {!Blockly.RenderedConnection} **/ (a), + /** @type {!Blockly.RenderedConnection} **/ (b), + opt_distance || 0)) { return Blockly.Connection.REASON_DRAG_CHECKS_FAILED; } @@ -169,12 +177,17 @@ Blockly.ConnectionChecker.prototype.doTypeChecks = function(a, b) { /** * Check whether this connection can be made by dragging. - * @param {!Blockly.Connection} a Connection to compare. - * @param {!Blockly.Connection} b Connection to compare against. - * @return {boolean} True if the connections share a type. + * @param {!Blockly.RenderedConnection} a Connection to compare. + * @param {!Blockly.RenderedConnection} b Connection to compare against. + * @param {number} distance The maximum allowable distance between connections. + * @return {boolean} True if the connection is allowed during a drag. * @public */ -Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b) { +Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) { + if (a.distanceFrom(b) > distance) { + return false; + } + // Don't consider insertion markers. if (b.getSourceBlock().isInsertionMarker()) { return false; diff --git a/core/connection_db.js b/core/connection_db.js index 2026678d2..d347ddbe0 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -247,17 +247,14 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, var bestConnection = null; var bestRadius = maxRadius; var temp; - var curDistance; // 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.connections_[pointerMin]; - curDistance = temp.distanceFrom(conn); - if (curDistance <= bestRadius && - this.connectionChecker_.canConnect(conn, temp, true)) { + if (this.connectionChecker_.canConnect(conn, temp, true, bestRadius)) { bestConnection = temp; - bestRadius = curDistance; + bestRadius = temp.distanceFrom(conn); } pointerMin--; } @@ -266,11 +263,9 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, while (pointerMax < this.connections_.length && this.isInYRange_(pointerMax, conn.y, maxRadius)) { temp = this.connections_[pointerMax]; - curDistance = temp.distanceFrom(conn); - if (curDistance <= bestRadius && - this.connectionChecker_.canConnect(conn, temp, true)) { + if (this.connectionChecker_.canConnect(conn, temp, true, bestRadius)) { bestConnection = temp; - bestRadius = curDistance; + bestRadius = temp.distanceFrom(conn); } pointerMax++; } diff --git a/core/interfaces/i_connection_checker.js b/core/interfaces/i_connection_checker.js index 6d386743c..505401666 100644 --- a/core/interfaces/i_connection_checker.js +++ b/core/interfaces/i_connection_checker.js @@ -29,6 +29,8 @@ Blockly.IConnectionChecker = function() {}; * @param {Blockly.Connection} b Connection to check compatibility with. * @param {boolean} isDragging True if the connection is being made by dragging * a block. + * @param {number=} opt_distance The max allowable distance between the + * connections for drag checks. * @return {boolean} Whether the connection is legal. * @public */ @@ -41,6 +43,8 @@ Blockly.IConnectionChecker.prototype.canConnect; * @param {Blockly.Connection} b Connection to check compatibility with. * @param {boolean} isDragging True if the connection is being made by dragging * a block. + * @param {number=} opt_distance The max allowable distance between the + * connections for drag checks. * @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal, * an error code otherwise. * @public @@ -81,9 +85,10 @@ Blockly.IConnectionChecker.prototype.doTypeChecks; /** * Check whether this connection can be made by dragging. - * @param {!Blockly.Connection} a Connection to compare. - * @param {!Blockly.Connection} b Connection to compare against. - * @return {boolean} True if the connections share a type. + * @param {!Blockly.RenderedConnection} a Connection to compare. + * @param {!Blockly.RenderedConnection} b Connection to compare against. + * @param {number} distance The maximum allowable distance between connections. + * @return {boolean} True if the connection is allowed during a drag. * @public */ Blockly.IConnectionChecker.prototype.doDragChecks; diff --git a/tests/mocha/connection_db_test.js b/tests/mocha/connection_db_test.js index f8dccd5d0..2013be0f9 100644 --- a/tests/mocha/connection_db_test.js +++ b/tests/mocha/connection_db_test.js @@ -190,14 +190,26 @@ suite('Connection Database', function() { this.assertOrder(); }); }); - // Does not cover logic for isConnectionAllowed + suite('Search For Closest', function() { setup(function() { - this.allowedStub = null; - this.allowedStub = sinon.stub(this.database.connectionChecker_, 'canConnect') - .callsFake(function(_dragging, _candidate) { + this.allowedStubs = []; + // Ignore type checks. + this.allowedStubs.push(sinon.stub(this.database.connectionChecker_, 'doTypeChecks') + .callsFake(function(_a, _b) { return true; - }); + })); + // Ignore safety checks. + this.allowedStubs.push(sinon.stub(this.database.connectionChecker_, 'doSafetyChecks') + .callsFake(function(_a, _b) { + return Blockly.Connection.CAN_CONNECT; + })); + // Skip everything but the distance checks. + this.allowedStubs.push(sinon.stub(this.database.connectionChecker_, 'doDragChecks') + .callsFake(function(a, b, distance) { + return a.distanceFrom(b) <= distance; + })); + this.createCheckConnection = function(x, y) { var checkConnection = this.createConnection(x, y, Blockly.NEXT_STATEMENT, new Blockly.ConnectionDB()); @@ -205,9 +217,7 @@ suite('Connection Database', function() { }; }); teardown(function() { - if (this.allowedStub) { - this.allowedStub.restore(); - } + this.allowedStubs.forEach(stub => stub.restore()); }); test('Empty Database', function() { var checkConnection = this.createConnection(0, 0, Blockly.NEXT_STATEMENT,