From 0a0bc472458d1e5360090a7fa910e80d3bf9c1fe Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 29 May 2025 09:52:01 -0700 Subject: [PATCH 1/2] feat: Commit moves before running keyboard shortcuts. --- src/actions/mover.ts | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/actions/mover.ts b/src/actions/mover.ts index 488fd8dd..3d4bf890 100644 --- a/src/actions/mover.ts +++ b/src/actions/mover.ts @@ -18,6 +18,7 @@ import { registry, utils, WorkspaceSvg, + ShortcutRegistry, } from 'blockly'; import * as Constants from '../constants'; import {Direction, getXYFromDirection} from '../drag_direction'; @@ -36,6 +37,11 @@ const UNCONSTRAINED_MOVE_DISTANCE = 20; */ const CONSTRAINED_ADDITIONAL_PADDING = 70; +/** + * Identifier for a keyboard shortcut that commits the in-progress move. + */ +const COMMIT_MOVE_SHORTCUT = 'commitMove'; + /** * Low-level code for moving blocks with keyboard shortcuts. */ @@ -140,6 +146,47 @@ export class Mover { // (otherwise dragging will break). getFocusManager().focusNode(block); block.getFocusableElement().addEventListener('blur', blurListener); + + // Register a keyboard shortcut under the key combos of all existing + // keyboard shortcuts that commits the move before allowing the real + // shortcut to proceed. This avoids all kinds of fun brokenness when + // deleting/copying/otherwise acting on a block in move mode. + const shortcutKeys = Object.values(ShortcutRegistry.registry.getRegistry()) + .flatMap((shortcut) => shortcut.keyCodes) + .filter((keyCode) => { + return ( + keyCode && + ![ + utils.KeyCodes.RIGHT, + utils.KeyCodes.LEFT, + utils.KeyCodes.UP, + utils.KeyCodes.DOWN, + utils.KeyCodes.ENTER, + ].includes( + typeof keyCode === 'number' + ? keyCode + : parseInt(`${keyCode.split('+').pop()}`), + ) + ); + }) + // Convince TS there aren't undefined values. + .filter((keyCode): keyCode is string | number => !!keyCode); + + const commitMoveShortcut = { + name: COMMIT_MOVE_SHORTCUT, + preconditionFn: (workspace: WorkspaceSvg) => { + return !!this.moves.get(workspace); + }, + callback: (workspace: WorkspaceSvg) => { + this.finishMove(workspace); + return false; + }, + keyCodes: shortcutKeys, + allowCollision: true, + }; + + ShortcutRegistry.registry.register(commitMoveShortcut); + return true; } @@ -152,6 +199,8 @@ export class Mover { * @returns True iff move successfully finished. */ finishMove(workspace: WorkspaceSvg) { + ShortcutRegistry.registry.unregister(COMMIT_MOVE_SHORTCUT); + clearMoveHints(workspace); const info = this.moves.get(workspace); From b5029682e5d7ccd0241e9248e2f38fe1e0180cdd Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 29 May 2025 10:55:44 -0700 Subject: [PATCH 2/2] fix: Handle aborting moves. --- src/actions/mover.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/actions/mover.ts b/src/actions/mover.ts index 3d4bf890..4e78b87f 100644 --- a/src/actions/mover.ts +++ b/src/actions/mover.ts @@ -162,6 +162,7 @@ export class Mover { utils.KeyCodes.UP, utils.KeyCodes.DOWN, utils.KeyCodes.ENTER, + utils.KeyCodes.ESC, ].includes( typeof keyCode === 'number' ? keyCode @@ -235,6 +236,7 @@ export class Mover { * @returns True iff move successfully aborted. */ abortMove(workspace: WorkspaceSvg) { + ShortcutRegistry.registry.unregister(COMMIT_MOVE_SHORTCUT); clearMoveHints(workspace); const info = this.moves.get(workspace);