Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion blockly_uncompressed.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions core/block_dragger.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
goog.provide('Blockly.BlockDragger');

goog.require('Blockly.BlockAnimations');
goog.require('Blockly.DraggedConnectionManager');
goog.require('Blockly.InsertionMarkerManager');
goog.require('Blockly.Events.BlockMove');

goog.require('goog.math.Coordinate');
Expand Down Expand Up @@ -57,10 +57,10 @@ Blockly.BlockDragger = function(block, workspace) {

/**
* Object that keeps track of connections on dragged blocks.
* @type {!Blockly.DraggedConnectionManager}
* @type {!Blockly.InsertionMarkerManager}
* @private
*/
this.draggedConnectionManager_ = new Blockly.DraggedConnectionManager(
this.draggedConnectionManager_ = new Blockly.InsertionMarkerManager(
this.draggingBlock_);

/**
Expand Down Expand Up @@ -162,6 +162,9 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY,
this.draggingBlock_.bringToFront();
}

// During a drag there may be a lot of rerenders, but not field changes.
// Turn the cache on so we don't do spurious remeasures during the drag.
Blockly.Field.startCache();
this.workspace_.setResizesEnabled(false);
Blockly.BlockAnimations.disconnectUiStop();

Expand Down Expand Up @@ -222,6 +225,8 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
this.dragBlock(e, currentDragDeltaXY);
this.dragIconData_ = [];

Blockly.Field.stopCache();

Blockly.BlockAnimations.disconnectUiStop();

var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
Expand Down
45 changes: 45 additions & 0 deletions core/block_render_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ Blockly.BlockSvg.prototype.renderFields_ = function(fieldList,
Blockly.BlockSvg.SEP_SPACE_X;
}
}
// Fields are invisible on insertion marker. They still have to be rendered
// so that the block can be sized correctly.
if (this.isInsertionMarker()) {
root.setAttribute('display', 'none');
}
}
return this.RTL ? -cursorX : cursorX;
};
Expand Down Expand Up @@ -1144,3 +1149,43 @@ Blockly.BlockSvg.prototype.renderStatementInput_ = function(pathObject, row,
cursor.y += Blockly.BlockSvg.SEP_SPACE_Y;
}
};

/**
* Position an new block correctly, so that it doesn't move the existing block
* when connected to it.
* @param {!Blockly.Block} newBlock The block to position - either the first
* block in a dragged stack or an insertion marker.
* @param {!Blockly.Connection} newConnection The connection on the new block's
* stack - either a connection on newBlock, or the last NEXT_STATEMENT
* connection on the stack if the stack's being dropped before another
* block.
* @param {!Blockly.Connection} existingConnection The connection on the
* existing block, which newBlock should line up with.
*/
Blockly.BlockSvg.prototype.positionNewBlock = function(newBlock, newConnection,
existingConnection) {
// We only need to position the new block if it's before the existing one,
// otherwise its position is set by the previous block.
if (newConnection.type == Blockly.NEXT_STATEMENT ||
newConnection.type == Blockly.INPUT_VALUE) {
var dx = existingConnection.x_ - newConnection.x_;
var dy = existingConnection.y_ - newConnection.y_;

newBlock.moveBy(dx, dy);
}
};

/**
* Visual effect to show that if the dragging block is dropped, this block will
* be replaced. If a shadow block, it will disappear. Otherwise it will bump.
* @param {boolean} add True if highlighting should be added.
*/
Blockly.BlockSvg.prototype.highlightForReplacement = function(add) {
if (add) {
Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_),
'blocklyReplaceable');
} else {
Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_),
'blocklyReplaceable');
}
};
75 changes: 64 additions & 11 deletions core/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,67 @@ Blockly.Connection.prototype.checkConnection_ = function(target) {
}
};

/**
* 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} candidate A nearby connection to check, which
* must be a previous connection.
* @return {boolean} True if the connection is allowed, false otherwise.
* @private
*/
Blockly.Connection.prototype.canConnectToPrevious_ = function(candidate) {
if (this.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(candidate) != -1) {
return false;
}

var firstStatementConnection =
this.sourceBlock_.getFirstStatementConnection();
var isFirstStatementConnection = this == firstStatementConnection;
var isNextConnection = this == this.sourceBlock_.nextConnection;

// Complex blocks with no previous connection will not be allowed to connect
// mid-stack.
var sourceHasPreviousConn = this.sourceBlock_.previousConnection != null;

if (isNextConnection ||
(isFirstStatementConnection && !sourceHasPreviousConn)) {
// If the candidate is the first connection in a stack, we can connect.
if (!candidate.targetConnection) {
return true;
}

var targetBlock = candidate.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();
}
console.warn('Returning false by default from canConnectToPrevious_.');
return false;
};

/**
* Check if the two connections can be dragged to connect to each other.
* @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;
}
// Type checking.
var canConnect = this.canConnectWithReason_(candidate);
if (canConnect != Blockly.Connection.CAN_CONNECT) {
Expand All @@ -348,30 +403,27 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {

switch (candidate.type) {
case Blockly.PREVIOUS_STATEMENT:
// Don't offer to connect the bottom of a statement block to one that's
// already connected.
if (candidate.isConnected() || this.isConnected()) {
return false;
}
break;
case Blockly.OUTPUT_VALUE:
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() || this.isConnected()) {
return false;
}
break;
case Blockly.INPUT_VALUE:
}
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 &&
// 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:
}
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
Expand All @@ -383,6 +435,7 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {
return false;
}
break;
}
default:
throw Error('Unknown connection type in isConnectionAllowed');
}
Expand Down
21 changes: 20 additions & 1 deletion core/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,26 @@ Blockly.FLYOUT_DRAG_RADIUS = 10;
/**
* Maximum misalignment between connections for them to snap together.
*/
Blockly.SNAP_RADIUS = 20;
Blockly.SNAP_RADIUS = 36;

/**
* Maximum misalignment between connections for them to snap together,
* when a connection is already highlighted.
*/
Blockly.CONNECTING_SNAP_RADIUS = 48;

/**
* How much to prefer staying connected to the current connection over moving to
* a new connection. The current previewed connection is considered to be this
* much closer to the matching connection on the block than it actually is.
*/
Blockly.CURRENT_CONNECTION_PREFERENCE = 0;

/**
* The main colour of insertion markers, in hex. The block is rendered a
* transparent grey by changing the fill opacity in CSS.
*/
Blockly.INSERTION_MARKER_COLOUR = '#000000';

/**
* Delay in ms between trigger and bumping unconnected block out of alignment.
Expand Down
16 changes: 16 additions & 0 deletions core/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,22 @@ Blockly.Css.CONTENT = [
'display: none;',
'}',

'.blocklyInsertionMarker>.blocklyPath,',
'.blocklyInsertionMarker>.blocklyPathLight,',
'.blocklyInsertionMarker>.blocklyPathDark {',
'fill-opacity: .2;',
'stroke: none',
'}',

'.blocklyReplaceable .blocklyPath {',
'fill-opacity: 0.5;',
'}',

'.blocklyReplaceable .blocklyPathLight,',
'.blocklyReplaceable .blocklyPathDark {',
'display: none;',
'}',

'.blocklyText {',
'cursor: default;',
'fill: #fff;',
Expand Down
1 change: 1 addition & 0 deletions core/dragged_connection_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ goog.require('goog.math.Coordinate');
* Class that controls updates to connections during drags. It is primarily
* responsible for finding the closest eligible connection and highlighting or
* unhiglighting it as needed during a drag.
* @deprecated July 2018. Use InsertionMarkerManager.
* @param {!Blockly.BlockSvg} block The top block in the stack being dragged.
* @constructor
*/
Expand Down
3 changes: 2 additions & 1 deletion core/icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ Blockly.Icon.prototype.updateColour = function() {
* @return {number} Horizontal offset for next item to draw.
*/
Blockly.Icon.prototype.renderIcon = function(cursorX) {
if (this.collapseHidden && this.block_.isCollapsed()) {
if ((this.collapseHidden && this.block_.isCollapsed()) ||
this.block_.isInsertionMarker()) {
this.iconGroup_.setAttribute('display', 'none');
return cursorX;
}
Expand Down
Loading