scratch-blocks/core/connection.js

735 lines
24 KiB
JavaScript
Raw Normal View History

/**
* @license
* Visual Blocks Editor
*
* Copyright 2011 Google Inc.
2014-10-07 13:09:55 -07:00
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Components for creating connections between blocks.
* @author fraser@google.com (Neil Fraser)
*/
'use strict';
goog.provide('Blockly.Connection');
goog.require('goog.asserts');
goog.require('goog.dom');
/**
* Class for a connection between blocks.
* @param {!Blockly.Block} source The block establishing this connection.
* @param {number} type The type of the connection.
* @constructor
*/
Blockly.Connection = function(source, type) {
2016-05-04 15:05:45 -07:00
/**
* @type {!Blockly.Block}
* @private
*/
this.sourceBlock_ = source;
/** @type {number} */
this.type = type;
// Shortcut for the databases for this connection's workspace.
2015-10-09 13:53:14 -07:00
if (source.workspace.connectionDBList) {
this.db_ = source.workspace.connectionDBList[type];
this.dbOpposite_ =
source.workspace.connectionDBList[Blockly.OPPOSITE_TYPE[type]];
this.hidden_ = !this.db_;
}
};
2016-01-26 16:20:33 -05:00
/**
* Constant for identifying connections that accept a boolean.
* @const
*/
Blockly.Connection.BOOLEAN = 1;
/**
* Constant for identifying connections that accept a string.
* @const
*/
Blockly.Connection.STRING = 2;
/**
* Constant for identifying connections that accept a number OR null.
* @const
*/
Blockly.Connection.NUMBER = 3;
/**
* Constants for checking whether two connections are compatible.
*/
Blockly.Connection.CAN_CONNECT = 0;
Blockly.Connection.REASON_SELF_CONNECTION = 1;
Blockly.Connection.REASON_WRONG_TYPE = 2;
Blockly.Connection.REASON_TARGET_NULL = 3;
Blockly.Connection.REASON_CHECKS_FAILED = 4;
Blockly.Connection.REASON_DIFFERENT_WORKSPACES = 5;
Blockly.Connection.REASON_SHADOW_PARENT = 6;
/**
* Connection this connection connects to. Null if not connected.
* @type {Blockly.Connection}
*/
Blockly.Connection.prototype.targetConnection = null;
/**
* List of compatible value types. Null if all types are compatible.
* @type {Array}
* @private
*/
Blockly.Connection.prototype.check_ = null;
/**
* DOM representation of a shadow block, or null if none.
* @type {Element}
* @private
*/
Blockly.Connection.prototype.shadowDom_ = null;
/**
* Horizontal location of this connection.
* @type {number}
* @private
*/
Blockly.Connection.prototype.x_ = 0;
/**
* Vertical location of this connection.
* @type {number}
* @private
*/
Blockly.Connection.prototype.y_ = 0;
/**
* Has this connection been added to the connection database?
* @type {boolean}
* @private
*/
Blockly.Connection.prototype.inDB_ = false;
/**
* Connection database for connections of this type on the current workspace.
* @type {Blockly.ConnectionDB}
* @private
*/
Blockly.Connection.prototype.db_ = null;
/**
* Connection database for connections compatible with this type on the
* current workspace.
* @type {Blockly.ConnectionDB}
* @private
*/
Blockly.Connection.prototype.dbOpposite_ = null;
/**
* Whether this connections is hidden (not tracked in a database) or not.
* @type {boolean}
* @private
*/
Blockly.Connection.prototype.hidden_ = null;
/**
* Connect two connections together. This is the connection on the superior
* block.
* @param {!Blockly.Connection} childConnection Connection on inferior block.
* @private
*/
Blockly.Connection.prototype.connect_ = function(childConnection) {
var parentConnection = this;
var parentBlock = parentConnection.getSourceBlock();
var childBlock = childConnection.getSourceBlock();
2016-03-14 17:10:15 -07:00
var isSurroundingC = false;
if (parentConnection == parentBlock.getFirstStatementConnection()) {
isSurroundingC = true;
}
// Disconnect any existing parent on the child connection.
2016-03-30 15:09:42 -07:00
if (childConnection.isConnected()) {
2016-03-14 17:10:15 -07:00
// Scratch-specific behaviour:
// If we're using a c-shaped block to surround a stack, remember where the
// stack used to be connected.
if (isSurroundingC) {
var previousParentConnection = childConnection.targetConnection;
}
childConnection.disconnect();
}
2016-03-30 15:09:42 -07:00
if (parentConnection.isConnected()) {
// Other connection is already connected to something.
// Disconnect it and reattach it or bump it as needed.
var orphanBlock = parentConnection.targetBlock();
var shadowDom = parentConnection.getShadowDom();
// Temporarily set the shadow DOM to null so it does not respawn.
parentConnection.setShadowDom(null);
// Displaced shadow blocks dissolve rather than reattaching or bumping.
if (orphanBlock.isShadow()) {
// Save the shadow block so that field values are preserved.
shadowDom = Blockly.Xml.blockToDom(orphanBlock);
orphanBlock.dispose();
orphanBlock = null;
} else if (parentConnection.type == Blockly.INPUT_VALUE) {
// Value connections.
// If female block is already connected, disconnect and bump the male.
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
// or to the first (and only) shadow block.
var connection = Blockly.Connection.lastConnectionInRow_(
childBlock, orphanBlock);
if (connection) {
orphanBlock.outputConnection.connect(connection);
orphanBlock = null;
}
} else if (parentConnection.type == Blockly.NEXT_STATEMENT) {
// Statement connections.
// Statement blocks may be inserted into the middle of a stack.
// Split the stack.
if (!orphanBlock.previousConnection) {
throw 'Orphan block does not have a previous connection.';
}
// Attempt to reattach the orphan at the bottom of the newly inserted
// block. Since this block may be a stack, walk down to the end.
var newBlock = childBlock;
while (newBlock.nextConnection) {
2016-03-30 15:09:42 -07:00
if (newBlock.nextConnection.isConnected()) {
newBlock = newBlock.getNextBlock();
} else {
if (orphanBlock.previousConnection.checkType_(
newBlock.nextConnection)) {
newBlock.nextConnection.connect(orphanBlock.previousConnection);
orphanBlock = null;
}
break;
}
}
}
if (orphanBlock) {
// Unable to reattach orphan.
parentConnection.disconnect();
if (Blockly.Events.recordUndo) {
// Bump it off to the side after a moment.
var group = Blockly.Events.getGroup();
setTimeout(function() {
// Verify orphan hasn't been deleted or reconnected (user on meth).
if (orphanBlock.workspace && !orphanBlock.getParent()) {
Blockly.Events.setGroup(group);
if (orphanBlock.outputConnection) {
orphanBlock.outputConnection.bumpAwayFrom_(parentConnection);
} else if (orphanBlock.previousConnection) {
orphanBlock.previousConnection.bumpAwayFrom_(parentConnection);
}
Blockly.Events.setGroup(false);
}
}, Blockly.BUMP_DELAY);
}
}
// Restore the shadow DOM.
parentConnection.setShadowDom(shadowDom);
}
2016-03-14 17:10:15 -07:00
if (isSurroundingC && previousParentConnection) {
2016-05-24 14:17:43 -07:00
previousParentConnection.connect(parentBlock.previousConnection);
2016-03-14 17:10:15 -07:00
}
var event;
if (Blockly.Events.isEnabled()) {
event = new Blockly.Events.Move(childBlock);
}
// Establish the connections.
Blockly.Connection.connectReciprocally_(parentConnection, childConnection);
// Demote the inferior block so that one is a child of the superior one.
childBlock.setParent(parentBlock);
if (event) {
event.recordNew();
Blockly.Events.fire(event);
}
};
/**
* Sever all links to this connection (not including from the source object).
*/
Blockly.Connection.prototype.dispose = function() {
2016-03-30 15:09:42 -07:00
if (this.isConnected()) {
throw 'Disconnect connection before disposing of it.';
}
if (this.inDB_) {
2015-09-29 23:12:32 -07:00
this.db_.removeConnection_(this);
}
if (Blockly.highlightedConnection_ == this) {
Blockly.highlightedConnection_ = null;
}
if (Blockly.localConnection_ == this) {
Blockly.localConnection_ = null;
}
2015-09-29 23:12:32 -07:00
this.db_ = null;
this.dbOpposite_ = null;
};
2016-03-22 13:03:47 -04:00
/**
2016-04-06 14:42:12 -07:00
* @return {boolean} true if the connection is not connected or is connected to
* an insertion marker, false otherwise.
2016-03-22 13:03:47 -04:00
*/
2016-04-06 14:42:12 -07:00
Blockly.Connection.prototype.isConnectedToNonInsertionMarker = function() {
return this.targetConnection && !this.targetBlock().isInsertionMarker();
2016-03-22 13:03:47 -04:00
};
/**
* Get the source block for this connection.
* @return {Blockly.Block} The source block, or null if there is none.
*/
Blockly.Connection.prototype.getSourceBlock = function() {
return this.sourceBlock_;
};
/**
* Does the connection belong to a superior block (higher in the source stack)?
* @return {boolean} True if connection faces down or right.
*/
Blockly.Connection.prototype.isSuperior = function() {
return this.type == Blockly.INPUT_VALUE ||
this.type == Blockly.NEXT_STATEMENT;
};
2016-03-30 15:09:42 -07:00
/**
* Is the connection connected?
* @return {boolean} True if connection is connected to another connection.
*/
Blockly.Connection.prototype.isConnected = function() {
return !!this.targetConnection;
};
/**
* Checks whether the current connection can connect with the target
* connection.
2016-02-26 11:05:36 -08:00
* @param {Blockly.Connection} target Connection to check compatibility with.
* @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal,
* an error code otherwise.
* @private
*/
Blockly.Connection.prototype.canConnectWithReason_ = function(target) {
if (this.isSuperior()) {
var blockA = this.sourceBlock_;
var blockB = target.getSourceBlock();
} else {
var blockB = this.sourceBlock_;
var blockA = target.getSourceBlock();
}
if (!target) {
return Blockly.Connection.REASON_TARGET_NULL;
} else 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;
2016-02-26 11:05:36 -08:00
};
/**
* Checks whether the current connection and target connection are compatible
* and throws an exception if they are not.
* @param {Blockly.Connection} target The connection to check compatibility
* with.
* @private
*/
Blockly.Connection.prototype.checkConnection_ = function(target) {
switch (this.canConnectWithReason_(target)) {
case Blockly.Connection.CAN_CONNECT:
break;
case Blockly.Connection.REASON_SELF_CONNECTION:
throw 'Attempted to connect a block to itself.';
case Blockly.Connection.REASON_DIFFERENT_WORKSPACES:
2016-03-24 15:30:29 -07:00
// Usually this means one block has been deleted.
throw 'Blocks not on same workspace.';
case Blockly.Connection.REASON_WRONG_TYPE:
throw 'Attempt to connect incompatible types.';
case Blockly.Connection.REASON_TARGET_NULL:
throw 'Target connection is null.';
2016-02-26 11:05:36 -08:00
case Blockly.Connection.REASON_CHECKS_FAILED:
throw 'Connection checks failed.';
case Blockly.Connection.REASON_SHADOW_PARENT:
throw 'Connecting non-shadow to shadow block.';
default:
throw 'Unknown connection failure: this should never happen!';
}
2016-02-26 11:05:36 -08:00
};
/**
* 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.
2016-03-06 14:51:03 -08:00
* @param {!Blockly.Connection} candidate A nearby connection to check.
* @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;
}
2016-03-06 14:51:03 -08:00
// Type checking.
var canConnect = this.canConnectWithReason_(candidate);
2016-02-29 15:50:12 -08:00
if (canConnect != Blockly.Connection.CAN_CONNECT &&
canConnect != Blockly.Connection.REASON_MUST_DISCONNECT) {
return false;
}
2016-03-14 17:10:15 -07:00
var firstStatementConnection =
this.sourceBlock_.getFirstStatementConnection();
2016-03-29 12:25:46 -07:00
switch (candidate.type) {
case Blockly.PREVIOUS_STATEMENT: {
if (!firstStatementConnection || this != firstStatementConnection) {
if (this.targetConnection) {
2016-03-22 17:12:00 -04:00
return false;
}
2016-03-29 12:25:46 -07:00
if (candidate.targetConnection) {
2016-04-06 14:42:12 -07:00
// If the other side of this connection is the active insertion marker
2016-03-29 12:25:46 -07:00
// connection, we've obviously already decided that this is a good
// connection.
2016-04-06 14:42:12 -07:00
if (candidate.targetConnection ==
Blockly.insertionMarkerConnection_) {
2016-03-29 12:25:46 -07:00
return true;
} else {
return false;
}
}
2016-03-22 17:12:00 -04:00
}
2016-03-29 12:25:46 -07:00
// Scratch-specific behaviour:
// If this is a c-shaped block, statement blocks cannot be connected
// anywhere other than inside the first statement input.
if (firstStatementConnection) {
2016-03-30 16:57:29 -07:00
// Can't connect if there is already a block inside the first statement
2016-03-29 12:25:46 -07:00
// input.
if (this == firstStatementConnection) {
if (this.targetConnection) {
return false;
}
}
// Can't connect this block's next connection unless we're connecting
// in front of the first block on a stack.
else if (this == this.sourceBlock_.nextConnection &&
2016-04-06 14:42:12 -07:00
candidate.isConnectedToNonInsertionMarker()) {
2016-03-14 17:10:15 -07:00
return false;
}
}
2016-03-29 12:25:46 -07:00
break;
}
case Blockly.OUTPUT_VALUE: {
// Can't drag an input to an output--you have to move the inferior block.
return false;
2016-03-14 17:10:15 -07:00
}
2016-03-29 12:25:46 -07:00
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 unmovable block.
if (candidate.targetConnection &&
!candidate.targetBlock().isMovable() &&
!candidate.targetBlock().isShadow()) {
return false;
}
break;
}
2016-03-29 12:25:46 -07:00
case Blockly.NEXT_STATEMENT: {
// Scratch-specific behaviour:
// If this is a c-block, we can't connect this block's
// previous connection unless we're connecting to the end of the last
// block on a stack or there's already a block connected inside the c.
if (firstStatementConnection &&
this == this.sourceBlock_.previousConnection &&
2016-04-06 14:42:12 -07:00
candidate.isConnectedToNonInsertionMarker() &&
2016-03-29 12:25:46 -07:00
!firstStatementConnection.targetConnection) {
return false;
}
// 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.
2016-04-06 14:42:12 -07:00
if (candidate.isConnectedToNonInsertionMarker() &&
!this.sourceBlock_.nextConnection &&
!candidate.targetBlock().isShadow() &&
candidate.targetBlock().nextConnection) {
2016-03-29 12:25:46 -07:00
return false;
}
break;
}
2016-03-29 12:25:46 -07:00
default:
throw 'Unknown connection type in isConnectionAllowed';
2016-03-14 17:10:15 -07:00
}
2016-03-29 12:25:46 -07:00
// Don't let blocks try to connect to themselves or ones they nest.
if (Blockly.draggingConnections_.indexOf(candidate) != -1) {
return false;
}
return true;
2016-03-29 12:25:46 -07:00
};
/**
* Connect this connection to another connection.
* @param {!Blockly.Connection} otherConnection Connection to connect to.
*/
Blockly.Connection.prototype.connect = function(otherConnection) {
if (this.targetConnection == otherConnection) {
// Already connected together. NOP.
return;
}
this.checkConnection_(otherConnection);
// Determine which block is superior (higher in the source stack).
if (this.isSuperior()) {
// Superior block.
this.connect_(otherConnection);
} else {
// Inferior block.
otherConnection.connect_(this);
}
};
2016-02-26 11:05:36 -08:00
/**
* Update two connections to target each other.
* @param {Blockly.Connection} first The first connection to update.
* @param {Blockly.Connection} second The second conneciton to update.
* @private
2016-02-26 11:05:36 -08:00
*/
Blockly.Connection.connectReciprocally_ = function(first, second) {
goog.asserts.assert(first && second, 'Cannot connect null connections.');
2016-02-26 11:05:36 -08:00
first.targetConnection = second;
second.targetConnection = first;
};
/**
* Does the given block have one and only one connection point that will accept
2015-10-06 18:09:27 -07:00
* an orphaned block?
* @param {!Blockly.Block} block The superior block.
* @param {!Blockly.Block} orphanBlock The inferior block.
* @return {Blockly.Connection} The suitable connection point on 'block',
* or null.
* @private
*/
Blockly.Connection.singleConnection_ = function(block, orphanBlock) {
var connection = false;
2015-09-29 23:12:32 -07:00
for (var i = 0; i < block.inputList.length; i++) {
var thisConnection = block.inputList[i].connection;
if (thisConnection && thisConnection.type == Blockly.INPUT_VALUE &&
orphanBlock.outputConnection.checkType_(thisConnection)) {
if (connection) {
return null; // More than one connection.
}
connection = thisConnection;
}
}
return connection;
};
/**
* Walks down a row a blocks, at each stage checking if there are any
* connections that will accept the orphaned block. If at any point there
* are zero or multiple eligible connections, returns null. Otherwise
* returns the only input on the last block in the chain.
* Terminates early for shadow blocks.
2016-03-18 15:19:26 -07:00
* @param {!Blockly.Block} startBlock The block on which to start the search.
* @param {!Blockly.Block} orphanBlock The block that is looking for a home.
* @return {Blockly.Connection} The suitable connection point on the chain
* of blocks, or null.
* @private
*/
Blockly.Connection.lastConnectionInRow_ = function(startBlock, orphanBlock) {
var newBlock = startBlock;
var connection;
while (connection = Blockly.Connection.singleConnection_(
/** @type {!Blockly.Block} */ (newBlock), orphanBlock)) {
// '=' is intentional in line above.
newBlock = connection.targetBlock();
if (!newBlock || newBlock.isShadow()) {
return connection;
}
}
return null;
};
/**
* Disconnect this connection.
*/
Blockly.Connection.prototype.disconnect = function() {
var otherConnection = this.targetConnection;
goog.asserts.assert(otherConnection, 'Source connection not connected.');
goog.asserts.assert(otherConnection.targetConnection == this,
'Target connection not connected to source connection.');
2015-10-06 18:09:27 -07:00
var parentBlock, childBlock, parentConnection;
if (this.isSuperior()) {
// Superior block.
parentBlock = this.sourceBlock_;
childBlock = otherConnection.getSourceBlock();
2015-10-06 18:09:27 -07:00
parentConnection = this;
} else {
// Inferior block.
parentBlock = otherConnection.getSourceBlock();
childBlock = this.sourceBlock_;
2015-10-06 18:09:27 -07:00
parentConnection = otherConnection;
}
2016-05-10 15:39:37 -07:00
this.disconnectInternal_(parentBlock, childBlock);
parentConnection.respawnShadow_();
};
2016-05-10 15:39:37 -07:00
/**
* Disconnect two blocks that are connected by this connection.
* @param {!Blockly.Block} parentBlock The superior block.
* @param {!Blockly.Block} childBlock The inferior block.
* @private
*/
Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
childBlock) {
var event;
if (Blockly.Events.isEnabled()) {
event = new Blockly.Events.Move(childBlock);
}
2016-05-10 15:39:37 -07:00
var otherConnection = this.targetConnection;
otherConnection.targetConnection = null;
this.targetConnection = null;
childBlock.setParent(null);
if (event) {
event.recordNew();
Blockly.Events.fire(event);
}
};
2016-05-10 15:39:37 -07:00
/**
* Respawn the shadow block if there was one connected to the this connection.
* @return {Blockly.Block} The newly spawned shadow block, or null if none was
* spawned.
* @private
*/
Blockly.Connection.prototype.respawnShadow_ = function() {
var parentBlock = this.getSourceBlock();
var shadow = this.getShadowDom();
if (parentBlock.workspace && shadow && Blockly.Events.recordUndo) {
2015-10-06 18:09:27 -07:00
var blockShadow =
Blockly.Xml.domToBlock(shadow, parentBlock.workspace);
2015-10-06 18:09:27 -07:00
if (blockShadow.outputConnection) {
2016-05-10 15:39:37 -07:00
this.connect(blockShadow.outputConnection);
2015-10-06 18:09:27 -07:00
} else if (blockShadow.previousConnection) {
2016-05-10 15:39:37 -07:00
this.connect(blockShadow.previousConnection);
2015-10-06 18:09:27 -07:00
} else {
throw 'Child block does not have output or previous statement.';
}
2016-04-27 13:32:39 -07:00
return blockShadow;
}
2016-04-27 13:32:39 -07:00
return null;
};
/**
* Returns the block that this connection connects to.
* @return {Blockly.Block} The connected block or null if none is connected.
*/
Blockly.Connection.prototype.targetBlock = function() {
2016-03-30 15:09:42 -07:00
if (this.isConnected()) {
return this.targetConnection.getSourceBlock();
}
return null;
};
/**
* 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} otherConnection Connection to compare against.
* @return {boolean} True if the connections share a type.
* @private
*/
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.
2015-09-29 23:12:32 -07:00
for (var i = 0; i < this.check_.length; i++) {
if (otherConnection.check_.indexOf(this.check_[i]) != -1) {
return true;
}
}
// No intersection.
return false;
};
/**
* Change a connection's compatibility.
* @param {*} check Compatible value type or list of value types.
* Null if all types are compatible.
* @return {!Blockly.Connection} The connection being modified
* (to allow chaining).
*/
Blockly.Connection.prototype.setCheck = function(check) {
if (check) {
// Ensure that check is in an array.
2014-09-08 14:26:52 -07:00
if (!goog.isArray(check)) {
check = [check];
}
this.check_ = check;
// The new value type may not be compatible with the existing connection.
2016-03-30 15:09:42 -07:00
if (this.isConnected() && !this.checkType_(this.targetConnection)) {
var child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_;
child.unplug();
// Bump away.
this.sourceBlock_.bumpNeighbours_();
}
} else {
this.check_ = null;
}
return this;
};
2016-01-26 16:20:33 -05:00
/**
* Returns a shape enum for this connection.
* @return {number} Enum representing shape.
*/
Blockly.Connection.prototype.getOutputShape = function() {
2016-05-24 14:17:43 -07:00
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;
}
2016-01-26 16:20:33 -05:00
2016-05-24 14:17:43 -07:00
return Blockly.Connection.NUMBER;
2016-01-26 16:20:33 -05:00
};
2015-10-06 18:09:27 -07:00
/**
* Change a connection's shadow block.
* @param {Element} shadow DOM representation of a block or null.
*/
Blockly.Connection.prototype.setShadowDom = function(shadow) {
this.shadowDom_ = shadow;
};
/**
* Return a connection's shadow block.
* @return {Element} shadow DOM representation of a block or null.
*/
Blockly.Connection.prototype.getShadowDom = function() {
return this.shadowDom_;
};