Skip to content

Commit

Permalink
Results respect disabled state of <option> (#5560)
Browse files Browse the repository at this point in the history
This check is in place in most other places, mostly because we have
run into widespread issues under similar circumstances and we like to
avoid those, but it was forgotten here. There also were no tests
covering this, so it was never caught.

This adds tests that ensure that the option in the results list will
be generated with the correct "disabled" state based on whether or
not it, or a parent element, is marked as disabled.

This should have been easy: just check `element.disabled`

Unfortunately the `disabled` property is not inherited within the
option chain, so if an `<optgroup>` is disabled, the `<option>`
elements or other `<optgroup>` elements held within it do not have
their `disabled` property set to `true`. As a result, we needed to
use the `matches` method to check if the `:disabled` state is
present for the element. The `matches` method is part of the official
standard, but it was not implemented under that name for a while and
as a result Internet Explorer only supports it under the prefixed
`msMatchesSelector` method and older versions of Webkit have it
implemented as `webkitMatchesSelector`. But once we use this method,
it appears to consistently return the expected results.

This `matches` method and prefixed predecessors are not supported in
IE 8, but they are supported in IE 9 and any browsers newer than
that. Instead of buulding a very hacky solution using
`querySelectorAll` that was brittle, I have chosen to act like
everyone else and pretend IE 8 no longer exists.

Fixes #3347
Closes #4818
  • Loading branch information
kevin-brown committed Jul 10, 2019
1 parent b5f136f commit bd7ac9d
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/js/select2/results.js
Expand Up @@ -175,7 +175,12 @@ define([
'aria-selected': 'false'
};

if (data.disabled) {
var matches = window.Element.prototype.matches ||
window.Element.prototype.msMatchesSelector ||
window.Element.prototype.webkitMatchesSelector;

if ((data.element != null && matches.call(data.element, ':disabled')) ||
(data.element == null && data.disabled)) {
delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
Expand Down
63 changes: 63 additions & 0 deletions tests/results/option-tests.js
@@ -0,0 +1,63 @@
module('Results - option');

var $ = require('jquery');

var Options = require('select2/options');

var Results = require('select2/results');

test('disabled property on option is respected - enabled', function (assert) {
var results = new Results($('<select></select>'), new Options({}));

var $option = $('<option></option>');
var option = results.option({
element: $option[0]
});

assert.notEqual(option.getAttribute('aria-disabled'), 'true');
});

test('disabled property on option is respected - disabled', function (assert) {
var results = new Results($('<select></select>'), new Options({}));

var $option = $('<option disabled></option>');
var option = results.option({
element: $option[0]
});

assert.equal(option.getAttribute('aria-disabled'), 'true');
});

test('disabled property on enabled optgroup is respected', function (assert) {
var results = new Results($('<select></select>'), new Options({}));

var $option = $('<optgroup></optgroup>');
var option = results.option({
element: $option[0]
});

assert.notEqual(option.getAttribute('aria-disabled'), 'true');
});

test('disabled property on disabled optgroup is respected', function (assert) {
var results = new Results($('<select></select>'), new Options({}));

var $option = $('<optgroup disabled></optgroup>');
var option = results.option({
element: $option[0]
});

assert.equal(option.getAttribute('aria-disabled'), 'true');
});

test('option in disabled optgroup is disabled', function (assert) {
var results = new Results($('<select></select>'), new Options({}));

var $option = $('<optgroup disabled><option></option></optgroup>')
.find('option');
var option = results.option({
element: $option[0]
});

assert.equal(option.getAttribute('aria-disabled'), 'true');
});
1 change: 1 addition & 0 deletions tests/unit-jq1.html
Expand Up @@ -82,6 +82,7 @@
<script src="options/width-tests.js" type="text/javascript"></script>

<script src="results/focusing-tests.js" type="text/javascript"></script>
<script src="results/option-tests.js" type="text/javascript"></script>

<script src="selection/allowClear-tests.js" type="text/javascript"></script>
<script src="selection/containerCss-tests.js" type="text/javascript"></script>
Expand Down
1 change: 1 addition & 0 deletions tests/unit-jq2.html
Expand Up @@ -82,6 +82,7 @@
<script src="options/width-tests.js" type="text/javascript"></script>

<script src="results/focusing-tests.js" type="text/javascript"></script>
<script src="results/option-tests.js" type="text/javascript"></script>

<script src="selection/allowClear-tests.js" type="text/javascript"></script>
<script src="selection/containerCss-tests.js" type="text/javascript"></script>
Expand Down
1 change: 1 addition & 0 deletions tests/unit-jq3.html
Expand Up @@ -82,6 +82,7 @@
<script src="options/width-tests.js" type="text/javascript"></script>

<script src="results/focusing-tests.js" type="text/javascript"></script>
<script src="results/option-tests.js" type="text/javascript"></script>

<script src="selection/allowClear-tests.js" type="text/javascript"></script>
<script src="selection/containerCss-tests.js" type="text/javascript"></script>
Expand Down

0 comments on commit bd7ac9d

Please sign in to comment.