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
100 changes: 54 additions & 46 deletions core/block_dragger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ import {WorkspaceSvg} from './workspace_svg.js';
* @alias Blockly.BlockDragger
*/
export class BlockDragger implements IBlockDragger {
/** The top block in the stack that is being dragged. */
protected draggingBlock_: BlockSvg;
protected draggedConnectionManager_: InsertionMarkerManager;

/** The workspace on which the block is being dragged. */
protected workspace_: WorkspaceSvg;

/** Which drag area the mouse pointer is over, if any. */
private dragTarget_: IDragTarget|null = null;

Expand All @@ -60,17 +65,20 @@ export class BlockDragger implements IBlockDragger {
* @param block The block to drag.
* @param workspace The workspace to drag on.
*/
constructor(
private readonly block: BlockSvg,
private readonly workspace: WorkspaceSvg) {
constructor(block: BlockSvg, workspace: WorkspaceSvg) {
this.draggingBlock_ = block;

/** Object that keeps track of connections on dragged blocks. */
this.draggedConnectionManager_ = new InsertionMarkerManager(this.block);
this.draggedConnectionManager_ =
new InsertionMarkerManager(this.draggingBlock_);

this.workspace_ = workspace;

/**
* The location of the top left corner of the dragging block at the
* beginning of the drag in workspace coordinates.
*/
this.startXY_ = this.block.getRelativeToSurfaceXY();
this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY();

/**
* A list of all of the icons (comment, warning, and mutator) that are
Expand Down Expand Up @@ -108,24 +116,24 @@ export class BlockDragger implements IBlockDragger {
// during a drag. They have to rely on the order of the blocks in the SVG.
// For performance reasons that usually happens at the end of a drag,
// but do it at the beginning for mutators.
if (this.workspace.isMutator) {
this.block.bringToFront();
if (this.workspace_.isMutator) {
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.
dom.startTextWidthCache();
this.workspace.setResizesEnabled(false);
this.workspace_.setResizesEnabled(false);
blockAnimation.disconnectUiStop();

if (this.shouldDisconnect_(healStack)) {
this.disconnectBlock_(healStack, currentDragDeltaXY);
}
this.block.setDragging(true);
this.draggingBlock_.setDragging(true);
// For future consideration: we may be able to put moveToDragSurface inside
// the block dragger, which would also let the block not track the block
// drag surface.
this.block.moveToDragSurface();
this.draggingBlock_.moveToDragSurface();
}

/**
Expand All @@ -135,9 +143,9 @@ export class BlockDragger implements IBlockDragger {
*/
protected shouldDisconnect_(healStack: boolean): boolean {
return !!(
this.block.getParent() ||
healStack && this.block.nextConnection &&
this.block.nextConnection.targetBlock());
this.draggingBlock_.getParent() ||
healStack && this.draggingBlock_.nextConnection &&
this.draggingBlock_.nextConnection.targetBlock());
}

/**
Expand All @@ -148,19 +156,19 @@ export class BlockDragger implements IBlockDragger {
*/
protected disconnectBlock_(
healStack: boolean, currentDragDeltaXY: Coordinate) {
this.block.unplug(healStack);
this.draggingBlock_.unplug(healStack);
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
const newLoc = Coordinate.sum(this.startXY_, delta);

this.block.translate(newLoc.x, newLoc.y);
blockAnimation.disconnectUiEffect(this.block);
this.draggingBlock_.translate(newLoc.x, newLoc.y);
blockAnimation.disconnectUiEffect(this.draggingBlock_);
this.draggedConnectionManager_.updateAvailableConnections();
}

/** Fire a UI event at the start of a block drag. */
protected fireDragStartEvent_() {
const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))!
(this.block, true, this.block.getDescendants(false));
(this.draggingBlock_, true, this.draggingBlock_.getDescendants(false));
eventUtils.fire(event);
}

Expand All @@ -174,11 +182,11 @@ export class BlockDragger implements IBlockDragger {
drag(e: Event, currentDragDeltaXY: Coordinate) {
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
const newLoc = Coordinate.sum(this.startXY_, delta);
this.block.moveDuringDrag(newLoc);
this.draggingBlock_.moveDuringDrag(newLoc);
this.dragIcons_(delta);

const oldDragTarget = this.dragTarget_;
this.dragTarget_ = this.workspace.getDragTarget(e);
this.dragTarget_ = this.workspace_.getDragTarget(e);

this.draggedConnectionManager_.update(delta, this.dragTarget_);
const oldWouldDeleteBlock = this.wouldDeleteBlock_;
Expand All @@ -191,10 +199,10 @@ export class BlockDragger implements IBlockDragger {
// Call drag enter/exit/over after wouldDeleteBlock is called in
// InsertionMarkerManager.update.
if (this.dragTarget_ !== oldDragTarget) {
oldDragTarget && oldDragTarget.onDragExit(this.block);
this.dragTarget_ && this.dragTarget_.onDragEnter(this.block);
oldDragTarget && oldDragTarget.onDragExit(this.draggingBlock_);
this.dragTarget_ && this.dragTarget_.onDragEnter(this.draggingBlock_);
}
this.dragTarget_ && this.dragTarget_.onDragOver(this.block);
this.dragTarget_ && this.dragTarget_.onDragOver(this.draggingBlock_);
}

/**
Expand All @@ -213,8 +221,8 @@ export class BlockDragger implements IBlockDragger {

blockAnimation.disconnectUiStop();

const preventMove =
!!this.dragTarget_ && this.dragTarget_.shouldPreventMove(this.block);
const preventMove = !!this.dragTarget_ &&
this.dragTarget_.shouldPreventMove(this.draggingBlock_);
let newLoc: Coordinate;
let delta: Coordinate|null = null;
if (preventMove) {
Expand All @@ -224,28 +232,28 @@ export class BlockDragger implements IBlockDragger {
delta = newValues.delta;
newLoc = newValues.newLocation;
}
this.block.moveOffDragSurface(newLoc);
this.draggingBlock_.moveOffDragSurface(newLoc);

if (this.dragTarget_) {
this.dragTarget_.onDrop(this.block);
this.dragTarget_.onDrop(this.draggingBlock_);
}

const deleted = this.maybeDeleteBlock_();
if (!deleted) {
// These are expensive and don't need to be done if we're deleting.
this.block.setDragging(false);
this.draggingBlock_.setDragging(false);
if (delta) { // !preventMove
this.updateBlockAfterMove_(delta);
} else {
// Blocks dragged directly from a flyout may need to be bumped into
// bounds.
bumpObjects.bumpIntoBounds(
this.block.workspace,
this.workspace.getMetricsManager().getScrollMetrics(true),
this.block);
this.draggingBlock_.workspace,
this.workspace_.getMetricsManager().getScrollMetrics(true),
this.draggingBlock_);
}
}
this.workspace.setResizesEnabled(true);
this.workspace_.setResizesEnabled(true);

eventUtils.setGroup(false);
}
Expand Down Expand Up @@ -277,7 +285,7 @@ export class BlockDragger implements IBlockDragger {
if (this.wouldDeleteBlock_) {
// Fire a move event, so we know where to go back to for an undo.
this.fireMoveEvent_();
this.block.dispose(false, true);
this.draggingBlock_.dispose(false, true);
common.draggingConnections.length = 0;
return true;
}
Expand All @@ -290,21 +298,21 @@ export class BlockDragger implements IBlockDragger {
* to where it ended the drag.
*/
protected updateBlockAfterMove_(delta: Coordinate) {
this.block.moveConnections(delta.x, delta.y);
this.draggingBlock_.moveConnections(delta.x, delta.y);
this.fireMoveEvent_();
if (this.draggedConnectionManager_.wouldConnectBlock()) {
// Applying connections also rerenders the relevant blocks.
this.draggedConnectionManager_.applyConnections();
} else {
this.block.render();
this.draggingBlock_.render();
}
this.block.scheduleSnapAndBump();
this.draggingBlock_.scheduleSnapAndBump();
}

/** Fire a UI event at the end of a block drag. */
protected fireDragEndEvent_() {
const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))!
(this.block, false, this.block.getDescendants(false));
(this.draggingBlock_, false, this.draggingBlock_.getDescendants(false));
eventUtils.fire(event);
}

Expand All @@ -315,11 +323,11 @@ export class BlockDragger implements IBlockDragger {
* @param isEnd True if we are at the end of a drag, false otherwise.
*/
protected updateToolboxStyle_(isEnd: boolean) {
const toolbox = this.workspace.getToolbox();
const toolbox = this.workspace_.getToolbox();

if (toolbox) {
const style = this.block.isDeletable() ? 'blocklyToolboxDelete' :
'blocklyToolboxGrab';
const style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
'blocklyToolboxGrab';

// AnyDuringMigration because: Property 'removeStyle' does not exist on
// type 'IToolbox'.
Expand All @@ -342,8 +350,8 @@ export class BlockDragger implements IBlockDragger {

/** Fire a move event at the end of a block drag. */
protected fireMoveEvent_() {
const event =
new (eventUtils.get(eventUtils.BLOCK_MOVE))!(this.block) as BlockMove;
const event = new (eventUtils.get(eventUtils.BLOCK_MOVE))!
(this.draggingBlock_) as BlockMove;
event.oldCoordinate = this.startXY_;
event.recordNew();
eventUtils.fire(event);
Expand All @@ -354,7 +362,7 @@ export class BlockDragger implements IBlockDragger {
* dragging block would be deleted if released immediately.
*/
protected updateCursorDuringBlockDrag_() {
this.block.setDeleteStyle(this.wouldDeleteBlock_);
this.draggingBlock_.setDeleteStyle(this.wouldDeleteBlock_);
}

/**
Expand All @@ -367,13 +375,13 @@ export class BlockDragger implements IBlockDragger {
*/
protected pixelsToWorkspaceUnits_(pixelCoord: Coordinate): Coordinate {
const result = new Coordinate(
pixelCoord.x / this.workspace.scale,
pixelCoord.y / this.workspace.scale);
if (this.workspace.isMutator) {
pixelCoord.x / this.workspace_.scale,
pixelCoord.y / this.workspace_.scale);
if (this.workspace_.isMutator) {
// If we're in a mutator, its scale is always 1, purely because of some
// oddities in our rendering optimizations. The actual scale is the same
// as the scale on the parent workspace. Fix that for dragging.
const mainScale = this.workspace.options.parentWorkspace!.scale;
const mainScale = this.workspace_.options.parentWorkspace!.scale;
result.scale(1 / mainScale);
}
return result;
Expand Down
20 changes: 12 additions & 8 deletions core/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export class Connection implements IASTNodeLocationWithBlock {
static REASON_DRAG_CHECKS_FAILED = 7;
static REASON_PREVIOUS_AND_OUTPUT = 8;

protected sourceBlock_: Block;

/** Connection this connection connects to. Null if not connected. */
targetConnection: Connection|null = null;

Expand Down Expand Up @@ -86,7 +88,9 @@ export class Connection implements IASTNodeLocationWithBlock {
* @param source The block establishing this connection.
* @param type The type of the connection.
*/
constructor(private readonly source: Block, public type: number) {}
constructor(source: Block, public type: number) {
this.sourceBlock_ = source;
}

/**
* Connect two connections together. This is the connection on the superior
Expand Down Expand Up @@ -171,7 +175,7 @@ export class Connection implements IASTNodeLocationWithBlock {
* @return The source block.
*/
getSourceBlock(): Block {
return this.source;
return this.sourceBlock_;
}

/**
Expand All @@ -198,7 +202,7 @@ export class Connection implements IASTNodeLocationWithBlock {
* @internal
*/
getConnectionChecker(): IConnectionChecker {
return this.source.workspace.connectionChecker;
return this.sourceBlock_.workspace.connectionChecker;
}

/**
Expand Down Expand Up @@ -258,13 +262,13 @@ export class Connection implements IASTNodeLocationWithBlock {
let parentConnection;
if (this.isSuperior()) {
// Superior block.
parentBlock = this.source;
parentBlock = this.sourceBlock_;
childBlock = otherConnection.getSourceBlock();
parentConnection = this;
} else {
// Inferior block.
parentBlock = otherConnection.getSourceBlock();
childBlock = this.source;
childBlock = this.sourceBlock_;
parentConnection = otherConnection;
}

Expand Down Expand Up @@ -333,7 +337,7 @@ export class Connection implements IASTNodeLocationWithBlock {
(!this.targetConnection ||
!this.getConnectionChecker().canConnect(
this, this.targetConnection, false))) {
const child = this.isSuperior() ? this.targetBlock() : this.source;
const child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_;
child!.unplug();
}
}
Expand Down Expand Up @@ -439,7 +443,7 @@ export class Connection implements IASTNodeLocationWithBlock {
*/
getParentInput(): Input|null {
let parentInput = null;
const inputs = this.source.inputList;
const inputs = this.sourceBlock_.inputList;
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].connection === this) {
parentInput = inputs[i];
Expand All @@ -455,7 +459,7 @@ export class Connection implements IASTNodeLocationWithBlock {
* @return The description.
*/
toString(): string {
const block = this.source;
const block = this.sourceBlock_;
if (!block) {
return 'Orphan Connection';
}
Expand Down
14 changes: 9 additions & 5 deletions core/flyout_metrics_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ import {WorkspaceSvg} from './workspace_svg.js';
* @alias Blockly.FlyoutMetricsManager
*/
export class FlyoutMetricsManager extends MetricsManager {
/** The flyout that owns the workspace to calculate metrics for. */
protected flyout_: IFlyout;

/**
* @param workspace The flyout's workspace.
* @param flyout The flyout.
*/
constructor(workspace: WorkspaceSvg, private readonly flyout: IFlyout) {
constructor(workspace: WorkspaceSvg, flyout: IFlyout) {
super(workspace);
this.flyout_ = flyout;
}

/**
Expand All @@ -45,7 +49,7 @@ export class FlyoutMetricsManager extends MetricsManager {
{height: number, y: number, width: number, x: number} {
let blockBoundingBox;
try {
blockBoundingBox = this.workspace.getCanvas().getBBox();
blockBoundingBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
// 2021 Update: It looks like this was fixed around Firefox 77 released in
Expand All @@ -58,7 +62,7 @@ export class FlyoutMetricsManager extends MetricsManager {
override getContentMetrics(opt_getWorkspaceCoordinates: boolean) {
// The bounding box is in workspace coordinates.
const blockBoundingBox = this.getBoundingBox_();
const scale = opt_getWorkspaceCoordinates ? 1 : this.workspace.scale;
const scale = opt_getWorkspaceCoordinates ? 1 : this.workspace_.scale;

return {
height: blockBoundingBox.height * scale,
Expand All @@ -74,8 +78,8 @@ export class FlyoutMetricsManager extends MetricsManager {
// AnyDuringMigration because: Expected 1 arguments, but got 0.
const contentMetrics =
opt_contentMetrics || (this.getContentMetrics as AnyDuringMigration)();
const margin = this.flyout.MARGIN * this.workspace.scale;
const scale = opt_getWorkspaceCoordinates ? this.workspace.scale : 1;
const margin = this.flyout_.MARGIN * this.workspace_.scale;
const scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;

// The left padding isn't just the margin. Some blocks are also offset by
// tabWidth so that value and statement blocks line up.
Expand Down
Loading