Skip to content

Commit 0fda594

Browse files
authored
Fix: Prevent label clicks and key presses from changing [aria-disabled] inputs (fixes #623) (#624)
1 parent 3cec6f1 commit 0fda594

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

js/a11y.js

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Adapt from 'core/js/adapt';
22
import offlineStorage from 'core/js/offlineStorage';
33
import device from 'core/js/device';
44
import location from 'core/js/location';
5+
import AriaDisabled from './a11y/ariaDisabled';
56
import BrowserConfig from './a11y/browserConfig';
67
import BrowserFocus from 'core/js/a11y/browserFocus';
78
import FocusOptions from 'core/js/a11y/focusOptions';
@@ -80,6 +81,7 @@ class A11y extends Backbone.Controller {
8081
this._htmlCharRegex = /&.*;/g;
8182
/** @type {Object} */
8283
this.config = null;
84+
this._ariaDisabled = new AriaDisabled({ a11y: this });
8385
this._browserConfig = new BrowserConfig({ a11y: this });
8486
this._browserFocus = new BrowserFocus({ a11y: this });
8587
this._keyboardFocusOutline = new KeyboardFocusOutline({ a11y: this });

js/a11y/ariaDisabled.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Adapt from 'core/js/adapt';
2+
3+
/**
4+
* Browser aria-disabled element interaction prevention
5+
* @class
6+
*/
7+
export default class BrowserFocus extends Backbone.Controller {
8+
9+
initialize({ a11y }) {
10+
this.a11y = a11y;
11+
this._onKeyDown = this._onKeyDown.bind(this);
12+
this._onClick = this._onClick.bind(this);
13+
this.$body = $('body');
14+
this.listenTo(Adapt, {
15+
'accessibility:ready': this._attachEventListeners
16+
});
17+
}
18+
19+
_attachEventListeners() {
20+
// 'Capture' events
21+
this.$body[0].addEventListener('keydown', this._onKeyDown, true);
22+
this.$body[0].addEventListener('click', this._onClick, true);
23+
}
24+
25+
isAriaDisabled($element) {
26+
// search element and parents for aria-disabled - see https://github.com/adaptlearning/adapt_framework/issues/3097
27+
// search closest 'for' element for aria-disabled - see https://github.com/adaptlearning/adapt-contrib-core/issues/623
28+
const $closestFor = $element.closest('[for]');
29+
const isAriaDisabled = $element.closest('[aria-disabled=true]').length === 1 ||
30+
($closestFor.length && $(`#${$closestFor.attr('for')}`).is('[aria-disabled=true]'));
31+
return isAriaDisabled;
32+
}
33+
34+
/**
35+
* Stop click handling on aria-disabled elements.
36+
*
37+
* @param {JQuery.Event} event
38+
*/
39+
_onClick(event) {
40+
if (!event.isTrusted) return;
41+
const $element = $(event.target);
42+
if (!this.isAriaDisabled($element)) return;
43+
event.preventDefault();
44+
event.stopImmediatePropagation();
45+
}
46+
47+
/**
48+
* Stop enter and space handling on aria-disabled elements.
49+
*
50+
* @param {JQuery.Event} event
51+
*/
52+
_onKeyDown(event) {
53+
if (!event.isTrusted) return;
54+
if (!['Enter', ' '].includes(event.key)) return;
55+
const $element = $(event.target);
56+
if (!this.isAriaDisabled($element)) return;
57+
event.preventDefault();
58+
event.stopImmediatePropagation();
59+
}
60+
61+
}

js/a11y/browserFocus.js

+1-8
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,16 @@ export default class BrowserFocus extends Backbone.Controller {
6161
/**
6262
* Force focus when clicked on a tabbable element,
6363
* making sure `document.activeElement` is updated.
64-
* Stop event handling on aria-disabled elements.
6564
*
6665
* @param {JQuery.Event} event
6766
*/
6867
_onClick(event) {
6968
if (!event.isTrusted) return;
70-
const $element = $(event.target);
71-
// search element and parents for aria-disabled - see https://github.com/adaptlearning/adapt_framework/issues/3097
72-
const isAriaDisabled = $element.closest('[aria-disabled=true]').length === 1;
73-
if (isAriaDisabled) {
74-
event.preventDefault();
75-
event.stopImmediatePropagation();
76-
}
7769
const config = this.a11y.config;
7870
if (!config._isEnabled || !config._options._isFocusOnClickEnabled) {
7971
return;
8072
}
73+
const $element = $(event.target);
8174
const $stack = $([...$element.toArray(), ...$element.parents().toArray()]);
8275
const $focusable = $stack.filter(config._options._tabbableElements);
8376
if (!$focusable.length) {

0 commit comments

Comments
 (0)