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.