PageSourceSearch

https://rider62.ru/components/com_gridbox/assets/modules/AccessibilityHelper.js

js rider62.ru collected 2026-10-08 13:43:58 UTC 3,064 bytes, 102 lines download raw bytes

1export default class AccessibilityHelper {
2    static focusableSelectors = [
3        'a[href]:not([tabindex="-1"])',
4        'area[href]:not([tabindex="-1"])',
5        'input:not([disabled]):not([tabindex="-1"])',
6        'select:not([disabled]):not([tabindex="-1"])',
7        'textarea:not([disabled]):not([tabindex="-1"])',
8        'button:not([disabled]):not([tabindex="-1"])',
9        'iframe:not([tabindex="-1"])',
10        'object:not([tabindex="-1"])',
11        'embed:not([tabindex="-1"])',
12        '[tabindex]:not([tabindex="-1"])',
13        '[contenteditable]:not([tabindex="-1"])',
14    ];
15
16    constructor(wrapper, timeout = 0) {
17        this.wrapper = wrapper;
18        this.timeout = timeout;
19        this.handleKeydown = this.handleTrappedKeydown.bind(this);
20    }
21
22    getTrappedElements() {
23        return this.wrapper.querySelectorAll(AccessibilityHelper.focusableSelectors.join(','));
24    }
25
26    trap() {
27        const elements = this.getTrappedElements();
28        if (elements.length === 0) return;
29
30        this.focusedElement = document.activeElement;
31        this.focusedElement.blur();
32        this.wrapper.setAttribute('tabindex', '-1');
33        this.wrapper.style.outline = 'none';
34        setTimeout(() => {
35            this.wrapper.focus();
36            this.wrapper.addEventListener('keydown', this.handleKeydown);
37        }, this.timeout);
38    }
39
40    handleTrappedKeydown(event) {
41        if (event.key !== 'Tab') {
42            return;
43        }
44
45        const elements = this.getTrappedElements();
46        if (elements.length === 0) {
47            return;
48        }
49
50
51        const first = elements[0];
52        const last = elements[elements.length - 1];
53        if (event.shiftKey && document.activeElement === first) {
54            event.preventDefault();
55            last.focus();
56        } else if (!event.shiftKey && document.activeElement === last) {
57            event.preventDefault();
58            first.focus();
59        }
60    }
61
62    release() {
63        this.wrapper.removeEventListener('keydown', this.handleKeydown);
64        this.wrapper.removeAttribute('tabindex');
65        this.wrapper.style.outline = '';
66        clearTimeout(this.delay);
67        this.delay = setTimeout(() => {
68            this.focusedElement.focus();
69        }, 300);
70    }
71
72    static trapFocus(wrapper, timeout = 0) {
73        if (!wrapper.accessibility) {
74            wrapper.accessibility = new this(wrapper, timeout);
75        }
76        wrapper.accessibility.trap();
77    }
78
79    static releaseTrap(wrapper) {
80        if (!wrapper.accessibility) {
81            return;
82        }
83
84        setTimeout(() => {
85            wrapper.accessibility.release()
86        }, 100);
87    }
88
89    static isClick(event) {
90        return event.type == "click" || event.type == "touchend"
91    }
92
93    static processAction(event, callback, eventsList) {
94        if (eventsList && eventsList.indexOf(event.type) == -1) {
95            return;
96        }
97
98        if (this.isClick(event) || (event.type == "keyup" && event.key == 'Enter')) {
99            callback.call();
100        }
101    }
102}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.