Skip to content

Commit 0c286a0

Browse files
author
Oleg Zinoviev
committed
MAGETWO-32186: WAI-ARIA in Search Autocomplete
1 parent bdb6ea9 commit 0c286a0

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

app/code/Magento/Search/view/frontend/templates/form.mini.phtml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ $helper = $this->helper('Magento\Search\Helper\Data');
2929
placeholder="<?php echo __('Search entire store here...'); ?>"
3030
class="input-text"
3131
maxlength="<?php echo $helper->getMaxQueryLength();?>"
32+
role="combobox"
33+
aria-haspopup="false"
34+
aria-autocomplete="both"
3235
autocomplete="off"/>
3336
<div id="search_autocomplete" class="search-autocomplete"></div>
3437
<?php echo $this->getChildHtml() ?>

app/code/Magento/Search/view/frontend/web/form-mini.js

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ define([
2929
minSearchLength: 2,
3030
responseFieldElements: 'ul li',
3131
selectClass: 'selected',
32-
template: '<li class="{{row_class}}" title="{{title}}">{{title}}<span class="amount">{{num_of_results}}</span></li>',
32+
template: '<li class="{{row_class}}" id="qs-option-{{index}}" role="option"><span class="qs-option-name">{{title}}</span><span aria-hidden="true" class="amount">{{num_of_results}}</span></li>',
3333
submitBtn: 'button[type="submit"]',
3434
searchLabel: '[data-role=minisearch-label]'
3535
},
@@ -54,6 +54,7 @@ define([
5454
this.searchLabel.removeClass('active');
5555
}
5656
this.autoComplete.hide();
57+
this._updateAriaHasPopup(false);
5758
}, this), 250);
5859
}, this));
5960

@@ -65,7 +66,10 @@ define([
6566
this.element.on('keydown', this._onKeyDown);
6667
this.element.on('input propertychange', this._onPropertyChange);
6768

68-
this.searchForm.on('submit', this._onSubmit);
69+
this.searchForm.on('submit', $.proxy(function() {
70+
this._onSubmit();
71+
this._updateAriaHasPopup(false);
72+
}, this));
6973
},
7074
/**
7175
* @private
@@ -83,6 +87,18 @@ define([
8387
return this.responseList.indexList ? this.responseList.indexList.last() : false;
8488
},
8589

90+
/**
91+
* @private
92+
* Update attribute aria-haspopup (true/false).
93+
*/
94+
_updateAriaHasPopup: function(show) {
95+
if (show === true) {
96+
this.element.attr('aria-haspopup', "true");
97+
} else {
98+
this.element.attr('aria-haspopup', "false");
99+
}
100+
},
101+
86102
/**
87103
* Clears the item selected from the suggestion list and resets the suggestion list.
88104
* @private
@@ -107,9 +123,9 @@ define([
107123
if (isEmpty(value)) {
108124
e.preventDefault();
109125
}
110-
126+
111127
if (this.responseList.selected) {
112-
this.element.val(this.responseList.selected.attr('title'));
128+
this.element.val(this.responseList.selected.find('.qs-option-name').text());
113129
}
114130
},
115131

@@ -152,6 +168,8 @@ define([
152168
this._getFirstVisibleElement().addClass(this.options.selectClass);
153169
this.responseList.selected = this._getFirstVisibleElement();
154170
}
171+
this.element.val(this.responseList.selected.find('.qs-option-name').text());
172+
this.element.attr('aria-activedescendant', this.responseList.selected.attr('id'));
155173
}
156174
break;
157175
case $.ui.keyCode.UP:
@@ -164,6 +182,8 @@ define([
164182
this._getLastElement().addClass(this.options.selectClass);
165183
this.responseList.selected = this._getLastElement();
166184
}
185+
this.element.val(this.responseList.selected.find('.qs-option-name').text());
186+
this.element.attr('aria-activedescendant', this.responseList.selected.attr('id'));
167187
}
168188
break;
169189
default:
@@ -188,14 +208,15 @@ define([
188208
},
189209
source = this.options.template,
190210
template = Handlebars.compile(source),
191-
dropdown = $('<ul></ul>'),
211+
dropdown = $('<ul role="listbox"></ul>'),
192212
value = this.element.val();
193213

194214
this.submitBtn.disabled = isEmpty(value);
195215

196216
if (value.length >= parseInt(this.options.minSearchLength, 10)) {
197217
$.get(this.options.url, {q: value}, $.proxy(function (data) {
198-
$.each(data, function(index, element){
218+
$.each(data, function(index, element) {
219+
element.index = index;
199220
var html = template(element);
200221
dropdown.append(html);
201222
});
@@ -205,7 +226,14 @@ define([
205226
.find(this.options.responseFieldElements + ':visible');
206227

207228
this._resetResponseList(false);
208-
229+
this.element.removeAttr('aria-activedescendant');
230+
231+
if (this.responseList.indexList.length) {
232+
this._updateAriaHasPopup(true);
233+
} else {
234+
this._updateAriaHasPopup(false);
235+
}
236+
209237
this.responseList.indexList
210238
.on('click', function (e) {
211239
this.responseList.selected = $(e.target);
@@ -215,6 +243,7 @@ define([
215243
this.responseList.indexList.removeClass(this.options.selectClass);
216244
$(e.target).addClass(this.options.selectClass);
217245
this.responseList.selected = $(e.target);
246+
this.element.attr('aria-activedescendant', $(e.target).attr('id'));
218247
}.bind(this))
219248
.on('mouseout', function (e) {
220249
if (!this._getLastElement() && this._getLastElement().hasClass(this.options.selectClass)) {
@@ -226,6 +255,8 @@ define([
226255
} else {
227256
this._resetResponseList(true);
228257
this.autoComplete.hide();
258+
this._updateAriaHasPopup(false);
259+
this.element.removeAttr('aria-activedescendant');
229260
}
230261
}
231262
});

0 commit comments

Comments
 (0)