This commit is contained in:
Aaron Dodson
2025-10-02 09:34:51 -07:00
parent 2c9732d466
commit 8a8bc4098e
2 changed files with 78 additions and 24 deletions

View File

@@ -18,9 +18,20 @@ import {RenderedWorkspaceComment} from '../comments/rendered_workspace_comment.j
import {getFocusManager} from '../focus_manager.js';
import type {IFocusableNode} from '../interfaces/i_focusable_node.js';
import * as registry from '../registry.js';
import {Renderer as Zelos} from '../renderers/zelos/renderer.js';
import type {WorkspaceSvg} from '../workspace_svg.js';
import {Marker} from './marker.js';
/**
* Representation of the direction of travel within a navigation context.
*/
export enum NavigationDirection {
NEXT,
PREVIOUS,
IN,
OUT,
}
/**
* Class for a line cursor.
*/
@@ -51,13 +62,7 @@ export class LineCursor extends Marker {
}
const newNode = this.getNextNode(
curNode,
(candidate: IFocusableNode | null) => {
return (
(candidate instanceof BlockSvg &&
!candidate.outputConnection?.targetBlock()) ||
candidate instanceof RenderedWorkspaceComment
);
},
this.getValidationFunction(NavigationDirection.NEXT),
true,
);
@@ -80,7 +85,11 @@ export class LineCursor extends Marker {
return null;
}
const newNode = this.getNextNode(curNode, () => true, true);
const newNode = this.getNextNode(
curNode,
this.getValidationFunction(NavigationDirection.IN),
true,
);
if (newNode) {
this.setCurNode(newNode);
@@ -101,13 +110,7 @@ export class LineCursor extends Marker {
}
const newNode = this.getPreviousNode(
curNode,
(candidate: IFocusableNode | null) => {
return (
(candidate instanceof BlockSvg &&
!candidate.outputConnection?.targetBlock()) ||
candidate instanceof RenderedWorkspaceComment
);
},
this.getValidationFunction(NavigationDirection.PREVIOUS),
true,
);
@@ -130,7 +133,11 @@ export class LineCursor extends Marker {
return null;
}
const newNode = this.getPreviousNode(curNode, () => true, true);
const newNode = this.getPreviousNode(
curNode,
this.getValidationFunction(NavigationDirection.OUT),
true,
);
if (newNode) {
this.setCurNode(newNode);
@@ -147,15 +154,14 @@ export class LineCursor extends Marker {
atEndOfLine(): boolean {
const curNode = this.getCurNode();
if (!curNode) return false;
const inNode = this.getNextNode(curNode, () => true, true);
const inNode = this.getNextNode(
curNode,
this.getValidationFunction(NavigationDirection.IN),
true,
);
const nextNode = this.getNextNode(
curNode,
(candidate: IFocusableNode | null) => {
return (
candidate instanceof BlockSvg &&
!candidate.outputConnection?.targetBlock()
);
},
this.getValidationFunction(NavigationDirection.NEXT),
true,
);
@@ -298,6 +304,54 @@ export class LineCursor extends Marker {
return this.getRightMostChild(newNode, stopIfFound);
}
/**
* Returns a function that will be used to determine whether a candidate for
* navigation is valid.
*
* @param direction The direction in which the user is navigating.
* @returns A function that takes a proposed navigation candidate and returns
* true if navigation should be allowed to proceed to it, or false to find
* a different candidate.
*/
getValidationFunction(
direction: NavigationDirection,
): (node: IFocusableNode | null) => boolean {
switch (direction) {
case NavigationDirection.IN:
case NavigationDirection.OUT:
return () => true;
case NavigationDirection.NEXT:
case NavigationDirection.PREVIOUS:
return (candidate: IFocusableNode | null) => {
if (
(candidate instanceof BlockSvg &&
!candidate.outputConnection?.targetBlock()) ||
candidate instanceof RenderedWorkspaceComment
) {
return true;
}
if (candidate instanceof BlockSvg) {
const outputTarget = candidate.outputConnection?.targetBlock();
if (
outputTarget &&
!outputTarget.getInputsInline() &&
!(this.workspace.getRenderer() instanceof Zelos)
) {
const inputConnections =
outputTarget?.inputList.reduce((total, input) => {
return total + (input.connection ? 1 : 0);
}, 0) ?? 0;
return inputConnections > 1;
}
}
return false;
};
}
}
/**
* Prepare for the deletion of a block by making a list of nodes we
* could move the cursor to afterwards and save it to

View File

@@ -142,7 +142,7 @@ suite('Cursor', function () {
this.cursor.setCurNode(prevConnectionNode);
this.cursor.prev();
const curNode = this.cursor.getCurNode();
assert.equal(curNode, this.blocks.A);
assert.equal(curNode, this.blocks.E);
});
test('Prev - From first block loop to last block', function () {