PageSourceSearch

https://www.hologic.es/sites/default/files/cohesion/scripts/modal/inert-polyfill.js?tm4wcr

js hologic.es collected 2026-10-08 20:33:12 UTC 9,211 bytes, 270 lines download raw bytes

1/*
2 * @sitestudioexcludesonar
vendor: 9,181 bytes, lines 2-270
2
3 * Copyright 2015 Google Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy of
7 * the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17
18if (!('inert' in HTMLElement.prototype)) {
19  Object.defineProperty(HTMLElement.prototype, 'inert', {
20    enumerable: true,
21
22    /**
23     * @return {boolean}
24     * @this {Element}
25     */
26    get: function() { return this.hasAttribute('inert'); },
27
28    /**
29     * @param {boolean} inert
30     * @this {Element}
31     */
32    set: function(inert) {
33      if (inert) {
34        this.setAttribute('inert', '');
35      } else {
36        this.removeAttribute('inert');
37      }
38    }
39  });
40
41  window.addEventListener('load', function() {
42    function applyStyle(css) {
43      var style = document.createElement('style');
44      style.type = 'text/css';
45      if (style.styleSheet) {
46        style.styleSheet.cssText = css;
47      } else {
48        style.appendChild(document.createTextNode(css));
49      }
50      document.body.appendChild(style);
51    }
52    var css = "/*[inert]*/*[inert]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}";
53    applyStyle(css);
54
55    /**
56     * Sends a fake tab event. This is only supported by some browsers.
57     *
58     * @param {boolean=} opt_shiftKey whether to send this tab with shiftKey
59     */
60    function dispatchTabEvent(opt_shiftKey) {
61      var ev = null;
62      try {
63        ev = new KeyboardEvent('keydown', {
64          keyCode: 9,
65          which: 9,
66          key: 'Tab',
67          code: 'Tab',
68          keyIdentifier: 'U+0009',
69          shiftKey: !!opt_shiftKey,
70          bubbles: true
71        });
72      } catch (e) {
73        try {
74          // Internet Explorer
75          ev = document.createEvent('KeyboardEvent');
76          ev.initKeyboardEvent(
77            'keydown',
78            true,
79            true,
80            window,
81            'Tab',
82            0,
83            opt_shiftKey ? 'Shift' : '',
84            false,
85            'en'
86          )
87        } catch (e) {}
88      }
89      if (ev) {
90        try {
91          Object.defineProperty(ev, 'keyCode', { value: 9 });
92        } catch (e) {}
93        document.dispatchEvent(ev);
94      }
95    }
96
97    /**
98     * Determines whether the specified element is inert, and returns the element
99     * which caused this state. This is limited to, but may include, the body
100     * element.
101     *
102     * @param {Element} e to check
103     * @return {Element} element is made inert by, if any
104     */
105    function madeInertBy(e) {
106      while (e && e !== document.documentElement) {
107        if (e.hasAttribute('inert')) {
108          return e;
109        }
110        e = e.parentElement;
111      }
112      return null;
113    }
114
115    /**
116     * Finds the nearest shadow root from an element that's within said shadow root.
117     *
118     * TODO(samthor): We probably want to find the highest shadow root.
119     *
120     * @param {Element} e to check
121     * @return {Node} shadow root, if any
122     */
123    var findShadowRoot = function(e) { return null; };
124    if (window.ShadowRoot) {
125      findShadowRoot = function(e) {
126        while (e && e !== document.documentElement) {
127          if (e instanceof window.ShadowRoot) { return e; }
128          e = e.parentNode;
129        }
130        return null;
131      }
132    }
133
134    /**
135     * Returns the target of the passed event. If there's a path (shadow DOM only), then prefer it.
136     *
137     * @param {!Event} event
138     * @return {Element} target of event
139     */
140    function targetForEvent(event) {
141      var p = event.path;
142      return  /** @type {Element} */ (p && p[0] || event.target);
143    }
144
145    // Hold onto the last tab direction: next (tab) or previous (shift-tab). This
146    // can be used to step over inert elements in the correct direction. Mouse
147    // or non-tab events should reset this and inert events should focus nothing.
148    var lastTabDirection = 0;
149    document.addEventListener('keydown', function(ev) {
150      if (ev.keyCode === 9) {
151        lastTabDirection = ev.shiftKey ? -1 : +1;
152      } else {
153        lastTabDirection = 0;
154      }
155    });
156    document.addEventListener('mousedown', function(ev) {
157      lastTabDirection = 0;
158    });
159
160    // Retain the currently focused shadowRoot.
161    var focusedShadowRoot = null;
162    function updateFocusedShadowRoot(root) {
163      if (root == focusedShadowRoot) { return; }
164      if (focusedShadowRoot) {
165        if (!(focusedShadowRoot instanceof window.ShadowRoot)) {
166          throw new Error('not shadow root: ' + focusedShadowRoot);
167        }
168        focusedShadowRoot.removeEventListener('focusin', shadowFocusHandler, true);  // remove
169      }
170      if (root) {
171        root.addEventListener('focusin', shadowFocusHandler, true);  // add
172      }
173      focusedShadowRoot = root;
174    }
175
176    /**
177     * Focus handler on a Shadow DOM host. This traps focus events within that root.
178     *
179     * @param {!Event} ev
180     */
181    function shadowFocusHandler(ev) {
182      // ignore "direct" focus, we only want shadow root focus
183      var last = ev.path[ev.path.length - 1];
184      if (last === /** @type {*} */ (window)) { return; }
185      sharedFocusHandler(targetForEvent(ev));
186      ev.preventDefault();
187      ev.stopPropagation();
188    }
189
190    /**
191     * Called indirectly by both the regular focus handler and Shadow DOM host focus handler. This
192     * is the bulk of the polyfill which prevents focus.
193     *
194     * @param {Element} target focused on
195     */
196    function sharedFocusHandler(target) {
197      var inertElement = madeInertBy(target);
198      if (!inertElement) { return; }
199
200      // If the page has been tabbed recently, then focus the next element
201      // in the known direction (if available).
202      if (document.hasFocus() && lastTabDirection !== 0) {
203        function getFocused() {
204          return (focusedShadowRoot || document).activeElement;
205        }
206
207        // Send a fake tab event to enumerate through the browser's view of
208        // focusable elements. This is supported in some browsers (not Firefox).
209        var previous = getFocused();
210        dispatchTabEvent(lastTabDirection < 0 ? true : false);
211        if (previous != getFocused()) { return; }
212
213        // Otherwise, enumerate through adjacent elements to find the next
214        // focusable element. This won't respect any custom tabIndex.
215        var filter = /** @type {NodeFilter} */ ({
216          /**
217           * @param {Node} node
218           * @return {number}
219           */
220          acceptNode: function(node) {
221            if (!node || !node.focus || node.tabIndex < 0) {
222              return NodeFilter.FILTER_SKIP;  // look at descendants
223            }
224            var contained = inertElement.contains(node);
225            return contained ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
226          },
227        });
228        var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, filter);
229        walker.currentNode = inertElement;
230
231        var nextFunc = Math.sign(lastTabDirection) === -1 ? walker.previousNode : walker.nextNode
232        var next = nextFunc.bind(walker);
233        for (var candidate; candidate = next(); ) {
234          candidate.focus();
235          if (getFocused() !== previous) { return; }
236        }
237
238        // FIXME: If a focusable element can't be found here, it's likely to mean
239        // that this is the start or end of the page. Blurring is then not quite
240        // right, as it prevents access to the browser chrome.
241      }
242
243      // Otherwise, immediately blur the targeted element. Technically, this
244      // still generates focus and blur events on the element. This is (probably)
245      // the price to pay for this polyfill.
246      target.blur();
247    }
248
249    // The 'focusin' event bubbles, but instead, use 'focus' with useCapture set
250    // to true as this is supported in Firefox. Additionally, target the body so
251    // this doesn't generate superfluous events on document itself.
252    document.body.addEventListener('focus', function(ev) {
253      var target = targetForEvent(ev);
254      updateFocusedShadowRoot((target == ev.target ? null : findShadowRoot(target)));
255      sharedFocusHandler(target);  // either real DOM node or shadow node
256    }, true);
257
258    // Use a capturing click listener as both a safety fallback where pointer-events is not
259    // available (IE10 and below), and to prevent accessKey access to inert elements.
260    // TODO(samthor): Note that pointer-events polyfills trap more mouse events, e.g.-
261    //   https://github.com/kmewhort/pointer_events_polyfill
262    document.addEventListener('click', function(ev) {
263      var target = targetForEvent(ev);
264      if (madeInertBy(target)) {
265        ev.preventDefault();
266        ev.stopPropagation();
267      }
268    }, true);
269  });
270}
270

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.