diff --git a/core/block_dragger.js b/core/block_dragger.js index 1326719a7..40200164d 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -265,8 +265,14 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) { Blockly.blockAnimations.disconnectUiStop(); - var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); + var preventMove = !!this.dragTarget_ && + this.dragTarget_.shouldPreventBlockMove(this.draggingBlock_); + if (preventMove) { + var newLoc = this.startXY_; + } else { + var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); + } this.draggingBlock_.moveOffDragSurface(newLoc); if (this.dragTarget_) { @@ -279,8 +285,17 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) { this.draggingBlock_.dispose(false, true); Blockly.draggingConnections = []; } else { - // Moving the block is expensive, so only do it if the block is not deleted. - this.updateBlockAfterMove_(delta); + this.draggingBlock_.setDragging(false); + if (delta) { // !preventMove + this.updateBlockLocationAfterMove_(delta); + } else { + // Blocks dragged directly from a flyout may need to be bumped into + // bounds. + Blockly.bumpObjectIntoBounds_( + this.draggingBlock_.workspace, + this.workspace_.getMetricsManager() + .getScrollMetrics(true), this.draggingBlock_); + } } this.workspace_.setResizesEnabled(true); @@ -293,9 +308,8 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) { * the block started the drag to where it ended the drag. * @protected */ -Blockly.BlockDragger.prototype.updateBlockAfterMove_ = function(delta) { +Blockly.BlockDragger.prototype.updateBlockLocationAfterMove_ = function(delta) { this.draggingBlock_.moveConnections(delta.x, delta.y); - this.draggingBlock_.setDragging(false); this.fireMoveEvent_(); if (this.draggedConnectionManager_.wouldConnectBlock()) { // Applying connections also rerenders the relevant blocks. diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index e372648cf..5c66a6d56 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -194,8 +194,14 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function( // Make sure internal state is fresh. this.dragBubble(e, currentDragDeltaXY); - var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); + var preventMove = this.dragTarget_ && + this.dragTarget_.shouldPreventBubbleMove(this.draggingBubble_); + if (preventMove) { + var newLoc = this.startXY_; + } else { + var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); + } // Move the bubble to its final location. this.draggingBubble_.moveTo(newLoc.x, newLoc.y); @@ -212,8 +218,9 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function( if (this.dragSurface_) { this.dragSurface_.clearAndHide(this.workspace_.getBubbleCanvas()); } - - this.draggingBubble_.setDragging && this.draggingBubble_.setDragging(false); + if (this.draggingBubble_) { + this.draggingBubble_.setDragging(false); + } this.fireMoveEvent_(); } this.workspace_.setResizesEnabled(true); diff --git a/core/drag_target.js b/core/drag_target.js index 7a905fa0d..5574e9853 100644 --- a/core/drag_target.js +++ b/core/drag_target.js @@ -68,3 +68,27 @@ Blockly.DragTarget.prototype.onBlockDrop = function(_block) { Blockly.DragTarget.prototype.onBubbleDrop = function(_bubble) { // no-op }; + +/** + * Returns whether the provided block should not be moved after being dropped + * on this component. If true, block will return to where it was when the drag + * started. + * @param {!Blockly.BlockSvg} _block The block. + * @return {boolean} Whether the block provided should be returned to drag + * start. + */ +Blockly.DragTarget.prototype.shouldPreventBlockMove = function(_block) { + return false; +}; + +/** + * Returns whether the provided bubble should not be moved after being dropped + * on this component. If true, bubble will return to where it was when the drag + * started. + * @param {!Blockly.IBubble} _bubble The bubble. + * @return {boolean} Whether the bubble provided should be returned to drag + * start. + */ +Blockly.DragTarget.prototype.shouldPreventBubbleMove = function(_bubble) { + return false; +}; diff --git a/core/inject.js b/core/inject.js index d8dede3e7..0b7590824 100644 --- a/core/inject.js +++ b/core/inject.js @@ -291,7 +291,7 @@ Blockly.bumpIntoBoundsHandler_ = function(workspace) { * in workspace coordinates. * @param {!Blockly.IBoundedElement} object The object to bump. * @return {boolean} True if block was bumped. - * @private + * @package */ Blockly.bumpObjectIntoBounds_ = function(workspace, scrollMetrics, object) { // Compute new top/left position for object. diff --git a/core/interfaces/i_drag_target.js b/core/interfaces/i_drag_target.js index fa7c2c286..b6b079487 100644 --- a/core/interfaces/i_drag_target.js +++ b/core/interfaces/i_drag_target.js @@ -58,3 +58,23 @@ Blockly.IDragTarget.prototype.onBlockDrop; * @param {!Blockly.IBubble} bubble The bubble. */ Blockly.IDragTarget.prototype.onBubbleDrop; + +/** + * Returns whether the provided block should not be moved after being dropped + * on this component. If true, block will return to where it was when the drag + * started. + * @param {!Blockly.BlockSvg} block The block. + * @return {boolean} Whether the block provided should be returned to drag + * start. + */ +Blockly.IDragTarget.prototype.shouldPreventBlockMove; + +/** + * Returns whether the provided bubble should not be moved after being dropped + * on this component. If true, bubble will return to where it was when the drag + * started. + * @param {!Blockly.IBubble} bubble The bubble. + * @return {boolean} Whether the bubble provided should be returned to drag + * start. + */ +Blockly.IDragTarget.prototype.shouldPreventBubbleMove;