From 2005576036c700091dcf2c591c32351a4df0ba0c Mon Sep 17 00:00:00 2001 From: Monica Kozbial <6621618+moniika@users.noreply.github.com> Date: Thu, 10 Jun 2021 16:27:04 -0700 Subject: [PATCH] Add onDragOver and wouldDelete_ to DeleteArea (#4888) * keep track of state for whether the block or bubble would be deleted for use with drag enter exit * Check if block and bubble is deletable in IDeleteArea * Add to jsdoc of IDeleteArea --- core/block_dragger.js | 13 ++++++++----- core/bubble_dragger.js | 15 +++++++-------- core/delete_area.js | 27 +++++++++++++++++++++------ core/drag_target.js | 8 ++++++++ core/insertion_marker_manager.js | 5 +---- core/interfaces/i_delete_area.js | 4 ++++ core/interfaces/i_drag_target.js | 7 +++++++ core/toolbox/toolbox.js | 10 +++++++--- core/trashcan.js | 22 +++++++++++++--------- 9 files changed, 76 insertions(+), 35 deletions(-) diff --git a/core/block_dragger.js b/core/block_dragger.js index 40200164d..c5dfa7c3f 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -228,16 +228,11 @@ Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() { Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) { var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); - this.draggingBlock_.moveDuringDrag(newLoc); this.dragIcons_(delta); var oldDragTarget = this.dragTarget_; this.dragTarget_ = this.workspace_.getDragTarget(e); - if (this.dragTarget_ !== oldDragTarget) { - oldDragTarget && oldDragTarget.onDragExit(); - this.dragTarget_ && this.dragTarget_.onDragEnter(); - } this.draggedConnectionManager_.update(delta, this.dragTarget_); var oldWouldDeleteBlock = this.wouldDeleteBlock_; @@ -246,6 +241,14 @@ Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) { // Prevent unnecessary add/remove class calls. this.updateCursorDuringBlockDrag_(); } + + // Call drag enter/exit/over after wouldDeleteBlock is called in + // InsertionMarkerManager.update. + if (this.dragTarget_ !== oldDragTarget) { + oldDragTarget && oldDragTarget.onDragExit(); + this.dragTarget_ && this.dragTarget_.onDragEnter(); + } + this.dragTarget_ && this.dragTarget_.onDragOver(); }; /** diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index 5c66a6d56..349b35803 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -132,15 +132,10 @@ Blockly.BubbleDragger.prototype.startBubbleDrag = function() { Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) { var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); - this.draggingBubble_.moveDuringDrag(this.dragSurface_, newLoc); var oldDragTarget = this.dragTarget_; this.dragTarget_ = this.workspace_.getDragTarget(e); - if (this.dragTarget_ !== oldDragTarget) { - oldDragTarget && oldDragTarget.onDragExit(); - this.dragTarget_ && this.dragTarget_.onDragEnter(); - } var oldWouldDeleteBubble = this.wouldDeleteBubble_; this.wouldDeleteBubble_ = this.shouldDelete_(this.dragTarget_); @@ -148,6 +143,12 @@ Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) { // Prevent unnecessary add/remove class calls. this.updateCursorDuringBubbleDrag_(); } + + if (this.dragTarget_ !== oldDragTarget) { + oldDragTarget && oldDragTarget.onDragExit(); + this.dragTarget_ && this.dragTarget_.onDragEnter(); + } + this.dragTarget_ && this.dragTarget_.onDragOver(); }; /** @@ -159,9 +160,7 @@ Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) { * @private */ Blockly.BubbleDragger.prototype.shouldDelete_ = function(dragTarget) { - var couldDeleteBubble = this.draggingBubble_.isDeletable(); - - if (couldDeleteBubble && dragTarget) { + if (dragTarget) { var componentManager = this.workspace_.getComponentManager(); var isDeleteArea = componentManager.hasCapability(dragTarget.id, Blockly.ComponentManager.Capability.DELETE_AREA); diff --git a/core/delete_area.js b/core/delete_area.js index 92edf36f5..155da12e7 100644 --- a/core/delete_area.js +++ b/core/delete_area.js @@ -27,27 +27,42 @@ goog.require('Blockly.IDeleteArea'); */ Blockly.DeleteArea = function() { Blockly.DeleteArea.superClass_.constructor.call(this); + + /** + * Whether the current block or bubble dragged over this delete area would be + * deleted if dropped on this component. + * @type {boolean} + * @protected + */ + this.wouldDelete_ = false; }; Blockly.utils.object.inherits(Blockly.DeleteArea, Blockly.DragTarget); /** * Returns whether the provided block would be deleted if dropped on this area. - * @param {!Blockly.BlockSvg} _block The block. + * This method should check if the block is deletable and is always called + * before onDragEnter/onDragOver/onDragExit. + * @param {!Blockly.BlockSvg} block The block. * @param {boolean} couldConnect Whether the block could could connect to * another. * @return {boolean} Whether the block provided would be deleted if dropped on * this area. */ -Blockly.DeleteArea.prototype.wouldDeleteBlock = function(_block, couldConnect) { - return !couldConnect; +Blockly.DeleteArea.prototype.wouldDeleteBlock = function(block, couldConnect) { + var couldDeleteBlock = !block.getParent() && block.isDeletable(); + this.wouldDelete_ = couldDeleteBlock && !couldConnect; + return this.wouldDelete_; }; /** * Returns whether the provided bubble would be deleted if dropped on this area. - * @param {!Blockly.IBubble} _bubble The bubble. + * This method should check if the bubble is deletable and is always called + * before onDragEnter/onDragOver/onDragExit. + * @param {!Blockly.IBubble} bubble The bubble. * @return {boolean} Whether the bubble provided would be deleted if dropped on * this area. */ -Blockly.DeleteArea.prototype.wouldDeleteBubble = function(_bubble) { - return true; +Blockly.DeleteArea.prototype.wouldDeleteBubble = function(bubble) { + this.wouldDelete_ = bubble.isDeletable(); + return this.wouldDelete_; }; diff --git a/core/drag_target.js b/core/drag_target.js index 5574e9853..8c66cdfc8 100644 --- a/core/drag_target.js +++ b/core/drag_target.js @@ -44,6 +44,14 @@ Blockly.DragTarget.prototype.onDragEnter = function() { // no-op }; +/** + * Handles when a cursor with a block or bubble is dragged over this drag + * target. + */ +Blockly.DragTarget.prototype.onDragOver = function() { + // no-op +}; + /** * Handles when a cursor with a block or bubble exits this drag target. */ diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 0a4eaca3a..d98a0217e 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -456,10 +456,7 @@ Blockly.InsertionMarkerManager.prototype.getStartRadius_ = function() { */ Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function( candidate, dragTarget) { - var couldDeleteBlock = - !this.topBlock_.getParent() && this.topBlock_.isDeletable(); - - if (couldDeleteBlock && dragTarget) { + if (dragTarget) { var componentManager = this.workspace_.getComponentManager(); var isDeleteArea = componentManager.hasCapability(dragTarget.id, Blockly.ComponentManager.Capability.DELETE_AREA); diff --git a/core/interfaces/i_delete_area.js b/core/interfaces/i_delete_area.js index 4ab7cddbe..301c9b1c9 100644 --- a/core/interfaces/i_delete_area.js +++ b/core/interfaces/i_delete_area.js @@ -30,6 +30,8 @@ Blockly.IDeleteArea = function() {}; /** * Returns whether the provided block would be deleted if dropped on this area. + * This method should check if the block is deletable and is always called + * before onDragEnter/onDragOver/onDragExit. * @param {!Blockly.BlockSvg} block The block. * @param {boolean} couldConnect Whether the block could could connect to * another. @@ -40,6 +42,8 @@ Blockly.IDeleteArea.prototype.wouldDeleteBlock; /** * Returns whether the provided bubble would be deleted if dropped on this area. + * This method should check if the bubble is deletable and is always called + * before onDragEnter/onDragOver/onDragExit. * @param {!Blockly.IBubble} bubble The bubble. * @return {boolean} Whether the bubble provided would be deleted if dropped on * this area. diff --git a/core/interfaces/i_drag_target.js b/core/interfaces/i_drag_target.js index b6b079487..c14ade21a 100644 --- a/core/interfaces/i_drag_target.js +++ b/core/interfaces/i_drag_target.js @@ -40,6 +40,13 @@ Blockly.IDragTarget.prototype.getClientRect; */ Blockly.IDragTarget.prototype.onDragEnter; +/** + * Handles when a cursor with a block or bubble is dragged over this drag + * target. + */ +Blockly.IDragTarget.prototype.onDragOver; + + /** * Handles when a cursor with a block or bubble exits this drag target. */ diff --git a/core/toolbox/toolbox.js b/core/toolbox/toolbox.js index aceb9a393..ec7be95d4 100644 --- a/core/toolbox/toolbox.js +++ b/core/toolbox/toolbox.js @@ -541,15 +541,19 @@ Blockly.Toolbox.prototype.getClientRect = function() { /** * Returns whether the provided block would be deleted if dropped on this area. - * @param {!Blockly.BlockSvg} _block The block. + * This method should check if the block is deletable and is always called + * before onDragEnter/onDragOver/onDragExit. + * @param {!Blockly.BlockSvg} block The block. * @param {boolean} _couldConnect Whether the block could could connect to * another. * @return {boolean} Whether the block provided would be deleted if dropped on * this area. + * @override */ -Blockly.Toolbox.prototype.wouldDeleteBlock = function(_block, _couldConnect) { +Blockly.Toolbox.prototype.wouldDeleteBlock = function(block, _couldConnect) { // Prefer dragging to the toolbox over connecting to other blocks. - return true; + this.wouldDelete_ = !block.getParent() && block.isDeletable(); + return this.wouldDelete_; }; /** diff --git a/core/trashcan.js b/core/trashcan.js index 9acc99004..337a33289 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -533,11 +533,13 @@ Blockly.Trashcan.prototype.getClientRect = function() { }; /** - * Handles when a cursor with a block or bubble enters this drag target. + * Handles when a cursor with a block or bubble is dragged over this drag + * target. * @override */ -Blockly.Trashcan.prototype.onDragEnter = function() { - this.setLidOpen(true); +Blockly.Trashcan.prototype.onDragOver = function() { + Blockly.Trashcan.superClass_.onDragOver.call(this); + this.setLidOpen(this.wouldDelete_); }; /** @@ -545,27 +547,29 @@ Blockly.Trashcan.prototype.onDragEnter = function() { * @override */ Blockly.Trashcan.prototype.onDragExit = function() { + Blockly.Trashcan.superClass_.onDragExit.call(this); this.setLidOpen(false); }; - /** * Handles when a block is dropped on this component. Should not handle delete * here. - * @param {!Blockly.BlockSvg} _block The block. + * @param {!Blockly.BlockSvg} block The block. * @override */ -Blockly.Trashcan.prototype.onBlockDrop = function(_block) { +Blockly.Trashcan.prototype.onBlockDrop = function(block) { + Blockly.Trashcan.superClass_.onBlockDrop.call(this, block); this.onDrop_(); }; /** * Handles when a bubble is dropped on this component. Should not handle delete * here. - * @param {!Blockly.IBubble} _bubble The bubble. + * @param {!Blockly.IBubble} bubble The bubble. * @override */ -Blockly.Trashcan.prototype.onBubbleDrop = function(_bubble) { +Blockly.Trashcan.prototype.onBubbleDrop = function(bubble) { + Blockly.Trashcan.superClass_.onBubbleDrop.call(this, bubble); this.onDrop_(); }; @@ -574,7 +578,7 @@ Blockly.Trashcan.prototype.onBubbleDrop = function(_bubble) { * @private */ Blockly.Trashcan.prototype.onDrop_ = function() { - setTimeout(this.closeLid.bind(this), 100); + setTimeout(this.setLidOpen.bind(this, false), 100); }; /**