From 41c76ea9ce0dc1f75bf88f197b1ee4e769982df3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 8 Apr 2025 15:29:19 -0700 Subject: [PATCH] fix: Disallow undo/redo during a keyboard-driven move. --- src/actions/undo_redo.ts | 77 ++++++++++++++++++++++++++++++++++++ src/navigation_controller.ts | 5 +++ 2 files changed, 82 insertions(+) create mode 100644 src/actions/undo_redo.ts diff --git a/src/actions/undo_redo.ts b/src/actions/undo_redo.ts new file mode 100644 index 00000000..e43e9b66 --- /dev/null +++ b/src/actions/undo_redo.ts @@ -0,0 +1,77 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + ShortcutRegistry, + utils as BlocklyUtils, + ShortcutItems, + WorkspaceSvg, +} from 'blockly/core'; + +import * as Constants from '../constants'; +import type {Navigation} from '../navigation'; + +const KeyCodes = BlocklyUtils.KeyCodes; + +/** + * Class for registering a shortcut for undo/redo actions. + */ +export class UndoRedoAction { + private originalUndo?: ShortcutRegistry.KeyboardShortcut; + private originalRedo?: ShortcutRegistry.KeyboardShortcut; + /** + * Patches the existing undo/redo shortcuts in the registry. + */ + install() { + const undo = + ShortcutRegistry.registry.getRegistry()[ShortcutItems.names.UNDO]; + if (undo) { + this.originalUndo = undo; + const patchedUndo = { + ...this.originalUndo, + preconditionFn: (workspace: WorkspaceSvg) => { + return !!( + !workspace.isDragging() && undo.preconditionFn?.(workspace) + ); + }, + allowCollision: true, + }; + + ShortcutRegistry.registry.register(patchedUndo, true); + } + + const redo = + ShortcutRegistry.registry.getRegistry()[ShortcutItems.names.REDO]; + if (redo) { + this.originalRedo = redo; + const patchedRedo = { + ...this.originalRedo, + preconditionFn: (workspace: WorkspaceSvg) => { + return !!( + !workspace.isDragging() && redo.preconditionFn?.(workspace) + ); + }, + allowCollision: true, + }; + + ShortcutRegistry.registry.register(patchedRedo, true); + } + } + + /** + * Reverts the patched undo/redo shortcuts in the registry. + */ + uninstall() { + if (this.originalUndo) { + ShortcutRegistry.registry.register(this.originalUndo, true); + this.originalUndo = undefined; + } + if (this.originalRedo) { + ShortcutRegistry.registry.register(this.originalRedo, true); + this.originalRedo = undefined; + } + } +} diff --git a/src/navigation_controller.ts b/src/navigation_controller.ts index f64b247b..462ee2d9 100644 --- a/src/navigation_controller.ts +++ b/src/navigation_controller.ts @@ -36,6 +36,7 @@ import {DisconnectAction} from './actions/disconnect'; import {ActionMenu} from './actions/action_menu'; import {MoveActions} from './actions/move'; import {Mover} from './actions/mover'; +import {UndoRedoAction} from './actions/undo_redo'; const KeyCodes = BlocklyUtils.KeyCodes; @@ -72,6 +73,8 @@ export class NavigationController { enterAction: EnterAction = new EnterAction(this.navigation); + undoRedoAction: UndoRedoAction = new UndoRedoAction(); + actionMenu: ActionMenu = new ActionMenu(this.navigation); moveActions = new MoveActions(this.mover); @@ -289,6 +292,7 @@ export class NavigationController { this.exitAction.install(); this.enterAction.install(); this.disconnectAction.install(); + this.undoRedoAction.install(); this.actionMenu.install(); this.clipboard.install(); @@ -315,6 +319,7 @@ export class NavigationController { this.arrowNavigation.uninstall(); this.exitAction.uninstall(); this.enterAction.uninstall(); + this.undoRedoAction.uninstall(); this.actionMenu.uninstall(); this.shortcutDialog.uninstall();