From 901cc7d63581ce67dede38d433b98dff5af99233 Mon Sep 17 00:00:00 2001 From: abaevbog Date: Mon, 2 Sep 2024 01:46:02 -0700 Subject: [PATCH] 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. --- chrome/content/zotero/customElements.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/chrome/content/zotero/customElements.js b/chrome/content/zotero/customElements.js index e8da5ec861..63d50305a4 100644 --- a/chrome/content/zotero/customElements.js +++ b/chrome/content/zotero/customElements.js @@ -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", () => {