[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 (function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? factory() : 3 typeof define === 'function' && define.amd ? define('inert', factory) : 4 (factory()); 5 }(this, (function () { 'use strict'; 6 7 var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 9 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 10 11 /** 12 * This work is licensed under the W3C Software and Document License 13 * (http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 14 */ 15 16 (function () { 17 // Return early if we're not running inside of the browser. 18 if (typeof window === 'undefined' || typeof Element === 'undefined') { 19 return; 20 } 21 22 // Convenience function for converting NodeLists. 23 /** @type {typeof Array.prototype.slice} */ 24 var slice = Array.prototype.slice; 25 26 /** 27 * IE has a non-standard name for "matches". 28 * @type {typeof Element.prototype.matches} 29 */ 30 var matches = Element.prototype.matches || Element.prototype.msMatchesSelector; 31 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', 'video', '[contenteditable]'].join(','); 34 35 /** 36 * `InertRoot` manages a single inert subtree, i.e. a DOM subtree whose root element has an `inert` 37 * attribute. 38 * 39 * Its main functions are: 40 * 41 * - to create and maintain a set of managed `InertNode`s, including when mutations occur in the 42 * subtree. The `makeSubtreeUnfocusable()` method handles collecting `InertNode`s via registering 43 * each focusable node in the subtree with the singleton `InertManager` which manages all known 44 * focusable nodes within inert subtrees. `InertManager` ensures that a single `InertNode` 45 * instance exists for each focusable node which has at least one inert root as an ancestor. 46 * 47 * - to notify all managed `InertNode`s when this subtree stops being inert (i.e. when the `inert` 48 * attribute is removed from the root node). This is handled in the destructor, which calls the 49 * `deregister` method on `InertManager` for each managed inert node. 50 */ 51 52 var InertRoot = function () { 53 /** 54 * @param {!HTMLElement} rootElement The HTMLElement at the root of the inert subtree. 55 * @param {!InertManager} inertManager The global singleton InertManager object. 56 */ 57 function InertRoot(rootElement, inertManager) { 58 _classCallCheck(this, InertRoot); 59 60 /** @type {!InertManager} */ 61 this._inertManager = inertManager; 62 63 /** @type {!HTMLElement} */ 64 this._rootElement = rootElement; 65 66 /** 67 * @type {!Set<!InertNode>} 68 * All managed focusable nodes in this InertRoot's subtree. 69 */ 70 this._managedNodes = new Set(); 71 72 // Make the subtree hidden from assistive technology 73 if (this._rootElement.hasAttribute('aria-hidden')) { 74 /** @type {?string} */ 75 this._savedAriaHidden = this._rootElement.getAttribute('aria-hidden'); 76 } else { 77 this._savedAriaHidden = null; 78 } 79 this._rootElement.setAttribute('aria-hidden', 'true'); 80 81 // Make all focusable elements in the subtree unfocusable and add them to _managedNodes 82 this._makeSubtreeUnfocusable(this._rootElement); 83 84 // Watch for: 85 // - any additions in the subtree: make them unfocusable too 86 // - any removals from the subtree: remove them from this inert root's managed nodes 87 // - attribute changes: if `tabindex` is added, or removed from an intrinsically focusable 88 // element, make that node a managed node. 89 this._observer = new MutationObserver(this._onMutation.bind(this)); 90 this._observer.observe(this._rootElement, { attributes: true, childList: true, subtree: true }); 91 } 92 93 /** 94 * Call this whenever this object is about to become obsolete. This unwinds all of the state 95 * stored in this object and updates the state of all of the managed nodes. 96 */ 97 98 99 _createClass(InertRoot, [{ 100 key: 'destructor', 101 value: function destructor() { 102 this._observer.disconnect(); 103 104 if (this._rootElement) { 105 if (this._savedAriaHidden !== null) { 106 this._rootElement.setAttribute('aria-hidden', this._savedAriaHidden); 107 } else { 108 this._rootElement.removeAttribute('aria-hidden'); 109 } 110 } 111 112 this._managedNodes.forEach(function (inertNode) { 113 this._unmanageNode(inertNode.node); 114 }, this); 115 116 // Note we cast the nulls to the ANY type here because: 117 // 1) We want the class properties to be declared as non-null, or else we 118 // need even more casts throughout this code. All bets are off if an 119 // instance has been destroyed and a method is called. 120 // 2) We don't want to cast "this", because we want type-aware optimizations 121 // to know which properties we're setting. 122 this._observer = /** @type {?} */null; 123 this._rootElement = /** @type {?} */null; 124 this._managedNodes = /** @type {?} */null; 125 this._inertManager = /** @type {?} */null; 126 } 127 128 /** 129 * @return {!Set<!InertNode>} A copy of this InertRoot's managed nodes set. 130 */ 131 132 }, { 133 key: '_makeSubtreeUnfocusable', 134 135 136 /** 137 * @param {!Node} startNode 138 */ 139 value: function _makeSubtreeUnfocusable(startNode) { 140 var _this2 = this; 141 142 composedTreeWalk(startNode, function (node) { 143 return _this2._visitNode(node); 144 }); 145 146 var activeElement = document.activeElement; 147 148 if (!document.body.contains(startNode)) { 149 // startNode may be in shadow DOM, so find its nearest shadowRoot to get the activeElement. 150 var node = startNode; 151 /** @type {!ShadowRoot|undefined} */ 152 var root = undefined; 153 while (node) { 154 if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { 155 root = /** @type {!ShadowRoot} */node; 156 break; 157 } 158 node = node.parentNode; 159 } 160 if (root) { 161 activeElement = root.activeElement; 162 } 163 } 164 if (startNode.contains(activeElement)) { 165 activeElement.blur(); 166 // In IE11, if an element is already focused, and then set to tabindex=-1 167 // calling blur() will not actually move the focus. 168 // To work around this we call focus() on the body instead. 169 if (activeElement === document.activeElement) { 170 document.body.focus(); 171 } 172 } 173 } 174 175 /** 176 * @param {!Node} node 177 */ 178 179 }, { 180 key: '_visitNode', 181 value: function _visitNode(node) { 182 if (node.nodeType !== Node.ELEMENT_NODE) { 183 return; 184 } 185 var element = /** @type {!HTMLElement} */node; 186 187 // If a descendant inert root becomes un-inert, its descendants will still be inert because of 188 // this inert root, so all of its managed nodes need to be adopted by this InertRoot. 189 if (element !== this._rootElement && element.hasAttribute('inert')) { 190 this._adoptInertRoot(element); 191 } 192 193 if (matches.call(element, _focusableElementsString) || element.hasAttribute('tabindex')) { 194 this._manageNode(element); 195 } 196 } 197 198 /** 199 * Register the given node with this InertRoot and with InertManager. 200 * @param {!Node} node 201 */ 202 203 }, { 204 key: '_manageNode', 205 value: function _manageNode(node) { 206 var inertNode = this._inertManager.register(node, this); 207 this._managedNodes.add(inertNode); 208 } 209 210 /** 211 * Unregister the given node with this InertRoot and with InertManager. 212 * @param {!Node} node 213 */ 214 215 }, { 216 key: '_unmanageNode', 217 value: function _unmanageNode(node) { 218 var inertNode = this._inertManager.deregister(node, this); 219 if (inertNode) { 220 this._managedNodes['delete'](inertNode); 221 } 222 } 223 224 /** 225 * Unregister the entire subtree starting at `startNode`. 226 * @param {!Node} startNode 227 */ 228 229 }, { 230 key: '_unmanageSubtree', 231 value: function _unmanageSubtree(startNode) { 232 var _this3 = this; 233 234 composedTreeWalk(startNode, function (node) { 235 return _this3._unmanageNode(node); 236 }); 237 } 238 239 /** 240 * If a descendant node is found with an `inert` attribute, adopt its managed nodes. 241 * @param {!HTMLElement} node 242 */ 243 244 }, { 245 key: '_adoptInertRoot', 246 value: function _adoptInertRoot(node) { 247 var inertSubroot = this._inertManager.getInertRoot(node); 248 249 // During initialisation this inert root may not have been registered yet, 250 // so register it now if need be. 251 if (!inertSubroot) { 252 this._inertManager.setInert(node, true); 253 inertSubroot = this._inertManager.getInertRoot(node); 254 } 255 256 inertSubroot.managedNodes.forEach(function (savedInertNode) { 257 this._manageNode(savedInertNode.node); 258 }, this); 259 } 260 261 /** 262 * Callback used when mutation observer detects subtree additions, removals, or attribute changes. 263 * @param {!Array<!MutationRecord>} records 264 * @param {!MutationObserver} self 265 */ 266 267 }, { 268 key: '_onMutation', 269 value: function _onMutation(records, self) { 270 records.forEach(function (record) { 271 var target = /** @type {!HTMLElement} */record.target; 272 if (record.type === 'childList') { 273 // Manage added nodes 274 slice.call(record.addedNodes).forEach(function (node) { 275 this._makeSubtreeUnfocusable(node); 276 }, this); 277 278 // Un-manage removed nodes 279 slice.call(record.removedNodes).forEach(function (node) { 280 this._unmanageSubtree(node); 281 }, this); 282 } else if (record.type === 'attributes') { 283 if (record.attributeName === 'tabindex') { 284 // Re-initialise inert node if tabindex changes 285 this._manageNode(target); 286 } else if (target !== this._rootElement && record.attributeName === 'inert' && target.hasAttribute('inert')) { 287 // If a new inert root is added, adopt its managed nodes and make sure it knows about the 288 // already managed nodes from this inert subroot. 289 this._adoptInertRoot(target); 290 var inertSubroot = this._inertManager.getInertRoot(target); 291 this._managedNodes.forEach(function (managedNode) { 292 if (target.contains(managedNode.node)) { 293 inertSubroot._manageNode(managedNode.node); 294 } 295 }); 296 } 297 } 298 }, this); 299 } 300 }, { 301 key: 'managedNodes', 302 get: function get() { 303 return new Set(this._managedNodes); 304 } 305 306 /** @return {boolean} */ 307 308 }, { 309 key: 'hasSavedAriaHidden', 310 get: function get() { 311 return this._savedAriaHidden !== null; 312 } 313 314 /** @param {?string} ariaHidden */ 315 316 }, { 317 key: 'savedAriaHidden', 318 set: function set(ariaHidden) { 319 this._savedAriaHidden = ariaHidden; 320 } 321 322 /** @return {?string} */ 323 , 324 get: function get() { 325 return this._savedAriaHidden; 326 } 327 }]); 328 329 return InertRoot; 330 }(); 331 332 /** 333 * `InertNode` initialises and manages a single inert node. 334 * A node is inert if it is a descendant of one or more inert root elements. 335 * 336 * On construction, `InertNode` saves the existing `tabindex` value for the node, if any, and 337 * either removes the `tabindex` attribute or sets it to `-1`, depending on whether the element 338 * is intrinsically focusable or not. 339 * 340 * `InertNode` maintains a set of `InertRoot`s which are descendants of this `InertNode`. When an 341 * `InertRoot` is destroyed, and calls `InertManager.deregister()`, the `InertManager` notifies the 342 * `InertNode` via `removeInertRoot()`, which in turn destroys the `InertNode` if no `InertRoot`s 343 * remain in the set. On destruction, `InertNode` reinstates the stored `tabindex` if one exists, 344 * or removes the `tabindex` attribute if the element is intrinsically focusable. 345 */ 346 347 348 var InertNode = function () { 349 /** 350 * @param {!Node} node A focusable element to be made inert. 351 * @param {!InertRoot} inertRoot The inert root element associated with this inert node. 352 */ 353 function InertNode(node, inertRoot) { 354 _classCallCheck(this, InertNode); 355 356 /** @type {!Node} */ 357 this._node = node; 358 359 /** @type {boolean} */ 360 this._overrodeFocusMethod = false; 361 362 /** 363 * @type {!Set<!InertRoot>} The set of descendant inert roots. 364 * If and only if this set becomes empty, this node is no longer inert. 365 */ 366 this._inertRoots = new Set([inertRoot]); 367 368 /** @type {?number} */ 369 this._savedTabIndex = null; 370 371 /** @type {boolean} */ 372 this._destroyed = false; 373 374 // Save any prior tabindex info and make this node untabbable 375 this.ensureUntabbable(); 376 } 377 378 /** 379 * Call this whenever this object is about to become obsolete. 380 * This makes the managed node focusable again and deletes all of the previously stored state. 381 */ 382 383 384 _createClass(InertNode, [{ 385 key: 'destructor', 386 value: function destructor() { 387 this._throwIfDestroyed(); 388 389 if (this._node && this._node.nodeType === Node.ELEMENT_NODE) { 390 var element = /** @type {!HTMLElement} */this._node; 391 if (this._savedTabIndex !== null) { 392 element.setAttribute('tabindex', this._savedTabIndex); 393 } else { 394 element.removeAttribute('tabindex'); 395 } 396 397 // Use `delete` to restore native focus method. 398 if (this._overrodeFocusMethod) { 399 delete element.focus; 400 } 401 } 402 403 // See note in InertRoot.destructor for why we cast these nulls to ANY. 404 this._node = /** @type {?} */null; 405 this._inertRoots = /** @type {?} */null; 406 this._destroyed = true; 407 } 408 409 /** 410 * @type {boolean} Whether this object is obsolete because the managed node is no longer inert. 411 * If the object has been destroyed, any attempt to access it will cause an exception. 412 */ 413 414 }, { 415 key: '_throwIfDestroyed', 416 417 418 /** 419 * Throw if user tries to access destroyed InertNode. 420 */ 421 value: function _throwIfDestroyed() { 422 if (this.destroyed) { 423 throw new Error('Trying to access destroyed InertNode'); 424 } 425 } 426 427 /** @return {boolean} */ 428 429 }, { 430 key: 'ensureUntabbable', 431 432 433 /** Save the existing tabindex value and make the node untabbable and unfocusable */ 434 value: function ensureUntabbable() { 435 if (this.node.nodeType !== Node.ELEMENT_NODE) { 436 return; 437 } 438 var element = /** @type {!HTMLElement} */this.node; 439 if (matches.call(element, _focusableElementsString)) { 440 if ( /** @type {!HTMLElement} */element.tabIndex === -1 && this.hasSavedTabIndex) { 441 return; 442 } 443 444 if (element.hasAttribute('tabindex')) { 445 this._savedTabIndex = /** @type {!HTMLElement} */element.tabIndex; 446 } 447 element.setAttribute('tabindex', '-1'); 448 if (element.nodeType === Node.ELEMENT_NODE) { 449 element.focus = function () {}; 450 this._overrodeFocusMethod = true; 451 } 452 } else if (element.hasAttribute('tabindex')) { 453 this._savedTabIndex = /** @type {!HTMLElement} */element.tabIndex; 454 element.removeAttribute('tabindex'); 455 } 456 } 457 458 /** 459 * Add another inert root to this inert node's set of managing inert roots. 460 * @param {!InertRoot} inertRoot 461 */ 462 463 }, { 464 key: 'addInertRoot', 465 value: function addInertRoot(inertRoot) { 466 this._throwIfDestroyed(); 467 this._inertRoots.add(inertRoot); 468 } 469 470 /** 471 * Remove the given inert root from this inert node's set of managing inert roots. 472 * If the set of managing inert roots becomes empty, this node is no longer inert, 473 * so the object should be destroyed. 474 * @param {!InertRoot} inertRoot 475 */ 476 477 }, { 478 key: 'removeInertRoot', 479 value: function removeInertRoot(inertRoot) { 480 this._throwIfDestroyed(); 481 this._inertRoots['delete'](inertRoot); 482 if (this._inertRoots.size === 0) { 483 this.destructor(); 484 } 485 } 486 }, { 487 key: 'destroyed', 488 get: function get() { 489 return (/** @type {!InertNode} */this._destroyed 490 ); 491 } 492 }, { 493 key: 'hasSavedTabIndex', 494 get: function get() { 495 return this._savedTabIndex !== null; 496 } 497 498 /** @return {!Node} */ 499 500 }, { 501 key: 'node', 502 get: function get() { 503 this._throwIfDestroyed(); 504 return this._node; 505 } 506 507 /** @param {?number} tabIndex */ 508 509 }, { 510 key: 'savedTabIndex', 511 set: function set(tabIndex) { 512 this._throwIfDestroyed(); 513 this._savedTabIndex = tabIndex; 514 } 515 516 /** @return {?number} */ 517 , 518 get: function get() { 519 this._throwIfDestroyed(); 520 return this._savedTabIndex; 521 } 522 }]); 523 524 return InertNode; 525 }(); 526 527 /** 528 * InertManager is a per-document singleton object which manages all inert roots and nodes. 529 * 530 * When an element becomes an inert root by having an `inert` attribute set and/or its `inert` 531 * property set to `true`, the `setInert` method creates an `InertRoot` object for the element. 532 * The `InertRoot` in turn registers itself as managing all of the element's focusable descendant 533 * nodes via the `register()` method. The `InertManager` ensures that a single `InertNode` instance 534 * is created for each such node, via the `_managedNodes` map. 535 */ 536 537 538 var InertManager = function () { 539 /** 540 * @param {!Document} document 541 */ 542 function InertManager(document) { 543 _classCallCheck(this, InertManager); 544 545 if (!document) { 546 throw new Error('Missing required argument; InertManager needs to wrap a document.'); 547 } 548 549 /** @type {!Document} */ 550 this._document = document; 551 552 /** 553 * All managed nodes known to this InertManager. In a map to allow looking up by Node. 554 * @type {!Map<!Node, !InertNode>} 555 */ 556 this._managedNodes = new Map(); 557 558 /** 559 * All inert roots known to this InertManager. In a map to allow looking up by Node. 560 * @type {!Map<!Node, !InertRoot>} 561 */ 562 this._inertRoots = new Map(); 563 564 /** 565 * Observer for mutations on `document.body`. 566 * @type {!MutationObserver} 567 */ 568 this._observer = new MutationObserver(this._watchForInert.bind(this)); 569 570 // Add inert style. 571 addInertStyle(document.head || document.body || document.documentElement); 572 573 // Wait for document to be loaded. 574 if (document.readyState === 'loading') { 575 document.addEventListener('DOMContentLoaded', this._onDocumentLoaded.bind(this)); 576 } else { 577 this._onDocumentLoaded(); 578 } 579 } 580 581 /** 582 * Set whether the given element should be an inert root or not. 583 * @param {!HTMLElement} root 584 * @param {boolean} inert 585 */ 586 587 588 _createClass(InertManager, [{ 589 key: 'setInert', 590 value: function setInert(root, inert) { 591 if (inert) { 592 if (this._inertRoots.has(root)) { 593 // element is already inert 594 return; 595 } 596 597 var inertRoot = new InertRoot(root, this); 598 root.setAttribute('inert', ''); 599 this._inertRoots.set(root, inertRoot); 600 // If not contained in the document, it must be in a shadowRoot. 601 // Ensure inert styles are added there. 602 if (!this._document.body.contains(root)) { 603 var parent = root.parentNode; 604 while (parent) { 605 if (parent.nodeType === 11) { 606 addInertStyle(parent); 607 } 608 parent = parent.parentNode; 609 } 610 } 611 } else { 612 if (!this._inertRoots.has(root)) { 613 // element is already non-inert 614 return; 615 } 616 617 var _inertRoot = this._inertRoots.get(root); 618 _inertRoot.destructor(); 619 this._inertRoots['delete'](root); 620 root.removeAttribute('inert'); 621 } 622 } 623 624 /** 625 * Get the InertRoot object corresponding to the given inert root element, if any. 626 * @param {!Node} element 627 * @return {!InertRoot|undefined} 628 */ 629 630 }, { 631 key: 'getInertRoot', 632 value: function getInertRoot(element) { 633 return this._inertRoots.get(element); 634 } 635 636 /** 637 * Register the given InertRoot as managing the given node. 638 * In the case where the node has a previously existing inert root, this inert root will 639 * be added to its set of inert roots. 640 * @param {!Node} node 641 * @param {!InertRoot} inertRoot 642 * @return {!InertNode} inertNode 643 */ 644 645 }, { 646 key: 'register', 647 value: function register(node, inertRoot) { 648 var inertNode = this._managedNodes.get(node); 649 if (inertNode !== undefined) { 650 // node was already in an inert subtree 651 inertNode.addInertRoot(inertRoot); 652 } else { 653 inertNode = new InertNode(node, inertRoot); 654 } 655 656 this._managedNodes.set(node, inertNode); 657 658 return inertNode; 659 } 660 661 /** 662 * De-register the given InertRoot as managing the given inert node. 663 * Removes the inert root from the InertNode's set of managing inert roots, and remove the inert 664 * node from the InertManager's set of managed nodes if it is destroyed. 665 * If the node is not currently managed, this is essentially a no-op. 666 * @param {!Node} node 667 * @param {!InertRoot} inertRoot 668 * @return {?InertNode} The potentially destroyed InertNode associated with this node, if any. 669 */ 670 671 }, { 672 key: 'deregister', 673 value: function deregister(node, inertRoot) { 674 var inertNode = this._managedNodes.get(node); 675 if (!inertNode) { 676 return null; 677 } 678 679 inertNode.removeInertRoot(inertRoot); 680 if (inertNode.destroyed) { 681 this._managedNodes['delete'](node); 682 } 683 684 return inertNode; 685 } 686 687 /** 688 * Callback used when document has finished loading. 689 */ 690 691 }, { 692 key: '_onDocumentLoaded', 693 value: function _onDocumentLoaded() { 694 // Find all inert roots in document and make them actually inert. 695 var inertElements = slice.call(this._document.querySelectorAll('[inert]')); 696 inertElements.forEach(function (inertElement) { 697 this.setInert(inertElement, true); 698 }, this); 699 700 // Comment this out to use programmatic API only. 701 this._observer.observe(this._document.body || this._document.documentElement, { attributes: true, subtree: true, childList: true }); 702 } 703 704 /** 705 * Callback used when mutation observer detects attribute changes. 706 * @param {!Array<!MutationRecord>} records 707 * @param {!MutationObserver} self 708 */ 709 710 }, { 711 key: '_watchForInert', 712 value: function _watchForInert(records, self) { 713 var _this = this; 714 records.forEach(function (record) { 715 switch (record.type) { 716 case 'childList': 717 slice.call(record.addedNodes).forEach(function (node) { 718 if (node.nodeType !== Node.ELEMENT_NODE) { 719 return; 720 } 721 var inertElements = slice.call(node.querySelectorAll('[inert]')); 722 if (matches.call(node, '[inert]')) { 723 inertElements.unshift(node); 724 } 725 inertElements.forEach(function (inertElement) { 726 this.setInert(inertElement, true); 727 }, _this); 728 }, _this); 729 break; 730 case 'attributes': 731 if (record.attributeName !== 'inert') { 732 return; 733 } 734 var target = /** @type {!HTMLElement} */record.target; 735 var inert = target.hasAttribute('inert'); 736 _this.setInert(target, inert); 737 break; 738 } 739 }, this); 740 } 741 }]); 742 743 return InertManager; 744 }(); 745 746 /** 747 * Recursively walk the composed tree from |node|. 748 * @param {!Node} node 749 * @param {(function (!HTMLElement))=} callback Callback to be called for each element traversed, 750 * before descending into child nodes. 751 * @param {?ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any. 752 */ 753 754 755 function composedTreeWalk(node, callback, shadowRootAncestor) { 756 if (node.nodeType == Node.ELEMENT_NODE) { 757 var element = /** @type {!HTMLElement} */node; 758 if (callback) { 759 callback(element); 760 } 761 762 // Descend into node: 763 // If it has a ShadowRoot, ignore all child elements - these will be picked 764 // up by the <content> or <shadow> elements. Descend straight into the 765 // ShadowRoot. 766 var shadowRoot = /** @type {!HTMLElement} */element.shadowRoot; 767 if (shadowRoot) { 768 composedTreeWalk(shadowRoot, callback, shadowRoot); 769 return; 770 } 771 772 // If it is a <content> element, descend into distributed elements - these 773 // are elements from outside the shadow root which are rendered inside the 774 // shadow DOM. 775 if (element.localName == 'content') { 776 var content = /** @type {!HTMLContentElement} */element; 777 // Verifies if ShadowDom v0 is supported. 778 var distributedNodes = content.getDistributedNodes ? content.getDistributedNodes() : []; 779 for (var i = 0; i < distributedNodes.length; i++) { 780 composedTreeWalk(distributedNodes[i], callback, shadowRootAncestor); 781 } 782 return; 783 } 784 785 // If it is a <slot> element, descend into assigned nodes - these 786 // are elements from outside the shadow root which are rendered inside the 787 // shadow DOM. 788 if (element.localName == 'slot') { 789 var slot = /** @type {!HTMLSlotElement} */element; 790 // Verify if ShadowDom v1 is supported. 791 var _distributedNodes = slot.assignedNodes ? slot.assignedNodes({ flatten: true }) : []; 792 for (var _i = 0; _i < _distributedNodes.length; _i++) { 793 composedTreeWalk(_distributedNodes[_i], callback, shadowRootAncestor); 794 } 795 return; 796 } 797 } 798 799 // If it is neither the parent of a ShadowRoot, a <content> element, a <slot> 800 // element, nor a <shadow> element recurse normally. 801 var child = node.firstChild; 802 while (child != null) { 803 composedTreeWalk(child, callback, shadowRootAncestor); 804 child = child.nextSibling; 805 } 806 } 807 808 /** 809 * Adds a style element to the node containing the inert specific styles 810 * @param {!Node} node 811 */ 812 function addInertStyle(node) { 813 if (node.querySelector('style#inert-style, link#inert-style')) { 814 return; 815 } 816 var style = document.createElement('style'); 817 style.setAttribute('id', 'inert-style'); 818 style.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'; 819 node.appendChild(style); 820 } 821 822 if (!HTMLElement.prototype.hasOwnProperty('inert')) { 823 /** @type {!InertManager} */ 824 var inertManager = new InertManager(document); 825 826 Object.defineProperty(HTMLElement.prototype, 'inert', { 827 enumerable: true, 828 /** @this {!HTMLElement} */ 829 get: function get() { 830 return this.hasAttribute('inert'); 831 }, 832 /** @this {!HTMLElement} */ 833 set: function set(inert) { 834 inertManager.setInert(this, inert); 835 } 836 }); 837 } 838 })(); 839 840 })));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |