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
18 changes: 13 additions & 5 deletions core/block_svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,22 @@ export class BlockSvg
(newParent as BlockSvg).getSvgRoot().appendChild(svgRoot);
} else if (oldParent) {
// If we are losing a parent, we want to move our DOM element to the
// root of the workspace.
const draggingBlock = this.workspace
// root of the workspace. Try to insert it before any top-level
// block being dragged, but note that blocks can have the
// blocklyDragging class even if they're not top blocks (especially
// at start and end of a drag).
const draggingBlockElement = this.workspace
.getCanvas()
.querySelector('.blocklyDragging');
if (draggingBlock) {
this.workspace.getCanvas().insertBefore(svgRoot, draggingBlock);
const draggingParentElement = draggingBlockElement?.parentElement as
| SVGElement
| null
| undefined;
const canvas = this.workspace.getCanvas();
if (draggingParentElement === canvas) {
canvas.insertBefore(svgRoot, draggingBlockElement);
} else {
this.workspace.getCanvas().appendChild(svgRoot);
canvas.appendChild(svgRoot);
}
this.translate(oldXY.x, oldXY.y);
}
Expand Down
18 changes: 9 additions & 9 deletions core/dragging/block_drag_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export class BlockDragStrategy implements IDragStrategy {
const currCandidate = this.connectionCandidate;
const newCandidate = this.getConnectionCandidate(draggingBlock, delta);
if (!newCandidate) {
this.connectionPreviewer!.hidePreview();
this.connectionPreviewer?.hidePreview();
this.connectionCandidate = null;
return;
}
Expand All @@ -254,7 +254,7 @@ export class BlockDragStrategy implements IDragStrategy {
local.type === ConnectionType.OUTPUT_VALUE ||
local.type === ConnectionType.PREVIOUS_STATEMENT;
const neighbourIsConnectedToRealBlock =
neighbour.isConnected() && !neighbour.targetBlock()!.isInsertionMarker();
neighbour.isConnected() && !neighbour.targetBlock()?.isInsertionMarker();
if (
localIsOutputOrPrevious &&
neighbourIsConnectedToRealBlock &&
Expand All @@ -264,14 +264,14 @@ export class BlockDragStrategy implements IDragStrategy {
local.type,
)
) {
this.connectionPreviewer!.previewReplacement(
this.connectionPreviewer?.previewReplacement(
local,
neighbour,
neighbour.targetBlock()!,
);
return;
}
this.connectionPreviewer!.previewConnection(local, neighbour);
this.connectionPreviewer?.previewConnection(local, neighbour);
}

/**
Expand Down Expand Up @@ -385,7 +385,7 @@ export class BlockDragStrategy implements IDragStrategy {
dom.stopTextWidthCache();

blockAnimation.disconnectUiStop();
this.connectionPreviewer!.hidePreview();
this.connectionPreviewer?.hidePreview();

if (!this.block.isDeadOrDying() && this.dragging) {
// These are expensive and don't need to be done if we're deleting, or
Expand Down Expand Up @@ -413,7 +413,7 @@ export class BlockDragStrategy implements IDragStrategy {

// Must dispose after connections are applied to not break the dynamic
// connections plugin. See #7859
this.connectionPreviewer!.dispose();
this.connectionPreviewer?.dispose();
this.workspace.setResizesEnabled(true);
eventUtils.setGroup(newGroup);
}
Expand Down Expand Up @@ -445,6 +445,9 @@ export class BlockDragStrategy implements IDragStrategy {
return;
}

this.connectionPreviewer?.hidePreview();
this.connectionCandidate = null;

this.startChildConn?.connect(this.block.nextConnection);
if (this.startParentConn) {
switch (this.startParentConn.type) {
Expand All @@ -471,9 +474,6 @@ export class BlockDragStrategy implements IDragStrategy {
this.startChildConn = null;
this.startParentConn = null;

this.connectionPreviewer!.hidePreview();
this.connectionCandidate = null;

this.block.setDragging(false);
this.dragging = false;
}
Expand Down
37 changes: 37 additions & 0 deletions tests/mocha/block_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,18 @@ suite('Blocks', function () {
);
this.textJoinBlock = this.printBlock.getInputTargetBlock('TEXT');
this.textBlock = this.textJoinBlock.getInputTargetBlock('ADD0');
this.extraTopBlock = Blockly.Xml.domToBlock(
Blockly.utils.xml.textToDom(`
<block type="text_print">
<value name="TEXT">
<block type="text">
<field name="TEXT">drag me</field>
</block>
</value>
</block>`),
this.workspace,
);
this.extraNestedBlock = this.extraTopBlock.getInputTargetBlock('TEXT');
});

function assertBlockIsOnlyChild(parent, child, inputName) {
Expand All @@ -1116,6 +1128,10 @@ suite('Blocks', function () {
assert.equal(nonParent.getChildren().length, 0);
assert.isNull(nonParent.getInputTargetBlock('TEXT'));
assert.isNull(orphan.getParent());
assert.equal(
orphan.getSvgRoot().parentElement,
orphan.workspace.getCanvas(),
);
}
function assertOriginalSetup() {
assertBlockIsOnlyChild(this.printBlock, this.textJoinBlock, 'TEXT');
Expand Down Expand Up @@ -1187,6 +1203,27 @@ suite('Blocks', function () {
);
assertNonParentAndOrphan(this.textJoinBlock, this.textBlock, 'ADD0');
});
test('Setting parent to null with dragging block', function () {
this.extraTopBlock.setDragging(true);
this.textBlock.outputConnection.disconnect();
assert.doesNotThrow(
this.textBlock.setParent.bind(this.textBlock, null),
);
assertNonParentAndOrphan(this.textJoinBlock, this.textBlock, 'ADD0');
assert.equal(
this.textBlock.getSvgRoot().nextSibling,
this.extraTopBlock.getSvgRoot(),
);
});
test('Setting parent to null with non-top dragging block', function () {
this.extraNestedBlock.setDragging(true);
this.textBlock.outputConnection.disconnect();
assert.doesNotThrow(
this.textBlock.setParent.bind(this.textBlock, null),
);
assertNonParentAndOrphan(this.textJoinBlock, this.textBlock, 'ADD0');
assert.equal(this.textBlock.getSvgRoot().nextSibling, null);
});
test('Setting parent to null without disconnecting', function () {
assert.throws(this.textBlock.setParent.bind(this.textBlock, null));
assertOriginalSetup.call(this);
Expand Down