Skip to content

Commit 1eea41e

Browse files
Merge 76defb7 into 55a9b32
2 parents 55a9b32 + 76defb7 commit 1eea41e

3 files changed

Lines changed: 46 additions & 1 deletion

File tree

source/browseMode.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,13 @@ def event_gainFocus(self, obj, nextHandler):
15521552
return
15531553
if not self.passThrough and self._shouldIgnoreFocus(obj):
15541554
return
1555+
1556+
# If the previous focus object was removed, we might hit a false positive for overlap detection.
1557+
# Track the previous focus target so that we can account for this scenario.
1558+
previousFocusObjIsDefunct=False
1559+
if self._lastFocusObj and controlTypes.STATE_DEFUNCT in self._lastFocusObj.states:
1560+
previousFocusObjIsDefunct=True
1561+
15551562
self._lastFocusObj=obj
15561563

15571564
try:
@@ -1569,7 +1576,8 @@ def event_gainFocus(self, obj, nextHandler):
15691576
caretInfo=self.makeTextInfo(textInfos.POSITION_CARET)
15701577
# Expand to one character, as isOverlapping() doesn't treat, for example, (4,4) and (4,5) as overlapping.
15711578
caretInfo.expand(textInfos.UNIT_CHARACTER)
1572-
if not self._hadFirstGainFocus or not focusInfo.isOverlapping(caretInfo):
1579+
isOverlapping = focusInfo.isOverlapping(caretInfo)
1580+
if not self._hadFirstGainFocus or not isOverlapping or (isOverlapping and previousFocusObjIsDefunct):
15731581
# The virtual caret is not within the focus node.
15741582
oldPassThrough=self.passThrough
15751583
passThrough = self.shouldPassThrough(obj, reason=OutputReason.FOCUS)

tests/system/robot/chromeTests.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,37 @@ def test_ariaCheckbox_browseMode():
345345
actualSpeech,
346346
"Sandwich Condiments grouping list with 4 items Lettuce check box not checked"
347347
)
348+
349+
350+
def test_i12147():
351+
"""
352+
New focus target should be announced if the triggering element is removed when activated.
353+
"""
354+
_chrome.prepareChrome(
355+
f"""
356+
<div>
357+
<button id='trigger0'>trigger 0</button>
358+
<h4 id='target0' tabindex='-1'>target 0</h4>
359+
</div>
360+
<script>
361+
let trigger0 = document.querySelector('#trigger0');
362+
trigger0.addEventListener('click', e => {{
363+
let focusTarget = document.querySelector('#target0');
364+
trigger0.remove();
365+
focusTarget.focus();
366+
}})
367+
</script>
368+
"""
369+
)
370+
# Jump to the first button (the trigger)
371+
actualSpeech = _chrome.getSpeechAfterKey("tab")
372+
_asserts.strings_match(
373+
actualSpeech,
374+
"trigger 0 button"
375+
)
376+
# Activate the button, we should hear the new focus target.
377+
actualSpeech = _chrome.getSpeechAfterKey("enter")
378+
_asserts.strings_match(
379+
actualSpeech,
380+
"target 0 heading level 4"
381+
)

tests/system/robot/chromeTests.robot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ ARIA checkbox
4747
[Documentation] Navigate to an unchecked checkbox in reading mode.
4848
[Tags] aria-at
4949
test_ariaCheckbox_browseMode
50+
i12147
51+
[Documentation] New focus target should be announced if the triggering element is removed when activated
52+
test_i12147

0 commit comments

Comments
 (0)