mirror of
https://github.com/google/blockly.git
synced 2026-01-09 01:50:11 +01:00
Start work on connection type checker
This commit is contained in:
@@ -543,7 +543,9 @@ Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = {
|
||||
var blockB = this.getInputTargetBlock('B');
|
||||
// Disconnect blocks that existed prior to this change if they don't match.
|
||||
if (blockA && blockB &&
|
||||
!blockA.outputConnection.checkType(blockB.outputConnection)) {
|
||||
!this.workspace.connectionTypeChecker.checkType(
|
||||
blockA.outputConnection, blockB.outputConnection)) {
|
||||
//!blockA.outputConnection.checkType(blockB.outputConnection)) {
|
||||
// Mismatch between two inputs. Revert the block connections,
|
||||
// bumping away the newly connected block(s).
|
||||
Blockly.Events.setGroup(e.group);
|
||||
@@ -610,7 +612,9 @@ Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN = {
|
||||
if ((blockA || blockB) && parentConnection) {
|
||||
for (var i = 0; i < 2; i++) {
|
||||
var block = (i == 1) ? blockA : blockB;
|
||||
if (block && !block.outputConnection.checkType(parentConnection)) {
|
||||
if (block &&
|
||||
block.workspace.connectionTypeChecker.checkType(block.outputConnection, parentConnection)) {
|
||||
//!block.outputConnection.checkType(parentConnection)) {
|
||||
// Ensure that any disconnections are grouped with the causing event.
|
||||
Blockly.Events.setGroup(e.group);
|
||||
if (parentConnection === this.prevParentConnection_) {
|
||||
|
||||
@@ -16,6 +16,7 @@ goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.BlockMove');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.ConnectionTypeChecker');
|
||||
goog.requireType('Blockly.IASTNodeLocationWithBlock');
|
||||
|
||||
|
||||
@@ -145,8 +146,10 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
|
||||
if (nextBlock && !nextBlock.isShadow()) {
|
||||
newBlock = nextBlock;
|
||||
} else {
|
||||
if (orphanBlock.previousConnection.checkType(
|
||||
newBlock.nextConnection)) {
|
||||
if (orphanBlock.workspace.connectionTypeChecker.checkType(
|
||||
orphanBlock.previousConnection, newBlock.nextConnection)) {
|
||||
//orphanBlock.previousConnection.checkType(
|
||||
//newBlock.nextConnection)) {
|
||||
newBlock.nextConnection.connect(orphanBlock.previousConnection);
|
||||
orphanBlock = null;
|
||||
}
|
||||
@@ -247,28 +250,29 @@ Blockly.Connection.prototype.isConnected = function() {
|
||||
* an error code otherwise.
|
||||
*/
|
||||
Blockly.Connection.prototype.canConnectWithReason = function(target) {
|
||||
if (!target) {
|
||||
return Blockly.Connection.REASON_TARGET_NULL;
|
||||
}
|
||||
if (this.isSuperior()) {
|
||||
var blockA = this.sourceBlock_;
|
||||
var blockB = target.getSourceBlock();
|
||||
} else {
|
||||
var blockB = this.sourceBlock_;
|
||||
var blockA = target.getSourceBlock();
|
||||
}
|
||||
if (blockA && blockA == blockB) {
|
||||
return Blockly.Connection.REASON_SELF_CONNECTION;
|
||||
} else if (target.type != Blockly.OPPOSITE_TYPE[this.type]) {
|
||||
return Blockly.Connection.REASON_WRONG_TYPE;
|
||||
} else if (blockA && blockB && blockA.workspace !== blockB.workspace) {
|
||||
return Blockly.Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
} else if (!this.checkType(target)) {
|
||||
return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
} else if (blockA.isShadow() && !blockB.isShadow()) {
|
||||
return Blockly.Connection.REASON_SHADOW_PARENT;
|
||||
}
|
||||
return Blockly.Connection.CAN_CONNECT;
|
||||
return this.sourceBlock_.workspace.connectionTypeChecker.canConnectWithReason(this, target);
|
||||
// if (!target) {
|
||||
// return Blockly.Connection.REASON_TARGET_NULL;
|
||||
// }
|
||||
// if (this.isSuperior()) {
|
||||
// var blockA = this.sourceBlock_;
|
||||
// var blockB = target.getSourceBlock();
|
||||
// } else {
|
||||
// var blockB = this.sourceBlock_;
|
||||
// var blockA = target.getSourceBlock();
|
||||
// }
|
||||
// if (blockA && blockA == blockB) {
|
||||
// return Blockly.Connection.REASON_SELF_CONNECTION;
|
||||
// } else if (target.type != Blockly.OPPOSITE_TYPE[this.type]) {
|
||||
// return Blockly.Connection.REASON_WRONG_TYPE;
|
||||
// } else if (blockA && blockB && blockA.workspace !== blockB.workspace) {
|
||||
// return Blockly.Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
// } else if (!this.checkType(target)) {
|
||||
// return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
// } else if (blockA.isShadow() && !blockB.isShadow()) {
|
||||
// return Blockly.Connection.REASON_SHADOW_PARENT;
|
||||
// }
|
||||
// return Blockly.Connection.CAN_CONNECT;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -279,26 +283,11 @@ Blockly.Connection.prototype.canConnectWithReason = function(target) {
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.checkConnection = function(target) {
|
||||
switch (this.canConnectWithReason(target)) {
|
||||
case Blockly.Connection.CAN_CONNECT:
|
||||
break;
|
||||
case Blockly.Connection.REASON_SELF_CONNECTION:
|
||||
throw Error('Attempted to connect a block to itself.');
|
||||
case Blockly.Connection.REASON_DIFFERENT_WORKSPACES:
|
||||
// Usually this means one block has been deleted.
|
||||
throw Error('Blocks not on same workspace.');
|
||||
case Blockly.Connection.REASON_WRONG_TYPE:
|
||||
throw Error('Attempt to connect incompatible types.');
|
||||
case Blockly.Connection.REASON_TARGET_NULL:
|
||||
throw Error('Target connection is null.');
|
||||
case Blockly.Connection.REASON_CHECKS_FAILED:
|
||||
var msg = 'Connection checks failed. ';
|
||||
msg += this + ' expected ' + this.check_ + ', found ' + target.check_;
|
||||
throw Error(msg);
|
||||
case Blockly.Connection.REASON_SHADOW_PARENT:
|
||||
throw Error('Connecting non-shadow to shadow block.');
|
||||
default:
|
||||
throw Error('Unknown connection failure: this should never happen!');
|
||||
|
||||
var checker = this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
var reason = checker.canConnectWithReason(this, target);
|
||||
if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
throw Error(checker.getErrorMessage(reason, this, target));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -344,63 +333,8 @@ Blockly.Connection.prototype.canConnectToPrevious_ = function(candidate) {
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
*/
|
||||
Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {
|
||||
// Don't consider insertion markers.
|
||||
if (candidate.sourceBlock_.isInsertionMarker()) {
|
||||
return false;
|
||||
}
|
||||
// Type checking.
|
||||
var canConnect = this.canConnectWithReason(candidate);
|
||||
if (canConnect != Blockly.Connection.CAN_CONNECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (candidate.type) {
|
||||
case Blockly.PREVIOUS_STATEMENT:
|
||||
return this.canConnectToPrevious_(candidate);
|
||||
case Blockly.OUTPUT_VALUE: {
|
||||
// Don't offer to connect an already connected left (male) value plug to
|
||||
// an available right (female) value plug.
|
||||
if ((candidate.isConnected() &&
|
||||
!candidate.targetBlock().isInsertionMarker()) ||
|
||||
this.isConnected()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Blockly.INPUT_VALUE: {
|
||||
// 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 immovable block.
|
||||
if (candidate.isConnected() &&
|
||||
!candidate.targetBlock().isMovable() &&
|
||||
!candidate.targetBlock().isShadow()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Blockly.NEXT_STATEMENT: {
|
||||
// Don't let a block with no next connection bump other blocks out of the
|
||||
// stack. But covering up a shadow block or stack of shadow blocks is
|
||||
// fine. Similarly, replacing a terminal statement with another terminal
|
||||
// statement is allowed.
|
||||
if (candidate.isConnected() &&
|
||||
!this.sourceBlock_.nextConnection &&
|
||||
!candidate.targetBlock().isShadow() &&
|
||||
candidate.targetBlock().nextConnection) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Error('Unknown connection type in isConnectionAllowed');
|
||||
}
|
||||
|
||||
// Don't let blocks try to connect to themselves or ones they nest.
|
||||
if (Blockly.draggingConnections.indexOf(candidate) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
var checker = this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
return checker.isConnectionAllowed(this, candidate);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -422,7 +356,13 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
|
||||
// Already connected together. NOP.
|
||||
return;
|
||||
}
|
||||
this.checkConnection(otherConnection);
|
||||
|
||||
var checker = this.sourceBlock_.workspace.connectionTypeChecker;
|
||||
var reason = checker.canConnectWithReason(this, otherConnection);
|
||||
if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
throw Error(checker.getErrorMessage(reason, this, otherConnection));
|
||||
}
|
||||
|
||||
var eventGroup = Blockly.Events.getGroup();
|
||||
if (!eventGroup) {
|
||||
Blockly.Events.setGroup(true);
|
||||
@@ -598,18 +538,8 @@ Blockly.Connection.prototype.targetBlock = function() {
|
||||
* @return {boolean} True if the connections share a type.
|
||||
*/
|
||||
Blockly.Connection.prototype.checkType = function(otherConnection) {
|
||||
if (!this.check_ || !otherConnection.check_) {
|
||||
// One or both sides are promiscuous enough that anything will fit.
|
||||
return true;
|
||||
}
|
||||
// Find any intersection in the check lists.
|
||||
for (var i = 0; i < this.check_.length; i++) {
|
||||
if (otherConnection.check_.indexOf(this.check_[i]) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// No intersection.
|
||||
return false;
|
||||
return this.sourceBlock_.workspace.connectionTypeChecker.checkType(
|
||||
this, otherConnection);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
243
core/connection_checks.js
Normal file
243
core/connection_checks.js
Normal file
@@ -0,0 +1,243 @@
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ConnectionTypeChecker');
|
||||
|
||||
goog.requireType('Blockly.Connection');
|
||||
|
||||
/**
|
||||
* Class for connection type checking logic.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker = function() {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method that translates a connection error code into a string.
|
||||
* @param {number} errorCode The error code.
|
||||
* @param {!Blockly.Connection} one One of the two connections being checked.
|
||||
* @param {!Blockly.Connection} two The second of the two connections being
|
||||
* checked.
|
||||
* @return {string} A developer-readable error string.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.getErrorMessage = function(errorCode,
|
||||
one, two) {
|
||||
switch (errorCode) {
|
||||
case Blockly.Connection.REASON_SELF_CONNECTION:
|
||||
return 'Attempted to connect a block to itself.';
|
||||
case Blockly.Connection.REASON_DIFFERENT_WORKSPACES:
|
||||
// Usually this means one block has been deleted.
|
||||
return 'Blocks not on same workspace.';
|
||||
case Blockly.Connection.REASON_WRONG_TYPE:
|
||||
return 'Attempt to connect incompatible types.';
|
||||
case Blockly.Connection.REASON_TARGET_NULL:
|
||||
return 'Target connection is null.';
|
||||
case Blockly.Connection.REASON_CHECKS_FAILED:
|
||||
var msg = 'Connection checks failed. ';
|
||||
msg += one + ' expected ' + one.check_ + ', found ' + two.check_;
|
||||
return msg;
|
||||
case Blockly.Connection.REASON_SHADOW_PARENT:
|
||||
return 'Connecting non-shadow to shadow block.';
|
||||
default:
|
||||
return 'Unknown connection failure: this should never happen!';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current connection can connect with the target
|
||||
* connection.
|
||||
* @param {Blockly.Connection} one Connection to check compatibility with.
|
||||
* @param {Blockly.Connection} two Connection to check compatibility with.
|
||||
* @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal,
|
||||
* an error code otherwise.
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.canConnectWithReason = function(one, two) {
|
||||
if (!two) {
|
||||
return Blockly.Connection.REASON_TARGET_NULL;
|
||||
}
|
||||
if (one.isSuperior()) {
|
||||
var blockA = one.sourceBlock_;
|
||||
var blockB = two.getSourceBlock();
|
||||
} else {
|
||||
var blockB = one.sourceBlock_;
|
||||
var blockA = two.getSourceBlock();
|
||||
}
|
||||
|
||||
if (blockA && blockA == blockB) {
|
||||
return Blockly.Connection.REASON_SELF_CONNECTION;
|
||||
} else if (two.type != Blockly.OPPOSITE_TYPE[one.type]) {
|
||||
return Blockly.Connection.REASON_WRONG_TYPE;
|
||||
} else if (blockA && blockB && blockA.workspace !== blockB.workspace) {
|
||||
return Blockly.Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
} else if (!this.checkType(one, two)) {
|
||||
return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
} else if (blockA.isShadow() && !blockB.isShadow()) {
|
||||
return Blockly.Connection.REASON_SHADOW_PARENT;
|
||||
}
|
||||
return Blockly.Connection.CAN_CONNECT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current connection and target connection are compatible
|
||||
* and throws an exception if they are not.
|
||||
* @param {!Blockly.Connection} one The connection to check compatibility
|
||||
* with.
|
||||
* @param {!Blockly.Connection} two The connection to check compatibility
|
||||
* with.
|
||||
* @package
|
||||
*/
|
||||
// Blockly.ConnectionTypeChecker.prototype.checkConnection = function(one, two) {
|
||||
// var reason = one.canConnectWithReason(two);
|
||||
// if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
// throw Error(this.getErrorMessage_(reason, one, two));
|
||||
// }
|
||||
// };
|
||||
|
||||
/**
|
||||
* Is this connection compatible with another connection with respect to the
|
||||
* value type system. E.g. square_root("Hello") is not compatible.
|
||||
* @param {!Blockly.Connection} one Connection to compare.
|
||||
* @param {!Blockly.Connection} two Connection to compare against.
|
||||
* @return {boolean} True if the connections share a type.
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.checkType = function(one, two) {
|
||||
var checkArrayOne = one.getCheck();
|
||||
var checkArrayTwo = two.getCheck();
|
||||
|
||||
if (!checkArrayOne || !checkArrayTwo) {
|
||||
// One or both sides are promiscuous enough that anything will fit.
|
||||
return true;
|
||||
}
|
||||
// Find any intersection in the check lists.
|
||||
for (var i = 0; i < checkArrayOne.length; i++) {
|
||||
if (checkArrayTwo.indexOf(checkArrayOne[i]) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// No intersection.
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the two connections can be dragged to connect to each other.
|
||||
* @param {!Blockly.Connection} one The moving connection to check.
|
||||
* @param {!Blockly.Connection} two A stationary connection to check.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.isConnectionAllowed = function(one, two) {
|
||||
// Don't consider insertion markers.
|
||||
if (two.sourceBlock_.isInsertionMarker()) {
|
||||
return false;
|
||||
}
|
||||
// Type checking.
|
||||
var canConnect = one.canConnectWithReason(two);
|
||||
if (canConnect != Blockly.Connection.CAN_CONNECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (two.type) {
|
||||
case Blockly.PREVIOUS_STATEMENT:
|
||||
return one.canConnectToPrevious_(two);
|
||||
case Blockly.OUTPUT_VALUE: {
|
||||
// Don't offer to connect an already connected left (male) value plug to
|
||||
// an available right (female) value plug.
|
||||
if ((two.isConnected() &&
|
||||
!two.targetBlock().isInsertionMarker()) ||
|
||||
one.isConnected()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Blockly.INPUT_VALUE: {
|
||||
// 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 immovable block.
|
||||
if (two.isConnected() &&
|
||||
!two.targetBlock().isMovable() &&
|
||||
!two.targetBlock().isShadow()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Blockly.NEXT_STATEMENT: {
|
||||
// Don't let a block with no next connection bump other blocks out of the
|
||||
// stack. But covering up a shadow block or stack of shadow blocks is
|
||||
// fine. Similarly, replacing a terminal statement with another terminal
|
||||
// statement is allowed.
|
||||
if (two.isConnected() &&
|
||||
!one.sourceBlock_.nextConnection &&
|
||||
!two.targetBlock().isShadow() &&
|
||||
two.targetBlock().nextConnection) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Error('Unknown connection type in isConnectionAllowed');
|
||||
}
|
||||
|
||||
// Don't let blocks try to connect to themselves or ones they nest.
|
||||
if (Blockly.draggingConnections.indexOf(two) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the two connections can be dragged to connect to each other.
|
||||
* @param {!Blockly.RenderedConnection} dragging The connection to check on a
|
||||
* block that is being dragged.
|
||||
* @param {!Blockly.RenderedConnection} candidate The stationary connection to
|
||||
* check.
|
||||
* @param {number=} maxRadius The maximum radius allowed for connections, in
|
||||
* workspace units.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.canConnectDuringDrag = function(
|
||||
dragging, candidate, maxRadius) {
|
||||
if (dragging.distanceFrom(candidate) > maxRadius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isConnectionAllowed(dragging, candidate);
|
||||
};
|
||||
/**
|
||||
* Check if the two connections can be dragged to connect to each other.
|
||||
* This is used by the connection database when searching for the closest
|
||||
* connection.
|
||||
* @param {!Blockly.Connection} one The connection to check, which must be a
|
||||
* statement input or next connection.
|
||||
* @param {!Blockly.Connection} two A nearby connection to check, which
|
||||
* must be a previous connection.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ConnectionTypeChecker.prototype.canConnectToPrevious_ = function(one, two) {
|
||||
if (one.targetConnection) {
|
||||
// This connection is already occupied.
|
||||
// A next connection will never disconnect itself mid-drag.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't let blocks try to connect to themselves or ones they nest.
|
||||
if (Blockly.draggingConnections.indexOf(two) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!two.targetConnection) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var targetBlock = two.targetBlock();
|
||||
// If it is connected to a real block, game over.
|
||||
if (!targetBlock.isInsertionMarker()) {
|
||||
return false;
|
||||
}
|
||||
// If it's connected to an insertion marker but that insertion marker
|
||||
// is the first block in a stack, it's still fine. If that insertion
|
||||
// marker is in the middle of a stack, it won't work.
|
||||
return !targetBlock.getPreviousBlock();
|
||||
};
|
||||
@@ -16,6 +16,8 @@ goog.provide('Blockly.ConnectionDB');
|
||||
|
||||
goog.require('Blockly.RenderedConnection');
|
||||
|
||||
goog.requireType('Blockly.ConnectionTypeChecker');
|
||||
|
||||
|
||||
/**
|
||||
* Database of connections.
|
||||
@@ -23,13 +25,14 @@ goog.require('Blockly.RenderedConnection');
|
||||
* connections in an area may be looked up quickly using a binary search.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ConnectionDB = function() {
|
||||
Blockly.ConnectionDB = function(typeChecker) {
|
||||
/**
|
||||
* Array of connections sorted by y position in workspace units.
|
||||
* @type {!Array.<!Blockly.RenderedConnection>}
|
||||
* @private
|
||||
*/
|
||||
this.connections_ = [];
|
||||
this.typeChecker_ = typeChecker;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -240,7 +243,8 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
var pointerMin = closestIndex - 1;
|
||||
while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y, maxRadius)) {
|
||||
temp = this.connections_[pointerMin];
|
||||
if (conn.isConnectionAllowed(temp, bestRadius)) {
|
||||
if (this.typeChecker_.canConnectDuringDrag(conn, temp, bestRadius)) {
|
||||
//conn.isConnectionAllowed(temp, bestRadius)) {
|
||||
bestConnection = temp;
|
||||
bestRadius = temp.distanceFrom(conn);
|
||||
}
|
||||
@@ -251,7 +255,8 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
while (pointerMax < this.connections_.length &&
|
||||
this.isInYRange_(pointerMax, conn.y, maxRadius)) {
|
||||
temp = this.connections_[pointerMax];
|
||||
if (conn.isConnectionAllowed(temp, bestRadius)) {
|
||||
if (this.typeChecker_.canConnectDuringDrag(conn, temp, bestRadius)) {
|
||||
//conn.isConnectionAllowed(temp, bestRadius)) {
|
||||
bestConnection = temp;
|
||||
bestRadius = temp.distanceFrom(conn);
|
||||
}
|
||||
@@ -270,12 +275,12 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
* Initialize a set of connection DBs for a workspace.
|
||||
* @return {!Array.<!Blockly.ConnectionDB>} Array of databases.
|
||||
*/
|
||||
Blockly.ConnectionDB.init = function() {
|
||||
Blockly.ConnectionDB.init = function(typeChecker) {
|
||||
// Create four databases, one for each connection type.
|
||||
var dbList = [];
|
||||
dbList[Blockly.INPUT_VALUE] = new Blockly.ConnectionDB();
|
||||
dbList[Blockly.OUTPUT_VALUE] = new Blockly.ConnectionDB();
|
||||
dbList[Blockly.NEXT_STATEMENT] = new Blockly.ConnectionDB();
|
||||
dbList[Blockly.PREVIOUS_STATEMENT] = new Blockly.ConnectionDB();
|
||||
dbList[Blockly.INPUT_VALUE] = new Blockly.ConnectionDB(typeChecker);
|
||||
dbList[Blockly.OUTPUT_VALUE] = new Blockly.ConnectionDB(typeChecker);
|
||||
dbList[Blockly.NEXT_STATEMENT] = new Blockly.ConnectionDB(typeChecker);
|
||||
dbList[Blockly.PREVIOUS_STATEMENT] = new Blockly.ConnectionDB(typeChecker);
|
||||
return dbList;
|
||||
};
|
||||
|
||||
@@ -18,6 +18,8 @@ goog.require('Blockly.ASTNode');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.user.keyMap');
|
||||
|
||||
goog.requireType('Blockly.ConnectionTypeChecker');
|
||||
|
||||
/**
|
||||
* A function to call to give feedback to the user about logs, warnings, and
|
||||
* errors. You can override this to customize feedback (e.g. warning sounds,
|
||||
|
||||
@@ -19,6 +19,8 @@ goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.ConnectionTypeChecker');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a connection between blocks that may be rendered on screen.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
goog.provide('Blockly.Workspace');
|
||||
|
||||
goog.require('Blockly.ConnectionTypeChecker');
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Options');
|
||||
goog.require('Blockly.utils');
|
||||
@@ -103,6 +104,8 @@ Blockly.Workspace = function(opt_options) {
|
||||
* @private
|
||||
*/
|
||||
this.potentialVariableMap_ = null;
|
||||
/** @type {Blockly.ConnectionTypeChecker} [description] */
|
||||
this.connectionTypeChecker = new Blockly.ConnectionTypeChecker();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,6 +44,7 @@ goog.require('Blockly.Xml');
|
||||
goog.requireType('Blockly.blockRendering.Renderer');
|
||||
goog.requireType('Blockly.IASTNodeLocationSvg');
|
||||
goog.requireType('Blockly.IBoundedElement');
|
||||
goog.requireType('Blockly.ConnectionTypeChecker');
|
||||
|
||||
|
||||
/**
|
||||
@@ -68,7 +69,8 @@ Blockly.WorkspaceSvg = function(options,
|
||||
this.setMetrics =
|
||||
options.setMetrics || Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_;
|
||||
|
||||
this.connectionDBList = Blockly.ConnectionDB.init();
|
||||
|
||||
this.connectionDBList = Blockly.ConnectionDB.init(this.connectionTypeChecker);
|
||||
|
||||
if (opt_blockDragSurface) {
|
||||
this.blockDragSurface_ = opt_blockDragSurface;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
suite('Connection Database', function() {
|
||||
setup(function() {
|
||||
this.database = new Blockly.ConnectionDB();
|
||||
this.database = new Blockly.ConnectionDB(new Blockly.ConnectionTypeChecker());
|
||||
|
||||
this.assertOrder = function() {
|
||||
var length = this.database.connections_.length;
|
||||
@@ -194,18 +194,26 @@ suite('Connection Database', function() {
|
||||
suite('Search For Closest', function() {
|
||||
setup(function() {
|
||||
this.allowedStub = null;
|
||||
|
||||
this.createCheckConnection = function(x, y) {
|
||||
var checkConnection = this.createConnection(x, y, Blockly.NEXT_STATEMENT,
|
||||
new Blockly.ConnectionDB());
|
||||
this.allowedStub = sinon.stub(checkConnection, 'isConnectionAllowed')
|
||||
.callsFake(function(candidate, maxRadius) {
|
||||
if (this.distanceFrom(candidate) > maxRadius) {
|
||||
this.database.typeChecker_.canConnectDuringDrag = function(
|
||||
dragging, candidate, maxRadius) {
|
||||
if (dragging.distanceFrom(candidate) > maxRadius) {
|
||||
return false;
|
||||
}
|
||||
// Ignore non-distance parameters.
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
this.createCheckConnection = function(x, y) {
|
||||
var checkConnection = this.createConnection(x, y, Blockly.NEXT_STATEMENT,
|
||||
new Blockly.ConnectionDB());
|
||||
// this.allowedStub = sinon.stub(checkConnection, 'isConnectionAllowed')
|
||||
// .callsFake(function(candidate, maxRadius) {
|
||||
// if (this.distanceFrom(candidate) > maxRadius) {
|
||||
// return false;
|
||||
// }
|
||||
// // Ignore non-distance parameters.
|
||||
// return true;
|
||||
// });
|
||||
return checkConnection;
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user