From fd417a0070a44d91e7dc044efe40179e1f6ba0ee Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Fri, 21 May 2021 16:04:05 -0700 Subject: [PATCH] Updates BlockDragger to make it easier to override (#4842) --- core/block_dragger.js | 182 ++++++++++++++++++----------- core/gesture.js | 10 +- core/interfaces/i_block_dragger.js | 6 +- 3 files changed, 123 insertions(+), 75 deletions(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 9c5b17b2a..85e07d30e 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -42,38 +42,38 @@ Blockly.BlockDragger = function(block, workspace) { /** * The top block in the stack that is being dragged. * @type {!Blockly.BlockSvg} - * @private + * @protected */ this.draggingBlock_ = block; /** * The workspace on which the block is being dragged. * @type {!Blockly.WorkspaceSvg} - * @private + * @protected */ this.workspace_ = workspace; /** * Object that keeps track of connections on dragged blocks. * @type {!Blockly.InsertionMarkerManager} - * @private + * @protected */ - this.draggedConnectionManager_ = new Blockly.InsertionMarkerManager( - this.draggingBlock_); + this.draggedConnectionManager_ = + new Blockly.InsertionMarkerManager(this.draggingBlock_); /** * Which delete area the mouse pointer is over, if any. * One of {@link Blockly.DELETE_AREA_TRASH}, * {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}. * @type {?number} - * @private + * @protected */ this.deleteArea_ = null; /** * Whether the block would be deleted if dropped immediately. * @type {boolean} - * @private + * @protected */ this.wouldDeleteBlock_ = false; @@ -81,7 +81,7 @@ Blockly.BlockDragger = function(block, workspace) { * The location of the top left corner of the dragging block at the beginning * of the drag in workspace coordinates. * @type {!Blockly.utils.Coordinate} - * @private + * @protected */ this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY(); @@ -90,7 +90,7 @@ Blockly.BlockDragger = function(block, workspace) { * on this block and its descendants. Moving an icon moves the bubble that * extends from it if that bubble is open. * @type {Array.} - * @private + * @protected */ this.dragIconData_ = Blockly.BlockDragger.initIconData_(block); }; @@ -123,7 +123,8 @@ Blockly.BlockDragger.initIconData_ = function(block) { var icons = descendant.getIcons(); for (var j = 0; j < icons.length; j++) { var data = { - // Blockly.utils.Coordinate with x and y properties (workspace coordinates). + // Blockly.utils.Coordinate with x and y properties (workspace + // coordinates). location: icons[j].getIconLocation(), // Blockly.Icon icon: icons[j] @@ -140,10 +141,10 @@ Blockly.BlockDragger.initIconData_ = function(block) { * moved from the position at mouse down, in pixel units. * @param {boolean} healStack Whether or not to heal the stack after * disconnecting. - * @package + * @public */ -Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, - healStack) { +Blockly.BlockDragger.prototype.startDrag = function( + currentDragDeltaXY, healStack) { if (!Blockly.Events.getGroup()) { Blockly.Events.setGroup(true); } @@ -163,16 +164,8 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, this.workspace_.setResizesEnabled(false); Blockly.blockAnimations.disconnectUiStop(); - if (this.draggingBlock_.getParent() || - (healStack && this.draggingBlock_.nextConnection && - this.draggingBlock_.nextConnection.targetBlock())) { - this.draggingBlock_.unplug(healStack); - var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); - - this.draggingBlock_.translate(newLoc.x, newLoc.y); - Blockly.blockAnimations.disconnectUiEffect(this.draggingBlock_); - this.draggedConnectionManager_.updateAvailableConnections(); + if (this.shouldDisconnect_(healStack)) { + this.disconnectBlock_(healStack, currentDragDeltaXY); } this.draggingBlock_.setDragging(true); // For future consideration: we may be able to put moveToDragSurface inside @@ -180,17 +173,44 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, // surface. this.draggingBlock_.moveToDragSurface(); - var toolbox = this.workspace_.getToolbox(); - if (toolbox && typeof toolbox.addStyle == 'function') { - var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' : - 'blocklyToolboxGrab'; - toolbox.addStyle(style); - } + this.updateToolboxStyle_(false); +}; + +/** + * Whether or not we should disconnect the block when a drag is started. + * @param {boolean} healStack Whether or not to heal the stack after + * disconnecting. + * @returns {boolean} True to disconnect the block, false otherwise. + * @protected + */ +Blockly.BlockDragger.prototype.shouldDisconnect_ = function(healStack) { + return !!(this.draggingBlock_.getParent() || + (healStack && this.draggingBlock_.nextConnection && + this.draggingBlock_.nextConnection.targetBlock())); +}; + +/** + * Disconnects the block and moves it to a new location. + * @param {boolean} healStack Whether or not to heal the stack after + * disconnecting. + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has + * moved from the position at mouse down, in pixel units. + * @protected + */ +Blockly.BlockDragger.prototype.disconnectBlock_ = function( + healStack, currentDragDeltaXY) { + this.draggingBlock_.unplug(healStack); + var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); + + this.draggingBlock_.translate(newLoc.x, newLoc.y); + Blockly.blockAnimations.disconnectUiEffect(this.draggingBlock_); + this.draggedConnectionManager_.updateAvailableConnections(); }; /** * Fire a UI event at the start of a block drag. - * @private + * @protected */ Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() { var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))( @@ -204,9 +224,9 @@ Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() { * @param {!Event} e The most recent move event. * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. - * @package + * @public */ -Blockly.BlockDragger.prototype.dragBlock = function(e, currentDragDeltaXY) { +Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) { var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); @@ -224,11 +244,11 @@ Blockly.BlockDragger.prototype.dragBlock = function(e, currentDragDeltaXY) { * @param {!Event} e The mouseup/touchend event. * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. - * @package + * @public */ -Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { +Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) { // Make sure internal state is fresh. - this.dragBlock(e, currentDragDeltaXY); + this.drag(e, currentDragDeltaXY); this.dragIconData_ = []; this.fireDragEndEvent_(); @@ -242,32 +262,36 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { var deleted = this.maybeDeleteBlock_(); if (!deleted) { - // These are expensive and don't need to be done if we're deleting. - this.draggingBlock_.moveConnections(delta.x, delta.y); - this.draggingBlock_.setDragging(false); - this.fireMoveEvent_(); - if (this.draggedConnectionManager_.wouldConnectBlock()) { - // Applying connections also rerenders the relevant blocks. - this.draggedConnectionManager_.applyConnections(); - } else { - this.draggingBlock_.render(); - } - this.draggingBlock_.scheduleSnapAndBump(); + // Moving the block is expensive, so only do it if the block is not deleted. + this.updateBlockAfterMove_(delta); } this.workspace_.setResizesEnabled(true); - var toolbox = this.workspace_.getToolbox(); - if (toolbox && typeof toolbox.removeStyle == 'function') { - var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' : - 'blocklyToolboxGrab'; - toolbox.removeStyle(style); + this.updateToolboxStyle_(true); +}; + +/** + * Updates the necessary information to place a block at a certain location. + * @param {!Blockly.utils.Coordinate} delta The change in location from where + * the block started the drag to where it ended the drag. + * @protected + */ +Blockly.BlockDragger.prototype.updateBlockAfterMove_ = 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. + this.draggedConnectionManager_.applyConnections(); + } else { + this.draggingBlock_.render(); } - Blockly.Events.setGroup(false); + this.draggingBlock_.scheduleSnapAndBump(); }; /** * Fire a UI event at the end of a block drag. - * @private + * @protected */ Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() { var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))( @@ -275,13 +299,36 @@ Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() { Blockly.Events.fire(event); }; +/** + * Adds or removes the style of the cursor for the toolbox. + * This is what changes the cursor to display an x when a deletable block is + * held over the toolbox. + * @param {boolean} isEnd True if we are at the end of a drag, false otherwise. + * @protected + */ +Blockly.BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) { + var toolbox = this.workspace_.getToolbox(); + + if (toolbox) { + var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' : + 'blocklyToolboxGrab'; + + if (isEnd && typeof toolbox.removeStyle == 'function') { + toolbox.removeStyle(style); + } else if (!isEnd && typeof toolbox.addStyle == 'function') { + toolbox.addStyle(style); + } + } +}; + + /** * Fire a move event at the end of a block drag. - * @private + * @protected */ Blockly.BlockDragger.prototype.fireMoveEvent_ = function() { - var event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))( - this.draggingBlock_); + var event = + new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this.draggingBlock_); event.oldCoordinate = this.startXY_; event.recordNew(); Blockly.Events.fire(event); @@ -291,7 +338,7 @@ Blockly.BlockDragger.prototype.fireMoveEvent_ = function() { * Shut the trash can and, if necessary, delete the dragging block. * Should be called at the end of a block drag. * @return {boolean} Whether the block was deleted. - * @private + * @protected */ Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() { var trashcan = this.workspace_.trashcan; @@ -314,7 +361,7 @@ Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() { /** * Update the cursor (and possibly the trash can lid) to reflect whether the * dragging block would be deleted if released immediately. - * @private + * @protected */ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() { this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock(); @@ -337,11 +384,11 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() { * correction for mutator workspaces. * This function does not consider differing origins. It simply scales the * input's x and y values. - * @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y values - * in CSS pixel units. - * @return {!Blockly.utils.Coordinate} The input coordinate divided by the workspace - * scale. - * @private + * @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y + * values in CSS pixel units. + * @return {!Blockly.utils.Coordinate} The input coordinate divided by the + * workspace scale. + * @protected */ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { var result = new Blockly.utils.Coordinate( @@ -362,7 +409,7 @@ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { * Move all of the icons connected to this drag. * @param {!Blockly.utils.Coordinate} dxy How far to move the icons from their * original positions, in workspace units. - * @private + * @protected */ Blockly.BlockDragger.prototype.dragIcons_ = function(dxy) { // Moving icons moves their associated bubbles. @@ -377,7 +424,7 @@ Blockly.BlockDragger.prototype.dragIcons_ = function(dxy) { * or 2 insertion markers. * @return {!Array.} A possibly empty list of insertion * marker blocks. - * @package + * @public */ Blockly.BlockDragger.prototype.getInsertionMarkers = function() { // No insertion markers with the old style of dragged connection managers. @@ -388,5 +435,6 @@ Blockly.BlockDragger.prototype.getInsertionMarkers = function() { return []; }; -Blockly.registry.register(Blockly.registry.Type.BLOCK_DRAGGER, - Blockly.registry.DEFAULT, Blockly.BlockDragger); +Blockly.registry.register( + Blockly.registry.Type.BLOCK_DRAGGER, Blockly.registry.DEFAULT, + Blockly.BlockDragger); diff --git a/core/gesture.js b/core/gesture.js index 48e5c46a1..741b0cd74 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -444,8 +444,8 @@ Blockly.Gesture.prototype.startDraggingBlock_ = function() { this.blockDragger_ = new BlockDraggerClass( /** @type {!Blockly.BlockSvg} */ (this.targetBlock_), /** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_)); - this.blockDragger_.startBlockDrag(this.currentDragDeltaXY_, this.healStack_); - this.blockDragger_.dragBlock(this.mostRecentEvent_, this.currentDragDeltaXY_); + this.blockDragger_.startDrag(this.currentDragDeltaXY_, this.healStack_); + this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_); }; /** @@ -537,7 +537,7 @@ Blockly.Gesture.prototype.handleMove = function(e) { if (this.isDraggingWorkspace_) { this.workspaceDragger_.drag(this.currentDragDeltaXY_); } else if (this.isDraggingBlock_) { - this.blockDragger_.dragBlock( + this.blockDragger_.drag( this.mostRecentEvent_, this.currentDragDeltaXY_); } else if (this.isDraggingBubble_) { this.bubbleDragger_.dragBubble( @@ -569,7 +569,7 @@ Blockly.Gesture.prototype.handleUp = function(e) { if (this.isDraggingBubble_) { this.bubbleDragger_.endBubbleDrag(e, this.currentDragDeltaXY_); } else if (this.isDraggingBlock_) { - this.blockDragger_.endBlockDrag(e, this.currentDragDeltaXY_); + this.blockDragger_.endDrag(e, this.currentDragDeltaXY_); } else if (this.isDraggingWorkspace_) { this.workspaceDragger_.endDrag(this.currentDragDeltaXY_); } else if (this.isBubbleClick_()) { @@ -605,7 +605,7 @@ Blockly.Gesture.prototype.cancel = function() { this.bubbleDragger_.endBubbleDrag( this.mostRecentEvent_, this.currentDragDeltaXY_); } else if (this.isDraggingBlock_) { - this.blockDragger_.endBlockDrag( + this.blockDragger_.endDrag( this.mostRecentEvent_, this.currentDragDeltaXY_); } else if (this.isDraggingWorkspace_) { this.workspaceDragger_.endDrag(this.currentDragDeltaXY_); diff --git a/core/interfaces/i_block_dragger.js b/core/interfaces/i_block_dragger.js index bc75c53c5..ec7b79ac6 100644 --- a/core/interfaces/i_block_dragger.js +++ b/core/interfaces/i_block_dragger.js @@ -30,7 +30,7 @@ Blockly.IBlockDragger = function() {}; * @param {boolean} healStack Whether or not to heal the stack after * disconnecting. */ -Blockly.IBlockDragger.prototype.startBlockDrag; +Blockly.IBlockDragger.prototype.startDrag; /** * Execute a step of block dragging, based on the given event. Update the @@ -39,7 +39,7 @@ Blockly.IBlockDragger.prototype.startBlockDrag; * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. */ -Blockly.IBlockDragger.prototype.dragBlock; +Blockly.IBlockDragger.prototype.drag; /** * Finish a block drag and put the block back on the workspace. @@ -47,7 +47,7 @@ Blockly.IBlockDragger.prototype.dragBlock; * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. */ -Blockly.IBlockDragger.prototype.endBlockDrag; +Blockly.IBlockDragger.prototype.endDrag; /** * Get a list of the insertion markers that currently exist. Drags have 0, 1,