Reduce duplication in Connection.connect. Support shadow statement blocks. Fix race condition.

This commit is contained in:
Neil Fraser
2016-01-30 13:08:47 -05:00
parent a114849545
commit bbfd883629

View File

@@ -156,54 +156,41 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
if (Blockly.OPPOSITE_TYPE[this.type] != otherConnection.type) {
throw 'Attempt to connect incompatible types.';
}
if (this.type == Blockly.INPUT_VALUE || this.type == Blockly.OUTPUT_VALUE) {
// Value connections.
if (this.targetConnection) {
// Can't make a value connection if male block is already connected.
throw 'Source connection already connected (value).';
} else if (otherConnection.targetConnection) {
if (this.targetConnection) {
throw 'Source connection already connected.';
}
if (otherConnection.targetConnection) {
// Other connection is already connected to something.
var orphanBlock = otherConnection.targetBlock();
if (orphanBlock.isShadow()) {
orphanBlock.dispose();
orphanBlock = null;
} else if (this.type == Blockly.INPUT_VALUE ||
this.type == Blockly.OUTPUT_VALUE) {
// Value connections.
// If female block is already connected, disconnect and bump the male.
var orphanBlock = otherConnection.targetBlock();
orphanBlock.setParent(null);
if (orphanBlock.isShadow()) {
orphanBlock.dispose();
} else {
if (!orphanBlock.outputConnection) {
throw 'Orphan block does not have an output connection.';
}
// Attempt to reattach the orphan at the end of the newly inserted
// block. Since this block may be a row, walk down to the end.
var newBlock = this.sourceBlock_;
var connection;
while (connection = Blockly.Connection.singleConnection_(
/** @type {!Blockly.Block} */ (newBlock), orphanBlock)) {
// '=' is intentional in line above.
newBlock = connection.targetBlock();
if (!newBlock || newBlock.isShadow()) {
orphanBlock.outputConnection.connect(connection);
orphanBlock = null;
break;
}
}
if (orphanBlock) {
// Unable to reattach orphan. Bump it off to the side.
setTimeout(function() {
orphanBlock.outputConnection.bumpAwayFrom_(otherConnection);
}, Blockly.BUMP_DELAY);
if (!orphanBlock.outputConnection) {
throw 'Orphan block does not have an output connection.';
}
// Attempt to reattach the orphan at the end of the newly inserted
// block. Since this block may be a row, walk down to the end.
var newBlock = this.sourceBlock_;
var connection;
while (connection = Blockly.Connection.singleConnection_(
/** @type {!Blockly.Block} */ (newBlock), orphanBlock)) {
// '=' is intentional in line above.
newBlock = connection.targetBlock();
if (!newBlock || newBlock.isShadow()) {
orphanBlock.outputConnection.connect(connection);
orphanBlock = null;
break;
}
}
}
} else {
// Statement connections.
if (this.targetConnection) {
throw 'Source connection already connected (block).';
} else if (otherConnection.targetConnection) {
} else if (this.type == Blockly.PREVIOUS_STATEMENT) {
// Statement connections.
// Statement blocks may be inserted into the middle of a stack.
if (this.type != Blockly.PREVIOUS_STATEMENT) {
throw 'Can only do a mid-stack connection with the top of a block.';
}
// Split the stack.
var orphanBlock = otherConnection.targetBlock();
orphanBlock.setParent(null);
if (!orphanBlock.previousConnection) {
throw 'Orphan block does not have a previous connection.';
@@ -223,12 +210,18 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
break;
}
}
if (orphanBlock) {
// Unable to reattach orphan. Bump it off to the side.
setTimeout(function() {
orphanBlock.previousConnection.bumpAwayFrom_(otherConnection);
}, Blockly.BUMP_DELAY);
}
} else {
// Type is Blockly.NEXT_STATEMENT.
throw 'Can only do a mid-stack connection with the top of a block.';
}
if (orphanBlock) {
// Unable to reattach orphan. Bump it off to the side after a moment.
setTimeout(function() {
// Verify orphan hasn't been deleted or reconnected (user on meth).
if (orphanBlock.workspace && !orphanBlock.getParent()) {
orphanBlock.outputConnection.bumpAwayFrom_(otherConnection);
}
}, Blockly.BUMP_DELAY);
}
}