rich-text.js (137499B)
1 this["wp"] = this["wp"] || {}; this["wp"]["richText"] = 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 = "yyEc"); 86 /******/ }) 87 /************************************************************************/ 88 /******/ ({ 89 90 /***/ "1ZqX": 91 /***/ (function(module, exports) { 92 93 (function() { module.exports = window["wp"]["data"]; }()); 94 95 /***/ }), 96 97 /***/ "GRId": 98 /***/ (function(module, exports) { 99 100 (function() { module.exports = window["wp"]["element"]; }()); 101 102 /***/ }), 103 104 /***/ "K9lf": 105 /***/ (function(module, exports) { 106 107 (function() { module.exports = window["wp"]["compose"]; }()); 108 109 /***/ }), 110 111 /***/ "RxS6": 112 /***/ (function(module, exports) { 113 114 (function() { module.exports = window["wp"]["keycodes"]; }()); 115 116 /***/ }), 117 118 /***/ "Vx3V": 119 /***/ (function(module, exports) { 120 121 (function() { module.exports = window["wp"]["escapeHtml"]; }()); 122 123 /***/ }), 124 125 /***/ "YLtl": 126 /***/ (function(module, exports) { 127 128 (function() { module.exports = window["lodash"]; }()); 129 130 /***/ }), 131 132 /***/ "pPDe": 133 /***/ (function(module, __webpack_exports__, __webpack_require__) { 134 135 "use strict"; 136 137 138 var LEAF_KEY, hasWeakMap; 139 140 /** 141 * Arbitrary value used as key for referencing cache object in WeakMap tree. 142 * 143 * @type {Object} 144 */ 145 LEAF_KEY = {}; 146 147 /** 148 * Whether environment supports WeakMap. 149 * 150 * @type {boolean} 151 */ 152 hasWeakMap = typeof WeakMap !== 'undefined'; 153 154 /** 155 * Returns the first argument as the sole entry in an array. 156 * 157 * @param {*} value Value to return. 158 * 159 * @return {Array} Value returned as entry in array. 160 */ 161 function arrayOf( value ) { 162 return [ value ]; 163 } 164 165 /** 166 * Returns true if the value passed is object-like, or false otherwise. A value 167 * is object-like if it can support property assignment, e.g. object or array. 168 * 169 * @param {*} value Value to test. 170 * 171 * @return {boolean} Whether value is object-like. 172 */ 173 function isObjectLike( value ) { 174 return !! value && 'object' === typeof value; 175 } 176 177 /** 178 * Creates and returns a new cache object. 179 * 180 * @return {Object} Cache object. 181 */ 182 function createCache() { 183 var cache = { 184 clear: function() { 185 cache.head = null; 186 }, 187 }; 188 189 return cache; 190 } 191 192 /** 193 * Returns true if entries within the two arrays are strictly equal by 194 * reference from a starting index. 195 * 196 * @param {Array} a First array. 197 * @param {Array} b Second array. 198 * @param {number} fromIndex Index from which to start comparison. 199 * 200 * @return {boolean} Whether arrays are shallowly equal. 201 */ 202 function isShallowEqual( a, b, fromIndex ) { 203 var i; 204 205 if ( a.length !== b.length ) { 206 return false; 207 } 208 209 for ( i = fromIndex; i < a.length; i++ ) { 210 if ( a[ i ] !== b[ i ] ) { 211 return false; 212 } 213 } 214 215 return true; 216 } 217 218 /** 219 * Returns a memoized selector function. The getDependants function argument is 220 * called before the memoized selector and is expected to return an immutable 221 * reference or array of references on which the selector depends for computing 222 * its own return value. The memoize cache is preserved only as long as those 223 * dependant references remain the same. If getDependants returns a different 224 * reference(s), the cache is cleared and the selector value regenerated. 225 * 226 * @param {Function} selector Selector function. 227 * @param {Function} getDependants Dependant getter returning an immutable 228 * reference or array of reference used in 229 * cache bust consideration. 230 * 231 * @return {Function} Memoized selector. 232 */ 233 /* harmony default export */ __webpack_exports__["a"] = (function( selector, getDependants ) { 234 var rootCache, getCache; 235 236 // Use object source as dependant if getter not provided 237 if ( ! getDependants ) { 238 getDependants = arrayOf; 239 } 240 241 /** 242 * Returns the root cache. If WeakMap is supported, this is assigned to the 243 * root WeakMap cache set, otherwise it is a shared instance of the default 244 * cache object. 245 * 246 * @return {(WeakMap|Object)} Root cache object. 247 */ 248 function getRootCache() { 249 return rootCache; 250 } 251 252 /** 253 * Returns the cache for a given dependants array. When possible, a WeakMap 254 * will be used to create a unique cache for each set of dependants. This 255 * is feasible due to the nature of WeakMap in allowing garbage collection 256 * to occur on entries where the key object is no longer referenced. Since 257 * WeakMap requires the key to be an object, this is only possible when the 258 * dependant is object-like. The root cache is created as a hierarchy where 259 * each top-level key is the first entry in a dependants set, the value a 260 * WeakMap where each key is the next dependant, and so on. This continues 261 * so long as the dependants are object-like. If no dependants are object- 262 * like, then the cache is shared across all invocations. 263 * 264 * @see isObjectLike 265 * 266 * @param {Array} dependants Selector dependants. 267 * 268 * @return {Object} Cache object. 269 */ 270 function getWeakMapCache( dependants ) { 271 var caches = rootCache, 272 isUniqueByDependants = true, 273 i, dependant, map, cache; 274 275 for ( i = 0; i < dependants.length; i++ ) { 276 dependant = dependants[ i ]; 277 278 // Can only compose WeakMap from object-like key. 279 if ( ! isObjectLike( dependant ) ) { 280 isUniqueByDependants = false; 281 break; 282 } 283 284 // Does current segment of cache already have a WeakMap? 285 if ( caches.has( dependant ) ) { 286 // Traverse into nested WeakMap. 287 caches = caches.get( dependant ); 288 } else { 289 // Create, set, and traverse into a new one. 290 map = new WeakMap(); 291 caches.set( dependant, map ); 292 caches = map; 293 } 294 } 295 296 // We use an arbitrary (but consistent) object as key for the last item 297 // in the WeakMap to serve as our running cache. 298 if ( ! caches.has( LEAF_KEY ) ) { 299 cache = createCache(); 300 cache.isUniqueByDependants = isUniqueByDependants; 301 caches.set( LEAF_KEY, cache ); 302 } 303 304 return caches.get( LEAF_KEY ); 305 } 306 307 // Assign cache handler by availability of WeakMap 308 getCache = hasWeakMap ? getWeakMapCache : getRootCache; 309 310 /** 311 * Resets root memoization cache. 312 */ 313 function clear() { 314 rootCache = hasWeakMap ? new WeakMap() : createCache(); 315 } 316 317 // eslint-disable-next-line jsdoc/check-param-names 318 /** 319 * The augmented selector call, considering first whether dependants have 320 * changed before passing it to underlying memoize function. 321 * 322 * @param {Object} source Source object for derivation. 323 * @param {...*} extraArgs Additional arguments to pass to selector. 324 * 325 * @return {*} Selector result. 326 */ 327 function callSelector( /* source, ...extraArgs */ ) { 328 var len = arguments.length, 329 cache, node, i, args, dependants; 330 331 // Create copy of arguments (avoid leaking deoptimization). 332 args = new Array( len ); 333 for ( i = 0; i < len; i++ ) { 334 args[ i ] = arguments[ i ]; 335 } 336 337 dependants = getDependants.apply( null, args ); 338 cache = getCache( dependants ); 339 340 // If not guaranteed uniqueness by dependants (primitive type or lack 341 // of WeakMap support), shallow compare against last dependants and, if 342 // references have changed, destroy cache to recalculate result. 343 if ( ! cache.isUniqueByDependants ) { 344 if ( cache.lastDependants && ! isShallowEqual( dependants, cache.lastDependants, 0 ) ) { 345 cache.clear(); 346 } 347 348 cache.lastDependants = dependants; 349 } 350 351 node = cache.head; 352 while ( node ) { 353 // Check whether node arguments match arguments 354 if ( ! isShallowEqual( node.args, args, 1 ) ) { 355 node = node.next; 356 continue; 357 } 358 359 // At this point we can assume we've found a match 360 361 // Surface matched node to head if not already 362 if ( node !== cache.head ) { 363 // Adjust siblings to point to each other. 364 node.prev.next = node.next; 365 if ( node.next ) { 366 node.next.prev = node.prev; 367 } 368 369 node.next = cache.head; 370 node.prev = null; 371 cache.head.prev = node; 372 cache.head = node; 373 } 374 375 // Return immediately 376 return node.val; 377 } 378 379 // No cached value found. Continue to insertion phase: 380 381 node = { 382 // Generate the result from original function 383 val: selector.apply( null, args ), 384 }; 385 386 // Avoid including the source object in the cache. 387 args[ 0 ] = null; 388 node.args = args; 389 390 // Don't need to check whether node is already head, since it would 391 // have been returned above already if it was 392 393 // Shift existing head down list 394 if ( cache.head ) { 395 cache.head.prev = node; 396 node.next = cache.head; 397 } 398 399 cache.head = node; 400 401 return node.val; 402 } 403 404 callSelector.getDependants = getDependants; 405 callSelector.clear = clear; 406 clear(); 407 408 return callSelector; 409 }); 410 411 412 /***/ }), 413 414 /***/ "yyEc": 415 /***/ (function(module, __webpack_exports__, __webpack_require__) { 416 417 "use strict"; 418 // ESM COMPAT FLAG 419 __webpack_require__.r(__webpack_exports__); 420 421 // EXPORTS 422 __webpack_require__.d(__webpack_exports__, "store", function() { return /* reexport */ store; }); 423 __webpack_require__.d(__webpack_exports__, "applyFormat", function() { return /* reexport */ applyFormat; }); 424 __webpack_require__.d(__webpack_exports__, "concat", function() { return /* reexport */ concat; }); 425 __webpack_require__.d(__webpack_exports__, "create", function() { return /* reexport */ create; }); 426 __webpack_require__.d(__webpack_exports__, "getActiveFormat", function() { return /* reexport */ getActiveFormat; }); 427 __webpack_require__.d(__webpack_exports__, "getActiveObject", function() { return /* reexport */ getActiveObject; }); 428 __webpack_require__.d(__webpack_exports__, "getTextContent", function() { return /* reexport */ getTextContent; }); 429 __webpack_require__.d(__webpack_exports__, "__unstableIsListRootSelected", function() { return /* reexport */ isListRootSelected; }); 430 __webpack_require__.d(__webpack_exports__, "__unstableIsActiveListType", function() { return /* reexport */ isActiveListType; }); 431 __webpack_require__.d(__webpack_exports__, "isCollapsed", function() { return /* reexport */ isCollapsed; }); 432 __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return /* reexport */ isEmpty; }); 433 __webpack_require__.d(__webpack_exports__, "__unstableIsEmptyLine", function() { return /* reexport */ isEmptyLine; }); 434 __webpack_require__.d(__webpack_exports__, "join", function() { return /* reexport */ join; }); 435 __webpack_require__.d(__webpack_exports__, "registerFormatType", function() { return /* reexport */ registerFormatType; }); 436 __webpack_require__.d(__webpack_exports__, "removeFormat", function() { return /* reexport */ removeFormat; }); 437 __webpack_require__.d(__webpack_exports__, "remove", function() { return /* reexport */ remove_remove; }); 438 __webpack_require__.d(__webpack_exports__, "replace", function() { return /* reexport */ replace_replace; }); 439 __webpack_require__.d(__webpack_exports__, "insert", function() { return /* reexport */ insert; }); 440 __webpack_require__.d(__webpack_exports__, "__unstableInsertLineSeparator", function() { return /* reexport */ insertLineSeparator; }); 441 __webpack_require__.d(__webpack_exports__, "__unstableRemoveLineSeparator", function() { return /* reexport */ removeLineSeparator; }); 442 __webpack_require__.d(__webpack_exports__, "insertObject", function() { return /* reexport */ insertObject; }); 443 __webpack_require__.d(__webpack_exports__, "slice", function() { return /* reexport */ slice; }); 444 __webpack_require__.d(__webpack_exports__, "split", function() { return /* reexport */ split; }); 445 __webpack_require__.d(__webpack_exports__, "__unstableToDom", function() { return /* reexport */ toDom; }); 446 __webpack_require__.d(__webpack_exports__, "toHTMLString", function() { return /* reexport */ toHTMLString; }); 447 __webpack_require__.d(__webpack_exports__, "toggleFormat", function() { return /* reexport */ toggleFormat; }); 448 __webpack_require__.d(__webpack_exports__, "__UNSTABLE_LINE_SEPARATOR", function() { return /* reexport */ LINE_SEPARATOR; }); 449 __webpack_require__.d(__webpack_exports__, "unregisterFormatType", function() { return /* reexport */ unregisterFormatType; }); 450 __webpack_require__.d(__webpack_exports__, "__unstableCanIndentListItems", function() { return /* reexport */ canIndentListItems; }); 451 __webpack_require__.d(__webpack_exports__, "__unstableCanOutdentListItems", function() { return /* reexport */ canOutdentListItems; }); 452 __webpack_require__.d(__webpack_exports__, "__unstableIndentListItems", function() { return /* reexport */ indentListItems; }); 453 __webpack_require__.d(__webpack_exports__, "__unstableOutdentListItems", function() { return /* reexport */ outdentListItems; }); 454 __webpack_require__.d(__webpack_exports__, "__unstableChangeListType", function() { return /* reexport */ changeListType; }); 455 __webpack_require__.d(__webpack_exports__, "__unstableCreateElement", function() { return /* reexport */ createElement; }); 456 __webpack_require__.d(__webpack_exports__, "useAnchorRef", function() { return /* reexport */ useAnchorRef; }); 457 __webpack_require__.d(__webpack_exports__, "__experimentalRichText", function() { return /* reexport */ __experimentalRichText; }); 458 __webpack_require__.d(__webpack_exports__, "__unstableUseRichText", function() { return /* reexport */ useRichText; }); 459 __webpack_require__.d(__webpack_exports__, "__unstableFormatEdit", function() { return /* reexport */ FormatEdit; }); 460 461 // NAMESPACE OBJECT: ./node_modules/@wordpress/rich-text/build-module/store/selectors.js 462 var selectors_namespaceObject = {}; 463 __webpack_require__.r(selectors_namespaceObject); 464 __webpack_require__.d(selectors_namespaceObject, "getFormatTypes", function() { return getFormatTypes; }); 465 __webpack_require__.d(selectors_namespaceObject, "getFormatType", function() { return getFormatType; }); 466 __webpack_require__.d(selectors_namespaceObject, "getFormatTypeForBareElement", function() { return getFormatTypeForBareElement; }); 467 __webpack_require__.d(selectors_namespaceObject, "getFormatTypeForClassName", function() { return getFormatTypeForClassName; }); 468 469 // NAMESPACE OBJECT: ./node_modules/@wordpress/rich-text/build-module/store/actions.js 470 var actions_namespaceObject = {}; 471 __webpack_require__.r(actions_namespaceObject); 472 __webpack_require__.d(actions_namespaceObject, "addFormatTypes", function() { return addFormatTypes; }); 473 __webpack_require__.d(actions_namespaceObject, "removeFormatTypes", function() { return removeFormatTypes; }); 474 475 // EXTERNAL MODULE: external ["wp","data"] 476 var external_wp_data_ = __webpack_require__("1ZqX"); 477 478 // EXTERNAL MODULE: external "lodash" 479 var external_lodash_ = __webpack_require__("YLtl"); 480 481 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/reducer.js 482 /** 483 * External dependencies 484 */ 485 486 /** 487 * WordPress dependencies 488 */ 489 490 491 /** 492 * Reducer managing the format types 493 * 494 * @param {Object} state Current state. 495 * @param {Object} action Dispatched action. 496 * 497 * @return {Object} Updated state. 498 */ 499 500 function reducer_formatTypes(state = {}, action) { 501 switch (action.type) { 502 case 'ADD_FORMAT_TYPES': 503 return { ...state, 504 ...Object(external_lodash_["keyBy"])(action.formatTypes, 'name') 505 }; 506 507 case 'REMOVE_FORMAT_TYPES': 508 return Object(external_lodash_["omit"])(state, action.names); 509 } 510 511 return state; 512 } 513 /* harmony default export */ var reducer = (Object(external_wp_data_["combineReducers"])({ 514 formatTypes: reducer_formatTypes 515 })); 516 517 // EXTERNAL MODULE: ./node_modules/rememo/es/rememo.js 518 var rememo = __webpack_require__("pPDe"); 519 520 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/selectors.js 521 /** 522 * External dependencies 523 */ 524 525 526 /** 527 * Returns all the available format types. 528 * 529 * @param {Object} state Data state. 530 * 531 * @return {Array} Format types. 532 */ 533 534 const getFormatTypes = Object(rememo["a" /* default */])(state => Object.values(state.formatTypes), state => [state.formatTypes]); 535 /** 536 * Returns a format type by name. 537 * 538 * @param {Object} state Data state. 539 * @param {string} name Format type name. 540 * 541 * @return {Object?} Format type. 542 */ 543 544 function getFormatType(state, name) { 545 return state.formatTypes[name]; 546 } 547 /** 548 * Gets the format type, if any, that can handle a bare element (without a 549 * data-format-type attribute), given the tag name of this element. 550 * 551 * @param {Object} state Data state. 552 * @param {string} bareElementTagName The tag name of the element to find a 553 * format type for. 554 * @return {?Object} Format type. 555 */ 556 557 function getFormatTypeForBareElement(state, bareElementTagName) { 558 return Object(external_lodash_["find"])(getFormatTypes(state), ({ 559 className, 560 tagName 561 }) => { 562 return className === null && bareElementTagName === tagName; 563 }); 564 } 565 /** 566 * Gets the format type, if any, that can handle an element, given its classes. 567 * 568 * @param {Object} state Data state. 569 * @param {string} elementClassName The classes of the element to find a format 570 * type for. 571 * @return {?Object} Format type. 572 */ 573 574 function getFormatTypeForClassName(state, elementClassName) { 575 return Object(external_lodash_["find"])(getFormatTypes(state), ({ 576 className 577 }) => { 578 if (className === null) { 579 return false; 580 } 581 582 return ` ${elementClassName} `.indexOf(` ${className} `) >= 0; 583 }); 584 } 585 586 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/actions.js 587 /** 588 * External dependencies 589 */ 590 591 /** 592 * Returns an action object used in signalling that format types have been 593 * added. 594 * 595 * @param {Array|Object} formatTypes Format types received. 596 * 597 * @return {Object} Action object. 598 */ 599 600 function addFormatTypes(formatTypes) { 601 return { 602 type: 'ADD_FORMAT_TYPES', 603 formatTypes: Object(external_lodash_["castArray"])(formatTypes) 604 }; 605 } 606 /** 607 * Returns an action object used to remove a registered format type. 608 * 609 * @param {string|Array} names Format name. 610 * 611 * @return {Object} Action object. 612 */ 613 614 function removeFormatTypes(names) { 615 return { 616 type: 'REMOVE_FORMAT_TYPES', 617 names: Object(external_lodash_["castArray"])(names) 618 }; 619 } 620 621 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/index.js 622 /** 623 * WordPress dependencies 624 */ 625 626 /** 627 * Internal dependencies 628 */ 629 630 631 632 633 const STORE_NAME = 'core/rich-text'; 634 /** 635 * Store definition for the rich-text namespace. 636 * 637 * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore 638 * 639 * @type {Object} 640 */ 641 642 const store = Object(external_wp_data_["createReduxStore"])(STORE_NAME, { 643 reducer: reducer, 644 selectors: selectors_namespaceObject, 645 actions: actions_namespaceObject 646 }); 647 Object(external_wp_data_["register"])(store); 648 649 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-format-equal.js 650 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 651 652 /** 653 * Optimised equality check for format objects. 654 * 655 * @param {?RichTextFormat} format1 Format to compare. 656 * @param {?RichTextFormat} format2 Format to compare. 657 * 658 * @return {boolean} True if formats are equal, false if not. 659 */ 660 function isFormatEqual(format1, format2) { 661 // Both not defined. 662 if (format1 === format2) { 663 return true; 664 } // Either not defined. 665 666 667 if (!format1 || !format2) { 668 return false; 669 } 670 671 if (format1.type !== format2.type) { 672 return false; 673 } 674 675 const attributes1 = format1.attributes; 676 const attributes2 = format2.attributes; // Both not defined. 677 678 if (attributes1 === attributes2) { 679 return true; 680 } // Either not defined. 681 682 683 if (!attributes1 || !attributes2) { 684 return false; 685 } 686 687 const keys1 = Object.keys(attributes1); 688 const keys2 = Object.keys(attributes2); 689 690 if (keys1.length !== keys2.length) { 691 return false; 692 } 693 694 const length = keys1.length; // Optimise for speed. 695 696 for (let i = 0; i < length; i++) { 697 const name = keys1[i]; 698 699 if (attributes1[name] !== attributes2[name]) { 700 return false; 701 } 702 } 703 704 return true; 705 } 706 707 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/normalise-formats.js 708 /** 709 * Internal dependencies 710 */ 711 712 /** @typedef {import('./create').RichTextValue} RichTextValue */ 713 714 /** 715 * Normalises formats: ensures subsequent adjacent equal formats have the same 716 * reference. 717 * 718 * @param {RichTextValue} value Value to normalise formats of. 719 * 720 * @return {RichTextValue} New value with normalised formats. 721 */ 722 723 function normaliseFormats(value) { 724 const newFormats = value.formats.slice(); 725 newFormats.forEach((formatsAtIndex, index) => { 726 const formatsAtPreviousIndex = newFormats[index - 1]; 727 728 if (formatsAtPreviousIndex) { 729 const newFormatsAtIndex = formatsAtIndex.slice(); 730 newFormatsAtIndex.forEach((format, formatIndex) => { 731 const previousFormat = formatsAtPreviousIndex[formatIndex]; 732 733 if (isFormatEqual(format, previousFormat)) { 734 newFormatsAtIndex[formatIndex] = previousFormat; 735 } 736 }); 737 newFormats[index] = newFormatsAtIndex; 738 } 739 }); 740 return { ...value, 741 formats: newFormats 742 }; 743 } 744 745 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/apply-format.js 746 /** 747 * External dependencies 748 */ 749 750 /** 751 * Internal dependencies 752 */ 753 754 755 /** @typedef {import('./create').RichTextValue} RichTextValue */ 756 757 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 758 759 function replace(array, index, value) { 760 array = array.slice(); 761 array[index] = value; 762 return array; 763 } 764 /** 765 * Apply a format object to a Rich Text value from the given `startIndex` to the 766 * given `endIndex`. Indices are retrieved from the selection if none are 767 * provided. 768 * 769 * @param {RichTextValue} value Value to modify. 770 * @param {RichTextFormat} format Format to apply. 771 * @param {number} [startIndex] Start index. 772 * @param {number} [endIndex] End index. 773 * 774 * @return {RichTextValue} A new value with the format applied. 775 */ 776 777 778 function applyFormat(value, format, startIndex = value.start, endIndex = value.end) { 779 const { 780 formats, 781 activeFormats 782 } = value; 783 const newFormats = formats.slice(); // The selection is collapsed. 784 785 if (startIndex === endIndex) { 786 const startFormat = Object(external_lodash_["find"])(newFormats[startIndex], { 787 type: format.type 788 }); // If the caret is at a format of the same type, expand start and end to 789 // the edges of the format. This is useful to apply new attributes. 790 791 if (startFormat) { 792 const index = newFormats[startIndex].indexOf(startFormat); 793 794 while (newFormats[startIndex] && newFormats[startIndex][index] === startFormat) { 795 newFormats[startIndex] = replace(newFormats[startIndex], index, format); 796 startIndex--; 797 } 798 799 endIndex++; 800 801 while (newFormats[endIndex] && newFormats[endIndex][index] === startFormat) { 802 newFormats[endIndex] = replace(newFormats[endIndex], index, format); 803 endIndex++; 804 } 805 } 806 } else { 807 // Determine the highest position the new format can be inserted at. 808 let position = +Infinity; 809 810 for (let index = startIndex; index < endIndex; index++) { 811 if (newFormats[index]) { 812 newFormats[index] = newFormats[index].filter(({ 813 type 814 }) => type !== format.type); 815 const length = newFormats[index].length; 816 817 if (length < position) { 818 position = length; 819 } 820 } else { 821 newFormats[index] = []; 822 position = 0; 823 } 824 } 825 826 for (let index = startIndex; index < endIndex; index++) { 827 newFormats[index].splice(position, 0, format); 828 } 829 } 830 831 return normaliseFormats({ ...value, 832 formats: newFormats, 833 // Always revise active formats. This serves as a placeholder for new 834 // inputs with the format so new input appears with the format applied, 835 // and ensures a format of the same type uses the latest values. 836 activeFormats: [...Object(external_lodash_["reject"])(activeFormats, { 837 type: format.type 838 }), format] 839 }); 840 } 841 842 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/create-element.js 843 /** 844 * Parse the given HTML into a body element. 845 * 846 * Note: The current implementation will return a shared reference, reset on 847 * each call to `createElement`. Therefore, you should not hold a reference to 848 * the value to operate upon asynchronously, as it may have unexpected results. 849 * 850 * @param {HTMLDocument} document The HTML document to use to parse. 851 * @param {string} html The HTML to parse. 852 * 853 * @return {HTMLBodyElement} Body element with parsed HTML. 854 */ 855 function createElement({ 856 implementation 857 }, html) { 858 // Because `createHTMLDocument` is an expensive operation, and with this 859 // function being internal to `rich-text` (full control in avoiding a risk 860 // of asynchronous operations on the shared reference), a single document 861 // is reused and reset for each call to the function. 862 if (!createElement.body) { 863 createElement.body = implementation.createHTMLDocument('').body; 864 } 865 866 createElement.body.innerHTML = html; 867 return createElement.body; 868 } 869 870 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/special-characters.js 871 /** 872 * Line separator character, used for multiline text. 873 */ 874 const LINE_SEPARATOR = '\u2028'; 875 /** 876 * Object replacement character, used as a placeholder for objects. 877 */ 878 879 const OBJECT_REPLACEMENT_CHARACTER = '\ufffc'; 880 /** 881 * Zero width non-breaking space, used as padding in the editable DOM tree when 882 * it is empty otherwise. 883 */ 884 885 const ZWNBSP = '\ufeff'; 886 887 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/create.js 888 /** 889 * WordPress dependencies 890 */ 891 892 /** 893 * Internal dependencies 894 */ 895 896 897 898 899 900 /** 901 * @typedef {Object} RichTextFormat 902 * 903 * @property {string} type Format type. 904 */ 905 906 /** 907 * @typedef {Array<RichTextFormat>} RichTextFormatList 908 */ 909 910 /** 911 * @typedef {Object} RichTextValue 912 * 913 * @property {string} text Text. 914 * @property {Array<RichTextFormatList>} formats Formats. 915 * @property {Array<RichTextFormat>} replacements Replacements. 916 * @property {number|undefined} start Selection start. 917 * @property {number|undefined} end Selection end. 918 */ 919 920 function createEmptyValue() { 921 return { 922 formats: [], 923 replacements: [], 924 text: '' 925 }; 926 } 927 928 function simpleFindKey(object, value) { 929 for (const key in object) { 930 if (object[key] === value) { 931 return key; 932 } 933 } 934 } 935 936 function toFormat({ 937 type, 938 attributes 939 }) { 940 let formatType; 941 942 if (attributes && attributes.class) { 943 formatType = Object(external_wp_data_["select"])('core/rich-text').getFormatTypeForClassName(attributes.class); 944 945 if (formatType) { 946 // Preserve any additional classes. 947 attributes.class = ` ${attributes.class} `.replace(` ${formatType.className} `, ' ').trim(); 948 949 if (!attributes.class) { 950 delete attributes.class; 951 } 952 } 953 } 954 955 if (!formatType) { 956 formatType = Object(external_wp_data_["select"])('core/rich-text').getFormatTypeForBareElement(type); 957 } 958 959 if (!formatType) { 960 return attributes ? { 961 type, 962 attributes 963 } : { 964 type 965 }; 966 } 967 968 if (formatType.__experimentalCreatePrepareEditableTree && !formatType.__experimentalCreateOnChangeEditableValue) { 969 return null; 970 } 971 972 if (!attributes) { 973 return { 974 type: formatType.name 975 }; 976 } 977 978 const registeredAttributes = {}; 979 const unregisteredAttributes = {}; 980 981 for (const name in attributes) { 982 const key = simpleFindKey(formatType.attributes, name); 983 984 if (key) { 985 registeredAttributes[key] = attributes[name]; 986 } else { 987 unregisteredAttributes[name] = attributes[name]; 988 } 989 } 990 991 return { 992 type: formatType.name, 993 attributes: registeredAttributes, 994 unregisteredAttributes 995 }; 996 } 997 /** 998 * Create a RichText value from an `Element` tree (DOM), an HTML string or a 999 * plain text string, with optionally a `Range` object to set the selection. If 1000 * called without any input, an empty value will be created. If 1001 * `multilineTag` is provided, any content of direct children whose type matches 1002 * `multilineTag` will be separated by two newlines. The optional functions can 1003 * be used to filter out content. 1004 * 1005 * A value will have the following shape, which you are strongly encouraged not 1006 * to modify without the use of helper functions: 1007 * 1008 * ```js 1009 * { 1010 * text: string, 1011 * formats: Array, 1012 * replacements: Array, 1013 * ?start: number, 1014 * ?end: number, 1015 * } 1016 * ``` 1017 * 1018 * As you can see, text and formatting are separated. `text` holds the text, 1019 * including any replacement characters for objects and lines. `formats`, 1020 * `objects` and `lines` are all sparse arrays of the same length as `text`. It 1021 * holds information about the formatting at the relevant text indices. Finally 1022 * `start` and `end` state which text indices are selected. They are only 1023 * provided if a `Range` was given. 1024 * 1025 * @param {Object} [$1] Optional named arguments. 1026 * @param {Element} [$1.element] Element to create value from. 1027 * @param {string} [$1.text] Text to create value from. 1028 * @param {string} [$1.html] HTML to create value from. 1029 * @param {Range} [$1.range] Range to create value from. 1030 * @param {string} [$1.multilineTag] Multiline tag if the structure is 1031 * multiline. 1032 * @param {Array} [$1.multilineWrapperTags] Tags where lines can be found if 1033 * nesting is possible. 1034 * @param {boolean} [$1.preserveWhiteSpace] Whether or not to collapse white 1035 * space characters. 1036 * @param {boolean} [$1.__unstableIsEditableTree] 1037 * 1038 * @return {RichTextValue} A rich text value. 1039 */ 1040 1041 1042 function create({ 1043 element, 1044 text, 1045 html, 1046 range, 1047 multilineTag, 1048 multilineWrapperTags, 1049 __unstableIsEditableTree: isEditableTree, 1050 preserveWhiteSpace 1051 } = {}) { 1052 if (typeof text === 'string' && text.length > 0) { 1053 return { 1054 formats: Array(text.length), 1055 replacements: Array(text.length), 1056 text 1057 }; 1058 } 1059 1060 if (typeof html === 'string' && html.length > 0) { 1061 // It does not matter which document this is, we're just using it to 1062 // parse. 1063 element = createElement(document, html); 1064 } 1065 1066 if (typeof element !== 'object') { 1067 return createEmptyValue(); 1068 } 1069 1070 if (!multilineTag) { 1071 return createFromElement({ 1072 element, 1073 range, 1074 isEditableTree, 1075 preserveWhiteSpace 1076 }); 1077 } 1078 1079 return createFromMultilineElement({ 1080 element, 1081 range, 1082 multilineTag, 1083 multilineWrapperTags, 1084 isEditableTree, 1085 preserveWhiteSpace 1086 }); 1087 } 1088 /** 1089 * Helper to accumulate the value's selection start and end from the current 1090 * node and range. 1091 * 1092 * @param {Object} accumulator Object to accumulate into. 1093 * @param {Node} node Node to create value with. 1094 * @param {Range} range Range to create value with. 1095 * @param {Object} value Value that is being accumulated. 1096 */ 1097 1098 function accumulateSelection(accumulator, node, range, value) { 1099 if (!range) { 1100 return; 1101 } 1102 1103 const { 1104 parentNode 1105 } = node; 1106 const { 1107 startContainer, 1108 startOffset, 1109 endContainer, 1110 endOffset 1111 } = range; 1112 const currentLength = accumulator.text.length; // Selection can be extracted from value. 1113 1114 if (value.start !== undefined) { 1115 accumulator.start = currentLength + value.start; // Range indicates that the current node has selection. 1116 } else if (node === startContainer && node.nodeType === node.TEXT_NODE) { 1117 accumulator.start = currentLength + startOffset; // Range indicates that the current node is selected. 1118 } else if (parentNode === startContainer && node === startContainer.childNodes[startOffset]) { 1119 accumulator.start = currentLength; // Range indicates that the selection is after the current node. 1120 } else if (parentNode === startContainer && node === startContainer.childNodes[startOffset - 1]) { 1121 accumulator.start = currentLength + value.text.length; // Fallback if no child inside handled the selection. 1122 } else if (node === startContainer) { 1123 accumulator.start = currentLength; 1124 } // Selection can be extracted from value. 1125 1126 1127 if (value.end !== undefined) { 1128 accumulator.end = currentLength + value.end; // Range indicates that the current node has selection. 1129 } else if (node === endContainer && node.nodeType === node.TEXT_NODE) { 1130 accumulator.end = currentLength + endOffset; // Range indicates that the current node is selected. 1131 } else if (parentNode === endContainer && node === endContainer.childNodes[endOffset - 1]) { 1132 accumulator.end = currentLength + value.text.length; // Range indicates that the selection is before the current node. 1133 } else if (parentNode === endContainer && node === endContainer.childNodes[endOffset]) { 1134 accumulator.end = currentLength; // Fallback if no child inside handled the selection. 1135 } else if (node === endContainer) { 1136 accumulator.end = currentLength + endOffset; 1137 } 1138 } 1139 /** 1140 * Adjusts the start and end offsets from a range based on a text filter. 1141 * 1142 * @param {Node} node Node of which the text should be filtered. 1143 * @param {Range} range The range to filter. 1144 * @param {Function} filter Function to use to filter the text. 1145 * 1146 * @return {Object|void} Object containing range properties. 1147 */ 1148 1149 1150 function filterRange(node, range, filter) { 1151 if (!range) { 1152 return; 1153 } 1154 1155 const { 1156 startContainer, 1157 endContainer 1158 } = range; 1159 let { 1160 startOffset, 1161 endOffset 1162 } = range; 1163 1164 if (node === startContainer) { 1165 startOffset = filter(node.nodeValue.slice(0, startOffset)).length; 1166 } 1167 1168 if (node === endContainer) { 1169 endOffset = filter(node.nodeValue.slice(0, endOffset)).length; 1170 } 1171 1172 return { 1173 startContainer, 1174 startOffset, 1175 endContainer, 1176 endOffset 1177 }; 1178 } 1179 /** 1180 * Collapse any whitespace used for HTML formatting to one space character, 1181 * because it will also be displayed as such by the browser. 1182 * 1183 * @param {string} string 1184 */ 1185 1186 1187 function collapseWhiteSpace(string) { 1188 return string.replace(/[\n\r\t]+/g, ' '); 1189 } 1190 1191 const ZWNBSPRegExp = new RegExp(ZWNBSP, 'g'); 1192 /** 1193 * Removes padding (zero width non breaking spaces) added by `toTree`. 1194 * 1195 * @param {string} string 1196 */ 1197 1198 function removePadding(string) { 1199 return string.replace(ZWNBSPRegExp, ''); 1200 } 1201 /** 1202 * Creates a Rich Text value from a DOM element and range. 1203 * 1204 * @param {Object} $1 Named argements. 1205 * @param {Element} [$1.element] Element to create value from. 1206 * @param {Range} [$1.range] Range to create value from. 1207 * @param {string} [$1.multilineTag] Multiline tag if the structure is 1208 * multiline. 1209 * @param {Array} [$1.multilineWrapperTags] Tags where lines can be found if 1210 * nesting is possible. 1211 * @param {boolean} [$1.preserveWhiteSpace] Whether or not to collapse white 1212 * space characters. 1213 * @param {Array} [$1.currentWrapperTags] 1214 * @param {boolean} [$1.isEditableTree] 1215 * 1216 * @return {RichTextValue} A rich text value. 1217 */ 1218 1219 1220 function createFromElement({ 1221 element, 1222 range, 1223 multilineTag, 1224 multilineWrapperTags, 1225 currentWrapperTags = [], 1226 isEditableTree, 1227 preserveWhiteSpace 1228 }) { 1229 const accumulator = createEmptyValue(); 1230 1231 if (!element) { 1232 return accumulator; 1233 } 1234 1235 if (!element.hasChildNodes()) { 1236 accumulateSelection(accumulator, element, range, createEmptyValue()); 1237 return accumulator; 1238 } 1239 1240 const length = element.childNodes.length; // Optimise for speed. 1241 1242 for (let index = 0; index < length; index++) { 1243 const node = element.childNodes[index]; 1244 const type = node.nodeName.toLowerCase(); 1245 1246 if (node.nodeType === node.TEXT_NODE) { 1247 let filter = removePadding; 1248 1249 if (!preserveWhiteSpace) { 1250 filter = string => removePadding(collapseWhiteSpace(string)); 1251 } 1252 1253 const text = filter(node.nodeValue); 1254 range = filterRange(node, range, filter); 1255 accumulateSelection(accumulator, node, range, { 1256 text 1257 }); // Create a sparse array of the same length as `text`, in which 1258 // formats can be added. 1259 1260 accumulator.formats.length += text.length; 1261 accumulator.replacements.length += text.length; 1262 accumulator.text += text; 1263 continue; 1264 } 1265 1266 if (node.nodeType !== node.ELEMENT_NODE) { 1267 continue; 1268 } 1269 1270 if (isEditableTree && ( // Ignore any placeholders. 1271 node.getAttribute('data-rich-text-placeholder') || // Ignore any line breaks that are not inserted by us. 1272 type === 'br' && !node.getAttribute('data-rich-text-line-break'))) { 1273 accumulateSelection(accumulator, node, range, createEmptyValue()); 1274 continue; 1275 } 1276 1277 if (type === 'script') { 1278 const value = { 1279 formats: [,], 1280 replacements: [{ 1281 type, 1282 attributes: { 1283 'data-rich-text-script': node.getAttribute('data-rich-text-script') || encodeURIComponent(node.innerHTML) 1284 } 1285 }], 1286 text: OBJECT_REPLACEMENT_CHARACTER 1287 }; 1288 accumulateSelection(accumulator, node, range, value); 1289 mergePair(accumulator, value); 1290 continue; 1291 } 1292 1293 if (type === 'br') { 1294 accumulateSelection(accumulator, node, range, createEmptyValue()); 1295 mergePair(accumulator, create({ 1296 text: '\n' 1297 })); 1298 continue; 1299 } 1300 1301 const lastFormats = accumulator.formats[accumulator.formats.length - 1]; 1302 const lastFormat = lastFormats && lastFormats[lastFormats.length - 1]; 1303 const newFormat = toFormat({ 1304 type, 1305 attributes: getAttributes({ 1306 element: node 1307 }) 1308 }); 1309 const format = isFormatEqual(newFormat, lastFormat) ? lastFormat : newFormat; 1310 1311 if (multilineWrapperTags && multilineWrapperTags.indexOf(type) !== -1) { 1312 const value = createFromMultilineElement({ 1313 element: node, 1314 range, 1315 multilineTag, 1316 multilineWrapperTags, 1317 currentWrapperTags: [...currentWrapperTags, format], 1318 isEditableTree, 1319 preserveWhiteSpace 1320 }); 1321 accumulateSelection(accumulator, node, range, value); 1322 mergePair(accumulator, value); 1323 continue; 1324 } 1325 1326 const value = createFromElement({ 1327 element: node, 1328 range, 1329 multilineTag, 1330 multilineWrapperTags, 1331 isEditableTree, 1332 preserveWhiteSpace 1333 }); 1334 accumulateSelection(accumulator, node, range, value); 1335 1336 if (!format) { 1337 mergePair(accumulator, value); 1338 } else if (value.text.length === 0) { 1339 if (format.attributes) { 1340 mergePair(accumulator, { 1341 formats: [,], 1342 replacements: [format], 1343 text: OBJECT_REPLACEMENT_CHARACTER 1344 }); 1345 } 1346 } else { 1347 // Indices should share a reference to the same formats array. 1348 // Only create a new reference if `formats` changes. 1349 function mergeFormats(formats) { 1350 if (mergeFormats.formats === formats) { 1351 return mergeFormats.newFormats; 1352 } 1353 1354 const newFormats = formats ? [format, ...formats] : [format]; 1355 mergeFormats.formats = formats; 1356 mergeFormats.newFormats = newFormats; 1357 return newFormats; 1358 } // Since the formats parameter can be `undefined`, preset 1359 // `mergeFormats` with a new reference. 1360 1361 1362 mergeFormats.newFormats = [format]; 1363 mergePair(accumulator, { ...value, 1364 formats: Array.from(value.formats, mergeFormats) 1365 }); 1366 } 1367 } 1368 1369 return accumulator; 1370 } 1371 /** 1372 * Creates a rich text value from a DOM element and range that should be 1373 * multiline. 1374 * 1375 * @param {Object} $1 Named argements. 1376 * @param {Element} [$1.element] Element to create value from. 1377 * @param {Range} [$1.range] Range to create value from. 1378 * @param {string} [$1.multilineTag] Multiline tag if the structure is 1379 * multiline. 1380 * @param {Array} [$1.multilineWrapperTags] Tags where lines can be found if 1381 * nesting is possible. 1382 * @param {boolean} [$1.currentWrapperTags] Whether to prepend a line 1383 * separator. 1384 * @param {boolean} [$1.preserveWhiteSpace] Whether or not to collapse white 1385 * space characters. 1386 * @param {boolean} [$1.isEditableTree] 1387 * 1388 * @return {RichTextValue} A rich text value. 1389 */ 1390 1391 1392 function createFromMultilineElement({ 1393 element, 1394 range, 1395 multilineTag, 1396 multilineWrapperTags, 1397 currentWrapperTags = [], 1398 isEditableTree, 1399 preserveWhiteSpace 1400 }) { 1401 const accumulator = createEmptyValue(); 1402 1403 if (!element || !element.hasChildNodes()) { 1404 return accumulator; 1405 } 1406 1407 const length = element.children.length; // Optimise for speed. 1408 1409 for (let index = 0; index < length; index++) { 1410 const node = element.children[index]; 1411 1412 if (node.nodeName.toLowerCase() !== multilineTag) { 1413 continue; 1414 } 1415 1416 const value = createFromElement({ 1417 element: node, 1418 range, 1419 multilineTag, 1420 multilineWrapperTags, 1421 currentWrapperTags, 1422 isEditableTree, 1423 preserveWhiteSpace 1424 }); // Multiline value text should be separated by a line separator. 1425 1426 if (index !== 0 || currentWrapperTags.length > 0) { 1427 mergePair(accumulator, { 1428 formats: [,], 1429 replacements: currentWrapperTags.length > 0 ? [currentWrapperTags] : [,], 1430 text: LINE_SEPARATOR 1431 }); 1432 } 1433 1434 accumulateSelection(accumulator, node, range, value); 1435 mergePair(accumulator, value); 1436 } 1437 1438 return accumulator; 1439 } 1440 /** 1441 * Gets the attributes of an element in object shape. 1442 * 1443 * @param {Object} $1 Named argements. 1444 * @param {Element} $1.element Element to get attributes from. 1445 * 1446 * @return {Object|void} Attribute object or `undefined` if the element has no 1447 * attributes. 1448 */ 1449 1450 1451 function getAttributes({ 1452 element 1453 }) { 1454 if (!element.hasAttributes()) { 1455 return; 1456 } 1457 1458 const length = element.attributes.length; 1459 let accumulator; // Optimise for speed. 1460 1461 for (let i = 0; i < length; i++) { 1462 const { 1463 name, 1464 value 1465 } = element.attributes[i]; 1466 1467 if (name.indexOf('data-rich-text-') === 0) { 1468 continue; 1469 } 1470 1471 const safeName = /^on/i.test(name) ? 'data-disable-rich-text-' + name : name; 1472 accumulator = accumulator || {}; 1473 accumulator[safeName] = value; 1474 } 1475 1476 return accumulator; 1477 } 1478 1479 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/concat.js 1480 /** 1481 * Internal dependencies 1482 */ 1483 1484 1485 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1486 1487 /** 1488 * Concats a pair of rich text values. Not that this mutates `a` and does NOT 1489 * normalise formats! 1490 * 1491 * @param {Object} a Value to mutate. 1492 * @param {Object} b Value to add read from. 1493 * 1494 * @return {Object} `a`, mutated. 1495 */ 1496 1497 function mergePair(a, b) { 1498 a.formats = a.formats.concat(b.formats); 1499 a.replacements = a.replacements.concat(b.replacements); 1500 a.text += b.text; 1501 return a; 1502 } 1503 /** 1504 * Combine all Rich Text values into one. This is similar to 1505 * `String.prototype.concat`. 1506 * 1507 * @param {...RichTextValue} values Objects to combine. 1508 * 1509 * @return {RichTextValue} A new value combining all given records. 1510 */ 1511 1512 function concat(...values) { 1513 return normaliseFormats(values.reduce(mergePair, create())); 1514 } 1515 1516 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-active-formats.js 1517 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1518 1519 /** @typedef {import('./create').RichTextFormatList} RichTextFormatList */ 1520 1521 /** 1522 * Gets the all format objects at the start of the selection. 1523 * 1524 * @param {RichTextValue} value Value to inspect. 1525 * @param {Array} EMPTY_ACTIVE_FORMATS Array to return if there are no 1526 * active formats. 1527 * 1528 * @return {RichTextFormatList} Active format objects. 1529 */ 1530 function getActiveFormats({ 1531 formats, 1532 start, 1533 end, 1534 activeFormats 1535 }, EMPTY_ACTIVE_FORMATS = []) { 1536 if (start === undefined) { 1537 return EMPTY_ACTIVE_FORMATS; 1538 } 1539 1540 if (start === end) { 1541 // For a collapsed caret, it is possible to override the active formats. 1542 if (activeFormats) { 1543 return activeFormats; 1544 } 1545 1546 const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS; 1547 const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS; // By default, select the lowest amount of formats possible (which means 1548 // the caret is positioned outside the format boundary). The user can 1549 // then use arrow keys to define `activeFormats`. 1550 1551 if (formatsBefore.length < formatsAfter.length) { 1552 return formatsBefore; 1553 } 1554 1555 return formatsAfter; 1556 } 1557 1558 return formats[start] || EMPTY_ACTIVE_FORMATS; 1559 } 1560 1561 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-active-format.js 1562 /** 1563 * External dependencies 1564 */ 1565 1566 /** 1567 * Internal dependencies 1568 */ 1569 1570 1571 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1572 1573 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 1574 1575 /** 1576 * Gets the format object by type at the start of the selection. This can be 1577 * used to get e.g. the URL of a link format at the current selection, but also 1578 * to check if a format is active at the selection. Returns undefined if there 1579 * is no format at the selection. 1580 * 1581 * @param {RichTextValue} value Value to inspect. 1582 * @param {string} formatType Format type to look for. 1583 * 1584 * @return {RichTextFormat|undefined} Active format object of the specified 1585 * type, or undefined. 1586 */ 1587 1588 function getActiveFormat(value, formatType) { 1589 return Object(external_lodash_["find"])(getActiveFormats(value), { 1590 type: formatType 1591 }); 1592 } 1593 1594 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-active-object.js 1595 /** 1596 * Internal dependencies 1597 */ 1598 1599 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1600 1601 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 1602 1603 /** 1604 * Gets the active object, if there is any. 1605 * 1606 * @param {RichTextValue} value Value to inspect. 1607 * 1608 * @return {RichTextFormat|void} Active object, or undefined. 1609 */ 1610 1611 function getActiveObject({ 1612 start, 1613 end, 1614 replacements, 1615 text 1616 }) { 1617 if (start + 1 !== end || text[start] !== OBJECT_REPLACEMENT_CHARACTER) { 1618 return; 1619 } 1620 1621 return replacements[start]; 1622 } 1623 1624 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-text-content.js 1625 /** 1626 * Internal dependencies 1627 */ 1628 1629 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1630 1631 /** 1632 * Get the textual content of a Rich Text value. This is similar to 1633 * `Element.textContent`. 1634 * 1635 * @param {RichTextValue} value Value to use. 1636 * 1637 * @return {string} The text content. 1638 */ 1639 1640 function getTextContent({ 1641 text 1642 }) { 1643 return text.replace(new RegExp(OBJECT_REPLACEMENT_CHARACTER, 'g'), '').replace(new RegExp(LINE_SEPARATOR, 'g'), '\n'); 1644 } 1645 1646 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-line-index.js 1647 /** 1648 * Internal dependencies 1649 */ 1650 1651 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1652 1653 /** 1654 * Gets the currently selected line index, or the first line index if the 1655 * selection spans over multiple items. 1656 * 1657 * @param {RichTextValue} value Value to get the line index from. 1658 * @param {boolean} startIndex Optional index that should be contained by 1659 * the line. Defaults to the selection start 1660 * of the value. 1661 * 1662 * @return {number|void} The line index. Undefined if not found. 1663 */ 1664 1665 function getLineIndex({ 1666 start, 1667 text 1668 }, startIndex = start) { 1669 let index = startIndex; 1670 1671 while (index--) { 1672 if (text[index] === LINE_SEPARATOR) { 1673 return index; 1674 } 1675 } 1676 } 1677 1678 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-list-root-selected.js 1679 /** 1680 * Internal dependencies 1681 */ 1682 1683 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1684 1685 /** 1686 * Whether or not the root list is selected. 1687 * 1688 * @param {RichTextValue} value The value to check. 1689 * 1690 * @return {boolean} True if the root list or nothing is selected, false if an 1691 * inner list is selected. 1692 */ 1693 1694 function isListRootSelected(value) { 1695 const { 1696 replacements, 1697 start 1698 } = value; 1699 const lineIndex = getLineIndex(value, start); 1700 const replacement = replacements[lineIndex]; 1701 return !replacement || replacement.length < 1; 1702 } 1703 1704 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-active-list-type.js 1705 /** 1706 * Internal dependencies 1707 */ 1708 1709 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1710 1711 /** 1712 * Whether or not the selected list has the given tag name. 1713 * 1714 * @param {RichTextValue} value The value to check. 1715 * @param {string} type The tag name the list should have. 1716 * @param {string} rootType The current root tag name, to compare with in 1717 * case nothing is selected. 1718 * 1719 * @return {boolean} True if the current list type matches `type`, false if not. 1720 */ 1721 1722 function isActiveListType(value, type, rootType) { 1723 const { 1724 replacements, 1725 start 1726 } = value; 1727 const lineIndex = getLineIndex(value, start); 1728 const replacement = replacements[lineIndex]; 1729 1730 if (!replacement || replacement.length === 0) { 1731 return type === rootType; 1732 } 1733 1734 const lastFormat = replacement[replacement.length - 1]; 1735 return lastFormat.type === type; 1736 } 1737 1738 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-collapsed.js 1739 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1740 1741 /** 1742 * Check if the selection of a Rich Text value is collapsed or not. Collapsed 1743 * means that no characters are selected, but there is a caret present. If there 1744 * is no selection, `undefined` will be returned. This is similar to 1745 * `window.getSelection().isCollapsed()`. 1746 * 1747 * @param {RichTextValue} value The rich text value to check. 1748 * 1749 * @return {boolean|undefined} True if the selection is collapsed, false if not, 1750 * undefined if there is no selection. 1751 */ 1752 function isCollapsed({ 1753 start, 1754 end 1755 }) { 1756 if (start === undefined || end === undefined) { 1757 return; 1758 } 1759 1760 return start === end; 1761 } 1762 1763 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-empty.js 1764 /** 1765 * Internal dependencies 1766 */ 1767 1768 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1769 1770 /** 1771 * Check if a Rich Text value is Empty, meaning it contains no text or any 1772 * objects (such as images). 1773 * 1774 * @param {RichTextValue} value Value to use. 1775 * 1776 * @return {boolean} True if the value is empty, false if not. 1777 */ 1778 1779 function isEmpty({ 1780 text 1781 }) { 1782 return text.length === 0; 1783 } 1784 /** 1785 * Check if the current collapsed selection is on an empty line in case of a 1786 * multiline value. 1787 * 1788 * @param {RichTextValue} value Value te check. 1789 * 1790 * @return {boolean} True if the line is empty, false if not. 1791 */ 1792 1793 function isEmptyLine({ 1794 text, 1795 start, 1796 end 1797 }) { 1798 if (start !== end) { 1799 return false; 1800 } 1801 1802 if (text.length === 0) { 1803 return true; 1804 } 1805 1806 if (start === 0 && text.slice(0, 1) === LINE_SEPARATOR) { 1807 return true; 1808 } 1809 1810 if (start === text.length && text.slice(-1) === LINE_SEPARATOR) { 1811 return true; 1812 } 1813 1814 return text.slice(start - 1, end + 1) === `${LINE_SEPARATOR}${LINE_SEPARATOR}`; 1815 } 1816 1817 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/join.js 1818 /** 1819 * Internal dependencies 1820 */ 1821 1822 1823 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1824 1825 /** 1826 * Combine an array of Rich Text values into one, optionally separated by 1827 * `separator`, which can be a Rich Text value, HTML string, or plain text 1828 * string. This is similar to `Array.prototype.join`. 1829 * 1830 * @param {Array<RichTextValue>} values An array of values to join. 1831 * @param {string|RichTextValue} [separator] Separator string or value. 1832 * 1833 * @return {RichTextValue} A new combined value. 1834 */ 1835 1836 function join(values, separator = '') { 1837 if (typeof separator === 'string') { 1838 separator = create({ 1839 text: separator 1840 }); 1841 } 1842 1843 return normaliseFormats(values.reduce((accumlator, { 1844 formats, 1845 replacements, 1846 text 1847 }) => ({ 1848 formats: accumlator.formats.concat(separator.formats, formats), 1849 replacements: accumlator.replacements.concat(separator.replacements, replacements), 1850 text: accumlator.text + separator.text + text 1851 }))); 1852 } 1853 1854 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/register-format-type.js 1855 /** 1856 * WordPress dependencies 1857 */ 1858 1859 /** 1860 * Internal dependencies 1861 */ 1862 1863 1864 /** 1865 * @typedef {Object} WPFormat 1866 * 1867 * @property {string} name A string identifying the format. Must be 1868 * unique across all registered formats. 1869 * @property {string} tagName The HTML tag this format will wrap the 1870 * selection with. 1871 * @property {string} [className] A class to match the format. 1872 * @property {string} title Name of the format. 1873 * @property {Function} edit Should return a component for the user to 1874 * interact with the new registered format. 1875 */ 1876 1877 /** 1878 * Registers a new format provided a unique name and an object defining its 1879 * behavior. 1880 * 1881 * @param {string} name Format name. 1882 * @param {WPFormat} settings Format settings. 1883 * 1884 * @return {WPFormat|undefined} The format, if it has been successfully 1885 * registered; otherwise `undefined`. 1886 */ 1887 1888 function registerFormatType(name, settings) { 1889 settings = { 1890 name, 1891 ...settings 1892 }; 1893 1894 if (typeof settings.name !== 'string') { 1895 window.console.error('Format names must be strings.'); 1896 return; 1897 } 1898 1899 if (!/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(settings.name)) { 1900 window.console.error('Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format'); 1901 return; 1902 } 1903 1904 if (Object(external_wp_data_["select"])(store).getFormatType(settings.name)) { 1905 window.console.error('Format "' + settings.name + '" is already registered.'); 1906 return; 1907 } 1908 1909 if (typeof settings.tagName !== 'string' || settings.tagName === '') { 1910 window.console.error('Format tag names must be a string.'); 1911 return; 1912 } 1913 1914 if ((typeof settings.className !== 'string' || settings.className === '') && settings.className !== null) { 1915 window.console.error('Format class names must be a string, or null to handle bare elements.'); 1916 return; 1917 } 1918 1919 if (!/^[_a-zA-Z]+[a-zA-Z0-9-]*$/.test(settings.className)) { 1920 window.console.error('A class name must begin with a letter, followed by any number of hyphens, letters, or numbers.'); 1921 return; 1922 } 1923 1924 if (settings.className === null) { 1925 const formatTypeForBareElement = Object(external_wp_data_["select"])(store).getFormatTypeForBareElement(settings.tagName); 1926 1927 if (formatTypeForBareElement) { 1928 window.console.error(`Format "${formatTypeForBareElement.name}" is already registered to handle bare tag name "${settings.tagName}".`); 1929 return; 1930 } 1931 } else { 1932 const formatTypeForClassName = Object(external_wp_data_["select"])(store).getFormatTypeForClassName(settings.className); 1933 1934 if (formatTypeForClassName) { 1935 window.console.error(`Format "${formatTypeForClassName.name}" is already registered to handle class name "${settings.className}".`); 1936 return; 1937 } 1938 } 1939 1940 if (!('title' in settings) || settings.title === '') { 1941 window.console.error('The format "' + settings.name + '" must have a title.'); 1942 return; 1943 } 1944 1945 if ('keywords' in settings && settings.keywords.length > 3) { 1946 window.console.error('The format "' + settings.name + '" can have a maximum of 3 keywords.'); 1947 return; 1948 } 1949 1950 if (typeof settings.title !== 'string') { 1951 window.console.error('Format titles must be strings.'); 1952 return; 1953 } 1954 1955 Object(external_wp_data_["dispatch"])(store).addFormatTypes(settings); 1956 return settings; 1957 } 1958 1959 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/remove-format.js 1960 /** 1961 * External dependencies 1962 */ 1963 1964 /** 1965 * Internal dependencies 1966 */ 1967 1968 1969 /** @typedef {import('./create').RichTextValue} RichTextValue */ 1970 1971 /** 1972 * Remove any format object from a Rich Text value by type from the given 1973 * `startIndex` to the given `endIndex`. Indices are retrieved from the 1974 * selection if none are provided. 1975 * 1976 * @param {RichTextValue} value Value to modify. 1977 * @param {string} formatType Format type to remove. 1978 * @param {number} [startIndex] Start index. 1979 * @param {number} [endIndex] End index. 1980 * 1981 * @return {RichTextValue} A new value with the format applied. 1982 */ 1983 1984 function removeFormat(value, formatType, startIndex = value.start, endIndex = value.end) { 1985 const { 1986 formats, 1987 activeFormats 1988 } = value; 1989 const newFormats = formats.slice(); // If the selection is collapsed, expand start and end to the edges of the 1990 // format. 1991 1992 if (startIndex === endIndex) { 1993 const format = Object(external_lodash_["find"])(newFormats[startIndex], { 1994 type: formatType 1995 }); 1996 1997 if (format) { 1998 while (Object(external_lodash_["find"])(newFormats[startIndex], format)) { 1999 filterFormats(newFormats, startIndex, formatType); 2000 startIndex--; 2001 } 2002 2003 endIndex++; 2004 2005 while (Object(external_lodash_["find"])(newFormats[endIndex], format)) { 2006 filterFormats(newFormats, endIndex, formatType); 2007 endIndex++; 2008 } 2009 } 2010 } else { 2011 for (let i = startIndex; i < endIndex; i++) { 2012 if (newFormats[i]) { 2013 filterFormats(newFormats, i, formatType); 2014 } 2015 } 2016 } 2017 2018 return normaliseFormats({ ...value, 2019 formats: newFormats, 2020 activeFormats: Object(external_lodash_["reject"])(activeFormats, { 2021 type: formatType 2022 }) 2023 }); 2024 } 2025 2026 function filterFormats(formats, index, formatType) { 2027 const newFormats = formats[index].filter(({ 2028 type 2029 }) => type !== formatType); 2030 2031 if (newFormats.length) { 2032 formats[index] = newFormats; 2033 } else { 2034 delete formats[index]; 2035 } 2036 } 2037 2038 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/insert.js 2039 /** 2040 * Internal dependencies 2041 */ 2042 2043 2044 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2045 2046 /** 2047 * Insert a Rich Text value, an HTML string, or a plain text string, into a 2048 * Rich Text value at the given `startIndex`. Any content between `startIndex` 2049 * and `endIndex` will be removed. Indices are retrieved from the selection if 2050 * none are provided. 2051 * 2052 * @param {RichTextValue} value Value to modify. 2053 * @param {RichTextValue|string} valueToInsert Value to insert. 2054 * @param {number} [startIndex] Start index. 2055 * @param {number} [endIndex] End index. 2056 * 2057 * @return {RichTextValue} A new value with the value inserted. 2058 */ 2059 2060 function insert(value, valueToInsert, startIndex = value.start, endIndex = value.end) { 2061 const { 2062 formats, 2063 replacements, 2064 text 2065 } = value; 2066 2067 if (typeof valueToInsert === 'string') { 2068 valueToInsert = create({ 2069 text: valueToInsert 2070 }); 2071 } 2072 2073 const index = startIndex + valueToInsert.text.length; 2074 return normaliseFormats({ 2075 formats: formats.slice(0, startIndex).concat(valueToInsert.formats, formats.slice(endIndex)), 2076 replacements: replacements.slice(0, startIndex).concat(valueToInsert.replacements, replacements.slice(endIndex)), 2077 text: text.slice(0, startIndex) + valueToInsert.text + text.slice(endIndex), 2078 start: index, 2079 end: index 2080 }); 2081 } 2082 2083 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/remove.js 2084 /** 2085 * Internal dependencies 2086 */ 2087 2088 2089 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2090 2091 /** 2092 * Remove content from a Rich Text value between the given `startIndex` and 2093 * `endIndex`. Indices are retrieved from the selection if none are provided. 2094 * 2095 * @param {RichTextValue} value Value to modify. 2096 * @param {number} [startIndex] Start index. 2097 * @param {number} [endIndex] End index. 2098 * 2099 * @return {RichTextValue} A new value with the content removed. 2100 */ 2101 2102 function remove_remove(value, startIndex, endIndex) { 2103 return insert(value, create(), startIndex, endIndex); 2104 } 2105 2106 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/replace.js 2107 /** 2108 * Internal dependencies 2109 */ 2110 2111 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2112 2113 /** 2114 * Search a Rich Text value and replace the match(es) with `replacement`. This 2115 * is similar to `String.prototype.replace`. 2116 * 2117 * @param {RichTextValue} value The value to modify. 2118 * @param {RegExp|string} pattern A RegExp object or literal. Can also be 2119 * a string. It is treated as a verbatim 2120 * string and is not interpreted as a 2121 * regular expression. Only the first 2122 * occurrence will be replaced. 2123 * @param {Function|string} replacement The match or matches are replaced with 2124 * the specified or the value returned by 2125 * the specified function. 2126 * 2127 * @return {RichTextValue} A new value with replacements applied. 2128 */ 2129 2130 function replace_replace({ 2131 formats, 2132 replacements, 2133 text, 2134 start, 2135 end 2136 }, pattern, replacement) { 2137 text = text.replace(pattern, (match, ...rest) => { 2138 const offset = rest[rest.length - 2]; 2139 let newText = replacement; 2140 let newFormats; 2141 let newReplacements; 2142 2143 if (typeof newText === 'function') { 2144 newText = replacement(match, ...rest); 2145 } 2146 2147 if (typeof newText === 'object') { 2148 newFormats = newText.formats; 2149 newReplacements = newText.replacements; 2150 newText = newText.text; 2151 } else { 2152 newFormats = Array(newText.length); 2153 newReplacements = Array(newText.length); 2154 2155 if (formats[offset]) { 2156 newFormats = newFormats.fill(formats[offset]); 2157 } 2158 } 2159 2160 formats = formats.slice(0, offset).concat(newFormats, formats.slice(offset + match.length)); 2161 replacements = replacements.slice(0, offset).concat(newReplacements, replacements.slice(offset + match.length)); 2162 2163 if (start) { 2164 start = end = offset + newText.length; 2165 } 2166 2167 return newText; 2168 }); 2169 return normaliseFormats({ 2170 formats, 2171 replacements, 2172 text, 2173 start, 2174 end 2175 }); 2176 } 2177 2178 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/insert-line-separator.js 2179 /** 2180 * Internal dependencies 2181 */ 2182 2183 2184 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2185 2186 /** 2187 * Insert a line break character into a Rich Text value at the given 2188 * `startIndex`. Any content between `startIndex` and `endIndex` will be 2189 * removed. Indices are retrieved from the selection if none are provided. 2190 * 2191 * @param {RichTextValue} value Value to modify. 2192 * @param {number} [startIndex] Start index. 2193 * @param {number} [endIndex] End index. 2194 * 2195 * @return {RichTextValue} A new value with the value inserted. 2196 */ 2197 2198 function insertLineSeparator(value, startIndex = value.start, endIndex = value.end) { 2199 const beforeText = value.text.slice(0, startIndex); 2200 const previousLineSeparatorIndex = beforeText.lastIndexOf(LINE_SEPARATOR); 2201 const previousLineSeparatorFormats = value.replacements[previousLineSeparatorIndex]; 2202 let replacements = [,]; 2203 2204 if (previousLineSeparatorFormats) { 2205 replacements = [previousLineSeparatorFormats]; 2206 } 2207 2208 const valueToInsert = { 2209 formats: [,], 2210 replacements, 2211 text: LINE_SEPARATOR 2212 }; 2213 return insert(value, valueToInsert, startIndex, endIndex); 2214 } 2215 2216 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/remove-line-separator.js 2217 /** 2218 * Internal dependencies 2219 */ 2220 2221 2222 2223 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2224 2225 /** 2226 * Removes a line separator character, if existing, from a Rich Text value at 2227 * the current indices. If no line separator exists on the indices it will 2228 * return undefined. 2229 * 2230 * @param {RichTextValue} value Value to modify. 2231 * @param {boolean} backward Indicates if are removing from the start 2232 * index or the end index. 2233 * 2234 * @return {RichTextValue|undefined} A new value with the line separator 2235 * removed. Or undefined if no line separator 2236 * is found on the position. 2237 */ 2238 2239 function removeLineSeparator(value, backward = true) { 2240 const { 2241 replacements, 2242 text, 2243 start, 2244 end 2245 } = value; 2246 const collapsed = isCollapsed(value); 2247 let index = start - 1; 2248 let removeStart = collapsed ? start - 1 : start; 2249 let removeEnd = end; 2250 2251 if (!backward) { 2252 index = end; 2253 removeStart = start; 2254 removeEnd = collapsed ? end + 1 : end; 2255 } 2256 2257 if (text[index] !== LINE_SEPARATOR) { 2258 return; 2259 } 2260 2261 let newValue; // If the line separator that is about te be removed 2262 // contains wrappers, remove the wrappers first. 2263 2264 if (collapsed && replacements[index] && replacements[index].length) { 2265 const newReplacements = replacements.slice(); 2266 newReplacements[index] = replacements[index].slice(0, -1); 2267 newValue = { ...value, 2268 replacements: newReplacements 2269 }; 2270 } else { 2271 newValue = remove_remove(value, removeStart, removeEnd); 2272 } 2273 2274 return newValue; 2275 } 2276 2277 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/insert-object.js 2278 /** 2279 * Internal dependencies 2280 */ 2281 2282 2283 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2284 2285 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 2286 2287 /** 2288 * Insert a format as an object into a Rich Text value at the given 2289 * `startIndex`. Any content between `startIndex` and `endIndex` will be 2290 * removed. Indices are retrieved from the selection if none are provided. 2291 * 2292 * @param {RichTextValue} value Value to modify. 2293 * @param {RichTextFormat} formatToInsert Format to insert as object. 2294 * @param {number} [startIndex] Start index. 2295 * @param {number} [endIndex] End index. 2296 * 2297 * @return {RichTextValue} A new value with the object inserted. 2298 */ 2299 2300 function insertObject(value, formatToInsert, startIndex, endIndex) { 2301 const valueToInsert = { 2302 formats: [,], 2303 replacements: [formatToInsert], 2304 text: OBJECT_REPLACEMENT_CHARACTER 2305 }; 2306 return insert(value, valueToInsert, startIndex, endIndex); 2307 } 2308 2309 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/slice.js 2310 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2311 2312 /** 2313 * Slice a Rich Text value from `startIndex` to `endIndex`. Indices are 2314 * retrieved from the selection if none are provided. This is similar to 2315 * `String.prototype.slice`. 2316 * 2317 * @param {RichTextValue} value Value to modify. 2318 * @param {number} [startIndex] Start index. 2319 * @param {number} [endIndex] End index. 2320 * 2321 * @return {RichTextValue} A new extracted value. 2322 */ 2323 function slice(value, startIndex = value.start, endIndex = value.end) { 2324 const { 2325 formats, 2326 replacements, 2327 text 2328 } = value; 2329 2330 if (startIndex === undefined || endIndex === undefined) { 2331 return { ...value 2332 }; 2333 } 2334 2335 return { 2336 formats: formats.slice(startIndex, endIndex), 2337 replacements: replacements.slice(startIndex, endIndex), 2338 text: text.slice(startIndex, endIndex) 2339 }; 2340 } 2341 2342 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/split.js 2343 /** 2344 * Internal dependencies 2345 */ 2346 2347 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2348 2349 /** 2350 * Split a Rich Text value in two at the given `startIndex` and `endIndex`, or 2351 * split at the given separator. This is similar to `String.prototype.split`. 2352 * Indices are retrieved from the selection if none are provided. 2353 * 2354 * @param {RichTextValue} value 2355 * @param {number|string} [string] Start index, or string at which to split. 2356 * 2357 * @return {Array<RichTextValue>|undefined} An array of new values. 2358 */ 2359 2360 function split({ 2361 formats, 2362 replacements, 2363 text, 2364 start, 2365 end 2366 }, string) { 2367 if (typeof string !== 'string') { 2368 return splitAtSelection(...arguments); 2369 } 2370 2371 let nextStart = 0; 2372 return text.split(string).map(substring => { 2373 const startIndex = nextStart; 2374 const value = { 2375 formats: formats.slice(startIndex, startIndex + substring.length), 2376 replacements: replacements.slice(startIndex, startIndex + substring.length), 2377 text: substring 2378 }; 2379 nextStart += string.length + substring.length; 2380 2381 if (start !== undefined && end !== undefined) { 2382 if (start >= startIndex && start < nextStart) { 2383 value.start = start - startIndex; 2384 } else if (start < startIndex && end > startIndex) { 2385 value.start = 0; 2386 } 2387 2388 if (end >= startIndex && end < nextStart) { 2389 value.end = end - startIndex; 2390 } else if (start < nextStart && end > nextStart) { 2391 value.end = substring.length; 2392 } 2393 } 2394 2395 return value; 2396 }); 2397 } 2398 2399 function splitAtSelection({ 2400 formats, 2401 replacements, 2402 text, 2403 start, 2404 end 2405 }, startIndex = start, endIndex = end) { 2406 if (start === undefined || end === undefined) { 2407 return; 2408 } 2409 2410 const before = { 2411 formats: formats.slice(0, startIndex), 2412 replacements: replacements.slice(0, startIndex), 2413 text: text.slice(0, startIndex) 2414 }; 2415 const after = { 2416 formats: formats.slice(endIndex), 2417 replacements: replacements.slice(endIndex), 2418 text: text.slice(endIndex), 2419 start: 0, 2420 end: 0 2421 }; 2422 return [// Ensure newlines are trimmed. 2423 replace_replace(before, /\u2028+$/, ''), replace_replace(after, /^\u2028+/, '')]; 2424 } 2425 2426 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-format-type.js 2427 /** 2428 * WordPress dependencies 2429 */ 2430 2431 /** 2432 * Internal dependencies 2433 */ 2434 2435 2436 /** @typedef {import('./register-format-type').RichTextFormatType} RichTextFormatType */ 2437 2438 /** 2439 * Returns a registered format type. 2440 * 2441 * @param {string} name Format name. 2442 * 2443 * @return {RichTextFormatType|undefined} Format type. 2444 */ 2445 2446 function get_format_type_getFormatType(name) { 2447 return Object(external_wp_data_["select"])(store).getFormatType(name); 2448 } 2449 2450 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/to-tree.js 2451 /** 2452 * Internal dependencies 2453 */ 2454 2455 2456 2457 2458 function restoreOnAttributes(attributes, isEditableTree) { 2459 if (isEditableTree) { 2460 return attributes; 2461 } 2462 2463 const newAttributes = {}; 2464 2465 for (const key in attributes) { 2466 let newKey = key; 2467 2468 if (key.startsWith('data-disable-rich-text-')) { 2469 newKey = key.slice('data-disable-rich-text-'.length); 2470 } 2471 2472 newAttributes[newKey] = attributes[key]; 2473 } 2474 2475 return newAttributes; 2476 } 2477 /** 2478 * Converts a format object to information that can be used to create an element 2479 * from (type, attributes and object). 2480 * 2481 * @param {Object} $1 Named parameters. 2482 * @param {string} $1.type The format type. 2483 * @param {Object} $1.attributes The format attributes. 2484 * @param {Object} $1.unregisteredAttributes The unregistered format 2485 * attributes. 2486 * @param {boolean} $1.object Whether or not it is an object 2487 * format. 2488 * @param {boolean} $1.boundaryClass Whether or not to apply a boundary 2489 * class. 2490 * @param {boolean} $1.isEditableTree 2491 * 2492 * @return {Object} Information to be used for 2493 * element creation. 2494 */ 2495 2496 2497 function fromFormat({ 2498 type, 2499 attributes, 2500 unregisteredAttributes, 2501 object, 2502 boundaryClass, 2503 isEditableTree 2504 }) { 2505 const formatType = get_format_type_getFormatType(type); 2506 let elementAttributes = {}; 2507 2508 if (boundaryClass) { 2509 elementAttributes['data-rich-text-format-boundary'] = 'true'; 2510 } 2511 2512 if (!formatType) { 2513 if (attributes) { 2514 elementAttributes = { ...attributes, 2515 ...elementAttributes 2516 }; 2517 } 2518 2519 return { 2520 type, 2521 attributes: restoreOnAttributes(elementAttributes, isEditableTree), 2522 object 2523 }; 2524 } 2525 2526 elementAttributes = { ...unregisteredAttributes, 2527 ...elementAttributes 2528 }; 2529 2530 for (const name in attributes) { 2531 const key = formatType.attributes ? formatType.attributes[name] : false; 2532 2533 if (key) { 2534 elementAttributes[key] = attributes[name]; 2535 } else { 2536 elementAttributes[name] = attributes[name]; 2537 } 2538 } 2539 2540 if (formatType.className) { 2541 if (elementAttributes.class) { 2542 elementAttributes.class = `${formatType.className} ${elementAttributes.class}`; 2543 } else { 2544 elementAttributes.class = formatType.className; 2545 } 2546 } 2547 2548 return { 2549 type: formatType.tagName, 2550 object: formatType.object, 2551 attributes: restoreOnAttributes(elementAttributes, isEditableTree) 2552 }; 2553 } 2554 /** 2555 * Checks if both arrays of formats up until a certain index are equal. 2556 * 2557 * @param {Array} a Array of formats to compare. 2558 * @param {Array} b Array of formats to compare. 2559 * @param {number} index Index to check until. 2560 */ 2561 2562 2563 function isEqualUntil(a, b, index) { 2564 do { 2565 if (a[index] !== b[index]) { 2566 return false; 2567 } 2568 } while (index--); 2569 2570 return true; 2571 } 2572 2573 function toTree({ 2574 value, 2575 multilineTag, 2576 preserveWhiteSpace, 2577 createEmpty, 2578 append, 2579 getLastChild, 2580 getParent, 2581 isText, 2582 getText, 2583 remove, 2584 appendText, 2585 onStartIndex, 2586 onEndIndex, 2587 isEditableTree, 2588 placeholder 2589 }) { 2590 const { 2591 formats, 2592 replacements, 2593 text, 2594 start, 2595 end 2596 } = value; 2597 const formatsLength = formats.length + 1; 2598 const tree = createEmpty(); 2599 const multilineFormat = { 2600 type: multilineTag 2601 }; 2602 const activeFormats = getActiveFormats(value); 2603 const deepestActiveFormat = activeFormats[activeFormats.length - 1]; 2604 let lastSeparatorFormats; 2605 let lastCharacterFormats; 2606 let lastCharacter; // If we're building a multiline tree, start off with a multiline element. 2607 2608 if (multilineTag) { 2609 append(append(tree, { 2610 type: multilineTag 2611 }), ''); 2612 lastCharacterFormats = lastSeparatorFormats = [multilineFormat]; 2613 } else { 2614 append(tree, ''); 2615 } 2616 2617 for (let i = 0; i < formatsLength; i++) { 2618 const character = text.charAt(i); 2619 const shouldInsertPadding = isEditableTree && ( // Pad the line if the line is empty. 2620 !lastCharacter || lastCharacter === LINE_SEPARATOR || // Pad the line if the previous character is a line break, otherwise 2621 // the line break won't be visible. 2622 lastCharacter === '\n'); 2623 let characterFormats = formats[i]; // Set multiline tags in queue for building the tree. 2624 2625 if (multilineTag) { 2626 if (character === LINE_SEPARATOR) { 2627 characterFormats = lastSeparatorFormats = (replacements[i] || []).reduce((accumulator, format) => { 2628 accumulator.push(format, multilineFormat); 2629 return accumulator; 2630 }, [multilineFormat]); 2631 } else { 2632 characterFormats = [...lastSeparatorFormats, ...(characterFormats || [])]; 2633 } 2634 } 2635 2636 let pointer = getLastChild(tree); 2637 2638 if (shouldInsertPadding && character === LINE_SEPARATOR) { 2639 let node = pointer; 2640 2641 while (!isText(node)) { 2642 node = getLastChild(node); 2643 } 2644 2645 append(getParent(node), ZWNBSP); 2646 } // Set selection for the start of line. 2647 2648 2649 if (lastCharacter === LINE_SEPARATOR) { 2650 let node = pointer; 2651 2652 while (!isText(node)) { 2653 node = getLastChild(node); 2654 } 2655 2656 if (onStartIndex && start === i) { 2657 onStartIndex(tree, node); 2658 } 2659 2660 if (onEndIndex && end === i) { 2661 onEndIndex(tree, node); 2662 } 2663 } 2664 2665 if (characterFormats) { 2666 characterFormats.forEach((format, formatIndex) => { 2667 if (pointer && lastCharacterFormats && // Reuse the last element if all formats remain the same. 2668 isEqualUntil(characterFormats, lastCharacterFormats, formatIndex) && ( // Do not reuse the last element if the character is a 2669 // line separator. 2670 character !== LINE_SEPARATOR || characterFormats.length - 1 !== formatIndex)) { 2671 pointer = getLastChild(pointer); 2672 return; 2673 } 2674 2675 const { 2676 type, 2677 attributes, 2678 unregisteredAttributes 2679 } = format; 2680 const boundaryClass = isEditableTree && character !== LINE_SEPARATOR && format === deepestActiveFormat; 2681 const parent = getParent(pointer); 2682 const newNode = append(parent, fromFormat({ 2683 type, 2684 attributes, 2685 unregisteredAttributes, 2686 boundaryClass, 2687 isEditableTree 2688 })); 2689 2690 if (isText(pointer) && getText(pointer).length === 0) { 2691 remove(pointer); 2692 } 2693 2694 pointer = append(newNode, ''); 2695 }); 2696 } // No need for further processing if the character is a line separator. 2697 2698 2699 if (character === LINE_SEPARATOR) { 2700 lastCharacterFormats = characterFormats; 2701 lastCharacter = character; 2702 continue; 2703 } // If there is selection at 0, handle it before characters are inserted. 2704 2705 2706 if (i === 0) { 2707 if (onStartIndex && start === 0) { 2708 onStartIndex(tree, pointer); 2709 } 2710 2711 if (onEndIndex && end === 0) { 2712 onEndIndex(tree, pointer); 2713 } 2714 } 2715 2716 if (character === OBJECT_REPLACEMENT_CHARACTER) { 2717 if (!isEditableTree && replacements[i].type === 'script') { 2718 pointer = append(getParent(pointer), fromFormat({ 2719 type: 'script', 2720 isEditableTree 2721 })); 2722 append(pointer, { 2723 html: decodeURIComponent(replacements[i].attributes['data-rich-text-script']) 2724 }); 2725 } else { 2726 pointer = append(getParent(pointer), fromFormat({ ...replacements[i], 2727 object: true, 2728 isEditableTree 2729 })); 2730 } // Ensure pointer is text node. 2731 2732 2733 pointer = append(getParent(pointer), ''); 2734 } else if (!preserveWhiteSpace && character === '\n') { 2735 pointer = append(getParent(pointer), { 2736 type: 'br', 2737 attributes: isEditableTree ? { 2738 'data-rich-text-line-break': 'true' 2739 } : undefined, 2740 object: true 2741 }); // Ensure pointer is text node. 2742 2743 pointer = append(getParent(pointer), ''); 2744 } else if (!isText(pointer)) { 2745 pointer = append(getParent(pointer), character); 2746 } else { 2747 appendText(pointer, character); 2748 } 2749 2750 if (onStartIndex && start === i + 1) { 2751 onStartIndex(tree, pointer); 2752 } 2753 2754 if (onEndIndex && end === i + 1) { 2755 onEndIndex(tree, pointer); 2756 } 2757 2758 if (shouldInsertPadding && i === text.length) { 2759 append(getParent(pointer), ZWNBSP); 2760 2761 if (placeholder && text.length === 0) { 2762 append(getParent(pointer), { 2763 type: 'span', 2764 attributes: { 2765 'data-rich-text-placeholder': placeholder, 2766 // Necessary to prevent the placeholder from catching 2767 // selection. The placeholder is also not editable after 2768 // all. 2769 contenteditable: 'false', 2770 style: 'pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;' 2771 } 2772 }); 2773 } 2774 } 2775 2776 lastCharacterFormats = characterFormats; 2777 lastCharacter = character; 2778 } 2779 2780 return tree; 2781 } 2782 2783 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/to-dom.js 2784 /** 2785 * Internal dependencies 2786 */ 2787 2788 2789 /** @typedef {import('./create').RichTextValue} RichTextValue */ 2790 2791 /** 2792 * Creates a path as an array of indices from the given root node to the given 2793 * node. 2794 * 2795 * @param {Node} node Node to find the path of. 2796 * @param {HTMLElement} rootNode Root node to find the path from. 2797 * @param {Array} path Initial path to build on. 2798 * 2799 * @return {Array} The path from the root node to the node. 2800 */ 2801 2802 function createPathToNode(node, rootNode, path) { 2803 const parentNode = node.parentNode; 2804 let i = 0; 2805 2806 while (node = node.previousSibling) { 2807 i++; 2808 } 2809 2810 path = [i, ...path]; 2811 2812 if (parentNode !== rootNode) { 2813 path = createPathToNode(parentNode, rootNode, path); 2814 } 2815 2816 return path; 2817 } 2818 /** 2819 * Gets a node given a path (array of indices) from the given node. 2820 * 2821 * @param {HTMLElement} node Root node to find the wanted node in. 2822 * @param {Array} path Path (indices) to the wanted node. 2823 * 2824 * @return {Object} Object with the found node and the remaining offset (if any). 2825 */ 2826 2827 2828 function getNodeByPath(node, path) { 2829 path = [...path]; 2830 2831 while (node && path.length > 1) { 2832 node = node.childNodes[path.shift()]; 2833 } 2834 2835 return { 2836 node, 2837 offset: path[0] 2838 }; 2839 } 2840 2841 function to_dom_append(element, child) { 2842 if (typeof child === 'string') { 2843 child = element.ownerDocument.createTextNode(child); 2844 } 2845 2846 const { 2847 type, 2848 attributes 2849 } = child; 2850 2851 if (type) { 2852 child = element.ownerDocument.createElement(type); 2853 2854 for (const key in attributes) { 2855 child.setAttribute(key, attributes[key]); 2856 } 2857 } 2858 2859 return element.appendChild(child); 2860 } 2861 2862 function to_dom_appendText(node, text) { 2863 node.appendData(text); 2864 } 2865 2866 function to_dom_getLastChild({ 2867 lastChild 2868 }) { 2869 return lastChild; 2870 } 2871 2872 function to_dom_getParent({ 2873 parentNode 2874 }) { 2875 return parentNode; 2876 } 2877 2878 function to_dom_isText(node) { 2879 return node.nodeType === node.TEXT_NODE; 2880 } 2881 2882 function to_dom_getText({ 2883 nodeValue 2884 }) { 2885 return nodeValue; 2886 } 2887 2888 function to_dom_remove(node) { 2889 return node.parentNode.removeChild(node); 2890 } 2891 2892 function toDom({ 2893 value, 2894 multilineTag, 2895 prepareEditableTree, 2896 isEditableTree = true, 2897 placeholder, 2898 doc = document 2899 }) { 2900 let startPath = []; 2901 let endPath = []; 2902 2903 if (prepareEditableTree) { 2904 value = { ...value, 2905 formats: prepareEditableTree(value) 2906 }; 2907 } 2908 /** 2909 * Returns a new instance of a DOM tree upon which RichText operations can be 2910 * applied. 2911 * 2912 * Note: The current implementation will return a shared reference, reset on 2913 * each call to `createEmpty`. Therefore, you should not hold a reference to 2914 * the value to operate upon asynchronously, as it may have unexpected results. 2915 * 2916 * @return {Object} RichText tree. 2917 */ 2918 2919 2920 const createEmpty = () => createElement(doc, ''); 2921 2922 const tree = toTree({ 2923 value, 2924 multilineTag, 2925 createEmpty, 2926 append: to_dom_append, 2927 getLastChild: to_dom_getLastChild, 2928 getParent: to_dom_getParent, 2929 isText: to_dom_isText, 2930 getText: to_dom_getText, 2931 remove: to_dom_remove, 2932 appendText: to_dom_appendText, 2933 2934 onStartIndex(body, pointer) { 2935 startPath = createPathToNode(pointer, body, [pointer.nodeValue.length]); 2936 }, 2937 2938 onEndIndex(body, pointer) { 2939 endPath = createPathToNode(pointer, body, [pointer.nodeValue.length]); 2940 }, 2941 2942 isEditableTree, 2943 placeholder 2944 }); 2945 return { 2946 body: tree, 2947 selection: { 2948 startPath, 2949 endPath 2950 } 2951 }; 2952 } 2953 /** 2954 * Create an `Element` tree from a Rich Text value and applies the difference to 2955 * the `Element` tree contained by `current`. If a `multilineTag` is provided, 2956 * text separated by two new lines will be wrapped in an `Element` of that type. 2957 * 2958 * @param {Object} $1 Named arguments. 2959 * @param {RichTextValue} $1.value Value to apply. 2960 * @param {HTMLElement} $1.current The live root node to apply the element tree to. 2961 * @param {string} [$1.multilineTag] Multiline tag. 2962 * @param {Function} [$1.prepareEditableTree] Function to filter editorable formats. 2963 * @param {boolean} [$1.__unstableDomOnly] Only apply elements, no selection. 2964 * @param {string} [$1.placeholder] Placeholder text. 2965 */ 2966 2967 function apply({ 2968 value, 2969 current, 2970 multilineTag, 2971 prepareEditableTree, 2972 __unstableDomOnly, 2973 placeholder 2974 }) { 2975 // Construct a new element tree in memory. 2976 const { 2977 body, 2978 selection 2979 } = toDom({ 2980 value, 2981 multilineTag, 2982 prepareEditableTree, 2983 placeholder, 2984 doc: current.ownerDocument 2985 }); 2986 applyValue(body, current); 2987 2988 if (value.start !== undefined && !__unstableDomOnly) { 2989 applySelection(selection, current); 2990 } 2991 } 2992 function applyValue(future, current) { 2993 let i = 0; 2994 let futureChild; 2995 2996 while (futureChild = future.firstChild) { 2997 const currentChild = current.childNodes[i]; 2998 2999 if (!currentChild) { 3000 current.appendChild(futureChild); 3001 } else if (!currentChild.isEqualNode(futureChild)) { 3002 if (currentChild.nodeName !== futureChild.nodeName || currentChild.nodeType === currentChild.TEXT_NODE && currentChild.data !== futureChild.data) { 3003 current.replaceChild(futureChild, currentChild); 3004 } else { 3005 const currentAttributes = currentChild.attributes; 3006 const futureAttributes = futureChild.attributes; 3007 3008 if (currentAttributes) { 3009 let ii = currentAttributes.length; // Reverse loop because `removeAttribute` on `currentChild` 3010 // changes `currentAttributes`. 3011 3012 while (ii--) { 3013 const { 3014 name 3015 } = currentAttributes[ii]; 3016 3017 if (!futureChild.getAttribute(name)) { 3018 currentChild.removeAttribute(name); 3019 } 3020 } 3021 } 3022 3023 if (futureAttributes) { 3024 for (let ii = 0; ii < futureAttributes.length; ii++) { 3025 const { 3026 name, 3027 value 3028 } = futureAttributes[ii]; 3029 3030 if (currentChild.getAttribute(name) !== value) { 3031 currentChild.setAttribute(name, value); 3032 } 3033 } 3034 } 3035 3036 applyValue(futureChild, currentChild); 3037 future.removeChild(futureChild); 3038 } 3039 } else { 3040 future.removeChild(futureChild); 3041 } 3042 3043 i++; 3044 } 3045 3046 while (current.childNodes[i]) { 3047 current.removeChild(current.childNodes[i]); 3048 } 3049 } 3050 /** 3051 * Returns true if two ranges are equal, or false otherwise. Ranges are 3052 * considered equal if their start and end occur in the same container and 3053 * offset. 3054 * 3055 * @param {Range} a First range object to test. 3056 * @param {Range} b First range object to test. 3057 * 3058 * @return {boolean} Whether the two ranges are equal. 3059 */ 3060 3061 function isRangeEqual(a, b) { 3062 return a.startContainer === b.startContainer && a.startOffset === b.startOffset && a.endContainer === b.endContainer && a.endOffset === b.endOffset; 3063 } 3064 3065 function applySelection({ 3066 startPath, 3067 endPath 3068 }, current) { 3069 const { 3070 node: startContainer, 3071 offset: startOffset 3072 } = getNodeByPath(current, startPath); 3073 const { 3074 node: endContainer, 3075 offset: endOffset 3076 } = getNodeByPath(current, endPath); 3077 const { 3078 ownerDocument 3079 } = current; 3080 const { 3081 defaultView 3082 } = ownerDocument; 3083 const selection = defaultView.getSelection(); 3084 const range = ownerDocument.createRange(); 3085 range.setStart(startContainer, startOffset); 3086 range.setEnd(endContainer, endOffset); 3087 const { 3088 activeElement 3089 } = ownerDocument; 3090 3091 if (selection.rangeCount > 0) { 3092 // If the to be added range and the live range are the same, there's no 3093 // need to remove the live range and add the equivalent range. 3094 if (isRangeEqual(range, selection.getRangeAt(0))) { 3095 return; 3096 } 3097 3098 selection.removeAllRanges(); 3099 } 3100 3101 selection.addRange(range); // This function is not intended to cause a shift in focus. Since the above 3102 // selection manipulations may shift focus, ensure that focus is restored to 3103 // its previous state. 3104 3105 if (activeElement !== ownerDocument.activeElement) { 3106 // The `instanceof` checks protect against edge cases where the focused 3107 // element is not of the interface HTMLElement (does not have a `focus` 3108 // or `blur` property). 3109 // 3110 // See: https://github.com/Microsoft/TypeScript/issues/5901#issuecomment-431649653 3111 if (activeElement instanceof defaultView.HTMLElement) { 3112 activeElement.focus(); 3113 } 3114 } 3115 } 3116 3117 // EXTERNAL MODULE: external ["wp","escapeHtml"] 3118 var external_wp_escapeHtml_ = __webpack_require__("Vx3V"); 3119 3120 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/to-html-string.js 3121 /** 3122 * WordPress dependencies 3123 */ 3124 3125 /** 3126 * Internal dependencies 3127 */ 3128 3129 3130 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3131 3132 /** 3133 * Create an HTML string from a Rich Text value. If a `multilineTag` is 3134 * provided, text separated by a line separator will be wrapped in it. 3135 * 3136 * @param {Object} $1 Named argements. 3137 * @param {RichTextValue} $1.value Rich text value. 3138 * @param {string} [$1.multilineTag] Multiline tag. 3139 * @param {boolean} [$1.preserveWhiteSpace] Whether or not to use newline 3140 * characters for line breaks. 3141 * 3142 * @return {string} HTML string. 3143 */ 3144 3145 function toHTMLString({ 3146 value, 3147 multilineTag, 3148 preserveWhiteSpace 3149 }) { 3150 const tree = toTree({ 3151 value, 3152 multilineTag, 3153 preserveWhiteSpace, 3154 createEmpty: to_html_string_createEmpty, 3155 append: to_html_string_append, 3156 getLastChild: to_html_string_getLastChild, 3157 getParent: to_html_string_getParent, 3158 isText: to_html_string_isText, 3159 getText: to_html_string_getText, 3160 remove: to_html_string_remove, 3161 appendText: to_html_string_appendText 3162 }); 3163 return createChildrenHTML(tree.children); 3164 } 3165 3166 function to_html_string_createEmpty() { 3167 return {}; 3168 } 3169 3170 function to_html_string_getLastChild({ 3171 children 3172 }) { 3173 return children && children[children.length - 1]; 3174 } 3175 3176 function to_html_string_append(parent, object) { 3177 if (typeof object === 'string') { 3178 object = { 3179 text: object 3180 }; 3181 } 3182 3183 object.parent = parent; 3184 parent.children = parent.children || []; 3185 parent.children.push(object); 3186 return object; 3187 } 3188 3189 function to_html_string_appendText(object, text) { 3190 object.text += text; 3191 } 3192 3193 function to_html_string_getParent({ 3194 parent 3195 }) { 3196 return parent; 3197 } 3198 3199 function to_html_string_isText({ 3200 text 3201 }) { 3202 return typeof text === 'string'; 3203 } 3204 3205 function to_html_string_getText({ 3206 text 3207 }) { 3208 return text; 3209 } 3210 3211 function to_html_string_remove(object) { 3212 const index = object.parent.children.indexOf(object); 3213 3214 if (index !== -1) { 3215 object.parent.children.splice(index, 1); 3216 } 3217 3218 return object; 3219 } 3220 3221 function createElementHTML({ 3222 type, 3223 attributes, 3224 object, 3225 children 3226 }) { 3227 let attributeString = ''; 3228 3229 for (const key in attributes) { 3230 if (!Object(external_wp_escapeHtml_["isValidAttributeName"])(key)) { 3231 continue; 3232 } 3233 3234 attributeString += ` ${key}="${Object(external_wp_escapeHtml_["escapeAttribute"])(attributes[key])}"`; 3235 } 3236 3237 if (object) { 3238 return `<${type}${attributeString}>`; 3239 } 3240 3241 return `<${type}${attributeString}>${createChildrenHTML(children)}</${type}>`; 3242 } 3243 3244 function createChildrenHTML(children = []) { 3245 return children.map(child => { 3246 if (child.html !== undefined) { 3247 return child.html; 3248 } 3249 3250 return child.text === undefined ? createElementHTML(child) : Object(external_wp_escapeHtml_["escapeEditableHTML"])(child.text); 3251 }).join(''); 3252 } 3253 3254 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/toggle-format.js 3255 /** 3256 * Internal dependencies 3257 */ 3258 3259 3260 3261 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3262 3263 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 3264 3265 /** 3266 * Toggles a format object to a Rich Text value at the current selection. 3267 * 3268 * @param {RichTextValue} value Value to modify. 3269 * @param {RichTextFormat} format Format to apply or remove. 3270 * 3271 * @return {RichTextValue} A new value with the format applied or removed. 3272 */ 3273 3274 function toggleFormat(value, format) { 3275 if (getActiveFormat(value, format.type)) { 3276 return removeFormat(value, format.type); 3277 } 3278 3279 return applyFormat(value, format); 3280 } 3281 3282 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/unregister-format-type.js 3283 /** 3284 * WordPress dependencies 3285 */ 3286 3287 /** 3288 * Internal dependencies 3289 */ 3290 3291 3292 /** @typedef {import('./register-format-type').RichTextFormatType} RichTextFormatType */ 3293 3294 /** 3295 * Unregisters a format. 3296 * 3297 * @param {string} name Format name. 3298 * 3299 * @return {RichTextFormatType|undefined} The previous format value, if it has 3300 * been successfully unregistered; 3301 * otherwise `undefined`. 3302 */ 3303 3304 function unregisterFormatType(name) { 3305 const oldFormat = Object(external_wp_data_["select"])(store).getFormatType(name); 3306 3307 if (!oldFormat) { 3308 window.console.error(`Format ${name} is not registered.`); 3309 return; 3310 } 3311 3312 Object(external_wp_data_["dispatch"])(store).removeFormatTypes(name); 3313 return oldFormat; 3314 } 3315 3316 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/can-indent-list-items.js 3317 /** 3318 * Internal dependencies 3319 */ 3320 3321 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3322 3323 /** 3324 * Checks if the selected list item can be indented. 3325 * 3326 * @param {RichTextValue} value Value to check. 3327 * 3328 * @return {boolean} Whether or not the selected list item can be indented. 3329 */ 3330 3331 function canIndentListItems(value) { 3332 const lineIndex = getLineIndex(value); // There is only one line, so the line cannot be indented. 3333 3334 if (lineIndex === undefined) { 3335 return false; 3336 } 3337 3338 const { 3339 replacements 3340 } = value; 3341 const previousLineIndex = getLineIndex(value, lineIndex); 3342 const formatsAtLineIndex = replacements[lineIndex] || []; 3343 const formatsAtPreviousLineIndex = replacements[previousLineIndex] || []; // If the indentation of the current line is greater than previous line, 3344 // then the line cannot be furter indented. 3345 3346 return formatsAtLineIndex.length <= formatsAtPreviousLineIndex.length; 3347 } 3348 3349 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/can-outdent-list-items.js 3350 /** 3351 * Internal dependencies 3352 */ 3353 3354 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3355 3356 /** 3357 * Checks if the selected list item can be outdented. 3358 * 3359 * @param {RichTextValue} value Value to check. 3360 * 3361 * @return {boolean} Whether or not the selected list item can be outdented. 3362 */ 3363 3364 function canOutdentListItems(value) { 3365 const { 3366 replacements, 3367 start 3368 } = value; 3369 const startingLineIndex = getLineIndex(value, start); 3370 return replacements[startingLineIndex] !== undefined; 3371 } 3372 3373 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/indent-list-items.js 3374 /** 3375 * Internal dependencies 3376 */ 3377 3378 3379 3380 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3381 3382 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 3383 3384 /** 3385 * Gets the line index of the first previous list item with higher indentation. 3386 * 3387 * @param {RichTextValue} value Value to search. 3388 * @param {number} lineIndex Line index of the list item to compare 3389 * with. 3390 * 3391 * @return {number|void} The line index. 3392 */ 3393 3394 function getTargetLevelLineIndex({ 3395 text, 3396 replacements 3397 }, lineIndex) { 3398 const startFormats = replacements[lineIndex] || []; 3399 let index = lineIndex; 3400 3401 while (index-- >= 0) { 3402 if (text[index] !== LINE_SEPARATOR) { 3403 continue; 3404 } 3405 3406 const formatsAtIndex = replacements[index] || []; // Return the first line index that is one level higher. If the level is 3407 // lower or equal, there is no result. 3408 3409 if (formatsAtIndex.length === startFormats.length + 1) { 3410 return index; 3411 } else if (formatsAtIndex.length <= startFormats.length) { 3412 return; 3413 } 3414 } 3415 } 3416 /** 3417 * Indents any selected list items if possible. 3418 * 3419 * @param {RichTextValue} value Value to change. 3420 * @param {RichTextFormat} rootFormat Root format. 3421 * 3422 * @return {RichTextValue} The changed value. 3423 */ 3424 3425 3426 function indentListItems(value, rootFormat) { 3427 if (!canIndentListItems(value)) { 3428 return value; 3429 } 3430 3431 const lineIndex = getLineIndex(value); 3432 const previousLineIndex = getLineIndex(value, lineIndex); 3433 const { 3434 text, 3435 replacements, 3436 end 3437 } = value; 3438 const newFormats = replacements.slice(); 3439 const targetLevelLineIndex = getTargetLevelLineIndex(value, lineIndex); 3440 3441 for (let index = lineIndex; index < end; index++) { 3442 if (text[index] !== LINE_SEPARATOR) { 3443 continue; 3444 } // Get the previous list, and if there's a child list, take over the 3445 // formats. If not, duplicate the last level and create a new level. 3446 3447 3448 if (targetLevelLineIndex) { 3449 const targetFormats = replacements[targetLevelLineIndex] || []; 3450 newFormats[index] = targetFormats.concat((newFormats[index] || []).slice(targetFormats.length - 1)); 3451 } else { 3452 const targetFormats = replacements[previousLineIndex] || []; 3453 const lastformat = targetFormats[targetFormats.length - 1] || rootFormat; 3454 newFormats[index] = targetFormats.concat([lastformat], (newFormats[index] || []).slice(targetFormats.length)); 3455 } 3456 } 3457 3458 return { ...value, 3459 replacements: newFormats 3460 }; 3461 } 3462 3463 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-parent-line-index.js 3464 /** 3465 * Internal dependencies 3466 */ 3467 3468 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3469 3470 /** 3471 * Gets the index of the first parent list. To get the parent list formats, we 3472 * go through every list item until we find one with exactly one format type 3473 * less. 3474 * 3475 * @param {RichTextValue} value Value to search. 3476 * @param {number} lineIndex Line index of a child list item. 3477 * 3478 * @return {number|void} The parent list line index. 3479 */ 3480 3481 function getParentLineIndex({ 3482 text, 3483 replacements 3484 }, lineIndex) { 3485 const startFormats = replacements[lineIndex] || []; 3486 let index = lineIndex; 3487 3488 while (index-- >= 0) { 3489 if (text[index] !== LINE_SEPARATOR) { 3490 continue; 3491 } 3492 3493 const formatsAtIndex = replacements[index] || []; 3494 3495 if (formatsAtIndex.length === startFormats.length - 1) { 3496 return index; 3497 } 3498 } 3499 } 3500 3501 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-last-child-index.js 3502 /** 3503 * Internal dependencies 3504 */ 3505 3506 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3507 3508 /** 3509 * Gets the line index of the last child in the list. 3510 * 3511 * @param {RichTextValue} value Value to search. 3512 * @param {number} lineIndex Line index of a list item in the list. 3513 * 3514 * @return {number} The index of the last child. 3515 */ 3516 3517 function getLastChildIndex({ 3518 text, 3519 replacements 3520 }, lineIndex) { 3521 const lineFormats = replacements[lineIndex] || []; // Use the given line index in case there are no next children. 3522 3523 let childIndex = lineIndex; // `lineIndex` could be `undefined` if it's the first line. 3524 3525 for (let index = lineIndex || 0; index < text.length; index++) { 3526 // We're only interested in line indices. 3527 if (text[index] !== LINE_SEPARATOR) { 3528 continue; 3529 } 3530 3531 const formatsAtIndex = replacements[index] || []; // If the amout of formats is equal or more, store it, then return the 3532 // last one if the amount of formats is less. 3533 3534 if (formatsAtIndex.length >= lineFormats.length) { 3535 childIndex = index; 3536 } else { 3537 return childIndex; 3538 } 3539 } // If the end of the text is reached, return the last child index. 3540 3541 3542 return childIndex; 3543 } 3544 3545 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/outdent-list-items.js 3546 /** 3547 * Internal dependencies 3548 */ 3549 3550 3551 3552 3553 3554 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3555 3556 /** 3557 * Outdents any selected list items if possible. 3558 * 3559 * @param {RichTextValue} value Value to change. 3560 * 3561 * @return {RichTextValue} The changed value. 3562 */ 3563 3564 function outdentListItems(value) { 3565 if (!canOutdentListItems(value)) { 3566 return value; 3567 } 3568 3569 const { 3570 text, 3571 replacements, 3572 start, 3573 end 3574 } = value; 3575 const startingLineIndex = getLineIndex(value, start); 3576 const newFormats = replacements.slice(0); 3577 const parentFormats = replacements[getParentLineIndex(value, startingLineIndex)] || []; 3578 const endingLineIndex = getLineIndex(value, end); 3579 const lastChildIndex = getLastChildIndex(value, endingLineIndex); // Outdent all list items from the starting line index until the last child 3580 // index of the ending list. All children of the ending list need to be 3581 // outdented, otherwise they'll be orphaned. 3582 3583 for (let index = startingLineIndex; index <= lastChildIndex; index++) { 3584 // Skip indices that are not line separators. 3585 if (text[index] !== LINE_SEPARATOR) { 3586 continue; 3587 } // In the case of level 0, the formats at the index are undefined. 3588 3589 3590 const currentFormats = newFormats[index] || []; // Omit the indentation level where the selection starts. 3591 3592 newFormats[index] = parentFormats.concat(currentFormats.slice(parentFormats.length + 1)); 3593 3594 if (newFormats[index].length === 0) { 3595 delete newFormats[index]; 3596 } 3597 } 3598 3599 return { ...value, 3600 replacements: newFormats 3601 }; 3602 } 3603 3604 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/change-list-type.js 3605 /** 3606 * Internal dependencies 3607 */ 3608 3609 3610 3611 /** @typedef {import('./create').RichTextValue} RichTextValue */ 3612 3613 /** @typedef {import('./create').RichTextFormat} RichTextFormat */ 3614 3615 /** 3616 * Changes the list type of the selected indented list, if any. Looks at the 3617 * currently selected list item and takes the parent list, then changes the list 3618 * type of this list. When multiple lines are selected, the parent lists are 3619 * takes and changed. 3620 * 3621 * @param {RichTextValue} value Value to change. 3622 * @param {RichTextFormat} newFormat The new list format object. Choose between 3623 * `{ type: 'ol' }` and `{ type: 'ul' }`. 3624 * 3625 * @return {RichTextValue} The changed value. 3626 */ 3627 3628 function changeListType(value, newFormat) { 3629 const { 3630 text, 3631 replacements, 3632 start, 3633 end 3634 } = value; 3635 const startingLineIndex = getLineIndex(value, start); 3636 const startLineFormats = replacements[startingLineIndex] || []; 3637 const endLineFormats = replacements[getLineIndex(value, end)] || []; 3638 const startIndex = getParentLineIndex(value, startingLineIndex); 3639 const newReplacements = replacements.slice(); 3640 const startCount = startLineFormats.length - 1; 3641 const endCount = endLineFormats.length - 1; 3642 let changed; 3643 3644 for (let index = startIndex + 1 || 0; index < text.length; index++) { 3645 if (text[index] !== LINE_SEPARATOR) { 3646 continue; 3647 } 3648 3649 if ((newReplacements[index] || []).length <= startCount) { 3650 break; 3651 } 3652 3653 if (!newReplacements[index]) { 3654 continue; 3655 } 3656 3657 changed = true; 3658 newReplacements[index] = newReplacements[index].map((format, i) => { 3659 return i < startCount || i > endCount ? format : newFormat; 3660 }); 3661 } 3662 3663 if (!changed) { 3664 return value; 3665 } 3666 3667 return { ...value, 3668 replacements: newReplacements 3669 }; 3670 } 3671 3672 // EXTERNAL MODULE: external ["wp","element"] 3673 var external_wp_element_ = __webpack_require__("GRId"); 3674 3675 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-anchor-ref.js 3676 /** 3677 * WordPress dependencies 3678 */ 3679 3680 /** 3681 * Internal dependencies 3682 */ 3683 3684 3685 /** @typedef {import('@wordpress/element').RefObject} RefObject */ 3686 3687 /** @typedef {import('../register-format-type').RichTextFormatType} RichTextFormatType */ 3688 3689 /** @typedef {import('../create').RichTextValue} RichTextValue */ 3690 3691 /** 3692 * This hook, to be used in a format type's Edit component, returns the active 3693 * element that is formatted, or the selection range if no format is active. 3694 * The returned value is meant to be used for positioning UI, e.g. by passing it 3695 * to the `Popover` component. 3696 * 3697 * @param {Object} $1 Named parameters. 3698 * @param {RefObject<HTMLElement>} $1.ref React ref of the element 3699 * containing the editable content. 3700 * @param {RichTextValue} $1.value Value to check for selection. 3701 * @param {RichTextFormatType} $1.settings The format type's settings. 3702 * 3703 * @return {Element|Range} The active element or selection range. 3704 */ 3705 3706 function useAnchorRef({ 3707 ref, 3708 value, 3709 settings = {} 3710 }) { 3711 const { 3712 tagName, 3713 className, 3714 name 3715 } = settings; 3716 const activeFormat = name ? getActiveFormat(value, name) : undefined; 3717 return Object(external_wp_element_["useMemo"])(() => { 3718 if (!ref.current) return; 3719 const { 3720 ownerDocument: { 3721 defaultView 3722 } 3723 } = ref.current; 3724 const selection = defaultView.getSelection(); 3725 3726 if (!selection.rangeCount) { 3727 return; 3728 } 3729 3730 const range = selection.getRangeAt(0); 3731 3732 if (!activeFormat) { 3733 return range; 3734 } 3735 3736 let element = range.startContainer; // If the caret is right before the element, select the next element. 3737 3738 element = element.nextElementSibling || element; 3739 3740 while (element.nodeType !== element.ELEMENT_NODE) { 3741 element = element.parentNode; 3742 } 3743 3744 return element.closest(tagName + (className ? '.' + className : '')); 3745 }, [activeFormat, value.start, value.end, tagName, className]); 3746 } 3747 3748 // EXTERNAL MODULE: external ["wp","compose"] 3749 var external_wp_compose_ = __webpack_require__("K9lf"); 3750 3751 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-default-style.js 3752 /** 3753 * WordPress dependencies 3754 */ 3755 3756 /** 3757 * In HTML, leading and trailing spaces are not visible, and multiple spaces 3758 * elsewhere are visually reduced to one space. This rule prevents spaces from 3759 * collapsing so all space is visible in the editor and can be removed. It also 3760 * prevents some browsers from inserting non-breaking spaces at the end of a 3761 * line to prevent the space from visually disappearing. Sometimes these non 3762 * breaking spaces can linger in the editor causing unwanted non breaking spaces 3763 * in between words. If also prevent Firefox from inserting a trailing `br` node 3764 * to visualise any trailing space, causing the element to be saved. 3765 * 3766 * > Authors are encouraged to set the 'white-space' property on editing hosts 3767 * > and on markup that was originally created through these editing mechanisms 3768 * > to the value 'pre-wrap'. Default HTML whitespace handling is not well 3769 * > suited to WYSIWYG editing, and line wrapping will not work correctly in 3770 * > some corner cases if 'white-space' is left at its default value. 3771 * 3772 * https://html.spec.whatwg.org/multipage/interaction.html#best-practices-for-in-page-editors 3773 * 3774 * @type {string} 3775 */ 3776 3777 const whiteSpace = 'pre-wrap'; 3778 /** 3779 * A minimum width of 1px will prevent the rich text container from collapsing 3780 * to 0 width and hiding the caret. This is useful for inline containers. 3781 */ 3782 3783 const minWidth = '1px'; 3784 function useDefaultStyle() { 3785 return Object(external_wp_element_["useCallback"])(element => { 3786 if (!element) return; 3787 element.style.whiteSpace = whiteSpace; 3788 element.style.minWidth = minWidth; 3789 }, []); 3790 } 3791 3792 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-boundary-style.js 3793 /** 3794 * WordPress dependencies 3795 */ 3796 3797 /* 3798 * Calculates and renders the format boundary style when the active formats 3799 * change. 3800 */ 3801 3802 function useBoundaryStyle({ 3803 record 3804 }) { 3805 const ref = Object(external_wp_element_["useRef"])(); 3806 const { 3807 activeFormats = [] 3808 } = record.current; 3809 Object(external_wp_element_["useEffect"])(() => { 3810 // There's no need to recalculate the boundary styles if no formats are 3811 // active, because no boundary styles will be visible. 3812 if (!activeFormats || !activeFormats.length) { 3813 return; 3814 } 3815 3816 const boundarySelector = '*[data-rich-text-format-boundary]'; 3817 const element = ref.current.querySelector(boundarySelector); 3818 3819 if (!element) { 3820 return; 3821 } 3822 3823 const { 3824 ownerDocument 3825 } = element; 3826 const { 3827 defaultView 3828 } = ownerDocument; 3829 const computedStyle = defaultView.getComputedStyle(element); 3830 const newColor = computedStyle.color.replace(')', ', 0.2)').replace('rgb', 'rgba'); 3831 const selector = `.rich-text:focus ${boundarySelector}`; 3832 const rule = `background-color: ${newColor}`; 3833 const style = `${selector} {${rule}}`; 3834 const globalStyleId = 'rich-text-boundary-style'; 3835 let globalStyle = ownerDocument.getElementById(globalStyleId); 3836 3837 if (!globalStyle) { 3838 globalStyle = ownerDocument.createElement('style'); 3839 globalStyle.id = globalStyleId; 3840 ownerDocument.head.appendChild(globalStyle); 3841 } 3842 3843 if (globalStyle.innerHTML !== style) { 3844 globalStyle.innerHTML = style; 3845 } 3846 }, [activeFormats]); 3847 return ref; 3848 } 3849 3850 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-inline-warning.js 3851 /** 3852 * WordPress dependencies 3853 */ 3854 3855 const message = 'RichText cannot be used with an inline container. Please use a different display property.'; 3856 function useInlineWarning() { 3857 const ref = Object(external_wp_element_["useRef"])(); 3858 Object(external_wp_element_["useEffect"])(() => { 3859 if (false) {} 3860 }, []); 3861 return ref; 3862 } 3863 3864 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-copy-handler.js 3865 /** 3866 * WordPress dependencies 3867 */ 3868 3869 3870 /** 3871 * Internal dependencies 3872 */ 3873 3874 3875 3876 3877 3878 function useCopyHandler(props) { 3879 const propsRef = Object(external_wp_element_["useRef"])(props); 3880 propsRef.current = props; 3881 return Object(external_wp_compose_["useRefEffect"])(element => { 3882 function onCopy(event) { 3883 const { 3884 record, 3885 multilineTag, 3886 preserveWhiteSpace 3887 } = propsRef.current; 3888 3889 if (isCollapsed(record.current) || !element.contains(element.ownerDocument.activeElement)) { 3890 return; 3891 } 3892 3893 const selectedRecord = slice(record.current); 3894 const plainText = getTextContent(selectedRecord); 3895 const html = toHTMLString({ 3896 value: selectedRecord, 3897 multilineTag, 3898 preserveWhiteSpace 3899 }); 3900 event.clipboardData.setData('text/plain', plainText); 3901 event.clipboardData.setData('text/html', html); 3902 event.clipboardData.setData('rich-text', 'true'); 3903 event.preventDefault(); 3904 } 3905 3906 element.addEventListener('copy', onCopy); 3907 return () => { 3908 element.removeEventListener('copy', onCopy); 3909 }; 3910 }, []); 3911 } 3912 3913 // EXTERNAL MODULE: external ["wp","keycodes"] 3914 var external_wp_keycodes_ = __webpack_require__("RxS6"); 3915 3916 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-format-boundaries.js 3917 /** 3918 * WordPress dependencies 3919 */ 3920 3921 3922 3923 /** 3924 * Internal dependencies 3925 */ 3926 3927 3928 const EMPTY_ACTIVE_FORMATS = []; 3929 function useFormatBoundaries(props) { 3930 const [, forceRender] = Object(external_wp_element_["useReducer"])(() => ({})); 3931 const propsRef = Object(external_wp_element_["useRef"])(props); 3932 propsRef.current = props; 3933 return Object(external_wp_compose_["useRefEffect"])(element => { 3934 function onKeyDown(event) { 3935 const { 3936 keyCode, 3937 shiftKey, 3938 altKey, 3939 metaKey, 3940 ctrlKey 3941 } = event; 3942 3943 if ( // Only override left and right keys without modifiers pressed. 3944 shiftKey || altKey || metaKey || ctrlKey || keyCode !== external_wp_keycodes_["LEFT"] && keyCode !== external_wp_keycodes_["RIGHT"]) { 3945 return; 3946 } 3947 3948 const { 3949 record, 3950 applyRecord 3951 } = propsRef.current; 3952 const { 3953 text, 3954 formats, 3955 start, 3956 end, 3957 activeFormats: currentActiveFormats = [] 3958 } = record.current; 3959 const collapsed = isCollapsed(record.current); 3960 const { 3961 ownerDocument 3962 } = element; 3963 const { 3964 defaultView 3965 } = ownerDocument; // To do: ideally, we should look at visual position instead. 3966 3967 const { 3968 direction 3969 } = defaultView.getComputedStyle(element); 3970 const reverseKey = direction === 'rtl' ? external_wp_keycodes_["RIGHT"] : external_wp_keycodes_["LEFT"]; 3971 const isReverse = event.keyCode === reverseKey; // If the selection is collapsed and at the very start, do nothing if 3972 // navigating backward. 3973 // If the selection is collapsed and at the very end, do nothing if 3974 // navigating forward. 3975 3976 if (collapsed && currentActiveFormats.length === 0) { 3977 if (start === 0 && isReverse) { 3978 return; 3979 } 3980 3981 if (end === text.length && !isReverse) { 3982 return; 3983 } 3984 } // If the selection is not collapsed, let the browser handle collapsing 3985 // the selection for now. Later we could expand this logic to set 3986 // boundary positions if needed. 3987 3988 3989 if (!collapsed) { 3990 return; 3991 } 3992 3993 const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS; 3994 const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS; 3995 let newActiveFormatsLength = currentActiveFormats.length; 3996 let source = formatsAfter; 3997 3998 if (formatsBefore.length > formatsAfter.length) { 3999 source = formatsBefore; 4000 } // If the amount of formats before the caret and after the caret is 4001 // different, the caret is at a format boundary. 4002 4003 4004 if (formatsBefore.length < formatsAfter.length) { 4005 if (!isReverse && currentActiveFormats.length < formatsAfter.length) { 4006 newActiveFormatsLength++; 4007 } 4008 4009 if (isReverse && currentActiveFormats.length > formatsBefore.length) { 4010 newActiveFormatsLength--; 4011 } 4012 } else if (formatsBefore.length > formatsAfter.length) { 4013 if (!isReverse && currentActiveFormats.length > formatsAfter.length) { 4014 newActiveFormatsLength--; 4015 } 4016 4017 if (isReverse && currentActiveFormats.length < formatsBefore.length) { 4018 newActiveFormatsLength++; 4019 } 4020 } 4021 4022 if (newActiveFormatsLength === currentActiveFormats.length) { 4023 record.current._newActiveFormats = isReverse ? formatsBefore : formatsAfter; 4024 return; 4025 } 4026 4027 event.preventDefault(); 4028 const newActiveFormats = source.slice(0, newActiveFormatsLength); 4029 const newValue = { ...record.current, 4030 activeFormats: newActiveFormats 4031 }; 4032 record.current = newValue; 4033 applyRecord(newValue); 4034 forceRender(); 4035 } 4036 4037 element.addEventListener('keydown', onKeyDown); 4038 return () => { 4039 element.removeEventListener('keydown', onKeyDown); 4040 }; 4041 }, []); 4042 } 4043 4044 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-select-object.js 4045 /** 4046 * WordPress dependencies 4047 */ 4048 4049 function useSelectObject() { 4050 return Object(external_wp_compose_["useRefEffect"])(element => { 4051 function onClick(event) { 4052 const { 4053 target 4054 } = event; // If the child element has no text content, it must be an object. 4055 4056 if (target === element || target.textContent) { 4057 return; 4058 } 4059 4060 const { 4061 ownerDocument 4062 } = target; 4063 const { 4064 defaultView 4065 } = ownerDocument; 4066 const range = ownerDocument.createRange(); 4067 const selection = defaultView.getSelection(); 4068 range.selectNode(target); 4069 selection.removeAllRanges(); 4070 selection.addRange(range); 4071 } 4072 4073 element.addEventListener('click', onClick); 4074 return () => { 4075 element.removeEventListener('click', onClick); 4076 }; 4077 }, []); 4078 } 4079 4080 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-indent-list-item-on-space.js 4081 /** 4082 * WordPress dependencies 4083 */ 4084 4085 4086 4087 /** 4088 * Internal dependencies 4089 */ 4090 4091 4092 4093 4094 function useIndentListItemOnSpace(props) { 4095 const propsRef = Object(external_wp_element_["useRef"])(props); 4096 propsRef.current = props; 4097 return Object(external_wp_compose_["useRefEffect"])(element => { 4098 function onKeyDown(event) { 4099 const { 4100 keyCode, 4101 shiftKey, 4102 altKey, 4103 metaKey, 4104 ctrlKey 4105 } = event; 4106 const { 4107 multilineTag, 4108 createRecord, 4109 handleChange 4110 } = propsRef.current; 4111 4112 if ( // Only override when no modifiers are pressed. 4113 shiftKey || altKey || metaKey || ctrlKey || keyCode !== external_wp_keycodes_["SPACE"] || multilineTag !== 'li') { 4114 return; 4115 } 4116 4117 const currentValue = createRecord(); 4118 4119 if (!isCollapsed(currentValue)) { 4120 return; 4121 } 4122 4123 const { 4124 text, 4125 start 4126 } = currentValue; 4127 const characterBefore = text[start - 1]; // The caret must be at the start of a line. 4128 4129 if (characterBefore && characterBefore !== LINE_SEPARATOR) { 4130 return; 4131 } 4132 4133 handleChange(indentListItems(currentValue, { 4134 type: element.tagName.toLowerCase() 4135 })); 4136 event.preventDefault(); 4137 } 4138 4139 element.addEventListener('keydown', onKeyDown); 4140 return () => { 4141 element.removeEventListener('keydown', onKeyDown); 4142 }; 4143 }, []); 4144 } 4145 4146 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/update-formats.js 4147 /** 4148 * Internal dependencies 4149 */ 4150 4151 /** @typedef {import('./create').RichTextValue} RichTextValue */ 4152 4153 /** 4154 * Efficiently updates all the formats from `start` (including) until `end` 4155 * (excluding) with the active formats. Mutates `value`. 4156 * 4157 * @param {Object} $1 Named paramentes. 4158 * @param {RichTextValue} $1.value Value te update. 4159 * @param {number} $1.start Index to update from. 4160 * @param {number} $1.end Index to update until. 4161 * @param {Array} $1.formats Replacement formats. 4162 * 4163 * @return {RichTextValue} Mutated value. 4164 */ 4165 4166 function updateFormats({ 4167 value, 4168 start, 4169 end, 4170 formats 4171 }) { 4172 const formatsBefore = value.formats[start - 1] || []; 4173 const formatsAfter = value.formats[end] || []; // First, fix the references. If any format right before or after are 4174 // equal, the replacement format should use the same reference. 4175 4176 value.activeFormats = formats.map((format, index) => { 4177 if (formatsBefore[index]) { 4178 if (isFormatEqual(format, formatsBefore[index])) { 4179 return formatsBefore[index]; 4180 } 4181 } else if (formatsAfter[index]) { 4182 if (isFormatEqual(format, formatsAfter[index])) { 4183 return formatsAfter[index]; 4184 } 4185 } 4186 4187 return format; 4188 }); 4189 4190 while (--end >= start) { 4191 if (value.activeFormats.length > 0) { 4192 value.formats[end] = value.activeFormats; 4193 } else { 4194 delete value.formats[end]; 4195 } 4196 } 4197 4198 return value; 4199 } 4200 4201 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-input-and-selection.js 4202 /** 4203 * WordPress dependencies 4204 */ 4205 4206 4207 /** 4208 * Internal dependencies 4209 */ 4210 4211 4212 4213 /** 4214 * All inserting input types that would insert HTML into the DOM. 4215 * 4216 * @see https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes 4217 * 4218 * @type {Set} 4219 */ 4220 4221 const INSERTION_INPUT_TYPES_TO_IGNORE = new Set(['insertParagraph', 'insertOrderedList', 'insertUnorderedList', 'insertHorizontalRule', 'insertLink']); 4222 const use_input_and_selection_EMPTY_ACTIVE_FORMATS = []; 4223 /** 4224 * If the selection is set on the placeholder element, collapse the selection to 4225 * the start (before the placeholder). 4226 * 4227 * @param {Window} defaultView 4228 */ 4229 4230 function fixPlaceholderSelection(defaultView) { 4231 const selection = defaultView.getSelection(); 4232 const { 4233 anchorNode, 4234 anchorOffset 4235 } = selection; 4236 4237 if (anchorNode.nodeType !== anchorNode.ELEMENT_NODE) { 4238 return; 4239 } 4240 4241 const targetNode = anchorNode.childNodes[anchorOffset]; 4242 4243 if (!targetNode || targetNode.nodeType !== targetNode.ELEMENT_NODE || !targetNode.getAttribute('data-rich-text-placeholder')) { 4244 return; 4245 } 4246 4247 selection.collapseToStart(); 4248 } 4249 4250 function useInputAndSelection(props) { 4251 const propsRef = Object(external_wp_element_["useRef"])(props); 4252 propsRef.current = props; 4253 return Object(external_wp_compose_["useRefEffect"])(element => { 4254 const { 4255 ownerDocument 4256 } = element; 4257 const { 4258 defaultView 4259 } = ownerDocument; 4260 let isComposing = false; 4261 let rafId; 4262 4263 function onInput(event) { 4264 // Do not trigger a change if characters are being composed. 4265 // Browsers will usually emit a final `input` event when the 4266 // characters are composed. 4267 // As of December 2019, Safari doesn't support 4268 // nativeEvent.isComposing. 4269 if (isComposing) { 4270 return; 4271 } 4272 4273 let inputType; 4274 4275 if (event) { 4276 inputType = event.inputType; 4277 } 4278 4279 const { 4280 record, 4281 applyRecord, 4282 createRecord, 4283 handleChange 4284 } = propsRef.current; // The browser formatted something or tried to insert HTML. 4285 // Overwrite it. It will be handled later by the format library if 4286 // needed. 4287 4288 if (inputType && (inputType.indexOf('format') === 0 || INSERTION_INPUT_TYPES_TO_IGNORE.has(inputType))) { 4289 applyRecord(record.current); 4290 return; 4291 } 4292 4293 const currentValue = createRecord(); 4294 const { 4295 start, 4296 activeFormats: oldActiveFormats = [] 4297 } = record.current; // Update the formats between the last and new caret position. 4298 4299 const change = updateFormats({ 4300 value: currentValue, 4301 start, 4302 end: currentValue.start, 4303 formats: oldActiveFormats 4304 }); 4305 handleChange(change); 4306 } 4307 /** 4308 * Syncs the selection to local state. A callback for the `selectionchange` 4309 * native events, `keyup`, `mouseup` and `touchend` synthetic events, and 4310 * animation frames after the `focus` event. 4311 * 4312 * @param {Event|DOMHighResTimeStamp} event 4313 */ 4314 4315 4316 function handleSelectionChange(event) { 4317 if (ownerDocument.activeElement !== element) { 4318 return; 4319 } 4320 4321 const { 4322 record, 4323 applyRecord, 4324 createRecord, 4325 isSelected, 4326 onSelectionChange 4327 } = propsRef.current; 4328 4329 if (event.type !== 'selectionchange' && !isSelected) { 4330 return; 4331 } // Check if the implementor disabled editing. `contentEditable` 4332 // does disable input, but not text selection, so we must ignore 4333 // selection changes. 4334 4335 4336 if (element.contentEditable !== 'true') { 4337 return; 4338 } // In case of a keyboard event, ignore selection changes during 4339 // composition. 4340 4341 4342 if (isComposing) { 4343 return; 4344 } 4345 4346 const { 4347 start, 4348 end, 4349 text 4350 } = createRecord(); 4351 const oldRecord = record.current; // Fallback mechanism for IE11, which doesn't support the input event. 4352 // Any input results in a selection change. 4353 4354 if (text !== oldRecord.text) { 4355 onInput(); 4356 return; 4357 } 4358 4359 if (start === oldRecord.start && end === oldRecord.end) { 4360 // Sometimes the browser may set the selection on the placeholder 4361 // element, in which case the caret is not visible. We need to set 4362 // the caret before the placeholder if that's the case. 4363 if (oldRecord.text.length === 0 && start === 0) { 4364 fixPlaceholderSelection(defaultView); 4365 } 4366 4367 return; 4368 } 4369 4370 const newValue = { ...oldRecord, 4371 start, 4372 end, 4373 // _newActiveFormats may be set on arrow key navigation to control 4374 // the right boundary position. If undefined, getActiveFormats will 4375 // give the active formats according to the browser. 4376 activeFormats: oldRecord._newActiveFormats, 4377 _newActiveFormats: undefined 4378 }; 4379 const newActiveFormats = getActiveFormats(newValue, use_input_and_selection_EMPTY_ACTIVE_FORMATS); // Update the value with the new active formats. 4380 4381 newValue.activeFormats = newActiveFormats; // It is important that the internal value is updated first, 4382 // otherwise the value will be wrong on render! 4383 4384 record.current = newValue; 4385 applyRecord(newValue, { 4386 domOnly: true 4387 }); 4388 onSelectionChange(start, end); 4389 } 4390 4391 function onCompositionStart() { 4392 isComposing = true; // Do not update the selection when characters are being composed as 4393 // this rerenders the component and might distroy internal browser 4394 // editing state. 4395 4396 ownerDocument.removeEventListener('selectionchange', handleSelectionChange); 4397 } 4398 4399 function onCompositionEnd() { 4400 isComposing = false; // Ensure the value is up-to-date for browsers that don't emit a final 4401 // input event after composition. 4402 4403 onInput({ 4404 inputType: 'insertText' 4405 }); // Tracking selection changes can be resumed. 4406 4407 ownerDocument.addEventListener('selectionchange', handleSelectionChange); 4408 } 4409 4410 function onFocus() { 4411 const { 4412 record, 4413 isSelected, 4414 onSelectionChange 4415 } = propsRef.current; 4416 4417 if (!isSelected) { 4418 // We know for certain that on focus, the old selection is invalid. 4419 // It will be recalculated on the next mouseup, keyup, or touchend 4420 // event. 4421 const index = undefined; 4422 record.current = { ...record.current, 4423 start: index, 4424 end: index, 4425 activeFormats: use_input_and_selection_EMPTY_ACTIVE_FORMATS 4426 }; 4427 onSelectionChange(index, index); 4428 } else { 4429 onSelectionChange(record.current.start, record.current.end); 4430 } // Update selection as soon as possible, which is at the next animation 4431 // frame. The event listener for selection changes may be added too late 4432 // at this point, but this focus event is still too early to calculate 4433 // the selection. 4434 4435 4436 rafId = defaultView.requestAnimationFrame(handleSelectionChange); 4437 ownerDocument.addEventListener('selectionchange', handleSelectionChange); 4438 } 4439 4440 function onBlur() { 4441 ownerDocument.removeEventListener('selectionchange', handleSelectionChange); 4442 } 4443 4444 element.addEventListener('input', onInput); 4445 element.addEventListener('compositionstart', onCompositionStart); 4446 element.addEventListener('compositionend', onCompositionEnd); 4447 element.addEventListener('focus', onFocus); 4448 element.addEventListener('blur', onBlur); // Selection updates must be done at these events as they 4449 // happen before the `selectionchange` event. In some cases, 4450 // the `selectionchange` event may not even fire, for 4451 // example when the window receives focus again on click. 4452 4453 element.addEventListener('keyup', handleSelectionChange); 4454 element.addEventListener('mouseup', handleSelectionChange); 4455 element.addEventListener('touchend', handleSelectionChange); 4456 return () => { 4457 element.removeEventListener('input', onInput); 4458 element.removeEventListener('compositionstart', onCompositionStart); 4459 element.removeEventListener('compositionend', onCompositionEnd); 4460 element.removeEventListener('focus', onFocus); 4461 element.removeEventListener('blur', onBlur); 4462 element.removeEventListener('keyup', handleSelectionChange); 4463 element.removeEventListener('mouseup', handleSelectionChange); 4464 element.removeEventListener('touchend', handleSelectionChange); 4465 ownerDocument.removeEventListener('selectionchange', handleSelectionChange); 4466 defaultView.cancelAnimationFrame(rafId); 4467 }; 4468 }, []); 4469 } 4470 4471 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-delete.js 4472 /** 4473 * WordPress dependencies 4474 */ 4475 4476 4477 4478 /** 4479 * Internal dependencies 4480 */ 4481 4482 4483 4484 4485 function useDelete(props) { 4486 const propsRef = Object(external_wp_element_["useRef"])(props); 4487 propsRef.current = props; 4488 return Object(external_wp_compose_["useRefEffect"])(element => { 4489 function onKeyDown(event) { 4490 const { 4491 keyCode 4492 } = event; 4493 const { 4494 createRecord, 4495 handleChange, 4496 multilineTag 4497 } = propsRef.current; 4498 4499 if (event.defaultPrevented) { 4500 return; 4501 } 4502 4503 if (keyCode !== external_wp_keycodes_["DELETE"] && keyCode !== external_wp_keycodes_["BACKSPACE"]) { 4504 return; 4505 } 4506 4507 const currentValue = createRecord(); 4508 const { 4509 start, 4510 end, 4511 text 4512 } = currentValue; 4513 const isReverse = keyCode === external_wp_keycodes_["BACKSPACE"]; // Always handle full content deletion ourselves. 4514 4515 if (start === 0 && end !== 0 && end === text.length) { 4516 handleChange(remove_remove(currentValue)); 4517 event.preventDefault(); 4518 return; 4519 } 4520 4521 if (multilineTag) { 4522 let newValue; // Check to see if we should remove the first item if empty. 4523 4524 if (isReverse && currentValue.start === 0 && currentValue.end === 0 && isEmptyLine(currentValue)) { 4525 newValue = removeLineSeparator(currentValue, !isReverse); 4526 } else { 4527 newValue = removeLineSeparator(currentValue, isReverse); 4528 } 4529 4530 if (newValue) { 4531 handleChange(newValue); 4532 event.preventDefault(); 4533 } 4534 } 4535 } 4536 4537 element.addEventListener('keydown', onKeyDown); 4538 return () => { 4539 element.removeEventListener('keydown', onKeyDown); 4540 }; 4541 }, []); 4542 } 4543 4544 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/index.js 4545 /** 4546 * WordPress dependencies 4547 */ 4548 4549 4550 /** 4551 * Internal dependencies 4552 */ 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 function useRichText({ 4567 value = '', 4568 selectionStart, 4569 selectionEnd, 4570 placeholder, 4571 preserveWhiteSpace, 4572 onSelectionChange, 4573 onChange, 4574 __unstableMultilineTag: multilineTag, 4575 __unstableDisableFormats: disableFormats, 4576 __unstableIsSelected: isSelected, 4577 __unstableDependencies, 4578 __unstableAfterParse, 4579 __unstableBeforeSerialize, 4580 __unstableAddInvisibleFormats 4581 }) { 4582 const [, forceRender] = Object(external_wp_element_["useReducer"])(() => ({})); 4583 const ref = Object(external_wp_element_["useRef"])(); 4584 4585 function createRecord() { 4586 const { 4587 ownerDocument: { 4588 defaultView 4589 } 4590 } = ref.current; 4591 const selection = defaultView.getSelection(); 4592 const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null; 4593 return create({ 4594 element: ref.current, 4595 range, 4596 multilineTag, 4597 multilineWrapperTags: multilineTag === 'li' ? ['ul', 'ol'] : undefined, 4598 __unstableIsEditableTree: true, 4599 preserveWhiteSpace 4600 }); 4601 } 4602 4603 function applyRecord(newRecord, { 4604 domOnly 4605 } = {}) { 4606 apply({ 4607 value: newRecord, 4608 current: ref.current, 4609 multilineTag, 4610 multilineWrapperTags: multilineTag === 'li' ? ['ul', 'ol'] : undefined, 4611 prepareEditableTree: __unstableAddInvisibleFormats, 4612 __unstableDomOnly: domOnly, 4613 placeholder 4614 }); 4615 } // Internal values are updated synchronously, unlike props and state. 4616 4617 4618 const _value = Object(external_wp_element_["useRef"])(value); 4619 4620 const record = Object(external_wp_element_["useRef"])(); 4621 4622 function setRecordFromProps() { 4623 _value.current = value; 4624 record.current = create({ 4625 html: value, 4626 multilineTag, 4627 multilineWrapperTags: multilineTag === 'li' ? ['ul', 'ol'] : undefined, 4628 preserveWhiteSpace 4629 }); 4630 4631 if (disableFormats) { 4632 record.current.formats = Array(value.length); 4633 record.current.replacements = Array(value.length); 4634 } 4635 4636 record.current.formats = __unstableAfterParse(record.current); 4637 record.current.start = selectionStart; 4638 record.current.end = selectionEnd; 4639 } 4640 4641 const hadSelectionUpdate = Object(external_wp_element_["useRef"])(false); 4642 4643 if (!record.current) { 4644 setRecordFromProps(); 4645 } else if (selectionStart !== record.current.start || selectionEnd !== record.current.end) { 4646 hadSelectionUpdate.current = isSelected; 4647 record.current = { ...record.current, 4648 start: selectionStart, 4649 end: selectionEnd 4650 }; 4651 } 4652 /** 4653 * Sync the value to global state. The node tree and selection will also be 4654 * updated if differences are found. 4655 * 4656 * @param {Object} newRecord The record to sync and apply. 4657 */ 4658 4659 4660 function handleChange(newRecord) { 4661 applyRecord(newRecord); 4662 4663 if (disableFormats) { 4664 _value.current = newRecord.text; 4665 } else { 4666 _value.current = toHTMLString({ 4667 value: { ...newRecord, 4668 formats: __unstableBeforeSerialize(newRecord) 4669 }, 4670 multilineTag, 4671 preserveWhiteSpace 4672 }); 4673 } 4674 4675 record.current = newRecord; 4676 const { 4677 start, 4678 end, 4679 formats, 4680 text 4681 } = newRecord; // Selection must be updated first, so it is recorded in history when 4682 // the content change happens. 4683 4684 onSelectionChange(start, end); 4685 onChange(_value.current, { 4686 __unstableFormats: formats, 4687 __unstableText: text 4688 }); 4689 forceRender(); 4690 } 4691 4692 function applyFromProps() { 4693 setRecordFromProps(); 4694 applyRecord(record.current); 4695 } 4696 4697 const didMount = Object(external_wp_element_["useRef"])(false); // Value updates must happen synchonously to avoid overwriting newer values. 4698 4699 Object(external_wp_element_["useLayoutEffect"])(() => { 4700 if (didMount.current && value !== _value.current) { 4701 applyFromProps(); 4702 } 4703 }, [value]); // Value updates must happen synchonously to avoid overwriting newer values. 4704 4705 Object(external_wp_element_["useLayoutEffect"])(() => { 4706 if (!hadSelectionUpdate.current) { 4707 return; 4708 } 4709 4710 applyFromProps(); 4711 hadSelectionUpdate.current = false; 4712 }, [hadSelectionUpdate.current]); 4713 4714 function focus() { 4715 ref.current.focus(); 4716 applyRecord(record.current); 4717 } 4718 4719 const mergedRefs = Object(external_wp_compose_["useMergeRefs"])([ref, useDefaultStyle(), useBoundaryStyle({ 4720 record 4721 }), useInlineWarning(), useCopyHandler({ 4722 record, 4723 multilineTag, 4724 preserveWhiteSpace 4725 }), useSelectObject(), useFormatBoundaries({ 4726 record, 4727 applyRecord 4728 }), useDelete({ 4729 createRecord, 4730 handleChange, 4731 multilineTag 4732 }), useIndentListItemOnSpace({ 4733 multilineTag, 4734 createRecord, 4735 handleChange 4736 }), useInputAndSelection({ 4737 record, 4738 applyRecord, 4739 createRecord, 4740 handleChange, 4741 isSelected, 4742 onSelectionChange 4743 }), Object(external_wp_compose_["useRefEffect"])(() => { 4744 applyFromProps(); 4745 didMount.current = true; 4746 }, [placeholder, ...__unstableDependencies])]); 4747 return { 4748 value: record.current, 4749 onChange: handleChange, 4750 onFocus: focus, 4751 ref: mergedRefs 4752 }; 4753 } 4754 function __experimentalRichText() {} 4755 4756 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/format-edit.js 4757 4758 4759 /** 4760 * Internal dependencies 4761 */ 4762 4763 4764 function FormatEdit({ 4765 formatTypes, 4766 onChange, 4767 onFocus, 4768 value, 4769 forwardedRef 4770 }) { 4771 return formatTypes.map(settings => { 4772 const { 4773 name, 4774 edit: Edit 4775 } = settings; 4776 4777 if (!Edit) { 4778 return null; 4779 } 4780 4781 const activeFormat = getActiveFormat(value, name); 4782 const isActive = activeFormat !== undefined; 4783 const activeObject = getActiveObject(value); 4784 const isObjectActive = activeObject !== undefined && activeObject.type === name; 4785 return Object(external_wp_element_["createElement"])(Edit, { 4786 key: name, 4787 isActive: isActive, 4788 activeAttributes: isActive ? activeFormat.attributes || {} : {}, 4789 isObjectActive: isObjectActive, 4790 activeObjectAttributes: isObjectActive ? activeObject.attributes || {} : {}, 4791 value: value, 4792 onChange: onChange, 4793 onFocus: onFocus, 4794 contentRef: forwardedRef 4795 }); 4796 }); 4797 } 4798 4799 // CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/index.js 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 /***/ }) 4839 4840 /******/ });