dom.js (63298B)
1 this["wp"] = this["wp"] || {}; this["wp"]["dom"] = 2 /******/ (function(modules) { // webpackBootstrap 3 /******/ // The module cache 4 /******/ var installedModules = {}; 5 /******/ 6 /******/ // The require function 7 /******/ function __webpack_require__(moduleId) { 8 /******/ 9 /******/ // Check if module is in cache 10 /******/ if(installedModules[moduleId]) { 11 /******/ return installedModules[moduleId].exports; 12 /******/ } 13 /******/ // Create a new module (and put it into the cache) 14 /******/ var module = installedModules[moduleId] = { 15 /******/ i: moduleId, 16 /******/ l: false, 17 /******/ exports: {} 18 /******/ }; 19 /******/ 20 /******/ // Execute the module function 21 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 /******/ 23 /******/ // Flag the module as loaded 24 /******/ module.l = true; 25 /******/ 26 /******/ // Return the exports of the module 27 /******/ return module.exports; 28 /******/ } 29 /******/ 30 /******/ 31 /******/ // expose the modules object (__webpack_modules__) 32 /******/ __webpack_require__.m = modules; 33 /******/ 34 /******/ // expose the module cache 35 /******/ __webpack_require__.c = installedModules; 36 /******/ 37 /******/ // define getter function for harmony exports 38 /******/ __webpack_require__.d = function(exports, name, getter) { 39 /******/ if(!__webpack_require__.o(exports, name)) { 40 /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 /******/ } 42 /******/ }; 43 /******/ 44 /******/ // define __esModule on exports 45 /******/ __webpack_require__.r = function(exports) { 46 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 /******/ } 49 /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 /******/ }; 51 /******/ 52 /******/ // create a fake namespace object 53 /******/ // mode & 1: value is a module id, require it 54 /******/ // mode & 2: merge all properties of value into the ns 55 /******/ // mode & 4: return value when already ns object 56 /******/ // mode & 8|1: behave like require 57 /******/ __webpack_require__.t = function(value, mode) { 58 /******/ if(mode & 1) value = __webpack_require__(value); 59 /******/ if(mode & 8) return value; 60 /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 /******/ var ns = Object.create(null); 62 /******/ __webpack_require__.r(ns); 63 /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 /******/ return ns; 66 /******/ }; 67 /******/ 68 /******/ // getDefaultExport function for compatibility with non-harmony modules 69 /******/ __webpack_require__.n = function(module) { 70 /******/ var getter = module && module.__esModule ? 71 /******/ function getDefault() { return module['default']; } : 72 /******/ function getModuleExports() { return module; }; 73 /******/ __webpack_require__.d(getter, 'a', getter); 74 /******/ return getter; 75 /******/ }; 76 /******/ 77 /******/ // Object.prototype.hasOwnProperty.call 78 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 /******/ 80 /******/ // __webpack_public_path__ 81 /******/ __webpack_require__.p = ""; 82 /******/ 83 /******/ 84 /******/ // Load entry module and return exports 85 /******/ return __webpack_require__(__webpack_require__.s = "2sUP"); 86 /******/ }) 87 /************************************************************************/ 88 /******/ ({ 89 90 /***/ "2sUP": 91 /***/ (function(module, __webpack_exports__, __webpack_require__) { 92 93 "use strict"; 94 // ESM COMPAT FLAG 95 __webpack_require__.r(__webpack_exports__); 96 97 // EXPORTS 98 __webpack_require__.d(__webpack_exports__, "focus", function() { return /* binding */ build_module_focus; }); 99 __webpack_require__.d(__webpack_exports__, "computeCaretRect", function() { return /* reexport */ computeCaretRect; }); 100 __webpack_require__.d(__webpack_exports__, "documentHasTextSelection", function() { return /* reexport */ documentHasTextSelection; }); 101 __webpack_require__.d(__webpack_exports__, "documentHasUncollapsedSelection", function() { return /* reexport */ documentHasUncollapsedSelection; }); 102 __webpack_require__.d(__webpack_exports__, "documentHasSelection", function() { return /* reexport */ documentHasSelection; }); 103 __webpack_require__.d(__webpack_exports__, "getRectangleFromRange", function() { return /* reexport */ getRectangleFromRange; }); 104 __webpack_require__.d(__webpack_exports__, "getScrollContainer", function() { return /* reexport */ getScrollContainer; }); 105 __webpack_require__.d(__webpack_exports__, "getOffsetParent", function() { return /* reexport */ getOffsetParent; }); 106 __webpack_require__.d(__webpack_exports__, "isEntirelySelected", function() { return /* reexport */ isEntirelySelected; }); 107 __webpack_require__.d(__webpack_exports__, "isHorizontalEdge", function() { return /* reexport */ isHorizontalEdge; }); 108 __webpack_require__.d(__webpack_exports__, "isNumberInput", function() { return /* reexport */ isNumberInput; }); 109 __webpack_require__.d(__webpack_exports__, "isTextField", function() { return /* reexport */ isTextField; }); 110 __webpack_require__.d(__webpack_exports__, "isVerticalEdge", function() { return /* reexport */ isVerticalEdge; }); 111 __webpack_require__.d(__webpack_exports__, "placeCaretAtHorizontalEdge", function() { return /* reexport */ placeCaretAtHorizontalEdge; }); 112 __webpack_require__.d(__webpack_exports__, "placeCaretAtVerticalEdge", function() { return /* reexport */ placeCaretAtVerticalEdge; }); 113 __webpack_require__.d(__webpack_exports__, "replace", function() { return /* reexport */ replace; }); 114 __webpack_require__.d(__webpack_exports__, "remove", function() { return /* reexport */ remove; }); 115 __webpack_require__.d(__webpack_exports__, "insertAfter", function() { return /* reexport */ insertAfter; }); 116 __webpack_require__.d(__webpack_exports__, "unwrap", function() { return /* reexport */ unwrap; }); 117 __webpack_require__.d(__webpack_exports__, "replaceTag", function() { return /* reexport */ replaceTag; }); 118 __webpack_require__.d(__webpack_exports__, "wrap", function() { return /* reexport */ wrap; }); 119 __webpack_require__.d(__webpack_exports__, "__unstableStripHTML", function() { return /* reexport */ stripHTML; }); 120 __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return /* reexport */ isEmpty; }); 121 __webpack_require__.d(__webpack_exports__, "removeInvalidHTML", function() { return /* reexport */ removeInvalidHTML; }); 122 __webpack_require__.d(__webpack_exports__, "isRTL", function() { return /* reexport */ isRTL; }); 123 __webpack_require__.d(__webpack_exports__, "safeHTML", function() { return /* reexport */ safeHTML; }); 124 __webpack_require__.d(__webpack_exports__, "getPhrasingContentSchema", function() { return /* reexport */ getPhrasingContentSchema; }); 125 __webpack_require__.d(__webpack_exports__, "isPhrasingContent", function() { return /* reexport */ isPhrasingContent; }); 126 __webpack_require__.d(__webpack_exports__, "isTextContent", function() { return /* reexport */ isTextContent; }); 127 __webpack_require__.d(__webpack_exports__, "getFilesFromDataTransfer", function() { return /* reexport */ getFilesFromDataTransfer; }); 128 129 // NAMESPACE OBJECT: ./node_modules/@wordpress/dom/build-module/focusable.js 130 var focusable_namespaceObject = {}; 131 __webpack_require__.r(focusable_namespaceObject); 132 __webpack_require__.d(focusable_namespaceObject, "find", function() { return find; }); 133 134 // NAMESPACE OBJECT: ./node_modules/@wordpress/dom/build-module/tabbable.js 135 var tabbable_namespaceObject = {}; 136 __webpack_require__.r(tabbable_namespaceObject); 137 __webpack_require__.d(tabbable_namespaceObject, "isTabbableIndex", function() { return isTabbableIndex; }); 138 __webpack_require__.d(tabbable_namespaceObject, "find", function() { return tabbable_find; }); 139 __webpack_require__.d(tabbable_namespaceObject, "findPrevious", function() { return findPrevious; }); 140 __webpack_require__.d(tabbable_namespaceObject, "findNext", function() { return findNext; }); 141 142 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/focusable.js 143 /** 144 * References: 145 * 146 * Focusable: 147 * - https://www.w3.org/TR/html5/editing.html#focus-management 148 * 149 * Sequential focus navigation: 150 * - https://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute 151 * 152 * Disabled elements: 153 * - https://www.w3.org/TR/html5/disabled-elements.html#disabled-elements 154 * 155 * getClientRects algorithm (requiring layout box): 156 * - https://www.w3.org/TR/cssom-view-1/#extension-to-the-element-interface 157 * 158 * AREA elements associated with an IMG: 159 * - https://w3c.github.io/html/editing.html#data-model 160 */ 161 const SELECTOR = ['[tabindex]', 'a[href]', 'button:not([disabled])', 'input:not([type="hidden"]):not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'iframe', 'object', 'embed', 'area[href]', '[contenteditable]:not([contenteditable=false])'].join(','); 162 /** 163 * Returns true if the specified element is visible (i.e. neither display: none 164 * nor visibility: hidden). 165 * 166 * @param {HTMLElement} element DOM element to test. 167 * 168 * @return {boolean} Whether element is visible. 169 */ 170 171 function isVisible(element) { 172 return element.offsetWidth > 0 || element.offsetHeight > 0 || element.getClientRects().length > 0; 173 } 174 /** 175 * Returns true if the specified element should be skipped from focusable elements. 176 * For now it rather specific for `iframes` and if tabindex attribute is set to -1. 177 * 178 * @param {Element} element DOM element to test. 179 * 180 * @return {boolean} Whether element should be skipped from focusable elements. 181 */ 182 183 184 function skipFocus(element) { 185 return element.nodeName.toLowerCase() === 'iframe' && element.getAttribute('tabindex') === '-1'; 186 } 187 /** 188 * Returns true if the specified area element is a valid focusable element, or 189 * false otherwise. Area is only focusable if within a map where a named map 190 * referenced by an image somewhere in the document. 191 * 192 * @param {HTMLAreaElement} element DOM area element to test. 193 * 194 * @return {boolean} Whether area element is valid for focus. 195 */ 196 197 198 function isValidFocusableArea(element) { 199 /** @type {HTMLMapElement | null} */ 200 const map = element.closest('map[name]'); 201 202 if (!map) { 203 return false; 204 } 205 /** @type {HTMLImageElement | null} */ 206 207 208 const img = element.ownerDocument.querySelector('img[usemap="#' + map.name + '"]'); 209 return !!img && isVisible(img); 210 } 211 /** 212 * Returns all focusable elements within a given context. 213 * 214 * @param {Element} context Element in which to search. 215 * 216 * @return {Element[]} Focusable elements. 217 */ 218 219 220 function find(context) { 221 /* eslint-disable jsdoc/no-undefined-types */ 222 223 /** @type {NodeListOf<HTMLElement>} */ 224 225 /* eslint-enable jsdoc/no-undefined-types */ 226 const elements = context.querySelectorAll(SELECTOR); 227 return Array.from(elements).filter(element => { 228 if (!isVisible(element) || skipFocus(element)) { 229 return false; 230 } 231 232 const { 233 nodeName 234 } = element; 235 236 if ('AREA' === nodeName) { 237 return isValidFocusableArea( 238 /** @type {HTMLAreaElement} */ 239 element); 240 } 241 242 return true; 243 }); 244 } 245 246 // EXTERNAL MODULE: external "lodash" 247 var external_lodash_ = __webpack_require__("YLtl"); 248 249 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/tabbable.js 250 /** 251 * External dependencies 252 */ 253 254 /** 255 * Internal dependencies 256 */ 257 258 259 /** 260 * Returns the tab index of the given element. In contrast with the tabIndex 261 * property, this normalizes the default (0) to avoid browser inconsistencies, 262 * operating under the assumption that this function is only ever called with a 263 * focusable node. 264 * 265 * @see https://bugzilla.mozilla.org/show_bug.cgi?id=1190261 266 * 267 * @param {Element} element Element from which to retrieve. 268 * 269 * @return {number} Tab index of element (default 0). 270 */ 271 272 function getTabIndex(element) { 273 const tabIndex = element.getAttribute('tabindex'); 274 return tabIndex === null ? 0 : parseInt(tabIndex, 10); 275 } 276 /** 277 * Returns true if the specified element is tabbable, or false otherwise. 278 * 279 * @param {Element} element Element to test. 280 * 281 * @return {boolean} Whether element is tabbable. 282 */ 283 284 285 function isTabbableIndex(element) { 286 return getTabIndex(element) !== -1; 287 } 288 /** @typedef {Element & { type?: string, checked?: boolean, name?: string }} MaybeHTMLInputElement */ 289 290 /** 291 * Returns a stateful reducer function which constructs a filtered array of 292 * tabbable elements, where at most one radio input is selected for a given 293 * name, giving priority to checked input, falling back to the first 294 * encountered. 295 * 296 * @return {(acc: MaybeHTMLInputElement[], el: MaybeHTMLInputElement) => MaybeHTMLInputElement[]} Radio group collapse reducer. 297 */ 298 299 function createStatefulCollapseRadioGroup() { 300 /** @type {Record<string, MaybeHTMLInputElement>} */ 301 const CHOSEN_RADIO_BY_NAME = {}; 302 return function collapseRadioGroup( 303 /** @type {MaybeHTMLInputElement[]} */ 304 result, 305 /** @type {MaybeHTMLInputElement} */ 306 element) { 307 const { 308 nodeName, 309 type, 310 checked, 311 name 312 } = element; // For all non-radio tabbables, construct to array by concatenating. 313 314 if (nodeName !== 'INPUT' || type !== 'radio' || !name) { 315 return result.concat(element); 316 } 317 318 const hasChosen = CHOSEN_RADIO_BY_NAME.hasOwnProperty(name); // Omit by skipping concatenation if the radio element is not chosen. 319 320 const isChosen = checked || !hasChosen; 321 322 if (!isChosen) { 323 return result; 324 } // At this point, if there had been a chosen element, the current 325 // element is checked and should take priority. Retroactively remove 326 // the element which had previously been considered the chosen one. 327 328 329 if (hasChosen) { 330 const hadChosenElement = CHOSEN_RADIO_BY_NAME[name]; 331 result = Object(external_lodash_["without"])(result, hadChosenElement); 332 } 333 334 CHOSEN_RADIO_BY_NAME[name] = element; 335 return result.concat(element); 336 }; 337 } 338 /** 339 * An array map callback, returning an object with the element value and its 340 * array index location as properties. This is used to emulate a proper stable 341 * sort where equal tabIndex should be left in order of their occurrence in the 342 * document. 343 * 344 * @param {Element} element Element. 345 * @param {number} index Array index of element. 346 * 347 * @return {{ element: Element, index: number }} Mapped object with element, index. 348 */ 349 350 351 function mapElementToObjectTabbable(element, index) { 352 return { 353 element, 354 index 355 }; 356 } 357 /** 358 * An array map callback, returning an element of the given mapped object's 359 * element value. 360 * 361 * @param {{ element: Element }} object Mapped object with element. 362 * 363 * @return {Element} Mapped object element. 364 */ 365 366 367 function mapObjectTabbableToElement(object) { 368 return object.element; 369 } 370 /** 371 * A sort comparator function used in comparing two objects of mapped elements. 372 * 373 * @see mapElementToObjectTabbable 374 * 375 * @param {{ element: Element, index: number }} a First object to compare. 376 * @param {{ element: Element, index: number }} b Second object to compare. 377 * 378 * @return {number} Comparator result. 379 */ 380 381 382 function compareObjectTabbables(a, b) { 383 const aTabIndex = getTabIndex(a.element); 384 const bTabIndex = getTabIndex(b.element); 385 386 if (aTabIndex === bTabIndex) { 387 return a.index - b.index; 388 } 389 390 return aTabIndex - bTabIndex; 391 } 392 /** 393 * Givin focusable elements, filters out tabbable element. 394 * 395 * @param {Element[]} focusables Focusable elements to filter. 396 * 397 * @return {Element[]} Tabbable elements. 398 */ 399 400 401 function filterTabbable(focusables) { 402 return focusables.filter(isTabbableIndex).map(mapElementToObjectTabbable).sort(compareObjectTabbables).map(mapObjectTabbableToElement).reduce(createStatefulCollapseRadioGroup(), []); 403 } 404 /** 405 * @param {Element} context 406 * @return {Element[]} Tabbable elements within the context. 407 */ 408 409 410 function tabbable_find(context) { 411 return filterTabbable(find(context)); 412 } 413 /** 414 * Given a focusable element, find the preceding tabbable element. 415 * 416 * @param {Element} element The focusable element before which to look. Defaults 417 * to the active element. 418 */ 419 420 function findPrevious(element) { 421 const focusables = find(element.ownerDocument.body); 422 const index = focusables.indexOf(element); // Remove all focusables after and including `element`. 423 424 focusables.length = index; 425 return Object(external_lodash_["last"])(filterTabbable(focusables)); 426 } 427 /** 428 * Given a focusable element, find the next tabbable element. 429 * 430 * @param {Element} element The focusable element after which to look. Defaults 431 * to the active element. 432 */ 433 434 function findNext(element) { 435 const focusables = find(element.ownerDocument.body); 436 const index = focusables.indexOf(element); // Remove all focusables before and inside `element`. 437 438 const remaining = focusables.slice(index + 1).filter(node => !element.contains(node)); 439 return Object(external_lodash_["first"])(filterTabbable(remaining)); 440 } 441 442 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/utils/assert-is-defined.js 443 function assertIsDefined(val, name) { 444 if (false) {} 445 } 446 447 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/get-rectangle-from-range.js 448 /** 449 * Internal dependencies 450 */ 451 452 /** 453 * Get the rectangle of a given Range. 454 * 455 * @param {Range} range The range. 456 * 457 * @return {DOMRect} The rectangle. 458 */ 459 460 function getRectangleFromRange(range) { 461 // For uncollapsed ranges, get the rectangle that bounds the contents of the 462 // range; this a rectangle enclosing the union of the bounding rectangles 463 // for all the elements in the range. 464 if (!range.collapsed) { 465 const rects = Array.from(range.getClientRects()); // If there's just a single rect, return it. 466 467 if (rects.length === 1) { 468 return rects[0]; 469 } // Ignore tiny selection at the edge of a range. 470 471 472 const filteredRects = rects.filter(({ 473 width 474 }) => width > 1); // If it's full of tiny selections, return browser default. 475 476 if (filteredRects.length === 0) { 477 return range.getBoundingClientRect(); 478 } 479 480 if (filteredRects.length === 1) { 481 return filteredRects[0]; 482 } 483 484 let { 485 top: furthestTop, 486 bottom: furthestBottom, 487 left: furthestLeft, 488 right: furthestRight 489 } = filteredRects[0]; 490 491 for (const { 492 top, 493 bottom, 494 left, 495 right 496 } of filteredRects) { 497 if (top < furthestTop) furthestTop = top; 498 if (bottom > furthestBottom) furthestBottom = bottom; 499 if (left < furthestLeft) furthestLeft = left; 500 if (right > furthestRight) furthestRight = right; 501 } 502 503 return new window.DOMRect(furthestLeft, furthestTop, furthestRight - furthestLeft, furthestBottom - furthestTop); 504 } 505 506 const { 507 startContainer 508 } = range; 509 const { 510 ownerDocument 511 } = startContainer; // Correct invalid "BR" ranges. The cannot contain any children. 512 513 if (startContainer.nodeName === 'BR') { 514 const { 515 parentNode 516 } = startContainer; 517 assertIsDefined(parentNode, 'parentNode'); 518 const index = 519 /** @type {Node[]} */ 520 Array.from(parentNode.childNodes).indexOf(startContainer); 521 assertIsDefined(ownerDocument, 'ownerDocument'); 522 range = ownerDocument.createRange(); 523 range.setStart(parentNode, index); 524 range.setEnd(parentNode, index); 525 } 526 527 let rect = range.getClientRects()[0]; // If the collapsed range starts (and therefore ends) at an element node, 528 // `getClientRects` can be empty in some browsers. This can be resolved 529 // by adding a temporary text node with zero-width space to the range. 530 // 531 // See: https://stackoverflow.com/a/6847328/995445 532 533 if (!rect) { 534 assertIsDefined(ownerDocument, 'ownerDocument'); 535 const padNode = ownerDocument.createTextNode('\u200b'); // Do not modify the live range. 536 537 range = range.cloneRange(); 538 range.insertNode(padNode); 539 rect = range.getClientRects()[0]; 540 assertIsDefined(padNode.parentNode, 'padNode.parentNode'); 541 padNode.parentNode.removeChild(padNode); 542 } 543 544 return rect; 545 } 546 547 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/compute-caret-rect.js 548 /** 549 * Internal dependencies 550 */ 551 552 553 /** 554 * Get the rectangle for the selection in a container. 555 * 556 * @param {Window} win The window of the selection. 557 * 558 * @return {DOMRect | null} The rectangle. 559 */ 560 561 function computeCaretRect(win) { 562 const selection = win.getSelection(); 563 assertIsDefined(selection, 'selection'); 564 const range = selection.rangeCount ? selection.getRangeAt(0) : null; 565 566 if (!range) { 567 return null; 568 } 569 570 return getRectangleFromRange(range); 571 } 572 573 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/document-has-text-selection.js 574 /** 575 * Internal dependencies 576 */ 577 578 /** 579 * Check whether the current document has selected text. This applies to ranges 580 * of text in the document, and not selection inside <input> and <textarea> 581 * elements. 582 * 583 * See: https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection#Related_objects. 584 * 585 * @param {Document} doc The document to check. 586 * 587 * @return {boolean} True if there is selection, false if not. 588 */ 589 590 function documentHasTextSelection(doc) { 591 assertIsDefined(doc.defaultView, 'doc.defaultView'); 592 const selection = doc.defaultView.getSelection(); 593 assertIsDefined(selection, 'selection'); 594 const range = selection.rangeCount ? selection.getRangeAt(0) : null; 595 return !!range && !range.collapsed; 596 } 597 598 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-html-input-element.js 599 /* eslint-disable jsdoc/valid-types */ 600 601 /** 602 * @param {Node} node 603 * @return {node is HTMLInputElement} Whether the node is an HTMLInputElement. 604 */ 605 function isHTMLInputElement(node) { 606 /* eslint-enable jsdoc/valid-types */ 607 return !!node && node.nodeName === 'INPUT'; 608 } 609 610 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-text-field.js 611 /** 612 * Internal dependencies 613 */ 614 615 /* eslint-disable jsdoc/valid-types */ 616 617 /** 618 * Check whether the given element is a text field, where text field is defined 619 * by the ability to select within the input, or that it is contenteditable. 620 * 621 * See: https://html.spec.whatwg.org/#textFieldSelection 622 * 623 * @param {Node} node The HTML element. 624 * @return {node is HTMLElement} True if the element is an text field, false if not. 625 */ 626 627 function isTextField(node) { 628 /* eslint-enable jsdoc/valid-types */ 629 const nonTextInputs = ['button', 'checkbox', 'hidden', 'file', 'radio', 'image', 'range', 'reset', 'submit', 'number']; 630 return isHTMLInputElement(node) && node.type && !nonTextInputs.includes(node.type) || node.nodeName === 'TEXTAREA' || 631 /** @type {HTMLElement} */ 632 node.contentEditable === 'true'; 633 } 634 635 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-number-input.js 636 /** 637 * Internal dependencies 638 */ 639 640 /* eslint-disable jsdoc/valid-types */ 641 642 /** 643 * Check whether the given element is an input field of type number 644 * and has a valueAsNumber 645 * 646 * @param {Node} node The HTML node. 647 * 648 * @return {node is HTMLInputElement} True if the node is input and holds a number. 649 */ 650 651 function isNumberInput(node) { 652 /* eslint-enable jsdoc/valid-types */ 653 return isHTMLInputElement(node) && node.type === 'number' && !!node.valueAsNumber; 654 } 655 656 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/input-field-has-uncollapsed-selection.js 657 /** 658 * Internal dependencies 659 */ 660 661 662 /** 663 * Check whether the given element, assumed an input field or textarea, 664 * contains a (uncollapsed) selection of text. 665 * 666 * Note: this is perhaps an abuse of the term "selection", since these elements 667 * manage selection differently and aren't covered by Selection#collapsed. 668 * 669 * See: https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection#Related_objects. 670 * 671 * @param {Element} element The HTML element. 672 * 673 * @return {boolean} Whether the input/textareaa element has some "selection". 674 */ 675 676 function inputFieldHasUncollapsedSelection(element) { 677 if (!isTextField(element) && !isNumberInput(element)) { 678 return false; 679 } 680 681 try { 682 const { 683 selectionStart, 684 selectionEnd 685 } = 686 /** @type {HTMLInputElement | HTMLTextAreaElement} */ 687 element; 688 return selectionStart !== null && selectionStart !== selectionEnd; 689 } catch (error) { 690 // Safari throws an exception when trying to get `selectionStart` 691 // on non-text <input> elements (which, understandably, don't 692 // have the text selection API). We catch this via a try/catch 693 // block, as opposed to a more explicit check of the element's 694 // input types, because of Safari's non-standard behavior. This 695 // also means we don't have to worry about the list of input 696 // types that support `selectionStart` changing as the HTML spec 697 // evolves over time. 698 return false; 699 } 700 } 701 702 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/document-has-uncollapsed-selection.js 703 /** 704 * Internal dependencies 705 */ 706 707 708 /** 709 * Check whether the current document has any sort of selection. This includes 710 * ranges of text across elements and any selection inside <input> and 711 * <textarea> elements. 712 * 713 * @param {Document} doc The document to check. 714 * 715 * @return {boolean} Whether there is any sort of "selection" in the document. 716 */ 717 718 function documentHasUncollapsedSelection(doc) { 719 return documentHasTextSelection(doc) || !!doc.activeElement && inputFieldHasUncollapsedSelection(doc.activeElement); 720 } 721 722 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/document-has-selection.js 723 /** 724 * Internal dependencies 725 */ 726 727 728 729 /** 730 * Check whether the current document has a selection. This checks for both 731 * focus in an input field and general text selection. 732 * 733 * @param {Document} doc The document to check. 734 * 735 * @return {boolean} True if there is selection, false if not. 736 */ 737 738 function documentHasSelection(doc) { 739 return !!doc.activeElement && (isTextField(doc.activeElement) || isNumberInput(doc.activeElement) || documentHasTextSelection(doc)); 740 } 741 742 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/get-computed-style.js 743 /** 744 * Internal dependencies 745 */ 746 747 /* eslint-disable jsdoc/valid-types */ 748 749 /** 750 * @param {Element} element 751 * @return {ReturnType<Window['getComputedStyle']>} The computed style for the element. 752 */ 753 754 function getComputedStyle(element) { 755 /* eslint-enable jsdoc/valid-types */ 756 assertIsDefined(element.ownerDocument.defaultView, 'element.ownerDocument.defaultView'); 757 return element.ownerDocument.defaultView.getComputedStyle(element); 758 } 759 760 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/get-scroll-container.js 761 /** 762 * Internal dependencies 763 */ 764 765 /** 766 * Given a DOM node, finds the closest scrollable container node. 767 * 768 * @param {Element | null} node Node from which to start. 769 * 770 * @return {Element | undefined} Scrollable container node, if found. 771 */ 772 773 function getScrollContainer(node) { 774 if (!node) { 775 return undefined; 776 } // Scrollable if scrollable height exceeds displayed... 777 778 779 if (node.scrollHeight > node.clientHeight) { 780 // ...except when overflow is defined to be hidden or visible 781 const { 782 overflowY 783 } = getComputedStyle(node); 784 785 if (/(auto|scroll)/.test(overflowY)) { 786 return node; 787 } 788 } // Continue traversing 789 790 791 return getScrollContainer( 792 /** @type {Element} */ 793 node.parentNode); 794 } 795 796 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/get-offset-parent.js 797 /** 798 * Internal dependencies 799 */ 800 801 /** 802 * Returns the closest positioned element, or null under any of the conditions 803 * of the offsetParent specification. Unlike offsetParent, this function is not 804 * limited to HTMLElement and accepts any Node (e.g. Node.TEXT_NODE). 805 * 806 * @see https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent 807 * 808 * @param {Node} node Node from which to find offset parent. 809 * 810 * @return {Node | null} Offset parent. 811 */ 812 813 function getOffsetParent(node) { 814 // Cannot retrieve computed style or offset parent only anything other than 815 // an element node, so find the closest element node. 816 let closestElement; 817 818 while (closestElement = 819 /** @type {Node} */ 820 node.parentNode) { 821 if (closestElement.nodeType === closestElement.ELEMENT_NODE) { 822 break; 823 } 824 } 825 826 if (!closestElement) { 827 return null; 828 } // If the closest element is already positioned, return it, as offsetParent 829 // does not otherwise consider the node itself. 830 831 832 if (getComputedStyle( 833 /** @type {Element} */ 834 closestElement).position !== 'static') { 835 return closestElement; 836 } // offsetParent is undocumented/draft 837 838 839 return ( 840 /** @type {Node & { offsetParent: Node }} */ 841 closestElement.offsetParent 842 ); 843 } 844 845 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-input-or-text-area.js 846 /* eslint-disable jsdoc/valid-types */ 847 848 /** 849 * @param {Element} element 850 * @return {element is HTMLInputElement | HTMLTextAreaElement} Whether the element is an input or textarea 851 */ 852 function isInputOrTextArea(element) { 853 /* eslint-enable jsdoc/valid-types */ 854 return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA'; 855 } 856 857 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-entirely-selected.js 858 /** 859 * Internal dependencies 860 */ 861 862 863 /** 864 * Check whether the contents of the element have been entirely selected. 865 * Returns true if there is no possibility of selection. 866 * 867 * @param {HTMLElement} element The element to check. 868 * 869 * @return {boolean} True if entirely selected, false if not. 870 */ 871 872 function isEntirelySelected(element) { 873 if (isInputOrTextArea(element)) { 874 return element.selectionStart === 0 && element.value.length === element.selectionEnd; 875 } 876 877 if (!element.isContentEditable) { 878 return true; 879 } 880 881 const { 882 ownerDocument 883 } = element; 884 const { 885 defaultView 886 } = ownerDocument; 887 assertIsDefined(defaultView, 'defaultView'); 888 const selection = defaultView.getSelection(); 889 assertIsDefined(selection, 'selection'); 890 const range = selection.rangeCount ? selection.getRangeAt(0) : null; 891 892 if (!range) { 893 return true; 894 } 895 896 const { 897 startContainer, 898 endContainer, 899 startOffset, 900 endOffset 901 } = range; 902 903 if (startContainer === element && endContainer === element && startOffset === 0 && endOffset === element.childNodes.length) { 904 return true; 905 } 906 907 const lastChild = element.lastChild; 908 assertIsDefined(lastChild, 'lastChild'); 909 const endContainerContentLength = endContainer.nodeType === endContainer.TEXT_NODE ? 910 /** @type {Text} */ 911 endContainer.data.length : endContainer.childNodes.length; 912 return isDeepChild(startContainer, element, 'firstChild') && isDeepChild(endContainer, element, 'lastChild') && startOffset === 0 && endOffset === endContainerContentLength; 913 } 914 /** 915 * Check whether the contents of the element have been entirely selected. 916 * Returns true if there is no possibility of selection. 917 * 918 * @param {HTMLElement|Node} query The element to check. 919 * @param {HTMLElement} container The container that we suspect "query" may be a first or last child of. 920 * @param {"firstChild"|"lastChild"} propName "firstChild" or "lastChild" 921 * 922 * @return {boolean} True if query is a deep first/last child of container, false otherwise. 923 */ 924 925 function isDeepChild(query, container, propName) { 926 /** @type {HTMLElement | ChildNode | null} */ 927 let candidate = container; 928 929 do { 930 if (query === candidate) { 931 return true; 932 } 933 934 candidate = candidate[propName]; 935 } while (candidate); 936 937 return false; 938 } 939 940 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-rtl.js 941 /** 942 * Internal dependencies 943 */ 944 945 /** 946 * Whether the element's text direction is right-to-left. 947 * 948 * @param {Element} element The element to check. 949 * 950 * @return {boolean} True if rtl, false if ltr. 951 */ 952 953 function isRTL(element) { 954 return getComputedStyle(element).direction === 'rtl'; 955 } 956 957 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/get-range-height.js 958 /** 959 * Gets the height of the range without ignoring zero width rectangles, which 960 * some browsers ignore when creating a union. 961 * 962 * @param {Range} range The range to check. 963 * @return {number | undefined} Height of the range or undefined if the range has no client rectangles. 964 */ 965 function getRangeHeight(range) { 966 const rects = Array.from(range.getClientRects()); 967 968 if (!rects.length) { 969 return; 970 } 971 972 const highestTop = Math.min(...rects.map(({ 973 top 974 }) => top)); 975 const lowestBottom = Math.max(...rects.map(({ 976 bottom 977 }) => bottom)); 978 return lowestBottom - highestTop; 979 } 980 981 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-selection-forward.js 982 /** 983 * Internal dependencies 984 */ 985 986 /** 987 * Returns true if the given selection object is in the forward direction, or 988 * false otherwise. 989 * 990 * @see https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition 991 * 992 * @param {Selection} selection Selection object to check. 993 * 994 * @return {boolean} Whether the selection is forward. 995 */ 996 997 function isSelectionForward(selection) { 998 const { 999 anchorNode, 1000 focusNode, 1001 anchorOffset, 1002 focusOffset 1003 } = selection; 1004 assertIsDefined(anchorNode, 'anchorNode'); 1005 assertIsDefined(focusNode, 'focusNode'); 1006 const position = anchorNode.compareDocumentPosition(focusNode); // Disable reason: `Node#compareDocumentPosition` returns a bitmask value, 1007 // so bitwise operators are intended. 1008 1009 /* eslint-disable no-bitwise */ 1010 // Compare whether anchor node precedes focus node. If focus node (where 1011 // end of selection occurs) is after the anchor node, it is forward. 1012 1013 if (position & anchorNode.DOCUMENT_POSITION_PRECEDING) { 1014 return false; 1015 } 1016 1017 if (position & anchorNode.DOCUMENT_POSITION_FOLLOWING) { 1018 return true; 1019 } 1020 /* eslint-enable no-bitwise */ 1021 // `compareDocumentPosition` returns 0 when passed the same node, in which 1022 // case compare offsets. 1023 1024 1025 if (position === 0) { 1026 return anchorOffset <= focusOffset; 1027 } // This should never be reached, but return true as default case. 1028 1029 1030 return true; 1031 } 1032 1033 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/caret-range-from-point.js 1034 /** 1035 * Polyfill. 1036 * Get a collapsed range for a given point. 1037 * 1038 * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/caretRangeFromPoint 1039 * 1040 * @param {Document} doc The document of the range. 1041 * @param {number} x Horizontal position within the current viewport. 1042 * @param {number} y Vertical position within the current viewport. 1043 * 1044 * @return {Range | null} The best range for the given point. 1045 */ 1046 function caretRangeFromPoint(doc, x, y) { 1047 if (doc.caretRangeFromPoint) { 1048 return doc.caretRangeFromPoint(x, y); 1049 } 1050 1051 if (!doc.caretPositionFromPoint) { 1052 return null; 1053 } 1054 1055 const point = doc.caretPositionFromPoint(x, y); // If x or y are negative, outside viewport, or there is no text entry node. 1056 // https://developer.mozilla.org/en-US/docs/Web/API/Document/caretRangeFromPoint 1057 1058 if (!point) { 1059 return null; 1060 } 1061 1062 const range = doc.createRange(); 1063 range.setStart(point.offsetNode, point.offset); 1064 range.collapse(true); 1065 return range; 1066 } 1067 1068 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/hidden-caret-range-from-point.js 1069 /** 1070 * Internal dependencies 1071 */ 1072 1073 1074 /** 1075 * Get a collapsed range for a given point. 1076 * Gives the container a temporary high z-index (above any UI). 1077 * This is preferred over getting the UI nodes and set styles there. 1078 * 1079 * @param {Document} doc The document of the range. 1080 * @param {number} x Horizontal position within the current viewport. 1081 * @param {number} y Vertical position within the current viewport. 1082 * @param {HTMLElement} container Container in which the range is expected to be found. 1083 * 1084 * @return {?Range} The best range for the given point. 1085 */ 1086 1087 function hiddenCaretRangeFromPoint(doc, x, y, container) { 1088 const originalZIndex = container.style.zIndex; 1089 const originalPosition = container.style.position; 1090 const { 1091 position = 'static' 1092 } = getComputedStyle(container); // A z-index only works if the element position is not static. 1093 1094 if (position === 'static') { 1095 container.style.position = 'relative'; 1096 } 1097 1098 container.style.zIndex = '10000'; 1099 const range = caretRangeFromPoint(doc, x, y); 1100 container.style.zIndex = originalZIndex; 1101 container.style.position = originalPosition; 1102 return range; 1103 } 1104 1105 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-edge.js 1106 /** 1107 * Internal dependencies 1108 */ 1109 1110 1111 1112 1113 1114 1115 1116 /** 1117 * Check whether the selection is at the edge of the container. Checks for 1118 * horizontal position by default. Set `onlyVertical` to true to check only 1119 * vertically. 1120 * 1121 * @param {Element} container Focusable element. 1122 * @param {boolean} isReverse Set to true to check left, false to check right. 1123 * @param {boolean} [onlyVertical=false] Set to true to check only vertical position. 1124 * 1125 * @return {boolean} True if at the edge, false if not. 1126 */ 1127 1128 function isEdge(container, isReverse, onlyVertical = false) { 1129 if (isInputOrTextArea(container)) { 1130 if (container.selectionStart !== container.selectionEnd) { 1131 return false; 1132 } 1133 1134 if (isReverse) { 1135 return container.selectionStart === 0; 1136 } 1137 1138 return container.value.length === container.selectionStart; 1139 } 1140 1141 if (! 1142 /** @type {HTMLElement} */ 1143 container.isContentEditable) { 1144 return true; 1145 } 1146 1147 const { 1148 ownerDocument 1149 } = container; 1150 const { 1151 defaultView 1152 } = ownerDocument; 1153 assertIsDefined(defaultView, 'defaultView'); 1154 const selection = defaultView.getSelection(); 1155 1156 if (!selection || !selection.rangeCount) { 1157 return false; 1158 } 1159 1160 const range = selection.getRangeAt(0); 1161 const collapsedRange = range.cloneRange(); 1162 const isForward = isSelectionForward(selection); 1163 const isCollapsed = selection.isCollapsed; // Collapse in direction of selection. 1164 1165 if (!isCollapsed) { 1166 collapsedRange.collapse(!isForward); 1167 } 1168 1169 const collapsedRangeRect = getRectangleFromRange(collapsedRange); 1170 const rangeRect = getRectangleFromRange(range); 1171 1172 if (!collapsedRangeRect || !rangeRect) { 1173 return false; 1174 } // Only consider the multiline selection at the edge if the direction is 1175 // towards the edge. The selection is multiline if it is taller than the 1176 // collapsed selection. 1177 1178 1179 const rangeHeight = getRangeHeight(range); 1180 1181 if (!isCollapsed && rangeHeight && rangeHeight > collapsedRangeRect.height && isForward === isReverse) { 1182 return false; 1183 } // In the case of RTL scripts, the horizontal edge is at the opposite side. 1184 1185 1186 const isReverseDir = isRTL(container) ? !isReverse : isReverse; 1187 const containerRect = container.getBoundingClientRect(); // To check if a selection is at the edge, we insert a test selection at the 1188 // edge of the container and check if the selections have the same vertical 1189 // or horizontal position. If they do, the selection is at the edge. 1190 // This method proves to be better than a DOM-based calculation for the 1191 // horizontal edge, since it ignores empty textnodes and a trailing line 1192 // break element. In other words, we need to check visual positioning, not 1193 // DOM positioning. 1194 // It also proves better than using the computed style for the vertical 1195 // edge, because we cannot know the padding and line height reliably in 1196 // pixels. `getComputedStyle` may return a value with different units. 1197 1198 const x = isReverseDir ? containerRect.left + 1 : containerRect.right - 1; 1199 const y = isReverse ? containerRect.top + 1 : containerRect.bottom - 1; 1200 const testRange = hiddenCaretRangeFromPoint(ownerDocument, x, y, 1201 /** @type {HTMLElement} */ 1202 container); 1203 1204 if (!testRange) { 1205 return false; 1206 } 1207 1208 const testRect = getRectangleFromRange(testRange); 1209 1210 if (!testRect) { 1211 return false; 1212 } 1213 1214 const verticalSide = isReverse ? 'top' : 'bottom'; 1215 const horizontalSide = isReverseDir ? 'left' : 'right'; 1216 const verticalDiff = testRect[verticalSide] - rangeRect[verticalSide]; 1217 const horizontalDiff = testRect[horizontalSide] - collapsedRangeRect[horizontalSide]; // Allow the position to be 1px off. 1218 1219 const hasVerticalDiff = Math.abs(verticalDiff) <= 1; 1220 const hasHorizontalDiff = Math.abs(horizontalDiff) <= 1; 1221 return onlyVertical ? hasVerticalDiff : hasVerticalDiff && hasHorizontalDiff; 1222 } 1223 1224 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-horizontal-edge.js 1225 /** 1226 * Internal dependencies 1227 */ 1228 1229 /** 1230 * Check whether the selection is horizontally at the edge of the container. 1231 * 1232 * @param {Element} container Focusable element. 1233 * @param {boolean} isReverse Set to true to check left, false for right. 1234 * 1235 * @return {boolean} True if at the horizontal edge, false if not. 1236 */ 1237 1238 function isHorizontalEdge(container, isReverse) { 1239 return isEdge(container, isReverse); 1240 } 1241 1242 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-vertical-edge.js 1243 /** 1244 * Internal dependencies 1245 */ 1246 1247 /** 1248 * Check whether the selection is vertically at the edge of the container. 1249 * 1250 * @param {Element} container Focusable element. 1251 * @param {boolean} isReverse Set to true to check top, false for bottom. 1252 * 1253 * @return {boolean} True if at the vertical edge, false if not. 1254 */ 1255 1256 function isVerticalEdge(container, isReverse) { 1257 return isEdge(container, isReverse, true); 1258 } 1259 1260 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/place-caret-at-horizontal-edge.js 1261 /** 1262 * Internal dependencies 1263 */ 1264 1265 /** 1266 * Internal dependencies 1267 */ 1268 1269 1270 1271 1272 /** 1273 * Gets the range to place. 1274 * 1275 * @param {HTMLElement} container Focusable element. 1276 * @param {boolean} isReverse True for end, false for start. 1277 * 1278 * @return {Range|null} The range to place. 1279 */ 1280 1281 function getRange(container, isReverse) { 1282 const { 1283 ownerDocument 1284 } = container; // In the case of RTL scripts, the horizontal edge is at the opposite side. 1285 1286 const isReverseDir = isRTL(container) ? !isReverse : isReverse; 1287 const containerRect = container.getBoundingClientRect(); // When placing at the end (isReverse), find the closest range to the bottom 1288 // right corner. When placing at the start, to the top left corner. 1289 1290 const x = isReverse ? containerRect.right - 1 : containerRect.left + 1; 1291 const y = isReverseDir ? containerRect.bottom - 1 : containerRect.top + 1; 1292 return hiddenCaretRangeFromPoint(ownerDocument, x, y, container); 1293 } 1294 /** 1295 * Places the caret at start or end of a given element. 1296 * 1297 * @param {HTMLElement} container Focusable element. 1298 * @param {boolean} isReverse True for end, false for start. 1299 */ 1300 1301 1302 function placeCaretAtHorizontalEdge(container, isReverse) { 1303 if (!container) { 1304 return; 1305 } 1306 1307 container.focus(); 1308 1309 if (isInputOrTextArea(container)) { 1310 // The element may not support selection setting. 1311 if (typeof container.selectionStart !== 'number') { 1312 return; 1313 } 1314 1315 if (isReverse) { 1316 container.selectionStart = container.value.length; 1317 container.selectionEnd = container.value.length; 1318 } else { 1319 container.selectionStart = 0; 1320 container.selectionEnd = 0; 1321 } 1322 1323 return; 1324 } 1325 1326 if (!container.isContentEditable) { 1327 return; 1328 } 1329 1330 let range = getRange(container, isReverse); // If no range range can be created or it is outside the container, the 1331 // element may be out of view. 1332 1333 if (!range || !range.startContainer || !container.contains(range.startContainer)) { 1334 container.scrollIntoView(isReverse); 1335 range = getRange(container, isReverse); 1336 1337 if (!range || !range.startContainer || !container.contains(range.startContainer)) { 1338 return; 1339 } 1340 } 1341 1342 const { 1343 ownerDocument 1344 } = container; 1345 const { 1346 defaultView 1347 } = ownerDocument; 1348 assertIsDefined(defaultView, 'defaultView'); 1349 const selection = defaultView.getSelection(); 1350 assertIsDefined(selection, 'selection'); 1351 selection.removeAllRanges(); 1352 selection.addRange(range); 1353 } 1354 1355 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/place-caret-at-vertical-edge.js 1356 /** 1357 * Internal dependencies 1358 */ 1359 1360 1361 1362 /** 1363 * Places the caret at the top or bottom of a given element. 1364 * 1365 * @param {HTMLElement} container Focusable element. 1366 * @param {boolean} isReverse True for bottom, false for top. 1367 * @param {DOMRect} [rect] The rectangle to position the caret with. 1368 * @param {boolean} [mayUseScroll=true] True to allow scrolling, false to disallow. 1369 */ 1370 1371 function placeCaretAtVerticalEdge(container, isReverse, rect, mayUseScroll = true) { 1372 if (!container) { 1373 return; 1374 } 1375 1376 if (!rect || !container.isContentEditable) { 1377 placeCaretAtHorizontalEdge(container, isReverse); 1378 return; 1379 } 1380 1381 container.focus(); // Offset by a buffer half the height of the caret rect. This is needed 1382 // because caretRangeFromPoint may default to the end of the selection if 1383 // offset is too close to the edge. It's unclear how to precisely calculate 1384 // this threshold; it may be the padded area of some combination of line 1385 // height, caret height, and font size. The buffer offset is effectively 1386 // equivalent to a point at half the height of a line of text. 1387 1388 const buffer = rect.height / 2; 1389 const editableRect = container.getBoundingClientRect(); 1390 const x = rect.left; 1391 const y = isReverse ? editableRect.bottom - buffer : editableRect.top + buffer; 1392 const { 1393 ownerDocument 1394 } = container; 1395 const { 1396 defaultView 1397 } = ownerDocument; 1398 const range = hiddenCaretRangeFromPoint(ownerDocument, x, y, container); 1399 1400 if (!range || !container.contains(range.startContainer)) { 1401 if (mayUseScroll && (!range || !range.startContainer || !range.startContainer.contains(container))) { 1402 // Might be out of view. 1403 // Easier than attempting to calculate manually. 1404 container.scrollIntoView(isReverse); 1405 placeCaretAtVerticalEdge(container, isReverse, rect, false); 1406 return; 1407 } 1408 1409 placeCaretAtHorizontalEdge(container, isReverse); 1410 return; 1411 } 1412 1413 assertIsDefined(defaultView, 'defaultView'); 1414 const selection = defaultView.getSelection(); 1415 assertIsDefined(selection, 'selection'); 1416 selection.removeAllRanges(); 1417 selection.addRange(range); 1418 } 1419 1420 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/insert-after.js 1421 /** 1422 * Internal dependencies 1423 */ 1424 1425 /** 1426 * Given two DOM nodes, inserts the former in the DOM as the next sibling of 1427 * the latter. 1428 * 1429 * @param {Node} newNode Node to be inserted. 1430 * @param {Node} referenceNode Node after which to perform the insertion. 1431 * @return {void} 1432 */ 1433 1434 function insertAfter(newNode, referenceNode) { 1435 assertIsDefined(referenceNode.parentNode, 'referenceNode.parentNode'); 1436 referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 1437 } 1438 1439 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/remove.js 1440 /** 1441 * Internal dependencies 1442 */ 1443 1444 /** 1445 * Given a DOM node, removes it from the DOM. 1446 * 1447 * @param {Node} node Node to be removed. 1448 * @return {void} 1449 */ 1450 1451 function remove(node) { 1452 assertIsDefined(node.parentNode, 'node.parentNode'); 1453 node.parentNode.removeChild(node); 1454 } 1455 1456 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/replace.js 1457 /** 1458 * Internal dependencies 1459 */ 1460 1461 1462 1463 /** 1464 * Given two DOM nodes, replaces the former with the latter in the DOM. 1465 * 1466 * @param {Element} processedNode Node to be removed. 1467 * @param {Element} newNode Node to be inserted in its place. 1468 * @return {void} 1469 */ 1470 1471 function replace(processedNode, newNode) { 1472 assertIsDefined(processedNode.parentNode, 'processedNode.parentNode'); 1473 insertAfter(newNode, processedNode.parentNode); 1474 remove(processedNode); 1475 } 1476 1477 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/unwrap.js 1478 /** 1479 * Internal dependencies 1480 */ 1481 1482 /** 1483 * Unwrap the given node. This means any child nodes are moved to the parent. 1484 * 1485 * @param {Node} node The node to unwrap. 1486 * 1487 * @return {void} 1488 */ 1489 1490 function unwrap(node) { 1491 const parent = node.parentNode; 1492 assertIsDefined(parent, 'node.parentNode'); 1493 1494 while (node.firstChild) { 1495 parent.insertBefore(node.firstChild, node); 1496 } 1497 1498 parent.removeChild(node); 1499 } 1500 1501 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/replace-tag.js 1502 /** 1503 * Internal dependencies 1504 */ 1505 1506 /** 1507 * Replaces the given node with a new node with the given tag name. 1508 * 1509 * @param {Element} node The node to replace 1510 * @param {string} tagName The new tag name. 1511 * 1512 * @return {Element} The new node. 1513 */ 1514 1515 function replaceTag(node, tagName) { 1516 const newNode = node.ownerDocument.createElement(tagName); 1517 1518 while (node.firstChild) { 1519 newNode.appendChild(node.firstChild); 1520 } 1521 1522 assertIsDefined(node.parentNode, 'node.parentNode'); 1523 node.parentNode.replaceChild(newNode, node); 1524 return newNode; 1525 } 1526 1527 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/wrap.js 1528 /** 1529 * Internal dependencies 1530 */ 1531 1532 /** 1533 * Wraps the given node with a new node with the given tag name. 1534 * 1535 * @param {Element} newNode The node to insert. 1536 * @param {Element} referenceNode The node to wrap. 1537 */ 1538 1539 function wrap(newNode, referenceNode) { 1540 assertIsDefined(referenceNode.parentNode, 'referenceNode.parentNode'); 1541 referenceNode.parentNode.insertBefore(newNode, referenceNode); 1542 newNode.appendChild(referenceNode); 1543 } 1544 1545 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/strip-html.js 1546 /** 1547 * Removes any HTML tags from the provided string. 1548 * 1549 * @param {string} html The string containing html. 1550 * 1551 * @return {string} The text content with any html removed. 1552 */ 1553 function stripHTML(html) { 1554 const document = new window.DOMParser().parseFromString(html, 'text/html'); 1555 return document.body.textContent || ''; 1556 } 1557 1558 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-empty.js 1559 /** 1560 * Recursively checks if an element is empty. An element is not empty if it 1561 * contains text or contains elements with attributes such as images. 1562 * 1563 * @param {Element} element The element to check. 1564 * 1565 * @return {boolean} Whether or not the element is empty. 1566 */ 1567 function isEmpty(element) { 1568 switch (element.nodeType) { 1569 case element.TEXT_NODE: 1570 // We cannot use \s since it includes special spaces which we want 1571 // to preserve. 1572 return /^[ \f\n\r\t\v\u00a0]*$/.test(element.nodeValue || ''); 1573 1574 case element.ELEMENT_NODE: 1575 if (element.hasAttributes()) { 1576 return false; 1577 } else if (!element.hasChildNodes()) { 1578 return true; 1579 } 1580 1581 return ( 1582 /** @type {Element[]} */ 1583 Array.from(element.childNodes).every(isEmpty) 1584 ); 1585 1586 default: 1587 return true; 1588 } 1589 } 1590 1591 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/phrasing-content.js 1592 /** 1593 * External dependencies 1594 */ 1595 1596 /** 1597 * All phrasing content elements. 1598 * 1599 * @see https://www.w3.org/TR/2011/WD-html5-20110525/content-models.html#phrasing-content-0 1600 */ 1601 1602 /** 1603 * @typedef {Record<string,SemanticElementDefinition>} ContentSchema 1604 */ 1605 1606 /** 1607 * @typedef SemanticElementDefinition 1608 * @property {string[]} [attributes] Content attributes 1609 * @property {ContentSchema} [children] Content attributes 1610 */ 1611 1612 /** 1613 * All text-level semantic elements. 1614 * 1615 * @see https://html.spec.whatwg.org/multipage/text-level-semantics.html 1616 * 1617 * @type {ContentSchema} 1618 */ 1619 1620 const textContentSchema = { 1621 strong: {}, 1622 em: {}, 1623 s: {}, 1624 del: {}, 1625 ins: {}, 1626 a: { 1627 attributes: ['href', 'target', 'rel'] 1628 }, 1629 code: {}, 1630 abbr: { 1631 attributes: ['title'] 1632 }, 1633 sub: {}, 1634 sup: {}, 1635 br: {}, 1636 small: {}, 1637 // To do: fix blockquote. 1638 // cite: {}, 1639 q: { 1640 attributes: ['cite'] 1641 }, 1642 dfn: { 1643 attributes: ['title'] 1644 }, 1645 data: { 1646 attributes: ['value'] 1647 }, 1648 time: { 1649 attributes: ['datetime'] 1650 }, 1651 var: {}, 1652 samp: {}, 1653 kbd: {}, 1654 i: {}, 1655 b: {}, 1656 u: {}, 1657 mark: {}, 1658 ruby: {}, 1659 rt: {}, 1660 rp: {}, 1661 bdi: { 1662 attributes: ['dir'] 1663 }, 1664 bdo: { 1665 attributes: ['dir'] 1666 }, 1667 wbr: {}, 1668 '#text': {} 1669 }; // Recursion is needed. 1670 // Possible: strong > em > strong. 1671 // Impossible: strong > strong. 1672 1673 Object(external_lodash_["without"])(Object.keys(textContentSchema), '#text', 'br').forEach(tag => { 1674 textContentSchema[tag].children = Object(external_lodash_["omit"])(textContentSchema, tag); 1675 }); 1676 /** 1677 * Embedded content elements. 1678 * 1679 * @see https://www.w3.org/TR/2011/WD-html5-20110525/content-models.html#embedded-content-0 1680 * 1681 * @type {ContentSchema} 1682 */ 1683 1684 const embeddedContentSchema = { 1685 audio: { 1686 attributes: ['src', 'preload', 'autoplay', 'mediagroup', 'loop', 'muted'] 1687 }, 1688 canvas: { 1689 attributes: ['width', 'height'] 1690 }, 1691 embed: { 1692 attributes: ['src', 'type', 'width', 'height'] 1693 }, 1694 img: { 1695 attributes: ['alt', 'src', 'srcset', 'usemap', 'ismap', 'width', 'height'] 1696 }, 1697 object: { 1698 attributes: ['data', 'type', 'name', 'usemap', 'form', 'width', 'height'] 1699 }, 1700 video: { 1701 attributes: ['src', 'poster', 'preload', 'autoplay', 'mediagroup', 'loop', 'muted', 'controls', 'width', 'height'] 1702 } 1703 }; 1704 /** 1705 * Phrasing content elements. 1706 * 1707 * @see https://www.w3.org/TR/2011/WD-html5-20110525/content-models.html#phrasing-content-0 1708 */ 1709 1710 const phrasingContentSchema = { ...textContentSchema, 1711 ...embeddedContentSchema 1712 }; 1713 /** 1714 * Get schema of possible paths for phrasing content. 1715 * 1716 * @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content 1717 * 1718 * @param {string} [context] Set to "paste" to exclude invisible elements and 1719 * sensitive data. 1720 * 1721 * @return {Partial<ContentSchema>} Schema. 1722 */ 1723 1724 function getPhrasingContentSchema(context) { 1725 if (context !== 'paste') { 1726 return phrasingContentSchema; 1727 } 1728 1729 return Object(external_lodash_["omit"])({ ...phrasingContentSchema, 1730 // We shouldn't paste potentially sensitive information which is not 1731 // visible to the user when pasted, so strip the attributes. 1732 ins: { 1733 children: phrasingContentSchema.ins.children 1734 }, 1735 del: { 1736 children: phrasingContentSchema.del.children 1737 } 1738 }, ['u', // Used to mark misspelling. Shouldn't be pasted. 1739 'abbr', // Invisible. 1740 'data', // Invisible. 1741 'time', // Invisible. 1742 'wbr', // Invisible. 1743 'bdi', // Invisible. 1744 'bdo' // Invisible. 1745 ]); 1746 } 1747 /** 1748 * Find out whether or not the given node is phrasing content. 1749 * 1750 * @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content 1751 * 1752 * @param {Node} node The node to test. 1753 * 1754 * @return {boolean} True if phrasing content, false if not. 1755 */ 1756 1757 function isPhrasingContent(node) { 1758 const tag = node.nodeName.toLowerCase(); 1759 return getPhrasingContentSchema().hasOwnProperty(tag) || tag === 'span'; 1760 } 1761 /** 1762 * @param {Node} node 1763 * @return {boolean} Node is text content 1764 */ 1765 1766 function isTextContent(node) { 1767 const tag = node.nodeName.toLowerCase(); 1768 return textContentSchema.hasOwnProperty(tag) || tag === 'span'; 1769 } 1770 1771 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/is-element.js 1772 /* eslint-disable jsdoc/valid-types */ 1773 1774 /** 1775 * @param {Node | null | undefined} node 1776 * @return {node is Element} True if node is an Element node 1777 */ 1778 function isElement(node) { 1779 /* eslint-enable jsdoc/valid-types */ 1780 return !!node && node.nodeType === node.ELEMENT_NODE; 1781 } 1782 1783 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/clean-node-list.js 1784 /** 1785 * External dependencies 1786 */ 1787 1788 /** 1789 * Internal dependencies 1790 */ 1791 1792 1793 1794 1795 1796 1797 1798 /* eslint-disable jsdoc/valid-types */ 1799 1800 /** 1801 * @typedef SchemaItem 1802 * @property {string[]} [attributes] Attributes. 1803 * @property {(string | RegExp)[]} [classes] Classnames or RegExp to test against. 1804 * @property {'*' | { [tag: string]: SchemaItem }} [children] Child schemas. 1805 * @property {string[]} [require] Selectors to test required children against. Leave empty or undefined if there are no requirements. 1806 * @property {boolean} allowEmpty Whether to allow nodes without children. 1807 * @property {(node: Node) => boolean} [isMatch] Function to test whether a node is a match. If left undefined any node will be assumed to match. 1808 */ 1809 1810 /** @typedef {{ [tag: string]: SchemaItem }} Schema */ 1811 1812 /* eslint-enable jsdoc/valid-types */ 1813 1814 /** 1815 * Given a schema, unwraps or removes nodes, attributes and classes on a node 1816 * list. 1817 * 1818 * @param {NodeList} nodeList The nodeList to filter. 1819 * @param {Document} doc The document of the nodeList. 1820 * @param {Schema} schema An array of functions that can mutate with the provided node. 1821 * @param {boolean} inline Whether to clean for inline mode. 1822 */ 1823 1824 function cleanNodeList(nodeList, doc, schema, inline) { 1825 Array.from(nodeList).forEach( 1826 /** @type {Node & { nextElementSibling?: unknown }} */ 1827 node => { 1828 var _schema$tag$isMatch, _schema$tag; 1829 1830 const tag = node.nodeName.toLowerCase(); // It's a valid child, if the tag exists in the schema without an isMatch 1831 // function, or with an isMatch function that matches the node. 1832 1833 if (schema.hasOwnProperty(tag) && (!schema[tag].isMatch || (_schema$tag$isMatch = (_schema$tag = schema[tag]).isMatch) !== null && _schema$tag$isMatch !== void 0 && _schema$tag$isMatch.call(_schema$tag, node))) { 1834 if (isElement(node)) { 1835 const { 1836 attributes = [], 1837 classes = [], 1838 children, 1839 require = [], 1840 allowEmpty 1841 } = schema[tag]; // If the node is empty and it's supposed to have children, 1842 // remove the node. 1843 1844 if (children && !allowEmpty && isEmpty(node)) { 1845 remove(node); 1846 return; 1847 } 1848 1849 if (node.hasAttributes()) { 1850 // Strip invalid attributes. 1851 Array.from(node.attributes).forEach(({ 1852 name 1853 }) => { 1854 if (name !== 'class' && !Object(external_lodash_["includes"])(attributes, name)) { 1855 node.removeAttribute(name); 1856 } 1857 }); // Strip invalid classes. 1858 // In jsdom-jscore, 'node.classList' can be undefined. 1859 // TODO: Explore patching this in jsdom-jscore. 1860 1861 if (node.classList && node.classList.length) { 1862 const mattchers = classes.map(item => { 1863 if (typeof item === 'string') { 1864 return ( 1865 /** @type {string} */ 1866 className => className === item 1867 ); 1868 } else if (item instanceof RegExp) { 1869 return ( 1870 /** @type {string} */ 1871 className => item.test(className) 1872 ); 1873 } 1874 1875 return external_lodash_["noop"]; 1876 }); 1877 Array.from(node.classList).forEach(name => { 1878 if (!mattchers.some(isMatch => isMatch(name))) { 1879 node.classList.remove(name); 1880 } 1881 }); 1882 1883 if (!node.classList.length) { 1884 node.removeAttribute('class'); 1885 } 1886 } 1887 } 1888 1889 if (node.hasChildNodes()) { 1890 // Do not filter any content. 1891 if (children === '*') { 1892 return; 1893 } // Continue if the node is supposed to have children. 1894 1895 1896 if (children) { 1897 // If a parent requires certain children, but it does 1898 // not have them, drop the parent and continue. 1899 if (require.length && !node.querySelector(require.join(','))) { 1900 cleanNodeList(node.childNodes, doc, schema, inline); 1901 unwrap(node); // If the node is at the top, phrasing content, and 1902 // contains children that are block content, unwrap 1903 // the node because it is invalid. 1904 } else if (node.parentNode && node.parentNode.nodeName === 'BODY' && isPhrasingContent(node)) { 1905 cleanNodeList(node.childNodes, doc, schema, inline); 1906 1907 if (Array.from(node.childNodes).some(child => !isPhrasingContent(child))) { 1908 unwrap(node); 1909 } 1910 } else { 1911 cleanNodeList(node.childNodes, doc, children, inline); 1912 } // Remove children if the node is not supposed to have any. 1913 1914 } else { 1915 while (node.firstChild) { 1916 remove(node.firstChild); 1917 } 1918 } 1919 } 1920 } // Invalid child. Continue with schema at the same place and unwrap. 1921 1922 } else { 1923 cleanNodeList(node.childNodes, doc, schema, inline); // For inline mode, insert a line break when unwrapping nodes that 1924 // are not phrasing content. 1925 1926 if (inline && !isPhrasingContent(node) && node.nextElementSibling) { 1927 insertAfter(doc.createElement('br'), node); 1928 } 1929 1930 unwrap(node); 1931 } 1932 }); 1933 } 1934 1935 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/remove-invalid-html.js 1936 /** 1937 * Internal dependencies 1938 */ 1939 1940 /** 1941 * Given a schema, unwraps or removes nodes, attributes and classes on HTML. 1942 * 1943 * @param {string} HTML The HTML to clean up. 1944 * @param {import('./clean-node-list').Schema} schema Schema for the HTML. 1945 * @param {boolean} inline Whether to clean for inline mode. 1946 * 1947 * @return {string} The cleaned up HTML. 1948 */ 1949 1950 function removeInvalidHTML(HTML, schema, inline) { 1951 const doc = document.implementation.createHTMLDocument(''); 1952 doc.body.innerHTML = HTML; 1953 cleanNodeList(doc.body.childNodes, doc, schema, inline); 1954 return doc.body.innerHTML; 1955 } 1956 1957 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/safe-html.js 1958 /** 1959 * Internal dependencies 1960 */ 1961 1962 /** 1963 * Strips scripts and on* attributes from HTML. 1964 * 1965 * @param {string} html HTML to sanitize. 1966 * 1967 * @return {string} The sanitized HTML. 1968 */ 1969 1970 function safeHTML(html) { 1971 const { 1972 body 1973 } = document.implementation.createHTMLDocument(''); 1974 body.innerHTML = html; 1975 const elements = body.getElementsByTagName('*'); 1976 let elementIndex = elements.length; 1977 1978 while (elementIndex--) { 1979 const element = elements[elementIndex]; 1980 1981 if (element.tagName === 'SCRIPT') { 1982 remove(element); 1983 } else { 1984 let attributeIndex = element.attributes.length; 1985 1986 while (attributeIndex--) { 1987 const { 1988 name: key 1989 } = element.attributes[attributeIndex]; 1990 1991 if (key.startsWith('on')) { 1992 element.removeAttribute(key); 1993 } 1994 } 1995 } 1996 } 1997 1998 return body.innerHTML; 1999 } 2000 2001 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/dom/index.js 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/data-transfer.js 2029 /** 2030 * Gets all files from a DataTransfer object. 2031 * 2032 * @param {DataTransfer} dataTransfer DataTransfer object to inspect. 2033 * 2034 * @return {File[]} An array containing all files. 2035 */ 2036 function getFilesFromDataTransfer(dataTransfer) { 2037 const files = Array.from(dataTransfer.files); 2038 Array.from(dataTransfer.items).forEach(item => { 2039 const file = item.getAsFile(); 2040 2041 if (file && !files.find(({ 2042 name, 2043 type, 2044 size 2045 }) => name === file.name && type === file.type && size === file.size)) { 2046 files.push(file); 2047 } 2048 }); 2049 return files; 2050 } 2051 2052 // CONCATENATED MODULE: ./node_modules/@wordpress/dom/build-module/index.js 2053 /** 2054 * Internal dependencies 2055 */ 2056 2057 2058 /** 2059 * Object grouping `focusable` and `tabbable` utils 2060 * under the keys with the same name. 2061 */ 2062 2063 const build_module_focus = { 2064 focusable: focusable_namespaceObject, 2065 tabbable: tabbable_namespaceObject 2066 }; 2067 2068 2069 2070 2071 2072 /***/ }), 2073 2074 /***/ "YLtl": 2075 /***/ (function(module, exports) { 2076 2077 (function() { module.exports = window["lodash"]; }()); 2078 2079 /***/ }) 2080 2081 /******/ });