mirror of
https://github.com/google/blockly.git
synced 2026-01-11 19:07:08 +01:00
Adding IDragTarget support. (#4852)
This commit is contained in:
@@ -42,6 +42,8 @@ goog.addDependency('../../core/contextmenu.js', ['Blockly.ContextMenu'], ['Block
|
||||
goog.addDependency('../../core/contextmenu_items.js', ['Blockly.ContextMenuItems'], ['Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.constants', 'Blockly.inputTypes'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/contextmenu_registry.js', ['Blockly.ContextMenuRegistry'], [], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/css.js', ['Blockly.Css'], [], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/delete_area.js', ['Blockly.DeleteArea'], ['Blockly.DragTarget', 'Blockly.IDeleteArea']);
|
||||
goog.addDependency('../../core/drag_target.js', ['Blockly.DragTarget'], ['Blockly.IDragTarget']);
|
||||
goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style']);
|
||||
goog.addDependency('../../core/events/block_events.js', ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']);
|
||||
goog.addDependency('../../core/events/events.js', ['Blockly.Events'], ['Blockly.registry', 'Blockly.utils']);
|
||||
@@ -73,11 +75,11 @@ goog.addDependency('../../core/field_number.js', ['Blockly.FieldNumber'], ['Bloc
|
||||
goog.addDependency('../../core/field_registry.js', ['Blockly.fieldRegistry'], ['Blockly.registry']);
|
||||
goog.addDependency('../../core/field_textinput.js', ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object']);
|
||||
goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.IDeleteArea', 'Blockly.IFlyout', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml']);
|
||||
goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.IFlyout', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml']);
|
||||
goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']);
|
||||
goog.addDependency('../../core/flyout_vertical.js', ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']);
|
||||
goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly.Block', 'Blockly.constants']);
|
||||
goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly.Block', 'Blockly.constants', 'Blockly.utils.deprecation']);
|
||||
goog.addDependency('../../core/gesture.js', ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.WorkspaceDragger', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate']);
|
||||
goog.addDependency('../../core/grid.js', ['Blockly.Grid'], ['Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom']);
|
||||
@@ -94,7 +96,8 @@ goog.addDependency('../../core/interfaces/i_connection_checker.js', ['Blockly.IC
|
||||
goog.addDependency('../../core/interfaces/i_contextmenu.js', ['Blockly.IContextMenu'], []);
|
||||
goog.addDependency('../../core/interfaces/i_copyable.js', ['Blockly.ICopyable'], []);
|
||||
goog.addDependency('../../core/interfaces/i_deletable.js', ['Blockly.IDeletable'], []);
|
||||
goog.addDependency('../../core/interfaces/i_deletearea.js', ['Blockly.IDeleteArea'], []);
|
||||
goog.addDependency('../../core/interfaces/i_delete_area.js', ['Blockly.IDeleteArea'], ['Blockly.IDragTarget']);
|
||||
goog.addDependency('../../core/interfaces/i_drag_target.js', ['Blockly.IDragTarget'], ['Blockly.IComponent']);
|
||||
goog.addDependency('../../core/interfaces/i_flyout.js', ['Blockly.IFlyout'], []);
|
||||
goog.addDependency('../../core/interfaces/i_metrics_manager.js', ['Blockly.IMetricsManager'], []);
|
||||
goog.addDependency('../../core/interfaces/i_movable.js', ['Blockly.IMovable'], []);
|
||||
@@ -174,12 +177,12 @@ goog.addDependency('../../core/theme_manager.js', ['Blockly.ThemeManager'], ['Bl
|
||||
goog.addDependency('../../core/toolbox/category.js', ['Blockly.ToolboxCategory'], ['Blockly.ISelectableToolboxItem', 'Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/toolbox/collapsible_category.js', ['Blockly.CollapsibleToolboxCategory'], ['Blockly.ICollapsibleToolboxItem', 'Blockly.ToolboxCategory', 'Blockly.ToolboxItem', 'Blockly.ToolboxSeparator', 'Blockly.registry', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox']);
|
||||
goog.addDependency('../../core/toolbox/separator.js', ['Blockly.ToolboxSeparator'], ['Blockly.IToolboxItem', 'Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils.dom'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/toolbox/toolbox.js', ['Blockly.Toolbox'], ['Blockly.CollapsibleToolboxCategory', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.ToolboxItemSelect', 'Blockly.IAutoHideable', 'Blockly.IDeleteArea', 'Blockly.IKeyboardAccessible', 'Blockly.IStyleable', 'Blockly.IToolbox', 'Blockly.Options', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/toolbox/toolbox.js', ['Blockly.Toolbox'], ['Blockly.CollapsibleToolboxCategory', 'Blockly.Css', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.ToolboxItemSelect', 'Blockly.IAutoHideable', 'Blockly.IKeyboardAccessible', 'Blockly.IStyleable', 'Blockly.IToolbox', 'Blockly.Options', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/toolbox/toolbox_item.js', ['Blockly.ToolboxItem'], ['Blockly.IToolboxItem']);
|
||||
goog.addDependency('../../core/tooltip.js', ['Blockly.Tooltip'], ['Blockly.browserEvents', 'Blockly.utils.string']);
|
||||
goog.addDependency('../../core/touch.js', ['Blockly.Touch'], ['Blockly.constants', 'Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.string']);
|
||||
goog.addDependency('../../core/touch_gesture.js', ['Blockly.TouchGesture'], ['Blockly.Gesture', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object']);
|
||||
goog.addDependency('../../core/trashcan.js', ['Blockly.Trashcan'], ['Blockly.Events', 'Blockly.Events.TrashcanOpen', 'Blockly.IAutoHideable', 'Blockly.IDeleteArea', 'Blockly.IPositionable', 'Blockly.Options', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.uiPosition', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/trashcan.js', ['Blockly.Trashcan'], ['Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.TrashcanOpen', 'Blockly.IAutoHideable', 'Blockly.IPositionable', 'Blockly.Options', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.uiPosition', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/utils.js', ['Blockly.utils'], ['Blockly.Msg', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.colour', 'Blockly.utils.global', 'Blockly.utils.string', 'Blockly.utils.style', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency('../../core/utils/aria.js', ['Blockly.utils.aria'], []);
|
||||
goog.addDependency('../../core/utils/colour.js', ['Blockly.utils.colour'], []);
|
||||
|
||||
@@ -25,6 +25,7 @@ goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.IDragTarget');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
@@ -59,13 +60,11 @@ Blockly.BlockDragger = function(block, workspace) {
|
||||
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}
|
||||
* Which drag area the mouse pointer is over, if any.
|
||||
* @type {?Blockly.IDragTarget}
|
||||
* @private
|
||||
*/
|
||||
this.deleteArea_ = null;
|
||||
this.dragTarget_ = null;
|
||||
|
||||
/**
|
||||
* Whether the block would be deleted if dropped immediately.
|
||||
@@ -210,8 +209,15 @@ Blockly.BlockDragger.prototype.dragBlock = function(e, currentDragDeltaXY) {
|
||||
this.draggingBlock_.moveDuringDrag(newLoc);
|
||||
this.dragIcons_(delta);
|
||||
|
||||
this.deleteArea_ = this.workspace_.isDeleteArea(e);
|
||||
this.draggedConnectionManager_.update(delta, this.deleteArea_);
|
||||
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_);
|
||||
this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock();
|
||||
|
||||
this.updateCursorDuringBlockDrag_();
|
||||
};
|
||||
@@ -237,8 +243,16 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
this.draggingBlock_.moveOffDragSurface(newLoc);
|
||||
|
||||
var deleted = this.maybeDeleteBlock_();
|
||||
if (!deleted) {
|
||||
if (this.dragTarget_) {
|
||||
this.dragTarget_.onBlockDrop(this.draggingBlock_);
|
||||
}
|
||||
|
||||
if (this.wouldDeleteBlock_) {
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
this.draggingBlock_.dispose(false, true);
|
||||
Blockly.draggingConnections = [];
|
||||
} else {
|
||||
// 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);
|
||||
@@ -284,49 +298,13 @@ Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
Blockly.Events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
var trashcan = this.workspace_.trashcan;
|
||||
|
||||
if (this.wouldDeleteBlock_) {
|
||||
if (trashcan) {
|
||||
setTimeout(trashcan.closeLid.bind(trashcan), 100);
|
||||
}
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
this.draggingBlock_.dispose(false, true);
|
||||
Blockly.draggingConnections = [];
|
||||
} else if (trashcan) {
|
||||
// Make sure the trash can lid is closed.
|
||||
trashcan.closeLid();
|
||||
}
|
||||
return this.wouldDeleteBlock_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the cursor (and possibly the trash can lid) to reflect whether the
|
||||
* dragging block would be deleted if released immediately.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock();
|
||||
var trashcan = this.workspace_.trashcan;
|
||||
if (this.wouldDeleteBlock_) {
|
||||
this.draggingBlock_.setDeleteStyle(true);
|
||||
if (this.deleteArea_ == Blockly.DELETE_AREA_TRASH && trashcan) {
|
||||
trashcan.setLidOpen(true);
|
||||
}
|
||||
} else {
|
||||
this.draggingBlock_.setDeleteStyle(false);
|
||||
if (trashcan) {
|
||||
trashcan.setLidOpen(false);
|
||||
}
|
||||
}
|
||||
this.draggingBlock_.setDeleteStyle(this.wouldDeleteBlock_);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,13 +51,11 @@ Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
this.workspace_ = workspace;
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* Which drag target the mouse pointer is over, if any.
|
||||
* @type {?Blockly.IDragTarget}
|
||||
* @private
|
||||
*/
|
||||
this.deleteArea_ = null;
|
||||
this.dragTarget_ = null;
|
||||
|
||||
/**
|
||||
* Whether the bubble would be deleted if dropped immediately.
|
||||
@@ -136,33 +134,41 @@ Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) {
|
||||
|
||||
this.draggingBubble_.moveDuringDrag(this.dragSurface_, newLoc);
|
||||
|
||||
if (this.draggingBubble_.isDeletable()) {
|
||||
this.deleteArea_ = this.workspace_.isDeleteArea(e);
|
||||
this.updateCursorDuringBubbleDrag_();
|
||||
var oldDragTarget = this.dragTarget_;
|
||||
this.dragTarget_ = this.workspace_.getDragTarget(e);
|
||||
if (this.dragTarget_ !== oldDragTarget) {
|
||||
oldDragTarget && oldDragTarget.onDragExit();
|
||||
this.dragTarget_ && this.dragTarget_.onDragEnter();
|
||||
}
|
||||
this.wouldDeleteBubble_ = this.shouldDelete_(this.dragTarget_);
|
||||
|
||||
this.updateCursorDuringBubbleDrag_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shut the trash can and, if necessary, delete the dragging bubble.
|
||||
* Should be called at the end of a bubble drag.
|
||||
* @return {boolean} Whether the bubble was deleted.
|
||||
* Whether ending the drag would delete the bubble.
|
||||
* @param {?Blockly.IDragTarget} dragTarget The drag target that the bubblee is
|
||||
* currently over.
|
||||
* @return {boolean} Whether dropping the bubble immediately would delete the
|
||||
* block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.maybeDeleteBubble_ = function() {
|
||||
var trashcan = this.workspace_.trashcan;
|
||||
Blockly.BubbleDragger.prototype.shouldDelete_ = function(dragTarget) {
|
||||
var couldDeleteBubble = this.draggingBubble_.isDeletable();
|
||||
|
||||
if (this.wouldDeleteBubble_) {
|
||||
if (trashcan) {
|
||||
setTimeout(trashcan.closeLid.bind(trashcan), 100);
|
||||
if (couldDeleteBubble && dragTarget) {
|
||||
// TODO(#4881) use hasCapability instead of getComponents
|
||||
var deleteAreas = this.workspace_.getComponentManager().getComponents(
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA, false);
|
||||
var isDeleteArea = deleteAreas.some(function(deleteArea) {
|
||||
return dragTarget === deleteArea;
|
||||
});
|
||||
if (isDeleteArea) {
|
||||
return (/** @type {!Blockly.IDeleteArea} */ (dragTarget))
|
||||
.wouldDeleteBubble(this.draggingBubble_);
|
||||
}
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
this.draggingBubble_.dispose(false, true);
|
||||
} else if (trashcan) {
|
||||
// Make sure the trash can lid is closed.
|
||||
trashcan.closeLid();
|
||||
}
|
||||
return this.wouldDeleteBubble_;
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -171,18 +177,10 @@ Blockly.BubbleDragger.prototype.maybeDeleteBubble_ = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.updateCursorDuringBubbleDrag_ = function() {
|
||||
this.wouldDeleteBubble_ = this.deleteArea_ != Blockly.DELETE_AREA_NONE;
|
||||
var trashcan = this.workspace_.trashcan;
|
||||
if (this.wouldDeleteBubble_) {
|
||||
this.draggingBubble_.setDeleteStyle(true);
|
||||
if (this.deleteArea_ == Blockly.DELETE_AREA_TRASH && trashcan) {
|
||||
trashcan.setLidOpen(true);
|
||||
}
|
||||
} else {
|
||||
this.draggingBubble_.setDeleteStyle(false);
|
||||
if (trashcan) {
|
||||
trashcan.setLidOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -200,12 +198,18 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function(
|
||||
|
||||
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);
|
||||
var deleted = this.maybeDeleteBubble_();
|
||||
|
||||
if (!deleted) {
|
||||
if (this.dragTarget_) {
|
||||
this.dragTarget_.onBubbleDrop(this.draggingBubble_);
|
||||
}
|
||||
|
||||
if (this.wouldDeleteBubble_) {
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
this.draggingBubble_.dispose(false, true);
|
||||
} else {
|
||||
// Put everything back onto the bubble canvas.
|
||||
if (this.dragSurface_) {
|
||||
this.dragSurface_.clearAndHide(this.workspace_.getBubbleCanvas());
|
||||
|
||||
@@ -15,6 +15,8 @@ goog.provide('Blockly.ComponentManager');
|
||||
|
||||
goog.requireType('Blockly.IAutoHideable');
|
||||
goog.requireType('Blockly.IComponent');
|
||||
goog.requireType('Blockly.IDeleteArea');
|
||||
goog.requireType('Blockly.IDragTarget');
|
||||
goog.requireType('Blockly.IPositionable');
|
||||
|
||||
|
||||
@@ -206,6 +208,15 @@ Blockly.ComponentManager.Capability.prototype.toString = function() {
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IPositionable>} */
|
||||
Blockly.ComponentManager.Capability.POSITIONABLE =
|
||||
new Blockly.ComponentManager.Capability('positionable');
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IDragTarget>} */
|
||||
Blockly.ComponentManager.Capability.DRAG_TARGET =
|
||||
new Blockly.ComponentManager.Capability('drag_target');
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IDeleteArea>} */
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA =
|
||||
new Blockly.ComponentManager.Capability('delete_area');
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IAutoHideable>} */
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE =
|
||||
new Blockly.ComponentManager.Capability('autohideable');
|
||||
|
||||
@@ -161,26 +161,6 @@ Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.NEXT_STATEMENT] =
|
||||
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.PREVIOUS_STATEMENT] =
|
||||
Blockly.connectionTypes.NEXT_STATEMENT;
|
||||
|
||||
/**
|
||||
* ENUM representing that an event is not in any delete areas.
|
||||
* Null for backwards compatibility reasons.
|
||||
* @const
|
||||
*/
|
||||
Blockly.DELETE_AREA_NONE = null;
|
||||
|
||||
/**
|
||||
* ENUM representing that an event is in the delete area of the trash can.
|
||||
* @const
|
||||
*/
|
||||
Blockly.DELETE_AREA_TRASH = 1;
|
||||
|
||||
/**
|
||||
* ENUM representing that an event is in the delete area of the toolbox or
|
||||
* flyout.
|
||||
* @const
|
||||
*/
|
||||
Blockly.DELETE_AREA_TOOLBOX = 2;
|
||||
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
|
||||
53
core/delete_area.js
Normal file
53
core/delete_area.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The abstract class for a component that can delete a block or
|
||||
* bubble that is dropped on top of it.
|
||||
* @author kozbial@google.com (Monica Kozbial)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.DeleteArea');
|
||||
|
||||
goog.require('Blockly.DragTarget');
|
||||
goog.require('Blockly.IDeleteArea');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a component that can delete a block or bubble that is
|
||||
* dropped on top of it.
|
||||
* @extends {Blockly.DragTarget}
|
||||
* @implements {Blockly.IDeleteArea}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.DeleteArea = function() {
|
||||
Blockly.DeleteArea.superClass_.constructor.call(this);
|
||||
};
|
||||
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.
|
||||
* @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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the provided bubble would be deleted if dropped on this area.
|
||||
* @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;
|
||||
};
|
||||
70
core/drag_target.js
Normal file
70
core/drag_target.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The abstract class for a component with custom behaviour when a
|
||||
* block or bubble is dragged over or dropped on top of it.
|
||||
* @author kozbial@google.com (Monica Kozbial)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.DragTarget');
|
||||
|
||||
goog.require('Blockly.IDragTarget');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a component with custom behaviour when a block or bubble
|
||||
* is dragged over or dropped on top of it.
|
||||
* @implements {Blockly.IDragTarget}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.DragTarget = function() {};
|
||||
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to the Blockly injection div.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.getClientRect;
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble enters this drag target.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onDragEnter = function() {
|
||||
// no-op
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble exits this drag target.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onDragExit = function() {
|
||||
// no-op
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a block is dropped on this component. Should not handle delete
|
||||
* here.
|
||||
* @param {!Blockly.BlockSvg} _block The block.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onBlockDrop = function(_block) {
|
||||
// no-op
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a bubble is dropped on this component. Should not handle delete
|
||||
* here.
|
||||
* @param {!Blockly.IBubble} _bubble The bubble.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onBubbleDrop = function(_bubble) {
|
||||
// no-op
|
||||
};
|
||||
@@ -16,6 +16,7 @@ goog.require('Blockly.Block');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.blockRendering');
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.DeleteArea');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockCreate');
|
||||
@@ -24,7 +25,6 @@ goog.require('Blockly.Events.VarCreate');
|
||||
goog.require('Blockly.FlyoutMetricsManager');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Gesture');
|
||||
goog.require('Blockly.IDeleteArea');
|
||||
goog.require('Blockly.IFlyout');
|
||||
goog.require('Blockly.ScrollbarPair');
|
||||
goog.require('Blockly.Tooltip');
|
||||
@@ -51,10 +51,11 @@ goog.requireType('Blockly.utils.Rect');
|
||||
* workspace.
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @implements {Blockly.IDeleteArea}
|
||||
* @implements {Blockly.IFlyout}
|
||||
* @extends {Blockly.DeleteArea}
|
||||
*/
|
||||
Blockly.Flyout = function(workspaceOptions) {
|
||||
Blockly.Flyout.superClass_.constructor.call(this);
|
||||
workspaceOptions.setMetrics = this.setMetrics_.bind(this);
|
||||
|
||||
/**
|
||||
@@ -140,6 +141,7 @@ Blockly.Flyout = function(workspaceOptions) {
|
||||
*/
|
||||
this.targetWorkspace = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Flyout, Blockly.DeleteArea);
|
||||
|
||||
/**
|
||||
* Does the flyout automatically close when a block is created?
|
||||
@@ -300,6 +302,16 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) {
|
||||
this.workspace_.setVariableMap(this.targetWorkspace.getVariableMap());
|
||||
|
||||
this.workspace_.createPotentialVariableMap();
|
||||
|
||||
targetWorkspace.getComponentManager().addComponent({
|
||||
id: 'flyout' + this.workspace_.id,
|
||||
component: this,
|
||||
weight: 1,
|
||||
capabilities: [
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA,
|
||||
Blockly.ComponentManager.Capability.DRAG_TARGET
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -380,6 +392,11 @@ Blockly.Flyout.prototype.setVisible = function(visible) {
|
||||
|
||||
this.isVisible_ = visible;
|
||||
if (visibilityChanged) {
|
||||
if (!this.autoClose) {
|
||||
// Auto-close flyouts are ignored as drag targets, so only non auto-close
|
||||
// flyouts need to have their drag target updated.
|
||||
this.workspace_.recordDragTargets();
|
||||
}
|
||||
this.updateDisplay_();
|
||||
}
|
||||
};
|
||||
@@ -1018,8 +1035,9 @@ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the deletion rectangle for this flyout in viewport coordinates.
|
||||
* @return {?Blockly.utils.Rect} Rectangle in which to delete.
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {Blockly.utils.Rect} The component's bounding box.
|
||||
*/
|
||||
Blockly.Flyout.prototype.getClientRect;
|
||||
|
||||
|
||||
@@ -304,11 +304,15 @@ Blockly.HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the deletion rectangle for this flyout in viewport coordinates.
|
||||
* @return {?Blockly.utils.Rect} Rectangle in which to delete.
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getClientRect = function() {
|
||||
if (!this.svgGroup_) {
|
||||
if (!this.svgGroup_ || this.autoClose || this.isVisible()) {
|
||||
// The bounding rectangle won't compute correctly if the flyout is closed
|
||||
// and auto-close flyouts aren't valid drag targets (or delete areas).
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -287,11 +287,15 @@ Blockly.VerticalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the deletion rectangle for this flyout in viewport coordinates.
|
||||
* @return {?Blockly.utils.Rect} Rectangle in which to delete.
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.getClientRect = function() {
|
||||
if (!this.svgGroup_) {
|
||||
if (!this.svgGroup_ || this.autoClose || this.isVisible()) {
|
||||
// The bounding rectangle won't compute correctly if the flyout is closed
|
||||
// and auto-close flyouts aren't valid drag targets (or delete areas).
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -240,14 +240,15 @@ Blockly.InsertionMarkerManager.prototype.applyConnections = function() {
|
||||
* Update connections based on the most recent move location.
|
||||
* @param {!Blockly.utils.Coordinate} dxy Position relative to drag start,
|
||||
* in workspace units.
|
||||
* @param {?number} deleteArea One of {@link Blockly.DELETE_AREA_TRASH},
|
||||
* {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}.
|
||||
* @param {?Blockly.IDragTarget} dragTarget The drag target that the block is
|
||||
* currently over.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.update = function(dxy, deleteArea) {
|
||||
Blockly.InsertionMarkerManager.prototype.update = function(dxy, dragTarget) {
|
||||
var candidate = this.getCandidate_(dxy);
|
||||
|
||||
this.wouldDeleteBlock_ = this.shouldDelete_(candidate, deleteArea);
|
||||
this.wouldDeleteBlock_ = this.shouldDelete_(candidate, dragTarget);
|
||||
|
||||
var shouldUpdate = this.wouldDeleteBlock_ ||
|
||||
this.shouldUpdatePreviews_(candidate, dxy);
|
||||
|
||||
@@ -445,23 +446,32 @@ Blockly.InsertionMarkerManager.prototype.getStartRadius_ = function() {
|
||||
/**
|
||||
* Whether ending the drag would delete the block.
|
||||
* @param {!Object} candidate An object containing a local connection, a closest
|
||||
* connection, and a radius.
|
||||
* @param {?number} deleteArea One of {@link Blockly.DELETE_AREA_TRASH},
|
||||
* {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}.
|
||||
* @return {boolean} True if dropping the block immediately would replace
|
||||
* delete the block. False otherwise.
|
||||
* connection, and a radius.
|
||||
* @param {?Blockly.IDragTarget} dragTarget The drag target that the block is
|
||||
* currently over.
|
||||
* @return {boolean} Whether dropping the block immediately would delete the
|
||||
* block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function(candidate,
|
||||
deleteArea) {
|
||||
// Prefer connecting over dropping into the trash can, but prefer dragging to
|
||||
// the toolbox over connecting to other blocks.
|
||||
var wouldConnect = candidate && !!candidate.closest &&
|
||||
deleteArea != Blockly.DELETE_AREA_TOOLBOX;
|
||||
var wouldDelete = !!deleteArea && !this.topBlock_.getParent() &&
|
||||
this.topBlock_.isDeletable();
|
||||
Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function(
|
||||
candidate, dragTarget) {
|
||||
var couldDeleteBlock =
|
||||
!this.topBlock_.getParent() && this.topBlock_.isDeletable();
|
||||
|
||||
return wouldDelete && !wouldConnect;
|
||||
if (couldDeleteBlock && dragTarget) {
|
||||
// TODO(#4881) use hasCapability instead of getComponents
|
||||
var deleteAreas = this.workspace_.getComponentManager().getComponents(
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA, false);
|
||||
var isDeleteArea = deleteAreas.some(function(deleteArea) {
|
||||
return dragTarget === deleteArea;
|
||||
});
|
||||
if (isDeleteArea) {
|
||||
return (
|
||||
/** @type {!Blockly.IDeleteArea} */ (dragTarget))
|
||||
.wouldDeleteBlock(this.topBlock_, candidate && !!candidate.closest);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
44
core/interfaces/i_delete_area.js
Normal file
44
core/interfaces/i_delete_area.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for a component that can delete a block or bubble
|
||||
* that is dropped on top of it.
|
||||
* @author kozbial@google.com (Monica Kozbial)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDeleteArea');
|
||||
|
||||
goog.require('Blockly.IDragTarget');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a component that can delete a block or bubble that is dropped
|
||||
* on top of it.
|
||||
* @extends {Blockly.IDragTarget}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDeleteArea = function() {};
|
||||
|
||||
/**
|
||||
* Returns whether the provided block would be deleted if dropped on this area.
|
||||
* @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.IDeleteArea.prototype.wouldDeleteBlock;
|
||||
|
||||
/**
|
||||
* Returns whether the provided bubble would be deleted if dropped on this area.
|
||||
* @param {!Blockly.IBubble} bubble The bubble.
|
||||
* @return {boolean} Whether the bubble provided would be deleted if dropped on
|
||||
* this area.
|
||||
*/
|
||||
Blockly.IDeleteArea.prototype.wouldDeleteBubble;
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for a component that can delete a block that is
|
||||
* dropped on top of it.
|
||||
* @author aschmiedt@google.com (Abby Schmiedt)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDeleteArea');
|
||||
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a component that can delete a block that is dropped on top of it.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDeleteArea = function() {};
|
||||
|
||||
/**
|
||||
* Return the deletion rectangle.
|
||||
* @return {Blockly.utils.Rect} Rectangle in which to delete.
|
||||
*/
|
||||
Blockly.IDeleteArea.prototype.getClientRect;
|
||||
60
core/interfaces/i_drag_target.js
Normal file
60
core/interfaces/i_drag_target.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for a component that has a handler for when a
|
||||
* block is dropped on top of it.
|
||||
* @author kozbial@google.com (Monica Kozbial)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDragTarget');
|
||||
|
||||
goog.require('Blockly.IComponent');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
/**
|
||||
* Interface for a component with custom behaviour when a block or bubble is
|
||||
* dragged over or dropped on top of it.
|
||||
* @extends {Blockly.IComponent}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDragTarget = function() {};
|
||||
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {Blockly.utils.Rect} The component's bounding box.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.getClientRect;
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble enters this drag target.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onDragEnter;
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble exits this drag target.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onDragExit;
|
||||
|
||||
/**
|
||||
* Handles when a block is dropped on this component. Should not handle delete
|
||||
* here.
|
||||
* @param {!Blockly.BlockSvg} block The block.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onBlockDrop;
|
||||
|
||||
/**
|
||||
* Handles when a bubble is dropped on this component. Should not handle delete
|
||||
* here.
|
||||
* @param {!Blockly.IBubble} bubble The bubble.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onBubbleDrop;
|
||||
@@ -287,7 +287,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
|
||||
*/
|
||||
Blockly.Mutator.prototype.onBubbleMove_ = function() {
|
||||
if (this.workspace_) {
|
||||
this.workspace_.recordDeleteAreas();
|
||||
this.workspace_.recordDragTargets();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ goog.require('Blockly.CollapsibleToolboxCategory');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.DeleteArea');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.ToolboxItemSelect');
|
||||
goog.require('Blockly.IAutoHideable');
|
||||
goog.require('Blockly.IDeleteArea');
|
||||
goog.require('Blockly.IKeyboardAccessible');
|
||||
goog.require('Blockly.IStyleable');
|
||||
goog.require('Blockly.IToolbox');
|
||||
@@ -50,11 +50,12 @@ goog.requireType('Blockly.WorkspaceSvg');
|
||||
* @constructor
|
||||
* @implements {Blockly.IAutoHideable}
|
||||
* @implements {Blockly.IKeyboardAccessible}
|
||||
* @implements {Blockly.IDeleteArea}
|
||||
* @implements {Blockly.IStyleable}
|
||||
* @implements {Blockly.IToolbox}
|
||||
* @extends {Blockly.DeleteArea}
|
||||
*/
|
||||
Blockly.Toolbox = function(workspace) {
|
||||
Blockly.Toolbox.superClass_.constructor.call(this);
|
||||
/**
|
||||
* The workspace this toolbox is on.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
@@ -159,6 +160,7 @@ Blockly.Toolbox = function(workspace) {
|
||||
*/
|
||||
this.boundEvents_ = [];
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Toolbox, Blockly.DeleteArea);
|
||||
|
||||
/**
|
||||
* Handles the given keyboard shortcut.
|
||||
@@ -189,13 +191,14 @@ Blockly.Toolbox.prototype.init = function() {
|
||||
themeManager.subscribe(this.HtmlDiv, 'toolboxBackgroundColour',
|
||||
'background-color');
|
||||
themeManager.subscribe(this.HtmlDiv, 'toolboxForegroundColour', 'color');
|
||||
|
||||
this.workspace_.getComponentManager().addComponent({
|
||||
id: 'toolbox',
|
||||
component: this,
|
||||
weight: 1,
|
||||
capabilities: [
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE,
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA,
|
||||
Blockly.ComponentManager.Capability.DRAG_TARGET
|
||||
]
|
||||
});
|
||||
};
|
||||
@@ -496,9 +499,10 @@ Blockly.Toolbox.prototype.removeStyle = function(style) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the deletion rectangle for this toolbox.
|
||||
* @return {?Blockly.utils.Rect} Rectangle in which to delete.
|
||||
* @public
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.Toolbox.prototype.getClientRect = function() {
|
||||
if (!this.HtmlDiv) {
|
||||
@@ -529,6 +533,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.
|
||||
* @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.Toolbox.prototype.wouldDeleteBlock = function(_block, _couldConnect) {
|
||||
// Prefer dragging to the toolbox over connecting to other blocks.
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the toolbox item with the given ID.
|
||||
* @param {string} id The ID of the toolbox item.
|
||||
|
||||
@@ -15,11 +15,11 @@ goog.provide('Blockly.Trashcan');
|
||||
goog.require('Blockly.browserEvents');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.DeleteArea');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.TrashcanOpen');
|
||||
goog.require('Blockly.IAutoHideable');
|
||||
goog.require('Blockly.IDeleteArea');
|
||||
goog.require('Blockly.IPositionable');
|
||||
goog.require('Blockly.Options');
|
||||
goog.require('Blockly.registry');
|
||||
@@ -40,10 +40,11 @@ goog.requireType('Blockly.WorkspaceSvg');
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace to sit in.
|
||||
* @constructor
|
||||
* @implements {Blockly.IAutoHideable}
|
||||
* @implements {Blockly.IDeleteArea}
|
||||
* @implements {Blockly.IPositionable}
|
||||
* @extends {Blockly.DeleteArea}
|
||||
*/
|
||||
Blockly.Trashcan = function(workspace) {
|
||||
Blockly.Trashcan.superClass_.constructor.call(this);
|
||||
/**
|
||||
* The workspace the trashcan sits in.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
@@ -102,6 +103,7 @@ Blockly.Trashcan = function(workspace) {
|
||||
}
|
||||
this.workspace_.addChangeListener(this.onDelete_.bind(this));
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Trashcan, Blockly.DeleteArea);
|
||||
|
||||
/**
|
||||
* Width of both the trash can and lid images.
|
||||
@@ -364,8 +366,10 @@ Blockly.Trashcan.prototype.init = function() {
|
||||
component: this,
|
||||
weight: 1,
|
||||
capabilities: [
|
||||
Blockly.ComponentManager.Capability.POSITIONABLE,
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE,
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA,
|
||||
Blockly.ComponentManager.Capability.DRAG_TARGET,
|
||||
Blockly.ComponentManager.Capability.POSITIONABLE
|
||||
]
|
||||
});
|
||||
this.initialized_ = true;
|
||||
@@ -501,8 +505,10 @@ Blockly.Trashcan.prototype.getBoundingRectangle = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the deletion rectangle for this trash can.
|
||||
* @return {?Blockly.utils.Rect} Rectangle in which to delete.
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.Trashcan.prototype.getClientRect = function() {
|
||||
if (!this.svgGroup_) {
|
||||
@@ -518,6 +524,51 @@ Blockly.Trashcan.prototype.getClientRect = function() {
|
||||
return new Blockly.utils.Rect(top, bottom, left, right);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble enters this drag target.
|
||||
* @override
|
||||
*/
|
||||
Blockly.Trashcan.prototype.onDragEnter = function() {
|
||||
this.setLidOpen(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble exits this drag target.
|
||||
* @override
|
||||
*/
|
||||
Blockly.Trashcan.prototype.onDragExit = function() {
|
||||
this.setLidOpen(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles when a block is dropped on this component. Should not handle delete
|
||||
* here.
|
||||
* @param {!Blockly.BlockSvg} _block The block.
|
||||
* @override
|
||||
*/
|
||||
Blockly.Trashcan.prototype.onBlockDrop = function(_block) {
|
||||
this.onDrop_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a bubble is dropped on this component. Should not handle delete
|
||||
* here.
|
||||
* @param {!Blockly.IBubble} _bubble The bubble.
|
||||
* @override
|
||||
*/
|
||||
Blockly.Trashcan.prototype.onBubbleDrop = function(_bubble) {
|
||||
this.onDrop_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a block or bubble is dropped on this component.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Trashcan.prototype.onDrop_ = function() {
|
||||
setTimeout(this.closeLid.bind(this), 100);
|
||||
};
|
||||
|
||||
/**
|
||||
* Flip the lid open or shut.
|
||||
* @param {boolean} state True if open.
|
||||
|
||||
@@ -61,6 +61,7 @@ goog.requireType('Blockly.blockRendering.Renderer');
|
||||
goog.requireType('Blockly.Cursor');
|
||||
goog.requireType('Blockly.FlyoutButton');
|
||||
goog.requireType('Blockly.IBoundedElement');
|
||||
goog.requireType('Blockly.IDragTarget');
|
||||
goog.requireType('Blockly.IFlyout');
|
||||
goog.requireType('Blockly.IMetricsManager');
|
||||
goog.requireType('Blockly.IToolbox');
|
||||
@@ -232,6 +233,17 @@ Blockly.WorkspaceSvg = function(
|
||||
*/
|
||||
this.topBoundedElements_ = [];
|
||||
|
||||
/**
|
||||
* The recorded drag targets.
|
||||
* @type {!Array<
|
||||
* {
|
||||
* component: !Blockly.IDragTarget,
|
||||
* clientRect: !Blockly.utils.Rect,
|
||||
* }>}
|
||||
* @private
|
||||
*/
|
||||
this.dragTargetAreas_ = [];
|
||||
|
||||
/**
|
||||
* The cached size of the parent svg element.
|
||||
* Used to compute svg metrics.
|
||||
@@ -879,7 +891,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) {
|
||||
if (this.grid_) {
|
||||
this.grid_.update(this.scale);
|
||||
}
|
||||
this.recordDeleteAreas();
|
||||
this.recordDragTargets();
|
||||
var CursorClass = Blockly.registry.getClassFromOptions(
|
||||
Blockly.registry.Type.CURSOR, this.options);
|
||||
|
||||
@@ -1096,7 +1108,7 @@ Blockly.WorkspaceSvg.prototype.getToolbox = function() {
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.updateScreenCalculations_ = function() {
|
||||
this.updateInverseScreenCTM();
|
||||
this.recordDeleteAreas();
|
||||
this.recordDragTargets();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1617,38 +1629,50 @@ Blockly.WorkspaceSvg.prototype.createVariable = function(name,
|
||||
|
||||
/**
|
||||
* Make a list of all the delete areas for this workspace.
|
||||
* @deprecated Use workspace.recordDragTargets. (2021 June)
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.recordDeleteAreas = function() {
|
||||
if (this.trashcan && this.svgGroup_.parentNode) {
|
||||
this.deleteAreaTrash_ = this.trashcan.getClientRect();
|
||||
} else {
|
||||
this.deleteAreaTrash_ = null;
|
||||
}
|
||||
if (this.flyout_) {
|
||||
this.deleteAreaToolbox_ = this.flyout_.getClientRect();
|
||||
} else if (this.toolbox_ && typeof this.toolbox_.getClientRect == 'function') {
|
||||
this.deleteAreaToolbox_ = this.toolbox_.getClientRect();
|
||||
} else {
|
||||
this.deleteAreaToolbox_ = null;
|
||||
}
|
||||
Blockly.utils.deprecation.warn(
|
||||
'WorkspaceSvg.prototype.recordDeleteAreas',
|
||||
'June 2021',
|
||||
'June 2022',
|
||||
'WorkspaceSvg.prototype.recordDragTargets');
|
||||
this.recordDragTargets();
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the mouse event over a delete area (toolbox or non-closing flyout)?
|
||||
* @param {!Event} e Mouse move event.
|
||||
* @return {?number} Null if not over a delete area, or an enum representing
|
||||
* which delete area the event is over.
|
||||
* Make a list of all the delete areas for this workspace.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.isDeleteArea = function(e) {
|
||||
if (this.deleteAreaTrash_ &&
|
||||
this.deleteAreaTrash_.contains(e.clientX, e.clientY)) {
|
||||
return Blockly.DELETE_AREA_TRASH;
|
||||
Blockly.WorkspaceSvg.prototype.recordDragTargets = function() {
|
||||
var dragTargets = this.componentManager_.getComponents(
|
||||
Blockly.ComponentManager.Capability.DRAG_TARGET, true);
|
||||
|
||||
this.dragTargetAreas_ = [];
|
||||
for (var i = 0, targetArea; (targetArea = dragTargets[i]); i++) {
|
||||
var rect = targetArea.getClientRect();
|
||||
if (rect) {
|
||||
this.dragTargetAreas_.push({
|
||||
component: targetArea,
|
||||
clientRect: rect,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (this.deleteAreaToolbox_ &&
|
||||
this.deleteAreaToolbox_.contains(e.clientX, e.clientY)) {
|
||||
return Blockly.DELETE_AREA_TOOLBOX;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the drag target the mouse event is over.
|
||||
* @param {!Event} e Mouse move event.
|
||||
* @return {?Blockly.IDragTarget} Null if not over a drag target, or the drag
|
||||
* target the event is over.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.getDragTarget = function(e) {
|
||||
for (var i = 0, targetArea; (targetArea = this.dragTargetAreas_[i]); i++) {
|
||||
if (targetArea.clientRect.contains(e.clientX, e.clientY)) {
|
||||
return targetArea.component;
|
||||
}
|
||||
}
|
||||
return Blockly.DELETE_AREA_NONE;
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2200,7 +2224,7 @@ Blockly.WorkspaceSvg.prototype.setScale = function(newScale) {
|
||||
if (this.flyout_) {
|
||||
// No toolbox, resize flyout.
|
||||
this.flyout_.reflow();
|
||||
this.recordDeleteAreas();
|
||||
this.recordDragTargets();
|
||||
}
|
||||
if (this.grid_) {
|
||||
this.grid_.update(this.scale);
|
||||
|
||||
Reference in New Issue
Block a user