|
| 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 | +} |
0 commit comments