Skip to content

Commit ff16482

Browse files
authored
fix: check if row is present when setting aria label of popup elements (#5750)
1 parent a27e1e8 commit ff16482

File tree

2 files changed

+34
-31
lines changed

2 files changed

+34
-31
lines changed

src/autocomplete/popup.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,19 @@ class AcePopup {
138138
var t = popup.renderer.$textLayer;
139139
for (var row = t.config.firstRow, l = t.config.lastRow; row <= l; row++) {
140140
const popupRowElement = /** @type {HTMLElement|null} */(t.element.childNodes[row - t.config.firstRow]);
141-
const rowData = popup.getData(row);
142-
const ariaLabel = `${rowData.caption || rowData.value}${rowData.meta ? `, ${rowData.meta}` : ''}`;
143141

144142
popupRowElement.setAttribute("role", optionAriaRole);
145143
popupRowElement.setAttribute("aria-roledescription", nls("autocomplete.popup.item.aria-roledescription", "item"));
146-
popupRowElement.setAttribute("aria-label", ariaLabel);
147144
popupRowElement.setAttribute("aria-setsize", popup.data.length);
148145
popupRowElement.setAttribute("aria-describedby", "doc-tooltip");
149146
popupRowElement.setAttribute("aria-posinset", row + 1);
150147

148+
const rowData = popup.getData(row);
149+
if (rowData) {
150+
const ariaLabel = `${rowData.caption || rowData.value}${rowData.meta ? `, ${rowData.meta}` : ''}`;
151+
popupRowElement.setAttribute("aria-label", ariaLabel);
152+
}
153+
151154
const highlightedSpans = popupRowElement.querySelectorAll(".ace_completion-highlight");
152155
highlightedSpans.forEach(span => {
153156
span.setAttribute("role", "mark");

src/autocomplete_test.js

+28-28
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,16 @@ module.exports = {
6868
assert.ok(!editor.container.querySelector("style"));
6969

7070
sendKey("a");
71-
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-label="arraysort, local" aria-setsize="2" aria-describedby="doc-tooltip" aria-posinset="1" id="suggest-aria-id:0" aria-selected="true"><s "ace_completion-highlight" role="mark">a</s><s "ace_">rraysort</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d><d "ace_line" role="option" aria-roledescription="item" aria-label="alooooooooooooooooooooooooooooong_word, local" aria-setsize="2" aria-describedby="doc-tooltip" aria-posinset="2"><s "ace_completion-highlight" role="mark">a</s><s "ace_">looooooooooooooooooooooooooooong_word</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function() {
71+
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-setsize="2" aria-describedby="doc-tooltip" aria-posinset="1" aria-label="arraysort, local" id="suggest-aria-id:0" aria-selected="true"><s "ace_completion-highlight" role="mark">a</s><s "ace_">rraysort</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d><d "ace_line" role="option" aria-roledescription="item" aria-setsize="2" aria-describedby="doc-tooltip" aria-posinset="2" aria-label="alooooooooooooooooooooooooooooong_word, local"><s "ace_completion-highlight" role="mark">a</s><s "ace_">looooooooooooooooooooooooooooong_word</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function() {
7272
sendKey("rr");
73-
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-label="arraysort, local" aria-setsize="1" aria-describedby="doc-tooltip" aria-posinset="1" id="suggest-aria-id:0" aria-selected="true"><s "ace_completion-highlight" role="mark">arr</s><s "ace_">aysort</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function() {
73+
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-setsize="1" aria-describedby="doc-tooltip" aria-posinset="1" aria-label="arraysort, local" id="suggest-aria-id:0" aria-selected="true"><s "ace_completion-highlight" role="mark">arr</s><s "ace_">aysort</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function () {
7474
sendKey("r");
75-
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-label="arraysort, local" aria-setsize="1" aria-describedby="doc-tooltip" aria-posinset="1" id="suggest-aria-id:0" aria-selected="true"><s "ace_completion-highlight" role="mark">arr</s><s "ace_">ayso</s><s "ace_completion-highlight" role="mark">r</s><s "ace_">t</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function() {
76-
75+
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-setsize="1" aria-describedby="doc-tooltip" aria-posinset="1" aria-label="arraysort, local" id="suggest-aria-id:0" aria-selected="true"><s "ace_completion-highlight" role="mark">arr</s><s "ace_">ayso</s><s "ace_completion-highlight" role="mark">r</s><s "ace_">t</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function () {
76+
7777
sendKey("Return");
7878
assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word");
7979
editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_");
80-
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-label="alooooooooooooooooooooooooooooong_word, local" aria-setsize="1" aria-describedby="doc-tooltip" aria-posinset="1" id="suggest-aria-id:0" aria-selected="true"><s "ace_">a</s><s "ace_completion-highlight" role="mark">looooooooooooooooooooooooooooong_</s><s "ace_">word</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function() {
80+
checkInnerHTML('<d "ace_line ace_selected" role="option" aria-roledescription="item" aria-setsize="1" aria-describedby="doc-tooltip" aria-posinset="1" aria-label="alooooooooooooooooooooooooooooong_word, local" id="suggest-aria-id:0" aria-selected="true"><s "ace_">a</s><s "ace_completion-highlight" role="mark">looooooooooooooooooooooooooooong_</s><s "ace_">word</s><s "ace_completion-spacer"> </s><s "ace_completion-meta">local</s></d>', function () {
8181
sendKey("Return");
8282
editor.destroy();
8383
editor.container.remove();
@@ -86,15 +86,15 @@ module.exports = {
8686
});
8787
});
8888
});
89-
89+
9090
var last;
9191
function checkInnerHTML(expected, callback) {
9292
var popup = editor.completer.popup;
93-
93+
9494
popup.renderer.on("afterRender", function wait() {
9595
var innerHTML = popup.renderer.$textLayer.element.innerHTML
9696
.replace(/\s*style="[^"]+"|class=|(d)iv|(s)pan/g, "$1$2");
97-
if (innerHTML == last)
97+
if (innerHTML == last)
9898
return;
9999
assert.equal(innerHTML, expected);
100100
last = innerHTML;
@@ -232,29 +232,29 @@ module.exports = {
232232
sendKey('Return');
233233
var popup = editor.completer.popup;
234234
check(function () {
235-
assert.equal(popup.data.length, 10);
236-
// check that the aria attributes have been set on all the elements of the popup and that aria selected attributes are set on the first item
237-
assert.ok(checkAria(popup.renderer.$textLayer.element.innerHTML, '<d role="option" aria-roledescription="item" aria-label="0" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="1" id="suggest-aria-id:0" aria-selected="true"><s >0</s><s > </s></d>' +
238-
'<d role="option" aria-roledescription="item" aria-label="1" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="2"><s >1</s><s > </s></d>' +
239-
'<d role="option" aria-roledescription="item" aria-label="2" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="3"><s >2</s><s > </s></d>' +
240-
'<d role="option" aria-roledescription="item" aria-label="3" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="4"><s >3</s><s > </s></d>' +
241-
'<d role="option" aria-roledescription="item" aria-label="4" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="5"><s >4</s><s > </s></d>' +
242-
'<d role="option" aria-roledescription="item" aria-label="5" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="6"><s >5</s><s > </s></d>' +
243-
'<d role="option" aria-roledescription="item" aria-label="6" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="7"><s >6</s><s > </s></d>' +
244-
'<d role="option" aria-roledescription="item" aria-label="7" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="8"><s >7</s><s > </s></d>' +
245-
'<d role="option" aria-roledescription="item" aria-label="8" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="9"><s >8</s><s > </s></d>'));
246-
const prevSelected = popup.selectedNode;
247-
sendKey('Down');
248-
check(function () {
249-
assert.ok(checkAria(popup.selectedNode.outerHTML, '<d role="option" aria-roledescription="item" aria-label="1" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="2" id="suggest-aria-id:1" aria-selected="true"><s >1</s><s > </s></d>'));
250-
// check that the aria selected attributes have been removed from the previously selected element
251-
assert.ok(checkAria(prevSelected.outerHTML, '<d role="option" aria-roledescription="item" aria-label="0" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="1"><s >0</s><s > </s></d>'));
235+
assert.equal(popup.data.length, 10);
236+
// check that the aria attributes have been set on all the elements of the popup and that aria selected attributes are set on the first item
237+
assert.ok(checkAria(popup.renderer.$textLayer.element.innerHTML, '<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="1" aria-label="0" id="suggest-aria-id:0" aria-selected="true"><s >0</s><s > </s></d>' +
238+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="2" aria-label="1"><s >1</s><s > </s></d>' +
239+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="3" aria-label="2"><s >2</s><s > </s></d>' +
240+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="4" aria-label="3"><s >3</s><s > </s></d>' +
241+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="5" aria-label="4"><s >4</s><s > </s></d>' +
242+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="6" aria-label="5"><s >5</s><s > </s></d>' +
243+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="7" aria-label="6"><s >6</s><s > </s></d>' +
244+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="8" aria-label="7"><s >7</s><s > </s></d>' +
245+
'<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="9" aria-label="8"><s >8</s><s > </s></d>'));
246+
const prevSelected = popup.selectedNode;
252247
sendKey('Down');
253248
check(function () {
254-
assert.ok(checkAria(popup.selectedNode.outerHTML, '<d role="option" aria-roledescription="item" aria-label="2" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="3" id="suggest-aria-id:2" aria-selected="true"><s >2</s><s > </s></d>'));
255-
done();
249+
assert.ok(checkAria(popup.selectedNode.outerHTML, '<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="2" aria-label="1" id="suggest-aria-id:1" aria-selected="true"><s >1</s><s > </s></d>'));
250+
// check that the aria selected attributes have been removed from the previously selected element
251+
assert.ok(checkAria(prevSelected.outerHTML, '<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="1" aria-label="0"><s >0</s><s > </s></d>'));
252+
sendKey('Down');
253+
check(function () {
254+
assert.ok(checkAria(popup.selectedNode.outerHTML, '<d role="option" aria-roledescription="item" aria-setsize="10" aria-describedby="doc-tooltip" aria-posinset="3" aria-label="2" id="suggest-aria-id:2" aria-selected="true"><s >2</s><s > </s></d>'));
255+
done();
256+
});
256257
});
257-
});
258258
});
259259
function check(callback) {
260260
popup = editor.completer.popup;

0 commit comments

Comments
 (0)