mirror of
https://github.com/google/blockly.git
synced 2026-06-02 09:20:06 +02:00
feat: Enable blocks during drags (#9935)
* feat: Enable disabled blocks while dragging * test: Add tests
This commit is contained in:
@@ -92,6 +92,12 @@ export class BlockDragStrategy implements IDragStrategy {
|
||||
/** Used to persist an event group when snapping is done async. */
|
||||
private originalEventGroup = '';
|
||||
|
||||
/**
|
||||
* Map from block IDs to reason(s) why it was disabled, used to restore
|
||||
* disabled state post-drag.
|
||||
*/
|
||||
private lastBlockDisabledReasons: Map<string, Set<string>> = new Map();
|
||||
|
||||
protected readonly BLOCK_CONNECTION_OFFSET = 10;
|
||||
|
||||
/**
|
||||
@@ -338,6 +344,9 @@ export class BlockDragStrategy implements IDragStrategy {
|
||||
|
||||
this.block.setDragging(true);
|
||||
|
||||
// Enable all blocks including children.
|
||||
this.enableAllDraggedBlocks(this.block);
|
||||
|
||||
// For keyboard-driven moves, cache a list of valid connection points for
|
||||
// use in constrained moved mode.
|
||||
if (e instanceof KeyboardEvent) {
|
||||
@@ -885,6 +894,9 @@ export class BlockDragStrategy implements IDragStrategy {
|
||||
);
|
||||
|
||||
this.block.setDragging(false);
|
||||
|
||||
// Re-disable the block for its original reasons.
|
||||
this.redisableAllDraggedBlocks(this.block);
|
||||
}
|
||||
|
||||
if (this.connectionCandidate) {
|
||||
@@ -979,6 +991,8 @@ export class BlockDragStrategy implements IDragStrategy {
|
||||
this.startParentConn = null;
|
||||
|
||||
this.block.setDragging(false);
|
||||
// Re-disable the block for its original reasons.
|
||||
this.redisableAllDraggedBlocks(this.block);
|
||||
this.dragging = false;
|
||||
aria.announceDynamicAriaState(Msg['ANNOUNCE_MOVE_CANCELED']);
|
||||
}
|
||||
@@ -1236,4 +1250,41 @@ export class BlockDragStrategy implements IDragStrategy {
|
||||
? MoveMode.CONSTRAINED
|
||||
: MoveMode.UNCONSTRAINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the given block and its children.
|
||||
* Stores the reasons each block was disabled so they can be restored.
|
||||
*
|
||||
* @param block The block to enable.
|
||||
*/
|
||||
private enableAllDraggedBlocks(block: BlockSvg) {
|
||||
const oldUndo = eventUtils.getRecordUndo();
|
||||
eventUtils.setRecordUndo(false);
|
||||
this.lastBlockDisabledReasons.clear();
|
||||
// getDescendants includes the block itself.
|
||||
block.getDescendants(false).forEach((descendant) => {
|
||||
const reasons = new Set(descendant.getDisabledReasons());
|
||||
this.lastBlockDisabledReasons.set(descendant.id, reasons);
|
||||
reasons.forEach((reason) => descendant.setDisabledReason(false, reason));
|
||||
});
|
||||
eventUtils.setRecordUndo(oldUndo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-disables the given block and its children using their original
|
||||
* disabled reasons.
|
||||
*
|
||||
* @param block The block to re-disable, if applicable.
|
||||
*/
|
||||
private redisableAllDraggedBlocks(block: BlockSvg) {
|
||||
console.log('redisable');
|
||||
const oldUndo = eventUtils.getRecordUndo();
|
||||
eventUtils.setRecordUndo(false);
|
||||
block.getDescendants(false).forEach((descendant) => {
|
||||
this.lastBlockDisabledReasons.get(descendant.id)?.forEach((reason) => {
|
||||
descendant.setDisabledReason(true, reason);
|
||||
});
|
||||
});
|
||||
eventUtils.setRecordUndo(oldUndo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,6 +733,52 @@ suite('Keyboard-driven movement', function () {
|
||||
cancelMove(this.workspace);
|
||||
});
|
||||
|
||||
test('Enables disabled blocks during drag and reenables when committed', function () {
|
||||
const ifBlock = this.workspace.newBlock('controls_if');
|
||||
const repeatBlock = this.workspace.newBlock('controls_repeat');
|
||||
ifBlock.initSvg();
|
||||
ifBlock.render();
|
||||
repeatBlock.initSvg();
|
||||
repeatBlock.render();
|
||||
repeatBlock.previousConnection.connect(
|
||||
ifBlock.getInput('DO0').connection,
|
||||
);
|
||||
|
||||
ifBlock.setDisabledReason(true, 'test');
|
||||
assert.isFalse(ifBlock.isEnabled());
|
||||
|
||||
Blockly.getFocusManager().focusNode(ifBlock);
|
||||
startMove(this.workspace);
|
||||
|
||||
assert.isTrue(ifBlock.isEnabled());
|
||||
|
||||
endMove(this.workspace);
|
||||
assert.isFalse(ifBlock.isEnabled());
|
||||
});
|
||||
|
||||
test('Enables disabled blocks during drag and reenables when cancelled', function () {
|
||||
const ifBlock = this.workspace.newBlock('controls_if');
|
||||
const repeatBlock = this.workspace.newBlock('controls_repeat');
|
||||
ifBlock.initSvg();
|
||||
ifBlock.render();
|
||||
repeatBlock.initSvg();
|
||||
repeatBlock.render();
|
||||
repeatBlock.previousConnection.connect(
|
||||
ifBlock.getInput('DO0').connection,
|
||||
);
|
||||
|
||||
ifBlock.setDisabledReason(true, 'test');
|
||||
assert.isFalse(ifBlock.isEnabled());
|
||||
|
||||
Blockly.getFocusManager().focusNode(ifBlock);
|
||||
startMove(this.workspace);
|
||||
|
||||
assert.isTrue(ifBlock.isEnabled());
|
||||
|
||||
cancelMove(this.workspace);
|
||||
assert.isFalse(ifBlock.isEnabled());
|
||||
});
|
||||
|
||||
suite('Statement move tests', function () {
|
||||
// Clear the workspace and load start blocks.
|
||||
setup(function () {
|
||||
|
||||
Reference in New Issue
Block a user