[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/vendor/ -> wp-polyfill-inert.js (source)

   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') {
  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', '[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  })));


Generated : Sun Apr 28 08:20:02 2024 Cross-referenced by PHPXref