Skip to content

Conversation

@BenHenning
Copy link
Collaborator

@BenHenning BenHenning commented Jun 26, 2025

The basics

The details

Resolves

Fixes #9155

Proposed Changes

In cases when an ID is missing for an element passed to FocusableTreeTraverser.findFocusableNodeFor(), always return null.

Additionally, the new short-circuit logic exposed that Toolbox actually wasn't being set up correctly (that is, its root element was not being configured with a valid ID). This has been fixed.

Reason for Changes

These are cases when a valid node should never be matched (and it's technically possible to incorrectly match if an IFocusableNode is set up incorrectly and is providing a focusable element with an unset ID). This avoids the extra computation time of potentially calling deep into WorkspaceSvg and exploring all possible nodes for an ID that should never match.

Note that there is a weird quirk with null IDs actually being the string "null". This is a side effect of how setAttribute and attributes in general work with HTML elements. There's nothing really that can be done here, so it's now considered invalid to also have an ID of string "null" just to ensure the null case is properly short-circuited.

Finally, the issue with toolbox being configured incorrectly was discovered with the introducing of a new hard failure in FocusManager.registerTree() when a tree with an invalid root element is registered. From testing there are no other such trees that need to be updated.

A new warning was also added if focusNode() is used on a node with an element that has an invalid ID. This isn't a hard failure to follow the convention of other invalid focusNode() situations. It's much more fragile for focusNode() to throw than registerTree() since the former generally happens much earlier in a page lifecycle, and is less prone to dynamic behaviors.

Test Coverage

New tests were added to validate the various empty ID cases for FocusableTreeTraverser.findFocusableNodeFor(), and to validate the new error check for FocusManager.registerTree().

Documentation

No new documentation should be needed.

Additional Information

Nothing to add.

@github-actions github-actions bot added PR: fix Fixes a bug and removed PR: fix Fixes a bug labels Jun 26, 2025
Copy link
Collaborator Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

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

Spot checked changes.

@BenHenning BenHenning changed the title fix: Short-circuit node lookups for missing IDs. fix: Short-circuit node lookups for missing IDs Jun 26, 2025
@github-actions github-actions bot added PR: fix Fixes a bug and removed PR: fix Fixes a bug labels Jun 26, 2025
@BenHenning
Copy link
Collaborator Author

Looks like this is a slightly less simple fix than I was hoping. Core tests are passing, but the nav tests might have issues (perhaps indicating a setup issue). Will need to dig.

Also, add a new check and warning, plus tests, for more robust
FocusManager behavior.
@github-actions github-actions bot added PR: fix Fixes a bug and removed PR: fix Fixes a bug labels Jun 26, 2025
Copy link
Collaborator Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

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

Spot checked latest fixes.

@BenHenning BenHenning marked this pull request as ready for review June 26, 2025 21:47
@BenHenning BenHenning requested a review from a team as a code owner June 26, 2025 21:47
@BenHenning BenHenning requested a review from RoboErikG June 26, 2025 21:47
@BenHenning BenHenning enabled auto-merge (squash) June 26, 2025 21:47
@BenHenning BenHenning disabled auto-merge June 26, 2025 21:47
Copy link
Contributor

@RoboErikG RoboErikG left a comment

Choose a reason for hiding this comment

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

One suggestion, otherwise LGTM.

// Fall back to a reasonable default since there's no valid node to focus.
const focusableNodeElement = focusableNode.getFocusableElement();
if (!focusableNodeElement.id || focusableNodeElement.id === 'null') {
console.warn('Trying to focus a node that has an invalid ID.');
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this clear isUpdatingFocusedNode and return early? It looks like the only time the rest of this method would do anything is if the element is a root node.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think that's correct, but perhaps I'm misunderstanding you.

If there's an invalid ID, then findFocusedNode will return null causing the condition on line 369 to fail, thus leading to the node to focus falling back to the tree's defaults (which can be one of several nodes depending on the tree and its state).

I'll add a line comment here to make it a bit more clear that it's intentionally falling through.

The line comment is meant to clarify why execution doesn't stop when the
new invalid state is encountered in focusNode().
Copy link
Collaborator Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

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

Self-reviewed latest.

@BenHenning
Copy link
Collaborator Author

@RoboErikG I'll go ahead and merge this, but per the conversation thread please let me know if I missed something and if there's something else you think needs to be addressed here.

@BenHenning BenHenning merged commit c426c6d into RaspberryPiFoundation:develop Jul 1, 2025
9 checks passed
@BenHenning BenHenning deleted the optimize-node-lookups-for-missing-id-cases branch July 1, 2025 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: fix Fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

short circuit findFocusableNode if id is null/empty

2 participants