Bug 1669016 - Make nsFocusManager::DetermineElementToMoveFocus look for next tabbable content from next/previous element at selection r=NeilDeakin

`nsFocusManager::DetermineElementToMoveFocus` starts to look for next tabbable
element from start boundary for first selection range if there is no focused
element in the document.  This means that if there is only one focusable element
and `Selection` is collapsed at the only focusable element, it won't move
focus to any element because it does not make the start element focused.

Chrome does not honor `Selection` to move focus unless `Selection` is starts
from a `Text`.  Therefore, I think that we don't need to take care of web-compat
to fix this bug.

This patch makes that the method move focus to the start element first if it's
focusable if there is no focused element.  This behavior matches with the
focus move by a caret move.  So I think that this may make users feel consistent
behavior with arrow keys and `Tab` key in the caret browsing mode.

Differential Revision: https://phabricator.services.mozilla.com/D215903
This commit is contained in:
Masayuki Nakano
2024-07-23 00:47:18 +00:00
parent 4aafa4d894
commit d58e2a77d9
3 changed files with 90 additions and 0 deletions

View File

@@ -3515,6 +3515,27 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
// previous element in the document. So the tabindex on elements
// should be ignored.
ignoreTabIndex = true;
// If selection starts from a focusable and tabbable element, we want
// to make it focused rather than next/previous one.
if (startContent->IsElement() && startContent->GetPrimaryFrame() &&
startContent->GetPrimaryFrame()->IsFocusable().IsTabbable()) {
startContent =
forward ? (startContent->GetPreviousSibling()
? startContent->GetPreviousSibling()
// We don't need to get previous leaf node
// because it may be too far from
// startContent. We just want the previous
// node immediately before startContent.
: startContent->GetParent())
// We want the next node immdiately after startContent.
// Therefore, we don't want its first child.
: startContent->GetNextNonChildNode();
// If we reached the root element, we should treat it as there is no
// selection as same as above.
if (startContent == rootElement) {
startContent = nullptr;
}
}
}
}