wicg-inert 3.1.1 → 3.1.3
Sign up to get free protection for your applications and to get access to all the features.
- package/.travis.yml +1 -1
- package/LICENSE.md +1 -1
- package/README.md +4 -9
- package/demo/index.html +1 -1
- package/dist/inert.esm.js +17 -17
- package/dist/inert.js +17 -17
- package/dist/inert.min.js +1 -1
- package/dist/inert.min.js.map +1 -1
- package/explainer.md +1 -0
- package/karma.conf.js +8 -66
- package/package.json +8 -8
- package/security-privacy.md +90 -0
- package/src/inert.js +17 -16
- package/test/specs/element.spec.js +3 -3
- package/test/specs/helpers/index.js +1 -1
package/.travis.yml
CHANGED
package/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
All Reports in this Repository are licensed by Contributors
|
2
2
|
under the
|
3
|
-
[W3C Software and Document License](
|
3
|
+
[W3C Software and Document License](https://www.w3.org/Consortium/Legal/2023/software-license.html).
|
4
4
|
|
5
5
|
Contributions to Specifications are made under the
|
6
6
|
[W3C CLA](https://www.w3.org/community/about/agreements/cla/).
|
package/README.md
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
[![Build Status](https://travis-ci.org/WICG/inert.svg?branch=master)](https://travis-ci.org/WICG/inert)
|
2
|
-
|
3
1
|
The `inert` attribute/property allows web authors to mark parts of the DOM tree
|
4
2
|
as [inert](https://html.spec.whatwg.org/multipage/interaction.html#inert):
|
5
3
|
|
@@ -31,9 +29,7 @@ ensure the version you're using is stable and thoroughly tested.
|
|
31
29
|
This project provides two versions of the polyfill in `package.json`.
|
32
30
|
|
33
31
|
- `main`: Points at `dist/inert.js` which is transpiled to ES3.
|
34
|
-
- `module`: Points at `
|
35
|
-
JavaScript. See [#136](https://github.com/WICG/inert/issues/136) if
|
36
|
-
you would like to tell webpack to use the version in `main`.
|
32
|
+
- `module`: Points at `dist/inert.esm.js` which is transpiled to ES3.
|
37
33
|
|
38
34
|
_If you do want to build from source, make sure you clone the latest tag!_
|
39
35
|
|
@@ -74,12 +70,12 @@ In accordance with the W3C's new [polyfill
|
|
74
70
|
guidance](https://www.w3.org/2001/tag/doc/polyfills/#don-t-serve-unnecessary-polyfills),
|
75
71
|
the `inert` polyfill does not bundle other polyfills.
|
76
72
|
|
77
|
-
You can use a service like [
|
73
|
+
You can use a service like [https://cdnjs.cloudflare.com/polyfill](https://cdnjs.cloudflare.com/polyfill)
|
78
74
|
to download only the polyfills needed by the current browser. Just add the
|
79
75
|
following line to the start of your page:
|
80
76
|
|
81
77
|
```html
|
82
|
-
<script src="https://
|
78
|
+
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0&features=Map%2CSet%2CElement.prototype.matches%2CNode.prototype.contains"></script>
|
83
79
|
```
|
84
80
|
|
85
81
|
### Strict Content Security Policy
|
@@ -106,7 +102,6 @@ The stylesheet should include the following rules:
|
|
106
102
|
[inert], [inert] * {
|
107
103
|
user-select: none;
|
108
104
|
-webkit-user-select: none;
|
109
|
-
-moz-user-select: none;
|
110
105
|
-ms-user-select: none;
|
111
106
|
}
|
112
107
|
```
|
@@ -149,7 +144,7 @@ Promise.resolve().then(() => {
|
|
149
144
|
Tests are written using ES5 syntax. This is to avoid needing to transpile them
|
150
145
|
for older browsers. There are a few modern features they rely upon, e.g.
|
151
146
|
`Array.from` and `Promises`. These are polyfilled for the tests using
|
152
|
-
[
|
147
|
+
[https://cdnjs.cloudflare.com/polyfill](https://cdnjs.cloudflare.com/polyfill). For a list of polyfilled features, check out
|
153
148
|
the `polyfill` section in `karma.conf.js`.
|
154
149
|
|
155
150
|
### Big Thanks
|
package/demo/index.html
CHANGED
@@ -132,7 +132,7 @@ This work is licensed under the W3C Software and Document License
|
|
132
132
|
</div>
|
133
133
|
</section>
|
134
134
|
|
135
|
-
<script src="https://
|
135
|
+
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0&features=Map%2CSet%2CElement.prototype.matches%2CNode.prototype.contains"></script>
|
136
136
|
<script src="https://unpkg.com/wicg-inert"></script>
|
137
137
|
<script>
|
138
138
|
var toggler = document.querySelector('#toggle');
|
package/dist/inert.esm.js
CHANGED
@@ -9,7 +9,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
9
9
|
|
10
10
|
(function () {
|
11
11
|
// Return early if we're not running inside of the browser.
|
12
|
-
if (typeof window === 'undefined') {
|
12
|
+
if (typeof window === 'undefined' || typeof Element === 'undefined') {
|
13
13
|
return;
|
14
14
|
}
|
15
15
|
|
@@ -24,7 +24,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
24
24
|
var matches = Element.prototype.matches || Element.prototype.msMatchesSelector;
|
25
25
|
|
26
26
|
/** @type {string} */
|
27
|
-
var _focusableElementsString = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'details', 'summary', 'iframe', 'object', 'embed', '[contenteditable]'].join(',');
|
27
|
+
var _focusableElementsString = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'details', 'summary', 'iframe', 'object', 'embed', 'video', '[contenteditable]'].join(',');
|
28
28
|
|
29
29
|
/**
|
30
30
|
* `InertRoot` manages a single inert subtree, i.e. a DOM subtree whose root element has an `inert`
|
@@ -45,7 +45,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
45
45
|
|
46
46
|
var InertRoot = function () {
|
47
47
|
/**
|
48
|
-
* @param {!
|
48
|
+
* @param {!HTMLElement} rootElement The HTMLElement at the root of the inert subtree.
|
49
49
|
* @param {!InertManager} inertManager The global singleton InertManager object.
|
50
50
|
*/
|
51
51
|
function InertRoot(rootElement, inertManager) {
|
@@ -54,7 +54,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
54
54
|
/** @type {!InertManager} */
|
55
55
|
this._inertManager = inertManager;
|
56
56
|
|
57
|
-
/** @type {!
|
57
|
+
/** @type {!HTMLElement} */
|
58
58
|
this._rootElement = rootElement;
|
59
59
|
|
60
60
|
/**
|
@@ -176,7 +176,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
176
176
|
if (node.nodeType !== Node.ELEMENT_NODE) {
|
177
177
|
return;
|
178
178
|
}
|
179
|
-
var element = /** @type {!
|
179
|
+
var element = /** @type {!HTMLElement} */node;
|
180
180
|
|
181
181
|
// If a descendant inert root becomes un-inert, its descendants will still be inert because of
|
182
182
|
// this inert root, so all of its managed nodes need to be adopted by this InertRoot.
|
@@ -232,7 +232,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
232
232
|
|
233
233
|
/**
|
234
234
|
* If a descendant node is found with an `inert` attribute, adopt its managed nodes.
|
235
|
-
* @param {!
|
235
|
+
* @param {!HTMLElement} node
|
236
236
|
*/
|
237
237
|
|
238
238
|
}, {
|
@@ -262,7 +262,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
262
262
|
key: '_onMutation',
|
263
263
|
value: function _onMutation(records, self) {
|
264
264
|
records.forEach(function (record) {
|
265
|
-
var target = /** @type {!
|
265
|
+
var target = /** @type {!HTMLElement} */record.target;
|
266
266
|
if (record.type === 'childList') {
|
267
267
|
// Manage added nodes
|
268
268
|
slice.call(record.addedNodes).forEach(function (node) {
|
@@ -381,7 +381,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
381
381
|
this._throwIfDestroyed();
|
382
382
|
|
383
383
|
if (this._node && this._node.nodeType === Node.ELEMENT_NODE) {
|
384
|
-
var element = /** @type {!
|
384
|
+
var element = /** @type {!HTMLElement} */this._node;
|
385
385
|
if (this._savedTabIndex !== null) {
|
386
386
|
element.setAttribute('tabindex', this._savedTabIndex);
|
387
387
|
} else {
|
@@ -429,7 +429,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
429
429
|
if (this.node.nodeType !== Node.ELEMENT_NODE) {
|
430
430
|
return;
|
431
431
|
}
|
432
|
-
var element = /** @type {!
|
432
|
+
var element = /** @type {!HTMLElement} */this.node;
|
433
433
|
if (matches.call(element, _focusableElementsString)) {
|
434
434
|
if ( /** @type {!HTMLElement} */element.tabIndex === -1 && this.hasSavedTabIndex) {
|
435
435
|
return;
|
@@ -574,7 +574,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
574
574
|
|
575
575
|
/**
|
576
576
|
* Set whether the given element should be an inert root or not.
|
577
|
-
* @param {!
|
577
|
+
* @param {!HTMLElement} root
|
578
578
|
* @param {boolean} inert
|
579
579
|
*/
|
580
580
|
|
@@ -725,7 +725,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
725
725
|
if (record.attributeName !== 'inert') {
|
726
726
|
return;
|
727
727
|
}
|
728
|
-
var target = /** @type {!
|
728
|
+
var target = /** @type {!HTMLElement} */record.target;
|
729
729
|
var inert = target.hasAttribute('inert');
|
730
730
|
_this.setInert(target, inert);
|
731
731
|
break;
|
@@ -740,7 +740,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
740
740
|
/**
|
741
741
|
* Recursively walk the composed tree from |node|.
|
742
742
|
* @param {!Node} node
|
743
|
-
* @param {(function (!
|
743
|
+
* @param {(function (!HTMLElement))=} callback Callback to be called for each element traversed,
|
744
744
|
* before descending into child nodes.
|
745
745
|
* @param {?ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any.
|
746
746
|
*/
|
@@ -748,7 +748,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
748
748
|
|
749
749
|
function composedTreeWalk(node, callback, shadowRootAncestor) {
|
750
750
|
if (node.nodeType == Node.ELEMENT_NODE) {
|
751
|
-
var element = /** @type {!
|
751
|
+
var element = /** @type {!HTMLElement} */node;
|
752
752
|
if (callback) {
|
753
753
|
callback(element);
|
754
754
|
}
|
@@ -813,17 +813,17 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
813
813
|
node.appendChild(style);
|
814
814
|
}
|
815
815
|
|
816
|
-
if (!
|
816
|
+
if (!HTMLElement.prototype.hasOwnProperty('inert')) {
|
817
817
|
/** @type {!InertManager} */
|
818
818
|
var inertManager = new InertManager(document);
|
819
819
|
|
820
|
-
Object.defineProperty(
|
820
|
+
Object.defineProperty(HTMLElement.prototype, 'inert', {
|
821
821
|
enumerable: true,
|
822
|
-
/** @this {!
|
822
|
+
/** @this {!HTMLElement} */
|
823
823
|
get: function get() {
|
824
824
|
return this.hasAttribute('inert');
|
825
825
|
},
|
826
|
-
/** @this {!
|
826
|
+
/** @this {!HTMLElement} */
|
827
827
|
set: function set(inert) {
|
828
828
|
inertManager.setInert(this, inert);
|
829
829
|
}
|
package/dist/inert.js
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
|
16
16
|
(function () {
|
17
17
|
// Return early if we're not running inside of the browser.
|
18
|
-
if (typeof window === 'undefined') {
|
18
|
+
if (typeof window === 'undefined' || typeof Element === 'undefined') {
|
19
19
|
return;
|
20
20
|
}
|
21
21
|
|
@@ -30,7 +30,7 @@
|
|
30
30
|
var matches = Element.prototype.matches || Element.prototype.msMatchesSelector;
|
31
31
|
|
32
32
|
/** @type {string} */
|
33
|
-
var _focusableElementsString = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'details', 'summary', 'iframe', 'object', 'embed', '[contenteditable]'].join(',');
|
33
|
+
var _focusableElementsString = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'details', 'summary', 'iframe', 'object', 'embed', 'video', '[contenteditable]'].join(',');
|
34
34
|
|
35
35
|
/**
|
36
36
|
* `InertRoot` manages a single inert subtree, i.e. a DOM subtree whose root element has an `inert`
|
@@ -51,7 +51,7 @@
|
|
51
51
|
|
52
52
|
var InertRoot = function () {
|
53
53
|
/**
|
54
|
-
* @param {!
|
54
|
+
* @param {!HTMLElement} rootElement The HTMLElement at the root of the inert subtree.
|
55
55
|
* @param {!InertManager} inertManager The global singleton InertManager object.
|
56
56
|
*/
|
57
57
|
function InertRoot(rootElement, inertManager) {
|
@@ -60,7 +60,7 @@
|
|
60
60
|
/** @type {!InertManager} */
|
61
61
|
this._inertManager = inertManager;
|
62
62
|
|
63
|
-
/** @type {!
|
63
|
+
/** @type {!HTMLElement} */
|
64
64
|
this._rootElement = rootElement;
|
65
65
|
|
66
66
|
/**
|
@@ -182,7 +182,7 @@
|
|
182
182
|
if (node.nodeType !== Node.ELEMENT_NODE) {
|
183
183
|
return;
|
184
184
|
}
|
185
|
-
var element = /** @type {!
|
185
|
+
var element = /** @type {!HTMLElement} */node;
|
186
186
|
|
187
187
|
// If a descendant inert root becomes un-inert, its descendants will still be inert because of
|
188
188
|
// this inert root, so all of its managed nodes need to be adopted by this InertRoot.
|
@@ -238,7 +238,7 @@
|
|
238
238
|
|
239
239
|
/**
|
240
240
|
* If a descendant node is found with an `inert` attribute, adopt its managed nodes.
|
241
|
-
* @param {!
|
241
|
+
* @param {!HTMLElement} node
|
242
242
|
*/
|
243
243
|
|
244
244
|
}, {
|
@@ -268,7 +268,7 @@
|
|
268
268
|
key: '_onMutation',
|
269
269
|
value: function _onMutation(records, self) {
|
270
270
|
records.forEach(function (record) {
|
271
|
-
var target = /** @type {!
|
271
|
+
var target = /** @type {!HTMLElement} */record.target;
|
272
272
|
if (record.type === 'childList') {
|
273
273
|
// Manage added nodes
|
274
274
|
slice.call(record.addedNodes).forEach(function (node) {
|
@@ -387,7 +387,7 @@
|
|
387
387
|
this._throwIfDestroyed();
|
388
388
|
|
389
389
|
if (this._node && this._node.nodeType === Node.ELEMENT_NODE) {
|
390
|
-
var element = /** @type {!
|
390
|
+
var element = /** @type {!HTMLElement} */this._node;
|
391
391
|
if (this._savedTabIndex !== null) {
|
392
392
|
element.setAttribute('tabindex', this._savedTabIndex);
|
393
393
|
} else {
|
@@ -435,7 +435,7 @@
|
|
435
435
|
if (this.node.nodeType !== Node.ELEMENT_NODE) {
|
436
436
|
return;
|
437
437
|
}
|
438
|
-
var element = /** @type {!
|
438
|
+
var element = /** @type {!HTMLElement} */this.node;
|
439
439
|
if (matches.call(element, _focusableElementsString)) {
|
440
440
|
if ( /** @type {!HTMLElement} */element.tabIndex === -1 && this.hasSavedTabIndex) {
|
441
441
|
return;
|
@@ -580,7 +580,7 @@
|
|
580
580
|
|
581
581
|
/**
|
582
582
|
* Set whether the given element should be an inert root or not.
|
583
|
-
* @param {!
|
583
|
+
* @param {!HTMLElement} root
|
584
584
|
* @param {boolean} inert
|
585
585
|
*/
|
586
586
|
|
@@ -731,7 +731,7 @@
|
|
731
731
|
if (record.attributeName !== 'inert') {
|
732
732
|
return;
|
733
733
|
}
|
734
|
-
var target = /** @type {!
|
734
|
+
var target = /** @type {!HTMLElement} */record.target;
|
735
735
|
var inert = target.hasAttribute('inert');
|
736
736
|
_this.setInert(target, inert);
|
737
737
|
break;
|
@@ -746,7 +746,7 @@
|
|
746
746
|
/**
|
747
747
|
* Recursively walk the composed tree from |node|.
|
748
748
|
* @param {!Node} node
|
749
|
-
* @param {(function (!
|
749
|
+
* @param {(function (!HTMLElement))=} callback Callback to be called for each element traversed,
|
750
750
|
* before descending into child nodes.
|
751
751
|
* @param {?ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any.
|
752
752
|
*/
|
@@ -754,7 +754,7 @@
|
|
754
754
|
|
755
755
|
function composedTreeWalk(node, callback, shadowRootAncestor) {
|
756
756
|
if (node.nodeType == Node.ELEMENT_NODE) {
|
757
|
-
var element = /** @type {!
|
757
|
+
var element = /** @type {!HTMLElement} */node;
|
758
758
|
if (callback) {
|
759
759
|
callback(element);
|
760
760
|
}
|
@@ -819,17 +819,17 @@
|
|
819
819
|
node.appendChild(style);
|
820
820
|
}
|
821
821
|
|
822
|
-
if (!
|
822
|
+
if (!HTMLElement.prototype.hasOwnProperty('inert')) {
|
823
823
|
/** @type {!InertManager} */
|
824
824
|
var inertManager = new InertManager(document);
|
825
825
|
|
826
|
-
Object.defineProperty(
|
826
|
+
Object.defineProperty(HTMLElement.prototype, 'inert', {
|
827
827
|
enumerable: true,
|
828
|
-
/** @this {!
|
828
|
+
/** @this {!HTMLElement} */
|
829
829
|
get: function get() {
|
830
830
|
return this.hasAttribute('inert');
|
831
831
|
},
|
832
|
-
/** @this {!
|
832
|
+
/** @this {!HTMLElement} */
|
833
833
|
set: function set(inert) {
|
834
834
|
inertManager.setInert(this, inert);
|
835
835
|
}
|
package/dist/inert.min.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
!function(e
|
1
|
+
!function(e){("object"!=typeof exports||"undefined"==typeof module)&&"function"==typeof define&&define.amd?define("inert",e):e()}(function(){"use strict";var o,r,t,i,s,n,e=function(e,t,n){return t&&a(e.prototype,t),n&&a(e,n),e};function a(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function d(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function u(e,t){d(this,u),this._inertManager=t,this._rootElement=e,this._managedNodes=new Set,this._rootElement.hasAttribute("aria-hidden")?this._savedAriaHidden=this._rootElement.getAttribute("aria-hidden"):this._savedAriaHidden=null,this._rootElement.setAttribute("aria-hidden","true"),this._makeSubtreeUnfocusable(this._rootElement),this._observer=new MutationObserver(this._onMutation.bind(this)),this._observer.observe(this._rootElement,{attributes:!0,childList:!0,subtree:!0})}function h(e,t){d(this,h),this._node=e,this._overrodeFocusMethod=!1,this._inertRoots=new Set([t]),this._savedTabIndex=null,this._destroyed=!1,this.ensureUntabbable()}function l(e){if(d(this,l),!e)throw new Error("Missing required argument; InertManager needs to wrap a document.");this._document=e,this._managedNodes=new Map,this._inertRoots=new Map,this._observer=new MutationObserver(this._watchForInert.bind(this)),_(e.head||e.body||e.documentElement),"loading"===e.readyState?e.addEventListener("DOMContentLoaded",this._onDocumentLoaded.bind(this)):this._onDocumentLoaded()}function c(e,t,n){if(e.nodeType==Node.ELEMENT_NODE){var i=e,o=(t&&t(i),i.shadowRoot);if(o)return void c(o,t,o);if("content"==i.localName){for(var o=i,r=o.getDistributedNodes?o.getDistributedNodes():[],s=0;s<r.length;s++)c(r[s],t,n);return}if("slot"==i.localName){for(var o=i,a=o.assignedNodes?o.assignedNodes({flatten:!0}):[],d=0;d<a.length;d++)c(a[d],t,n);return}}for(var u=e.firstChild;null!=u;)c(u,t,n),u=u.nextSibling}function _(e){var t;e.querySelector("style#inert-style, link#inert-style")||((t=document.createElement("style")).setAttribute("id","inert-style"),t.textContent="\n[inert] {\n pointer-events: none;\n cursor: default;\n}\n\n[inert], [inert] * {\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n",e.appendChild(t))}"undefined"!=typeof window&&"undefined"!=typeof Element&&(o=Array.prototype.slice,r=Element.prototype.matches||Element.prototype.msMatchesSelector,t=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","details","summary","iframe","object","embed","video","[contenteditable]"].join(","),e(u,[{key:"destructor",value:function(){this._observer.disconnect(),this._rootElement&&(null!==this._savedAriaHidden?this._rootElement.setAttribute("aria-hidden",this._savedAriaHidden):this._rootElement.removeAttribute("aria-hidden")),this._managedNodes.forEach(function(e){this._unmanageNode(e.node)},this),this._observer=null,this._rootElement=null,this._managedNodes=null,this._inertManager=null}},{key:"_makeSubtreeUnfocusable",value:function(e){var t=this,n=(c(e,function(e){return t._visitNode(e)}),document.activeElement);if(!document.body.contains(e)){for(var i=e,o=void 0;i;){if(i.nodeType===Node.DOCUMENT_FRAGMENT_NODE){o=i;break}i=i.parentNode}o&&(n=o.activeElement)}e.contains(n)&&(n.blur(),n===document.activeElement&&document.body.focus())}},{key:"_visitNode",value:function(e){e.nodeType===Node.ELEMENT_NODE&&((e=e)!==this._rootElement&&e.hasAttribute("inert")&&this._adoptInertRoot(e),(r.call(e,t)||e.hasAttribute("tabindex"))&&this._manageNode(e))}},{key:"_manageNode",value:function(e){e=this._inertManager.register(e,this);this._managedNodes.add(e)}},{key:"_unmanageNode",value:function(e){e=this._inertManager.deregister(e,this);e&&this._managedNodes.delete(e)}},{key:"_unmanageSubtree",value:function(e){var t=this;c(e,function(e){return t._unmanageNode(e)})}},{key:"_adoptInertRoot",value:function(e){var t=this._inertManager.getInertRoot(e);t||(this._inertManager.setInert(e,!0),t=this._inertManager.getInertRoot(e)),t.managedNodes.forEach(function(e){this._manageNode(e.node)},this)}},{key:"_onMutation",value:function(e,t){e.forEach(function(e){var t,n=e.target;"childList"===e.type?(o.call(e.addedNodes).forEach(function(e){this._makeSubtreeUnfocusable(e)},this),o.call(e.removedNodes).forEach(function(e){this._unmanageSubtree(e)},this)):"attributes"===e.type&&("tabindex"===e.attributeName?this._manageNode(n):n!==this._rootElement&&"inert"===e.attributeName&&n.hasAttribute("inert")&&(this._adoptInertRoot(n),t=this._inertManager.getInertRoot(n),this._managedNodes.forEach(function(e){n.contains(e.node)&&t._manageNode(e.node)})))},this)}},{key:"managedNodes",get:function(){return new Set(this._managedNodes)}},{key:"hasSavedAriaHidden",get:function(){return null!==this._savedAriaHidden}},{key:"savedAriaHidden",set:function(e){this._savedAriaHidden=e},get:function(){return this._savedAriaHidden}}]),i=u,e(h,[{key:"destructor",value:function(){var e;this._throwIfDestroyed(),this._node&&this._node.nodeType===Node.ELEMENT_NODE&&(e=this._node,null!==this._savedTabIndex?e.setAttribute("tabindex",this._savedTabIndex):e.removeAttribute("tabindex"),this._overrodeFocusMethod&&delete e.focus),this._node=null,this._inertRoots=null,this._destroyed=!0}},{key:"_throwIfDestroyed",value:function(){if(this.destroyed)throw new Error("Trying to access destroyed InertNode")}},{key:"ensureUntabbable",value:function(){var e;this.node.nodeType===Node.ELEMENT_NODE&&(e=this.node,r.call(e,t)?-1===e.tabIndex&&this.hasSavedTabIndex||(e.hasAttribute("tabindex")&&(this._savedTabIndex=e.tabIndex),e.setAttribute("tabindex","-1"),e.nodeType===Node.ELEMENT_NODE&&(e.focus=function(){},this._overrodeFocusMethod=!0)):e.hasAttribute("tabindex")&&(this._savedTabIndex=e.tabIndex,e.removeAttribute("tabindex")))}},{key:"addInertRoot",value:function(e){this._throwIfDestroyed(),this._inertRoots.add(e)}},{key:"removeInertRoot",value:function(e){this._throwIfDestroyed(),this._inertRoots.delete(e),0===this._inertRoots.size&&this.destructor()}},{key:"destroyed",get:function(){return this._destroyed}},{key:"hasSavedTabIndex",get:function(){return null!==this._savedTabIndex}},{key:"node",get:function(){return this._throwIfDestroyed(),this._node}},{key:"savedTabIndex",set:function(e){this._throwIfDestroyed(),this._savedTabIndex=e},get:function(){return this._throwIfDestroyed(),this._savedTabIndex}}]),s=h,e(l,[{key:"setInert",value:function(e,t){if(t){if(!this._inertRoots.has(e)){t=new i(e,this);if(e.setAttribute("inert",""),this._inertRoots.set(e,t),!this._document.body.contains(e))for(var n=e.parentNode;n;)11===n.nodeType&&_(n),n=n.parentNode}}else this._inertRoots.has(e)&&(this._inertRoots.get(e).destructor(),this._inertRoots.delete(e),e.removeAttribute("inert"))}},{key:"getInertRoot",value:function(e){return this._inertRoots.get(e)}},{key:"register",value:function(e,t){var n=this._managedNodes.get(e);return void 0!==n?n.addInertRoot(t):n=new s(e,t),this._managedNodes.set(e,n),n}},{key:"deregister",value:function(e,t){var n=this._managedNodes.get(e);return n?(n.removeInertRoot(t),n.destroyed&&this._managedNodes.delete(e),n):null}},{key:"_onDocumentLoaded",value:function(){o.call(this._document.querySelectorAll("[inert]")).forEach(function(e){this.setInert(e,!0)},this),this._observer.observe(this._document.body||this._document.documentElement,{attributes:!0,subtree:!0,childList:!0})}},{key:"_watchForInert",value:function(e,t){var i=this;e.forEach(function(e){switch(e.type){case"childList":o.call(e.addedNodes).forEach(function(e){var t;e.nodeType===Node.ELEMENT_NODE&&(t=o.call(e.querySelectorAll("[inert]")),r.call(e,"[inert]")&&t.unshift(e),t.forEach(function(e){this.setInert(e,!0)},i))},i);break;case"attributes":if("inert"!==e.attributeName)return;var t=e.target,n=t.hasAttribute("inert");i.setInert(t,n)}},this)}}]),e=l,HTMLElement.prototype.hasOwnProperty("inert")||(n=new e(document),Object.defineProperty(HTMLElement.prototype,"inert",{enumerable:!0,get:function(){return this.hasAttribute("inert")},set:function(e){n.setInert(this,e)}})))});
|
2
2
|
//# sourceMappingURL=inert.min.js.map
|
package/dist/inert.min.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"inert.min.js","sources":["../src/inert.js"],"sourcesContent":["/**\n * This work is licensed under the W3C Software and Document License\n * (http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document).\n */\n\n(function() {\n // Return early if we're not running inside of the browser.\n if (typeof window === 'undefined') {\n return;\n }\n\n // Convenience function for converting NodeLists.\n /** @type {typeof Array.prototype.slice} */\n const slice = Array.prototype.slice;\n\n /**\n * IE has a non-standard name for \"matches\".\n * @type {typeof Element.prototype.matches}\n */\n const matches =\n Element.prototype.matches || Element.prototype.msMatchesSelector;\n\n /** @type {string} */\n const _focusableElementsString = ['a[href]',\n 'area[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'button:not([disabled])',\n 'details',\n 'summary',\n 'iframe',\n 'object',\n 'embed',\n '[contenteditable]'].join(',');\n\n /**\n * `InertRoot` manages a single inert subtree, i.e. a DOM subtree whose root element has an `inert`\n * attribute.\n *\n * Its main functions are:\n *\n * - to create and maintain a set of managed `InertNode`s, including when mutations occur in the\n * subtree. The `makeSubtreeUnfocusable()` method handles collecting `InertNode`s via registering\n * each focusable node in the subtree with the singleton `InertManager` which manages all known\n * focusable nodes within inert subtrees. `InertManager` ensures that a single `InertNode`\n * instance exists for each focusable node which has at least one inert root as an ancestor.\n *\n * - to notify all managed `InertNode`s when this subtree stops being inert (i.e. when the `inert`\n * attribute is removed from the root node). This is handled in the destructor, which calls the\n * `deregister` method on `InertManager` for each managed inert node.\n */\n class InertRoot {\n /**\n * @param {!Element} rootElement The Element at the root of the inert subtree.\n * @param {!InertManager} inertManager The global singleton InertManager object.\n */\n constructor(rootElement, inertManager) {\n /** @type {!InertManager} */\n this._inertManager = inertManager;\n\n /** @type {!Element} */\n this._rootElement = rootElement;\n\n /**\n * @type {!Set<!InertNode>}\n * All managed focusable nodes in this InertRoot's subtree.\n */\n this._managedNodes = new Set();\n\n // Make the subtree hidden from assistive technology\n if (this._rootElement.hasAttribute('aria-hidden')) {\n /** @type {?string} */\n this._savedAriaHidden = this._rootElement.getAttribute('aria-hidden');\n } else {\n this._savedAriaHidden = null;\n }\n this._rootElement.setAttribute('aria-hidden', 'true');\n\n // Make all focusable elements in the subtree unfocusable and add them to _managedNodes\n this._makeSubtreeUnfocusable(this._rootElement);\n\n // Watch for:\n // - any additions in the subtree: make them unfocusable too\n // - any removals from the subtree: remove them from this inert root's managed nodes\n // - attribute changes: if `tabindex` is added, or removed from an intrinsically focusable\n // element, make that node a managed node.\n this._observer = new MutationObserver(this._onMutation.bind(this));\n this._observer.observe(this._rootElement, {attributes: true, childList: true, subtree: true});\n }\n\n /**\n * Call this whenever this object is about to become obsolete. This unwinds all of the state\n * stored in this object and updates the state of all of the managed nodes.\n */\n destructor() {\n this._observer.disconnect();\n\n if (this._rootElement) {\n if (this._savedAriaHidden !== null) {\n this._rootElement.setAttribute('aria-hidden', this._savedAriaHidden);\n } else {\n this._rootElement.removeAttribute('aria-hidden');\n }\n }\n\n this._managedNodes.forEach(function(inertNode) {\n this._unmanageNode(inertNode.node);\n }, this);\n\n // Note we cast the nulls to the ANY type here because:\n // 1) We want the class properties to be declared as non-null, or else we\n // need even more casts throughout this code. All bets are off if an\n // instance has been destroyed and a method is called.\n // 2) We don't want to cast \"this\", because we want type-aware optimizations\n // to know which properties we're setting.\n this._observer = /** @type {?} */ (null);\n this._rootElement = /** @type {?} */ (null);\n this._managedNodes = /** @type {?} */ (null);\n this._inertManager = /** @type {?} */ (null);\n }\n\n /**\n * @return {!Set<!InertNode>} A copy of this InertRoot's managed nodes set.\n */\n get managedNodes() {\n return new Set(this._managedNodes);\n }\n\n /** @return {boolean} */\n get hasSavedAriaHidden() {\n return this._savedAriaHidden !== null;\n }\n\n /** @param {?string} ariaHidden */\n set savedAriaHidden(ariaHidden) {\n this._savedAriaHidden = ariaHidden;\n }\n\n /** @return {?string} */\n get savedAriaHidden() {\n return this._savedAriaHidden;\n }\n\n /**\n * @param {!Node} startNode\n */\n _makeSubtreeUnfocusable(startNode) {\n composedTreeWalk(startNode, (node) => this._visitNode(node));\n\n let activeElement = document.activeElement;\n\n if (!document.body.contains(startNode)) {\n // startNode may be in shadow DOM, so find its nearest shadowRoot to get the activeElement.\n let node = startNode;\n /** @type {!ShadowRoot|undefined} */\n let root = undefined;\n while (node) {\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n root = /** @type {!ShadowRoot} */ (node);\n break;\n }\n node = node.parentNode;\n }\n if (root) {\n activeElement = root.activeElement;\n }\n }\n if (startNode.contains(activeElement)) {\n activeElement.blur();\n // In IE11, if an element is already focused, and then set to tabindex=-1\n // calling blur() will not actually move the focus.\n // To work around this we call focus() on the body instead.\n if (activeElement === document.activeElement) {\n document.body.focus();\n }\n }\n }\n\n /**\n * @param {!Node} node\n */\n _visitNode(node) {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return;\n }\n const element = /** @type {!Element} */ (node);\n\n // If a descendant inert root becomes un-inert, its descendants will still be inert because of\n // this inert root, so all of its managed nodes need to be adopted by this InertRoot.\n if (element !== this._rootElement && element.hasAttribute('inert')) {\n this._adoptInertRoot(element);\n }\n\n if (matches.call(element, _focusableElementsString) || element.hasAttribute('tabindex')) {\n this._manageNode(element);\n }\n }\n\n /**\n * Register the given node with this InertRoot and with InertManager.\n * @param {!Node} node\n */\n _manageNode(node) {\n const inertNode = this._inertManager.register(node, this);\n this._managedNodes.add(inertNode);\n }\n\n /**\n * Unregister the given node with this InertRoot and with InertManager.\n * @param {!Node} node\n */\n _unmanageNode(node) {\n const inertNode = this._inertManager.deregister(node, this);\n if (inertNode) {\n this._managedNodes.delete(inertNode);\n }\n }\n\n /**\n * Unregister the entire subtree starting at `startNode`.\n * @param {!Node} startNode\n */\n _unmanageSubtree(startNode) {\n composedTreeWalk(startNode, (node) => this._unmanageNode(node));\n }\n\n /**\n * If a descendant node is found with an `inert` attribute, adopt its managed nodes.\n * @param {!Element} node\n */\n _adoptInertRoot(node) {\n let inertSubroot = this._inertManager.getInertRoot(node);\n\n // During initialisation this inert root may not have been registered yet,\n // so register it now if need be.\n if (!inertSubroot) {\n this._inertManager.setInert(node, true);\n inertSubroot = this._inertManager.getInertRoot(node);\n }\n\n inertSubroot.managedNodes.forEach(function(savedInertNode) {\n this._manageNode(savedInertNode.node);\n }, this);\n }\n\n /**\n * Callback used when mutation observer detects subtree additions, removals, or attribute changes.\n * @param {!Array<!MutationRecord>} records\n * @param {!MutationObserver} self\n */\n _onMutation(records, self) {\n records.forEach(function(record) {\n const target = /** @type {!Element} */ (record.target);\n if (record.type === 'childList') {\n // Manage added nodes\n slice.call(record.addedNodes).forEach(function(node) {\n this._makeSubtreeUnfocusable(node);\n }, this);\n\n // Un-manage removed nodes\n slice.call(record.removedNodes).forEach(function(node) {\n this._unmanageSubtree(node);\n }, this);\n } else if (record.type === 'attributes') {\n if (record.attributeName === 'tabindex') {\n // Re-initialise inert node if tabindex changes\n this._manageNode(target);\n } else if (target !== this._rootElement &&\n record.attributeName === 'inert' &&\n target.hasAttribute('inert')) {\n // If a new inert root is added, adopt its managed nodes and make sure it knows about the\n // already managed nodes from this inert subroot.\n this._adoptInertRoot(target);\n const inertSubroot = this._inertManager.getInertRoot(target);\n this._managedNodes.forEach(function(managedNode) {\n if (target.contains(managedNode.node)) {\n inertSubroot._manageNode(managedNode.node);\n }\n });\n }\n }\n }, this);\n }\n }\n\n /**\n * `InertNode` initialises and manages a single inert node.\n * A node is inert if it is a descendant of one or more inert root elements.\n *\n * On construction, `InertNode` saves the existing `tabindex` value for the node, if any, and\n * either removes the `tabindex` attribute or sets it to `-1`, depending on whether the element\n * is intrinsically focusable or not.\n *\n * `InertNode` maintains a set of `InertRoot`s which are descendants of this `InertNode`. When an\n * `InertRoot` is destroyed, and calls `InertManager.deregister()`, the `InertManager` notifies the\n * `InertNode` via `removeInertRoot()`, which in turn destroys the `InertNode` if no `InertRoot`s\n * remain in the set. On destruction, `InertNode` reinstates the stored `tabindex` if one exists,\n * or removes the `tabindex` attribute if the element is intrinsically focusable.\n */\n class InertNode {\n /**\n * @param {!Node} node A focusable element to be made inert.\n * @param {!InertRoot} inertRoot The inert root element associated with this inert node.\n */\n constructor(node, inertRoot) {\n /** @type {!Node} */\n this._node = node;\n\n /** @type {boolean} */\n this._overrodeFocusMethod = false;\n\n /**\n * @type {!Set<!InertRoot>} The set of descendant inert roots.\n * If and only if this set becomes empty, this node is no longer inert.\n */\n this._inertRoots = new Set([inertRoot]);\n\n /** @type {?number} */\n this._savedTabIndex = null;\n\n /** @type {boolean} */\n this._destroyed = false;\n\n // Save any prior tabindex info and make this node untabbable\n this.ensureUntabbable();\n }\n\n /**\n * Call this whenever this object is about to become obsolete.\n * This makes the managed node focusable again and deletes all of the previously stored state.\n */\n destructor() {\n this._throwIfDestroyed();\n\n if (this._node && this._node.nodeType === Node.ELEMENT_NODE) {\n const element = /** @type {!Element} */ (this._node);\n if (this._savedTabIndex !== null) {\n element.setAttribute('tabindex', this._savedTabIndex);\n } else {\n element.removeAttribute('tabindex');\n }\n\n // Use `delete` to restore native focus method.\n if (this._overrodeFocusMethod) {\n delete element.focus;\n }\n }\n\n // See note in InertRoot.destructor for why we cast these nulls to ANY.\n this._node = /** @type {?} */ (null);\n this._inertRoots = /** @type {?} */ (null);\n this._destroyed = true;\n }\n\n /**\n * @type {boolean} Whether this object is obsolete because the managed node is no longer inert.\n * If the object has been destroyed, any attempt to access it will cause an exception.\n */\n get destroyed() {\n return /** @type {!InertNode} */ (this)._destroyed;\n }\n\n /**\n * Throw if user tries to access destroyed InertNode.\n */\n _throwIfDestroyed() {\n if (this.destroyed) {\n throw new Error('Trying to access destroyed InertNode');\n }\n }\n\n /** @return {boolean} */\n get hasSavedTabIndex() {\n return this._savedTabIndex !== null;\n }\n\n /** @return {!Node} */\n get node() {\n this._throwIfDestroyed();\n return this._node;\n }\n\n /** @param {?number} tabIndex */\n set savedTabIndex(tabIndex) {\n this._throwIfDestroyed();\n this._savedTabIndex = tabIndex;\n }\n\n /** @return {?number} */\n get savedTabIndex() {\n this._throwIfDestroyed();\n return this._savedTabIndex;\n }\n\n /** Save the existing tabindex value and make the node untabbable and unfocusable */\n ensureUntabbable() {\n if (this.node.nodeType !== Node.ELEMENT_NODE) {\n return;\n }\n const element = /** @type {!Element} */ (this.node);\n if (matches.call(element, _focusableElementsString)) {\n if (/** @type {!HTMLElement} */ (element).tabIndex === -1 &&\n this.hasSavedTabIndex) {\n return;\n }\n\n if (element.hasAttribute('tabindex')) {\n this._savedTabIndex = /** @type {!HTMLElement} */ (element).tabIndex;\n }\n element.setAttribute('tabindex', '-1');\n if (element.nodeType === Node.ELEMENT_NODE) {\n element.focus = function() {};\n this._overrodeFocusMethod = true;\n }\n } else if (element.hasAttribute('tabindex')) {\n this._savedTabIndex = /** @type {!HTMLElement} */ (element).tabIndex;\n element.removeAttribute('tabindex');\n }\n }\n\n /**\n * Add another inert root to this inert node's set of managing inert roots.\n * @param {!InertRoot} inertRoot\n */\n addInertRoot(inertRoot) {\n this._throwIfDestroyed();\n this._inertRoots.add(inertRoot);\n }\n\n /**\n * Remove the given inert root from this inert node's set of managing inert roots.\n * If the set of managing inert roots becomes empty, this node is no longer inert,\n * so the object should be destroyed.\n * @param {!InertRoot} inertRoot\n */\n removeInertRoot(inertRoot) {\n this._throwIfDestroyed();\n this._inertRoots.delete(inertRoot);\n if (this._inertRoots.size === 0) {\n this.destructor();\n }\n }\n }\n\n /**\n * InertManager is a per-document singleton object which manages all inert roots and nodes.\n *\n * When an element becomes an inert root by having an `inert` attribute set and/or its `inert`\n * property set to `true`, the `setInert` method creates an `InertRoot` object for the element.\n * The `InertRoot` in turn registers itself as managing all of the element's focusable descendant\n * nodes via the `register()` method. The `InertManager` ensures that a single `InertNode` instance\n * is created for each such node, via the `_managedNodes` map.\n */\n class InertManager {\n /**\n * @param {!Document} document\n */\n constructor(document) {\n if (!document) {\n throw new Error('Missing required argument; InertManager needs to wrap a document.');\n }\n\n /** @type {!Document} */\n this._document = document;\n\n /**\n * All managed nodes known to this InertManager. In a map to allow looking up by Node.\n * @type {!Map<!Node, !InertNode>}\n */\n this._managedNodes = new Map();\n\n /**\n * All inert roots known to this InertManager. In a map to allow looking up by Node.\n * @type {!Map<!Node, !InertRoot>}\n */\n this._inertRoots = new Map();\n\n /**\n * Observer for mutations on `document.body`.\n * @type {!MutationObserver}\n */\n this._observer = new MutationObserver(this._watchForInert.bind(this));\n\n // Add inert style.\n addInertStyle(document.head || document.body || document.documentElement);\n\n // Wait for document to be loaded.\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', this._onDocumentLoaded.bind(this));\n } else {\n this._onDocumentLoaded();\n }\n }\n\n /**\n * Set whether the given element should be an inert root or not.\n * @param {!Element} root\n * @param {boolean} inert\n */\n setInert(root, inert) {\n if (inert) {\n if (this._inertRoots.has(root)) { // element is already inert\n return;\n }\n\n const inertRoot = new InertRoot(root, this);\n root.setAttribute('inert', '');\n this._inertRoots.set(root, inertRoot);\n // If not contained in the document, it must be in a shadowRoot.\n // Ensure inert styles are added there.\n if (!this._document.body.contains(root)) {\n let parent = root.parentNode;\n while (parent) {\n if (parent.nodeType === 11) {\n addInertStyle(parent);\n }\n parent = parent.parentNode;\n }\n }\n } else {\n if (!this._inertRoots.has(root)) { // element is already non-inert\n return;\n }\n\n const inertRoot = this._inertRoots.get(root);\n inertRoot.destructor();\n this._inertRoots.delete(root);\n root.removeAttribute('inert');\n }\n }\n\n /**\n * Get the InertRoot object corresponding to the given inert root element, if any.\n * @param {!Node} element\n * @return {!InertRoot|undefined}\n */\n getInertRoot(element) {\n return this._inertRoots.get(element);\n }\n\n /**\n * Register the given InertRoot as managing the given node.\n * In the case where the node has a previously existing inert root, this inert root will\n * be added to its set of inert roots.\n * @param {!Node} node\n * @param {!InertRoot} inertRoot\n * @return {!InertNode} inertNode\n */\n register(node, inertRoot) {\n let inertNode = this._managedNodes.get(node);\n if (inertNode !== undefined) { // node was already in an inert subtree\n inertNode.addInertRoot(inertRoot);\n } else {\n inertNode = new InertNode(node, inertRoot);\n }\n\n this._managedNodes.set(node, inertNode);\n\n return inertNode;\n }\n\n /**\n * De-register the given InertRoot as managing the given inert node.\n * Removes the inert root from the InertNode's set of managing inert roots, and remove the inert\n * node from the InertManager's set of managed nodes if it is destroyed.\n * If the node is not currently managed, this is essentially a no-op.\n * @param {!Node} node\n * @param {!InertRoot} inertRoot\n * @return {?InertNode} The potentially destroyed InertNode associated with this node, if any.\n */\n deregister(node, inertRoot) {\n const inertNode = this._managedNodes.get(node);\n if (!inertNode) {\n return null;\n }\n\n inertNode.removeInertRoot(inertRoot);\n if (inertNode.destroyed) {\n this._managedNodes.delete(node);\n }\n\n return inertNode;\n }\n\n /**\n * Callback used when document has finished loading.\n */\n _onDocumentLoaded() {\n // Find all inert roots in document and make them actually inert.\n const inertElements = slice.call(this._document.querySelectorAll('[inert]'));\n inertElements.forEach(function(inertElement) {\n this.setInert(inertElement, true);\n }, this);\n\n // Comment this out to use programmatic API only.\n this._observer.observe(this._document.body || this._document.documentElement, {attributes: true, subtree: true, childList: true});\n }\n\n /**\n * Callback used when mutation observer detects attribute changes.\n * @param {!Array<!MutationRecord>} records\n * @param {!MutationObserver} self\n */\n _watchForInert(records, self) {\n const _this = this;\n records.forEach(function(record) {\n switch (record.type) {\n case 'childList':\n slice.call(record.addedNodes).forEach(function(node) {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return;\n }\n const inertElements = slice.call(node.querySelectorAll('[inert]'));\n if (matches.call(node, '[inert]')) {\n inertElements.unshift(node);\n }\n inertElements.forEach(function(inertElement) {\n this.setInert(inertElement, true);\n }, _this);\n }, _this);\n break;\n case 'attributes':\n if (record.attributeName !== 'inert') {\n return;\n }\n const target = /** @type {!Element} */ (record.target);\n const inert = target.hasAttribute('inert');\n _this.setInert(target, inert);\n break;\n }\n }, this);\n }\n }\n\n /**\n * Recursively walk the composed tree from |node|.\n * @param {!Node} node\n * @param {(function (!Element))=} callback Callback to be called for each element traversed,\n * before descending into child nodes.\n * @param {?ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any.\n */\n function composedTreeWalk(node, callback, shadowRootAncestor) {\n if (node.nodeType == Node.ELEMENT_NODE) {\n const element = /** @type {!Element} */ (node);\n if (callback) {\n callback(element);\n }\n\n // Descend into node:\n // If it has a ShadowRoot, ignore all child elements - these will be picked\n // up by the <content> or <shadow> elements. Descend straight into the\n // ShadowRoot.\n const shadowRoot = /** @type {!HTMLElement} */ (element).shadowRoot;\n if (shadowRoot) {\n composedTreeWalk(shadowRoot, callback, shadowRoot);\n return;\n }\n\n // If it is a <content> element, descend into distributed elements - these\n // are elements from outside the shadow root which are rendered inside the\n // shadow DOM.\n if (element.localName == 'content') {\n const content = /** @type {!HTMLContentElement} */ (element);\n // Verifies if ShadowDom v0 is supported.\n const distributedNodes = content.getDistributedNodes ?\n content.getDistributedNodes() : [];\n for (let i = 0; i < distributedNodes.length; i++) {\n composedTreeWalk(distributedNodes[i], callback, shadowRootAncestor);\n }\n return;\n }\n\n // If it is a <slot> element, descend into assigned nodes - these\n // are elements from outside the shadow root which are rendered inside the\n // shadow DOM.\n if (element.localName == 'slot') {\n const slot = /** @type {!HTMLSlotElement} */ (element);\n // Verify if ShadowDom v1 is supported.\n const distributedNodes = slot.assignedNodes ?\n slot.assignedNodes({flatten: true}) : [];\n for (let i = 0; i < distributedNodes.length; i++) {\n composedTreeWalk(distributedNodes[i], callback, shadowRootAncestor);\n }\n return;\n }\n }\n\n // If it is neither the parent of a ShadowRoot, a <content> element, a <slot>\n // element, nor a <shadow> element recurse normally.\n let child = node.firstChild;\n while (child != null) {\n composedTreeWalk(child, callback, shadowRootAncestor);\n child = child.nextSibling;\n }\n }\n\n /**\n * Adds a style element to the node containing the inert specific styles\n * @param {!Node} node\n */\n function addInertStyle(node) {\n if (node.querySelector('style#inert-style, link#inert-style')) {\n return;\n }\n const style = document.createElement('style');\n style.setAttribute('id', 'inert-style');\n style.textContent = '\\n'+\n '[inert] {\\n' +\n ' pointer-events: none;\\n' +\n ' cursor: default;\\n' +\n '}\\n' +\n '\\n' +\n '[inert], [inert] * {\\n' +\n ' -webkit-user-select: none;\\n' +\n ' -moz-user-select: none;\\n' +\n ' -ms-user-select: none;\\n' +\n ' user-select: none;\\n' +\n '}\\n';\n node.appendChild(style);\n }\n\n if (!Element.prototype.hasOwnProperty('inert')) {\n /** @type {!InertManager} */\n const inertManager = new InertManager(document);\n \n Object.defineProperty(Element.prototype, 'inert', {\n enumerable: true,\n /** @this {!Element} */\n get: function() {\n return this.hasAttribute('inert');\n },\n /** @this {!Element} */\n set: function(inert) {\n inertManager.setInert(this, inert);\n },\n });\n }\n})();\n"],"names":["window","slice","Array","prototype","matches","Element","msMatchesSelector","_focusableElementsString","join","InertRoot","rootElement","inertManager","_inertManager","_rootElement","_managedNodes","Set","this","hasAttribute","_savedAriaHidden","getAttribute","setAttribute","_makeSubtreeUnfocusable","_observer","MutationObserver","_onMutation","bind","observe","attributes","childList","subtree","disconnect","removeAttribute","forEach","inertNode","_unmanageNode","node","startNode","_this2","_visitNode","activeElement","document","body","contains","root","undefined","nodeType","Node","DOCUMENT_FRAGMENT_NODE","parentNode","blur","focus","ELEMENT_NODE","element","_adoptInertRoot","call","_manageNode","register","add","deregister","_this3","inertSubroot","getInertRoot","setInert","managedNodes","savedInertNode","records","self","record","target","type","addedNodes","removedNodes","_unmanageSubtree","attributeName","managedNode","ariaHidden","InertNode","inertRoot","_node","_overrodeFocusMethod","_inertRoots","_savedTabIndex","_destroyed","ensureUntabbable","_throwIfDestroyed","destroyed","Error","tabIndex","hasSavedTabIndex","size","destructor","InertManager","_document","Map","_watchForInert","head","documentElement","readyState","addEventListener","_onDocumentLoaded","inert","has","set","parent","get","addInertRoot","removeInertRoot","querySelectorAll","inertElement","_this","inertElements","unshift","hasOwnProperty","defineProperty","composedTreeWalk","callback","shadowRootAncestor","shadowRoot","localName","content","distributedNodes","getDistributedNodes","i","length","slot","assignedNodes","flatten","child","firstChild","nextSibling","addInertStyle","querySelector","style","createElement","textContent","appendChild"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"inert.min.js","sources":["../src/inert.js"],"sourcesContent":["/**\n * This work is licensed under the W3C Software and Document License\n * (http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document).\n */\n\n(function() {\n // Return early if we're not running inside of the browser.\n if (typeof window === 'undefined' || typeof Element === 'undefined') {\n return;\n }\n\n // Convenience function for converting NodeLists.\n /** @type {typeof Array.prototype.slice} */\n const slice = Array.prototype.slice;\n\n /**\n * IE has a non-standard name for \"matches\".\n * @type {typeof Element.prototype.matches}\n */\n const matches =\n Element.prototype.matches || Element.prototype.msMatchesSelector;\n\n /** @type {string} */\n const _focusableElementsString = ['a[href]',\n 'area[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'button:not([disabled])',\n 'details',\n 'summary',\n 'iframe',\n 'object',\n 'embed',\n 'video',\n '[contenteditable]'].join(',');\n\n /**\n * `InertRoot` manages a single inert subtree, i.e. a DOM subtree whose root element has an `inert`\n * attribute.\n *\n * Its main functions are:\n *\n * - to create and maintain a set of managed `InertNode`s, including when mutations occur in the\n * subtree. The `makeSubtreeUnfocusable()` method handles collecting `InertNode`s via registering\n * each focusable node in the subtree with the singleton `InertManager` which manages all known\n * focusable nodes within inert subtrees. `InertManager` ensures that a single `InertNode`\n * instance exists for each focusable node which has at least one inert root as an ancestor.\n *\n * - to notify all managed `InertNode`s when this subtree stops being inert (i.e. when the `inert`\n * attribute is removed from the root node). This is handled in the destructor, which calls the\n * `deregister` method on `InertManager` for each managed inert node.\n */\n class InertRoot {\n /**\n * @param {!HTMLElement} rootElement The HTMLElement at the root of the inert subtree.\n * @param {!InertManager} inertManager The global singleton InertManager object.\n */\n constructor(rootElement, inertManager) {\n /** @type {!InertManager} */\n this._inertManager = inertManager;\n\n /** @type {!HTMLElement} */\n this._rootElement = rootElement;\n\n /**\n * @type {!Set<!InertNode>}\n * All managed focusable nodes in this InertRoot's subtree.\n */\n this._managedNodes = new Set();\n\n // Make the subtree hidden from assistive technology\n if (this._rootElement.hasAttribute('aria-hidden')) {\n /** @type {?string} */\n this._savedAriaHidden = this._rootElement.getAttribute('aria-hidden');\n } else {\n this._savedAriaHidden = null;\n }\n this._rootElement.setAttribute('aria-hidden', 'true');\n\n // Make all focusable elements in the subtree unfocusable and add them to _managedNodes\n this._makeSubtreeUnfocusable(this._rootElement);\n\n // Watch for:\n // - any additions in the subtree: make them unfocusable too\n // - any removals from the subtree: remove them from this inert root's managed nodes\n // - attribute changes: if `tabindex` is added, or removed from an intrinsically focusable\n // element, make that node a managed node.\n this._observer = new MutationObserver(this._onMutation.bind(this));\n this._observer.observe(this._rootElement, {attributes: true, childList: true, subtree: true});\n }\n\n /**\n * Call this whenever this object is about to become obsolete. This unwinds all of the state\n * stored in this object and updates the state of all of the managed nodes.\n */\n destructor() {\n this._observer.disconnect();\n\n if (this._rootElement) {\n if (this._savedAriaHidden !== null) {\n this._rootElement.setAttribute('aria-hidden', this._savedAriaHidden);\n } else {\n this._rootElement.removeAttribute('aria-hidden');\n }\n }\n\n this._managedNodes.forEach(function(inertNode) {\n this._unmanageNode(inertNode.node);\n }, this);\n\n // Note we cast the nulls to the ANY type here because:\n // 1) We want the class properties to be declared as non-null, or else we\n // need even more casts throughout this code. All bets are off if an\n // instance has been destroyed and a method is called.\n // 2) We don't want to cast \"this\", because we want type-aware optimizations\n // to know which properties we're setting.\n this._observer = /** @type {?} */ (null);\n this._rootElement = /** @type {?} */ (null);\n this._managedNodes = /** @type {?} */ (null);\n this._inertManager = /** @type {?} */ (null);\n }\n\n /**\n * @return {!Set<!InertNode>} A copy of this InertRoot's managed nodes set.\n */\n get managedNodes() {\n return new Set(this._managedNodes);\n }\n\n /** @return {boolean} */\n get hasSavedAriaHidden() {\n return this._savedAriaHidden !== null;\n }\n\n /** @param {?string} ariaHidden */\n set savedAriaHidden(ariaHidden) {\n this._savedAriaHidden = ariaHidden;\n }\n\n /** @return {?string} */\n get savedAriaHidden() {\n return this._savedAriaHidden;\n }\n\n /**\n * @param {!Node} startNode\n */\n _makeSubtreeUnfocusable(startNode) {\n composedTreeWalk(startNode, (node) => this._visitNode(node));\n\n let activeElement = document.activeElement;\n\n if (!document.body.contains(startNode)) {\n // startNode may be in shadow DOM, so find its nearest shadowRoot to get the activeElement.\n let node = startNode;\n /** @type {!ShadowRoot|undefined} */\n let root = undefined;\n while (node) {\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n root = /** @type {!ShadowRoot} */ (node);\n break;\n }\n node = node.parentNode;\n }\n if (root) {\n activeElement = root.activeElement;\n }\n }\n if (startNode.contains(activeElement)) {\n activeElement.blur();\n // In IE11, if an element is already focused, and then set to tabindex=-1\n // calling blur() will not actually move the focus.\n // To work around this we call focus() on the body instead.\n if (activeElement === document.activeElement) {\n document.body.focus();\n }\n }\n }\n\n /**\n * @param {!Node} node\n */\n _visitNode(node) {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return;\n }\n const element = /** @type {!HTMLElement} */ (node);\n\n // If a descendant inert root becomes un-inert, its descendants will still be inert because of\n // this inert root, so all of its managed nodes need to be adopted by this InertRoot.\n if (element !== this._rootElement && element.hasAttribute('inert')) {\n this._adoptInertRoot(element);\n }\n\n if (matches.call(element, _focusableElementsString) || element.hasAttribute('tabindex')) {\n this._manageNode(element);\n }\n }\n\n /**\n * Register the given node with this InertRoot and with InertManager.\n * @param {!Node} node\n */\n _manageNode(node) {\n const inertNode = this._inertManager.register(node, this);\n this._managedNodes.add(inertNode);\n }\n\n /**\n * Unregister the given node with this InertRoot and with InertManager.\n * @param {!Node} node\n */\n _unmanageNode(node) {\n const inertNode = this._inertManager.deregister(node, this);\n if (inertNode) {\n this._managedNodes.delete(inertNode);\n }\n }\n\n /**\n * Unregister the entire subtree starting at `startNode`.\n * @param {!Node} startNode\n */\n _unmanageSubtree(startNode) {\n composedTreeWalk(startNode, (node) => this._unmanageNode(node));\n }\n\n /**\n * If a descendant node is found with an `inert` attribute, adopt its managed nodes.\n * @param {!HTMLElement} node\n */\n _adoptInertRoot(node) {\n let inertSubroot = this._inertManager.getInertRoot(node);\n\n // During initialisation this inert root may not have been registered yet,\n // so register it now if need be.\n if (!inertSubroot) {\n this._inertManager.setInert(node, true);\n inertSubroot = this._inertManager.getInertRoot(node);\n }\n\n inertSubroot.managedNodes.forEach(function(savedInertNode) {\n this._manageNode(savedInertNode.node);\n }, this);\n }\n\n /**\n * Callback used when mutation observer detects subtree additions, removals, or attribute changes.\n * @param {!Array<!MutationRecord>} records\n * @param {!MutationObserver} self\n */\n _onMutation(records, self) {\n records.forEach(function(record) {\n const target = /** @type {!HTMLElement} */ (record.target);\n if (record.type === 'childList') {\n // Manage added nodes\n slice.call(record.addedNodes).forEach(function(node) {\n this._makeSubtreeUnfocusable(node);\n }, this);\n\n // Un-manage removed nodes\n slice.call(record.removedNodes).forEach(function(node) {\n this._unmanageSubtree(node);\n }, this);\n } else if (record.type === 'attributes') {\n if (record.attributeName === 'tabindex') {\n // Re-initialise inert node if tabindex changes\n this._manageNode(target);\n } else if (target !== this._rootElement &&\n record.attributeName === 'inert' &&\n target.hasAttribute('inert')) {\n // If a new inert root is added, adopt its managed nodes and make sure it knows about the\n // already managed nodes from this inert subroot.\n this._adoptInertRoot(target);\n const inertSubroot = this._inertManager.getInertRoot(target);\n this._managedNodes.forEach(function(managedNode) {\n if (target.contains(managedNode.node)) {\n inertSubroot._manageNode(managedNode.node);\n }\n });\n }\n }\n }, this);\n }\n }\n\n /**\n * `InertNode` initialises and manages a single inert node.\n * A node is inert if it is a descendant of one or more inert root elements.\n *\n * On construction, `InertNode` saves the existing `tabindex` value for the node, if any, and\n * either removes the `tabindex` attribute or sets it to `-1`, depending on whether the element\n * is intrinsically focusable or not.\n *\n * `InertNode` maintains a set of `InertRoot`s which are descendants of this `InertNode`. When an\n * `InertRoot` is destroyed, and calls `InertManager.deregister()`, the `InertManager` notifies the\n * `InertNode` via `removeInertRoot()`, which in turn destroys the `InertNode` if no `InertRoot`s\n * remain in the set. On destruction, `InertNode` reinstates the stored `tabindex` if one exists,\n * or removes the `tabindex` attribute if the element is intrinsically focusable.\n */\n class InertNode {\n /**\n * @param {!Node} node A focusable element to be made inert.\n * @param {!InertRoot} inertRoot The inert root element associated with this inert node.\n */\n constructor(node, inertRoot) {\n /** @type {!Node} */\n this._node = node;\n\n /** @type {boolean} */\n this._overrodeFocusMethod = false;\n\n /**\n * @type {!Set<!InertRoot>} The set of descendant inert roots.\n * If and only if this set becomes empty, this node is no longer inert.\n */\n this._inertRoots = new Set([inertRoot]);\n\n /** @type {?number} */\n this._savedTabIndex = null;\n\n /** @type {boolean} */\n this._destroyed = false;\n\n // Save any prior tabindex info and make this node untabbable\n this.ensureUntabbable();\n }\n\n /**\n * Call this whenever this object is about to become obsolete.\n * This makes the managed node focusable again and deletes all of the previously stored state.\n */\n destructor() {\n this._throwIfDestroyed();\n\n if (this._node && this._node.nodeType === Node.ELEMENT_NODE) {\n const element = /** @type {!HTMLElement} */ (this._node);\n if (this._savedTabIndex !== null) {\n element.setAttribute('tabindex', this._savedTabIndex);\n } else {\n element.removeAttribute('tabindex');\n }\n\n // Use `delete` to restore native focus method.\n if (this._overrodeFocusMethod) {\n delete element.focus;\n }\n }\n\n // See note in InertRoot.destructor for why we cast these nulls to ANY.\n this._node = /** @type {?} */ (null);\n this._inertRoots = /** @type {?} */ (null);\n this._destroyed = true;\n }\n\n /**\n * @type {boolean} Whether this object is obsolete because the managed node is no longer inert.\n * If the object has been destroyed, any attempt to access it will cause an exception.\n */\n get destroyed() {\n return /** @type {!InertNode} */ (this)._destroyed;\n }\n\n /**\n * Throw if user tries to access destroyed InertNode.\n */\n _throwIfDestroyed() {\n if (this.destroyed) {\n throw new Error('Trying to access destroyed InertNode');\n }\n }\n\n /** @return {boolean} */\n get hasSavedTabIndex() {\n return this._savedTabIndex !== null;\n }\n\n /** @return {!Node} */\n get node() {\n this._throwIfDestroyed();\n return this._node;\n }\n\n /** @param {?number} tabIndex */\n set savedTabIndex(tabIndex) {\n this._throwIfDestroyed();\n this._savedTabIndex = tabIndex;\n }\n\n /** @return {?number} */\n get savedTabIndex() {\n this._throwIfDestroyed();\n return this._savedTabIndex;\n }\n\n /** Save the existing tabindex value and make the node untabbable and unfocusable */\n ensureUntabbable() {\n if (this.node.nodeType !== Node.ELEMENT_NODE) {\n return;\n }\n const element = /** @type {!HTMLElement} */ (this.node);\n if (matches.call(element, _focusableElementsString)) {\n if (/** @type {!HTMLElement} */ (element).tabIndex === -1 &&\n this.hasSavedTabIndex) {\n return;\n }\n\n if (element.hasAttribute('tabindex')) {\n this._savedTabIndex = /** @type {!HTMLElement} */ (element).tabIndex;\n }\n element.setAttribute('tabindex', '-1');\n if (element.nodeType === Node.ELEMENT_NODE) {\n element.focus = function() {};\n this._overrodeFocusMethod = true;\n }\n } else if (element.hasAttribute('tabindex')) {\n this._savedTabIndex = /** @type {!HTMLElement} */ (element).tabIndex;\n element.removeAttribute('tabindex');\n }\n }\n\n /**\n * Add another inert root to this inert node's set of managing inert roots.\n * @param {!InertRoot} inertRoot\n */\n addInertRoot(inertRoot) {\n this._throwIfDestroyed();\n this._inertRoots.add(inertRoot);\n }\n\n /**\n * Remove the given inert root from this inert node's set of managing inert roots.\n * If the set of managing inert roots becomes empty, this node is no longer inert,\n * so the object should be destroyed.\n * @param {!InertRoot} inertRoot\n */\n removeInertRoot(inertRoot) {\n this._throwIfDestroyed();\n this._inertRoots.delete(inertRoot);\n if (this._inertRoots.size === 0) {\n this.destructor();\n }\n }\n }\n\n /**\n * InertManager is a per-document singleton object which manages all inert roots and nodes.\n *\n * When an element becomes an inert root by having an `inert` attribute set and/or its `inert`\n * property set to `true`, the `setInert` method creates an `InertRoot` object for the element.\n * The `InertRoot` in turn registers itself as managing all of the element's focusable descendant\n * nodes via the `register()` method. The `InertManager` ensures that a single `InertNode` instance\n * is created for each such node, via the `_managedNodes` map.\n */\n class InertManager {\n /**\n * @param {!Document} document\n */\n constructor(document) {\n if (!document) {\n throw new Error('Missing required argument; InertManager needs to wrap a document.');\n }\n\n /** @type {!Document} */\n this._document = document;\n\n /**\n * All managed nodes known to this InertManager. In a map to allow looking up by Node.\n * @type {!Map<!Node, !InertNode>}\n */\n this._managedNodes = new Map();\n\n /**\n * All inert roots known to this InertManager. In a map to allow looking up by Node.\n * @type {!Map<!Node, !InertRoot>}\n */\n this._inertRoots = new Map();\n\n /**\n * Observer for mutations on `document.body`.\n * @type {!MutationObserver}\n */\n this._observer = new MutationObserver(this._watchForInert.bind(this));\n\n // Add inert style.\n addInertStyle(document.head || document.body || document.documentElement);\n\n // Wait for document to be loaded.\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', this._onDocumentLoaded.bind(this));\n } else {\n this._onDocumentLoaded();\n }\n }\n\n /**\n * Set whether the given element should be an inert root or not.\n * @param {!HTMLElement} root\n * @param {boolean} inert\n */\n setInert(root, inert) {\n if (inert) {\n if (this._inertRoots.has(root)) { // element is already inert\n return;\n }\n\n const inertRoot = new InertRoot(root, this);\n root.setAttribute('inert', '');\n this._inertRoots.set(root, inertRoot);\n // If not contained in the document, it must be in a shadowRoot.\n // Ensure inert styles are added there.\n if (!this._document.body.contains(root)) {\n let parent = root.parentNode;\n while (parent) {\n if (parent.nodeType === 11) {\n addInertStyle(parent);\n }\n parent = parent.parentNode;\n }\n }\n } else {\n if (!this._inertRoots.has(root)) { // element is already non-inert\n return;\n }\n\n const inertRoot = this._inertRoots.get(root);\n inertRoot.destructor();\n this._inertRoots.delete(root);\n root.removeAttribute('inert');\n }\n }\n\n /**\n * Get the InertRoot object corresponding to the given inert root element, if any.\n * @param {!Node} element\n * @return {!InertRoot|undefined}\n */\n getInertRoot(element) {\n return this._inertRoots.get(element);\n }\n\n /**\n * Register the given InertRoot as managing the given node.\n * In the case where the node has a previously existing inert root, this inert root will\n * be added to its set of inert roots.\n * @param {!Node} node\n * @param {!InertRoot} inertRoot\n * @return {!InertNode} inertNode\n */\n register(node, inertRoot) {\n let inertNode = this._managedNodes.get(node);\n if (inertNode !== undefined) { // node was already in an inert subtree\n inertNode.addInertRoot(inertRoot);\n } else {\n inertNode = new InertNode(node, inertRoot);\n }\n\n this._managedNodes.set(node, inertNode);\n\n return inertNode;\n }\n\n /**\n * De-register the given InertRoot as managing the given inert node.\n * Removes the inert root from the InertNode's set of managing inert roots, and remove the inert\n * node from the InertManager's set of managed nodes if it is destroyed.\n * If the node is not currently managed, this is essentially a no-op.\n * @param {!Node} node\n * @param {!InertRoot} inertRoot\n * @return {?InertNode} The potentially destroyed InertNode associated with this node, if any.\n */\n deregister(node, inertRoot) {\n const inertNode = this._managedNodes.get(node);\n if (!inertNode) {\n return null;\n }\n\n inertNode.removeInertRoot(inertRoot);\n if (inertNode.destroyed) {\n this._managedNodes.delete(node);\n }\n\n return inertNode;\n }\n\n /**\n * Callback used when document has finished loading.\n */\n _onDocumentLoaded() {\n // Find all inert roots in document and make them actually inert.\n const inertElements = slice.call(this._document.querySelectorAll('[inert]'));\n inertElements.forEach(function(inertElement) {\n this.setInert(inertElement, true);\n }, this);\n\n // Comment this out to use programmatic API only.\n this._observer.observe(this._document.body || this._document.documentElement, {attributes: true, subtree: true, childList: true});\n }\n\n /**\n * Callback used when mutation observer detects attribute changes.\n * @param {!Array<!MutationRecord>} records\n * @param {!MutationObserver} self\n */\n _watchForInert(records, self) {\n const _this = this;\n records.forEach(function(record) {\n switch (record.type) {\n case 'childList':\n slice.call(record.addedNodes).forEach(function(node) {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return;\n }\n const inertElements = slice.call(node.querySelectorAll('[inert]'));\n if (matches.call(node, '[inert]')) {\n inertElements.unshift(node);\n }\n inertElements.forEach(function(inertElement) {\n this.setInert(inertElement, true);\n }, _this);\n }, _this);\n break;\n case 'attributes':\n if (record.attributeName !== 'inert') {\n return;\n }\n const target = /** @type {!HTMLElement} */ (record.target);\n const inert = target.hasAttribute('inert');\n _this.setInert(target, inert);\n break;\n }\n }, this);\n }\n }\n\n /**\n * Recursively walk the composed tree from |node|.\n * @param {!Node} node\n * @param {(function (!HTMLElement))=} callback Callback to be called for each element traversed,\n * before descending into child nodes.\n * @param {?ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any.\n */\n function composedTreeWalk(node, callback, shadowRootAncestor) {\n if (node.nodeType == Node.ELEMENT_NODE) {\n const element = /** @type {!HTMLElement} */ (node);\n if (callback) {\n callback(element);\n }\n\n // Descend into node:\n // If it has a ShadowRoot, ignore all child elements - these will be picked\n // up by the <content> or <shadow> elements. Descend straight into the\n // ShadowRoot.\n const shadowRoot = /** @type {!HTMLElement} */ (element).shadowRoot;\n if (shadowRoot) {\n composedTreeWalk(shadowRoot, callback, shadowRoot);\n return;\n }\n\n // If it is a <content> element, descend into distributed elements - these\n // are elements from outside the shadow root which are rendered inside the\n // shadow DOM.\n if (element.localName == 'content') {\n const content = /** @type {!HTMLContentElement} */ (element);\n // Verifies if ShadowDom v0 is supported.\n const distributedNodes = content.getDistributedNodes ?\n content.getDistributedNodes() : [];\n for (let i = 0; i < distributedNodes.length; i++) {\n composedTreeWalk(distributedNodes[i], callback, shadowRootAncestor);\n }\n return;\n }\n\n // If it is a <slot> element, descend into assigned nodes - these\n // are elements from outside the shadow root which are rendered inside the\n // shadow DOM.\n if (element.localName == 'slot') {\n const slot = /** @type {!HTMLSlotElement} */ (element);\n // Verify if ShadowDom v1 is supported.\n const distributedNodes = slot.assignedNodes ?\n slot.assignedNodes({flatten: true}) : [];\n for (let i = 0; i < distributedNodes.length; i++) {\n composedTreeWalk(distributedNodes[i], callback, shadowRootAncestor);\n }\n return;\n }\n }\n\n // If it is neither the parent of a ShadowRoot, a <content> element, a <slot>\n // element, nor a <shadow> element recurse normally.\n let child = node.firstChild;\n while (child != null) {\n composedTreeWalk(child, callback, shadowRootAncestor);\n child = child.nextSibling;\n }\n }\n\n /**\n * Adds a style element to the node containing the inert specific styles\n * @param {!Node} node\n */\n function addInertStyle(node) {\n if (node.querySelector('style#inert-style, link#inert-style')) {\n return;\n }\n const style = document.createElement('style');\n style.setAttribute('id', 'inert-style');\n style.textContent = '\\n'+\n '[inert] {\\n' +\n ' pointer-events: none;\\n' +\n ' cursor: default;\\n' +\n '}\\n' +\n '\\n' +\n '[inert], [inert] * {\\n' +\n ' -webkit-user-select: none;\\n' +\n ' -moz-user-select: none;\\n' +\n ' -ms-user-select: none;\\n' +\n ' user-select: none;\\n' +\n '}\\n';\n node.appendChild(style);\n }\n\n if (!HTMLElement.prototype.hasOwnProperty('inert')) {\n /** @type {!InertManager} */\n const inertManager = new InertManager(document);\n \n Object.defineProperty(HTMLElement.prototype, 'inert', {\n enumerable: true,\n /** @this {!HTMLElement} */\n get: function() {\n return this.hasAttribute('inert');\n },\n /** @this {!HTMLElement} */\n set: function(inert) {\n inertManager.setInert(this, inert);\n },\n });\n }\n})();\n"],"names":["slice","matches","_focusableElementsString","InertRoot","InertNode","inertManager","rootElement","_inertManager","_rootElement","_managedNodes","Set","this","hasAttribute","_savedAriaHidden","getAttribute","setAttribute","_makeSubtreeUnfocusable","_observer","MutationObserver","_onMutation","bind","observe","attributes","childList","subtree","node","inertRoot","_node","_overrodeFocusMethod","_inertRoots","_savedTabIndex","_destroyed","ensureUntabbable","document","Error","_document","Map","_watchForInert","head","body","documentElement","readyState","addEventListener","_onDocumentLoaded","composedTreeWalk","callback","shadowRootAncestor","nodeType","Node","ELEMENT_NODE","element","shadowRoot","localName","content","distributedNodes","getDistributedNodes","i","length","slot","assignedNodes","flatten","child","firstChild","nextSibling","addInertStyle","style","querySelector","createElement","textContent","appendChild","window","Element","Array","prototype","msMatchesSelector","join","disconnect","removeAttribute","forEach","inertNode","_unmanageNode","startNode","activeElement","_this2","_visitNode","contains","root","undefined","DOCUMENT_FRAGMENT_NODE","parentNode","blur","focus","_adoptInertRoot","call","_manageNode","register","add","deregister","_this3","inertSubroot","getInertRoot","setInert","managedNodes","savedInertNode","records","self","record","target","type","addedNodes","removedNodes","_unmanageSubtree","attributeName","managedNode","ariaHidden","_throwIfDestroyed","destroyed","tabIndex","hasSavedTabIndex","size","destructor","inert","has","set","parent","get","addInertRoot","removeInertRoot","querySelectorAll","inertElement","_this","inertElements","unshift","InertManager","HTMLElement","hasOwnProperty","defineProperty"],"mappings":"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"}
|
package/explainer.md
CHANGED
@@ -120,6 +120,7 @@ implementers may get useful functionality into the hands of developers sooner wh
|
|
120
120
|
+ rendering content, such as a menu, offscreen, before having it animate on-screen;
|
121
121
|
+ similarly, for content like a menu which may be repeatedly shown to the user,
|
122
122
|
avoiding re-rendering this content each time;
|
123
|
+
+ disabling an element as you fade it in or out, without needing to rely on `transitionend` events;
|
123
124
|
+ a carousel or other type of content cycler (such as a "tweet cycler")
|
124
125
|
which visually hides non-current items by placing them at a lower z-index than the active item,
|
125
126
|
or by setting their `opacity` to zero,
|
package/karma.conf.js
CHANGED
@@ -16,7 +16,7 @@ module.exports = function(config) {
|
|
16
16
|
],
|
17
17
|
// Change this to 'Chrome' if you would like to debug.
|
18
18
|
// Can also add additional local browsers like 'Firefox'.
|
19
|
-
browsers: ['
|
19
|
+
browsers: ['FirefoxHeadless'],
|
20
20
|
// Set this to false to leave the browser open for debugging.
|
21
21
|
// You'll probably also need to remove the afterEach block in your tests
|
22
22
|
// so the content is not removed from the page you're trying to debug.
|
@@ -24,10 +24,10 @@ module.exports = function(config) {
|
|
24
24
|
// https://mochajs.org/#exclusive-tests
|
25
25
|
singleRun: true,
|
26
26
|
// Use the mocha test framework with chai assertions.
|
27
|
-
// Use polyfills loaded
|
27
|
+
// Use polyfills loaded
|
28
28
|
// Use an html fixture loader.
|
29
29
|
frameworks: ['mocha', 'chai', 'polyfill', 'fixture'],
|
30
|
-
// List of polyfills to load
|
30
|
+
// List of polyfills to load
|
31
31
|
polyfill: [
|
32
32
|
'Array.from', // Used in tests.
|
33
33
|
'Promise',
|
@@ -57,82 +57,24 @@ module.exports = function(config) {
|
|
57
57
|
if (process.env.TRAVIS || process.env.SAUCE) {
|
58
58
|
// List of browsers to test on SauceLabs.
|
59
59
|
// To add more browsers, use:
|
60
|
-
// https://
|
61
|
-
// This set of browsers was copied from:
|
62
|
-
// https://github.com/angular/angular.js/blob/master/karma-shared.conf.js#L42-L116
|
60
|
+
// https://docs.saucelabs.com/visual/e2e-testing/supported-browsers/#browser-versions-supported
|
63
61
|
const customLaunchers = {
|
64
62
|
'SL_Chrome': {
|
65
63
|
base: 'SauceLabs',
|
66
64
|
browserName: 'chrome',
|
67
|
-
version: '
|
68
|
-
},
|
69
|
-
'SL_Chrome-1': {
|
70
|
-
base: 'SauceLabs',
|
71
|
-
browserName: 'chrome',
|
72
|
-
version: 'latest-1',
|
65
|
+
version: '100',
|
73
66
|
},
|
74
67
|
'SL_Firefox': {
|
75
68
|
base: 'SauceLabs',
|
76
69
|
browserName: 'firefox',
|
77
|
-
version: '
|
78
|
-
},
|
79
|
-
'SL_Firefox-1': {
|
80
|
-
base: 'SauceLabs',
|
81
|
-
browserName: 'firefox',
|
82
|
-
version: 'latest-1',
|
83
|
-
},
|
84
|
-
'SL_Safari-1': {
|
85
|
-
base: 'SauceLabs',
|
86
|
-
browserName: 'safari',
|
87
|
-
platform: 'OS X 10.12',
|
88
|
-
version: 'latest-1',
|
70
|
+
version: '100',
|
89
71
|
},
|
90
72
|
'SL_Safari': {
|
91
73
|
base: 'SauceLabs',
|
92
74
|
browserName: 'safari',
|
93
|
-
platform: 'OS X
|
94
|
-
version: '
|
95
|
-
},
|
96
|
-
// 'SL_IE_9': {
|
97
|
-
// base: 'SauceLabs',
|
98
|
-
// browserName: 'internet explorer',
|
99
|
-
// platform: 'Windows 2008',
|
100
|
-
// version: '9',
|
101
|
-
// },
|
102
|
-
// 'SL_IE_10': {
|
103
|
-
// base: 'SauceLabs',
|
104
|
-
// browserName: 'internet explorer',
|
105
|
-
// platform: 'Windows 2012',
|
106
|
-
// version: '10',
|
107
|
-
// },
|
108
|
-
'SL_IE_11': {
|
109
|
-
base: 'SauceLabs',
|
110
|
-
browserName: 'internet explorer',
|
111
|
-
platform: 'Windows 8.1',
|
112
|
-
version: '11',
|
113
|
-
},
|
114
|
-
'SL_EDGE': {
|
115
|
-
base: 'SauceLabs',
|
116
|
-
browserName: 'microsoftedge',
|
117
|
-
platform: 'Windows 10',
|
118
|
-
version: 'latest',
|
119
|
-
},
|
120
|
-
'SL_EDGE-1': {
|
121
|
-
base: 'SauceLabs',
|
122
|
-
browserName: 'microsoftedge',
|
123
|
-
platform: 'Windows 10',
|
124
|
-
version: 'latest-1',
|
75
|
+
platform: 'OS X 11.00',
|
76
|
+
version: '14',
|
125
77
|
},
|
126
|
-
// 'SL_iOS_10': {
|
127
|
-
// base: 'SauceLabs',
|
128
|
-
// browserName: 'iphone',
|
129
|
-
// version: '10.3',
|
130
|
-
// },
|
131
|
-
// 'SL_iOS_11': {
|
132
|
-
// base: 'SauceLabs',
|
133
|
-
// browserName: 'iphone',
|
134
|
-
// version: '11',
|
135
|
-
// },
|
136
78
|
};
|
137
79
|
|
138
80
|
config.set({
|
package/package.json
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
{
|
2
2
|
"name": "wicg-inert",
|
3
|
-
"version": "3.1.
|
3
|
+
"version": "3.1.3",
|
4
4
|
"description": "A polyfill for the proposed inert API",
|
5
5
|
"main": "dist/inert.js",
|
6
6
|
"module": "dist/inert.esm.js",
|
7
7
|
"scripts": {
|
8
|
-
"build": "rollup -c"
|
9
|
-
"prepublishOnly": "SAUCE=true npm run test",
|
10
|
-
"test": "npm run build && karma start"
|
8
|
+
"build": "rollup -c"
|
11
9
|
},
|
12
10
|
"repository": {
|
13
11
|
"type": "git",
|
@@ -38,21 +36,23 @@
|
|
38
36
|
"eslint-config-google": "^0.9.1",
|
39
37
|
"eslint-plugin-es5": "^1.3.1",
|
40
38
|
"husky": "^0.14.3",
|
41
|
-
"karma": "^3.
|
39
|
+
"karma": "^6.3.20",
|
42
40
|
"karma-chai": "^0.1.0",
|
43
41
|
"karma-chrome-launcher": "^2.2.0",
|
44
42
|
"karma-firefox-launcher": "^1.1.0",
|
45
43
|
"karma-fixture": "^0.2.6",
|
46
44
|
"karma-html2js-preprocessor": "^1.1.0",
|
47
|
-
"karma-mocha": "^
|
45
|
+
"karma-mocha": "^2.0.1",
|
48
46
|
"karma-polyfill": "^1.0.0",
|
47
|
+
"karma-safari-launcher": "^1.0.0",
|
49
48
|
"karma-sauce-launcher": "^1.2.0",
|
50
49
|
"karma-sourcemap-loader": "^0.3.7",
|
51
50
|
"karma-spec-reporter": "0.0.32",
|
52
51
|
"lint-staged": "^7.0.0",
|
53
|
-
"mocha": "^
|
52
|
+
"mocha": "^10.0.0",
|
54
53
|
"rollup": "^0.65.0",
|
55
54
|
"rollup-plugin-babel": "^3.0.4",
|
56
55
|
"rollup-plugin-uglify": "^4.0.0"
|
57
|
-
}
|
56
|
+
},
|
57
|
+
"license": "W3C-20150513"
|
58
58
|
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# [Self-Review Questionnaire: Security and Privacy](https://w3ctag.github.io/security-questionnaire/)
|
2
|
+
|
3
|
+
> 01. What information might this feature expose to Web sites or other parties,
|
4
|
+
and for what purposes is that exposure necessary?
|
5
|
+
|
6
|
+
None.
|
7
|
+
|
8
|
+
> 02. Do features in your specification expose the minimum amount of information
|
9
|
+
necessary to enable their intended uses?
|
10
|
+
|
11
|
+
Yes.
|
12
|
+
|
13
|
+
> 03. How do the features in your specification deal with personal information,
|
14
|
+
personally-identifiable information (PII), or information derived from
|
15
|
+
them?
|
16
|
+
|
17
|
+
No PII is used.
|
18
|
+
|
19
|
+
> 04. How do the features in your specification deal with sensitive information?
|
20
|
+
|
21
|
+
No sensitive information is used.
|
22
|
+
|
23
|
+
> 05. Do the features in your specification introduce new state for an origin
|
24
|
+
that persists across browsing sessions?
|
25
|
+
|
26
|
+
No.
|
27
|
+
|
28
|
+
> 06. Do the features in your specification expose information about the
|
29
|
+
underlying platform to origins?
|
30
|
+
|
31
|
+
No.
|
32
|
+
|
33
|
+
> 07. Does this specification allow an origin to send data to the underlying
|
34
|
+
platform?
|
35
|
+
|
36
|
+
No.
|
37
|
+
|
38
|
+
> 08. Do features in this specification allow an origin access to sensors on a user’s
|
39
|
+
device
|
40
|
+
|
41
|
+
No.
|
42
|
+
|
43
|
+
> 09. What data do the features in this specification expose to an origin? Please
|
44
|
+
also document what data is identical to data exposed by other features, in the
|
45
|
+
same or different contexts.
|
46
|
+
|
47
|
+
No data is exposed to any origin.
|
48
|
+
|
49
|
+
> 10. Do feautres in this specification enable new script execution/loading
|
50
|
+
mechanisms?
|
51
|
+
|
52
|
+
No.
|
53
|
+
|
54
|
+
> 11. Do features in this specification allow an origin to access other devices?
|
55
|
+
|
56
|
+
No.
|
57
|
+
|
58
|
+
> 12. Do features in this specification allow an origin some measure of control over
|
59
|
+
a user agent's native UI?
|
60
|
+
|
61
|
+
No.
|
62
|
+
|
63
|
+
> 13. What temporary identifiers do the feautures in this specification create or
|
64
|
+
expose to the web?
|
65
|
+
|
66
|
+
None.
|
67
|
+
|
68
|
+
> 14. How does this specification distinguish between behavior in first-party and
|
69
|
+
third-party contexts?
|
70
|
+
|
71
|
+
It doesn't.
|
72
|
+
|
73
|
+
> 15. How do the features in this specification work in the context of a browser’s
|
74
|
+
Private Browsing or Incognito mode?
|
75
|
+
|
76
|
+
This feature behaves identically in any mode.
|
77
|
+
|
78
|
+
> 16. Does this specification have both "Security Considerations" and "Privacy
|
79
|
+
Considerations" sections?
|
80
|
+
|
81
|
+
No.
|
82
|
+
|
83
|
+
> 17. Do features in your specification enable origins to downgrade default
|
84
|
+
security protections?
|
85
|
+
|
86
|
+
No.
|
87
|
+
|
88
|
+
> 18. What should this questionnaire have asked?
|
89
|
+
|
90
|
+
🤷
|
package/src/inert.js
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
(function() {
|
7
7
|
// Return early if we're not running inside of the browser.
|
8
|
-
if (typeof window === 'undefined') {
|
8
|
+
if (typeof window === 'undefined' || typeof Element === 'undefined') {
|
9
9
|
return;
|
10
10
|
}
|
11
11
|
|
@@ -32,6 +32,7 @@
|
|
32
32
|
'iframe',
|
33
33
|
'object',
|
34
34
|
'embed',
|
35
|
+
'video',
|
35
36
|
'[contenteditable]'].join(',');
|
36
37
|
|
37
38
|
/**
|
@@ -52,14 +53,14 @@
|
|
52
53
|
*/
|
53
54
|
class InertRoot {
|
54
55
|
/**
|
55
|
-
* @param {!
|
56
|
+
* @param {!HTMLElement} rootElement The HTMLElement at the root of the inert subtree.
|
56
57
|
* @param {!InertManager} inertManager The global singleton InertManager object.
|
57
58
|
*/
|
58
59
|
constructor(rootElement, inertManager) {
|
59
60
|
/** @type {!InertManager} */
|
60
61
|
this._inertManager = inertManager;
|
61
62
|
|
62
|
-
/** @type {!
|
63
|
+
/** @type {!HTMLElement} */
|
63
64
|
this._rootElement = rootElement;
|
64
65
|
|
65
66
|
/**
|
@@ -184,7 +185,7 @@
|
|
184
185
|
if (node.nodeType !== Node.ELEMENT_NODE) {
|
185
186
|
return;
|
186
187
|
}
|
187
|
-
const element = /** @type {!
|
188
|
+
const element = /** @type {!HTMLElement} */ (node);
|
188
189
|
|
189
190
|
// If a descendant inert root becomes un-inert, its descendants will still be inert because of
|
190
191
|
// this inert root, so all of its managed nodes need to be adopted by this InertRoot.
|
@@ -227,7 +228,7 @@
|
|
227
228
|
|
228
229
|
/**
|
229
230
|
* If a descendant node is found with an `inert` attribute, adopt its managed nodes.
|
230
|
-
* @param {!
|
231
|
+
* @param {!HTMLElement} node
|
231
232
|
*/
|
232
233
|
_adoptInertRoot(node) {
|
233
234
|
let inertSubroot = this._inertManager.getInertRoot(node);
|
@@ -251,7 +252,7 @@
|
|
251
252
|
*/
|
252
253
|
_onMutation(records, self) {
|
253
254
|
records.forEach(function(record) {
|
254
|
-
const target = /** @type {!
|
255
|
+
const target = /** @type {!HTMLElement} */ (record.target);
|
255
256
|
if (record.type === 'childList') {
|
256
257
|
// Manage added nodes
|
257
258
|
slice.call(record.addedNodes).forEach(function(node) {
|
@@ -334,7 +335,7 @@
|
|
334
335
|
this._throwIfDestroyed();
|
335
336
|
|
336
337
|
if (this._node && this._node.nodeType === Node.ELEMENT_NODE) {
|
337
|
-
const element = /** @type {!
|
338
|
+
const element = /** @type {!HTMLElement} */ (this._node);
|
338
339
|
if (this._savedTabIndex !== null) {
|
339
340
|
element.setAttribute('tabindex', this._savedTabIndex);
|
340
341
|
} else {
|
@@ -398,7 +399,7 @@
|
|
398
399
|
if (this.node.nodeType !== Node.ELEMENT_NODE) {
|
399
400
|
return;
|
400
401
|
}
|
401
|
-
const element = /** @type {!
|
402
|
+
const element = /** @type {!HTMLElement} */ (this.node);
|
402
403
|
if (matches.call(element, _focusableElementsString)) {
|
403
404
|
if (/** @type {!HTMLElement} */ (element).tabIndex === -1 &&
|
404
405
|
this.hasSavedTabIndex) {
|
@@ -495,7 +496,7 @@
|
|
495
496
|
|
496
497
|
/**
|
497
498
|
* Set whether the given element should be an inert root or not.
|
498
|
-
* @param {!
|
499
|
+
* @param {!HTMLElement} root
|
499
500
|
* @param {boolean} inert
|
500
501
|
*/
|
501
502
|
setInert(root, inert) {
|
@@ -624,7 +625,7 @@
|
|
624
625
|
if (record.attributeName !== 'inert') {
|
625
626
|
return;
|
626
627
|
}
|
627
|
-
const target = /** @type {!
|
628
|
+
const target = /** @type {!HTMLElement} */ (record.target);
|
628
629
|
const inert = target.hasAttribute('inert');
|
629
630
|
_this.setInert(target, inert);
|
630
631
|
break;
|
@@ -636,13 +637,13 @@
|
|
636
637
|
/**
|
637
638
|
* Recursively walk the composed tree from |node|.
|
638
639
|
* @param {!Node} node
|
639
|
-
* @param {(function (!
|
640
|
+
* @param {(function (!HTMLElement))=} callback Callback to be called for each element traversed,
|
640
641
|
* before descending into child nodes.
|
641
642
|
* @param {?ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any.
|
642
643
|
*/
|
643
644
|
function composedTreeWalk(node, callback, shadowRootAncestor) {
|
644
645
|
if (node.nodeType == Node.ELEMENT_NODE) {
|
645
|
-
const element = /** @type {!
|
646
|
+
const element = /** @type {!HTMLElement} */ (node);
|
646
647
|
if (callback) {
|
647
648
|
callback(element);
|
648
649
|
}
|
@@ -720,17 +721,17 @@
|
|
720
721
|
node.appendChild(style);
|
721
722
|
}
|
722
723
|
|
723
|
-
if (!
|
724
|
+
if (!HTMLElement.prototype.hasOwnProperty('inert')) {
|
724
725
|
/** @type {!InertManager} */
|
725
726
|
const inertManager = new InertManager(document);
|
726
727
|
|
727
|
-
Object.defineProperty(
|
728
|
+
Object.defineProperty(HTMLElement.prototype, 'inert', {
|
728
729
|
enumerable: true,
|
729
|
-
/** @this {!
|
730
|
+
/** @this {!HTMLElement} */
|
730
731
|
get: function() {
|
731
732
|
return this.hasAttribute('inert');
|
732
733
|
},
|
733
|
-
/** @this {!
|
734
|
+
/** @this {!HTMLElement} */
|
734
735
|
set: function(inert) {
|
735
736
|
inertManager.setInert(this, inert);
|
736
737
|
},
|
@@ -1,5 +1,5 @@
|
|
1
|
-
describe('
|
2
|
-
it('should patch the
|
3
|
-
expect(
|
1
|
+
describe('HTMLElement.prototype', function() {
|
2
|
+
it('should patch the HTMLElement prototype', function() {
|
3
|
+
expect(HTMLElement.prototype.hasOwnProperty('inert')).to.be.ok;
|
4
4
|
});
|
5
5
|
});
|
@@ -14,7 +14,7 @@ LOG.info = function() {
|
|
14
14
|
* Check if an element is not focusable.
|
15
15
|
* Note: This will be injected into the global scope by the test runner.
|
16
16
|
* See the files array in karma.conf.js.
|
17
|
-
* @param {
|
17
|
+
* @param {HTMLElement} el
|
18
18
|
* @return {Boolean}
|
19
19
|
*/
|
20
20
|
function isUnfocusable(el) { // eslint-disable-line no-unused-vars
|