Skip to content
Merged
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
52 changes: 4 additions & 48 deletions src/actions/action_menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import {
ASTNode,
Connection,
ContextMenu,
ContextMenuRegistry,
ShortcutRegistry,
Expand All @@ -22,10 +21,6 @@ const createSerializedKey = ShortcutRegistry.registry.createSerializedKey.bind(
ShortcutRegistry.registry,
);

export interface ScopeWithConnection extends ContextMenuRegistry.Scope {
connection?: Connection;
}

/**
* Keyboard shortcut to show the action menu on Cmr/Ctrl/Alt+Enter key.
*/
Expand Down Expand Up @@ -114,10 +109,10 @@ export class ActionMenu {
const connection = node.getLocation() as RenderedConnection;
rtl = connection.getSourceBlock().RTL;

// Slightly hacky: get insert action from registry. Hacky
// because registry typings don't include {connection: ...} as
// a possible kind of scope.
const menuOptions = this.addConnectionItems(connection, menuOpenEvent);
const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions(
{focusedNode: connection},
menuOpenEvent,
);
// If no valid options, don't show a menu
if (!menuOptions?.length) return true;
const location = this.calculateLocationForConnectionMenu(connection);
Expand Down Expand Up @@ -153,45 +148,6 @@ export class ActionMenu {
return true;
}

/**
* Add menu items for a context menu on a connection scope.
*
* @param connection The connection on which the menu is shown.
* @param menuOpenEvent The event that opened this context menu.
*/
private addConnectionItems(connection: Connection, menuOpenEvent: Event) {
const menuOptions: Array<
| ContextMenuRegistry.ContextMenuOption
| ContextMenuRegistry.LegacyContextMenuOption
> = [];
const possibleOptions = [
this.getContextMenuAction('insert'),
this.getContextMenuAction('blockPasteFromContextMenu'),
];

// Check preconditions and get menu texts.
const scope = {
connection,
} as unknown as ContextMenuRegistry.Scope;

for (const option of possibleOptions) {
const precondition = option.preconditionFn?.(scope, menuOpenEvent);
if (precondition === 'hidden') continue;
const displayText =
(typeof option.displayText === 'function'
? option.displayText(scope)
: option.displayText) ?? '';
menuOptions.push({
text: displayText,
enabled: precondition === 'enabled',
callback: option.callback,
scope,
weight: option.weight,
});
}
return menuOptions;
}

/**
* Find a context menu action, throwing an `Error` if it is not present or
* not an action. This usefully narrows the type to `ActionRegistryItem`
Expand Down
21 changes: 15 additions & 6 deletions src/actions/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
import * as Constants from '../constants';
import type {BlockSvg, WorkspaceSvg} from 'blockly';
import {Navigation} from '../navigation';
import {ScopeWithConnection} from './action_menu';
import {getShortActionShortcut} from '../shortcut_formatting';
import * as Blockly from 'blockly';

const KeyCodes = blocklyUtils.KeyCodes;
const createSerializedKey = ShortcutRegistry.registry.createSerializedKey.bind(
Expand Down Expand Up @@ -306,19 +306,28 @@ export class Clipboard {
private registerPasteContextMenuAction() {
const pasteAction: ContextMenuRegistry.RegistryItem = {
displayText: (scope) => `Paste (${getShortActionShortcut('paste')})`,
preconditionFn: (scope: ScopeWithConnection) => {
const block = scope.block ?? scope.connection?.getSourceBlock();
preconditionFn: (scope: ContextMenuRegistry.Scope) => {
let block;
if (scope.focusedNode instanceof Blockly.Block) {
block = scope.focusedNode;
} else if (scope.focusedNode instanceof Blockly.Connection) {
block = scope.focusedNode.getSourceBlock();
}
const ws = block?.workspace as WorkspaceSvg | null;
if (!ws) return 'hidden';
return this.pastePrecondition(ws) ? 'enabled' : 'disabled';
},
callback: (scope: ScopeWithConnection) => {
const block = scope.block ?? scope.connection?.getSourceBlock();
callback: (scope: ContextMenuRegistry.Scope) => {
let block;
if (scope.focusedNode instanceof Blockly.Block) {
block = scope.focusedNode;
} else if (scope.focusedNode instanceof Blockly.Connection) {
block = scope.focusedNode.getSourceBlock();
}
const ws = block?.workspace as WorkspaceSvg | null;
if (!ws) return;
return this.pasteCallback(ws);
},
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
id: 'blockPasteFromContextMenu',
weight: BASE_WEIGHT + 2,
};
Expand Down
19 changes: 12 additions & 7 deletions src/actions/insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
import * as Constants from '../constants';
import type {WorkspaceSvg} from 'blockly';
import {Navigation} from '../navigation';
import {ScopeWithConnection} from './action_menu';

import * as Blockly from 'blockly/core';

const KeyCodes = BlocklyUtils.KeyCodes;

Expand Down Expand Up @@ -70,21 +71,25 @@ export class InsertAction {
displayText: () => {
return 'Insert Block (I)';
},
preconditionFn: (scope: ScopeWithConnection) => {
const block = scope.block ?? scope.connection?.getSourceBlock();
preconditionFn: (scope: ContextMenuRegistry.Scope) => {
let block;
if (scope.focusedNode instanceof Blockly.Block) {
block = scope.focusedNode;
} else if (scope.focusedNode instanceof Blockly.Connection) {
block = scope.focusedNode.getSourceBlock();
}
const ws = block?.workspace as WorkspaceSvg | null;
if (!ws) return 'hidden';

return this.insertPrecondition(ws) ? 'enabled' : 'hidden';
},
callback: (scope: ScopeWithConnection) => {
callback: (scope: ContextMenuRegistry.Scope) => {
const ws =
scope.block?.workspace ??
(scope.connection?.getSourceBlock().workspace as WorkspaceSvg);
scope.focusedNode?.workspace ??
(scope.focusedNode?.getSourceBlock().workspace as WorkspaceSvg);
if (!ws) return false;
this.insertCallback(ws);
},
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
id: 'insert',
weight: 9,
};
Expand Down
4 changes: 2 additions & 2 deletions src/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,8 @@ export class Navigation {
const passiveFocusNode = this.passiveFocusIndicator.getCurNode();
this.passiveFocusIndicator.hide();
const disposed = passiveFocusNode?.getSourceBlock()?.disposed;
// If there's a gesture then it will either set the node if it has not
// been disposed (which can happen when blocks are reloaded) or be a click
// If there's a gesture then it will either set the node if it has not
// been disposed (which can happen when blocks are reloaded) or be a click
// that should not set one.
if (!Blockly.Gesture.inProgress() && passiveFocusNode && !disposed) {
cursor.setCurNode(passiveFocusNode);
Expand Down
Loading