Skip to content
Closed
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
83 changes: 83 additions & 0 deletions src/actions/stack_navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {
ShortcutRegistry,
WorkspaceSvg,
getFocusManager,
utils,
} from 'blockly/core';
import {KeyboardShortcut} from 'node_modules/blockly/core/shortcut_registry';

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import has gone weird


const SHORTCUT_PREV_STACK = utils.KeyCodes.P;
const SHORTCUT_NEXT_STACK = utils.KeyCodes.N;

/**
* Class for registering a shortcut for quick movement between root blocks.
*/
export class StackNavigationAction {
stackShortcuts: KeyboardShortcut[] = [];
install() {
const preconditionFn = (workspace: WorkspaceSvg) => {
const currentRoot = workspace
?.getCursor()
?.getSourceBlock()
?.getRootBlock();
return !!currentRoot;
};

const previousStackShortcut: KeyboardShortcut = {
name: 'go_to_previous_stack',
preconditionFn,
callback: (workspace) => {
const currentRoot = workspace
?.getCursor()
?.getSourceBlock()
?.getRootBlock();
if (!currentRoot) return false;
const prevRoot = workspace
.getNavigator()
.getPreviousSibling(currentRoot);
if (!prevRoot) return false;
getFocusManager().focusNode(prevRoot);
return true;
},
keyCodes: [SHORTCUT_PREV_STACK],
};

const nextStackShortcut: KeyboardShortcut = {
name: 'go_to_next_stack',
preconditionFn,
callback: (workspace) => {
const currentRoot = workspace
?.getCursor()
?.getSourceBlock()
?.getRootBlock();
if (!currentRoot) return false;
const nextRoot = workspace.getNavigator().getNextSibling(currentRoot);
if (!nextRoot) return false;
getFocusManager().focusNode(nextRoot);
return true;
},
keyCodes: [SHORTCUT_NEXT_STACK],
};

ShortcutRegistry.registry.register(previousStackShortcut);
this.stackShortcuts.push(previousStackShortcut);
ShortcutRegistry.registry.register(nextStackShortcut);
this.stackShortcuts.push(nextStackShortcut);
}

/**
* Reverts the patched undo/redo shortcuts in the registry.
*/
uninstall() {
this.stackShortcuts.forEach((ss) =>
ShortcutRegistry.registry.unregister(ss.name),
);
this.stackShortcuts = [];
}
}
5 changes: 5 additions & 0 deletions src/navigation_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {ActionMenu} from './actions/action_menu';
import {MoveActions} from './actions/move';
import {Mover} from './actions/mover';
import {UndoRedoAction} from './actions/undo_redo';
import {StackNavigationAction} from './actions/stack_navigation';

const KeyCodes = BlocklyUtils.KeyCodes;

Expand Down Expand Up @@ -75,6 +76,8 @@ export class NavigationController {

moveActions = new MoveActions(this.mover);

stackNavigationAction: StackNavigationAction = new StackNavigationAction();

/**
* Original Toolbox.prototype.onShortcut method, saved by
* addShortcutHandlers.
Expand Down Expand Up @@ -250,6 +253,7 @@ export class NavigationController {
this.clipboard.install();
this.moveActions.install();
this.shortcutDialog.install();
this.stackNavigationAction.install();

// Initialize the shortcut modal with available shortcuts. Needs
// to be done separately rather at construction, as many shortcuts
Expand All @@ -273,6 +277,7 @@ export class NavigationController {
this.undoRedoAction.uninstall();
this.actionMenu.uninstall();
this.shortcutDialog.uninstall();
this.stackNavigationAction.uninstall();

for (const shortcut of Object.values(this.shortcuts)) {
ShortcutRegistry.registry.unregister(shortcut.name);
Expand Down