vpat 7,14: popups count and cursor fixes (#3969)

- vpat_7: When a popup is showing, mark menuseparators with
role="presentation" to clear whatever semantics a separator
has. It prevents the screen readers from counting it as
an interactable element while announcing the index of
a menuitem within the popup. It also makes the screen readers
count items across all sections, instead of stopping at
the first separator.
- vpat_14: When menupopup is hiding, for a moment, mark it
as aria-hidden. It forces VoiceOver to move cursor back to
the previously focused element. Otherwise, it is not aware that
the popup went away, the cursor gets stuck inside of the
invisible menu, no elements will be announced until the screen
readers is reloaded.
This commit is contained in:
abaevbog 2024-09-02 01:46:02 -07:00 committed by GitHub
parent 6b7834876f
commit 901cc7d635
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -95,6 +95,15 @@ Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemPaneSe
});
}
// Clear whatever aria semantics the separator has so it is not counted when
// screen readers list how many menuitems a menu has.
document.addEventListener("popupshowing", (event) => {
if (event.originalTarget.tagName !== "menupopup") return;
for (let separator of [...event.originalTarget.querySelectorAll("menuseparator")]) {
separator.setAttribute("role", "presentation");
}
});
// Add MacOS menupopup fade animation to menupopups
if (Zotero.isMac) {
let MozMenuPopupPrototype = customElements.get("menupopup").prototype;
@ -161,6 +170,19 @@ Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemPaneSe
}, 200);
});
// If a menu closes with voiceover cursor in it, the cursor gets stuck in no-longer-visible
// menu and voiceover will be quiet until it is restarted. Marking the menu
// as aria-hidden for a moment forces voiceover to shift its cursor.
this.addEventListener("popuphidden", (e) => {
if (this !== e.target || this.parentNode?.closest("menupopup")) {
return;
}
this.setAttribute("aria-hidden", true);
setTimeout(() => {
this.removeAttribute("aria-hidden");
});
});
// This event is triggered after clicking the menu and before popuphiding
// where we control whether the fade out animation should run
this.addEventListener("command", () => {