Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / devtools / client / shared / focus.js
blob6248c69573ecfad2afec4d71b24a85e59fe3777a
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 /*
8  * Simplied selector targetting elements that can receive the focus, full
9  * version at http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus
10  */
11 const focusableSelector = [
12   "a[href]:not([tabindex='-1'])",
13   "button:not([disabled], [tabindex='-1'])",
14   "iframe:not([tabindex='-1'])",
15   "input:not([disabled], [tabindex='-1'])",
16   "select:not([disabled], [tabindex='-1'])",
17   "textarea:not([disabled], [tabindex='-1'])",
18   "[tabindex]:not([tabindex='-1'])",
19 ].join(", ");
21 /**
22  * Wrap and move keyboard focus to first/last focusable element inside a container
23  * element to prevent the focus from escaping the container.
24  *
25  * @param  {Array} elms
26  *         focusable elements inside a container
27  * @param  {DOMNode} current
28  *         currently focused element inside containter
29  * @param  {Boolean} back
30  *         direction
31  * @return {DOMNode}
32  *         newly focused element
33  */
34 function wrapMoveFocus(elms, current, back) {
35   let next;
37   if (elms.length === 0) {
38     return false;
39   }
41   if (back) {
42     if (elms.indexOf(current) === 0) {
43       next = elms[elms.length - 1];
44       next.focus();
45     }
46   } else if (elms.indexOf(current) === elms.length - 1) {
47     next = elms[0];
48     next.focus();
49   }
51   return next;
54 /**
55  * Get a list of all elements that are focusable with a keyboard inside the parent element
56  *
57  * @param  {DOMNode} parentEl
58  *         parent DOM element to be queried
59  * @return {Array}
60  *         array of focusable children elements inside the parent
61  */
62 function getFocusableElements(parentEl) {
63   return parentEl
64     ? Array.from(parentEl.querySelectorAll(focusableSelector))
65     : [];
68 // Make this available to both AMD and CJS environments
69 define(function (require, exports, module) {
70   module.exports.focusableSelector = focusableSelector;
71   exports.wrapMoveFocus = wrapMoveFocus;
72   exports.getFocusableElements = getFocusableElements;
73 });