diff --git a/packages/blockly/core/dragging/block_drag_strategy.ts b/packages/blockly/core/dragging/block_drag_strategy.ts index 2e6dd476bc5..3494a9642ca 100644 --- a/packages/blockly/core/dragging/block_drag_strategy.ts +++ b/packages/blockly/core/dragging/block_drag_strategy.ts @@ -347,11 +347,16 @@ export class BlockDragStrategy implements IDragStrategy { // Enable all blocks including children. this.enableAllDraggedBlocks(this.block); + // Cached connection pairs are primarily used for keyboard-driven moves, + // but they are also needed in order to determine whether announcement text + // must disambiguate between multiple compatible connections. This is a + // relatively expensive operation, so we only do it once at the start of + // the drag. + this.cacheAllConnectionPairs(); + // For keyboard-driven moves, cache a list of valid connection points for // use in constrained moved mode. if (e instanceof KeyboardEvent) { - this.cacheAllConnectionPairs(); - // Scooch the block to be offset from the connection preview indicator. const neighbour = this.updateConnectionPreview( this.block, @@ -380,10 +385,13 @@ export class BlockDragStrategy implements IDragStrategy { } /** - * Handles any setup for starting the drag, including disconnecting the block - * from any parent blocks. + * Caches a list of all valid connection pairs between the dragging block + * and any other blocks on the workspace. This is used to determine the + * closest valid connection during keyboard-driven moves and to determine + * the need to disambiguate between multiple compatible connections when + * announcing moves to assistive technologies. */ - private cacheAllConnectionPairs() { + cacheAllConnectionPairs() { const connectionChecker = this.block.workspace.connectionChecker; const workspaceConns = []; this.allConnectionPairs = []; diff --git a/packages/blockly/tests/mocha/keyboard_movement_test.js b/packages/blockly/tests/mocha/keyboard_movement_test.js index 43022ed6c56..bc416d966a4 100644 --- a/packages/blockly/tests/mocha/keyboard_movement_test.js +++ b/packages/blockly/tests/mocha/keyboard_movement_test.js @@ -1146,6 +1146,66 @@ suite('Keyboard-driven movement', function () { EXPECTED_SIMPLE_LEFT, ), ); + suite('Recaching after inputs change mid-move', function () { + setup(function () { + this.mover = this.workspace.getBlockById(VALUE_SIMPLE.id); + this.join = this.workspace.getBlockById('join0'); + this.strategy = this.mover.getDragStrategy(); + + Blockly.getFocusManager().focusNode(this.mover); + startMove(this.workspace); + + // Snapshot the start-of-drag cache before the block grows. + this.originalPairs = [...this.strategy.allConnectionPairs]; + + this.join.appendValueInput('ADD2'); + this.newConnection = this.join.getInput('ADD2').connection; + }); + + teardown(function () { + if (Blockly.KeyboardMover.mover.isMoving()) { + cancelMove(this.workspace); + } + }); + + test('the original cache excludes the new connection', function () { + assert.isFalse( + this.originalPairs.some( + (pair) => pair.neighbour === this.newConnection, + ), + ); + }); + + test('the refreshed cache includes the new connection', function () { + this.strategy.cacheAllConnectionPairs(); + + assert.isTrue( + this.strategy.allConnectionPairs.some( + (pair) => pair.neighbour === this.newConnection, + ), + ); + }); + + test('traverses to the new connection in order after recaching', function () { + this.strategy.cacheAllConnectionPairs(); + + moveRight(this.workspace); + console.log(getConnectionCandidate()); + assert.deepEqual(getConnectionCandidate(), { + id: 'join0', + index: 2, + ownIndex: 0, + }); + + moveRight(this.workspace); + console.log(getConnectionCandidate()); + assert.deepEqual(getConnectionCandidate(), { + id: 'join0', + index: 3, + ownIndex: 0, + }); + }); + }); }); suite('Constrained moves of row of value blocks', function () {