From 684590546746fa2ef090c10c140e01e43974d8f4 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Mon, 27 Nov 2023 16:30:17 +0100 Subject: [PATCH 1/4] fix: set completion popup role to 'menu' for safari --- src/autocomplete/popup.js | 8 +++++--- src/autocomplete_test.js | 8 ++++---- src/lib/useragent.js | 2 ++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 51a491ec987..526c28e0f29 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -7,6 +7,7 @@ var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); var nls = require("../config").nls; +var userAgent = require("./../lib/useragent"); var getAriaId = function(index) { return `suggest-aria-id:${index}`; @@ -50,8 +51,8 @@ class AcePopup { popup.renderer.setStyle("ace_autocomplete"); // Set aria attributes for the popup - popup.renderer.$textLayer.element.setAttribute("role", "listbox"); - popup.renderer.$textLayer.element.setAttribute("aria-label", nls("Autocomplete suggestions")); + popup.renderer.$textLayer.element.setAttribute("role", userAgent.isSafari ? "menu" : "listbox"); + popup.renderer.$textLayer.element.setAttribute("aria-roledescription", nls("Autocomplete suggestions")); popup.renderer.textarea.setAttribute("aria-hidden", "true"); popup.setOption("displayIndentGuides", false); @@ -137,7 +138,8 @@ class AcePopup { selected.id = ariaId; t.element.setAttribute("aria-activedescendant", ariaId); el.setAttribute("aria-activedescendant", ariaId); - selected.setAttribute("role", "option"); + selected.setAttribute("role", userAgent.isSafari ? "menuitem" : "option"); + selected.setAttribute("aria-roledescription", nls("item")); selected.setAttribute("aria-label", popup.getData(row).value); selected.setAttribute("aria-setsize", popup.data.length); selected.setAttribute("aria-posinset", row+1); diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index c16904e24e0..409836ab7ed 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -66,16 +66,16 @@ module.exports = { assert.ok(!editor.container.querySelector("style")); sendKey("a"); - checkInnerHTML('arraysort localalooooooooooooooooooooooooooooong_word local', function() { + checkInnerHTML('arraysort localalooooooooooooooooooooooooooooong_word local', function() { sendKey("rr"); - checkInnerHTML('arraysort local', function() { + checkInnerHTML('arraysort local', function() { sendKey("r"); - checkInnerHTML('arraysort local', function() { + checkInnerHTML('arraysort local', function() { sendKey("Return"); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_word local', function() { + checkInnerHTML('alooooooooooooooooooooooooooooong_word local', function() { sendKey("Return"); editor.destroy(); editor.container.remove(); diff --git a/src/lib/useragent.js b/src/lib/useragent.js index 8427c076c3a..d3e57adb07a 100644 --- a/src/lib/useragent.js +++ b/src/lib/useragent.js @@ -61,6 +61,8 @@ exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined; exports.isChrome = parseFloat(ua.split(" Chrome/")[1]) || undefined; +exports.isSafari = parseFloat(ua.split(" Safari/")[1]) && !exports.isChrome || undefined; + exports.isEdge = parseFloat(ua.split(" Edge/")[1]) || undefined; exports.isAIR = ua.indexOf("AdobeAIR") >= 0; From 6100090c01b7f82df52af134ac4a0c96c8c6f5a6 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Tue, 28 Nov 2023 11:18:46 +0100 Subject: [PATCH 2/4] set aria-selected --- src/autocomplete/popup.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 526c28e0f29..02e858c9601 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -129,6 +129,7 @@ class AcePopup { if (selected !== t.selectedNode && t.selectedNode) { dom.removeCssClass(t.selectedNode, "ace_selected"); el.removeAttribute("aria-activedescendant"); + selected.removeAttribute("aria-selected"); t.selectedNode.removeAttribute("id"); } t.selectedNode = selected; @@ -144,6 +145,7 @@ class AcePopup { selected.setAttribute("aria-setsize", popup.data.length); selected.setAttribute("aria-posinset", row+1); selected.setAttribute("aria-describedby", "doc-tooltip"); + selected.setAttribute("aria-selected", "true"); } }); var hideHoverMarker = function() { setHoverMarker(-1); }; From 6e2c02c64e9bf77a1e6f025e965ef19c93aac0b8 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Tue, 28 Nov 2023 11:22:11 +0100 Subject: [PATCH 3/4] add aria-label back --- src/autocomplete/popup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 02e858c9601..196191eea17 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -53,6 +53,7 @@ class AcePopup { // Set aria attributes for the popup popup.renderer.$textLayer.element.setAttribute("role", userAgent.isSafari ? "menu" : "listbox"); popup.renderer.$textLayer.element.setAttribute("aria-roledescription", nls("Autocomplete suggestions")); + popup.renderer.$textLayer.element.setAttribute("aria-label", nls("Autocomplete suggestions")); popup.renderer.textarea.setAttribute("aria-hidden", "true"); popup.setOption("displayIndentGuides", false); From fbcb850ab6f870927b4a5e0de23c443b3dbe81f4 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Tue, 28 Nov 2023 11:26:03 +0100 Subject: [PATCH 4/4] fix test --- src/autocomplete_test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 409836ab7ed..35e9dd4cae4 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -66,16 +66,16 @@ module.exports = { assert.ok(!editor.container.querySelector("style")); sendKey("a"); - checkInnerHTML('arraysort localalooooooooooooooooooooooooooooong_word local', function() { + checkInnerHTML('arraysort localalooooooooooooooooooooooooooooong_word local', function() { sendKey("rr"); - checkInnerHTML('arraysort local', function() { + checkInnerHTML('arraysort local', function() { sendKey("r"); - checkInnerHTML('arraysort local', function() { + checkInnerHTML('arraysort local', function() { sendKey("Return"); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_word local', function() { + checkInnerHTML('alooooooooooooooooooooooooooooong_word local', function() { sendKey("Return"); editor.destroy(); editor.container.remove();