Skip to content

Commit 44af6c4

Browse files
authored
refactor: Update to use INavigable instead of ASTNode. (#491)
* chore: Disable the workspace cursor. * refactor: Use INavigable instead of ASTNode. * fix: Partially fix tests. * fix: Fix build error from `Marker.hide()` removal.
1 parent 1f10d7d commit 44af6c4

File tree

13 files changed

+182
-311
lines changed

13 files changed

+182
-311
lines changed

src/actions/action_menu.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const createSerializedKey = ShortcutRegistry.registry.createSerializedKey.bind(
1515
);
1616

1717
/**
18-
* Keyboard shortcut to show the action menu on Cmr/Ctrl/Alt+Enter key.
18+
* Keyboard shortcut to show the action menu on Cmd/Ctrl/Alt+Enter key.
1919
*/
2020
export class ActionMenu {
2121
/**
@@ -86,14 +86,13 @@ export class ActionMenu {
8686
const node = cursor.getCurNode();
8787
if (!node) return false;
8888
// TODO(google/blockly#8847): Add typeguard for IContextMenu in core when this moves over
89-
const location = node.getLocation();
9089
if (
91-
'showContextMenu' in location &&
92-
typeof location.showContextMenu === 'function'
90+
'showContextMenu' in node &&
91+
typeof node.showContextMenu === 'function'
9392
) {
94-
location.showContextMenu(menuOpenEvent);
93+
node.showContextMenu(menuOpenEvent);
9594
} else {
96-
console.info(`No action menu for ASTNode of type ${node.getType()}`);
95+
console.info(`No action menu for node ${node}`);
9796
return false;
9897
}
9998

src/actions/arrow_navigation.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
import {ASTNode, ShortcutRegistry, utils as BlocklyUtils} from 'blockly/core';
7+
import {ShortcutRegistry, utils as BlocklyUtils, Field} from 'blockly/core';
88

9-
import type {Field, Toolbox, WorkspaceSvg} from 'blockly/core';
9+
import type {Toolbox, WorkspaceSvg} from 'blockly/core';
1010

1111
import * as Blockly from 'blockly/core';
1212
import * as Constants from '../constants';
@@ -38,8 +38,8 @@ export class ArrowNavigation {
3838
return false;
3939
}
4040
const curNode = cursor.getCurNode();
41-
if (curNode?.getType() === ASTNode.types.FIELD) {
42-
return (curNode.getLocation() as Field).onShortcut(shortcut);
41+
if (curNode instanceof Field) {
42+
return curNode.onShortcut(shortcut);
4343
}
4444
return false;
4545
}

src/actions/clipboard.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {
1313
clipboard,
1414
ICopyData,
1515
LineCursor,
16+
FocusableTreeTraverser,
1617
getFocusManager,
1718
} from 'blockly';
1819
import * as Constants from '../constants';
19-
import type {BlockSvg, WorkspaceSvg} from 'blockly';
20+
import type {BlockSvg, WorkspaceSvg, INavigable} from 'blockly';
2021
import {Navigation} from '../navigation';
2122
import {getShortActionShortcut} from '../shortcut_formatting';
2223
import * as Blockly from 'blockly';
@@ -134,17 +135,15 @@ export class Clipboard {
134135
*/
135136
private cutPrecondition(workspace: WorkspaceSvg) {
136137
if (this.navigation.canCurrentlyEdit(workspace)) {
137-
const curNode = workspace.getCursor()?.getCurNode();
138-
if (curNode && curNode.getSourceBlock()) {
139-
const sourceBlock = curNode.getSourceBlock();
140-
return !!(
141-
!Gesture.inProgress() &&
142-
sourceBlock &&
143-
sourceBlock.isDeletable() &&
144-
sourceBlock.isMovable() &&
145-
!sourceBlock.workspace.isFlyout
146-
);
147-
}
138+
const sourceBlock = workspace.getCursor()?.getSourceBlock();
139+
140+
return !!(
141+
!Gesture.inProgress() &&
142+
sourceBlock &&
143+
sourceBlock.isDeletable() &&
144+
sourceBlock.isMovable() &&
145+
!sourceBlock.workspace.isFlyout
146+
);
148147
}
149148
return false;
150149
}
@@ -161,9 +160,7 @@ export class Clipboard {
161160
private cutCallback(workspace: WorkspaceSvg) {
162161
const cursor = workspace.getCursor();
163162
if (!cursor) throw new TypeError('no cursor');
164-
const sourceBlock = cursor
165-
.getCurNode()
166-
?.getSourceBlock() as BlockSvg | null;
163+
const sourceBlock = cursor.getSourceBlock();
167164
if (!sourceBlock) throw new TypeError('no source block');
168165
this.copyData = sourceBlock.toCopyData();
169166
this.copyWorkspace = sourceBlock.workspace;
@@ -235,8 +232,7 @@ export class Clipboard {
235232
if (!this.navigation.canCurrentlyEdit(workspace)) return false;
236233
switch (this.navigation.getState(workspace)) {
237234
case Constants.STATE.WORKSPACE: {
238-
const curNode = workspace?.getCursor()?.getCurNode();
239-
const source = curNode?.getSourceBlock();
235+
const source = workspace?.getCursor()?.getSourceBlock();
240236
return !!(
241237
source?.isDeletable() &&
242238
source?.isMovable() &&
@@ -245,10 +241,7 @@ export class Clipboard {
245241
}
246242
case Constants.STATE.FLYOUT: {
247243
const flyoutWorkspace = workspace.getFlyout()?.getWorkspace();
248-
const sourceBlock = flyoutWorkspace
249-
?.getCursor()
250-
?.getCurNode()
251-
?.getSourceBlock();
244+
const sourceBlock = flyoutWorkspace?.getCursor()?.getSourceBlock();
252245
return !!(sourceBlock && !Gesture.inProgress());
253246
}
254247
default:
@@ -271,10 +264,7 @@ export class Clipboard {
271264
if (navigationState === Constants.STATE.FLYOUT) {
272265
activeWorkspace = workspace.getFlyout()?.getWorkspace();
273266
}
274-
const sourceBlock = activeWorkspace
275-
?.getCursor()
276-
?.getCurNode()
277-
?.getSourceBlock() as BlockSvg;
267+
const sourceBlock = activeWorkspace?.getCursor()?.getSourceBlock();
278268
if (!sourceBlock) return false;
279269

280270
this.copyData = sourceBlock.toCopyData();
@@ -376,7 +366,9 @@ export class Clipboard {
376366
? workspace
377367
: this.copyWorkspace;
378368

379-
const targetNode = this.navigation.getFocusedASTNode(pasteWorkspace);
369+
const targetNode = FocusableTreeTraverser.findFocusedNode(
370+
pasteWorkspace,
371+
) as unknown as INavigable<any>;
380372
// If we're pasting in the flyout it still targets the workspace. Focus
381373
// first as to ensure correct selection handling.
382374
getFocusManager().focusTree(workspace);

src/actions/delete.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class DeleteAction {
155155
* @returns True iff `deleteCallback` function should be called.
156156
*/
157157
private deletePrecondition(workspace: WorkspaceSvg) {
158-
const sourceBlock = workspace.getCursor()?.getCurNode()?.getSourceBlock();
158+
const sourceBlock = workspace.getCursor()?.getSourceBlock();
159159
return (
160160
!workspace.isDragging() &&
161161
this.navigation.canCurrentlyEdit(workspace) &&
@@ -178,9 +178,7 @@ export class DeleteAction {
178178
const cursor = workspace.getCursor();
179179
if (!cursor) return false;
180180

181-
const sourceBlock = cursor
182-
.getCurNode()
183-
?.getSourceBlock() as BlockSvg | null;
181+
const sourceBlock = cursor.getSourceBlock();
184182
if (!sourceBlock) return false;
185183
// Delete or backspace.
186184
// There is an event if this is triggered from a keyboard shortcut,

src/actions/disconnect.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
*/
66

77
import {
8-
ASTNode,
98
BlockSvg,
109
RenderedConnection,
1110
ShortcutRegistry,
1211
utils as BlocklyUtils,
1312
} from 'blockly';
1413
import * as Constants from '../constants';
15-
import type {WorkspaceSvg} from 'blockly';
14+
import type {WorkspaceSvg, INavigable} from 'blockly';
1615
import {Navigation} from '../navigation';
1716

1817
const KeyCodes = BlocklyUtils.KeyCodes;
@@ -80,45 +79,46 @@ export class DisconnectAction {
8079
if (!cursor) {
8180
return;
8281
}
83-
let curNode: ASTNode | null = cursor.getCurNode();
82+
let curNode: INavigable<any> | null = cursor.getCurNode();
8483
let wasVisitingConnection = true;
85-
while (curNode && !curNode.isConnection()) {
86-
const location = curNode.getLocation();
87-
if (location instanceof BlockSvg) {
88-
const previous = location.previousConnection;
89-
const output = location.outputConnection;
84+
while (
85+
curNode &&
86+
!(curNode instanceof RenderedConnection && curNode.isConnected())
87+
) {
88+
if (curNode instanceof BlockSvg) {
89+
const previous = curNode.previousConnection;
90+
const output = curNode.outputConnection;
9091
if (previous?.isConnected()) {
91-
curNode = ASTNode.createConnectionNode(previous);
92+
curNode = previous;
9293
break;
9394
} else if (output?.isConnected()) {
94-
curNode = ASTNode.createConnectionNode(output);
95+
curNode = output;
9596
break;
9697
}
9798
}
9899

99-
curNode = curNode.out();
100+
curNode = workspace.getNavigator().getParent(curNode);
100101
wasVisitingConnection = false;
101102
}
102103
if (!curNode) {
103104
console.log('Unable to find a connection to disconnect');
104105
return;
105106
}
106-
const curConnection = curNode.getLocation() as RenderedConnection;
107-
if (!curConnection.isConnected()) {
107+
if (!(curNode instanceof RenderedConnection && curNode.isConnected())) {
108108
return;
109109
}
110-
const targetConnection = curConnection.targetConnection;
110+
const targetConnection = curNode.targetConnection;
111111
if (!targetConnection) {
112112
throw new Error('Must have target if connected');
113113
}
114114

115-
const superiorConnection = curConnection.isSuperior()
116-
? curConnection
115+
const superiorConnection = curNode.isSuperior()
116+
? curNode
117117
: targetConnection;
118118

119-
const inferiorConnection = curConnection.isSuperior()
119+
const inferiorConnection = curNode.isSuperior()
120120
? targetConnection
121-
: curConnection;
121+
: curNode;
122122

123123
if (inferiorConnection.getSourceBlock().isShadow()) {
124124
return;
@@ -135,8 +135,7 @@ export class DisconnectAction {
135135
rootBlock.bringToFront();
136136

137137
if (wasVisitingConnection) {
138-
const connectionNode = ASTNode.createConnectionNode(superiorConnection);
139-
workspace.getCursor()?.setCurNode(connectionNode);
138+
workspace.getCursor()?.setCurNode(superiorConnection);
140139
}
141140
}
142141
}

src/actions/enter.ts

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,20 @@
55
*/
66

77
import {
8-
ASTNode,
98
Events,
109
ShortcutRegistry,
1110
utils as BlocklyUtils,
1211
getFocusManager,
13-
} from 'blockly/core';
14-
15-
import type {
16-
Block,
1712
BlockSvg,
18-
Field,
1913
FlyoutButton,
14+
RenderedConnection,
2015
WorkspaceSvg,
16+
Field,
17+
FocusableTreeTraverser,
2118
} from 'blockly/core';
2219

20+
import type {Block, INavigable} from 'blockly/core';
21+
2322
import * as Constants from '../constants';
2423
import type {Navigation} from '../navigation';
2524
import {Mover} from './mover';
@@ -72,15 +71,10 @@ export class EnterAction {
7271
return false;
7372
}
7473
curNode = flyoutCursor.getCurNode();
75-
nodeType = curNode?.getType();
76-
77-
switch (nodeType) {
78-
case ASTNode.types.STACK:
79-
this.insertFromFlyout(workspace);
80-
break;
81-
case ASTNode.types.BUTTON:
82-
this.triggerButtonCallback(workspace);
83-
break;
74+
if (curNode instanceof BlockSvg) {
75+
this.insertFromFlyout(workspace);
76+
} else if (curNode instanceof FlyoutButton) {
77+
this.triggerButtonCallback(workspace);
8478
}
8579

8680
return true;
@@ -102,18 +96,17 @@ export class EnterAction {
10296
if (!cursor) return;
10397
const curNode = cursor.getCurNode();
10498
if (!curNode) return;
105-
const nodeType = curNode.getType();
106-
if (nodeType === ASTNode.types.FIELD) {
107-
(curNode.getLocation() as Field).showEditor();
108-
} else if (nodeType === ASTNode.types.BLOCK) {
109-
const block = curNode.getLocation() as Block;
110-
if (!this.tryShowFullBlockFieldEditor(block)) {
99+
if (curNode instanceof Field) {
100+
curNode.showEditor();
101+
} else if (curNode instanceof BlockSvg) {
102+
if (!this.tryShowFullBlockFieldEditor(curNode)) {
111103
showHelpHint(workspace);
112104
}
113-
} else if (curNode.isConnection() || nodeType === ASTNode.types.WORKSPACE) {
105+
} else if (
106+
curNode instanceof RenderedConnection ||
107+
curNode instanceof WorkspaceSvg
108+
) {
114109
this.navigation.openToolboxOrFlyout(workspace);
115-
} else if (nodeType === ASTNode.types.STACK) {
116-
console.warn('Cannot mark a stack.');
117110
}
118111
}
119112

@@ -135,7 +128,9 @@ export class EnterAction {
135128
Events.setGroup(true);
136129
}
137130

138-
const stationaryNode = this.navigation.getFocusedASTNode(workspace);
131+
const stationaryNode = FocusableTreeTraverser.findFocusedNode(
132+
workspace,
133+
) as unknown as INavigable<any>;
139134
const newBlock = this.createNewBlock(workspace);
140135
if (!newBlock) return;
141136
const insertStartPoint = stationaryNode
@@ -148,8 +143,7 @@ export class EnterAction {
148143
workspace.setResizesEnabled(true);
149144

150145
getFocusManager().focusTree(workspace);
151-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
152-
workspace.getCursor()?.setCurNode(ASTNode.createBlockNode(newBlock)!);
146+
workspace.getCursor()?.setCurNode(newBlock);
153147
this.mover.startMove(workspace, newBlock, insertStartPoint);
154148

155149
const isStartBlock =
@@ -253,11 +247,8 @@ export class EnterAction {
253247
* containing a flyout with a button.
254248
*/
255249
private triggerButtonCallback(workspace: WorkspaceSvg) {
256-
const button = this.navigation
257-
.getFlyoutCursor(workspace)
258-
?.getCurNode()
259-
?.getLocation() as FlyoutButton | undefined;
260-
if (!button) return;
250+
const button = this.navigation.getFlyoutCursor(workspace)?.getCurNode();
251+
if (!(button instanceof FlyoutButton)) return;
261252

262253
const flyoutButtonCallbacks: Map<string, (p1: FlyoutButton) => void> =
263254
// @ts-expect-error private field access
@@ -310,11 +301,8 @@ export class EnterAction {
310301
return null;
311302
}
312303

313-
const curBlock = this.navigation
314-
.getFlyoutCursor(workspace)
315-
?.getCurNode()
316-
?.getLocation() as BlockSvg | undefined;
317-
if (!curBlock?.isEnabled()) {
304+
const curBlock = this.navigation.getFlyoutCursor(workspace)?.getCurNode();
305+
if (!(curBlock instanceof BlockSvg) || !curBlock.isEnabled()) {
318306
console.warn("Can't insert a disabled block.");
319307
return null;
320308
}

src/actions/move.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,9 @@ export class MoveActions {
196196
* could be found.
197197
*/
198198
getCurrentBlock(workspace: WorkspaceSvg): BlockSvg | undefined {
199-
const curNode = workspace?.getCursor()?.getCurNode();
200-
let block = curNode?.getSourceBlock();
199+
let block = workspace?.getCursor()?.getSourceBlock();
201200
if (!block) return undefined;
202-
while (block?.isShadow()) {
201+
while (block.isShadow()) {
203202
block = block.getParent();
204203
if (!block) {
205204
throw new Error(
@@ -208,6 +207,6 @@ export class MoveActions {
208207
);
209208
}
210209
}
211-
return block as BlockSvg;
210+
return block;
212211
}
213212
}

0 commit comments

Comments
 (0)