vendor: 5,745 bytes, lines 1-185
1var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; 2 3function getDefaultExportFromCjs (x) { 4 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; 5} 6 7var prism = {exports: {}}; 8 9var hasRequiredPrism; 10 11function requirePrism () { 12 if (hasRequiredPrism) return prism.exports; 13 hasRequiredPrism = 1; 14 (function (module) { 15 /* ********************************************** 16 Begin prism-core.js 17 ********************************************** */ 18 19 /// <reference lib="WebWorker"/> 20 21 var _self = (typeof window !== 'undefined') 22 ? window // if in browser 23 : ( 24 (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) 25 ? self // if in worker 26 : {} // if in node js 27 ); 28 29 /** 30 * Prism: Lightweight, robust, elegant syntax highlighting 31 * 32 * @license MIT <https://opensource.org/licenses/MIT> 33 * @author Lea Verou <https://lea.verou.me> 34 * @namespace 35 * @public 36 */ 37 var Prism = (function (_self) { 38 39 // Private helper vars 40 var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; 41 var uniqueId = 0; 42 43 // The grammar object for plaintext 44 var plainTextGrammar = {}; 45 46 47 var _ = { 48 /** 49 * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the 50 * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load 51 * additional languages or plugins yourself. 52 * 53 * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. 54 * 55 * You obviously have to change this value before the automatic highlighting started. To do this, you can add an 56 * empty Prism object into the global scope before loading the Prism script like this: 57 * 58 * ```js 59 * window.Prism = window.Prism || {}; 60 * Prism.manual = true; 61 * // add a new <script> to load Prism's script 62 * ``` 63 * 64 * @default false 65 * @type {boolean} 66 * @memberof Prism 67 * @public 68 */ 69 manual: _self.Prism && _self.Prism.manual, 70 /** 71 * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses 72 * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your 73 * own worker, you don't want it to do this. 74 * 75 * By setting this value to `true`, Prism will not add its own listeners to the worker. 76 * 77 * You obviously have to change this value before Prism executes. To do this, you can add an 78 * empty Prism object into the global scope before loading the Prism script like this: 79 * 80 * ```js 81 * window.Prism = window.Prism || {}; 82 * Prism.disableWorkerMessageHandler = true; 83 * // Load Prism's script 84 * ``` 85 * 86 * @default false 87 * @type {boolean} 88 * @memberof Prism 89 * @public 90 */ 91 disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, 92 93 /** 94 * A namespace for utility methods. 95 * 96 * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may 97 * change or disappear at any time. 98 * 99 * @namespace 100 * @memberof Prism 101 */ 102 util: { 103 encode: function encode(tokens) { 104 if (tokens instanceof Token) { 105 return new Token(tokens.type, encode(tokens.content), tokens.alias); 106 } else if (Array.isArray(tokens)) { 107 return tokens.map(encode); 108 } else { 109 return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); 110 } 111 }, 112 113 /** 114 * Returns the name of the type of the given value. 115 * 116 * @param {any} o 117 * @returns {string} 118 * @example 119 * type(null) === 'Null' 120 * type(undefined) === 'Undefined' 121 * type(123) === 'Number' 122 * type('foo') === 'String' 123 * type(true) === 'Boolean' 124 * type([1, 2]) === 'Array' 125 * type({}) === 'Object' 126 * type(String) === 'Function' 127 * type(/abc+/) === 'RegExp' 128 */ 129 type: function (o) { 130 return Object.prototype.toString.call(o).slice(8, -1); 131 }, 132 133 /** 134 * Returns a unique number for the given object. Later calls will still return the same number. 135 * 136 * @param {Object} obj 137 * @returns {number} 138 */ 139 objId: function (obj) { 140 if (!obj['__id']) { 141 Object.defineProperty(obj, '__id', { value: ++uniqueId }); 142 } 143 return obj['__id']; 144 }, 145 146 /** 147 * Creates a deep clone of the given object. 148 * 149 * The main intended use of this function is to clone language definitions. 150 * 151 * @param {T} o 152 * @param {Record<number, any>} [visited] 153 * @returns {T} 154 * @template T 155 */ 156 clone: function deepClone(o, visited) { 157 visited = visited || {}; 158 159 var clone; var id; 160 switch (_.util.type(o)) { 161 case 'Object': 162 id = _.util.objId(o); 163 if (visited[id]) { 164 return visited[id]; 165 } 166 clone = /** @type {Record<string, any>} */ ({}); 167 visited[id] = clone; 168 169 for (var key in o) { 170 if (o.hasOwnProperty(key)) { 171 clone[key] = deepClone(o[key], visited); 172 } 173 } 174 175 return /** @type {any} */ (clone); 176 177 case 'Array': 178 id = _.util.objId(o); 179 if (visited[id]) { 180 return visited[id]; 181 } 182 clone = []; 183 visited[id] = clone; 184 185 (/** @type {Array} */(/** @type {any}
vendor: 4,983 bytes, lines 185-334
185 */(o))).forEach(function (v, i) { 186 clone[i] = deepClone(v, visited); 187 }); 188 189 return /** @type {any} */ (clone); 190 191 default: 192 return o; 193 } 194 }, 195 196 /** 197 * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class. 198 * 199 * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned. 200 * 201 * @param {Element} element 202 * @returns {string} 203 */ 204 getLanguage: function (element) { 205 while (element) { 206 var m = lang.exec(element.className); 207 if (m) { 208 return m[1].toLowerCase(); 209 } 210 element = element.parentElement; 211 } 212 return 'none'; 213 }, 214 215 /** 216 * Sets the Prism `language-xxxx` class of the given element. 217 * 218 * @param {Element} element 219 * @param {string} language 220 * @returns {void} 221 */ 222 setLanguage: function (element, language) { 223 // remove all `language-xxxx` classes 224 // (this might leave behind a leading space) 225 element.className = element.className.replace(RegExp(lang, 'gi'), ''); 226 227 // add the new `language-xxxx` class 228 // (using `classList` will automatically clean up spaces for us) 229 element.classList.add('language-' + language); 230 }, 231 232 /** 233 * Returns the script element that is currently executing. 234 * 235 * This does __not__ work for line script element. 236 * 237 * @returns {HTMLScriptElement | null} 238 */ 239 currentScript: function () { 240 if (typeof document === 'undefined') { 241 return null; 242 } 243 if (document.currentScript && document.currentScript.tagName === 'SCRIPT' && 1 < 2 /* hack to trip TS' flow analysis */) { 244 return /** @type {any} */ (document.currentScript); 245 } 246 247 // IE11 workaround 248 // we'll get the src of the current script by parsing IE11's error stack trace 249 // this will not work for inline scripts 250 251 try { 252 throw new Error(); 253 } catch (err) { 254 // Get file src url from stack. Specifically works with the format of stack traces in IE. 255 // A stack will look like this: 256 // 257 // Error 258 // at _.util.currentScript (http://localhost/components/prism-core.js:119:5) 259 // at Global code (http://localhost/components/prism-core.js:606:1) 260 261 var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1]; 262 if (src) { 263 var scripts = document.getElementsByTagName('script'); 264 for (var i in scripts) { 265 if (scripts[i].src == src) { 266 return scripts[i]; 267 } 268 } 269 } 270 return null; 271 } 272 }, 273 274 /** 275 * Returns whether a given class is active for `element`. 276 * 277 * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated 278 * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the 279 * given class is just the given class with a `no-` prefix. 280 * 281 * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is 282 * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its 283 * ancestors have the given class or the negated version of it, then the default activation will be returned. 284 * 285 * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated 286 * version of it, the class is considered active. 287 * 288 * @param {Element} element 289 * @param {string} className 290 * @param {boolean} [defaultActivation=false] 291 * @returns {boolean} 292 */ 293 isActive: function (element, className, defaultActivation) { 294 var no = 'no-' + className; 295 296 while (element) { 297 var classList = element.classList; 298 if (classList.contains(className)) { 299 return true; 300 } 301 if (classList.contains(no)) { 302 return false; 303 } 304 element = element.parentElement; 305 } 306 return !!defaultActivation; 307 } 308 }, 309 310 /** 311 * This namespace contains all currently loaded languages and the some helper functions to create and modify languages. 312 * 313 * @namespace 314 * @memberof Prism 315 * @public 316 */ 317 languages: { 318 /** 319 * The grammar for plain, unformatted text. 320 */ 321 plain: plainTextGrammar, 322 plaintext: plainTextGrammar, 323 text: plainTextGrammar, 324 txt: plainTextGrammar, 325 326 /** 327 * Creates a deep copy of the language with the given id and appends the given tokens. 328 * 329 * If a token in `redef` also appears in the copied language, then the existing token in the copied language 330 * will be overwritten at its original position. 331 * 332 * ## Best practices 333 * 334 * Since the position of overwriting tokens (token in `redef` that over
334write tokens in the copied language) 335 * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to 336 * understand the language definition because, normally, the order of tokens matters in Prism grammars. 337 * 338 * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. 339 * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. 340 * 341 * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. 342 * @param {Grammar} redef The new tokens to append. 343 * @returns {Grammar} The new language created. 344 * @public 345 * @example 346 * Prism.languages['css-with-colors'] = Prism.languages.extend('css', { 347 * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token 348 * // at its original position 349 * 'comment': { ... }, 350 * // CSS doesn't have a 'color' token, so this token will be appended 351 * 'color': /\b(?:red|green|blue)\b/ 352 * }); 353 */ 354 extend: function (id, redef) { 355 var lang = _.util.clone(_.languages[id]); 356 357 for (var key in redef) { 358 lang[key] = redef[key]; 359 } 360 361 return lang; 362 }, 363 364 /** 365 * Inserts tokens _before_ another token in a language definition or any other grammar. 366 * 367 * ## Usage 368 * 369 * This helper method makes it easy to modify existing languages. For example, the CSS language definition 370 * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded 371 * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the 372 * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do 373 * this: 374 * 375 * ```js 376 * Prism.languages.markup.style = { 377 * // token 378 * }; 379 * ``` 380 * 381 * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens 382 * before existing tokens. For the CSS example above, you would use it like this: 383 * 384 * ```js 385 * Prism.languages.insertBefore('markup', 'cdata', { 386 * 'style': { 387 * // token 388 * } 389 * }); 390 * ``` 391 * 392 * ## Special cases 393 * 394 * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar 395 * will be ignored. 396 * 397 * This behavior can be used to insert tokens after `before`: 398 * 399 * ```js 400 * Prism.languages.insertBefore('markup', 'comment', { 401 * 'comment': Prism.languages.markup.comment, 402 * // tokens after 'comment' 403 * }); 404 * ``` 405 * 406 * ## Limitations 407 * 408 * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object 409 * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave 410 * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily 411 * deleting properties which is necessary to insert at arbitrary positions. 412 * 413 * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object. 414 * Instead, it will create a new object and replace all references to the target object with the new one. This 415 * can be done without temporarily deleting properties, so the iteration order is well-defined. 416 * 417 * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if 418 * you hold the target object in a variable, then the value of the variable will not change. 419 * 420 * ```js 421 * var oldMarkup = Prism.languages.markup; 422 * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... }); 423 * 424 * assert(oldMarkup !== Prism.languages.markup); 425 * assert(newMarkup === Prism.languages.markup); 426 * ``` 427 * 428 * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the 429 * object to be modified. 430 * @param {string} before The key to insert before. 431 * @param {Grammar}
vendor: 7,557 bytes, lines 431-653
431 insert An object containing the key-value pairs to be inserted. 432 * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the 433 * object to be modified. 434 * 435 * Defaults to `Prism.languages`. 436 * @returns {Grammar} The new grammar object. 437 * @public 438 */ 439 insertBefore: function (inside, before, insert, root) { 440 root = root || /** @type {any} */ (_.languages); 441 var grammar = root[inside]; 442 /** @type {Grammar} */ 443 var ret = {}; 444 445 for (var token in grammar) { 446 if (grammar.hasOwnProperty(token)) { 447 448 if (token == before) { 449 for (var newToken in insert) { 450 if (insert.hasOwnProperty(newToken)) { 451 ret[newToken] = insert[newToken]; 452 } 453 } 454 } 455 456 // Do not insert token which also occur in insert. See #1525 457 if (!insert.hasOwnProperty(token)) { 458 ret[token] = grammar[token]; 459 } 460 } 461 } 462 463 var old = root[inside]; 464 root[inside] = ret; 465 466 // Update references in other language definitions 467 _.languages.DFS(_.languages, function (key, value) { 468 if (value === old && key != inside) { 469 this[key] = ret; 470 } 471 }); 472 473 return ret; 474 }, 475 476 // Traverse a language definition with Depth First Search 477 DFS: function DFS(o, callback, type, visited) { 478 visited = visited || {}; 479 480 var objId = _.util.objId; 481 482 for (var i in o) { 483 if (o.hasOwnProperty(i)) { 484 callback.call(o, i, o[i], type || i); 485 486 var property = o[i]; 487 var propertyType = _.util.type(property); 488 489 if (propertyType === 'Object' && !visited[objId(property)]) { 490 visited[objId(property)] = true; 491 DFS(property, callback, null, visited); 492 } else if (propertyType === 'Array' && !visited[objId(property)]) { 493 visited[objId(property)] = true; 494 DFS(property, callback, i, visited); 495 } 496 } 497 } 498 } 499 }, 500 501 plugins: {}, 502 503 /** 504 * This is the most high-level function in Prismâs API. 505 * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on 506 * each one of them. 507 * 508 * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`. 509 * 510 * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}. 511 * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}. 512 * @memberof Prism 513 * @public 514 */ 515 highlightAll: function (async, callback) { 516 _.highlightAllUnder(document, async, callback); 517 }, 518 519 /** 520 * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls 521 * {@link Prism.highlightElement} on each one of them. 522 * 523 * The following hooks will be run: 524 * 1. `before-highlightall` 525 * 2. `before-all-elements-highlight` 526 * 3. All hooks of {@link Prism.highlightElement} for each element. 527 * 528 * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted. 529 * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers. 530 * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done. 531 * @memberof Prism 532 * @public 533 */ 534 highlightAllUnder: function (container, async, callback) { 535 var env = { 536 callback: callback, 537 container: container, 538 selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' 539 }; 540 541 _.hooks.run('before-highlightall', env); 542 543 env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector)); 544 545 _.hooks.run('before-all-elements-highlight', env); 546 547 for (var i = 0, element; (element = env.elements[i++]);) { 548 _.highlightElement(element, async === true, env.callback); 549 } 550 }, 551 552 /** 553 * Highlights the code inside a single element. 554 * 555 * The following hooks will be run: 556 * 1. `before-sanity-check` 557 * 2. `before-highlight` 558 * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`. 559 * 4. `before-insert` 560 * 5. `after-highlight` 561 * 6. `complete` 562 * 563 * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for 564 * the element's language. 565 * 566 * @param {Element} element The element containing the code. 567 * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier. 568 * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers 569 * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is 570 * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default). 571 * 572 * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for 573 * asynchronous highlighting to work. You can build your own bundle on the 574 * [Download page](https://prismjs.com/download.html). 575 * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done. 576 * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously. 577 * @memberof Prism 578 * @public 579 */ 580 highlightElement: function (element, async, callback) { 581 // Find language 582 var language = _.util.getLanguage(element); 583 var grammar = _.languages[language]; 584 585 // Set language on the element, if not present 586 _.util.setLanguage(element, language); 587 588 // Set language on the parent, for styling 589 var parent = element.parentElement; 590 if (parent && parent.nodeName.toLowerCase() === 'pre') { 591 _.util.setLanguage(parent, language); 592 } 593 594 var code = element.textContent; 595 596 var env = { 597 element: element, 598 language: language, 599 grammar: grammar, 600 code: code 601 }; 602 603 function insertHighlightedCode(highlightedCode) { 604 env.highlightedCode = highlightedCode; 605 606 _.hooks.run('before-insert', env); 607 608 env.element.innerHTML = env.highlightedCode; 609 610 _.hooks.run('after-highlight', env); 611 _.hooks.run('complete', env); 612 callback && callback.call(env.element); 613 } 614 615 _.hooks.run('before-sanity-check', env); 616 617 // plugins may change/add the parent/element 618 parent = env.element.parentElement; 619 if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) { 620 parent.setAttribute('tabindex', '0'); 621 } 622 623 if (!env.code) { 624 _.hooks.run('complete', env); 625 callback && callback.call(env.element); 626 return; 627 } 628 629 _.hooks.run('before-highlight', env); 630 631 if (!env.grammar) { 632 insertHighlightedCode(_.util.encode(env.code)); 633 return; 634 } 635 636 if (async && _self.Worker) { 637 var worker = new Worker(_.filename); 638 639 worker.onmessage = function (evt) { 640 insertHighlightedCode(evt.data); 641 }; 642 643 worker.postMessage(JSON.stringify({ 644 language: env.language, 645 code: env.code, 646 immediateClose: true 647 })); 648 } else { 649 insertHighlightedCode(_.highlight(env.code, env.grammar, env.language)); 650 } 651 }, 652 653 /**
654 * Low-level function, only use if you know what youâre doing. It accepts a string of text as input 655 * and the language definitions to use, and returns a string with the HTML produced. 656 * 657 * The following hooks will be run: 658 * 1. `before-tokenize` 659 * 2. `after-tokenize` 660 * 3. `wrap`: On each {@link Token}. 661 * 662 * @param {string} text A string with the code to be highlighted. 663 * @param {Grammar} grammar An object containing the tokens to use. 664 * 665 * Usually a language definition like `Prism.languages.markup`. 666 * @param {string} language The name of the language definition passed to `grammar`. 667 * @returns {string} The highlighted HTML. 668 * @memberof Prism 669 * @public 670 * @example 671 * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript'); 672 */ 673 highlight: function (text, grammar, language) { 674 var env = { 675 code: text, 676 grammar: grammar, 677 language: language 678 }; 679 _.hooks.run('before-tokenize', env); 680 if (!env.grammar) { 681 throw new Error('The language "' + env.language + '" has no grammar.'); 682 } 683 env.tokens = _.tokenize(env.code, env.grammar); 684 _.hooks.run('after-tokenize', env); 685 return Token.stringify(_.util.encode(env.tokens), env.language); 686 }, 687 688 /** 689 * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input 690 * and the language definitions to use, and returns an array with the tokenized code. 691 * 692 * When the language definition includes nested tokens, the function is called recursively on each of these tokens. 693 * 694 * This method could be useful in other contexts as well, as a very crude parser. 695 * 696 * @param {string} text A string with the code to be highlighted. 697 * @param {Grammar} grammar An object containing the tokens to use. 698 * 699 * Usually a language definition like `Prism.languages.markup`. 700 * @returns {TokenStream} An array of strings and tokens, a token stream. 701 * @memberof Prism 702 * @public 703 * @example 704 * let code = `var foo = 0;`; 705 * let tokens = Prism.tokenize(code, Prism.languages.javascript); 706 * tokens.forEach(token => { 707 * if (token instanceof Prism.Token && token.type === 'number') { 708 * console.log(`Found numeric literal: ${token.content}`); 709 * } 710 * }); 711 */ 712 tokenize: function (text, grammar) { 713 var rest = grammar.rest; 714 if (rest) { 715 for (var token in rest) { 716 grammar[token] = rest[token]; 717 } 718 719 delete grammar.rest; 720 } 721 722 var tokenList = new LinkedList(); 723 addAfter(tokenList, tokenList.head, text); 724 725 matchGrammar(text, tokenList, grammar, tokenList.head, 0); 726 727 return toArray(tokenList); 728 }, 729 730 /** 731 * @namespace 732 * @memberof Prism 733 * @public 734 */ 735 hooks: { 736 all: {}, 737 738 /** 739 * Adds the given callback to the list of callbacks for the given hook. 740 * 741 * The callback will be invoked when the hook it is registered for is run. 742 * Hooks are usually directly run by a highlight function but you can also run hooks yourself. 743 * 744 * One callback function can be registered to multiple hooks and the same hook multiple times. 745 * 746 * @param {string} name The name of the hook. 747 * @param {HookCallback} callback The callback function which is given environment variables. 748 * @public 749 */ 750 add: function (name, callback) { 751 var hooks = _.hooks.all; 752 753 hooks[name] = hooks[name] || []; 754 755 hooks[name].push(callback); 756 }, 757 758 /** 759 * Runs a hook invoking all registered callbacks with the given environment variables. 760 * 761 * Callbacks will be invoked synchronously and in the order in which they were registered. 762 * 763 * @param {string} name The name of the hook. 764 * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered. 765 * @public 766 */ 767 run: function (name, env) { 768 var callbacks = _.hooks.all[name]; 769 770 if (!callbacks || !callbacks.length) { 771 return; 772 } 773 774 for (var i = 0, callback; (callback = callbacks[i++]);) { 775 callback(env); 776 } 777 } 778 }, 779 780 Token: Token 781 }; 782 _self.Prism = _; 783 784 785 // Typescript note: 786 // The following can be used to import the Token type in JSDoc: 787 // 788 // @typedef {InstanceType<import("./prism-core")["Token"]>} Token 789 790 /** 791 * Creates a new token. 792 * 793 * @param {string} type See {@link Token#type type} 794 * @param {string | TokenStream} content See {@link Token#content content} 795 * @param {string|string[]} [alias] The alias(es) of the token. 796 * @param {string} [matchedStr=""] A copy of the full string this token was created from. 797 * @class 798 * @global 799 * @public 800 */ 801 function Token(type, content, alias, matchedStr) { 802 /** 803 * The type of the token. 804 * 805 * This is usually the key of a pattern in a {@link Grammar}. 806 * 807 * @type {string} 808 * @see GrammarToken 809 * @public 810 */ 811 this.type = type; 812 /** 813 * The strings or tokens contained by this token. 814 * 815 * This will be a token stream if the pattern matched also defined an `inside` grammar. 816 * 817 * @type {string | TokenStream} 818 * @public 819 */ 820 this.content = content; 821 /** 822 * The alias(es) of the token. 823 * 824 * @type {string|string[]} 825 * @see GrammarToken 826 * @public 827 */ 828 this.alias = alias; 829 // Copy of the full string this token was created from 830 this.length = (matchedStr || '').length | 0; 831 } 832 833 /**
vendor: 4,762 bytes, lines 834-996
834 * A token stream is an array of strings and {@link Token Token} objects. 835 * 836 * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process 837 * them. 838 * 839 * 1. No adjacent strings. 840 * 2. No empty strings. 841 * 842 * The only exception here is the token stream that only contains the empty string and nothing else. 843 * 844 * @typedef {Array<string | Token>} TokenStream 845 * @global 846 * @public 847 */ 848 849 /** 850 * Converts the given token or token stream to an HTML representation. 851 * 852 * The following hooks will be run: 853 * 1. `wrap`: On each {@link Token}. 854 * 855 * @param {string | Token | TokenStream} o The token or token stream to be converted. 856 * @param {string} language The name of current language. 857 * @returns {string} The HTML representation of the token or token stream. 858 * @memberof Token 859 * @static 860 */ 861 Token.stringify = function stringify(o, language) { 862 if (typeof o == 'string') { 863 return o; 864 } 865 if (Array.isArray(o)) { 866 var s = ''; 867 o.forEach(function (e) { 868 s += stringify(e, language); 869 }); 870 return s; 871 } 872 873 var env = { 874 type: o.type, 875 content: stringify(o.content, language), 876 tag: 'span', 877 classes: ['token', o.type], 878 attributes: {}, 879 language: language 880 }; 881 882 var aliases = o.alias; 883 if (aliases) { 884 if (Array.isArray(aliases)) { 885 Array.prototype.push.apply(env.classes, aliases); 886 } else { 887 env.classes.push(aliases); 888 } 889 } 890 891 _.hooks.run('wrap', env); 892 893 var attributes = ''; 894 for (var name in env.attributes) { 895 attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; 896 } 897 898 return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>'; 899 }; 900 901 /** 902 * @param {RegExp} pattern 903 * @param {number} pos 904 * @param {string} text 905 * @param {boolean} lookbehind 906 * @returns {RegExpExecArray | null} 907 */ 908 function matchPattern(pattern, pos, text, lookbehind) { 909 pattern.lastIndex = pos; 910 var match = pattern.exec(text); 911 if (match && lookbehind && match[1]) { 912 // change the match to remove the text matched by the Prism lookbehind group 913 var lookbehindLength = match[1].length; 914 match.index += lookbehindLength; 915 match[0] = match[0].slice(lookbehindLength); 916 } 917 return match; 918 } 919 920 /** 921 * @param {string} text 922 * @param {LinkedList<string | Token>} tokenList 923 * @param {any} grammar 924 * @param {LinkedListNode<string | Token>} startNode 925 * @param {number} startPos 926 * @param {RematchOptions} [rematch] 927 * @returns {void} 928 * @private 929 * 930 * @typedef RematchOptions 931 * @property {string} cause 932 * @property {number} reach 933 */ 934 function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) { 935 for (var token in grammar) { 936 if (!grammar.hasOwnProperty(token) || !grammar[token]) { 937 continue; 938 } 939 940 var patterns = grammar[token]; 941 patterns = Array.isArray(patterns) ? patterns : [patterns]; 942 943 for (var j = 0; j < patterns.length; ++j) { 944 if (rematch && rematch.cause == token + ',' + j) { 945 return; 946 } 947 948 var patternObj = patterns[j]; 949 var inside = patternObj.inside; 950 var lookbehind = !!patternObj.lookbehind; 951 var greedy = !!patternObj.greedy; 952 var alias = patternObj.alias; 953 954 if (greedy && !patternObj.pattern.global) { 955 // Without the global flag, lastIndex won't work 956 var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; 957 patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g'); 958 } 959 960 /** @type {RegExp} */ 961 var pattern = patternObj.pattern || patternObj; 962 963 for ( // iterate the token list and keep track of the current token/string position 964 var currentNode = startNode.next, pos = startPos; 965 currentNode !== tokenList.tail; 966 pos += currentNode.value.length, currentNode = currentNode.next 967 ) { 968 969 if (rematch && pos >= rematch.reach) { 970 break; 971 } 972 973 var str = currentNode.value; 974 975 if (tokenList.length > text.length) { 976 // Something went terribly wrong, ABORT, ABORT! 977 return; 978 } 979 980 if (str instanceof Token) { 981 continue; 982 } 983 984 var removeCount = 1; // this is the to parameter of removeBetween 985 var match; 986 987 if (greedy) { 988 match = matchPattern(pattern, pos, text, lookbehind); 989 if (!match || match.index >= text.length) { 990 break; 991 } 992 993 var from = match.index; 994 var to = match.index + match[0].length; 995 var p = pos; 996
vendor: 6,526 bytes, lines 997-1236
997 // find the node that contains the match 998 p += currentNode.value.length; 999 while (from >= p) { 1000 currentNode = currentNode.next; 1001 p += currentNode.value.length; 1002 } 1003 // adjust pos (and p) 1004 p -= currentNode.value.length; 1005 pos = p; 1006 1007 // the current node is a Token, then the match starts inside another Token, which is invalid 1008 if (currentNode.value instanceof Token) { 1009 continue; 1010 } 1011 1012 // find the last node which is affected by this match 1013 for ( 1014 var k = currentNode; 1015 k !== tokenList.tail && (p < to || typeof k.value === 'string'); 1016 k = k.next 1017 ) { 1018 removeCount++; 1019 p += k.value.length; 1020 } 1021 removeCount--; 1022 1023 // replace with the new match 1024 str = text.slice(pos, p); 1025 match.index -= pos; 1026 } else { 1027 match = matchPattern(pattern, 0, str, lookbehind); 1028 if (!match) { 1029 continue; 1030 } 1031 } 1032 1033 // eslint-disable-next-line no-redeclare 1034 var from = match.index; 1035 var matchStr = match[0]; 1036 var before = str.slice(0, from); 1037 var after = str.slice(from + matchStr.length); 1038 1039 var reach = pos + str.length; 1040 if (rematch && reach > rematch.reach) { 1041 rematch.reach = reach; 1042 } 1043 1044 var removeFrom = currentNode.prev; 1045 1046 if (before) { 1047 removeFrom = addAfter(tokenList, removeFrom, before); 1048 pos += before.length; 1049 } 1050 1051 removeRange(tokenList, removeFrom, removeCount); 1052 1053 var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr); 1054 currentNode = addAfter(tokenList, removeFrom, wrapped); 1055 1056 if (after) { 1057 addAfter(tokenList, currentNode, after); 1058 } 1059 1060 if (removeCount > 1) { 1061 // at least one Token object was removed, so we have to do some rematching 1062 // this can only happen if the current pattern is greedy 1063 1064 /** @type {RematchOptions} */ 1065 var nestedRematch = { 1066 cause: token + ',' + j, 1067 reach: reach 1068 }; 1069 matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch); 1070 1071 // the reach might have been extended because of the rematching 1072 if (rematch && nestedRematch.reach > rematch.reach) { 1073 rematch.reach = nestedRematch.reach; 1074 } 1075 } 1076 } 1077 } 1078 } 1079 } 1080 1081 /** 1082 * @typedef LinkedListNode 1083 * @property {T} value 1084 * @property {LinkedListNode<T> | null} prev The previous node. 1085 * @property {LinkedListNode<T> | null} next The next node. 1086 * @template T 1087 * @private 1088 */ 1089 1090 /** 1091 * @template T 1092 * @private 1093 */ 1094 function LinkedList() { 1095 /** @type {LinkedListNode<T>} */ 1096 var head = { value: null, prev: null, next: null }; 1097 /** @type {LinkedListNode<T>} */ 1098 var tail = { value: null, prev: head, next: null }; 1099 head.next = tail; 1100 1101 /** @type {LinkedListNode<T>} */ 1102 this.head = head; 1103 /** @type {LinkedListNode<T>} */ 1104 this.tail = tail; 1105 this.length = 0; 1106 } 1107 1108 /** 1109 * Adds a new node with the given value to the list. 1110 * 1111 * @param {LinkedList<T>} list 1112 * @param {LinkedListNode<T>} node 1113 * @param {T} value 1114 * @returns {LinkedListNode<T>} The added node. 1115 * @template T 1116 */ 1117 function addAfter(list, node, value) { 1118 // assumes that node != list.tail && values.length >= 0 1119 var next = node.next; 1120 1121 var newNode = { value: value, prev: node, next: next }; 1122 node.next = newNode; 1123 next.prev = newNode; 1124 list.length++; 1125 1126 return newNode; 1127 } 1128 /** 1129 * Removes `count` nodes after the given node. The given node will not be removed. 1130 * 1131 * @param {LinkedList<T>} list 1132 * @param {LinkedListNode<T>} node 1133 * @param {number} count 1134 * @template T 1135 */ 1136 function removeRange(list, node, count) { 1137 var next = node.next; 1138 for (var i = 0; i < count && next !== list.tail; i++) { 1139 next = next.next; 1140 } 1141 node.next = next; 1142 next.prev = node; 1143 list.length -= i; 1144 } 1145 /** 1146 * @param {LinkedList<T>} list 1147 * @returns {T[]} 1148 * @template T 1149 */ 1150 function toArray(list) { 1151 var array = []; 1152 var node = list.head.next; 1153 while (node !== list.tail) { 1154 array.push(node.value); 1155 node = node.next; 1156 } 1157 return array; 1158 } 1159 1160 1161 if (!_self.document) { 1162 if (!_self.addEventListener) { 1163 // in Node.js 1164 return _; 1165 } 1166 1167 if (!_.disableWorkerMessageHandler) { 1168 // In worker 1169 _self.addEventListener('message', function (evt) { 1170 var message = JSON.parse(evt.data); 1171 var lang = message.language; 1172 var code = message.code; 1173 var immediateClose = message.immediateClose; 1174 1175 _self.postMessage(_.highlight(code, _.languages[lang], lang)); 1176 if (immediateClose) { 1177 _self.close(); 1178 } 1179 }, false); 1180 } 1181 1182 return _; 1183 } 1184 1185 // Get current script and highlight 1186 var script = _.util.currentScript(); 1187 1188 if (script) { 1189 _.filename = script.src; 1190 1191 if (script.hasAttribute('data-manual')) { 1192 _.manual = true; 1193 } 1194 } 1195 1196 function highlightAutomaticallyCallback() { 1197 if (!_.manual) { 1198 _.highlightAll(); 1199 } 1200 } 1201 1202 if (!_.manual) { 1203 // If the document state is "loading", then we'll use DOMContentLoaded. 1204 // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the 1205 // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they 1206 // might take longer one animation frame to execute which can create a race condition where only some plugins have 1207 // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. 1208 // See https://github.com/PrismJS/prism/issues/2102 1209 var readyState = document.readyState; 1210 if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { 1211 document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); 1212 } else { 1213 if (window.requestAnimationFrame) { 1214 window.requestAnimationFrame(highlightAutomaticallyCallback); 1215 } else { 1216 window.setTimeout(highlightAutomaticallyCallback, 16); 1217 } 1218 } 1219 } 1220 1221 return _; 1222 1223 }(_self)); 1224 1225 if (module.exports) { 1226 module.exports = Prism; 1227 } 1228 1229 // hack for components to work correctly in node.js 1230 if (typeof commonjsGlobal !== 'undefined') { 1231 commonjsGlobal.Prism = Prism; 1232 } 1233 1234 // some additional documentation/types 1235 1236 /**
1237 * The expansion of a simple `RegExp` literal to support additional properties. 1238 * 1239 * @typedef GrammarToken 1240 * @property {RegExp} pattern The regular expression of the token. 1241 * @property {boolean} [lookbehind=false] If `true`, then the first capturing group of `pattern` will (effectively) 1242 * behave as a lookbehind group meaning that the captured text will not be part of the matched text of the new token. 1243 * @property {boolean} [greedy=false] Whether the token is greedy. 1244 * @property {string|string[]} [alias] An optional alias or list of aliases. 1245 * @property {Grammar} [inside] The nested grammar of this token. 1246 * 1247 * The `inside` grammar will be used to tokenize the text value of each token of this kind. 1248 * 1249 * This can be used to make nested and even recursive language definitions. 1250 * 1251 * Note: This can cause infinite recursion. Be careful when you embed different languages or even the same language into 1252 * each another. 1253 * @global 1254 * @public 1255 */ 1256 1257 /** 1258 * @typedef Grammar 1259 * @type {Object<string, RegExp | GrammarToken | Array<RegExp | GrammarToken>>} 1260 * @property {Grammar} [rest] An optional grammar object that will be appended to this grammar. 1261 * @global 1262 * @public 1263 */ 1264 1265 /** 1266 * A function which will invoked after an element was successfully highlighted. 1267 * 1268 * @callback HighlightCallback 1269 * @param {Element} element The element successfully highlighted. 1270 * @returns {void} 1271 * @global 1272 * @public 1273 */ 1274 1275 /** 1276 * @callback HookCallback 1277 * @param {Object<string, any>} env The environment variables of the hook. 1278 * @returns {void} 1279 * @global 1280 * @public 1281 */ 1282 1283 1284 /* ********************************************** 1285 Begin prism-markup.js 1286 ********************************************** */ 1287 1288 Prism.languages.markup = { 1289 'comment': { 1290 pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, 1291 greedy: true 1292 }, 1293 'prolog': { 1294 pattern: /<\?[\s\S]+?\?>/, 1295 greedy: true 1296 }, 1297 'doctype': { 1298 // https://www.w3.org/TR/xml/#NT-doctypedecl 1299 pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i, 1300 greedy: true, 1301 inside: { 1302 'internal-subset': { 1303 pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, 1304 lookbehind: true, 1305 greedy: true, 1306 inside: null // see below 1307 }, 1308 'string': { 1309 pattern: /"[^"]*"|'[^']*'/, 1310 greedy: true 1311 }, 1312 'punctuation': /^<!|>$|[[\]]/, 1313 'doctype-tag': /^DOCTYPE/i, 1314 'name': /[^\s<>'"]+/ 1315 } 1316 }, 1317 'cdata': { 1318 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 1319 greedy: true 1320 }, 1321 'tag': { 1322 pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, 1323 greedy: true, 1324 inside: { 1325 'tag': { 1326 pattern: /^<\/?[^\s>\/]+/, 1327 inside: { 1328 'punctuation': /^<\/?/, 1329 'namespace': /^[^\s>\/:]+:/ 1330 } 1331 }, 1332 'special-attr': [], 1333 'attr-value': { 1334 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, 1335 inside: { 1336 'punctuation': [ 1337 { 1338 pattern: /^=/, 1339 alias: 'attr-equals' 1340 }, 1341 { 1342 pattern: /^(\s*)["']|["']$/, 1343 lookbehind: true 1344 } 1345 ] 1346 } 1347 }, 1348 'punctuation': /\/?>/, 1349 'attr-name': { 1350 pattern: /[^\s>\/]+/, 1351 inside: { 1352 'namespace': /^[^\s>\/:]+:/ 1353 } 1354 } 1355 1356 } 1357 }, 1358 'entity': [ 1359 { 1360 pattern: /&[\da-z]{1,8};/i, 1361 alias: 'named-entity' 1362 }, 1363 /&#x?[\da-f]{1,8};/i 1364 ] 1365 }; 1366 1367 Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] = 1368 Prism.languages.markup['entity']; 1369 Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup; 1370 1371 // Plugin to make entity title show the real entity, idea by Roman Komarov 1372 Prism.hooks.add('wrap', function (env) { 1373 1374 if (env.type === 'entity') { 1375 env.attributes['title'] = env.content.replace(/&/, '&'); 1376 } 1377 }); 1378 1379 Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { 1380 /** 1381 * Adds an inlined language to markup. 1382 * 1383 * An example of an inlined language is CSS with `<style>` tags. 1384 * 1385 * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as 1386 * case insensitive. 1387 * @param {string} lang The language key. 1388 * @example 1389 * addInlined('style', 'css'); 1390 */ 1391 value: function addInlined(tagName, lang) { 1392 var includedCdataInside = {};
vendor: 17,693 bytes, lines 1393-1949
1393 includedCdataInside['language-' + lang] = { 1394 pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i, 1395 lookbehind: true, 1396 inside: Prism.languages[lang] 1397 }; 1398 includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i; 1399 1400 var inside = { 1401 'included-cdata': { 1402 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 1403 inside: includedCdataInside 1404 } 1405 }; 1406 inside['language-' + lang] = { 1407 pattern: /[\s\S]+/, 1408 inside: Prism.languages[lang] 1409 }; 1410 1411 var def = {}; 1412 def[tagName] = { 1413 pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'), 1414 lookbehind: true, 1415 greedy: true, 1416 inside: inside 1417 }; 1418 1419 Prism.languages.insertBefore('markup', 'cdata', def); 1420 } 1421 }); 1422 Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', { 1423 /** 1424 * Adds an pattern to highlight languages embedded in HTML attributes. 1425 * 1426 * An example of an inlined language is CSS with `style` attributes. 1427 * 1428 * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as 1429 * case insensitive. 1430 * @param {string} lang The language key. 1431 * @example 1432 * addAttribute('style', 'css'); 1433 */ 1434 value: function (attrName, lang) { 1435 Prism.languages.markup.tag.inside['special-attr'].push({ 1436 pattern: RegExp( 1437 /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, 1438 'i' 1439 ), 1440 lookbehind: true, 1441 inside: { 1442 'attr-name': /^[^\s=]+/, 1443 'attr-value': { 1444 pattern: /=[\s\S]+/, 1445 inside: { 1446 'value': { 1447 pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, 1448 lookbehind: true, 1449 alias: [lang, 'language-' + lang], 1450 inside: Prism.languages[lang] 1451 }, 1452 'punctuation': [ 1453 { 1454 pattern: /^=/, 1455 alias: 'attr-equals' 1456 }, 1457 /"|'/ 1458 ] 1459 } 1460 } 1461 } 1462 }); 1463 } 1464 }); 1465 1466 Prism.languages.html = Prism.languages.markup; 1467 Prism.languages.mathml = Prism.languages.markup; 1468 Prism.languages.svg = Prism.languages.markup; 1469 1470 Prism.languages.xml = Prism.languages.extend('markup', {}); 1471 Prism.languages.ssml = Prism.languages.xml; 1472 Prism.languages.atom = Prism.languages.xml; 1473 Prism.languages.rss = Prism.languages.xml; 1474 1475 1476 /* ********************************************** 1477 Begin prism-css.js 1478 ********************************************** */ 1479 1480 (function (Prism) { 1481 1482 var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; 1483 1484 Prism.languages.css = { 1485 'comment': /\/\*[\s\S]*?\*\//, 1486 'atrule': { 1487 pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source), 1488 inside: { 1489 'rule': /^@[\w-]+/, 1490 'selector-function-argument': { 1491 pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, 1492 lookbehind: true, 1493 alias: 'selector' 1494 }, 1495 'keyword': { 1496 pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, 1497 lookbehind: true 1498 } 1499 // See rest below 1500 } 1501 }, 1502 'url': { 1503 // https://drafts.csswg.org/css-values-3/#urls 1504 pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'), 1505 greedy: true, 1506 inside: { 1507 'function': /^url/i, 1508 'punctuation': /^\(|\)$/, 1509 'string': { 1510 pattern: RegExp('^' + string.source + '$'), 1511 alias: 'url' 1512 } 1513 } 1514 }, 1515 'selector': { 1516 pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'), 1517 lookbehind: true 1518 }, 1519 'string': { 1520 pattern: string, 1521 greedy: true 1522 }, 1523 'property': { 1524 pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, 1525 lookbehind: true 1526 }, 1527 'important': /!important\b/i, 1528 'function': { 1529 pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, 1530 lookbehind: true 1531 }, 1532 'punctuation': /[(){};:,]/ 1533 }; 1534 1535 Prism.languages.css['atrule'].inside.rest = Prism.languages.css; 1536 1537 var markup = Prism.languages.markup; 1538 if (markup) { 1539 markup.tag.addInlined('style', 'css'); 1540 markup.tag.addAttribute('style', 'css'); 1541 } 1542 1543 }(Prism)); 1544 1545 1546 /* ********************************************** 1547 Begin prism-clike.js 1548 ********************************************** */ 1549 1550 Prism.languages.clike = { 1551 'comment': [ 1552 { 1553 pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, 1554 lookbehind: true, 1555 greedy: true 1556 }, 1557 { 1558 pattern: /(^|[^\\:])\/\/.*/, 1559 lookbehind: true, 1560 greedy: true 1561 } 1562 ], 1563 'string': { 1564 pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, 1565 greedy: true 1566 }, 1567 'class-name': { 1568 pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, 1569 lookbehind: true, 1570 inside: { 1571 'punctuation': /[.\\]/ 1572 } 1573 }, 1574 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, 1575 'boolean': /\b(?:false|true)\b/, 1576 'function': /\b\w+(?=\()/, 1577 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, 1578 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, 1579 'punctuation': /[{}[\];(),.:]/ 1580 }; 1581 1582 1583 /* ********************************************** 1584 Begin prism-javascript.js 1585 ********************************************** */ 1586 1587 Prism.languages.javascript = Prism.languages.extend('clike', { 1588 'class-name': [ 1589 Prism.languages.clike['class-name'], 1590 { 1591 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, 1592 lookbehind: true 1593 } 1594 ], 1595 'keyword': [ 1596 { 1597 pattern: /((?:^|\})\s*)catch\b/, 1598 lookbehind: true 1599 }, 1600 { 1601 pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, 1602 lookbehind: true 1603 }, 1604 ], 1605 // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) 1606 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, 1607 'number': { 1608 pattern: RegExp( 1609 /(^|[^\w$])/.source + 1610 '(?:' + 1611 ( 1612 // constant 1613 /NaN|Infinity/.source + 1614 '|' + 1615 // binary integer 1616 /0[bB][01]+(?:_[01]+)*n?/.source + 1617 '|' + 1618 // octal integer 1619 /0[oO][0-7]+(?:_[0-7]+)*n?/.source + 1620 '|' + 1621 // hexadecimal integer 1622 /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + 1623 '|' + 1624 // decimal bigint 1625 /\d+(?:_\d+)*n/.source + 1626 '|' + 1627 // decimal number (integer or float) but no bigint 1628 /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source 1629 ) + 1630 ')' + 1631 /(?![\w$])/.source 1632 ), 1633 lookbehind: true 1634 }, 1635 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/ 1636 }); 1637 1638 Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; 1639 1640 Prism.languages.insertBefore('javascript', 'keyword', { 1641 'regex': { 1642 pattern: RegExp( 1643 // lookbehind 1644 // eslint-disable-next-line regexp/no-dupe-characters-character-class 1645 /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + 1646 // Regex pattern: 1647 // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character 1648 // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible 1649 // with the only syntax, so we have to define 2 different regex patterns. 1650 /\//.source + 1651 '(?:' + 1652 /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source + 1653 '|' + 1654 // `v` flag syntax. This supports 3 levels of nested character classes. 1655 /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source + 1656 ')' + 1657 // lookahead 1658 /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source 1659 ), 1660 lookbehind: true, 1661 greedy: true, 1662 inside: { 1663 'regex-source': { 1664 pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, 1665 lookbehind: true, 1666 alias: 'language-regex', 1667 inside: Prism.languages.regex 1668 }, 1669 'regex-delimiter': /^\/|\/$/, 1670 'regex-flags': /^[a-z]+$/, 1671 } 1672 }, 1673 // This must be declared before keyword because we use "function" inside the look-forward 1674 'function-variable': { 1675 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, 1676 alias: 'function' 1677 }, 1678 'parameter': [ 1679 { 1680 pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, 1681 lookbehind: true, 1682 inside: Prism.languages.javascript 1683 }, 1684 { 1685 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, 1686 lookbehind: true, 1687 inside: Prism.languages.javascript 1688 }, 1689 { 1690 pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, 1691 lookbehind: true, 1692 inside: Prism.languages.javascript 1693 }, 1694 { 1695 pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, 1696 lookbehind: true, 1697 inside: Prism.languages.javascript 1698 } 1699 ], 1700 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/ 1701 }); 1702 1703 Prism.languages.insertBefore('javascript', 'string', { 1704 'hashbang': { 1705 pattern: /^#!.*/, 1706 greedy: true, 1707 alias: 'comment' 1708 }, 1709 'template-string': { 1710 pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, 1711 greedy: true, 1712 inside: { 1713 'template-punctuation': { 1714 pattern: /^`|`$/, 1715 alias: 'string' 1716 }, 1717 'interpolation': { 1718 pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, 1719 lookbehind: true, 1720 inside: { 1721 'interpolation-punctuation': { 1722 pattern: /^\$\{|\}$/, 1723 alias: 'punctuation' 1724 }, 1725 rest: Prism.languages.javascript 1726 } 1727 }, 1728 'string': /[\s\S]+/ 1729 } 1730 }, 1731 'string-property': { 1732 pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, 1733 lookbehind: true, 1734 greedy: true, 1735 alias: 'property' 1736 } 1737 }); 1738 1739 Prism.languages.insertBefore('javascript', 'operator', { 1740 'literal-property': { 1741 pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, 1742 lookbehind: true, 1743 alias: 'property' 1744 }, 1745 }); 1746 1747 if (Prism.languages.markup) { 1748 Prism.languages.markup.tag.addInlined('script', 'javascript'); 1749 1750 // add attribute support for all DOM events. 1751 // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events 1752 Prism.languages.markup.tag.addAttribute( 1753 /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source, 1754 'javascript' 1755 ); 1756 } 1757 1758 Prism.languages.js = Prism.languages.javascript; 1759 1760 1761 /* ********************************************** 1762 Begin prism-file-highlight.js 1763 ********************************************** */ 1764 1765 (function () { 1766 1767 if (typeof Prism === 'undefined' || typeof document === 'undefined') { 1768 return; 1769 } 1770 1771 // https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill 1772 if (!Element.prototype.matches) { 1773 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 1774 } 1775 1776 var LOADING_MESSAGE = 'Loadingâ¦'; 1777 var FAILURE_MESSAGE = function (status, message) { 1778 return 'â Error ' + status + ' while fetching file: ' + message; 1779 }; 1780 var FAILURE_EMPTY_MESSAGE = 'â Error: File does not exist or is empty'; 1781 1782 var EXTENSIONS = { 1783 'js': 'javascript', 1784 'py': 'python', 1785 'rb': 'ruby', 1786 'ps1': 'powershell', 1787 'psm1': 'powershell', 1788 'sh': 'bash', 1789 'bat': 'batch', 1790 'h': 'c', 1791 'tex': 'latex' 1792 }; 1793 1794 var STATUS_ATTR = 'data-src-status'; 1795 var STATUS_LOADING = 'loading'; 1796 var STATUS_LOADED = 'loaded'; 1797 var STATUS_FAILED = 'failed'; 1798 1799 var SELECTOR = 'pre[data-src]:not([' + STATUS_ATTR + '="' + STATUS_LOADED + '"])' 1800 + ':not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])'; 1801 1802 /** 1803 * Loads the given file. 1804 * 1805 * @param {string} src The URL or path of the source file to load. 1806 * @param {(result: string) => void} success 1807 * @param {(reason: string) => void} error 1808 */ 1809 function loadFile(src, success, error) { 1810 var xhr = new XMLHttpRequest(); 1811 xhr.open('GET', src, true); 1812 xhr.onreadystatechange = function () { 1813 if (xhr.readyState == 4) { 1814 if (xhr.status < 400 && xhr.responseText) { 1815 success(xhr.responseText); 1816 } else { 1817 if (xhr.status >= 400) { 1818 error(FAILURE_MESSAGE(xhr.status, xhr.statusText)); 1819 } else { 1820 error(FAILURE_EMPTY_MESSAGE); 1821 } 1822 } 1823 } 1824 }; 1825 xhr.send(null); 1826 } 1827 1828 /** 1829 * Parses the given range. 1830 * 1831 * This returns a range with inclusive ends. 1832 * 1833 * @param {string | null | undefined} range 1834 * @returns {[number, number | undefined] | undefined} 1835 */ 1836 function parseRange(range) { 1837 var m = /^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(range || ''); 1838 if (m) { 1839 var start = Number(m[1]); 1840 var comma = m[2]; 1841 var end = m[3]; 1842 1843 if (!comma) { 1844 return [start, start]; 1845 } 1846 if (!end) { 1847 return [start, undefined]; 1848 } 1849 return [start, Number(end)]; 1850 } 1851 return undefined; 1852 } 1853 1854 Prism.hooks.add('before-highlightall', function (env) { 1855 env.selector += ', ' + SELECTOR; 1856 }); 1857 1858 Prism.hooks.add('before-sanity-check', function (env) { 1859 var pre = /** @type {HTMLPreElement} */ (env.element); 1860 if (pre.matches(SELECTOR)) { 1861 env.code = ''; // fast-path the whole thing and go to complete 1862 1863 pre.setAttribute(STATUS_ATTR, STATUS_LOADING); // mark as loading 1864 1865 // add code element with loading message 1866 var code = pre.appendChild(document.createElement('CODE')); 1867 code.textContent = LOADING_MESSAGE; 1868 1869 var src = pre.getAttribute('data-src'); 1870 1871 var language = env.language; 1872 if (language === 'none') { 1873 // the language might be 'none' because there is no language set; 1874 // in this case, we want to use the extension as the language 1875 var extension = (/\.(\w+)$/.exec(src) || [, 'none'])[1]; 1876 language = EXTENSIONS[extension] || extension; 1877 } 1878 1879 // set language classes 1880 Prism.util.setLanguage(code, language); 1881 Prism.util.setLanguage(pre, language); 1882 1883 // preload the language 1884 var autoloader = Prism.plugins.autoloader; 1885 if (autoloader) { 1886 autoloader.loadLanguages(language); 1887 } 1888 1889 // load file 1890 loadFile( 1891 src, 1892 function (text) { 1893 // mark as loaded 1894 pre.setAttribute(STATUS_ATTR, STATUS_LOADED); 1895 1896 // handle data-range 1897 var range = parseRange(pre.getAttribute('data-range')); 1898 if (range) { 1899 var lines = text.split(/\r\n?|\n/g); 1900 1901 // the range is one-based and inclusive on both ends 1902 var start = range[0]; 1903 var end = range[1] == null ? lines.length : range[1]; 1904 1905 if (start < 0) { start += lines.length; } 1906 start = Math.max(0, Math.min(start - 1, lines.length)); 1907 if (end < 0) { end += lines.length; } 1908 end = Math.max(0, Math.min(end, lines.length)); 1909 1910 text = lines.slice(start, end).join('\n'); 1911 1912 // add data-start for line numbers 1913 if (!pre.hasAttribute('data-start')) { 1914 pre.setAttribute('data-start', String(start + 1)); 1915 } 1916 } 1917 1918 // highlight code 1919 code.textContent = text; 1920 Prism.highlightElement(code); 1921 }, 1922 function (error) { 1923 // mark as failed 1924 pre.setAttribute(STATUS_ATTR, STATUS_FAILED); 1925 1926 code.textContent = error; 1927 } 1928 ); 1929 } 1930 }); 1931 1932 Prism.plugins.fileHighlight = { 1933 /** 1934 * Executes the File Highlight plugin for all matching `pre` elements under the given container. 1935 * 1936 * Note: Elements which are already loaded or currently loading will not be touched by this method. 1937 * 1938 * @param {ParentNode} [container=document] 1939 */ 1940 highlight: function highlight(container) { 1941 var elements = (container || document).querySelectorAll(SELECTOR); 1942 1943 for (var i = 0, element; (element = elements[i++]);) { 1944 Prism.highlightElement(element); 1945 } 1946 } 1947 }; 1948 1949 var logged = false;
vendor: 4,244 bytes, lines 1950-2104
1950 /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */ 1951 Prism.fileHighlight = function () { 1952 if (!logged) { 1953 console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); 1954 logged = true; 1955 } 1956 Prism.plugins.fileHighlight.highlight.apply(this, arguments); 1957 }; 1958 1959 }()); 1960 } (prism)); 1961 return prism.exports; 1962} 1963 1964var prismExports = requirePrism(); 1965var Prism$1 = /*@__PURE__*/getDefaultExportFromCjs(prismExports); 1966 1967Prism$1.languages.clike = { 1968 'comment': [ 1969 { 1970 pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, 1971 lookbehind: true, 1972 greedy: true 1973 }, 1974 { 1975 pattern: /(^|[^\\:])\/\/.*/, 1976 lookbehind: true, 1977 greedy: true 1978 } 1979 ], 1980 'string': { 1981 pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, 1982 greedy: true 1983 }, 1984 'class-name': { 1985 pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, 1986 lookbehind: true, 1987 inside: { 1988 'punctuation': /[.\\]/ 1989 } 1990 }, 1991 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, 1992 'boolean': /\b(?:false|true)\b/, 1993 'function': /\b\w+(?=\()/, 1994 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, 1995 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, 1996 'punctuation': /[{}[\];(),.:]/ 1997}; 1998 1999(function (Prism) { 2000 2001 Prism.languages.diff = { 2002 'coord': [ 2003 // Match all kinds of coord lines (prefixed by "+++", "---" or "***"). 2004 /^(?:\*{3}|-{3}|\+{3}).*$/m, 2005 // Match "@@ ... @@" coord lines in unified diff. 2006 /^@@.*@@$/m, 2007 // Match coord lines in normal diff (starts with a number). 2008 /^\d.*$/m 2009 ] 2010 2011 // deleted, inserted, unchanged, diff 2012 }; 2013 2014 /** 2015 * A map from the name of a block to its line prefix. 2016 * 2017 * @type {Object<string, string>} 2018 */ 2019 var PREFIXES = { 2020 'deleted-sign': '-', 2021 'deleted-arrow': '<', 2022 'inserted-sign': '+', 2023 'inserted-arrow': '>', 2024 'unchanged': ' ', 2025 'diff': '!', 2026 }; 2027 2028 // add a token for each prefix 2029 Object.keys(PREFIXES).forEach(function (name) { 2030 var prefix = PREFIXES[name]; 2031 2032 var alias = []; 2033 if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted" 2034 alias.push(/\w+/.exec(name)[0]); 2035 } 2036 if (name === 'diff') { 2037 alias.push('bold'); 2038 } 2039 2040 Prism.languages.diff[name] = { 2041 pattern: RegExp('^(?:[' + prefix + '].*(?:\r\n?|\n|(?![\\s\\S])))+', 'm'), 2042 alias: alias, 2043 inside: { 2044 'line': { 2045 pattern: /(.)(?=[\s\S]).*(?:\r\n?|\n)?/, 2046 lookbehind: true 2047 }, 2048 'prefix': { 2049 pattern: /[\s\S]/, 2050 alias: /\w+/.exec(name)[0] 2051 } 2052 } 2053 }; 2054 2055 }); 2056 2057 // make prefixes available to Diff plugin 2058 Object.defineProperty(Prism.languages.diff, 'PREFIXES', { 2059 value: PREFIXES 2060 }); 2061 2062}(Prism$1)); 2063 2064Prism$1.languages.javascript = Prism$1.languages.extend('clike', { 2065 'class-name': [ 2066 Prism$1.languages.clike['class-name'], 2067 { 2068 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, 2069 lookbehind: true 2070 } 2071 ], 2072 'keyword': [ 2073 { 2074 pattern: /((?:^|\})\s*)catch\b/, 2075 lookbehind: true 2076 }, 2077 { 2078 pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, 2079 lookbehind: true 2080 }, 2081 ], 2082 // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) 2083 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, 2084 'number': { 2085 pattern: RegExp( 2086 /(^|[^\w$])/.source + 2087 '(?:' + 2088 ( 2089 // constant 2090 /NaN|Infinity/.source + 2091 '|' + 2092 // binary integer 2093 /0[bB][01]+(?:_[01]+)*n?/.source + 2094 '|' + 2095 // octal integer 2096 /0[oO][0-7]+(?:_[0-7]+)*n?/.source + 2097 '|' + 2098 // hexadecimal integer 2099 /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + 2100 '|' + 2101 // decimal bigint 2102 /\d+(?:_\d+)*n/.source + 2103 '|' + 2104 // decimal number (integer or float) but no bigint
vendor: 4,609 bytes, lines 2105-2230
2105 /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source 2106 ) + 2107 ')' + 2108 /(?![\w$])/.source 2109 ), 2110 lookbehind: true 2111 }, 2112 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/ 2113}); 2114 2115Prism$1.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; 2116 2117Prism$1.languages.insertBefore('javascript', 'keyword', { 2118 'regex': { 2119 pattern: RegExp( 2120 // lookbehind 2121 // eslint-disable-next-line regexp/no-dupe-characters-character-class 2122 /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + 2123 // Regex pattern: 2124 // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character 2125 // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible 2126 // with the only syntax, so we have to define 2 different regex patterns. 2127 /\//.source + 2128 '(?:' + 2129 /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source + 2130 '|' + 2131 // `v` flag syntax. This supports 3 levels of nested character classes. 2132 /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source + 2133 ')' + 2134 // lookahead 2135 /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source 2136 ), 2137 lookbehind: true, 2138 greedy: true, 2139 inside: { 2140 'regex-source': { 2141 pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, 2142 lookbehind: true, 2143 alias: 'language-regex', 2144 inside: Prism$1.languages.regex 2145 }, 2146 'regex-delimiter': /^\/|\/$/, 2147 'regex-flags': /^[a-z]+$/, 2148 } 2149 }, 2150 // This must be declared before keyword because we use "function" inside the look-forward 2151 'function-variable': { 2152 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, 2153 alias: 'function' 2154 }, 2155 'parameter': [ 2156 { 2157 pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, 2158 lookbehind: true, 2159 inside: Prism$1.languages.javascript 2160 }, 2161 { 2162 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, 2163 lookbehind: true, 2164 inside: Prism$1.languages.javascript 2165 }, 2166 { 2167 pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, 2168 lookbehind: true, 2169 inside: Prism$1.languages.javascript 2170 }, 2171 { 2172 pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, 2173 lookbehind: true, 2174 inside: Prism$1.languages.javascript 2175 } 2176 ], 2177 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/ 2178}); 2179 2180Prism$1.languages.insertBefore('javascript', 'string', { 2181 'hashbang': { 2182 pattern: /^#!.*/, 2183 greedy: true, 2184 alias: 'comment' 2185 }, 2186 'template-string': { 2187 pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, 2188 greedy: true, 2189 inside: { 2190 'template-punctuation': { 2191 pattern: /^`|`$/, 2192 alias: 'string' 2193 }, 2194 'interpolation': { 2195 pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, 2196 lookbehind: true, 2197 inside: { 2198 'interpolation-punctuation': { 2199 pattern: /^\$\{|\}$/, 2200 alias: 'punctuation' 2201 }, 2202 rest: Prism$1.languages.javascript 2203 } 2204 }, 2205 'string': /[\s\S]+/ 2206 } 2207 }, 2208 'string-property': { 2209 pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, 2210 lookbehind: true, 2211 greedy: true, 2212 alias: 'property' 2213 } 2214}); 2215 2216Prism$1.languages.insertBefore('javascript', 'operator', { 2217 'literal-property': { 2218 pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, 2219 lookbehind: true, 2220 alias: 'property' 2221 }, 2222}); 2223 2224if (Prism$1.languages.markup) { 2225 Prism$1.languages.markup.tag.addInlined('script', 'javascript'); 2226 2227 // add attribute support for all DOM events. 2228 // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events 2229 Prism$1.languages.markup.tag.addAttribute( 2230 /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?
vendor: 4,158 bytes, lines 2230-2386
2230:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source, 2231 'javascript' 2232 ); 2233} 2234 2235Prism$1.languages.js = Prism$1.languages.javascript; 2236 2237Prism$1.languages.markup = { 2238 'comment': { 2239 pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, 2240 greedy: true 2241 }, 2242 'prolog': { 2243 pattern: /<\?[\s\S]+?\?>/, 2244 greedy: true 2245 }, 2246 'doctype': { 2247 // https://www.w3.org/TR/xml/#NT-doctypedecl 2248 pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i, 2249 greedy: true, 2250 inside: { 2251 'internal-subset': { 2252 pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, 2253 lookbehind: true, 2254 greedy: true, 2255 inside: null // see below 2256 }, 2257 'string': { 2258 pattern: /"[^"]*"|'[^']*'/, 2259 greedy: true 2260 }, 2261 'punctuation': /^<!|>$|[[\]]/, 2262 'doctype-tag': /^DOCTYPE/i, 2263 'name': /[^\s<>'"]+/ 2264 } 2265 }, 2266 'cdata': { 2267 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 2268 greedy: true 2269 }, 2270 'tag': { 2271 pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, 2272 greedy: true, 2273 inside: { 2274 'tag': { 2275 pattern: /^<\/?[^\s>\/]+/, 2276 inside: { 2277 'punctuation': /^<\/?/, 2278 'namespace': /^[^\s>\/:]+:/ 2279 } 2280 }, 2281 'special-attr': [], 2282 'attr-value': { 2283 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, 2284 inside: { 2285 'punctuation': [ 2286 { 2287 pattern: /^=/, 2288 alias: 'attr-equals' 2289 }, 2290 { 2291 pattern: /^(\s*)["']|["']$/, 2292 lookbehind: true 2293 } 2294 ] 2295 } 2296 }, 2297 'punctuation': /\/?>/, 2298 'attr-name': { 2299 pattern: /[^\s>\/]+/, 2300 inside: { 2301 'namespace': /^[^\s>\/:]+:/ 2302 } 2303 } 2304 2305 } 2306 }, 2307 'entity': [ 2308 { 2309 pattern: /&[\da-z]{1,8};/i, 2310 alias: 'named-entity' 2311 }, 2312 /&#x?[\da-f]{1,8};/i 2313 ] 2314}; 2315 2316Prism$1.languages.markup['tag'].inside['attr-value'].inside['entity'] = 2317 Prism$1.languages.markup['entity']; 2318Prism$1.languages.markup['doctype'].inside['internal-subset'].inside = Prism$1.languages.markup; 2319 2320// Plugin to make entity title show the real entity, idea by Roman Komarov 2321Prism$1.hooks.add('wrap', function (env) { 2322 2323 if (env.type === 'entity') { 2324 env.attributes['title'] = env.content.replace(/&/, '&'); 2325 } 2326}); 2327 2328Object.defineProperty(Prism$1.languages.markup.tag, 'addInlined', { 2329 /** 2330 * Adds an inlined language to markup. 2331 * 2332 * An example of an inlined language is CSS with `<style>` tags. 2333 * 2334 * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as 2335 * case insensitive. 2336 * @param {string} lang The language key. 2337 * @example 2338 * addInlined('style', 'css'); 2339 */ 2340 value: function addInlined(tagName, lang) { 2341 var includedCdataInside = {}; 2342 includedCdataInside['language-' + lang] = { 2343 pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i, 2344 lookbehind: true, 2345 inside: Prism$1.languages[lang] 2346 }; 2347 includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i; 2348 2349 var inside = { 2350 'included-cdata': { 2351 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 2352 inside: includedCdataInside 2353 } 2354 }; 2355 inside['language-' + lang] = { 2356 pattern: /[\s\S]+/, 2357 inside: Prism$1.languages[lang] 2358 }; 2359 2360 var def = {}; 2361 def[tagName] = { 2362 pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'), 2363 lookbehind: true, 2364 greedy: true, 2365 inside: inside 2366 }; 2367 2368 Prism$1.languages.insertBefore('markup', 'cdata', def); 2369 } 2370}); 2371Object.defineProperty(Prism$1.languages.markup.tag, 'addAttribute', { 2372 /** 2373 * Adds an pattern to highlight languages embedded in HTML attributes. 2374 * 2375 * An example of an inlined language is CSS with `style` attributes. 2376 * 2377 * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as 2378 * case insensitive. 2379 * @param {string} lang The language key. 2380 * @example 2381 * addAttribute('style', 'css'); 2382 */ 2383 value: function (attrName, lang) { 2384 Prism$1.languages.markup.tag.inside['special-attr'].push({ 2385 pattern: RegExp( 2386 /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\
vendor: 13,576 bytes, lines 2386-2894
2386s'">=]+(?=[\s>]))/.source, 2387 'i' 2388 ), 2389 lookbehind: true, 2390 inside: { 2391 'attr-name': /^[^\s=]+/, 2392 'attr-value': { 2393 pattern: /=[\s\S]+/, 2394 inside: { 2395 'value': { 2396 pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, 2397 lookbehind: true, 2398 alias: [lang, 'language-' + lang], 2399 inside: Prism$1.languages[lang] 2400 }, 2401 'punctuation': [ 2402 { 2403 pattern: /^=/, 2404 alias: 'attr-equals' 2405 }, 2406 /"|'/ 2407 ] 2408 } 2409 } 2410 } 2411 }); 2412 } 2413}); 2414 2415Prism$1.languages.html = Prism$1.languages.markup; 2416Prism$1.languages.mathml = Prism$1.languages.markup; 2417Prism$1.languages.svg = Prism$1.languages.markup; 2418 2419Prism$1.languages.xml = Prism$1.languages.extend('markup', {}); 2420Prism$1.languages.ssml = Prism$1.languages.xml; 2421Prism$1.languages.atom = Prism$1.languages.xml; 2422Prism$1.languages.rss = Prism$1.languages.xml; 2423 2424(function (Prism) { 2425 2426 // Allow only one line break 2427 var inner = /(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source; 2428 2429 /** 2430 * This function is intended for the creation of the bold or italic pattern. 2431 * 2432 * This also adds a lookbehind group to the given pattern to ensure that the pattern is not backslash-escaped. 2433 * 2434 * _Note:_ Keep in mind that this adds a capturing group. 2435 * 2436 * @param {string} pattern 2437 * @returns {RegExp} 2438 */ 2439 function createInline(pattern) { 2440 pattern = pattern.replace(/<inner>/g, function () { return inner; }); 2441 return RegExp(/((?:^|[^\\])(?:\\{2})*)/.source + '(?:' + pattern + ')'); 2442 } 2443 2444 2445 var tableCell = /(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source; 2446 var tableRow = /\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g, function () { return tableCell; }); 2447 var tableLine = /\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source; 2448 2449 2450 Prism.languages.markdown = Prism.languages.extend('markup', {}); 2451 Prism.languages.insertBefore('markdown', 'prolog', { 2452 'front-matter-block': { 2453 pattern: /(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/, 2454 lookbehind: true, 2455 greedy: true, 2456 inside: { 2457 'punctuation': /^---|---$/, 2458 'front-matter': { 2459 pattern: /\S+(?:\s+\S+)*/, 2460 alias: ['yaml', 'language-yaml'], 2461 inside: Prism.languages.yaml 2462 } 2463 } 2464 }, 2465 'blockquote': { 2466 // > ... 2467 pattern: /^>(?:[\t ]*>)*/m, 2468 alias: 'punctuation' 2469 }, 2470 'table': { 2471 pattern: RegExp('^' + tableRow + tableLine + '(?:' + tableRow + ')*', 'm'), 2472 inside: { 2473 'table-data-rows': { 2474 pattern: RegExp('^(' + tableRow + tableLine + ')(?:' + tableRow + ')*$'), 2475 lookbehind: true, 2476 inside: { 2477 'table-data': { 2478 pattern: RegExp(tableCell), 2479 inside: Prism.languages.markdown 2480 }, 2481 'punctuation': /\|/ 2482 } 2483 }, 2484 'table-line': { 2485 pattern: RegExp('^(' + tableRow + ')' + tableLine + '$'), 2486 lookbehind: true, 2487 inside: { 2488 'punctuation': /\||:?-{3,}:?/ 2489 } 2490 }, 2491 'table-header-row': { 2492 pattern: RegExp('^' + tableRow + '$'), 2493 inside: { 2494 'table-header': { 2495 pattern: RegExp(tableCell), 2496 alias: 'important', 2497 inside: Prism.languages.markdown 2498 }, 2499 'punctuation': /\|/ 2500 } 2501 } 2502 } 2503 }, 2504 'code': [ 2505 { 2506 // Prefixed by 4 spaces or 1 tab and preceded by an empty line 2507 pattern: /((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/, 2508 lookbehind: true, 2509 alias: 'keyword' 2510 }, 2511 { 2512 // ```optional language 2513 // code block 2514 // ``` 2515 pattern: /^```[\s\S]*?^```$/m, 2516 greedy: true, 2517 inside: { 2518 'code-block': { 2519 pattern: /^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m, 2520 lookbehind: true 2521 }, 2522 'code-language': { 2523 pattern: /^(```).+/, 2524 lookbehind: true 2525 }, 2526 'punctuation': /```/ 2527 } 2528 } 2529 ], 2530 'title': [ 2531 { 2532 // title 1 2533 // ======= 2534 2535 // title 2 2536 // ------- 2537 pattern: /\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m, 2538 alias: 'important', 2539 inside: { 2540 punctuation: /==+$|--+$/ 2541 } 2542 }, 2543 { 2544 // # title 1 2545 // ###### title 6 2546 pattern: /(^\s*)#.+/m, 2547 lookbehind: true, 2548 alias: 'important', 2549 inside: { 2550 punctuation: /^#+|#+$/ 2551 } 2552 } 2553 ], 2554 'hr': { 2555 // *** 2556 // --- 2557 // * * * 2558 // ----------- 2559 pattern: /(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m, 2560 lookbehind: true, 2561 alias: 'punctuation' 2562 }, 2563 'list': { 2564 // * item 2565 // + item 2566 // - item 2567 // 1. item 2568 pattern: /(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m, 2569 lookbehind: true, 2570 alias: 'punctuation' 2571 }, 2572 'url-reference': { 2573 // [id]: http://example.com "Optional title" 2574 // [id]: http://example.com 'Optional title' 2575 // [id]: http://example.com (Optional title) 2576 // [id]: <http://example.com> "Optional title" 2577 pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/, 2578 inside: { 2579 'variable': { 2580 pattern: /^(!?\[)[^\]]+/, 2581 lookbehind: true 2582 }, 2583 'string': /(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/, 2584 'punctuation': /^[\[\]!:]|[<>]/ 2585 }, 2586 alias: 'url' 2587 }, 2588 'bold': { 2589 // **strong** 2590 // __strong__ 2591 2592 // allow one nested instance of italic text using the same delimiter 2593 pattern: createInline(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source), 2594 lookbehind: true, 2595 greedy: true, 2596 inside: { 2597 'content': { 2598 pattern: /(^..)[\s\S]+(?=..$)/, 2599 lookbehind: true, 2600 inside: {} // see below 2601 }, 2602 'punctuation': /\*\*|__/ 2603 } 2604 }, 2605 'italic': { 2606 // *em* 2607 // _em_ 2608 2609 // allow one nested instance of bold text using the same delimiter 2610 pattern: createInline(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source), 2611 lookbehind: true, 2612 greedy: true, 2613 inside: { 2614 'content': { 2615 pattern: /(^.)[\s\S]+(?=.$)/, 2616 lookbehind: true, 2617 inside: {} // see below 2618 }, 2619 'punctuation': /[*_]/ 2620 } 2621 }, 2622 'strike': { 2623 // ~~strike through~~ 2624 // ~strike~ 2625 // eslint-disable-next-line regexp/strict 2626 pattern: createInline(/(~~?)(?:(?!~)<inner>)+\2/.source), 2627 lookbehind: true, 2628 greedy: true, 2629 inside: { 2630 'content': { 2631 pattern: /(^~~?)[\s\S]+(?=\1$)/, 2632 lookbehind: true, 2633 inside: {} // see below 2634 }, 2635 'punctuation': /~~?/ 2636 } 2637 }, 2638 'code-snippet': { 2639 // `code` 2640 // ``code`` 2641 pattern: /(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/, 2642 lookbehind: true, 2643 greedy: true, 2644 alias: ['code', 'keyword'] 2645 }, 2646 'url': { 2647 // [example](http://example.com "Optional title") 2648 // [example][id] 2649 // [example] [id] 2650 pattern: createInline(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source), 2651 lookbehind: true, 2652 greedy: true, 2653 inside: { 2654 'operator': /^!/, 2655 'content': { 2656 pattern: /(^\[)[^\]]+(?=\])/, 2657 lookbehind: true, 2658 inside: {} // see below 2659 }, 2660 'variable': { 2661 pattern: /(^\][ \t]?\[)[^\]]+(?=\]$)/, 2662 lookbehind: true 2663 }, 2664 'url': { 2665 pattern: /(^\]\()[^\s)]+/, 2666 lookbehind: true 2667 }, 2668 'string': { 2669 pattern: /(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/, 2670 lookbehind: true 2671 } 2672 } 2673 } 2674 }); 2675 2676 ['url', 'bold', 'italic', 'strike'].forEach(function (token) { 2677 ['url', 'bold', 'italic', 'strike', 'code-snippet'].forEach(function (inside) { 2678 if (token !== inside) { 2679 Prism.languages.markdown[token].inside.content.inside[inside] = Prism.languages.markdown[inside]; 2680 } 2681 }); 2682 }); 2683 2684 Prism.hooks.add('after-tokenize', function (env) { 2685 if (env.language !== 'markdown' && env.language !== 'md') { 2686 return; 2687 } 2688 2689 function walkTokens(tokens) { 2690 if (!tokens || typeof tokens === 'string') { 2691 return; 2692 } 2693 2694 for (var i = 0, l = tokens.length; i < l; i++) { 2695 var token = tokens[i]; 2696 2697 if (token.type !== 'code') { 2698 walkTokens(token.content); 2699 continue; 2700 } 2701 2702 /* 2703 * Add the correct `language-xxxx` class to this code block. Keep in mind that the `code-language` token 2704 * is optional. But the grammar is defined so that there is only one case we have to handle: 2705 * 2706 * token.content = [ 2707 * <span class="punctuation">```</span>, 2708 * <span class="code-language">xxxx</span>, 2709 * '\n', // exactly one new lines (\r or \n or \r\n) 2710 * <span class="code-block">...</span>, 2711 * '\n', // exactly one new lines again 2712 * <span class="punctuation">```</span> 2713 * ]; 2714 */ 2715 2716 var codeLang = token.content[1]; 2717 var codeBlock = token.content[3]; 2718 2719 if (codeLang && codeBlock && 2720 codeLang.type === 'code-language' && codeBlock.type === 'code-block' && 2721 typeof codeLang.content === 'string') { 2722 2723 // this might be a language that Prism does not support 2724 2725 // do some replacements to support C++, C#, and F# 2726 var lang = codeLang.content.replace(/\b#/g, 'sharp').replace(/\b\+\+/g, 'pp'); 2727 // only use the first word 2728 lang = (/[a-z][\w-]*/i.exec(lang) || [''])[0].toLowerCase(); 2729 var alias = 'language-' + lang; 2730 2731 // add alias 2732 if (!codeBlock.alias) { 2733 codeBlock.alias = [alias]; 2734 } else if (typeof codeBlock.alias === 'string') { 2735 codeBlock.alias = [codeBlock.alias, alias]; 2736 } else { 2737 codeBlock.alias.push(alias); 2738 } 2739 } 2740 } 2741 } 2742 2743 walkTokens(env.tokens); 2744 }); 2745 2746 Prism.hooks.add('wrap', function (env) { 2747 if (env.type !== 'code-block') { 2748 return; 2749 } 2750 2751 var codeLang = ''; 2752 for (var i = 0, l = env.classes.length; i < l; i++) { 2753 var cls = env.classes[i]; 2754 var match = /language-(.+)/.exec(cls); 2755 if (match) { 2756 codeLang = match[1]; 2757 break; 2758 } 2759 } 2760 2761 var grammar = Prism.languages[codeLang]; 2762 2763 if (!grammar) { 2764 if (codeLang && codeLang !== 'none' && Prism.plugins.autoloader) { 2765 var id = 'md-' + new Date().valueOf() + '-' + Math.floor(Math.random() * 1e16); 2766 env.attributes['id'] = id; 2767 2768 Prism.plugins.autoloader.loadLanguages(codeLang, function () { 2769 var ele = document.getElementById(id); 2770 if (ele) { 2771 ele.innerHTML = Prism.highlight(ele.textContent, Prism.languages[codeLang], codeLang); 2772 } 2773 }); 2774 } 2775 } else { 2776 env.content = Prism.highlight(textContent(env.content), grammar, codeLang); 2777 } 2778 }); 2779 2780 var tagPattern = RegExp(Prism.languages.markup.tag.pattern.source, 'gi'); 2781 2782 /** 2783 * A list of known entity names. 2784 * 2785 * This will always be incomplete to save space. The current list is the one used by lowdash's unescape function. 2786 * 2787 * @see {@link https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/unescape.js#L2} 2788 */ 2789 var KNOWN_ENTITY_NAMES = { 2790 'amp': '&', 2791 'lt': '<', 2792 'gt': '>', 2793 'quot': '"', 2794 }; 2795 2796 // IE 11 doesn't support `String.fromCodePoint` 2797 var fromCodePoint = String.fromCodePoint || String.fromCharCode; 2798 2799 /** 2800 * Returns the text content of a given HTML source code string. 2801 * 2802 * @param {string} html 2803 * @returns {string} 2804 */ 2805 function textContent(html) { 2806 // remove all tags 2807 var text = html.replace(tagPattern, ''); 2808 2809 // decode known entities 2810 text = text.replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi, function (m, code) { 2811 code = code.toLowerCase(); 2812 2813 if (code[0] === '#') { 2814 var value; 2815 if (code[1] === 'x') { 2816 value = parseInt(code.slice(2), 16); 2817 } else { 2818 value = Number(code.slice(1)); 2819 } 2820 2821 return fromCodePoint(value); 2822 } else { 2823 var known = KNOWN_ENTITY_NAMES[code]; 2824 if (known) { 2825 return known; 2826 } 2827 2828 // unable to decode 2829 return m; 2830 } 2831 }); 2832 2833 return text; 2834 } 2835 2836 Prism.languages.md = Prism.languages.markdown; 2837 2838}(Prism$1)); 2839 2840Prism$1.languages.c = Prism$1.languages.extend('clike', { 2841 'comment': { 2842 pattern: /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/, 2843 greedy: true 2844 }, 2845 'string': { 2846 // https://en.cppreference.com/w/c/language/string_literal 2847 pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, 2848 greedy: true 2849 }, 2850 'class-name': { 2851 pattern: /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/, 2852 lookbehind: true 2853 }, 2854 'keyword': /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/, 2855 'function': /\b[a-z_]\w*(?=\s*\()/i, 2856 'number': /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i, 2857 'operator': />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/ 2858}); 2859 2860Prism$1.languages.insertBefore('c', 'string', { 2861 'char': { 2862 // https://en.cppreference.com/w/c/language/character_constant 2863 pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/, 2864 greedy: true 2865 } 2866}); 2867 2868Prism$1.languages.insertBefore('c', 'string', { 2869 'macro': { 2870 // allow for multiline macro definitions 2871 // spaces after the # character compile fine with gcc 2872 pattern: /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im, 2873 lookbehind: true, 2874 greedy: true, 2875 alias: 'property', 2876 inside: { 2877 'string': [ 2878 { 2879 // highlight the path of the include statement as a string 2880 pattern: /^(#\s*include\s*)<[^>]+>/, 2881 lookbehind: true 2882 }, 2883 Prism$1.languages.c['string'] 2884 ], 2885 'char': Prism$1.languages.c['char'], 2886 'comment': Prism$1.languages.c['comment'], 2887 'macro-name': [ 2888 { 2889 pattern: /(^#\s*define\s+)\w+\b(?!\()/i, 2890 lookbehind: true 2891 }, 2892 { 2893 pattern: /(^#\s*define\s+)\w+\b(?=\()/i, 2894 lookbehind: true,
2895 alias: 'function' 2896 } 2897 ], 2898 // highlight macro directives as keywords 2899 'directive': { 2900 pattern: /^(#\s*)[a-z]+/, 2901 lookbehind: true, 2902 alias: 'keyword' 2903 }, 2904 'directive-hash': /^#/, 2905 'punctuation': /##|\\(?=[\r\n])/, 2906 'expression': { 2907 pattern: /\S[\s\S]*/, 2908 inside: Prism$1.languages.c 2909 } 2910 } 2911 } 2912}); 2913 2914Prism$1.languages.insertBefore('c', 'function', { 2915 // highlight predefined macros as constants 2916 'constant': /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/ 2917}); 2918 2919delete Prism$1.languages.c['boolean']; 2920 2921(function (Prism) { 2922 2923 var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; 2924 2925 Prism.languages.css = { 2926 'comment': /\/\*[\s\S]*?\*\//, 2927 'atrule': { 2928 pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source), 2929 inside: { 2930 'rule': /^@[\w-]+/, 2931 'selector-function-argument': { 2932 pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, 2933 lookbehind: true, 2934 alias: 'selector' 2935 }, 2936 'keyword': { 2937 pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, 2938 lookbehind: true 2939 } 2940 // See rest below 2941 } 2942 }, 2943 'url': { 2944 // https://drafts.csswg.org/css-values-3/#urls 2945 pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'), 2946 greedy: true, 2947 inside: { 2948 'function': /^url/i, 2949 'punctuation': /^\(|\)$/, 2950 'string': { 2951 pattern: RegExp('^' + string.source + '$'), 2952 alias: 'url' 2953 } 2954 } 2955 }, 2956 'selector': { 2957 pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'), 2958 lookbehind: true 2959 }, 2960 'string': { 2961 pattern: string, 2962 greedy: true 2963 }, 2964 'property': { 2965 pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, 2966 lookbehind: true 2967 }, 2968 'important': /!important\b/i, 2969 'function': { 2970 pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, 2971 lookbehind: true 2972 }, 2973 'punctuation': /[(){};:,]/ 2974 }; 2975 2976 Prism.languages.css['atrule'].inside.rest = Prism.languages.css; 2977 2978 var markup = Prism.languages.markup; 2979 if (markup) { 2980 markup.tag.addInlined('style', 'css'); 2981 markup.tag.addAttribute('style', 'css'); 2982 } 2983 2984}(Prism$1)); 2985 2986Prism$1.languages.objectivec = Prism$1.languages.extend('c', { 2987 'string': { 2988 pattern: /@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, 2989 greedy: true 2990 }, 2991 'keyword': /\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/, 2992 'operator': /-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/ 2993}); 2994 2995delete Prism$1.languages.objectivec['class-name']; 2996 2997Prism$1.languages.objc = Prism$1.languages.objectivec; 2998 2999Prism$1.languages.sql = { 3000 'comment': { 3001 pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/, 3002 lookbehind: true 3003 }, 3004 'variable': [ 3005 { 3006 pattern: /@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/, 3007 greedy: true 3008 }, 3009 /@[\w.$]+/ 3010 ], 3011 'string': { 3012 pattern: /(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/, 3013 greedy: true, 3014 lookbehind: true 3015 }, 3016 'identifier': { 3017 pattern: /(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/, 3018 greedy: true, 3019 lookbehind: true, 3020 inside: { 3021 'punctuation': /^`|`$/ 3022 } 3023 }, 3024 'function': /\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i, // Should we highlight user defined functions too? 3025 'keyword': /\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECI
3025MAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i, 3026 'boolean': /\b(?:FALSE|NULL|TRUE)\b/i, 3027 'number': /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i, 3028 'operator': /[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i, 3029 'punctuation': /[;[\]()`,.]/ 3030}; 3031 3032(function (Prism) { 3033 3034 var powershell = Prism.languages.powershell = { 3035 'comment': [ 3036 { 3037 pattern: /(^|[^`])<#[\s\S]*?#>/, 3038 lookbehind: true 3039 }, 3040 { 3041 pattern: /(^|[^`])#.*/, 3042 lookbehind: true 3043 } 3044 ], 3045 'string': [ 3046 { 3047 pattern: /"(?:`[\s\S]|[^`"])*"/, 3048 greedy: true, 3049 inside: null // see below 3050 }, 3051 { 3052 pattern: /'(?:[^']|'')*'/, 3053 greedy: true 3054 } 3055 ], 3056 // Matches name spaces as well as casts, attribute decorators. Force starting with letter to avoid matching array indices 3057 // Supports two levels of nested brackets (e.g. `[OutputType([System.Collections.Generic.List[int]])]`) 3058 'namespace': /\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i, 3059 'boolean': /\$(?:false|true)\b/i, 3060 'variable': /\$\w+\b/, 3061 // Cmdlets and aliases. Aliases should come last, otherwise "write" gets preferred over "write-host" for example 3062 // Get-Command | ?{ $_.ModuleName -match "Microsoft.PowerShell.(Util|Core|Management)" } 3063 // Get-Alias | ?{ $_.ReferencedCommand.Module.Name -match "Microsoft.PowerShell.(Util|Core|Management)" } 3064 'function': [ 3065 /\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,
3066 /\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i 3067 ], 3068 // per http://technet.microsoft.com/en-us/library/hh847744.aspx 3069 'keyword': /\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i, 3070 'operator': { 3071 pattern: /(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i, 3072 lookbehind: true 3073 }, 3074 'punctuation': /[|{}[\];(),.]/ 3075 }; 3076 3077 // Variable interpolation inside strings, and nested expressions 3078 powershell.string[0].inside = { 3079 'function': { 3080 // Allow for one level of nesting 3081 pattern: /(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/, 3082 lookbehind: true, 3083 inside: powershell 3084 }, 3085 'boolean': powershell.boolean, 3086 'variable': powershell.variable, 3087 }; 3088 3089}(Prism$1)); 3090 3091var prismPython = {}; 3092 3093var hasRequiredPrismPython; 3094 3095function requirePrismPython () { 3096 if (hasRequiredPrismPython) return prismPython; 3097 hasRequiredPrismPython = 1; 3098 Prism$1.languages.python = { 3099 'comment': { 3100 pattern: /(^|[^\\])#.*/, 3101 lookbehind: true, 3102 greedy: true 3103 }, 3104 'string-interpolation': { 3105 pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i, 3106 greedy: true, 3107 inside: { 3108 'interpolation': { 3109 // "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}" 3110 pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/, 3111 lookbehind: true, 3112 inside: { 3113 'format-spec': { 3114 pattern: /(:)[^:(){}]+(?=\}$)/, 3115 lookbehind: true 3116 }, 3117 'conversion-option': { 3118 pattern: //, 3119 alias: 'punctuation' 3120 }, 3121 rest: null 3122 } 3123 }, 3124 'string': /[\s\S]+/ 3125 } 3126 }, 3127 'triple-quoted-string': { 3128 pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i, 3129 greedy: true, 3130 alias: 'string' 3131 }, 3132 'string': { 3133 pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i, 3134 greedy: true 3135 }, 3136 'function': { 3137 pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g, 3138 lookbehind: true 3139 }, 3140 'class-name': { 3141 pattern: /(\bclass\s+)\w+/i, 3142 lookbehind: true 3143 }, 3144 'decorator': { 3145 pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m, 3146 lookbehind: true, 3147 alias: ['annotation', 'punctuation'], 3148 inside: { 3149 'punctuation': /\./ 3150 } 3151 }, 3152 'keyword': /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/, 3153 'builtin': /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/, 3154 'boolean': /\b(?:False|None|True)\b/, 3155 'number': /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i, 3156 'operator': /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/, 3157 'punctuation': /[{}[\];(),.:]/ 3158 }; 3159 3160 Prism$1.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism$1.languages.python; 3161 3162 Prism$1.languages.py = Prism$1.languages.python; 3163 return prismPython; 3164} 3165 3166requirePrismPython(); 3167 3168var prismRust = {}; 3169 3170var hasRequiredPrismRust; 3171 3172function requirePrismRust () { 3173 if (hasRequiredPrismRust) return prismRust; 3174 hasRequiredPrismRust = 1; 3175 (function (Prism) { 3176 3177 var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source; 3178 for (var i = 0; i < 2; i++) { 3179 // support 4 levels of nested comments 3180 multilineComment = multilineComment.replace(/<self>/g, function () { return multilineComment; }); 3181 } 3182 multilineComment = multilineComment.replace(/<self>/g, function () { return /[^\s\S]/.source; }); 3183 3184 3185 Prism.languages.rust = { 3186 'comment': [ 3187 { 3188 pattern: RegExp(/(^|[^\\])/.source + multilineComment), 3189 lookbehind: true, 3190 greedy: true 3191 }, 3192 { 3193 pattern: /(^|[^\\:])\/\/.*/, 3194 lookbehind: true, 3195 greedy: true 3196 } 3197 ], 3198 'string': {
3199 pattern: /b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/, 3200 greedy: true 3201 }, 3202 'char': { 3203 pattern: /b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/, 3204 greedy: true 3205 }, 3206 'attribute': { 3207 pattern: /#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/, 3208 greedy: true, 3209 alias: 'attr-name', 3210 inside: { 3211 'string': null // see below 3212 } 3213 }, 3214 3215 // Closure params should not be confused with bitwise OR | 3216 'closure-params': { 3217 pattern: /([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/, 3218 lookbehind: true, 3219 greedy: true, 3220 inside: { 3221 'closure-punctuation': { 3222 pattern: /^\||\|$/, 3223 alias: 'punctuation' 3224 }, 3225 rest: null // see below 3226 } 3227 }, 3228 3229 'lifetime-annotation': { 3230 pattern: /'\w+/, 3231 alias: 'symbol' 3232 }, 3233 3234 'fragment-specifier': { 3235 pattern: /(\$\w+:)[a-z]+/, 3236 lookbehind: true, 3237 alias: 'punctuation' 3238 }, 3239 'variable': /\$\w+/, 3240 3241 'function-definition': { 3242 pattern: /(\bfn\s+)\w+/, 3243 lookbehind: true, 3244 alias: 'function' 3245 }, 3246 'type-definition': { 3247 pattern: /(\b(?:enum|struct|trait|type|union)\s+)\w+/, 3248 lookbehind: true, 3249 alias: 'class-name' 3250 }, 3251 'module-declaration': [ 3252 { 3253 pattern: /(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/, 3254 lookbehind: true, 3255 alias: 'namespace' 3256 }, 3257 { 3258 pattern: /(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/, 3259 lookbehind: true, 3260 alias: 'namespace', 3261 inside: { 3262 'punctuation': /::/ 3263 } 3264 } 3265 ], 3266 'keyword': [ 3267 // https://github.com/rust-lang/reference/blob/master/src/keywords.md 3268 /\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/, 3269 // primitives and str 3270 // https://doc.rust-lang.org/stable/rust-by-example/primitives.html 3271 /\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/ 3272 ], 3273 3274 // functions can technically start with an upper-case letter, but this will introduce a lot of false positives 3275 // and Rust's naming conventions recommend snake_case anyway. 3276 // https://doc.rust-lang.org/1.0.0/style/style/naming/README.html 3277 'function': /\b[a-z_]\w*(?=\s*(?:::\s*<|\())/, 3278 'macro': { 3279 pattern: /\b\w+!/, 3280 alias: 'property' 3281 }, 3282 'constant': /\b[A-Z_][A-Z_\d]+\b/, 3283 'class-name': /\b[A-Z]\w*\b/, 3284 3285 'namespace': { 3286 pattern: /(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/, 3287 inside: { 3288 'punctuation': /::/ 3289 } 3290 }, 3291 3292 // Hex, oct, bin, dec numbers with visual separators and type suffix 3293 'number': /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/, 3294 'boolean': /\b(?:false|true)\b/, 3295 'punctuation': /->|\.\.=|\.{1,3}|::|[{}[\];(),:]/, 3296 'operator': /[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/ 3297 }; 3298 3299 Prism.languages.rust['closure-params'].inside.rest = Prism.languages.rust; 3300 Prism.languages.rust['attribute'].inside['string'] = Prism.languages.rust['string']; 3301 3302 }(Prism$1)); 3303 return prismRust; 3304} 3305 3306requirePrismRust(); 3307 3308Prism$1.languages.swift = { 3309 'comment': { 3310 // Nested comments are supported up to 2 levels 3311 pattern: /(^|[^\\:])(?:\/\/.*|\/\*(?:[^/*]|\/(?!\*)|\*(?!\/)|\/\*(?:[^*]|\*(?!\/))*\*\/)*\*\/)/, 3312 lookbehind: true, 3313 greedy: true 3314 }, 3315 'string-literal': [ 3316 // https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html 3317 { 3318 pattern: RegExp( 3319 /(^|[^"#])/.source 3320 + '(?:' 3321 // single-line string
3322 + /"(?:\\(?:\((?:[^()]|\([^()]*\))*\)|\r\n|[^(])|[^\\\r\n"])*"/.source 3323 + '|' 3324 // multi-line string 3325 + /"""(?:\\(?:\((?:[^()]|\([^()]*\))*\)|[^(])|[^\\"]|"(?!""))*"""/.source 3326 + ')' 3327 + /(?!["#])/.source 3328 ), 3329 lookbehind: true, 3330 greedy: true, 3331 inside: { 3332 'interpolation': { 3333 pattern: /(\\\()(?:[^()]|\([^()]*\))*(?=\))/, 3334 lookbehind: true, 3335 inside: null // see below 3336 }, 3337 'interpolation-punctuation': { 3338 pattern: /^\)|\\\($/, 3339 alias: 'punctuation' 3340 }, 3341 'punctuation': /\\(?=[\r\n])/, 3342 'string': /[\s\S]+/ 3343 } 3344 }, 3345 { 3346 pattern: RegExp( 3347 /(^|[^"#])(#+)/.source 3348 + '(?:' 3349 // single-line string 3350 + /"(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|\r\n|[^#])|[^\\\r\n])*?"/.source 3351 + '|' 3352 // multi-line string 3353 + /"""(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|[^#])|[^\\])*?"""/.source 3354 + ')' 3355 + '\\2' 3356 ), 3357 lookbehind: true, 3358 greedy: true, 3359 inside: { 3360 'interpolation': { 3361 pattern: /(\\#+\()(?:[^()]|\([^()]*\))*(?=\))/, 3362 lookbehind: true, 3363 inside: null // see below 3364 }, 3365 'interpolation-punctuation': { 3366 pattern: /^\)|\\#+\($/, 3367 alias: 'punctuation' 3368 }, 3369 'string': /[\s\S]+/ 3370 } 3371 }, 3372 ], 3373 3374 'directive': { 3375 // directives with conditions 3376 pattern: RegExp( 3377 /#/.source 3378 + '(?:' 3379 + ( 3380 /(?:elseif|if)\b/.source 3381 + '(?:[ \t]*' 3382 // This regex is a little complex. It's equivalent to this: 3383 // (?:![ \t]*)?(?:\b\w+\b(?:[ \t]*<round>)?|<round>)(?:[ \t]*(?:&&|\|\|))? 3384 // where <round> is a general parentheses expression. 3385 + /(?:![ \t]*)?(?:\b\w+\b(?:[ \t]*\((?:[^()]|\([^()]*\))*\))?|\((?:[^()]|\([^()]*\))*\))(?:[ \t]*(?:&&|\|\|))?/.source 3386 + ')+' 3387 ) 3388 + '|' 3389 + /(?:else|endif)\b/.source 3390 + ')' 3391 ), 3392 alias: 'property', 3393 inside: { 3394 'directive-name': /^#\w+/, 3395 'boolean': /\b(?:false|true)\b/, 3396 'number': /\b\d+(?:\.\d+)*\b/, 3397 'operator': /!|&&|\|\||[<>]=?/, 3398 'punctuation': /[(),]/ 3399 } 3400 }, 3401 'literal': { 3402 pattern: /#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\b/, 3403 alias: 'constant' 3404 }, 3405 'other-directive': { 3406 pattern: /#\w+\b/, 3407 alias: 'property' 3408 }, 3409 3410 'attribute': { 3411 pattern: /@\w+/, 3412 alias: 'atrule' 3413 }, 3414 3415 'function-definition': { 3416 pattern: /(\bfunc\s+)\w+/, 3417 lookbehind: true, 3418 alias: 'function' 3419 }, 3420 'label': { 3421 // https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html#ID141 3422 pattern: /\b(break|continue)\s+\w+|\b[a-zA-Z_]\w*(?=\s*:\s*(?:for|repeat|while)\b)/, 3423 lookbehind: true, 3424 alias: 'important' 3425 }, 3426 3427 'keyword': /\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\b/, 3428 'boolean': /\b(?:false|true)\b/, 3429 'nil': { 3430 pattern: /\bnil\b/, 3431 alias: 'constant' 3432 }, 3433 3434 'short-argument': /\$\d+\b/, 3435 'omit': { 3436 pattern: /\b_\b/, 3437 alias: 'keyword' 3438 }, 3439 'number': /\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i, 3440 3441 // A class name must start with an upper-case letter and be either 1 letter long or contain a lower-case letter. 3442 'class-name': /\b[A-Z](?:[A-Z_\d]*[a-z]\w*)?\b/, 3443 'function': /\b[a-z_]\w*(?=\s*\()/i, 3444 'constant': /\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/, 3445 3446 // Operators are generic in Swift. Developers can even create new operators (e.g. +++). 3447 // https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html#ID481 3448 // This regex only supports ASCII operators. 3449 'operator': /[-+*/%=!<>&|^~?]+|\.[.\-+*/%=!<>&|^~?]+/, 3450 'punctuation': /[{}[\]();,.:\\]/ 3451}; 3452 3453Prism$1.languages.swift['string-literal'].forEach(function (rule) {
3454 rule.inside['interpolation'].inside = Prism$1.languages.swift; 3455}); 3456 3457var prismTypescript = {}; 3458 3459var hasRequiredPrismTypescript; 3460 3461function requirePrismTypescript () { 3462 if (hasRequiredPrismTypescript) return prismTypescript; 3463 hasRequiredPrismTypescript = 1; 3464 (function (Prism) { 3465 3466 Prism.languages.typescript = Prism.languages.extend('javascript', { 3467 'class-name': { 3468 pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/, 3469 lookbehind: true, 3470 greedy: true, 3471 inside: null // see below 3472 }, 3473 'builtin': /\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/, 3474 }); 3475 3476 // The keywords TypeScript adds to JavaScript 3477 Prism.languages.typescript.keyword.push( 3478 /\b(?:abstract|declare|is|keyof|readonly|require)\b/, 3479 // keywords that have to be followed by an identifier 3480 /\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/, 3481 // This is for `import type *, {}` 3482 /\btype\b(?=\s*(?:[\{*]|$))/ 3483 ); 3484 3485 // doesn't work with TS because TS is too complex 3486 delete Prism.languages.typescript['parameter']; 3487 delete Prism.languages.typescript['literal-property']; 3488 3489 // a version of typescript specifically for highlighting types 3490 var typeInside = Prism.languages.extend('typescript', {}); 3491 delete typeInside['class-name']; 3492 3493 Prism.languages.typescript['class-name'].inside = typeInside; 3494 3495 Prism.languages.insertBefore('typescript', 'function', { 3496 'decorator': { 3497 pattern: /@[$\w\xA0-\uFFFF]+/, 3498 inside: { 3499 'at': { 3500 pattern: /^@/, 3501 alias: 'operator' 3502 }, 3503 'function': /^[\s\S]+/ 3504 } 3505 }, 3506 'generic-function': { 3507 // e.g. foo<T extends "bar" | "baz">( ... 3508 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/, 3509 greedy: true, 3510 inside: { 3511 'function': /^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/, 3512 'generic': { 3513 pattern: /<[\s\S]+/, // everything after the first < 3514 alias: 'class-name', 3515 inside: typeInside 3516 } 3517 } 3518 } 3519 }); 3520 3521 Prism.languages.ts = Prism.languages.typescript; 3522 3523 }(Prism$1)); 3524 return prismTypescript; 3525} 3526 3527requirePrismTypescript(); 3528 3529var prismJava = {}; 3530 3531var hasRequiredPrismJava; 3532 3533function requirePrismJava () { 3534 if (hasRequiredPrismJava) return prismJava; 3535 hasRequiredPrismJava = 1; 3536 (function (Prism) { 3537 3538 var keywords = /\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/; 3539 3540 // full package (optional) + parent classes (optional) 3541 var classNamePrefix = /(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source; 3542 3543 // based on the java naming conventions 3544 var className = { 3545 pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source), 3546 lookbehind: true, 3547 inside: { 3548 'namespace': { 3549 pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/, 3550 inside: { 3551 'punctuation': /\./ 3552 } 3553 }, 3554 'punctuation': /\./ 3555 } 3556 }; 3557 3558 Prism.languages.java = Prism.languages.extend('clike', { 3559 'string': { 3560 pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"/, 3561 lookbehind: true, 3562 greedy: true 3563 }, 3564 'class-name': [ 3565 className, 3566 { 3567 // variables, parameters, and constructor references 3568 // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) 3569 pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source), 3570 lookbehind: true, 3571 inside: className.inside 3572 }, 3573 {
vendor: 11,608 bytes, lines 3574-3934
3574 // class names based on keyword 3575 // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) 3576 pattern: RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source + classNamePrefix + /[A-Z]\w*\b/.source), 3577 lookbehind: true, 3578 inside: className.inside 3579 } 3580 ], 3581 'keyword': keywords, 3582 'function': [ 3583 Prism.languages.clike.function, 3584 { 3585 pattern: /(::\s*)[a-z_]\w*/, 3586 lookbehind: true 3587 } 3588 ], 3589 'number': /\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i, 3590 'operator': { 3591 pattern: /(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m, 3592 lookbehind: true 3593 }, 3594 'constant': /\b[A-Z][A-Z_\d]+\b/ 3595 }); 3596 3597 Prism.languages.insertBefore('java', 'string', { 3598 'triple-quoted-string': { 3599 // http://openjdk.java.net/jeps/355#Description 3600 pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, 3601 greedy: true, 3602 alias: 'string' 3603 }, 3604 'char': { 3605 pattern: /'(?:\\.|[^'\\\r\n]){1,6}'/, 3606 greedy: true 3607 } 3608 }); 3609 3610 Prism.languages.insertBefore('java', 'class-name', { 3611 'annotation': { 3612 pattern: /(^|[^.])@\w+(?:\s*\.\s*\w+)*/, 3613 lookbehind: true, 3614 alias: 'punctuation' 3615 }, 3616 'generics': { 3617 pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/, 3618 inside: { 3619 'class-name': className, 3620 'keyword': keywords, 3621 'punctuation': /[<>(),.:]/, 3622 'operator': /[?&|]/ 3623 } 3624 }, 3625 'import': [ 3626 { 3627 pattern: RegExp(/(\bimport\s+)/.source + classNamePrefix + /(?:[A-Z]\w*|\*)(?=\s*;)/.source), 3628 lookbehind: true, 3629 inside: { 3630 'namespace': className.inside.namespace, 3631 'punctuation': /\./, 3632 'operator': /\*/, 3633 'class-name': /\w+/ 3634 } 3635 }, 3636 { 3637 pattern: RegExp(/(\bimport\s+static\s+)/.source + classNamePrefix + /(?:\w+|\*)(?=\s*;)/.source), 3638 lookbehind: true, 3639 alias: 'static', 3640 inside: { 3641 'namespace': className.inside.namespace, 3642 'static': /\b\w+$/, 3643 'punctuation': /\./, 3644 'operator': /\*/, 3645 'class-name': /\w+/ 3646 } 3647 } 3648 ], 3649 'namespace': { 3650 pattern: RegExp( 3651 /(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/ 3652 .source.replace(/<keyword>/g, function () { return keywords.source; })), 3653 lookbehind: true, 3654 inside: { 3655 'punctuation': /\./, 3656 } 3657 } 3658 }); 3659 }(Prism$1)); 3660 return prismJava; 3661} 3662 3663requirePrismJava(); 3664 3665var prismCpp = {}; 3666 3667var hasRequiredPrismCpp; 3668 3669function requirePrismCpp () { 3670 if (hasRequiredPrismCpp) return prismCpp; 3671 hasRequiredPrismCpp = 1; 3672 (function (Prism) { 3673 3674 var keyword = /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/; 3675 var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g, function () { return keyword.source; }); 3676 3677 Prism.languages.cpp = Prism.languages.extend('c', { 3678 'class-name': [ 3679 { 3680 pattern: RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source 3681 .replace(/<keyword>/g, function () { return keyword.source; })), 3682 lookbehind: true 3683 }, 3684 // This is intended to capture the class name of method implementations like: 3685 // void foo::bar() const {} 3686 // However! The `foo` in the above example could also be a namespace, so we only capture the class name if 3687 // it starts with an uppercase letter. This approximation should give decent results. 3688 /\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/, 3689 // This will capture the class name before destructors like: 3690 // Foo::~Foo() {} 3691 /\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i, 3692 // This also intends to capture the class name of method implementations but here the class has template 3693 // parameters, so it can't be a namespace (until C++ adds generic namespaces). 3694 /\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/ 3695 ], 3696 'keyword': keyword, 3697 'number': { 3698 pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i, 3699 greedy: true 3700 }, 3701 'operator': />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/, 3702 'boolean': /\b(?:false|true)\b/ 3703 }); 3704 3705 Prism.languages.insertBefore('cpp', 'string', { 3706 'module': { 3707 // https://en.cppreference.com/w/cpp/language/modules 3708 pattern: RegExp( 3709 /(\b(?:import|module)\s+)/.source + 3710 '(?:' + 3711 // header-name 3712 /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source + 3713 '|' + 3714 // module name or partition or both 3715 /<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g, function () { return modName; }) + 3716 ')' 3717 ), 3718 lookbehind: true, 3719 greedy: true, 3720 inside: { 3721 'string': /^[<"][\s\S]+/, 3722 'operator': /:/, 3723 'punctuation': /\./ 3724 } 3725 }, 3726 'raw-string': { 3727 pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/, 3728 alias: 'string', 3729 greedy: true 3730 } 3731 }); 3732 3733 Prism.languages.insertBefore('cpp', 'keyword', { 3734 'generic-function': { 3735 pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i, 3736 inside: { 3737 'function': /^\w+/, 3738 'generic': { 3739 pattern: /<[\s\S]+/, 3740 alias: 'class-name', 3741 inside: Prism.languages.cpp 3742 } 3743 } 3744 } 3745 }); 3746 3747 Prism.languages.insertBefore('cpp', 'operator', { 3748 'double-colon': { 3749 pattern: /::/, 3750 alias: 'punctuation' 3751 } 3752 }); 3753 3754 Prism.languages.insertBefore('cpp', 'class-name', { 3755 // the base clause is an optional list of parent classes 3756 // https://en.cppreference.com/w/cpp/language/class 3757 'base-clause': { 3758 pattern: /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/, 3759 lookbehind: true, 3760 greedy: true, 3761 inside: Prism.languages.extend('cpp', {}) 3762 } 3763 }); 3764 3765 Prism.languages.insertBefore('inside', 'double-colon', { 3766 // All untokenized words that are not namespaces should be class names 3767 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i 3768 }, Prism.languages.cpp['base-clause']); 3769 3770 }(Prism$1)); 3771 return prismCpp; 3772} 3773 3774requirePrismCpp(); 3775 3776(function (Prism) { 3777 3778 /** 3779 * Returns the placeholder for the given language id and index. 3780 * 3781 * @param {string} language 3782 * @param {string|number} index 3783 * @returns {string} 3784 */ 3785 function getPlaceholder(language, index) { 3786 return '___' + language.toUpperCase() + index + '___'; 3787 } 3788 3789 Object.defineProperties(Prism.languages['markup-templating'] = {}, { 3790 buildPlaceholders: { 3791 /** 3792 * Tokenize all inline templating expressions matching `placeholderPattern`. 3793 * 3794 * If `replaceFilter` is provided, only matches of `placeholderPattern` for which `replaceFilter` returns 3795 * `true` will be replaced. 3796 * 3797 * @param {object} env The environment of the `before-tokenize` hook. 3798 * @param {string} language The language id. 3799 * @param {RegExp} placeholderPattern The matches of this pattern will be replaced by placeholders. 3800 * @param {(match: string) => boolean} [replaceFilter] 3801 */ 3802 value: function (env, language, placeholderPattern, replaceFilter) { 3803 if (env.language !== language) { 3804 return; 3805 } 3806 3807 var tokenStack = env.tokenStack = []; 3808 3809 env.code = env.code.replace(placeholderPattern, function (match) { 3810 if (typeof replaceFilter === 'function' && !replaceFilter(match)) { 3811 return match; 3812 } 3813 var i = tokenStack.length; 3814 var placeholder; 3815 3816 // Check for existing strings 3817 while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1) { 3818 ++i; 3819 } 3820 3821 // Create a sparse array 3822 tokenStack[i] = match; 3823 3824 return placeholder; 3825 }); 3826 3827 // Switch the grammar to markup 3828 env.grammar = Prism.languages.markup; 3829 } 3830 }, 3831 tokenizePlaceholders: { 3832 /** 3833 * Replace placeholders with proper tokens after tokenizing. 3834 * 3835 * @param {object} env The environment of the `after-tokenize` hook. 3836 * @param {string} language The language id. 3837 */ 3838 value: function (env, language) { 3839 if (env.language !== language || !env.tokenStack) { 3840 return; 3841 } 3842 3843 // Switch the grammar back 3844 env.grammar = Prism.languages[language]; 3845 3846 var j = 0; 3847 var keys = Object.keys(env.tokenStack); 3848 3849 function walkTokens(tokens) { 3850 for (var i = 0; i < tokens.length; i++) { 3851 // all placeholders are replaced already 3852 if (j >= keys.length) { 3853 break; 3854 } 3855 3856 var token = tokens[i]; 3857 if (typeof token === 'string' || (token.content && typeof token.content === 'string')) { 3858 var k = keys[j]; 3859 var t = env.tokenStack[k]; 3860 var s = typeof token === 'string' ? token : token.content; 3861 var placeholder = getPlaceholder(language, k); 3862 3863 var index = s.indexOf(placeholder); 3864 if (index > -1) { 3865 ++j; 3866 3867 var before = s.substring(0, index); 3868 var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar), 'language-' + language, t); 3869 var after = s.substring(index + placeholder.length); 3870 3871 var replacement = []; 3872 if (before) { 3873 replacement.push.apply(replacement, walkTokens([before])); 3874 } 3875 replacement.push(middle); 3876 if (after) { 3877 replacement.push.apply(replacement, walkTokens([after])); 3878 } 3879 3880 if (typeof token === 'string') { 3881 tokens.splice.apply(tokens, [i, 1].concat(replacement)); 3882 } else { 3883 token.content = replacement; 3884 } 3885 } 3886 } else if (token.content /* && typeof token.content !== 'string' */) { 3887 walkTokens(token.content); 3888 } 3889 } 3890 3891 return tokens; 3892 } 3893 3894 walkTokens(env.tokens); 3895 } 3896 } 3897 }); 3898 3899}(Prism$1)); 3900 3901var prismRuby = {}; 3902 3903var hasRequiredPrismRuby; 3904 3905function requirePrismRuby () { 3906 if (hasRequiredPrismRuby) return prismRuby; 3907 hasRequiredPrismRuby = 1; 3908 (function (Prism) { 3909 Prism.languages.ruby = Prism.languages.extend('clike', { 3910 'comment': { 3911 pattern: /#.*|^=begin\s[\s\S]*?^=end/m, 3912 greedy: true 3913 }, 3914 'class-name': { 3915 pattern: /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/, 3916 lookbehind: true, 3917 inside: { 3918 'punctuation': /[.\\]/ 3919 } 3920 }, 3921 'keyword': /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/, 3922 'operator': /\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/, 3923 'punctuation': /[(){}[\].,;]/, 3924 }); 3925 3926 Prism.languages.insertBefore('ruby', 'operator', { 3927 'double-colon': { 3928 pattern: /::/, 3929 alias: 'punctuation' 3930 }, 3931 }); 3932 3933 var interpolation = { 3934 pattern: /((?:^|[^\\])(?:\\{2}
3934)*)#\{(?:[^{}]|\{[^{}]*\})*\}/, 3935 lookbehind: true, 3936 inside: { 3937 'content': { 3938 pattern: /^(#\{)[\s\S]+(?=\}$)/, 3939 lookbehind: true, 3940 inside: Prism.languages.ruby 3941 }, 3942 'delimiter': { 3943 pattern: /^#\{|\}$/, 3944 alias: 'punctuation' 3945 } 3946 } 3947 }; 3948 3949 delete Prism.languages.ruby.function; 3950 3951 var percentExpression = '(?:' + [ 3952 /([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source, 3953 /\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source, 3954 /\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source, 3955 /\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source, 3956 /<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source 3957 ].join('|') + ')'; 3958 3959 var symbolName = /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source; 3960 3961 Prism.languages.insertBefore('ruby', 'keyword', { 3962 'regex-literal': [ 3963 { 3964 pattern: RegExp(/%r/.source + percentExpression + /[egimnosux]{0,6}/.source), 3965 greedy: true, 3966 inside: { 3967 'interpolation': interpolation, 3968 'regex': /[\s\S]+/ 3969 } 3970 }, 3971 { 3972 pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/, 3973 lookbehind: true, 3974 greedy: true, 3975 inside: { 3976 'interpolation': interpolation, 3977 'regex': /[\s\S]+/ 3978 } 3979 } 3980 ], 3981 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/, 3982 'symbol': [ 3983 { 3984 pattern: RegExp(/(^|[^:]):/.source + symbolName), 3985 lookbehind: true, 3986 greedy: true 3987 }, 3988 { 3989 pattern: RegExp(/([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source), 3990 lookbehind: true, 3991 greedy: true 3992 }, 3993 ], 3994 'method-definition': { 3995 pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/, 3996 lookbehind: true, 3997 inside: { 3998 'function': /\b\w+$/, 3999 'keyword': /^self\b/, 4000 'class-name': /^\w+/, 4001 'punctuation': /\./ 4002 } 4003 } 4004 }); 4005 4006 Prism.languages.insertBefore('ruby', 'string', { 4007 'string-literal': [ 4008 { 4009 pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression), 4010 greedy: true, 4011 inside: { 4012 'interpolation': interpolation, 4013 'string': /[\s\S]+/ 4014 } 4015 }, 4016 { 4017 pattern: /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/, 4018 greedy: true, 4019 inside: { 4020 'interpolation': interpolation, 4021 'string': /[\s\S]+/ 4022 } 4023 }, 4024 { 4025 pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i, 4026 alias: 'heredoc-string', 4027 greedy: true, 4028 inside: { 4029 'delimiter': { 4030 pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i, 4031 inside: { 4032 'symbol': /\b\w+/, 4033 'punctuation': /^<<[-~]?/ 4034 } 4035 }, 4036 'interpolation': interpolation, 4037 'string': /[\s\S]+/ 4038 } 4039 }, 4040 { 4041 pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i, 4042 alias: 'heredoc-string', 4043 greedy: true, 4044 inside: { 4045 'delimiter': { 4046 pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i, 4047 inside: { 4048 'symbol': /\b\w+/, 4049 'punctuation': /^<<[-~]?'|'$/, 4050 } 4051 }, 4052 'string': /[\s\S]+/ 4053 } 4054 } 4055 ], 4056 'command-literal': [ 4057 { 4058 pattern: RegExp(/%x/.source + percentExpression), 4059 greedy: true, 4060 inside: { 4061 'interpolation': interpolation, 4062 'command': { 4063 pattern: /[\s\S]+/, 4064 alias: 'string' 4065 } 4066 } 4067 }, 4068 { 4069 pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/, 4070 greedy: true, 4071 inside: { 4072 'interpolation': interpolation, 4073 'command': { 4074 pattern: /[\s\S]+/, 4075 alias: 'string' 4076 } 4077 } 4078 } 4079 ] 4080 }); 4081 4082 delete Prism.languages.ruby.string; 4083 4084 Prism.languages.insertBefore('ruby', 'number', { 4085 'builtin': /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/, 4086 'constant': /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/ 4087 }); 4088 4089 Prism.languages.rb = Prism.languages.ruby; 4090 }(Prism$1)); 4091 return prismRuby; 4092} 4093 4094requirePrismRuby(); 4095 4096var prismPhp = {}; 4097 4098var hasRequiredPrismPhp; 4099 4100function requirePrismPhp () { 4101 if (hasRequiredPrismPhp) return prismPhp; 4102 hasRequiredPrismPhp = 1; 4103 (function (Prism) { 4104 var comment = /\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/; 4105 var constant = [ 4106 { 4107 pattern: /\b(?:false|true)\b/i, 4108 alias: 'boolean' 4109 }, 4110 { 4111 pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i, 4112 greedy: true, 4113 lookbehind: true, 4114 }, 4115 { 4116 pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i, 4117 greedy: true, 4118 lookbehind: true, 4119 }, 4120 /\b(?:null)\b/i, 4121 /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/, 4122 ]; 4123 var number = /\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i; 4124 var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/; 4125 var punctuation = /[{}\[\](),:;]/; 4126 4127 Prism.languages.php = { 4128 'delimiter': { 4129 pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i,
vendor: 10,661 bytes, lines 4130-4477
4130 alias: 'important' 4131 }, 4132 'comment': comment, 4133 'variable': /\$+(?:\w+\b|(?=\{))/, 4134 'package': { 4135 pattern: /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, 4136 lookbehind: true, 4137 inside: { 4138 'punctuation': /\\/ 4139 } 4140 }, 4141 'class-name-definition': { 4142 pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i, 4143 lookbehind: true, 4144 alias: 'class-name' 4145 }, 4146 'function-definition': { 4147 pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i, 4148 lookbehind: true, 4149 alias: 'function' 4150 }, 4151 'keyword': [ 4152 { 4153 pattern: /(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i, 4154 alias: 'type-casting', 4155 greedy: true, 4156 lookbehind: true 4157 }, 4158 { 4159 pattern: /([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i, 4160 alias: 'type-hint', 4161 greedy: true, 4162 lookbehind: true 4163 }, 4164 { 4165 pattern: /(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i, 4166 alias: 'return-type', 4167 greedy: true, 4168 lookbehind: true 4169 }, 4170 { 4171 pattern: /\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i, 4172 alias: 'type-declaration', 4173 greedy: true 4174 }, 4175 { 4176 pattern: /(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i, 4177 alias: 'type-declaration', 4178 greedy: true, 4179 lookbehind: true 4180 }, 4181 { 4182 pattern: /\b(?:parent|self|static)(?=\s*::)/i, 4183 alias: 'static-context', 4184 greedy: true 4185 }, 4186 { 4187 // yield from 4188 pattern: /(\byield\s+)from\b/i, 4189 lookbehind: true 4190 }, 4191 // `class` is always a keyword unlike other keywords 4192 /\bclass\b/i, 4193 { 4194 // https://www.php.net/manual/en/reserved.keywords.php 4195 // 4196 // keywords cannot be preceded by "->" 4197 // the complex lookbehind means `(?<!(?:->|::)\s*)` 4198 pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i, 4199 lookbehind: true 4200 } 4201 ], 4202 'argument-name': { 4203 pattern: /([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i, 4204 lookbehind: true 4205 }, 4206 'class-name': [ 4207 { 4208 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i, 4209 greedy: true, 4210 lookbehind: true 4211 }, 4212 { 4213 pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i, 4214 greedy: true, 4215 lookbehind: true 4216 }, 4217 { 4218 pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i, 4219 greedy: true 4220 }, 4221 { 4222 pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i, 4223 alias: 'class-name-fully-qualified', 4224 greedy: true, 4225 lookbehind: true, 4226 inside: { 4227 'punctuation': /\\/ 4228 } 4229 }, 4230 { 4231 pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i, 4232 alias: 'class-name-fully-qualified', 4233 greedy: true, 4234 inside: { 4235 'punctuation': /\\/ 4236 } 4237 }, 4238 { 4239 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, 4240 alias: 'class-name-fully-qualified', 4241 greedy: true, 4242 lookbehind: true, 4243 inside: { 4244 'punctuation': /\\/ 4245 } 4246 }, 4247 { 4248 pattern: /\b[a-z_]\w*(?=\s*\$)/i, 4249 alias: 'type-declaration', 4250 greedy: true 4251 }, 4252 { 4253 pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i, 4254 alias: ['class-name-fully-qualified', 'type-declaration'], 4255 greedy: true, 4256 inside: { 4257 'punctuation': /\\/ 4258 } 4259 }, 4260 { 4261 pattern: /\b[a-z_]\w*(?=\s*::)/i, 4262 alias: 'static-context', 4263 greedy: true 4264 }, 4265 { 4266 pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i, 4267 alias: ['class-name-fully-qualified', 'static-context'], 4268 greedy: true, 4269 inside: { 4270 'punctuation': /\\/ 4271 } 4272 }, 4273 { 4274 pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i, 4275 alias: 'type-hint', 4276 greedy: true, 4277 lookbehind: true 4278 }, 4279 { 4280 pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i, 4281 alias: ['class-name-fully-qualified', 'type-hint'], 4282 greedy: true, 4283 lookbehind: true, 4284 inside: { 4285 'punctuation': /\\/ 4286 } 4287 }, 4288 { 4289 pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i, 4290 alias: 'return-type', 4291 greedy: true, 4292 lookbehind: true 4293 }, 4294 { 4295 pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, 4296 alias: ['class-name-fully-qualified', 'return-type'], 4297 greedy: true, 4298 lookbehind: true, 4299 inside: { 4300 'punctuation': /\\/ 4301 } 4302 } 4303 ], 4304 'constant': constant, 4305 'function': { 4306 pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i, 4307 lookbehind: true, 4308 inside: { 4309 'punctuation': /\\/ 4310 } 4311 }, 4312 'property': { 4313 pattern: /(->\s*)\w+/, 4314 lookbehind: true 4315 }, 4316 'number': number, 4317 'operator': operator, 4318 'punctuation': punctuation 4319 }; 4320 4321 var string_interpolation = { 4322 pattern: /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/, 4323 lookbehind: true, 4324 inside: Prism.languages.php 4325 }; 4326 4327 var string = [ 4328 { 4329 pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/, 4330 alias: 'nowdoc-string', 4331 greedy: true, 4332 inside: { 4333 'delimiter': { 4334 pattern: /^<<<'[^']+'|[a-z_]\w*;$/i, 4335 alias: 'symbol', 4336 inside: { 4337 'punctuation': /^<<<'?|[';]$/ 4338 } 4339 } 4340 } 4341 }, 4342 { 4343 pattern: /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i, 4344 alias: 'heredoc-string', 4345 greedy: true, 4346 inside: { 4347 'delimiter': { 4348 pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i, 4349 alias: 'symbol', 4350 inside: { 4351 'punctuation': /^<<<"?|[";]$/ 4352 } 4353 }, 4354 'interpolation': string_interpolation 4355 } 4356 }, 4357 { 4358 pattern: /`(?:\\[\s\S]|[^\\`])*`/, 4359 alias: 'backtick-quoted-string', 4360 greedy: true 4361 }, 4362 { 4363 pattern: /'(?:\\[\s\S]|[^\\'])*'/, 4364 alias: 'single-quoted-string', 4365 greedy: true 4366 }, 4367 { 4368 pattern: /"(?:\\[\s\S]|[^\\"])*"/, 4369 alias: 'double-quoted-string', 4370 greedy: true, 4371 inside: { 4372 'interpolation': string_interpolation 4373 } 4374 } 4375 ]; 4376 4377 Prism.languages.insertBefore('php', 'variable', { 4378 'string': string, 4379 'attribute': { 4380 pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im, 4381 greedy: true, 4382 inside: { 4383 'attribute-content': { 4384 pattern: /^(#\[)[\s\S]+(?=\]$)/, 4385 lookbehind: true, 4386 // inside can appear subset of php 4387 inside: { 4388 'comment': comment, 4389 'string': string, 4390 'attribute-class-name': [ 4391 { 4392 pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i, 4393 alias: 'class-name', 4394 greedy: true, 4395 lookbehind: true 4396 }, 4397 { 4398 pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i, 4399 alias: [ 4400 'class-name', 4401 'class-name-fully-qualified' 4402 ], 4403 greedy: true, 4404 lookbehind: true, 4405 inside: { 4406 'punctuation': /\\/ 4407 } 4408 } 4409 ], 4410 'constant': constant, 4411 'number': number, 4412 'operator': operator, 4413 'punctuation': punctuation 4414 } 4415 }, 4416 'delimiter': { 4417 pattern: /^#\[|\]$/, 4418 alias: 'punctuation' 4419 } 4420 } 4421 }, 4422 }); 4423 4424 Prism.hooks.add('before-tokenize', function (env) { 4425 if (!/<\?/.test(env.code)) { 4426 return; 4427 } 4428 4429 var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g; 4430 Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern); 4431 }); 4432 4433 Prism.hooks.add('after-tokenize', function (env) { 4434 Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php'); 4435 }); 4436 4437 }(Prism$1)); 4438 return prismPhp; 4439} 4440 4441requirePrismPhp(); 4442 4443Prism$1.languages.go = Prism$1.languages.extend('clike', { 4444 'string': { 4445 pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/, 4446 lookbehind: true, 4447 greedy: true 4448 }, 4449 'keyword': /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/, 4450 'boolean': /\b(?:_|false|iota|nil|true)\b/, 4451 'number': [ 4452 // binary and octal integers 4453 /\b0(?:b[01_]+|o[0-7_]+)i?\b/i, 4454 // hexadecimal integers and floats 4455 /\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i, 4456 // decimal integers and floats 4457 /(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i 4458 ], 4459 'operator': /[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./, 4460 'builtin': /\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/ 4461}); 4462 4463Prism$1.languages.insertBefore('go', 'string', { 4464 'char': { 4465 pattern: /'(?:\\.|[^'\\\r\n]){0,10}'/, 4466 greedy: true 4467 } 4468}); 4469 4470delete Prism$1.languages.go['class-name']; 4471 4472(function (Prism) { 4473 // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|' 4474 // + LC_ALL, RANDOM, REPLY, SECONDS. 4475 // + make sure PS1..4 are here as they are not always set, 4476 // - some useless things. 4477 var envVars = '\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_
4477CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b'; 4478 4479 var commandAfterHeredoc = { 4480 pattern: /(^(["']?)\w+\2)[ \t]+\S.*/, 4481 lookbehind: true, 4482 alias: 'punctuation', // this looks reasonably well in all themes 4483 inside: null // see below 4484 }; 4485 4486 var insideString = { 4487 'bash': commandAfterHeredoc, 4488 'environment': { 4489 pattern: RegExp('\\$' + envVars), 4490 alias: 'constant' 4491 }, 4492 'variable': [ 4493 // [0]: Arithmetic Environment 4494 { 4495 pattern: /\$?\(\([\s\S]+?\)\)/, 4496 greedy: true, 4497 inside: { 4498 // If there is a $ sign at the beginning highlight $(( and )) as variable 4499 'variable': [ 4500 { 4501 pattern: /(^\$\(\([\s\S]+)\)\)/, 4502 lookbehind: true 4503 }, 4504 /^\$\(\(/ 4505 ], 4506 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/, 4507 // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic 4508 'operator': /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/, 4509 // If there is no $ sign at the beginning highlight (( and )) as punctuation 4510 'punctuation': /\(\(?|\)\)?|,|;/ 4511 } 4512 }, 4513 // [1]: Command Substitution 4514 { 4515 pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/, 4516 greedy: true, 4517 inside: { 4518 'variable': /^\$\(|^`|\)$|`$/ 4519 } 4520 }, 4521 // [2]: Brace expansion 4522 { 4523 pattern: /\$\{[^}]+\}/, 4524 greedy: true, 4525 inside: { 4526 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/, 4527 'punctuation': /[\[\]]/, 4528 'environment': { 4529 pattern: RegExp('(\\{)' + envVars), 4530 lookbehind: true, 4531 alias: 'constant' 4532 } 4533 } 4534 }, 4535 /\$(?:\w+|[#?*!@$])/ 4536 ], 4537 // Escape sequences from echo and printf's manuals, and escaped quotes. 4538 'entity': /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/ 4539 }; 4540 4541 Prism.languages.bash = { 4542 'shebang': { 4543 pattern: /^#!\s*\/.*/, 4544 alias: 'important' 4545 }, 4546 'comment': { 4547 pattern: /(^|[^"{\\$])#.*/, 4548 lookbehind: true 4549 }, 4550 'function-name': [ 4551 // a) function foo { 4552 // b) foo() { 4553 // c) function foo() { 4554 // but not âfoo {â 4555 { 4556 // a) and c) 4557 pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/, 4558 lookbehind: true, 4559 alias: 'function' 4560 }, 4561 { 4562 // b) 4563 pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/, 4564 alias: 'function' 4565 } 4566 ], 4567 // Highlight variable names as variables in for and select beginnings. 4568 'for-or-select': { 4569 pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/, 4570 alias: 'variable', 4571 lookbehind: true 4572 }, 4573 // Highlight variable names as variables in the left-hand part 4574 // of assignments (â=â and â+=â). 4575 'assign-left': { 4576 pattern: /(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/, 4577 inside: { 4578 'environment': { 4579 pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars), 4580 lookbehind: true, 4581 alias: 'constant' 4582 } 4583 }, 4584 alias: 'variable', 4585 lookbehind: true 4586 }, 4587 // Highlight parameter names as variables 4588 'parameter': { 4589 pattern: /(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/, 4590 alias: 'variable', 4591 lookbehind: true 4592 }, 4593 'string': [ 4594 // Support for Here-documents https://en.wikipedia.org/wiki/Here_document 4595 { 4596 pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/, 4597 lookbehind: true, 4598 greedy: true, 4599 inside: insideString 4600 }, 4601 // Here-document with quotes around the tag 4602 // â No expansion (so no âinsideâ). 4603 { 4604 pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/, 4605 lookbehind: true, 4606 greedy: true, 4607 inside: { 4608 'bash': commandAfterHeredoc 4609 } 4610 }, 4611 // âNormalâ string 4612 { 4613 // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html 4614 pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/, 4615 lookbehind: true, 4616 greedy: true, 4617 inside: insideString 4618 }, 4619 { 4620 // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html 4621 pattern: /(^|[^$\\])'[^']*'/, 4622 lookbehind: true, 4623 greedy: true 4624 }, 4625 { 4626 // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html 4627 pattern: /\$'(?:[^'\\]|\\[\s\S])*'/, 4628 greedy: true, 4629 inside: { 4630 'entity': insideString.entity 4631 } 4632 } 4633 ], 4634 'environment': { 4635 pattern: RegExp('\\$?' + envVars), 4636 alias: 'constant' 4637 }, 4638 'variable': insideString.variable, 4639 'function': { 4640 pattern: /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|
4640ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/, 4641 lookbehind: true 4642 }, 4643 'keyword': { 4644 pattern: /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/, 4645 lookbehind: true 4646 }, 4647 // https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html 4648 'builtin': { 4649 pattern: /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/, 4650 lookbehind: true, 4651 // Alias added to make those easier to distinguish from strings. 4652 alias: 'class-name' 4653 }, 4654 'boolean': { 4655 pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/, 4656 lookbehind: true 4657 }, 4658 'file-descriptor': { 4659 pattern: /\B&\d\b/, 4660 alias: 'important' 4661 }, 4662 'operator': { 4663 // Lots of redirections here, but not just that. 4664 pattern: /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/, 4665 inside: { 4666 'file-descriptor': { 4667 pattern: /^\d/, 4668 alias: 'important' 4669 } 4670 } 4671 }, 4672 'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/, 4673 'number': { 4674 pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/, 4675 lookbehind: true 4676 } 4677 }; 4678 4679 commandAfterHeredoc.inside = Prism.languages.bash; 4680 4681 /* Patterns in command substitution. */ 4682 var toBeCopied = [ 4683 'comment', 4684 'function-name', 4685 'for-or-select', 4686 'assign-left', 4687 'parameter', 4688 'string', 4689 'environment', 4690 'function', 4691 'keyword', 4692 'builtin', 4693 'boolean', 4694 'file-descriptor', 4695 'operator', 4696 'punctuation', 4697 'number' 4698 ]; 4699 var inside = insideString.variable[1].inside; 4700 for (var i = 0; i < toBeCopied.length; i++) { 4701 inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]]; 4702 } 4703 4704 Prism.languages.sh = Prism.languages.bash; 4705 Prism.languages.shell = Prism.languages.bash; 4706}(Prism$1)); 4707 4708// https://www.json.org/json-en.html 4709Prism$1.languages.json = { 4710 'property': { 4711 pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/, 4712 lookbehind: true, 4713 greedy: true 4714 }, 4715 'string': { 4716 pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/, 4717 lookbehind: true, 4718 greedy: true 4719 }, 4720 'comment': { 4721 pattern: /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/, 4722 greedy: true 4723 }, 4724 'number': /-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i, 4725 'punctuation': /[{}[\],]/, 4726 'operator': /:/, 4727 'boolean': /\b(?:false|true)\b/, 4728 'null': { 4729 pattern: /\bnull\b/, 4730 alias: 'keyword' 4731 } 4732}; 4733 4734Prism$1.languages.webmanifest = Prism$1.languages.json; 4735 4736(function (Prism) { 4737 Prism.languages.kotlin = Prism.languages.extend('clike', { 4738 'keyword': { 4739 // The lookbehind prevents wrong highlighting of e.g. kotlin.properties.get 4740 pattern: /(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/, 4741 lookbehind: true 4742 }, 4743 'function': [ 4744 { 4745 pattern: /(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/, 4746 greedy: true 4747 }, 4748 { 4749 pattern: /(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/, 4750 lookbehind: true, 4751 greedy: true 4752 } 4753 ], 4754 'number': /\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?
4754:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/, 4755 'operator': /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/ 4756 }); 4757 4758 delete Prism.languages.kotlin['class-name']; 4759 4760 var interpolationInside = { 4761 'interpolation-punctuation': { 4762 pattern: /^\$\{?|\}$/, 4763 alias: 'punctuation' 4764 }, 4765 'expression': { 4766 pattern: /[\s\S]+/, 4767 inside: Prism.languages.kotlin 4768 } 4769 }; 4770 4771 Prism.languages.insertBefore('kotlin', 'string', { 4772 // https://kotlinlang.org/spec/expressions.html#string-interpolation-expressions 4773 'string-literal': [ 4774 { 4775 pattern: /"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/, 4776 alias: 'multiline', 4777 inside: { 4778 'interpolation': { 4779 pattern: /\$(?:[a-z_]\w*|\{[^{}]*\})/i, 4780 inside: interpolationInside 4781 }, 4782 'string': /[\s\S]+/ 4783 } 4784 }, 4785 { 4786 pattern: /"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/, 4787 alias: 'singleline', 4788 inside: { 4789 'interpolation': { 4790 pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i, 4791 lookbehind: true, 4792 inside: interpolationInside 4793 }, 4794 'string': /[\s\S]+/ 4795 } 4796 } 4797 ], 4798 'char': { 4799 // https://kotlinlang.org/spec/expressions.html#character-literals 4800 pattern: /'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/, 4801 greedy: true 4802 } 4803 }); 4804 4805 delete Prism.languages.kotlin['string']; 4806 4807 Prism.languages.insertBefore('kotlin', 'keyword', { 4808 'annotation': { 4809 pattern: /\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/, 4810 alias: 'builtin' 4811 } 4812 }); 4813 4814 Prism.languages.insertBefore('kotlin', 'function', { 4815 'label': { 4816 pattern: /\b\w+@|@\w+\b/, 4817 alias: 'symbol' 4818 } 4819 }); 4820 4821 Prism.languages.kt = Prism.languages.kotlin; 4822 Prism.languages.kts = Prism.languages.kotlin; 4823}(Prism$1)); 4824 4825// Configure Prism for manual highlighting mode 4826// This must be set before importing prismjs 4827window.Prism ||= {}; 4828window.Prism.manual = true; 4829 4830/*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */ 4831 4832function _arrayLikeToArray(r, a) { 4833 (null == a || a > r.length) && (a = r.length); 4834 for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; 4835 return n; 4836} 4837function _arrayWithHoles(r) { 4838 if (Array.isArray(r)) return r; 4839} 4840function _iterableToArrayLimit(r, l) { 4841 var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; 4842 if (null != t) { 4843 var e, 4844 n, 4845 i, 4846 u, 4847 a = [], 4848 f = true, 4849 o = false; 4850 try { 4851 if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0
vendor: 8,931 bytes, lines 4851-5124
4851); 4852 } catch (r) { 4853 o = true, n = r; 4854 } finally { 4855 try { 4856 if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; 4857 } finally { 4858 if (o) throw n; 4859 } 4860 } 4861 return a; 4862 } 4863} 4864function _nonIterableRest() { 4865 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 4866} 4867function _slicedToArray(r, e) { 4868 return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); 4869} 4870function _unsupportedIterableToArray(r, a) { 4871 if (r) { 4872 if ("string" == typeof r) return _arrayLikeToArray(r, a); 4873 var t = {}.toString.call(r).slice(8, -1); 4874 return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; 4875 } 4876} 4877 4878const entries = Object.entries, 4879 setPrototypeOf = Object.setPrototypeOf, 4880 isFrozen = Object.isFrozen, 4881 getPrototypeOf = Object.getPrototypeOf, 4882 getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 4883let freeze = Object.freeze, 4884 seal = Object.seal, 4885 create = Object.create; // eslint-disable-line import/no-mutable-exports 4886let _ref = typeof Reflect !== 'undefined' && Reflect, 4887 apply = _ref.apply, 4888 construct = _ref.construct; 4889if (!freeze) { 4890 freeze = function freeze(x) { 4891 return x; 4892 }; 4893} 4894if (!seal) { 4895 seal = function seal(x) { 4896 return x; 4897 }; 4898} 4899if (!apply) { 4900 apply = function apply(func, thisArg) { 4901 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { 4902 args[_key - 2] = arguments[_key]; 4903 } 4904 return func.apply(thisArg, args); 4905 }; 4906} 4907if (!construct) { 4908 construct = function construct(Func) { 4909 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 4910 args[_key2 - 1] = arguments[_key2]; 4911 } 4912 return new Func(...args); 4913 }; 4914} 4915const arrayForEach = unapply(Array.prototype.forEach); 4916const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf); 4917const arrayPop = unapply(Array.prototype.pop); 4918const arrayPush = unapply(Array.prototype.push); 4919const arraySplice = unapply(Array.prototype.splice); 4920const arrayIsArray = Array.isArray; 4921const stringToLowerCase = unapply(String.prototype.toLowerCase); 4922const stringToString = unapply(String.prototype.toString); 4923const stringMatch = unapply(String.prototype.match); 4924const stringReplace = unapply(String.prototype.replace); 4925const stringIndexOf = unapply(String.prototype.indexOf); 4926const stringTrim = unapply(String.prototype.trim); 4927const numberToString = unapply(Number.prototype.toString); 4928const booleanToString = unapply(Boolean.prototype.toString); 4929const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString); 4930const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString); 4931const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); 4932const objectToString = unapply(Object.prototype.toString); 4933const regExpTest = unapply(RegExp.prototype.test); 4934const typeErrorCreate = unconstruct(TypeError); 4935/** 4936 * Creates a new function that calls the given function with a specified thisArg and arguments. 4937 * 4938 * @param func - The function to be wrapped and called. 4939 * @returns A new function that calls the given function with a specified thisArg and arguments. 4940 */ 4941function unapply(func) { 4942 return function (thisArg) { 4943 if (thisArg instanceof RegExp) { 4944 thisArg.lastIndex = 0; 4945 } 4946 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { 4947 args[_key3 - 1] = arguments[_key3]; 4948 } 4949 return apply(func, thisArg, args); 4950 }; 4951} 4952/** 4953 * Creates a new function that constructs an instance of the given constructor function with the provided arguments. 4954 * 4955 * @param func - The constructor function to be wrapped and called. 4956 * @returns A new function that constructs an instance of the given constructor function with the provided arguments. 4957 */ 4958function unconstruct(Func) { 4959 return function () { 4960 for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { 4961 args[_key4] = arguments[_key4]; 4962 } 4963 return construct(Func, args); 4964 }; 4965} 4966/** 4967 * Add properties to a lookup table 4968 * 4969 * @param set - The set to which elements will be added. 4970 * @param array - The array containing elements to be added to the set. 4971 * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set. 4972 * @returns The modified set with added elements. 4973 */ 4974function addToSet(set, array) { 4975 let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase; 4976 if (setPrototypeOf) { 4977 // Make 'in' and truthy checks like Boolean(set.constructor) 4978 // independent of any properties defined on Object.prototype. 4979 // Prevent prototype setters from intercepting set as a this value. 4980 setPrototypeOf(set, null); 4981 } 4982 if (!arrayIsArray(array)) { 4983 return set; 4984 } 4985 let l = array.length; 4986 while (l--) { 4987 let element = array[l]; 4988 if (typeof element === 'string') { 4989 const lcElement = transformCaseFunc(element); 4990 if (lcElement !== element) { 4991 // Config presets (e.g. tags.js, attrs.js) are immutable. 4992 if (!isFrozen(array)) { 4993 array[l] = lcElement; 4994 } 4995 element = lcElement; 4996 } 4997 } 4998 set[element] = true; 4999 } 5000 return set; 5001} 5002/** 5003 * Clean up an array to harden against CSPP 5004 * 5005 * @param array - The array to be cleaned. 5006 * @returns The cleaned version of the array 5007 */ 5008function cleanArray(array) { 5009 for (let index = 0; index < array.length; index++) { 5010 const isPropertyExist = objectHasOwnProperty(array, index); 5011 if (!isPropertyExist) { 5012 array[index] = null; 5013 } 5014 } 5015 return array; 5016} 5017/** 5018 * Shallow clone an object 5019 * 5020 * @param object - The object to be cloned. 5021 * @returns A new object that copies the original. 5022 */ 5023function clone(object) { 5024 const newObject = create(null); 5025 for (const _ref2 of entries(object)) { 5026 var _ref3 = _slicedToArray(_ref2, 2); 5027 const property = _ref3[0]; 5028 const value = _ref3[1]; 5029 const isPropertyExist = objectHasOwnProperty(object, property); 5030 if (isPropertyExist) { 5031 if (arrayIsArray(value)) { 5032 newObject[property] = cleanArray(value); 5033 } else if (value && typeof value === 'object' && value.constructor === Object) { 5034 newObject[property] = clone(value); 5035 } else { 5036 newObject[property] = value; 5037 } 5038 } 5039 } 5040 return newObject; 5041} 5042/** 5043 * Convert non-node values into strings without depending on direct property access. 5044 * 5045 * @param value - The value to stringify. 5046 * @returns A string representation of the provided value. 5047 */ 5048function stringifyValue(value) { 5049 switch (typeof value) { 5050 case 'string': 5051 { 5052 return value; 5053 } 5054 case 'number': 5055 { 5056 return numberToString(value); 5057 } 5058 case 'boolean': 5059 { 5060 return booleanToString(value); 5061 } 5062 case 'bigint': 5063 { 5064 return bigintToString ? bigintToString(value) : '0'; 5065 } 5066 case 'symbol': 5067 { 5068 return symbolToString ? symbolToString(value) : 'Symbol()'; 5069 } 5070 case 'undefined': 5071 { 5072 return objectToString(value); 5073 } 5074 case 'function': 5075 case 'object': 5076 { 5077 if (value === null) { 5078 return objectToString(value); 5079 } 5080 const valueAsRecord = value; 5081 const valueToString = lookupGetter(valueAsRecord, 'toString'); 5082 if (typeof valueToString === 'function') { 5083 const stringified = valueToString(valueAsRecord); 5084 return typeof stringified === 'string' ? stringified : objectToString(stringified); 5085 } 5086 return objectToString(value); 5087 } 5088 default: 5089 { 5090 return objectToString(value); 5091 } 5092 } 5093} 5094/** 5095 * This method automatically checks if the prop is function or getter and behaves accordingly. 5096 * 5097 * @param object - The object to look up the getter function in its prototype chain. 5098 * @param prop - The property name for which to find the getter function. 5099 * @returns The getter function found in the prototype chain or a fallback function. 5100 */ 5101function lookupGetter(object, prop) { 5102 while (object !== null) { 5103 const desc = getOwnPropertyDescriptor(object, prop); 5104 if (desc) { 5105 if (desc.get) { 5106 return unapply(desc.get); 5107 } 5108 if (typeof desc.value === 'function') { 5109 return unapply(desc.value); 5110 } 5111 } 5112 object = getPrototypeOf(object); 5113 } 5114 function fallbackValue() { 5115 return null; 5116 } 5117 return fallbackValue; 5118} 5119function isRegex(value) { 5120 try { 5121 regExpTest(value, ''); 5122 return true; 5123 } catch (_unused) { 5124 return false;
vendor: 8,255 bytes, lines 5125-5155
5125 } 5126} 5127 5128const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']); 5129const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']); 5130const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); 5131// List of SVG elements that are disallowed by default. 5132// We still need to know them so that we can do namespace 5133// checks properly in case one wants to add them to 5134// allow-list. 5135const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']); 5136const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']); 5137// Similarly to SVG, we want to know all MathML elements, 5138// even those that we disallow by default. 5139const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']); 5140const text = freeze(['#text']); 5141 5142const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']); 5143const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dominant-baseline', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-orientation', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']); 5144const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']); 5145const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']); 5146 5147const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g); 5148const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g); 5149const TMPLIT_EXPR = seal(/\${[\w\W]*/g); 5150const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape 5151const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape 5152const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape 5153); 5154const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); 5155const ATTR_WHITESPACE
vendor: 9,242 bytes, lines 5155-5359
5155$1 = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex 5156); 5157const DOCTYPE_NAME = seal(/^html$/i); 5158const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); 5159// Markup-significant character probes used by _sanitizeElements. 5160// Shared module-level instances are safe despite the sticky /g flags: 5161// unapply() resets lastIndex for RegExp receivers before every call. 5162const ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g); 5163const COMMENT_MARKUP_PROBE = seal(/<[/\w]/g); 5164const FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i); 5165const SELF_CLOSING_TAG = seal(/\/>/i); 5166 5167// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType 5168const NODE_TYPE = { 5169 element: 1, 5170 attribute: 2, 5171 text: 3, 5172 cdataSection: 4, 5173 entityReference: 5, 5174 // Deprecated 5175 entityNode: 6, 5176 // Deprecated 5177 processingInstruction: 7, 5178 comment: 8, 5179 document: 9, 5180 documentType: 10, 5181 documentFragment: 11, 5182 notation: 12 // Deprecated 5183}; 5184const getGlobal = function getGlobal() { 5185 return typeof window === 'undefined' ? null : window; 5186}; 5187/** 5188 * Creates a no-op policy for internal use only. 5189 * Don't export this function outside this module! 5190 * @param trustedTypes The policy factory. 5191 * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix). 5192 * @return The policy created (or null, if Trusted Types 5193 * are not supported or creating the policy failed). 5194 */ 5195const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) { 5196 if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') { 5197 return null; 5198 } 5199 // Allow the callers to control the unique policy name 5200 // by adding a data-tt-policy-suffix to the script element with the DOMPurify. 5201 // Policy creation with duplicate names throws in Trusted Types. 5202 let suffix = null; 5203 const ATTR_NAME = 'data-tt-policy-suffix'; 5204 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) { 5205 suffix = purifyHostElement.getAttribute(ATTR_NAME); 5206 } 5207 const policyName = 'dompurify' + (suffix ? '#' + suffix : ''); 5208 try { 5209 return trustedTypes.createPolicy(policyName, { 5210 createHTML(html) { 5211 return html; 5212 }, 5213 createScriptURL(scriptUrl) { 5214 return scriptUrl; 5215 } 5216 }); 5217 } catch (_) { 5218 // Policy creation failed (most likely another DOMPurify script has 5219 // already run). Skip creating the policy, as this will only cause errors 5220 // if TT are enforced. 5221 console.warn('TrustedTypes policy ' + policyName + ' could not be created.'); 5222 return null; 5223 } 5224}; 5225const _createHooksMap = function _createHooksMap() { 5226 return { 5227 afterSanitizeAttributes: [], 5228 afterSanitizeElements: [], 5229 afterSanitizeShadowDOM: [], 5230 beforeSanitizeAttributes: [], 5231 beforeSanitizeElements: [], 5232 beforeSanitizeShadowDOM: [], 5233 uponSanitizeAttribute: [], 5234 uponSanitizeElement: [], 5235 uponSanitizeShadowNode: [] 5236 }; 5237}; 5238/** 5239 * Resolve a set-valued configuration option: a fresh set built from 5240 * cfg[key] when it is an own array property (seeded with a clone of 5241 * options.base when given, case-normalized via options.transform), 5242 * the fallback set otherwise. 5243 * 5244 * @param cfg the cloned, prototype-free configuration object 5245 * @param key the configuration property to read 5246 * @param fallback the set to use when the option is absent or not an array 5247 * @param options transform and optional base set to merge into 5248 * @returns the resolved set 5249 */ 5250const _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) { 5251 return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback; 5252}; 5253function createDOMPurify() { 5254 let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); 5255 const DOMPurify = root => createDOMPurify(root); 5256 DOMPurify.version = '3.4.13'; 5257 DOMPurify.removed = []; 5258 if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { 5259 // Not running in a browser, provide a factory function 5260 // so that you can pass your own Window 5261 DOMPurify.isSupported = false; 5262 return DOMPurify; 5263 } 5264 let document = window.document; 5265 const originalDocument = document; 5266 const currentScript = originalDocument.currentScript; 5267 window.DocumentFragment; 5268 const HTMLTemplateElement = window.HTMLTemplateElement, 5269 Node = window.Node, 5270 Element = window.Element, 5271 NodeFilter = window.NodeFilter, 5272 _window$NamedNodeMap = window.NamedNodeMap; 5273 _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap; 5274 window.HTMLFormElement; 5275 const DOMParser = window.DOMParser, 5276 trustedTypes = window.trustedTypes; 5277 const ElementPrototype = Element.prototype; 5278 const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); 5279 const remove = lookupGetter(ElementPrototype, 'remove'); 5280 const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); 5281 const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); 5282 const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); 5283 const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot'); 5284 const getAttributes = lookupGetter(ElementPrototype, 'attributes'); 5285 const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null; 5286 const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null; 5287 const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, 'ownerDocument') : null; 5288 // As per issue #47, the web-components registry is inherited by a 5289 // new document created via createHTMLDocument. As per the spec 5290 // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) 5291 // a new empty registry is used when creating a template contents owner 5292 // document, so we use that as our parent document to ensure nothing 5293 // is inherited. 5294 if (typeof HTMLTemplateElement === 'function') { 5295 const template = document.createElement('template'); 5296 if (template.content && template.content.ownerDocument) { 5297 document = template.content.ownerDocument; 5298 } 5299 } 5300 let trustedTypesPolicy; 5301 let emptyHTML = ''; 5302 // The instance's own internal Trusted Types policy. Unlike a caller-supplied 5303 // `TRUSTED_TYPES_POLICY`, this is created at most once â Trusted Types throws 5304 // on duplicate policy names â and is the only policy allowed to persist 5305 // across configurations and survive `clearConfig()`. 5306 let defaultTrustedTypesPolicy; 5307 let defaultTrustedTypesPolicyResolved = false; 5308 // Tracks whether we are already inside a call to the configured Trusted Types 5309 // policy (`createHTML` or `createScriptURL`). If a supplied policy callback 5310 // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would 5311 // re-enter the policy and recurse until the stack overflows. We detect that 5312 // re-entry and throw a clear, actionable error instead. The guard is shared 5313 // across both callbacks, because either one re-entering `sanitize` triggers 5314 // the same unbounded recursion. 5315 let IN_TRUSTED_TYPES_POLICY = 0; 5316 const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() { 5317 if (IN_TRUSTED_TYPES_POLICY > 0) { 5318 throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or ' + 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' + 'infinite recursion. Do not pass a policy whose callbacks wrap ' + 'DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted ' + 'Types" section of the README.'); 5319 } 5320 }; 5321 const _createTrustedHTML = function _createTrustedHTML(html) { 5322 _assertNotInTrustedTypesPolicy(); 5323 IN_TRUSTED_TYPES_POLICY++; 5324 try { 5325 return trustedTypesPolicy.createHTML(html); 5326 } finally { 5327 IN_TRUSTED_TYPES_POLICY--; 5328 } 5329 }; 5330 const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) { 5331 _assertNotInTrustedTypesPolicy(); 5332 IN_TRUSTED_TYPES_POLICY++; 5333 try { 5334 return trustedTypesPolicy.createScriptURL(scriptUrl); 5335 } finally { 5336 IN_TRUSTED_TYPES_POLICY--; 5337 } 5338 }; 5339 // Lazily resolve (and cache) the instance's internal default policy. 5340 // Resolution is attempted at most once: a successful `createPolicy` cannot be 5341 // repeated (Trusted Types throws on duplicate names), and a failed or 5342 // unsupported attempt must not be retried on every parse. 5343 const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() { 5344 if (!defaultTrustedTypesPolicyResolved) { 5345 defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); 5346 defaultTrustedTypesPolicyResolved = true; 5347 } 5348 return defaultTrustedTypesPolicy; 5349 }; 5350 const _document = document, 5351 implementation = _document.implementation, 5352 createNodeIterator = _document.createNodeIterator, 5353 createDocumentFragment = _document.createDocumentFragment, 5354 getElementsByTagName = _document.getElementsByTagName; 5355 const importNode = originalDocument.importNode; 5356 let hooks = _createHooksMap(); 5357 /** 5358 * Expose whether this browser supports running the full DOMPurify. 5359 */
5360 DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined; 5361 const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, 5362 ERB_EXPR$1 = ERB_EXPR, 5363 TMPLIT_EXPR$1 = TMPLIT_EXPR, 5364 DATA_ATTR$1 = DATA_ATTR, 5365 ARIA_ATTR$1 = ARIA_ATTR, 5366 IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, 5367 ATTR_WHITESPACE$1$1 = ATTR_WHITESPACE$1
vendor: 25,707 bytes, lines 5367-5894
5367, 5368 CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT; 5369 let IS_ALLOWED_URI$1 = IS_ALLOWED_URI; 5370 /** 5371 * We consider the elements and attributes below to be safe. Ideally 5372 * don't add any new ones but feel free to remove unwanted ones. 5373 */ 5374 /* allowed element names */ 5375 let ALLOWED_TAGS = null; 5376 const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]); 5377 /* Allowed attribute names */ 5378 let ALLOWED_ATTR = null; 5379 const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]); 5380 /* 5381 * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements. 5382 * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements) 5383 * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list) 5384 * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`. 5385 */ 5386 let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, { 5387 tagNameCheck: { 5388 writable: true, 5389 configurable: false, 5390 enumerable: true, 5391 value: null 5392 }, 5393 attributeNameCheck: { 5394 writable: true, 5395 configurable: false, 5396 enumerable: true, 5397 value: null 5398 }, 5399 allowCustomizedBuiltInElements: { 5400 writable: true, 5401 configurable: false, 5402 enumerable: true, 5403 value: false 5404 } 5405 })); 5406 /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ 5407 let FORBID_TAGS = null; 5408 /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ 5409 let FORBID_ATTR = null; 5410 /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */ 5411 const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, { 5412 tagCheck: { 5413 writable: true, 5414 configurable: false, 5415 enumerable: true, 5416 value: null 5417 }, 5418 attributeCheck: { 5419 writable: true, 5420 configurable: false, 5421 enumerable: true, 5422 value: null 5423 } 5424 })); 5425 /* Decide if ARIA attributes are okay */ 5426 let ALLOW_ARIA_ATTR = true; 5427 /* Decide if custom data attributes are okay */ 5428 let ALLOW_DATA_ATTR = true; 5429 /* Decide if unknown protocols are okay */ 5430 let ALLOW_UNKNOWN_PROTOCOLS = false; 5431 /* Decide if self-closing tags in attributes are allowed. 5432 * Usually removed due to a mXSS issue in jQuery 3.0 */ 5433 let ALLOW_SELF_CLOSE_IN_ATTR = true; 5434 /* Output should be safe for common template engines. 5435 * This means, DOMPurify removes data attributes, mustaches and ERB 5436 */ 5437 let SAFE_FOR_TEMPLATES = false; 5438 /* Output should be safe even for XML used within HTML and alike. 5439 * This means, DOMPurify removes comments when containing risky content. 5440 */ 5441 let SAFE_FOR_XML = true; 5442 /* Decide if document with <html>... should be returned */ 5443 let WHOLE_DOCUMENT = false; 5444 /* Track whether config is already set on this instance of DOMPurify. */ 5445 let SET_CONFIG = false; 5446 /* Pristine allowlist bindings captured at setConfig() time. On the 5447 * persistent-config path sanitize() restores the sets from these before 5448 * the per-walk hook clone-guard, so a hook's in-call widening cannot 5449 * carry across calls. Null until setConfig() is called; reset by 5450 * clearConfig(). */ 5451 let SET_CONFIG_ALLOWED_TAGS = null; 5452 let SET_CONFIG_ALLOWED_ATTR = null; 5453 /* Decide if all elements (e.g. style, script) must be children of 5454 * document.body. By default, browsers might move them to document.head */ 5455 let FORCE_BODY = false; 5456 /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html 5457 * string (or a TrustedHTML object if Trusted Types are supported). 5458 * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead 5459 */ 5460 let RETURN_DOM = false; 5461 /* Decide if a DOM `DocumentFragment` should be returned, instead of a html 5462 * string (or a TrustedHTML object if Trusted Types are supported) */ 5463 let RETURN_DOM_FRAGMENT = false; 5464 /* Try to return a Trusted Type object instead of a string, return a string in 5465 * case Trusted Types are not supported */ 5466 let RETURN_TRUSTED_TYPE = false; 5467 /* Output should be free from DOM clobbering attacks? 5468 * This sanitizes markups named with colliding, clobberable built-in DOM APIs. 5469 */ 5470 let SANITIZE_DOM = true; 5471 /* Achieve full DOM Clobbering protection by isolating the namespace of named 5472 * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules. 5473 * 5474 * HTML/DOM spec rules that enable DOM Clobbering: 5475 * - Named Access on Window (§7.3.3) 5476 * - DOM Tree Accessors (§3.1.5) 5477 * - Form Element Parent-Child Relations (§4.10.3) 5478 * - Iframe srcdoc / Nested WindowProxies (§4.8.5) 5479 * - HTMLCollection (§4.2.10.2) 5480 * 5481 * Namespace isolation is implemented by prefixing `id` and `name` attributes 5482 * with a constant string, i.e., `user-content-` 5483 */ 5484 let SANITIZE_NAMED_PROPS = false; 5485 const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-'; 5486 /* Keep element content when removing element? */ 5487 let KEEP_CONTENT = true; 5488 /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead 5489 * of importing it into a new Document and returning a sanitized copy */ 5490 let IN_PLACE = false; 5491 /* Allow usage of profiles like html, svg and mathMl */ 5492 let USE_PROFILES = {}; 5493 /* Tags to ignore content of when KEEP_CONTENT is true */ 5494 let FORBID_CONTENTS = null; 5495 const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 5496 // <selectedcontent> mirrors the selected <option>'s subtree, cloned by 5497 // the UA (customizable <select>) â including any on* handlers â and the 5498 // engine re-mirrors synchronously whenever a removal changes which 5499 // option/selectedcontent is current, even inside DOMPurify's inert 5500 // DOMParser document. Hoisting its children on removal re-inserts a fresh 5501 // mirror target ahead of the walk, which the engine refills, looping 5502 // forever (DoS) and amplifying output. Dropping its content on removal 5503 // (rather than hoisting) breaks that cascade; the content is a duplicate 5504 // of the option, which is sanitized on its own. See campaign-3 F1/F6. 5505 'selectedcontent', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']); 5506 /* Tags that are safe for data: URIs */ 5507 let DATA_URI_TAGS = null; 5508 const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']); 5509 /* Attributes safe for values like "javascript:" */ 5510 let URI_SAFE_ATTRIBUTES = null; 5511 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']); 5512 const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; 5513 const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; 5514 const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; 5515 /* Document namespace */ 5516 let NAMESPACE = HTML_NAMESPACE; 5517 let IS_EMPTY_INPUT = false; 5518 /* Allowed XHTML+XML namespaces */ 5519 let ALLOWED_NAMESPACES = null; 5520 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString); 5521 const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze(['mi', 'mo', 'mn', 'ms', 'mtext']); 5522 let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); 5523 const DEFAULT_HTML_INTEGRATION_POINTS = freeze(['annotation-xml']); 5524 let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); 5525 // Certain elements are allowed in both SVG and HTML 5526 // namespace. We need to specify them explicitly 5527 // so that they don't get erroneously deleted from 5528 // HTML namespace. 5529 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']); 5530 /* Parsing of strict XHTML documents */ 5531 let PARSER_MEDIA_TYPE = null; 5532 const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html']; 5533 const DEFAULT_PARSER_MEDIA_TYPE = 'text/html'; 5534 let transformCaseFunc = null; 5535 /* Keep a reference to config to pass to hooks */ 5536 let CONFIG = null; 5537 /* Ideally, do not touch anything below this line */ 5538 /* ______________________________________________ */ 5539 const formElement = document.createElement('form'); 5540 const isRegexOrFunction = function isRegexOrFunction(testValue) { 5541 return testValue instanceof RegExp || testValue instanceof Function; 5542 }; 5543 /** 5544 * _parseConfig 5545 * 5546 * @param cfg optional config literal 5547 */ 5548 // eslint-disable-next-line complexity 5549 const _parseConfig = function _parseConfig() { 5550 let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 5551 if (CONFIG && CONFIG === cfg) { 5552 return; 5553 } 5554 /* Shield configuration object from tampering */ 5555 if (!cfg || typeof cfg !== 'object') { 5556 cfg = {}; 5557 } 5558 /* Shield configuration object from prototype pollution */ 5559 cfg = clone(cfg); 5560 PARSER_MEDIA_TYPE = 5561 // eslint-disable-next-line unicorn/prefer-includes 5562 SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE; 5563 // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is. 5564 transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase; 5565 /* Set configuration parameters */ 5566 ALLOWED_TAGS = _resolveSetOption(cfg, 'ALLOWED_TAGS', DEFAULT_ALLOWED_TAGS, { 5567 transform: transformCaseFunc 5568 }); 5569 ALLOWED_ATTR = _resolveSetOption(cfg, 'ALLOWED_ATTR', DEFAULT_ALLOWED_ATTR, { 5570 transform: transformCaseFunc 5571 }); 5572 ALLOWED_NAMESPACES = _resolveSetOption(cfg, 'ALLOWED_NAMESPACES', DEFAULT_ALLOWED_NAMESPACES, { 5573 transform: stringToString 5574 }); 5575 URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, 'ADD_URI_SAFE_ATTR', DEFAULT_URI_SAFE_ATTRIBUTES, { 5576 transform: transformCaseFunc, 5577 base: DEFAULT_URI_SAFE_ATTRIBUTES 5578 }); 5579 DATA_URI_TAGS = _resolveSetOption(cfg, 'ADD_DATA_URI_TAGS', DEFAULT_DATA_URI_TAGS, { 5580 transform: transformCaseFunc, 5581 base: DEFAULT_DATA_URI_TAGS 5582 }); 5583 FORBID_CONTENTS = _resolveSetOption(cfg, 'FORBID_CONTENTS', DEFAULT_FORBID_CONTENTS, { 5584 transform: transformCaseFunc 5585 }); 5586 FORBID_TAGS = _resolveSetOption(cfg, 'FORBID_TAGS', clone({}), { 5587 transform: transformCaseFunc 5588 }); 5589 FORBID_ATTR = _resolveSetOption(cfg, 'FORBID_ATTR', clone({}), { 5590 transform: transformCaseFunc 5591 }); 5592 USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === 'object' ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false; 5593 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true 5594 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true 5595 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false 5596 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true 5597 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false 5598 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true 5599 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false 5600 RETURN_DOM = cfg.RETURN_DOM || false; // Default false 5601 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false 5602 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false 5603 FORCE_BODY = cfg.FORCE_BODY || false; // Default false 5604 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true 5605 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false 5606 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true 5607 IN_PLACE = cfg.IN_PLACE || false; // Default false 5608 IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; // Default regexp 5609 NAMESPACE = typeof cfg.NAMESPACE === 'string' ? cfg.NAMESPACE : HTML_NAMESPACE; // Default HTML namespace 5610 MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'MATHML_TEXT_INTEGRATION_POINTS') && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === 'object' ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); // Default built-in map 5611 HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'HTML_INTEGRATION_POINTS') && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === 'object' ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); // Default built-in map 5612 const customElementHandling = objectHasOwnProperty(cfg, 'CUSTOM_ELEMENT_HANDLING') && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === 'object' ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null); 5613 CUSTOM_ELEMENT_HANDLING = create(null); 5614 if (objectHasOwnProperty(customElementHandling, 'tagNameCheck') && isRegexOrFunction(customElementHandling.tagNameCheck)) { 5615 CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined 5616 } 5617 if (objectHasOwnProperty(customElementHandling, 'attributeNameCheck') && isRegexOrFunction(customElementHandling.attributeNameCheck)) { 5618 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; // Default undefined 5619 } 5620 if (objectHasOwnProperty(customElementHandling, 'allowCustomizedBuiltInElements') && typeof customElementHandling.allowCustomizedBuiltInElements === 'boolean') { 5621 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; // Default undefined 5622 } 5623 seal(CUSTOM_ELEMENT_HANDLING); 5624 if (SAFE_FOR_TEMPLATES) { 5625 ALLOW_DATA_ATTR = false; 5626 } 5627 if (RETURN_DOM_FRAGMENT) { 5628 RETURN_DOM = true; 5629 } 5630 /* Parse profile info */ 5631 if (USE_PROFILES) { 5632 ALLOWED_TAGS = addToSet({}, text); 5633 ALLOWED_ATTR = create(null); 5634 if (USE_PROFILES.html === true) { 5635 addToSet(ALLOWED_TAGS, html$1); 5636 addToSet(ALLOWED_ATTR, html); 5637 } 5638 if (USE_PROFILES.svg === true) { 5639 addToSet(ALLOWED_TAGS, svg$1); 5640 addToSet(ALLOWED_ATTR, svg); 5641 addToSet(ALLOWED_ATTR, xml); 5642 } 5643 if (USE_PROFILES.svgFilters === true) { 5644 addToSet(ALLOWED_TAGS, svgFilters); 5645 addToSet(ALLOWED_ATTR, svg); 5646 addToSet(ALLOWED_ATTR, xml); 5647 } 5648 if (USE_PROFILES.mathMl === true) { 5649 addToSet(ALLOWED_TAGS, mathMl$1); 5650 addToSet(ALLOWED_ATTR, mathMl); 5651 addToSet(ALLOWED_ATTR, xml); 5652 } 5653 } 5654 /* Always reset function-based ADD_TAGS / ADD_ATTR checks to prevent 5655 * leaking across calls when switching from function to array config */ 5656 EXTRA_ELEMENT_HANDLING.tagCheck = null; 5657 EXTRA_ELEMENT_HANDLING.attributeCheck = null; 5658 /* Merge configuration parameters */ 5659 if (objectHasOwnProperty(cfg, 'ADD_TAGS')) { 5660 if (typeof cfg.ADD_TAGS === 'function') { 5661 EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS; 5662 } else if (arrayIsArray(cfg.ADD_TAGS)) { 5663 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { 5664 ALLOWED_TAGS = clone(ALLOWED_TAGS); 5665 } 5666 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); 5667 } 5668 } 5669 if (objectHasOwnProperty(cfg, 'ADD_ATTR')) { 5670 if (typeof cfg.ADD_ATTR === 'function') { 5671 EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR; 5672 } else if (arrayIsArray(cfg.ADD_ATTR)) { 5673 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { 5674 ALLOWED_ATTR = clone(ALLOWED_ATTR); 5675 } 5676 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); 5677 } 5678 } 5679 if (objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) { 5680 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); 5681 } 5682 if (objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS)) { 5683 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { 5684 FORBID_CONTENTS = clone(FORBID_CONTENTS); 5685 } 5686 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); 5687 } 5688 if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) { 5689 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { 5690 FORBID_CONTENTS = clone(FORBID_CONTENTS); 5691 } 5692 addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc); 5693 } 5694 /* Add #text in case KEEP_CONTENT is set to true */ 5695 if (KEEP_CONTENT) { 5696 ALLOWED_TAGS['#text'] = true; 5697 } 5698 /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */ 5699 if (WHOLE_DOCUMENT) { 5700 addToSet(ALLOWED_TAGS, ['html', 'head', 'body']); 5701 } 5702 /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */ 5703 if (ALLOWED_TAGS.table) { 5704 addToSet(ALLOWED_TAGS, ['tbody']); 5705 delete FORBID_TAGS.tbody; 5706 } 5707 // Re-derive the active Trusted Types policy from this configuration on 5708 // every parse. The active policy must never be sticky closure state that 5709 // outlives the config that set it: a caller-supplied policy left in place 5710 // after `clearConfig()` â or after a later call that supplied none, or 5711 // `TRUSTED_TYPES_POLICY: null` â could sign a subsequent "default" 5712 // `RETURN_TRUSTED_TYPE` result with a foreign, possibly unsafe policy. 5713 // See GHSA-vxr8-fq34-vvx9. 5714 if (cfg.TRUSTED_TYPES_POLICY) { 5715 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') { 5716 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.'); 5717 } 5718 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') { 5719 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.'); 5720 } 5721 // A caller-supplied policy applies to this configuration only. 5722 const previousTrustedTypesPolicy = trustedTypesPolicy; 5723 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; 5724 // Sign local variables required by `sanitize`. If the supplied policy's 5725 // `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this 5726 // throws via the re-entrancy guard. Restore the previous policy first so 5727 // the instance is not left in a poisoned state. See #1422. 5728 try { 5729 emptyHTML = _createTrustedHTML(''); 5730 } catch (error) { 5731 trustedTypesPolicy = previousTrustedTypesPolicy; 5732 throw error; 5733 } 5734 } else if (cfg.TRUSTED_TYPES_POLICY === null) { 5735 // Explicit opt-out for this call: perform no Trusted Types signing and 5736 // create nothing (so a strict `trusted-types` CSP that disallows a 5737 // `dompurify` policy can still call `sanitize` from inside its own 5738 // policy â see #1422). Resetting to `undefined` rather than a sticky 5739 // `null` also drops any previously retained caller policy, so it cannot 5740 // resurface on a later call, while still allowing the next config-less 5741 // call to restore the internal default policy. See GHSA-vxr8-fq34-vvx9. 5742 trustedTypesPolicy = undefined; 5743 emptyHTML = ''; 5744 } else { 5745 // No policy supplied: keep the currently active policy if one is set â a 5746 // previously supplied policy is intentionally sticky across config-less 5747 // calls â otherwise fall back to the instance's own internal policy, 5748 // created at most once. (A policy supplied for a *single* call still 5749 // lingers by design; what must not linger is a policy whose configuration 5750 // has been torn down via `clearConfig()`, which restores the default.) 5751 if (trustedTypesPolicy === undefined) { 5752 trustedTypesPolicy = _getDefaultTrustedTypesPolicy(); 5753 } 5754 // Sign internal variables only when a policy is active. A falsy policy 5755 // (Trusted Types unsupported, creation failed, or an explicit opt-out) 5756 // leaves `emptyHTML` as a plain string, so we never call `.createHTML` on 5757 // a non-policy and throw. See #1422. 5758 if (trustedTypesPolicy && typeof emptyHTML === 'string') { 5759 emptyHTML = _createTrustedHTML(''); 5760 } 5761 } 5762 // Prevent further manipulation of configuration. 5763 // Not available in IE8, Safari 5, etc. 5764 if (freeze) { 5765 freeze(cfg); 5766 } 5767 CONFIG = cfg; 5768 }; 5769 /* Keep track of all possible SVG and MathML tags 5770 * so that we can perform the namespace checks 5771 * correctly. */ 5772 const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]); 5773 const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]); 5774 /** 5775 * Namespace rules for an element in the SVG namespace. 5776 * 5777 * @param tagName the element's lowercase tag name 5778 * @param parent the (possibly simulated) parent node 5779 * @param parentTagName the parent's lowercase tag name 5780 * @returns true if a spec-compliant parser could produce this element 5781 */ 5782 const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) { 5783 // The only way to switch from HTML namespace to SVG 5784 // is via <svg>. If it happens via any other tag, then 5785 // it should be killed. 5786 if (parent.namespaceURI === HTML_NAMESPACE) { 5787 return tagName === 'svg'; 5788 } 5789 // The only way to switch from MathML to SVG is via <svg> 5790 // if the parent is either <annotation-xml> or a MathML 5791 // text integration point. 5792 if (parent.namespaceURI === MATHML_NAMESPACE) { 5793 return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); 5794 } 5795 // We only allow elements that are defined in SVG 5796 // spec. All others are disallowed in SVG namespace. 5797 return Boolean(ALL_SVG_TAGS[tagName]); 5798 }; 5799 /** 5800 * Namespace rules for an element in the MathML namespace. 5801 * 5802 * @param tagName the element's lowercase tag name 5803 * @param parent the (possibly simulated) parent node 5804 * @param parentTagName the parent's lowercase tag name 5805 * @returns true if a spec-compliant parser could produce this element 5806 */ 5807 const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) { 5808 // The only way to switch from HTML namespace to MathML 5809 // is via <math>. If it happens via any other tag, then 5810 // it should be killed. 5811 if (parent.namespaceURI === HTML_NAMESPACE) { 5812 return tagName === 'math'; 5813 } 5814 // The only way to switch from SVG to MathML is via 5815 // <math> and HTML integration points 5816 if (parent.namespaceURI === SVG_NAMESPACE) { 5817 return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName]; 5818 } 5819 // We only allow elements that are defined in MathML 5820 // spec. All others are disallowed in MathML namespace. 5821 return Boolean(ALL_MATHML_TAGS[tagName]); 5822 }; 5823 /** 5824 * Namespace rules for an element in the HTML namespace. 5825 * 5826 * @param tagName the element's lowercase tag name 5827 * @param parent the (possibly simulated) parent node 5828 * @param parentTagName the parent's lowercase tag name 5829 * @returns true if a spec-compliant parser could produce this element 5830 */ 5831 const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) { 5832 // The only way to switch from SVG to HTML is via 5833 // HTML integration points, and from MathML to HTML 5834 // is via MathML text integration points 5835 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { 5836 return false; 5837 } 5838 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { 5839 return false; 5840 } 5841 // We disallow tags that are specific for MathML 5842 // or SVG and should never appear in HTML namespace 5843 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); 5844 }; 5845 /** 5846 * @param element a DOM element whose namespace is being checked 5847 * @returns Return false if the element has a 5848 * namespace that a spec-compliant parser would never 5849 * return. Return true otherwise. 5850 */ 5851 const _checkValidNamespace = function _checkValidNamespace(element) { 5852 let parent = getParentNode(element); 5853 // In JSDOM, if we're inside shadow DOM, then parentNode 5854 // can be null. We just simulate parent in this case. 5855 if (!parent || !parent.tagName) { 5856 parent = { 5857 namespaceURI: NAMESPACE, 5858 tagName: 'template' 5859 }; 5860 } 5861 const tagName = stringToLowerCase(element.tagName); 5862 const parentTagName = stringToLowerCase(parent.tagName); 5863 if (!ALLOWED_NAMESPACES[element.namespaceURI]) { 5864 return false; 5865 } 5866 if (element.namespaceURI === SVG_NAMESPACE) { 5867 return _checkSvgNamespace(tagName, parent, parentTagName); 5868 } 5869 if (element.namespaceURI === MATHML_NAMESPACE) { 5870 return _checkMathMlNamespace(tagName, parent, parentTagName); 5871 } 5872 if (element.namespaceURI === HTML_NAMESPACE) { 5873 return _checkHtmlNamespace(tagName, parent, parentTagName); 5874 } 5875 // For XHTML and XML documents that support custom namespaces 5876 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) { 5877 return true; 5878 } 5879 // The code should never reach this place (this means 5880 // that the element somehow got namespace that is not 5881 // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES). 5882 // Return false just in case. 5883 return false; 5884 }; 5885 /** 5886 * _forceRemove 5887 * 5888 * @param node a DOM node 5889 */ 5890 const _forceRemove = function _forceRemove(node) { 5891 arrayPush(DOMPurify.removed, { 5892 element: node 5893 }); 5894 try {
vendor: 12,552 bytes, lines 5895-6182
5895 // eslint-disable-next-line unicorn/prefer-dom-node-remove 5896 getParentNode(node).removeChild(node); 5897 } catch (_) { 5898 /* The normal detach failed â this is reached for a parentless node 5899 (getParentNode() is null, so .removeChild throws). Element.prototype 5900 .remove() is itself a spec no-op on a parentless node, so a recorded 5901 "removal" would otherwise hand the caller back an intact, 5902 payload-bearing node (e.g. a detached IN_PLACE root the mXSS canary or 5903 the style-with-element-child rule decided to kill). Fail closed by 5904 throwing â exactly as a clobbered root does at the IN_PLACE entry â 5905 rather than trying to "neutralize" the node via its own methods. 5906 Neutralizing would mean calling getAttributeNames()/removeAttribute() 5907 on the node, both of which a <form> root can clobber via a named child 5908 (and _isClobbered does not even probe getAttributeNames), so the 5909 neutralize step could itself be silently defeated, leaving the payload 5910 intact. A throw touches only the cached, clobber-safe remove() and 5911 getParentNode(). Generalizes GHSA-r47g-fvhr-h676 (clobbered-form root) 5912 to every root-kill reason. REPORT-3. 5913 This lives inside the catch, so it never fires for a normally-removed 5914 in-tree node: those have a parent, removeChild() succeeds, and the 5915 catch is not entered. Only a kept (parentless) root reaches here. */ 5916 remove(node); 5917 if (!getParentNode(node)) { 5918 throw typeErrorCreate('a node selected for removal could not be detached from its tree ' + 'and cannot be safely returned; refusing to sanitize in place'); 5919 } 5920 } 5921 }; 5922 /** 5923 * _neutralizeRoot 5924 * 5925 * Fail-closed teardown of an in-place root after the sanitize walk aborts 5926 * (campaign-3 F2). An internal throw mid-walk â e.g. a page-registered 5927 * custom element's reaction detaches a node so `_forceRemove`'s deliberate 5928 * parentless guard throws, or any other re-entrant engine mutation â would 5929 * otherwise leave the caller's *live* tree half-sanitized, with everything 5930 * after the abort point still carrying its handlers. There is no safe way 5931 * to resume the walk (the tree mutated under us), so we strip the root bare: 5932 * remove every child and every attribute, then let the caller's catch see 5933 * the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes` 5934 * getters; the root was already clobber-pre-flighted at the IN_PLACE entry). 5935 * 5936 * @param root the in-place root to empty 5937 */ 5938 const _neutralizeRoot = function _neutralizeRoot(root) { 5939 /* Strip every disallowed attribute (on* handlers included) off the whole 5940 subtree BEFORE detaching anything. Detaching first would hand back 5941 handler-bearing originals (e.g. an already-loading `<img onerror>`) 5942 whose queued resource event still fires in page scope after we throw. 5943 Clobber-safe reads; a doomed clobbered node's own attributes are 5944 irrelevant while its non-clobbered descendants are reached and scrubbed. */ 5945 _neutralizeSubtree(root); 5946 const childNodes = getChildNodes(root); 5947 if (childNodes) { 5948 const snapshot = []; 5949 arrayForEach(childNodes, child => { 5950 arrayPush(snapshot, child); 5951 }); 5952 arrayForEach(snapshot, child => { 5953 try { 5954 remove(child); 5955 } catch (_) { 5956 /* Best-effort teardown; a still-attached child is handled below */ 5957 } 5958 }); 5959 } 5960 const attributes = getAttributes(root); 5961 if (attributes) { 5962 for (let i = attributes.length - 1; i >= 0; --i) { 5963 const attribute = attributes[i]; 5964 const name = attribute && attribute.name; 5965 if (typeof name === 'string') { 5966 try { 5967 root.removeAttribute(name); 5968 } catch (_) { 5969 /* Clobbered removeAttribute â ignore (fail-closed best effort) */ 5970 } 5971 } 5972 } 5973 } 5974 }; 5975 /** 5976 * _removeAttribute 5977 * 5978 * @param name an Attribute name 5979 * @param element a DOM node 5980 */ 5981 const _removeAttribute = function _removeAttribute(name, element) { 5982 try { 5983 arrayPush(DOMPurify.removed, { 5984 attribute: element.getAttributeNode(name), 5985 from: element 5986 }); 5987 } catch (_) { 5988 arrayPush(DOMPurify.removed, { 5989 attribute: null, 5990 from: element 5991 }); 5992 } 5993 element.removeAttribute(name); 5994 // We void attribute values for unremovable "is" attributes 5995 if (name === 'is') { 5996 if (RETURN_DOM || RETURN_DOM_FRAGMENT) { 5997 try { 5998 _forceRemove(element); 5999 } catch (_) {} 6000 } else { 6001 try { 6002 element.setAttribute(name, ''); 6003 } catch (_) {} 6004 } 6005 } 6006 }; 6007 /** 6008 * _stripDisallowedAttributes 6009 * 6010 * Removes every attribute the active configuration does not allow from a 6011 * single element, using the same allowlist as the main attribute pass (so 6012 * `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to 6013 * neutralise nodes that are being discarded from an in-place tree. 6014 * 6015 * @param element the element to strip 6016 */ 6017 const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) { 6018 const attributes = getAttributes(element); 6019 if (!attributes) { 6020 return; 6021 } 6022 for (let i = attributes.length - 1; i >= 0; --i) { 6023 const attribute = attributes[i]; 6024 const name = attribute && attribute.name; 6025 if (typeof name !== 'string' || ALLOWED_ATTR[transformCaseFunc(name)]) { 6026 continue; 6027 } 6028 try { 6029 element.removeAttribute(name); 6030 } catch (_) { 6031 /* Clobbered removeAttribute on a doomed node â ignore */ 6032 } 6033 } 6034 }; 6035 /** 6036 * _neutralizeSubtree 6037 * 6038 * Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT 6039 * move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary, 6040 * namespace, comment, processing-instruction and KEEP_CONTENT:false removals 6041 * all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path 6042 * those dropped nodes are detached from the caller's LIVE tree but a 6043 * handler-bearing original among them (an `<img onerror>`/`<video>` that was 6044 * loading) keeps its queued resource event, which fires in page scope after 6045 * sanitize returns. This walks a removed subtree and strips every attribute 6046 * the active configuration does not allow â so `on*` handlers are cancelled 6047 * through the SAME allowlist that governs kept nodes, not a separate `/^on/` 6048 * blocklist. Run synchronously before sanitize returns, i.e. before any 6049 * queued event can fire. Hook-free by design: these nodes leave the output, 6050 * so firing attribute hooks for them would be surprising. Clobber-safe reads; 6051 * a doomed clobbered node may shadow `removeAttribute` (its own attributes are 6052 * irrelevant â it is discarded â while its non-clobbered descendants, e.g. 6053 * the `<img>`, are reached and scrubbed). 6054 * 6055 * @param root the root of a removed subtree to neutralise 6056 */ 6057 const _neutralizeSubtree = function _neutralizeSubtree(root) { 6058 const stack = [root]; 6059 while (stack.length > 0) { 6060 const node = stack.pop(); 6061 const nodeType = getNodeType ? getNodeType(node) : node.nodeType; 6062 if (nodeType === NODE_TYPE.element) { 6063 _stripDisallowedAttributes(node); 6064 } 6065 const childNodes = getChildNodes(node); 6066 if (childNodes) { 6067 for (let i = childNodes.length - 1; i >= 0; --i) { 6068 stack.push(childNodes[i]); 6069 } 6070 } 6071 } 6072 }; 6073 /** 6074 * _neutralizePatchLinkage 6075 * 6076 * IN_PLACE entry pre-pass (declarative-partial-updates / streaming 6077 * hardening, https://github.com/WICG/declarative-partial-updates). 6078 * 6079 * The main walk strips patch linkage (`for`/`patchsrc`) and removes range 6080 * markers (PIs / markup comments) node-by-node, in document order, AS it 6081 * reaches each node. On a live in-place root that leaves a window: from the 6082 * moment the root is connected until the walk arrives at a given node, that 6083 * node's linkage is live. A patch applied on connection/stream can fire as 6084 * a microtask during the walk and inject or teleport an unsanitized DOM 6085 * range into a region the iterator has already passed and will not revisit, 6086 * so the post-return "tree is sanitized" contract is violated. Sweep the 6087 * whole tree once up front and sever every linkage before the walk begins, 6088 * closing that window. 6089 * 6090 * This CANNOT undo a patch that already fired before sanitize ran â that is 6091 * the irreducible "do not IN_PLACE a live-connected attacker tree" caveat â 6092 * but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML 6093 * to group with the rest of the declarative-partial-updates handling and 6094 * stay overridable, consistent with the codebase. 6095 * 6096 * Clobber-safe traversal (cached childNodes getter); per-node try/catch so a 6097 * clobbered root cannot defeat the sweep of its non-clobbered descendants. 6098 * 6099 * NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe 6100 * .html Q1): this mirrors the existing policy of keeping `for` on 6101 * <label>/<output>. If the shipping feature can drive a patch through a 6102 * surviving `for`-on-label/output + `id` pair, this pre-pass and the 6103 * attribute check at _isBasicCustomElement's caller must additionally drop 6104 * that pair on the IN_PLACE path. Left as-is until the taxonomy is verified. 6105 * 6106 * @param root the in-place root to sweep 6107 */ 6108 const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) { 6109 if (!SAFE_FOR_XML) { 6110 return; 6111 } 6112 const stack = [root]; 6113 while (stack.length > 0) { 6114 const node = stack.pop(); 6115 const nodeType = getNodeType ? getNodeType(node) : node.nodeType; 6116 /* Remove range markers (the target side of a patch linkage): every 6117 processing instruction, and any markup-bearing comment. */ 6118 if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) { 6119 try { 6120 remove(node); 6121 } catch (_) { 6122 /* Best-effort */ 6123 } 6124 continue; 6125 } 6126 /* Strip patch-source attributes (the source side) off elements. */ 6127 if (nodeType === NODE_TYPE.element) { 6128 const element = node; 6129 const lcTag = transformCaseFunc(getNodeName ? getNodeName(node) : node.nodeName); 6130 try { 6131 if (element.hasAttribute && element.hasAttribute('patchsrc')) { 6132 element.removeAttribute('patchsrc'); 6133 } 6134 if (element.hasAttribute && element.hasAttribute('for') && lcTag !== 'label' && lcTag !== 'output') { 6135 element.removeAttribute('for'); 6136 } 6137 } catch (_) { 6138 /* Clobbered removeAttribute/hasAttribute on a doomed node â ignore */ 6139 } 6140 } 6141 const childNodes = getChildNodes(node); 6142 if (childNodes) { 6143 for (let i = childNodes.length - 1; i >= 0; --i) { 6144 stack.push(childNodes[i]); 6145 } 6146 } 6147 } 6148 }; 6149 /** 6150 * _initDocument 6151 * 6152 * @param dirty - a string of dirty markup 6153 * @return a DOM, filled with the dirty markup 6154 */ 6155 const _initDocument = function _initDocument(dirty) { 6156 /* Create a HTML document */ 6157 let doc = null; 6158 let leadingWhitespace = null; 6159 if (FORCE_BODY) { 6160 dirty = '<remove></remove>' + dirty; 6161 } else { 6162 /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */ 6163 const matches = stringMatch(dirty, /^[\r\n\t ]+/); 6164 leadingWhitespace = matches && matches[0]; 6165 } 6166 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) { 6167 // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict) 6168 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>'; 6169 } 6170 const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty; 6171 /* 6172 * Use the DOMParser API by default, fallback later if needs be 6173 * DOMParser not work for svg when has multiple root element. 6174 */ 6175 if (NAMESPACE === HTML_NAMESPACE) { 6176 try { 6177 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); 6178 } catch (_) {} 6179 } 6180 /* Use createHTMLDocument in case DOMParser is not available */ 6181 if (!doc || !doc.documentElement) { 6182 doc = implementation.createDocument(NAMESPACE, 'template', null);
vendor: 10,704 bytes, lines 6183-6396
6183 try { 6184 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload; 6185 } catch (_) { 6186 // Syntax error if dirtyPayload is invalid xml 6187 } 6188 } 6189 const body = doc.body || doc.documentElement; 6190 if (dirty && leadingWhitespace) { 6191 body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null); 6192 } 6193 /* Work on whole document or just its body */ 6194 if (NAMESPACE === HTML_NAMESPACE) { 6195 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0]; 6196 } 6197 return WHOLE_DOCUMENT ? doc.documentElement : body; 6198 }; 6199 /** 6200 * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. 6201 * 6202 * @param root The root element or node to start traversing on. 6203 * @return The created NodeIterator 6204 */ 6205 const _createNodeIterator = function _createNodeIterator(root) { 6206 /* Read ownerDocument through the cached Node.prototype getter, never the 6207 direct property. HTMLFormElement has [LegacyOverrideBuiltIns], so a 6208 clobbering child (<input name="ownerDocument"> or a form-associated 6209 external input) shadows the prototype getter and makes a direct read 6210 return that <input>. createNodeIterator.call(<input>, ...) then throws 6211 "Illegal invocation", and on the IN_PLACE path that throw lands before 6212 the walk's fail-closed barrier - leaving the caller's live tree, with 6213 any already-armed handler in it, un-neutralized. The cached getter 6214 returns the real Document regardless of the clobber. */ 6215 const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument; 6216 return createNodeIterator.call(doc || root, root, 6217 // eslint-disable-next-line no-bitwise 6218 NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null); 6219 }; 6220 /** 6221 * Replace template expression syntax (mustache, ERB, template 6222 * literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub 6223 * sites. Order matters: mustache, then ERB, then template literal. 6224 * 6225 * @param value the string to scrub 6226 * @returns the scrubbed string 6227 */ 6228 const _stripTemplateExpressions = function _stripTemplateExpressions(value) { 6229 value = stringReplace(value, MUSTACHE_EXPR$1, ' '); 6230 value = stringReplace(value, ERB_EXPR$1, ' '); 6231 value = stringReplace(value, TMPLIT_EXPR$1, ' '); 6232 return value; 6233 }; 6234 /** 6235 * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the 6236 * character data of an element subtree. Used as the final safety net for 6237 * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions 6238 * which only form after text-node normalization (e.g. fragments split across 6239 * stripped elements) cannot survive into a template-evaluating framework. 6240 * 6241 * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data` 6242 * in place rather than round-tripping through innerHTML. This preserves 6243 * descendant node references (important for IN_PLACE callers), avoids a 6244 * serialize/reparse cycle, and reads literal character data â which means 6245 * `<%...%>` in text content matches the ERB regex against its real bytes 6246 * instead of the HTML-entity-escaped form innerHTML would produce. 6247 * 6248 * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for 6249 * attributes is performed during the per-node `_sanitizeAttributes` pass. 6250 * 6251 * @param node The root element whose character data should be scrubbed. 6252 */ 6253 const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) { 6254 var _node$querySelectorAl; 6255 node.normalize(); 6256 /* Clobber-safe ownerDocument read, same reasoning as _createNodeIterator: 6257 under SAFE_FOR_TEMPLATES this runs on the live IN_PLACE root, which may 6258 carry a form-named-getter override of ownerDocument. */ 6259 const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument; 6260 const walker = createNodeIterator.call(doc || node, node, 6261 // eslint-disable-next-line no-bitwise 6262 NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null); 6263 let currentNode = walker.nextNode(); 6264 while (currentNode) { 6265 currentNode.data = _stripTemplateExpressions(currentNode.data); 6266 currentNode = walker.nextNode(); 6267 } 6268 // NodeIterator does not descend into <template>.content per the DOM spec, 6269 // so we must explicitly recurse into each template's content fragment, 6270 // mirroring the approach used by _sanitizeShadowDOM. 6271 const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, 'template'); 6272 if (templates) { 6273 arrayForEach(templates, tmpl => { 6274 if (_isDocumentFragment(tmpl.content)) { 6275 _scrubTemplateExpressions2(tmpl.content); 6276 } 6277 }); 6278 } 6279 }; 6280 /** 6281 * _isClobbered 6282 * 6283 * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML 6284 * interface with [LegacyOverrideBuiltIns]; a descendant element with a 6285 * `name` attribute matching a prototype property shadows that property 6286 * on direct reads. We use this check at the IN_PLACE entry-point and 6287 * during attribute sanitization to refuse clobbered forms. 6288 * 6289 * @param element element to check for clobbering attacks 6290 * @return true if clobbered, false if safe 6291 */ 6292 const _isClobbered = function _isClobbered(element) { 6293 // Realm-independent tag-name probe. If we can't determine the tag 6294 // name at all, we can't reason about clobbering â return false 6295 // (the caller's other defences still apply). 6296 const realTagName = getNodeName ? getNodeName(element) : null; 6297 if (typeof realTagName !== 'string') { 6298 return false; 6299 } 6300 if (transformCaseFunc(realTagName) !== 'form') { 6301 return false; 6302 } 6303 return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || 6304 // Realm-safe NamedNodeMap detection: equality against the cached 6305 // prototype getter. Clobbered .attributes (e.g. <input name="attributes">) 6306 // makes the direct read diverge from the cached read; a clean form 6307 // (same-realm OR foreign-realm) has both reads pointing at the same 6308 // canonical NamedNodeMap. 6309 element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' || 6310 // NodeType clobbering probe. Cached Node.prototype.nodeType getter 6311 // returns the integer 1 for any Element regardless of realm; direct 6312 // read on a clobbered form (e.g. <input name="nodeType">) returns 6313 // the named child element. Cheap addition â nodeType is read from 6314 // an internal slot, no serialization cost â and removes a residual 6315 // clobbering surface used by several mXSS / PI / comment branches 6316 // in _sanitizeElements that compare currentNode.nodeType directly. 6317 element.nodeType !== getNodeType(element) || 6318 // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named 6319 // "childNodes" shadows the prototype getter. Direct reads of 6320 // form.childNodes from a clobbered form return the named child 6321 // instead of the real NodeList, so any walk that reads it directly 6322 // skips the form's real children. Compare the direct read to the 6323 // cached Node.prototype getter â when the form's named-property 6324 // getter intercepts the read, the two values differ and we flag 6325 // the form. This catches every clobbering child type (input, 6326 // select, etc.) regardless of whether the named child happens to 6327 // carry a numeric .length, which a typeof-based probe would miss 6328 // (e.g. HTMLSelectElement.length is a defined unsigned-long). 6329 element.childNodes !== getChildNodes(element); 6330 }; 6331 /** 6332 * Checks whether the given value is a DocumentFragment from any realm. 6333 * 6334 * The realm-independent replacement reads `nodeType` through the cached 6335 * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE 6336 * constant (11). nodeType is a numeric value resolved from the node's 6337 * internal slot, identical across realms for the same kind of node. 6338 * 6339 * @param value object to check 6340 * @return true if value is a DocumentFragment-shaped node from any realm 6341 */ 6342 const _isDocumentFragment = function _isDocumentFragment(value) { 6343 if (!getNodeType || typeof value !== 'object' || value === null) { 6344 return false; 6345 } 6346 try { 6347 return getNodeType(value) === NODE_TYPE.documentFragment; 6348 } catch (_) { 6349 return false; 6350 } 6351 }; 6352 /** 6353 * Checks whether the given object is a DOM node, including nodes that 6354 * originate from a different window/realm (e.g. an iframe's 6355 * contentDocument). The previous `value instanceof Node` check was 6356 * realm-bound: nodes from a different window failed it, causing 6357 * sanitize() to silently stringify them and reset IN_PLACE to false, 6358 * returning the original node unsanitized. See GHSA-4w3q-35jp-p934. 6359 * 6360 * @param value object to check whether it's a DOM node 6361 * @return true if value is a DOM node from any realm 6362 */ 6363 const _isNode = function _isNode(value) { 6364 if (!getNodeType || typeof value !== 'object' || value === null) { 6365 return false; 6366 } 6367 try { 6368 return typeof getNodeType(value) === 'number'; 6369 } catch (_) { 6370 return false; 6371 } 6372 }; 6373 function _executeHooks(hooks, currentNode, data) { 6374 if (hooks.length === 0) { 6375 return; 6376 } 6377 arrayForEach(hooks, hook => { 6378 hook.call(DOMPurify, currentNode, data, CONFIG); 6379 }); 6380 } 6381 /** 6382 * Structural-threat checks that condemn a node regardless of the 6383 * allowlists: mXSS via namespace confusion, risky CSS construction, 6384 * processing instructions, markup-bearing comments. Pure predicate; 6385 * the caller removes. Check order is load-bearing. 6386 * 6387 * @param currentNode the node to inspect 6388 * @param tagName the node's transformCaseFunc'd tag name 6389 * @return true if the node must be removed 6390 */ 6391 const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) { 6392 /* Detect mXSS attempts abusing namespace confusion */ 6393 if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) { 6394 return true; 6395 } 6396 /* Remove r
vendor: 1,737 bytes, lines 6396-6431
6396isky CSS construction leading to mXSS */ 6397 if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) { 6398 return true; 6399 } 6400 /* Remove any occurrence of processing instructions */ 6401 if (currentNode.nodeType === NODE_TYPE.processingInstruction) { 6402 return true; 6403 } 6404 /* Remove any kind of possibly harmful comments */ 6405 if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) { 6406 return true; 6407 } 6408 return false; 6409 }; 6410 /** 6411 * Handle a node whose tag is forbidden or not allowlisted: keep 6412 * allowed custom elements (false return exits _sanitizeElements 6413 * early - the namespace and fallback-tag removal checks are 6414 * intentionally skipped for kept custom elements), else hoist 6415 * content per KEEP_CONTENT and remove. 6416 * 6417 * A kept custom element is the ONLY case in which this function 6418 * returns false, so the caller uses that return value to run the 6419 * afterSanitizeElements hook on the kept element and keep the 6420 * element-hook lifecycle consistent with normal allowlisted 6421 * elements (GHSA-c2j3-45gr-mqc4). 6422 * 6423 * @param currentNode the disallowed node 6424 * @param tagName the node's transformCaseFunc'd tag name 6425 * @return true if the node was removed, false if kept 6426 */ 6427 const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) { 6428 /* Check if we have a custom element to handle */ 6429 if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) { 6430 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) { 6431 return false;
6432 } 6433 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) { 6434 return false; 6435 } 6436 } 6437 /* Keep content except for bad-listed elements. 6438 Use the cached prototype getters exclusively â the previous code 6439 had `|| currentNode.parentNode` / `|| currentNode.childNodes` 6440 fallbacks, but the cached getters always return the canonical 6441 value (or null for a real parent-less node), so the fallback 6442 path was dead in safe cases and a clobbering surface in unsafe 6443 ones. Falsy cached results stay falsy; the `if (childNodes && 6444 parentNode)` check already gates correctly. */ 6445 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { 6446 const parentNode = getParentNode(currentNode); 6447 const childNodes = getChildNodes(currentNode); 6448 if (childNodes && parentNode) { 6449 const childCount = childNodes.length; 6450 /* Hoist by moving each child up one level rather than deep-cloning 6451 it. Moving transfers every descendant exactly once, so a chain of 6452 nested disallowed elements costs O(n) instead of the O(n^2) that 6453 re-cloning the shrinking subtree at each level produced; it also 6454 empties the removed original, so `DOMPurify.removed` no longer 6455 pins whole subtrees. Moving preserves the in-place guarantee too: 6456 an original carrying already-queued resource events (`<img 6457 onerror>`, `<video>`/`<audio>` error, lazy/`onload`, â¦) is 6458 relocated and sanitised rather than left detached but still armed. 6459 The sole case that must clone is removing the walk root itself. 6460 The result is serialised from the root's subtree, so a restrictive 6461 ALLOWED_TAGS that strips the root (`body` on the string path) must 6462 leave the content inside it, which only cloning does. In IN_PLACE 6463 the root is pre-validated as an allowed tag and so is never removed 6464 here, so that path always takes the move branch. 6465 `childNodes` is live; a tail-to-head walk keeps `childNodes[i]` 6466 valid whether we move (drops the trailing entry) or clone (leaves 6467 the list intact). */ 6468 for (let i = childCount - 1; i >= 0; --i) { 6469 const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i]; 6470 parentNode.insertBefore(hoisted, getNextSibling(currentNode)); 6471 } 6472 } 6473 } 6474 _forceRemove(currentNode); 6475 return true; 6476 }; 6477 /** 6478 * Fork a hook-mutable allowlist off its shared binding the first time a 6479 * (possibly lazily-installed) uponSanitize* hook is about to see it, so the 6480 * hook cannot widen the per-instance default or the setConfig binding by 6481 * reference and leak past the call. Returns the set unchanged once it is 6482 * already call-local, so repeated calls across elements are idempotent. 6483 * 6484 * @param hookList the uponSanitize* hook array for this event 6485 * @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding 6486 * @param defaultSet the per-instance DEFAULT_ALLOWED_* constant 6487 * @param setConfigSet the captured setConfig() binding, or null 6488 * @return a call-local clone if a hook is present and set is still shared, 6489 * else set unchanged 6490 */ 6491 const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) { 6492 if (hookList.length === 0) { 6493 return set; 6494 } 6495 return set === defaultSet || set === setConfigSet ? clone(set) : set; 6496 }; 6497 /** 6498 * _sanitizeElements 6499 * 6500 * @protect nodeName 6501 * @protect textContent 6502 * @protect removeChild 6503 * @param currentNode to check for permission to exist 6504 * @return true if node was killed, false if left alive 6505 */ 6506 // eslint-disable-next-line complexity 6507 const _sanitizeElements = function _sanitizeElements(currentNode, root) { 6508 /* Execute a hook if present */ 6509 _executeHooks(hooks.beforeSanitizeElements, currentNode, null); 6510 /* A hook may have detached the node - treat it as removed (see the 6511 detached-node comment after the uponSanitizeElement hook below). On 6512 the IN_PLACE path, neutralize the detached subtree first so a queued 6513 resource handler on it cannot fire in page scope after we return. */ 6514 if (currentNode !== root && getParentNode(currentNode) === null) { 6515 if (IN_PLACE) { 6516 _neutralizeSubtree(currentNode); 6517 } 6518 return true; 6519 } 6520 /* Check if element is clobbered or can clobber */ 6521 if (_isClobbered(currentNode)) { 6522 _forceRemove(currentNode); 6523 return true; 6524 } 6525 /* Now let's check the element's type and name */
6526 const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName); 6527 /* Close the pre-walk clone-guard's timing gap: an uponSanitizeElement 6528 hook may have been installed after that guard sampled the hook arrays 6529 (e.g. lazily from beforeSanitizeElements), leaving ALLOWED_TAGS still 6530 aliasing a shared binding that a widening hook would mutate by 6531 reference. Fork it before exposing it to the hook. */ 6532 ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS); 6533 /* Execute a hook if present */ 6534 _executeHooks(hooks.uponSanitizeElement, currentNode, { 6535 tagName, 6536 allowedTags: ALLOWED_TAGS 6537 }); 6538 /* A hook may have detached the node from the tree â a long-standing 6539 user pattern (issue #469; draw.io-style foreignObject filtering). 6540 Per the cached, unclobberable parentNode getter the node is 6541 genuinely out of the tree, so it can reach neither the serialized 6542 output nor an IN_PLACE live tree; treat it as removed and stop 6543 processing it. Without this guard, the unsafe-node / namespace 6544 checks below would call _forceRemove on a parentless node and hit 6545 the REPORT-3 fail-closed throw â which exists for nodes DOMPurify 6546 wants gone but *cannot* detach (clobbered / parentless roots), the 6547 opposite of a node that is already safely gone. The walk root is 6548 exempt: a detached IN_PLACE root is legitimate input and must still 6549 be fully sanitized, and a kill-decision on it must keep hitting the 6550 REPORT-3 throw. Nodes detached by hooks stay the hook's 6551 responsibility for placement: they are not recorded in 6552 DOMPurify.removed, so the post-walk IN_PLACE pass (which iterates 6553 DOMPurify.removed) does not reach them. But a hook-detached subtree 6554 can still hold a queued resource-event handler - e.g. an <img onload> 6555 that began loading when the caller built the live tree - which fires 6556 in page scope after sanitize returns even though the handler never 6557 reached the returned tree. That is the audit-5 F1 hazard, and the 6558 documented node.remove() hook pattern walks straight into it. So on 6559 the IN_PLACE path we neutralize the detached subtree inline here, 6560 stripping its non-allow-listed attributes before returning, exactly 6561 as the post-walk pass does for _forceRemove'd subtrees. */ 6562 if (currentNode !== root && getParentNode(currentNode) === null) { 6563 if (IN_PLACE) { 6564 _neutralizeSubtree(currentNode); 6565 } 6566 return true; 6567 } 6568 /* Remove mXSS vectors, processing instructions and risky comments */ 6569 if (_isUnsafeNode(currentNode, tagName)) { 6570 _forceRemove(currentNode); 6571 return true; 6572 } 6573 /* Remove element if anything forbids its presence */ 6574 if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) { 6575 const removed = _sanitizeDisallowedNode(currentNode, tagName, root
vendor: 7,065 bytes, lines 6575-6685
6575); 6576 /* A false return means the node is a custom element kept via 6577 CUSTOM_ELEMENT_HANDLING - the only keep path through 6578 _sanitizeDisallowedNode. Run afterSanitizeElements on it so the 6579 element-hook lifecycle matches normal allowlisted elements: a 6580 security policy applied in this hook (e.g. stripping an attribute 6581 from every surviving element) must not silently skip kept custom 6582 elements (GHSA-c2j3-45gr-mqc4). This mirrors the normal-element 6583 tail below - the hook runs, then the walker's subsequent 6584 _sanitizeAttributes pass sanitizes the element's attributes. The 6585 deliberately skipped namespace and fallback-tag removal checks stay 6586 skipped; they are removal decisions, not the hook contract. */ 6587 if (removed === false) { 6588 _executeHooks(hooks.afterSanitizeElements, currentNode, null); 6589 } 6590 return removed; 6591 } 6592 /* Check whether element has a valid namespace. 6593 Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype 6594 nodeType getter rather than `instanceof Element`, which is realm- 6595 bound and short-circuits to false for any node minted in a different 6596 realm â letting a foreign-realm element with a forbidden namespace 6597 slip past the namespace check entirely. */ 6598 const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType; 6599 if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { 6600 _forceRemove(currentNode); 6601 return true; 6602 } 6603 /* Make sure that older browsers don't get fallback-tag mXSS */ 6604 if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) { 6605 _forceRemove(currentNode); 6606 return true; 6607 } 6608 /* Sanitize element content to be template-safe */ 6609 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { 6610 /* Get the element's text content */ 6611 const content = _stripTemplateExpressions(currentNode.textContent); 6612 if (currentNode.textContent !== content) { 6613 arrayPush(DOMPurify.removed, { 6614 element: currentNode.cloneNode() 6615 }); 6616 currentNode.textContent = content; 6617 } 6618 } 6619 /* Execute a hook if present */ 6620 _executeHooks(hooks.afterSanitizeElements, currentNode, null); 6621 return false; 6622 }; 6623 /** 6624 * _isValidAttribute 6625 * 6626 * @param lcTag Lowercase tag name of containing element. 6627 * @param lcName Lowercase attribute name. 6628 * @param value Attribute value. 6629 * @return Returns true if `value` is valid, otherwise false. 6630 */ 6631 // eslint-disable-next-line complexity 6632 const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { 6633 /* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */ 6634 if (FORBID_ATTR[lcName]) { 6635 return false; 6636 } 6637 /* Reject declarative-partial-updates patch-linkage attributes 6638 (https://github.com/WICG/declarative-partial-updates). 6639 Empirical note (Chrome 150, verified â see 6640 test/declarative-patch-probe-v3.html): expansion is NOT applied after 6641 sanitization. For the string path it fires during sanitize()'s own 6642 parse, so the walk sees and sanitizes the fully materialized expanded 6643 tree â teleports into MathML/SVG integration points included; a 6644 weaponized `<template for>`->`<img onerror>` comes back with the handler 6645 stripped. For the IN_PLACE path it fires on connection, before the walk. 6646 Either way DOMPurify is NOT blind to the patch. 6647 This removal is therefore defense-in-depth rather than the sole barrier: 6648 it prevents live linkage from surviving into the OUTPUT and re-expanding 6649 in the caller's context, and keeps behaviour deterministic if a future 6650 engine defers expansion. `for` is legitimate only on <label>/<output>; 6651 anywhere else (notably <template for>) it links the element to a patch 6652 target and teleports or removes an arbitrary DOM range by id/marker name. 6653 `patchsrc` fetches remote markup and is treated as a script-loading 6654 mechanism (CSP). Gated on SAFE_FOR_XML so the removal groups with the 6655 other structural-threat checks and stays overridable, consistent with 6656 the rest of the codebase. PI range markers are already removed by 6657 _isUnsafeNode. */ 6658 if (SAFE_FOR_XML && lcName === 'patchsrc') { 6659 return false; 6660 } 6661 if (SAFE_FOR_XML && lcName === 'for' && lcTag !== 'label' && lcTag !== 'output') { 6662 return false; 6663 } 6664 /* Make sure attribute cannot clobber */ 6665 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) { 6666 return false; 6667 } 6668 const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag); 6669 /* Allow valid data-* attributes: At least one character after "-" 6670 (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) 6671 XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) 6672 We don't need to check the value; it's always URI safe. */ 6673 if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!nameIsPermitted) { 6674 if ( 6675 // First condition does a very basic check if a) it's basically a valid custom element tagname AND 6676 // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck 6677 // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck 6678 _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) || 6679 // Alternative, second condition checks if it's an `is`-attribute, AND 6680 // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck 6681 lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else { 6682 return false; 6683 } 6684 /* Check value is safe. First, is attr inert? If so, is safe */ 6685 } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1
vendor: 4,485 bytes, lines 6685-6782
6685$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1$1, ''))) ; else if (value) { 6686 return false; 6687 } else ; 6688 return true; 6689 }; 6690 /* Names the HTML spec reserves from valid-custom-element-name; these must 6691 * never be treated as basic custom elements even when a permissive 6692 * CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */ 6693 const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ['annotation-xml', 'color-profile', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'missing-glyph']); 6694 /** 6695 * _isBasicCustomElement 6696 * checks if at least one dash is included in tagName, and it's not the first char 6697 * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name 6698 * 6699 * @param tagName name of the tag of the node to sanitize 6700 * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false. 6701 */ 6702 const _isBasicCustomElement = function _isBasicCustomElement(tagName) { 6703 return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName); 6704 }; 6705 /** 6706 * Wrap an attribute value in the matching Trusted Types object when 6707 * the active policy requires it. Namespaced attributes pass through 6708 * unchanged (no TT support yet, see 6709 * https://bugs.chromium.org/p/chromium/issues/detail?id=1305293). 6710 * 6711 * @param lcTag lowercase tag name of the containing element 6712 * @param lcName lowercase attribute name 6713 * @param namespaceURI the attribute's namespace, if any 6714 * @param value the attribute value to wrap 6715 * @return the value, wrapped when Trusted Types demand it 6716 */ 6717 const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) { 6718 if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function' && !namespaceURI) { 6719 switch (trustedTypes.getAttributeType(lcTag, lcName)) { 6720 case 'TrustedHTML': 6721 { 6722 return _createTrustedHTML(value); 6723 } 6724 case 'TrustedScriptURL': 6725 { 6726 return _createTrustedScriptURL(value); 6727 } 6728 } 6729 } 6730 return value; 6731 }; 6732 /** 6733 * Write a modified attribute value back onto the element. On 6734 * success, re-probe for clobbering introduced by the new value and 6735 * remove the element when found; otherwise pop the removal entry 6736 * recorded by the earlier _removeAttribute (long-standing pairing 6737 * with the SANITIZE_NAMED_PROPS path - do not "fix" casually). On 6738 * failure, remove the attribute instead. 6739 * 6740 * @param currentNode the element carrying the attribute 6741 * @param name the attribute name as present on the element 6742 * @param namespaceURI the attribute's namespace, if any 6743 * @param value the new attribute value 6744 */ 6745 const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) { 6746 try { 6747 if (namespaceURI) { 6748 currentNode.setAttributeNS(namespaceURI, name, value); 6749 } else { 6750 /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */ 6751 currentNode.setAttribute(name, value); 6752 } 6753 if (_isClobbered(currentNode)) { 6754 _forceRemove(currentNode); 6755 } else { 6756 arrayPop(DOMPurify.removed); 6757 } 6758 } catch (_) { 6759 _removeAttribute(name, currentNode); 6760 } 6761 }; 6762 /** 6763 * _sanitizeAttributes 6764 * 6765 * @protect attributes 6766 * @protect nodeName 6767 * @protect removeAttribute 6768 * @protect setAttribute 6769 * 6770 * @param currentNode to sanitize 6771 */ 6772 const _sanitizeAttributes = function _sanitizeAttributes(currentNode) { 6773 /* Execute a hook if present */ 6774 _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null); 6775 const attributes = currentNode.attributes; 6776 /* Check if we have attributes; if not we might have a text node */ 6777 if (!attributes || _isClobbered(currentNode)) { 6778 return; 6779 } 6780 /* Same lazy-install guard as uponSanitizeElement (see there): fork the 6781 attribute allowlist off its shared binding before a hook can see it. */ 6782 ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
vendor: 5,961 bytes, lines 6782-6917
6782 6783 const hookEvent = { 6784 attrName: '', 6785 attrValue: '', 6786 keepAttr: true, 6787 allowedAttributes: ALLOWED_ATTR, 6788 forceKeepAttr: undefined 6789 }; 6790 let l = attributes.length; 6791 const lcTag = transformCaseFunc(currentNode.nodeName); 6792 /* Go backwards over all attributes; safely remove bad ones */ 6793 while (l--) { 6794 const attr = attributes[l]; 6795 const name = attr.name, 6796 namespaceURI = attr.namespaceURI, 6797 attrValue = attr.value; 6798 const lcName = transformCaseFunc(name); 6799 const initValue = attrValue; 6800 let value = name === 'value' ? initValue : stringTrim(initValue); 6801 /* Execute a hook if present */ 6802 hookEvent.attrName = lcName; 6803 hookEvent.attrValue = value; 6804 hookEvent.keepAttr = true; 6805 hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set 6806 _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent); 6807 value = hookEvent.attrValue; 6808 /* Full DOM Clobbering protection via namespace isolation, 6809 * Prefix id and name attributes with `user-content-` 6810 */ 6811 if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name') && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) { 6812 // Remove the attribute with this value 6813 _removeAttribute(name, currentNode); 6814 // Prefix the value and later re-create the attribute with the sanitized value 6815 value = SANITIZE_NAMED_PROPS_PREFIX + value; 6816 } 6817 // Else: already prefixed, leave the attribute alone â the prefix is 6818 // itself the clobbering protection, and re-applying it is incorrect. 6819 /* Work around a security issue with comments inside attributes */ 6820 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) { 6821 _removeAttribute(name, currentNode); 6822 continue; 6823 } 6824 /* Make sure we cannot easily use animated hrefs, even if animations are allowed */ 6825 if (lcName === 'attributename' && stringMatch(value, 'href')) { 6826 _removeAttribute(name, currentNode); 6827 continue; 6828 } 6829 /* Did the hooks force-keep the attribute? */ 6830 if (hookEvent.forceKeepAttr) { 6831 continue; 6832 } 6833 /* Did the hooks approve of the attribute? */ 6834 if (!hookEvent.keepAttr) { 6835 _removeAttribute(name, currentNode); 6836 continue; 6837 } 6838 /* Work around a security issue in jQuery 3.0 */ 6839 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) { 6840 _removeAttribute(name, currentNode); 6841 continue; 6842 } 6843 /* Sanitize attribute content to be template-safe */ 6844 if (SAFE_FOR_TEMPLATES) { 6845 value = _stripTemplateExpressions(value); 6846 } 6847 /* Is `value` valid for this attribute? */ 6848 if (!_isValidAttribute(lcTag, lcName, value)) { 6849 _removeAttribute(name, currentNode); 6850 continue; 6851 } 6852 /* Handle attributes that require Trusted Types */ 6853 value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value); 6854 /* Handle invalid data-* attribute set by try-catching it */ 6855 if (value !== initValue) { 6856 _setAttributeValue(currentNode, name, namespaceURI, value); 6857 } 6858 } 6859 /* Execute a hook if present */ 6860 _executeHooks(hooks.afterSanitizeAttributes, currentNode, null); 6861 }; 6862 /** 6863 * _sanitizeShadowDOM 6864 * 6865 * @param fragment to iterate over recursively 6866 */ 6867 const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) { 6868 let shadowNode = null; 6869 const shadowIterator = _createNodeIterator(fragment); 6870 /* Execute a hook if present */ 6871 _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null); 6872 while (shadowNode = shadowIterator.nextNode()) { 6873 /* Execute a hook if present */ 6874 _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null); 6875 /* Sanitize tags and elements */ 6876 _sanitizeElements(shadowNode, fragment); 6877 /* Check attributes next */ 6878 _sanitizeAttributes(shadowNode); 6879 /* Deep shadow DOM detected. 6880 Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the 6881 DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we 6882 recurse into <template>.content from foreign realms too. */ 6883 if (_isDocumentFragment(shadowNode.content)) { 6884 _sanitizeShadowDOM2(shadowNode.content); 6885 } 6886 /* An element iterated here may itself host an attached 6887 shadow root. The default NodeIterator does not enter shadow 6888 trees, so a shadow root nested inside template.content was 6889 previously reached by no walk at all (the pre-pass at 6890 _sanitizeAttachedShadowRoots descends via childNodes, which 6891 doesn't enter template.content; the template-content recursion 6892 above iterates the content but never inspected shadowRoot). 6893 Walk it explicitly. The nodeType guard avoids reading 6894 shadowRoot off text / comment / CDATA / PI nodes that the 6895 iterator also surfaces. */ 6896 const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType; 6897 if (shadowNodeType === NODE_TYPE.element) { 6898 const innerSr = getShadowRoot(shadowNode); 6899 if (_isDocumentFragment(innerSr)) { 6900 _sanitizeAttachedShadowRoots(innerSr); 6901 _sanitizeShadowDOM2(innerSr); 6902 } 6903 } 6904 } 6905 /* Execute a hook if present */ 6906 _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null); 6907 }; 6908 /** 6909 * _sanitizeAttachedShadowRoots 6910 * 6911 * Walks `root` and feeds every attached shadow root we encounter into 6912 * the existing _sanitizeShadowDOM pipeline. The default node iterator 6913 * does not descend into shadow trees, so nodes inside an attached 6914 * shadow root would otherwise be skipped entirely. 6915 * 6916 * Two real input paths put attached shadow roots in front of us: 6917 * 1. IN_PLACE on a DOM node that already has shadow roots attached.
vendor: 3,953 bytes, lines 6918-7007
6918 * 2. DOM-node input where importNode(dirty, true) deep-clones the 6919 * shadow root because it was created with `clonable: true`. 6920 * 6921 * This pass runs once, up front, so the main iteration loop (and the 6922 * existing _sanitizeShadowDOM template-content recursion) stay 6923 * untouched â string-input paths are not affected. 6924 * 6925 * @param root the subtree root to walk for attached shadow roots 6926 */ 6927 const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) { 6928 /* Iterative (explicit stack) rather than per-child recursion. DOM APIs 6929 impose no depth cap, so an attacker-shaped tree (JSON/CRDT/editor data 6930 built straight into the DOM â the IN_PLACE surface) deeper than the JS 6931 call-stack budget would otherwise overflow native recursion here and 6932 throw at the IN_PLACE entry pre-pass, before a single node is 6933 sanitized, leaving the caller's live tree untouched (fail-open). See 6934 campaign-3 F4. A heap stack keeps depth off the call stack. 6935 Each work item is either a node to descend into, or a deferred 6936 `_sanitizeShadowDOM` for an already-walked shadow root. The deferred 6937 form preserves the original post-order discipline: a shadow root's 6938 nested shadow roots are discovered before the outer shadow is 6939 sanitized (which may remove hosts). Pushes are in reverse of the 6940 desired processing order (LIFO): template content, then children, then 6941 the shadow-sanitize, then the shadow walk â so the order matches the 6942 previous recursion exactly. */ 6943 const stack = [{ 6944 node: root, 6945 shadow: null 6946 }]; 6947 while (stack.length > 0) { 6948 const item = stack.pop(); 6949 /* Deferred shadow-DOM sanitisation: runs after its subtree was walked. */ 6950 if (item.shadow) { 6951 _sanitizeShadowDOM2(item.shadow); 6952 continue; 6953 } 6954 const node = item.node; 6955 const nodeType = getNodeType ? getNodeType(node) : node.nodeType; 6956 const isElement = nodeType === NODE_TYPE.element; 6957 /* (pushed last â processed first) Children, snapshotted in reverse so 6958 the first child is processed first. Snapshotting matters because a 6959 hook may detach siblings mid-walk. */ 6960 const childNodes = getChildNodes(node); 6961 if (childNodes) { 6962 for (let i = childNodes.length - 1; i >= 0; --i) { 6963 stack.push({ 6964 node: childNodes[i], 6965 shadow: null 6966 }); 6967 } 6968 } 6969 /* (pushed before children â processed after them, matching the old 6970 "template content last" order) When the node is a <template>, 6971 descend into its content. */ 6972 if (isElement) { 6973 const rootName = getNodeName ? getNodeName(node) : null; 6974 if (typeof rootName === 'string' && transformCaseFunc(rootName) === 'template') { 6975 const content = node.content; 6976 if (_isDocumentFragment(content)) { 6977 stack.push({ 6978 node: content, 6979 shadow: null 6980 }); 6981 } 6982 } 6983 } 6984 /* Shadow root (processed first): walk its subtree, then sanitise it. 6985 Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection 6986 rather than `instanceof DocumentFragment`, which is realm-bound and 6987 silently skipped foreign-realm shadow roots (e.g. 6988 iframe.contentDocument attachShadow). */ 6989 if (isElement) { 6990 const sr = getShadowRoot(node); 6991 if (_isDocumentFragment(sr)) { 6992 /* Push the deferred sanitise first so it pops after the shadow 6993 walk we push next, i.e. nested shadow roots are discovered 6994 before this one is sanitised. */ 6995 stack.push({ 6996 node: null, 6997 shadow: sr 6998 }, { 6999 node: sr, 7000 shadow: null 7001 }); 7002 } 7003 } 7004 } 7005 }; 7006 // eslint-disable-next-line complexity 7007 DOMPurify.sanitize = function (dirty) {
vendor: 5,221 bytes, lines 7008-7105
7008 let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 7009 let body = null; 7010 let importedNode = null; 7011 let currentNode = null; 7012 let returnNode = null; 7013 /* Make sure we have a string to sanitize. 7014 DO NOT return early, as this will return the wrong type if 7015 the user has requested a DOM object rather than a string */ 7016 IS_EMPTY_INPUT = !dirty; 7017 if (IS_EMPTY_INPUT) { 7018 dirty = '<!-->'; 7019 } 7020 /* Stringify, in case dirty is an object */ 7021 if (typeof dirty !== 'string' && !_isNode(dirty)) { 7022 dirty = stringifyValue(dirty); 7023 if (typeof dirty !== 'string') { 7024 throw typeErrorCreate('dirty is not a string, aborting'); 7025 } 7026 } 7027 /* Return dirty HTML if DOMPurify cannot run */ 7028 if (!DOMPurify.isSupported) { 7029 return dirty; 7030 } 7031 /* Assign config vars */ 7032 if (SET_CONFIG) { 7033 /* Persistent setConfig() path: _parseConfig is skipped, so the sets are 7034 * not re-derived per call. Restore them from the pristine bindings 7035 * captured at setConfig() time so a previous call's hook clone (mutated 7036 * below) does not carry over. */ 7037 ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS; 7038 ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR; 7039 } else { 7040 _parseConfig(cfg); 7041 } 7042 /* Clone the hook-mutable allowlists before the walk whenever an 7043 * uponSanitize* hook is registered. The hook event exposes ALLOWED_TAGS 7044 * and ALLOWED_ATTR by reference (as allowedTags / allowedAttributes), so 7045 * a hook that widens them would otherwise mutate the shared set 7046 * permanently: across later calls and across every element. Cloning per 7047 * walk keeps documented in-call widening working while scoping it to the 7048 * call. A single guard for both config paths - the per-call path rebinds 7049 * the sets in _parseConfig each call, the persistent path restores them 7050 * from the captured bindings just above - so the two cannot diverge. */ 7051 if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) { 7052 ALLOWED_TAGS = clone(ALLOWED_TAGS); 7053 } 7054 if (hooks.uponSanitizeAttribute.length > 0) { 7055 ALLOWED_ATTR = clone(ALLOWED_ATTR); 7056 } 7057 /* Clean up removed elements */ 7058 DOMPurify.removed = []; 7059 /* Resolve IN_PLACE for this call without mutating persistent config. 7060 Writing the IN_PLACE closure variable here leaks under setConfig(), 7061 where _parseConfig is skipped on later calls: a single string call would 7062 disable in-place mode for every subsequent node call, returning a 7063 sanitized copy while leaving the caller's node â which in-place callers 7064 keep using and whose return value they ignore â unsanitized. REPORT-2. */ 7065 const inPlace = IN_PLACE && typeof dirty !== 'string' && _isNode(dirty); 7066 if (inPlace) { 7067 /* Declarative-partial-updates / streaming pre-pass: sever every patch 7068 linkage across the live tree BEFORE the walk, so no patch can fire 7069 mid-walk and inject into an already-processed region. Runs first, so 7070 it also covers the forbidden/clobbered roots that throw below. */ 7071 _neutralizePatchLinkage(dirty); 7072 /* Do some early pre-sanitization to avoid unsafe root nodes. 7073 Read nodeName through the cached prototype getter â a clobbering 7074 child named "nodeName" on the form root would otherwise shadow 7075 the property and let this check skip the root-allowlist 7076 validation entirely. */ 7077 const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName; 7078 if (typeof nn === 'string') { 7079 const tagName = transformCaseFunc(nn); 7080 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { 7081 /* Fail closed on a live root: neutralize handlers/children before 7082 throwing, exactly as the mid-walk abort path does. */ 7083 _neutralizeRoot(dirty); 7084 throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place'); 7085 } 7086 } 7087 /* Pre-flight the root through _isClobbered. The iterator-driven 7088 removal path can not detach a parent-less root: _forceRemove 7089 falls through to Element.prototype.remove(), which per spec 7090 is a no-op on a node with no parent. A clobbered root would 7091 then survive the main loop with its attributes uninspected, 7092 because _sanitizeAttributes early-returns on _isClobbered. The 7093 result would be an attacker-controlled form, complete with any 7094 event-handler attributes the caller passed in, handed back to 7095 the application unsanitized. Refuse to sanitize such a root 7096 the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */ 7097 if (_isClobbered(dirty)) { 7098 /* Fail closed on a live clobbered root before throwing. 7099 _neutralizeRoot's reads are clobber-safe (cached getters); the 7100 form's non-clobbered descendants, e.g. an armed <img>, are scrubbed. */ 7101 _neutralizeRoot(dirty); 7102 throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place'); 7103 } 7104 /* Sanitize attached shadow roots before the main iterator runs. 7105 The iterator does not descend into shadow trees. Same fail-closed
vendor: 5,016 bytes, lines 7106-7210
7106 barrier as the main walk (campaign-3 F2): a custom-element reaction 7107 inside a shadow root could abort this pre-pass before the walk runs, 7108 which would otherwise leave the entire live tree unsanitized. */ 7109 try { 7110 _sanitizeAttachedShadowRoots(dirty); 7111 } catch (error) { 7112 _neutralizeRoot(dirty); 7113 throw error; 7114 } 7115 } else if (_isNode(dirty)) { 7116 /* If dirty is a DOM element, append to an empty document to avoid 7117 elements being stripped by the parser */ 7118 body = _initDocument('<!---->'); 7119 importedNode = body.ownerDocument.importNode(dirty, true); 7120 if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') { 7121 /* Node is already a body, use as is */ 7122 body = importedNode; 7123 } else if (importedNode.nodeName === 'HTML') { 7124 body = importedNode; 7125 } else { 7126 // eslint-disable-next-line unicorn/prefer-dom-node-append 7127 body.appendChild(importedNode); 7128 } 7129 /* Clonable shadow roots are deep-cloned by importNode(); sanitize 7130 them before the main iterator runs, since the iterator does not 7131 descend into shadow trees. The walk routes every read through a 7132 cached prototype getter so clobbering descendants on a form root 7133 cannot hide a shadow host from this pass. */ 7134 _sanitizeAttachedShadowRoots(importedNode); 7135 } else { 7136 /* Exit directly if we have nothing to do */ 7137 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && 7138 // eslint-disable-next-line unicorn/prefer-includes 7139 dirty.indexOf('<') === -1) { 7140 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty; 7141 } 7142 /* Initialize the document to work on */ 7143 body = _initDocument(dirty); 7144 /* Check we have a DOM node from the data */ 7145 if (!body) { 7146 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : ''; 7147 } 7148 } 7149 /* Remove first element node (ours) if FORCE_BODY is set */ 7150 if (body && FORCE_BODY) { 7151 _forceRemove(body.firstChild); 7152 } 7153 /* Get node iterator */ 7154 const walkRoot = inPlace ? dirty : body; 7155 /* Now start iterating over the created document. 7156 The walk runs inside an exception barrier (campaign-3 F2): a re-entrant 7157 engine/custom-element mutation can detach a node mid-walk so 7158 `_forceRemove`'s parentless guard throws, aborting the loop. Without the 7159 barrier the caller's in-place tree would be left half-sanitized with the 7160 unvisited tail still armed. _createNodeIterator itself is inside the 7161 barrier too: constructing the iterator dereferences the root's document, 7162 and any failure there (e.g. an exotic/clobbered root) must still fail 7163 closed rather than skip the neutralize. On any throw we fail closed - 7164 strip the in-place root bare - then rethrow so the existing throw 7165 contract is preserved. (String/DOM-copy paths never return the partial 7166 body, so the propagating throw is already fail-closed there.) */ 7167 try { 7168 const nodeIterator = _createNodeIterator(walkRoot); 7169 while (currentNode = nodeIterator.nextNode()) { 7170 /* Sanitize tags and elements */ 7171 _sanitizeElements(currentNode, walkRoot); 7172 /* Check attributes next */ 7173 _sanitizeAttributes(currentNode); 7174 /* Shadow DOM detected, sanitize it. 7175 Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection 7176 instead of instanceof, so foreign-realm <template>.content is 7177 walked correctly. */ 7178 if (_isDocumentFragment(currentNode.content)) { 7179 _sanitizeShadowDOM2(currentNode.content); 7180 } 7181 } 7182 } catch (error) { 7183 if (inPlace) { 7184 _neutralizeRoot(dirty); 7185 /* Nodes _forceRemove'd earlier in the aborted walk are already 7186 detached from the root, so _neutralizeRoot's subtree pass does not 7187 reach them. Defuse them too, mirroring the success-path loop below. */ 7188 arrayForEach(DOMPurify.removed, entry => { 7189 if (entry.element) { 7190 _neutralizeSubtree(entry.element); 7191 } 7192 }); 7193 } 7194 throw error; 7195 } 7196 /* If we sanitized `dirty` in-place, return it. */ 7197 if (inPlace) { 7198 /* Fail-closed completion of the audit-5 F1 fix: every node removed from 7199 the caller's live tree is detached but may still hold a queued 7200 resource-event handler that fires in page scope after we return. The 7201 move-hoist covers only disallowed-tag KEEP_CONTENT removals; strip the 7202 non-allow-listed attributes off every other removed subtree (clobber, 7203 mXSS, namespace, comments, KEEP_CONTENT:false, â¦) so those handlers are 7204 cancelled before any event can fire. Runs synchronously, pre-return. */ 7205 arrayForEach(DOMPurify.removed, entry => { 7206 if (entry.element) { 7207 _neutralizeSubtree(entry.element); 7208 } 7209 }); 7210 if (SAFE_FOR_TEMPLATES) {
vendor: 4,041 bytes, lines 7211-7315
7211 _scrubTemplateExpressions2(dirty); 7212 } 7213 return dirty; 7214 } 7215 /* Return sanitized string or DOM */ 7216 if (RETURN_DOM) { 7217 if (SAFE_FOR_TEMPLATES) { 7218 _scrubTemplateExpressions2(body); 7219 } 7220 if (RETURN_DOM_FRAGMENT) { 7221 returnNode = createDocumentFragment.call(body.ownerDocument); 7222 while (body.firstChild) { 7223 // eslint-disable-next-line unicorn/prefer-dom-node-append 7224 returnNode.appendChild(body.firstChild); 7225 } 7226 } else { 7227 returnNode = body; 7228 } 7229 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) { 7230 /* 7231 AdoptNode() is not used because internal state is not reset 7232 (e.g. the past names map of a HTMLFormElement), this is safe 7233 in theory but we would rather not risk another attack vector. 7234 The state that is cloned by importNode() is explicitly defined 7235 by the specs. 7236 */ 7237 returnNode = importNode.call(originalDocument, returnNode, true); 7238 } 7239 return returnNode; 7240 } 7241 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; 7242 /* Serialize doctype if allowed */ 7243 if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) { 7244 serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML; 7245 } 7246 /* Sanitize final string template-safe */ 7247 if (SAFE_FOR_TEMPLATES) { 7248 serializedHTML = _stripTemplateExpressions(serializedHTML); 7249 } 7250 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML; 7251 }; 7252 DOMPurify.setConfig = function () { 7253 let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 7254 _parseConfig(cfg); 7255 SET_CONFIG = true; 7256 SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS; 7257 SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR; 7258 }; 7259 DOMPurify.clearConfig = function () { 7260 CONFIG = null; 7261 SET_CONFIG = false; 7262 SET_CONFIG_ALLOWED_TAGS = null; 7263 SET_CONFIG_ALLOWED_ATTR = null; 7264 // Drop any caller-supplied Trusted Types policy so it cannot poison later 7265 // `RETURN_TRUSTED_TYPE` output. The internal default policy (cached, and 7266 // never recreated â Trusted Types throws on duplicate names) is restored by 7267 // the next `_parseConfig`. See GHSA-vxr8-fq34-vvx9. 7268 trustedTypesPolicy = defaultTrustedTypesPolicy; 7269 emptyHTML = ''; 7270 }; 7271 DOMPurify.isValidAttribute = function (tag, attr, value) { 7272 /* Initialize shared config vars if necessary. */ 7273 if (!CONFIG) { 7274 _parseConfig({}); 7275 } 7276 const lcTag = transformCaseFunc(tag); 7277 const lcName = transformCaseFunc(attr); 7278 return _isValidAttribute(lcTag, lcName, value); 7279 }; 7280 DOMPurify.addHook = function (entryPoint, hookFunction) { 7281 if (typeof hookFunction !== 'function') { 7282 return; 7283 } 7284 /* Reject unknown entry points. Without this, a non-hook key (e.g. 7285 * '__proto__') indexes off the prototype chain rather than a real 7286 * hook array, and arrayPush then writes to Object.prototype. Guard 7287 * with an own-property check against the known hook names. */ 7288 if (!objectHasOwnProperty(hooks, entryPoint)) { 7289 return; 7290 } 7291 arrayPush(hooks[entryPoint], hookFunction); 7292 }; 7293 DOMPurify.removeHook = function (entryPoint, hookFunction) { 7294 if (!objectHasOwnProperty(hooks, entryPoint)) { 7295 return undefined; 7296 } 7297 if (hookFunction !== undefined) { 7298 const index = arrayLastIndexOf(hooks[entryPoint], hookFunction); 7299 return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0]; 7300 } 7301 return arrayPop(hooks[entryPoint]); 7302 }; 7303 DOMPurify.removeHooks = function (entryPoint) { 7304 if (!objectHasOwnProperty(hooks, entryPoint)) { 7305 return; 7306 } 7307 hooks[entryPoint] = []; 7308 }; 7309 DOMPurify.removeAllHooks = function () { 7310 hooks = _createHooksMap(); 7311 }; 7312 return DOMPurify; 7313} 7314var purify = createDOMPurify(); 7315
7316/** 7317 * Copyright (c) Meta Platforms, Inc. and affiliates. 7318 * 7319 * This source code is licensed under the MIT license found in the 7320 * LICENSE file in the root directory of this source tree. 7321 * 7322 */ 7323 7324function t(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);throw n.search=r.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function e(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);n.search=r.toString(),console.warn(`Minified Lexical warning #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`);}const n="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,r$1=n&&"documentMode"in document?document.documentMode:null,i=n&&/Mac|iPod|iPhone|iPad/.test(navigator.platform),o$1=n&&/^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent),s$1=!(!n||!("InputEvent"in window)||r$1)&&"getTargetRanges"in new window.InputEvent("input"),l=n&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,c=n&&/Android/.test(navigator.userAgent),a$1=n&&/Version\/[\d.]+.*Safari/.test(navigator.userAgent)&&!c,u=n&&/^(?=.*Chrome).*/i.test(navigator.userAgent),f=n&&c&&u,d$1=n&&/AppleWebKit\/[\d.]+/.test(navigator.userAgent)&&i&&!u,h$1=0,g=1,_$3=2,p=1,y$1=2,m$1=4,x$1=8,C$4=16,S$1=32,v$1=64,k$3=128,T$2=2047,N$3=1,b$3=2,w$3=3,E$4=4,O$4=5,M$5=6,A$3=a$1||l||d$1?"\xa0":"\u200b",D$4="\n\n",P$3=o$1?"\xa0":A$3,F$7="\u0591-\u07ff\ufb1d-\ufdfd\ufe70-\ufefc",L$5="A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff",I$6=new RegExp("^[^"+L$5+"]*["+F$7+"]"),K$4=new RegExp("^[^"+F$7+"]*["+L$5+"]"),z$7={bold:1,capitalize:1024,code:16,highlight:k$3,italic:2,lowercase:256,strikethrough:4,subscript:32,superscript:64,underline:8,uppercase:512},R$4={directionless:1,unmergeable:2},B$5={center:2,end:6,justify:4,left:1,right:3,start:5}
7324,W$5={[b$3]:"center",[M$5]:"end",[E$4]:"justify",[N$3]:"left",[w$3]:"right",[O$4]:"start"},$$4={normal:0,segmented:2,token:1},J$7={[h$1]:"normal",[_$3]:"segmented",[g]:"token"},j$7="$",U$6="$config";let V$7 = class V{_front=new Set;_back=new Set;_cache;get size(){return this._front.size+this._back.size}addBack(t){return delete this._cache,this._front.has(t)||this._back.add(t),this}addFront(t){return delete this._cache,this._back.has(t)||this._front.add(t),this}delete(t){return delete this._cache,this._front.delete(t)||this._back.delete(t)}toArray(){const t=Array.from(this._front).reverse();for(const e of this._back)t.push(e);return t}toReadonlyArray(){return this._cache=this._cache||this.toArray(),this._cache}[Symbol.iterator](){return this.toReadonlyArray()[Symbol.iterator]()}};function Y$5(t,e,n,r,i,o){let s=t.getFirstChild();for(;null!==s;){const t=s.__key;s.__parent===e&&(Wi(s)&&Y$5(s,t,n,r,i,o),n.has(t)||o.delete(t),i.push(t)),s=s.getNextSibling();}}let q$7=false,H$7=0;function G$a(t){H$7=t.timeStamp;}function X$6(t,e,n){const r="BR"===t.nodeName,i=e.__lexicalLineBreak;return i&&(t===i||r&&t.previousSibling===i)||r&&void 0!==Ho(t,n)}function Q$9(t,e,n){const r=Js(Ps(n));let i=null,o=null;null!==r&&r.anchorNode===t&&(i=r.anchorOffset,o=r.focusOffset);const s=t.nodeValue;null!==s&&cs(e,s,i,o,false);}function Z$5(t,e,n){if(Fr(t)){const e=t.anchor.getNode();if(e.is(n)&&t.format!==e.getFormat())return false}return Ko(e)&&n.isAttached()}function tt$4(t,e,n,r){for(let i=t;i&&!cl(i);i=bs(i)){const t=Ho(i,e);if(void 0!==t){const e=Yo(t,n);if(e)return ji(e)||!Ys(i)?void 0:[i,e]}else if(i===r)return [r,ts(n)]}}function et$2(t,e,n){q$7=true;const r=performance.now()-H$7>100;try{Ki(t,()=>{const i=Qr()||function(t){return t.getEditorState().read(()=>{const t=Qr();return null!==t?t.clone():null})}(t),s=new Map,l=t.getRootElement(),c=t._editorState,a=t._blockCursorElement;let u=!1,f="";for(let n=0;n<e.length;n++){const d=e[n],h=d.type,g=d.target,_=tt$4(g,t,c,l);if(!_)continue;const[p,y]=_;if("characterData"===h)r&&Tr(y)&&Ko(g)&&Z$5(i,g,y)&&Q$9(g,y,t);else if("childList"===h){u=!0;const e=d.addedNodes;for(let n=0;n<e.length;n++){const r=e[n],i=qo(r),s=r.parentNode;if(null!=s&&r!==a&&null===i&&!X$6(r,s,t)){if(o$1){const t=(Ys(r)?r.innerText:null)||r.nodeValue;t&&(f+=t);}s.removeChild(r);}}const n=d.removedNodes,r=n.length;if(r>0){let e=0;for(let i=0;i<r;i++){const r=n[i];(X$6(r,g,t)||a===r)&&(g.appendChild(r),e++);}r!==e&&s.set(p,y);}}}if(s.size>0)for(const[e,n]of s)n.reconcileObservedMutation(e,t);const d=n.takeRecords();if(d.length>0){for(let e=0;e<d.length;e++){const n=d[e],r=n.addedNodes,i=n.target;for(let e=0;e<r.length;e++){const n=r[e],o=n.parentNode;null==o||"BR"!==n.nodeName||X$6(n,i,t)||o.removeChild(n);}}n.takeRecords();}null!==i&&(u&&es(i),o$1&&ks(t)&&i.insertRawText(f));});}finally{q$7=false;}}function nt$4(t){const e=t._observer;if(null!==e){et$2(t,e.takeRecords(),e);}}function rt$4(t){!function(t){0===H$7&&Ps(t).addEventListener("textInput",G$a,true);}(t),t._observer=new MutationObserver((e,n)=>{et$2(t,e,n);});}let it$2 = class it{key;parse;unparse;isEqual;defaultValue;resetOnCopyNode;constructor(t,e){this.key=t,this.parse=e.parse.bind(e),this.unparse=(e.unparse||gt$3).bind(e),this.isEqual=(e.isEqual||Object.is).bind(e),this.defaultValue=this.parse(void 0),this.resetOnCopyNode=e.resetOnCopyNode||false;}};function ot$3(t,e){return new it$2(t,e)}function st$2(t,e,n="latest"){const r=("latest"===n?t.getLatest():t).__state;return r?r.getValue(e):e.defaultValue}function lt$3(t,e,n){const r=st$2(t,n,"direct"),i=st$2(e,n,"direct");return n.isEqual(r,i)?null:[r,i]}function ct$2(t,e,n){let r;if(xi(),"function"==typeof n){const i=t.getLatest(),o=st$2(i,e);if(r=n(o),e.isEqual(o,r))return i}else r=n;const i=t.getWritable();return ft$2(i).updateFromKnown(e,r),i}function at$3(t){const e=new Map,n=new Set;for(let r="function"==typeof t?t:t.replace;r.prototype&&void 0!==r.prototype.getType;r=Object.getPrototypeOf(r)){const{ownNodeConfig:t}=ul(r);if(t&&t.stateConfigs)for(const r of t.stateConfigs){let t;"stateConfig"in r?(t=r.stateConfig,r.flat&&n.add(t.key)):t=r,e.set(t.key,t);}}return {flatKeys:n,sharedConfigMap:e}}let ut$3 = class ut{node;knownState;unknownState;sharedNodeState;size;constructor(t,e,n=void 0,r=new Map,i=void 0){this.node=t,this.sharedNodeState=e,this.unknownState=n,this.knownState=r;const{sharedConfigMap:o}=this.sharedNodeState,s=void 0!==i?i:function(t,e,n){let r=n.size;if(e)for(const i in e){const e=t.get(i);e&&n.has(e)||r++;}return r}(o,n,r);this.size=s;}getValue(t){const e=this.knownState.get(t);if(void 0!==e)return e;this.sharedNodeState.sharedConfigMap.set(t.key,t);let n=t.defaultValue;if(this.unknownState&&t.key in this.unknownState){const e=this.unknownState[t.key];void 0!==e&&(n=t.parse(e)),this.updateFromKnown(t,n);}return n}getInternalState(){return [this.unknownState,this.knownState]}toJSON(){const t={...this.unknownState},e={};for(const[e,n]of this.knownState)e.isEqual(n,e.defaultValue)?delete t[e.key]:t[e.key]=e.unparse(n);for(const n of this.sharedNodeState.flatKeys)n in t&&(e[n]=t[n],delete t[n]);return ht$3(t)&&(e.$=t),e}getWritable(t){if(this.node===t)return this;const{sharedNodeState:e,unknownState:n}=this,r=new Map(this.knownState);return new ut(t,e,function(t,e,n){let r;if(n)for(const[i,o]of Object.entries(n)){const n=t.get(i);n?e.has(n)||e.set(n,n.parse(o)):(r=r||{},r[i]=o);}return r}(e.sharedConfigMap,r,n),r,this.size)}resetOnCopyNode(){for(const t of this.knownState.keys())t.resetOnCopyNode&&this.knownState.set(t,t.defaultValue);return this}updateFromKnown(t,e){const n=t.key;this.sharedNodeState.sharedConfigMap.set(n,t);const{knownState:r,unknownState:i}=this;r.has(t)||i&&n in i||(i&&(delete i[n],this.unknownState=ht$3(i)),this.size++),r.set(t,e);}updateFromUnknown(t,e){const n=this.sharedNodeState.sharedConfigMap.get(t);n?this.updateFromKnown(n,n.parse(e)):(this.unknownState=this.unknownState||{},t in this.unknownState||this.size++,this.unknownState[t]=e);}updateFromJSON(t){const{knownState:e}=this;for(const t of e.keys())e.set(t,t.defaultValue);if(this.size=e.size,this.unknownState=void 0,t)for(const[e,n]of Object.entries(t))this.updateFromUnknown(e,n);}};function ft$2(t){const e=t.getWritable(),n=e.__state?e.__state.getWritable(e):new ut$3(e,dt$3(e));return e.__state=n,n}function dt$3(t){return t.__state?t.__state.sharedNodeState:No(Zs(),t.getType()).sharedNodeState}function ht$3(t){if(t)for(const e in t)return t}function gt$3(t){return t}
7324function _t$3(t,e,n){for(const[r,i]of e.knownState){if(t.has(r.key))continue;t.add(r.key);const e=n?n.getValue(r):r.defaultValue;if(e!==i&&!r.isEqual(e,i))return true}return false}function pt$3(t,e,n){const{unknownState:r}=e,i=n?n.unknownState:void 0;if(r)for(const[e,n]of Object.entries(r)){if(t.has(e))continue;t.add(e);if(n!==(i?i[e]:void 0))return true}return false}function yt$6(t,e){const n=t.__state;return n&&n.node===t?n.getWritable(e):n}function mt$3(t,e){const n=t.__mode,r=t.__format,i=t.__style,o=e.__mode,s=e.__format,l=e.__style,c=t.__state,a=e.__state;return (null===n||n===o)&&(null===r||r===s)&&(null===i||i===l)&&(null===t.__state||c===a||function(t,e){if(t===e)return true;const n=new Set;return !(t&&_t$3(n,t,e)||e&&_t$3(n,e,t)||t&&pt$3(n,t,e)||e&&pt$3(n,e,t))}(c,a))}function xt$3(t,e){const n=t.mergeWithSibling(e),r=vi()._normalizedNodes;return r.add(t.__key),r.add(e.__key),n}function Ct$2(t){let e,n,r=t;if(""!==r.__text||!r.isSimpleText()||r.isUnmergeable()){for(;null!==(e=r.getPreviousSibling())&&Tr(e)&&e.isSimpleText()&&!e.isUnmergeable();){if(""!==e.__text){if(mt$3(e,r)){r=xt$3(e,r);break}break}e.remove();}for(;null!==(n=r.getNextSibling())&&Tr(n)&&n.isSimpleText()&&!n.isUnmergeable();){if(""!==n.__text){if(mt$3(r,n)){r=xt$3(r,n);break}break}n.remove();}}else r.remove();}function St$3(t){return vt$3(t.anchor),vt$3(t.focus),t}function vt$3(t){for(;"element"===t.type;){const e=t.getNode(),n=t.offset;let r,i;if(n===e.getChildrenSize()?(r=e.getChildAtIndex(n-1),i=true):(r=e.getChildAtIndex(n),i=false),Tr(r)){t.set(r.__key,i?r.getTextContentSize():0,"text",true);break}if(!Wi(r))break;t.set(r.__key,i?r.getChildrenSize():0,"element",true);}}let kt$3,Tt$5,Nt$3,bt$3,wt$3,Et$4,Ot$4,Mt$3,At$3,Dt$5,Pt$4,Ft$3="",Lt$4=null,It$2=null,Kt$3=false,zt$5=false;function Rt$4(t,e){const n=Ot$4.get(t);if(null!==e){const n=ne$5(t);n.parentNode===e&&e.removeChild(n);}if(Mt$3.has(t)||Tt$5._keyToDOMMap.delete(t),Wi(n)){const t=hl(n,Ot$4);Bt$4(t,0,t.length-1,null);} void 0!==n&&xs(Dt$5,Nt$3,bt$3,n,"destroyed");}function Bt$4(t,e,n,r){for(let i=e;i<=n;++i){const e=t[i];void 0!==e&&Rt$4(e,r);}}function Wt$4(t,e){t.setProperty("text-align",e);}const $t$3="40px";function Jt$4(t,e){const n=kt$3.theme.indent;if("string"==typeof n){const r=t.classList.contains(n);e>0&&!r?t.classList.add(n):e<1&&r&&t.classList.remove(n);}if(0===e)return void t.style.setProperty("padding-inline-start","");const r=getComputedStyle(Tt$5._rootElement||t).getPropertyValue("--lexical-indent-base-value")||$t$3;t.style.setProperty("padding-inline-start",`calc(${e} * ${r})`);}function jt$3(t,e){const n=t.style;0===e?Wt$4(n,""):1===e?Wt$4(n,"left"):2===e?Wt$4(n,"center"):3===e?Wt$4(n,"right"):4===e?Wt$4(n,"justify"):5===e?Wt$4(n,"start"):6===e&&Wt$4(n,"end");}function Ut$4(t,e){const n=function(t){const e=t.__dir;if(null!==e)return e;if(Vi(t))return null;const n=t.getParentOrThrow();return Vi(n)&&null===n.__dir?"auto":null}(e);null!==n?t.dir=n:t.removeAttribute("dir");}function Vt$3(e,n){const r=Mt$3.get(e);void 0===r&&t(60);const i=Pt$4.$createDOM(r,Tt$5);if(function(t,e,n){const r=n._keyToDOMMap;((function(t,e,n){const r=`__lexicalKey_${e._key}`;t[r]=n;}))(e,n,t),r.set(t,e);}(e,i,Tt$5),Tr(r)?i.setAttribute("data-lexical-text","true"):ji(r)&&i.setAttribute("data-lexical-decorator","true"),Wi(r)){const t=r.__indent,e=r.__size;if(Ut$4(i,r),0!==t&&Jt$4(i,t),0!==e){const t=e-1;Yt$3(hl(r,Mt$3),r,0,t,Pt$4.$getDOMSlot(r,i,Tt$5));}const n=r.__format;0!==n&&jt$3(i,n),r.isInline()||Ht$4(null,r,i);}else {const t=r.getTextContent();if(ji(r)){const t=r.decorate(Tt$5,kt$3);null!==t&&Qt$3(e,t),i.contentEditable="false";}Ft$3+=t;}return null!==n&&n.insertChild(i),Pt$4.$decorateDOM(r,null,i,Tt$5),xs(Dt$5,Nt$3,bt$3,r,"created"),i}function Yt$3(t,e,n,r,i){const o=Ft$3;Ft$3="";let s=n;for(;s<=r;++s){Vt$3(t[s],i);const e=Mt$3.get(t[s]);null!==e&&Tr(e)?null===Lt$4&&(Lt$4=e.getFormat(),It$2=e.getStyle()):Wi(e)&&s<r&&!e.isInline()&&(Ft$3+=D$4);}i.element.__lexicalTextContent=Ft$3,Ft$3=o+Ft$3;}function qt$4(t,e){if(t){const n=t.__last;if(n){const t=e.get(n);if(t)return sr(t)?"line-break":ji(t)&&t.isInline()?"decorator":null}return "empty"}return null}function Ht$4(t,e,n){const r=qt$4(t,Ot$4),i=qt$4(e,Mt$3);r!==i&&Pt$4.$getDOMSlot(e,n,Tt$5).setManagedLineBreak(i);}function Gt$3(e,n,r){var i;Lt$4=null,It$2=null,function(e,n,r){const i=Ft$3,o=e.__size,s=n.__size;Ft$3="";const l=r.element;if(1===o&&1===s){const t=e.__first,r=n.__first;if(t===r)Xt$4(t,l);else {const e=ne$5(t),n=Vt$3(r,null);try{l.replaceChild(n,e);}catch(i){if("object"==typeof i&&null!=i){const o=`${i.toString()} Parent: ${l.tagName}, new child: {tag: ${n.tagName} key: ${r}}, old child: {tag: ${e.tagName}, key: ${t}}.`;throw new Error(o)}throw i}Rt$4(t,null);}const i=Mt$3.get(r);Tr(i)&&null===Lt$4&&(Lt$4=i.getFormat(),It$2=i.getStyle());}else {const i=hl(e,Ot$4),c=hl(n,Mt$3);if(i.length!==o&&t(227),c.length!==s&&t(228),0===o)0!==s&&Yt$3(c,0,0,s-1,r);
7324else if(0===s){if(0!==o){const t=null==r.after&&null==r.before&&null==r.element.__lexicalLineBreak;Bt$4(i,0,o-1,t?null:l),t&&(l.textContent="");}}else !function(t,e,n,r,i,o){const s=r-1,l=i-1;let c,a,u=o.getFirstChild(),f=0,d=0;for(;f<=s&&d<=l;){const t=e[f],r=n[d];if(t===r)u=Zt$3(Xt$4(r,o.element)),f++,d++;else {if(void 0===a&&(a=te$5(n,d)),void 0===c)c=te$5(e,f);else if(!c.has(t)){f++;continue}if(!a.has(t)){u=Zt$3(ne$5(t)),Rt$4(t,o.element),f++,c.delete(t);continue}if(c.has(r)){const t=Ns(Tt$5,r);t!==u&&o.withBefore(u).insertChild(t),u=Zt$3(Xt$4(r,o.element)),f++,d++;}else Vt$3(r,o.withBefore(u)),d++;}const i=Mt$3.get(r);null!==i&&Tr(i)?null===Lt$4&&(Lt$4=i.getFormat(),It$2=i.getStyle()):Wi(i)&&d<=l&&!i.isInline()&&(Ft$3+=D$4);}const h=f>s,g=d>l;if(h&&!g){const t=n[l+1],e=void 0===t?null:Tt$5.getElementByKey(t);Yt$3(n,0,d,l,o.withBefore(e));}else g&&!h&&Bt$4(e,f,s,o.element);}(0,i,c,o,s,r);}l.__lexicalTextContent=Ft$3,Ft$3=i+Ft$3;}(e,n,Pt$4.$getDOMSlot(n,r,Tt$5)),i=n,null==Lt$4||Lt$4===i.__textFormat||zt$5||i.setTextFormat(Lt$4),function(t){null==It$2||It$2===t.__textStyle||zt$5||t.setTextStyle(It$2);}(n);}function Xt$4(e,n){const r=Ot$4.get(e);let i=Mt$3.get(e);void 0!==r&&void 0!==i||t(61);const o=Kt$3||Et$4.has(e)||wt$3.has(e),s=Ns(Tt$5,e);if(r===i&&!o){let t;if(Wi(r)){const e=s.__lexicalTextContent;"string"==typeof e?t=e:(t=r.getTextContent(),s.__lexicalTextContent=t);}else t=r.getTextContent();return Ft$3+=t,s}if(r!==i&&o&&xs(Dt$5,Nt$3,bt$3,i,"updated"),Pt$4.$updateDOM(i,r,s,Tt$5)){const r=Vt$3(e,null);return null===n&&t(62),n.replaceChild(r,s),Rt$4(e,null),r}if(Wi(r)){Wi(i)||t(334,e);const n=i.__indent;(Kt$3||n!==r.__indent)&&Jt$4(s,n);const l=i.__format;if((Kt$3||l!==r.__format)&&jt$3(s,l),o)Gt$3(r,i,s),Vi(i)||i.isInline()||Ht$4(r,i,s);else {const t=s.__lexicalTextContent;let e;"string"==typeof t?e=t:(e=r.getTextContent(),s.__lexicalTextContent=e),Ft$3+=e;}if((Kt$3||i.__dir!==r.__dir)&&(Ut$4(s,i),Vi(i)&&!Kt$3))for(const t of i.getChildren())if(Wi(t)){Ut$4(Ns(Tt$5,t.getKey()),t);}}else {const t=i.getTextContent();if(ji(i)){const t=i.decorate(Tt$5,kt$3);null!==t&&Qt$3(e,t);}Ft$3+=t;}if(!zt$5&&Vi(i)&&i.__cachedText!==Ft$3){const t=i.getWritable();t.__cachedText=Ft$3,i=t;}return Pt$4.$decorateDOM(i,r,s,Tt$5),s}function Qt$3(t,e){let n=Tt$5._pendingDecorators;const r=Tt$5._decorators;if(null===n){if(r[t]===e)return;n=Xo(Tt$5);}n[t]=e;}function Zt$3(t){let e=t.nextSibling;return null!==e&&e===Tt$5._blockCursorElement&&(e=e.nextSibling),e}function te$5(t,e){const n=new Set;for(let r=e;r<t.length;r++)n.add(t[r]);return n}function ee$4(t,e,n,r,i,o){Ft$3="",Kt$3=2===r,Tt$5=n,kt$3=n._config,Pt$4=n._config.dom||po,Nt$3=n._nodes,bt$3=Tt$5._listeners.mutation,wt$3=i,Et$4=o,Ot$4=t._nodeMap,Mt$3=e._nodeMap,zt$5=e._readOnly,At$3=new Map(n._keyToDOMMap);const s=new Map;return Dt$5=s,Xt$4("root",null),Tt$5=void 0,Nt$3=void 0,wt$3=void 0,Et$4=void 0,Ot$4=void 0,Mt$3=void 0,kt$3=void 0,At$3=void 0,Dt$5=void 0,Pt$4=po,s}function ne$5(e){const n=At$3.get(e);return void 0===n&&t(75,e),n}function re$5(t){return {type:t}}const ie$4=re$5("SELECTION_CHANGE_COMMAND"),oe$6=re$5("SELECTION_INSERT_CLIPBOARD_NODES_COMMAND"),se$5=re$5("CLICK_COMMAND"),le$3=re$5("BEFORE_INPUT_COMMAND"),ce$4=re$5("INPUT_COMMAND"),ae$4=re$5("COMPOSITION_START_COMMAND"),ue$4=re$5("COMPOSITION_END_COMMAND"),fe$4=re$5("DELETE_CHARACTER_COMMAND"),de$4=re$5("INSERT_LINE_BREAK_COMMAND"),he$3=re$5("INSERT_PARAGRAPH_COMMAND"),ge$3=re$5("CONTROLLED_TEXT_INSERTION_COMMAND"),_e$2=re$5("PASTE_COMMAND"),pe$3=re$5("REMOVE_TEXT_COMMAND"),ye$2=re$5("DELETE_WORD_COMMAND"),me$3=re$5("DELETE_LINE_COMMAND"),xe=re$5("FORMAT_TEXT_COMMAND"),Ce$2=re$5("UNDO_COMMAND"),Se$2=re$5("REDO_COMMAND"),ve$2=re$5("KEYDOWN_COMMAND"),ke$2=re$5("KEY_ARROW_RIGHT_COMMAND"),Te$2=re$5("MOVE_TO_END"),Ne$1=re$5("KEY_ARROW_LEFT_COMMAND"),be$1=re$5("MOVE_TO_START"),we$1=re$5("KEY_ARROW_UP_COMMAND"),Ee$3=re$5("KEY_ARROW_DOWN_COMMAND"),Oe$2=re$5("KEY_ENTER_COMMAND"),Me$2=re$5("KEY_SPACE_COMMAND"),Ae$3=re$5("KEY_BACKSPACE_COMMAND"),De$2=re$5("KEY_ESCAPE_COMMAND"),Pe$2=re$5("KEY_DELETE_COMMAND"),Fe$2=re$5("KEY_TAB_COMMAND"),Le$2=re$5("INSERT_TAB_COMMAND"),Ie$3=re$5("INDENT_CONTENT_COMMAND"),Ke$2=re$5("OUTDENT_CONTENT_COMMAND"),ze$2=re$5("DROP_COMMAND"),Re$1=re$5("FORMAT_ELEMENT_COMMAND"),Be$2=re$5("DRAGSTART_COMMAND"),We$2=re$5("DRAGOVER_COMMAND"),$e$2=re$5("DRAGEND_COMMAND"),Je$2=re$5("COPY_COMMAND"),je$2=re$5("CUT_COMMAND"),Ue$2=re$5("SELECT_ALL_COMMAND"),Ve$2=re$5("CLEAR_EDITOR_COMMAND"),Ye$1=re$5("CLEAR_HISTORY_COMMAND"),qe$2=re$5("CAN_REDO_COMMAND"),He$2=re$5("CAN_UNDO_COMMAND"),Ge$2=re$5("FOCUS_COMMAND"),Xe$2=re$5("BLUR_COMMAND"),Qe$1=re$5("KEY_MODIFIER_COMMAND"),Ze$1=Object.freeze({}),tn$1=[["keydown",function(t,e){if(en$1=t.timeStamp,nn$1=t.key,e.isComposing())return;Ts(e,ve$2,t);}],["pointerdown",function(t,e){const n=t.target,r=t.pointerType;qs(n)&&"touch"!==r&&"pen"!==r&&0===t.button&&Ki(e,()=>{Eo(n)||(an$1=true);});}],["compositionstart",function(t,e){Ts(e,ae$4,t);}],["compositionend",function(t,e){o$1?fn$1=true:l||!a$1&&!d$1?Ts(e,ue$4,t):(dn$1=true,hn$1=t.data);}],["input",function(t,e){t.stopPropagation(),Ki(e,()=>{e.dispatchCommand(ce$4,t);},{event:t}),on$1=null;}],["click",function(t,e){Ki(e,()=>{const n=Qr(),r=Js(Ps(e)),i=Zr();
7324if(r)if(Fr(n)){const e=n.anchor,o=e.getNode();if("element"===e.type&&0===e.offset&&n.isCollapsed()&&!Vi(o)&&1===Zo().getChildrenSize()&&o.getTopLevelElementOrThrow().isEmpty()&&null!==i&&n.is(i))r.removeAllRanges(),n.dirty=true;else if(3===t.detail&&!n.isCollapsed()){if(o!==n.focus.getNode()){const t=dl(o,t=>Wi(t)&&!t.isInline());Wi(t)&&t.select(0);}}}else if("touch"===t.pointerType||"pen"===t.pointerType){const n=r.anchorNode;if(Ys(n)||Ko(n)){es(Xr(i,r,e,t));}}Ts(e,se$5,t);});}],["cut",Ze$1],["copy",Ze$1],["dragstart",Ze$1],["dragover",Ze$1],["dragend",Ze$1],["paste",Ze$1],["focus",Ze$1],["blur",Ze$1],["drop",Ze$1]];s$1&&tn$1.push(["beforeinput",(t,e)=>function(t,e){const n=t.inputType;if("deleteCompositionText"===n||o$1&&ks(e))return;if("insertCompositionText"===n)return;Ts(e,le$3,t);}(t,e)]);let en$1=0,nn$1=null,rn$1=0,on$1=null;const sn$1=new WeakMap,ln$1=new WeakMap;let cn$1=false,an$1=false,un$1=false,fn$1=false,dn$1=false,hn$1="",gn$1=null,_n$1=[0,"",0,"root",0];function pn$1(t,e,n,r,i){const o=t.anchor,l=t.focus,c=o.getNode(),a=vi(),u=Js(Ps(a)),f=null!==u?u.anchorNode:null,d=o.key,h=a.getElementByKey(d),g=n.length;return d!==l.key||!Tr(c)||(!i&&(!s$1||rn$1<r+50)||c.isDirty()&&g<2||rs(n))&&o.offset!==l.offset&&!c.isComposing()||Io(c)||c.isDirty()&&g>1||(i||!s$1)&&null!==h&&!c.isComposing()&&f!==Ro(h)||null!==u&&null!==e&&(!e.collapsed||e.startContainer!==u.anchorNode||e.startOffset!==u.anchorOffset)||!c.isComposing()&&(c.getFormat()!==t.format||c.getStyle()!==t.style)||function(t,e){if(e.isSegmented())return true;if(!t.isCollapsed())return false;const n=t.anchor.offset,r=e.getParentOrThrow(),i=Lo(e);return 0===n?!e.canInsertTextBefore()||!r.canInsertTextBefore()&&!e.isComposing()||i||function(t){const e=t.getPreviousSibling();return (Tr(e)||Wi(e)&&e.isInline())&&!e.canInsertTextAfter()}(e):n===e.getTextContentSize()&&(!e.canInsertTextAfter()||!r.canInsertTextAfter()&&!e.isComposing()||i)}(t,c)}function yn$1(t,e){return Ko(t)&&null!==t.nodeValue&&0!==e&&e!==t.nodeValue.length}function mn$1(e,n,r){const{anchorNode:i,anchorOffset:o,focusNode:s,focusOffset:l}=e;cn$1&&(cn$1=false,yn$1(i,o)&&yn$1(s,l)&&!gn$1)||Ki(n,()=>{if(!r)return void es(null);if(!Mo(n,i,s))return;let c=Qr();if(gn$1&&Fr(c)&&c.isCollapsed()){const t=c.anchor,e=gn$1.anchor;(t.key===e.key&&t.offset===e.offset+1||1===t.offset&&e.getNode().is(t.getNode().getPreviousSibling()))&&(c=gn$1.clone(),es(c));}if(gn$1=null,Fr(c)){const r=c.anchor,i=r.getNode();if(c.isCollapsed()){"Range"===e.type&&e.anchorNode===e.focusNode&&(c.dirty=true);const o=Ps(n).event,s=o?o.timeStamp:performance.now(),[l,a,u,f,d]=_n$1,h=Zo(),g=false===n.isComposing()&&""===h.getTextContent();if(s<d+200&&r.offset===u&&r.key===f)xn$1(c,l,a);else if("text"===r.type)Tr(i)||t(141),Cn$1(c,i);else if("element"===r.type&&!g){Wi(i)||t(259);const e=r.getNode();e.isEmpty()?function(t,e){const n=e.getTextFormat(),r=e.getTextStyle();xn$1(t,n,r);}(c,e):xn$1(c,c.format,"");}}else {const t=r.key,e=c.focus.key,n=c.getNodes(),i=n.length,s=c.isBackward(),a=s?l:o,u=s?o:l,f=s?e:t,d=s?t:e;let h=2047,g=false;for(let t=0;t<i;t++){const e=n[t],r=e.getTextContentSize();if(Tr(e)&&0!==r&&!(0===t&&e.__key===f&&a===r||t===i-1&&e.__key===d&&0===u)&&(g=true,h&=e.getFormat(),0===h))break}c.format=g?h:0;}}Ts(n,ie$4,void 0);});}function xn$1(t,e,n){t.format===e&&t.style===n||(t.format=e,t.style=n,t.dirty=true);}function Cn$1(t,e){xn$1(t,e.getFormat(),e.getStyle());}function Sn$1(t){if(!t.getTargetRanges)return null;const e=t.getTargetRanges();return 0===e.length?null:e[0]}function vn$1(e){const n=e.inputType,r=Sn$1(e),i=vi(),o=Qr();if("deleteContentBackward"===n){if(null===o){const t=Zr();if(!Fr(t))return true;es(t.clone());}if(Fr(o)){const n=o.anchor.key===o.focus.key;if(s=e.timeStamp,"MediaLast"===nn$1&&s<en$1+30&&i.isComposing()&&n){if(Uo(null),en$1=0,setTimeout(()=>{Ki(i,()=>{Uo(null);});},30),Fr(o)){const e=o.anchor.getNode();e.markDirty(),Tr(e)||t(142),Cn$1(o,e);}}else {Uo(null),e.preventDefault();const t=o.anchor.getNode(),r=t.getTextContent(),s=t.canInsertTextAfter(),l=0===o.anchor.offset&&o.focus.offset===r.length;let c=f&&n&&!l&&s;if(c&&o.isCollapsed()&&(c=!ji(vs(o.anchor,true))),!c){Ts(i,fe$4,true);const t=Qr();f&&Fr(t)&&t.isCollapsed()&&(gn$1=t,setTimeout(()=>gn$1=null));}}return true}}var s;if(!Fr(o))return true;const c=e.data;null!==on$1&&ls(false,i,on$1),o.dirty&&null===on$1||!o.isCollapsed()||Vi(o.anchor.getNode())||null===r||o.applyDOMRange(r),on$1=null;const a=o.anchor,u=o.focus,d=a.getNode(),h=u.getNode();if("insertText"===n||"insertTranspose"===n){if("\n"===c)e.preventDefault(),Ts(i,de$4,false);else if(c===D$4)e.preventDefault(),Ts(i,he$3,void 0);else if(null==c&&e.dataTransfer){const t=e.dataTransfer.getData("text/plain");e.preventDefault(),o.insertRawText(t);}else null!=c&&pn$1(o,r,c,e.timeStamp,true)?(e.preventDefault(),Ts(i,ge$3,c)):on$1=c;return rn$1=e.timeStamp,true}switch(e.preventDefault(),n){case "insertFromYank":case "insertFromDrop":case "insertReplacementText":Ts(i,ge$3,e);break;case "insertFromComposition":Uo(null),Ts(i,ge$3,e);break;case "insertLineBreak":Uo(null),Ts(i,de$4,false);break;case "insertParagraph":Uo(null),un$1&&!l?(un$1=false,Ts(i,de$4,false)):Ts(i,he$3,void 0);break;case "insertFromPaste":case "insertFromPasteAsQuotation":Ts(i,_e$2,e);break;case "deleteByComposition":(function(t,e){return t!==e||Wi(t)||Wi(e)||!Lo(t)||!Lo(e)})(d,h)&&Ts(i,pe$3,e);break;case "deleteByDrag":Os(Hn),Ts(i,pe$3,e);break;case "deleteByCut":Ts(i,pe$3,e);break;case "deleteContent":Ts(i,fe$4,false);break;case "deleteWordBackward":Ts(i,ye$2,true);break;
7324case "deleteWordForward":Ts(i,ye$2,false);break;case "deleteHardLineBackward":case "deleteSoftLineBackward":Ts(i,me$3,true);break;case "deleteContentForward":case "deleteHardLineForward":case "deleteSoftLineForward":Ts(i,me$3,false);break;case "formatStrikeThrough":Ts(i,xe,"strikethrough");break;case "formatBold":Ts(i,xe,"bold");break;case "formatItalic":Ts(i,xe,"italic");break;case "formatUnderline":Ts(i,xe,"underline");break;case "historyUndo":Ts(i,Ce$2,void 0);break;case "historyRedo":Ts(i,Se$2,void 0);}return true}function kn$1(t){if(Ys(t.target)&&Eo(t.target))return true;const e=vi(),n=Qr(),r=t.data,i=Sn$1(t);if(null!=r&&Fr(n)&&pn$1(n,i,r,t.timeStamp,false)){fn$1&&(bn$1(e,r),fn$1=false);const i=n.anchor.getNode(),l=Js(Ps(e));if(null===l)return true;const c=n.isBackward(),a=c?n.anchor.offset:n.focus.offset,u=c?n.focus.offset:n.anchor.offset;s$1&&!n.isCollapsed()&&Tr(i)&&null!==l.anchorNode&&i.getTextContent().slice(0,a)+r+i.getTextContent().slice(a+u)===ss(l.anchorNode)||Ts(e,ge$3,r);const d=r.length;o$1&&d>1&&"insertCompositionText"===t.inputType&&!e.isComposing()&&(n.anchor.offset-=d),f&&e.isComposing()&&(en$1=0,Uo(null));}else {ls(false,e,null!==r?r:void 0),fn$1&&(bn$1(e,r||void 0),fn$1=false);}return function(){xi();const t=vi();nt$4(t);}(),true}function Tn$1(t){const e=vi(),n=Qr();if(Fr(n)&&!e.isComposing()){const r=n.anchor,i=n.anchor.getNode();Uo(r.key),Os(Gn),(t.timeStamp<en$1+30||"element"===r.type||!n.isCollapsed()||i.getFormat()!==n.format||Tr(i)&&i.getStyle()!==n.style)&&Ts(e,ge$3,P$3);}return true}function Nn$1(t){return bn$1(vi(),t.data),Os(Xn),true}function bn$1(t,e){const n=t._compositionKey;if(Uo(null),null!==n&&null!=e){if(""===e){const e=Yo(n),r=Ro(t.getElementByKey(n));if(null!==r&&null!==r.nodeValue&&Tr(e)){const n=Js(Ps(t));let i=null,o=null;null!==n&&n.anchorNode===r&&(i=n.anchorOffset,o=n.focusOffset),cs(e,r.nodeValue,i,o,true);}return}if("\n"===e[e.length-1]){const e=Qr();if(Fr(e)||Ir(e)){if(Fr(e)){const t=e.focus;e.anchor.set(t.key,t.offset,t.type);}return void Ts(t,Oe$2,null)}}}ls(true,t,e);}function wn$1(t){const e=vi();if(null==t.key)return true;if(dn$1){if(_s(t))return Ki(e,()=>{bn$1(e,hn$1);}),dn$1=false,hn$1="",true;dn$1=false,hn$1="";}if(function(t){return ds(t,"ArrowRight",{shiftKey:"any"})}(t))Ts(e,ke$2,t);else if(function(t){return ds(t,"ArrowRight",hs)}(t))Ts(e,Te$2,t);else if(function(t){return ds(t,"ArrowLeft",{shiftKey:"any"})}(t))Ts(e,Ne$1,t);else if(function(t){return ds(t,"ArrowLeft",hs)}(t))Ts(e,be$1,t);else if(function(t){return ds(t,"ArrowUp",{altKey:"any",shiftKey:"any"})}(t))Ts(e,we$1,t);else if(function(t){return ds(t,"ArrowDown",{altKey:"any",shiftKey:"any"})}(t))Ts(e,Ee$3,t);else if(function(t){return ds(t,"Enter",{altKey:"any",ctrlKey:"any",metaKey:"any",shiftKey:true})}(t))un$1=true,Ts(e,Oe$2,t);else if(function(t){return " "===t.key}(t))Ts(e,Me$2,t);else if(function(t){return i&&ds(t,"o",{ctrlKey:true})}(t))t.preventDefault(),un$1=true,Ts(e,de$4,true);else if(function(t){return ds(t,"Enter",{altKey:"any",ctrlKey:"any",metaKey:"any"})}(t))un$1=false,Ts(e,Oe$2,t);else if(function(t){return ds(t,"Backspace",{shiftKey:"any"})||i&&ds(t,"h",{ctrlKey:true})}(t))_s(t)?Ts(e,Ae$3,t):(t.preventDefault(),Ts(e,fe$4,true));
7324else if(function(t){return "Escape"===t.key}(t))Ts(e,De$2,t);else if(function(t){return ds(t,"Delete",{})||i&&ds(t,"d",{ctrlKey:true})}(t))!function(t){return "Delete"===t.key}(t)?(t.preventDefault(),Ts(e,fe$4,false)):Ts(e,Pe$2,t);else if(function(t){return ds(t,"Backspace",gs)}(t))t.preventDefault(),Ts(e,ye$2,true);else if(function(t){return ds(t,"Delete",gs)}(t))t.preventDefault(),Ts(e,ye$2,false);else if(function(t){return i&&ds(t,"Backspace",{metaKey:true})}(t))t.preventDefault(),Ts(e,me$3,true);else if(function(t){return i&&(ds(t,"Delete",{metaKey:true})||ds(t,"k",{ctrlKey:true}))}(t))t.preventDefault(),Ts(e,me$3,false);else if(function(t){return ds(t,"b",hs)}(t))t.preventDefault(),Ts(e,xe,"bold");else if(function(t){return ds(t,"u",hs)}(t))t.preventDefault(),Ts(e,xe,"underline");else if(function(t){return ds(t,"i",hs)}(t))t.preventDefault(),Ts(e,xe,"italic");else if(function(t){return ds(t,"Tab",{shiftKey:"any"})}(t))Ts(e,Fe$2,t);else if(function(t){return ds(t,"z",hs)}(t))t.preventDefault(),Ts(e,Ce$2,void 0);else if(function(t){if(i)return ds(t,"z",{metaKey:true,shiftKey:true});return ds(t,"y",{ctrlKey:true})||ds(t,"z",{ctrlKey:true,shiftKey:true})}(t))t.preventDefault(),Ts(e,Se$2,void 0);else {const n=e._editorState._selection;null===n||Fr(n)?ps(t)&&(t.preventDefault(),Ts(e,Ue$2,t)):!function(t){return ds(t,"c",hs)}(t)?!function(t){return ds(t,"x",hs)}(t)?ps(t)&&(t.preventDefault(),Ts(e,Ue$2,t)):(t.preventDefault(),Ts(e,je$2,t)):(t.preventDefault(),Ts(e,Je$2,t));}return function(t){return t.ctrlKey||t.shiftKey||t.altKey||t.metaKey}(t)&&e.dispatchCommand(Qe$1,t),true}function En$1(t){let e=t.__lexicalEventHandles;return void 0===e&&(e=[],t.__lexicalEventHandles=e),e}const On$1=new Map;function Mn(t){const e=js(t.target);if(null===e)return;const n=Do(e.anchorNode);if(null===n)return;an$1&&(an$1=false,Ki(n,()=>{const r=Zr(),i=e.anchorNode;if(Ys(i)||Ko(i)){es(Xr(r,e,n,t));}}));const r=is(n),i=r[r.length-1],o=i._key,s=On$1.get(o),l=s||i;l!==n&&mn$1(e,l,false),mn$1(e,n,true),n!==i?On$1.set(o,n):s&&On$1.delete(o);}function An$1(t){t._lexicalHandled=true;}function Dn(t){return true===t._lexicalHandled}function Fn$1(e){const n=sn$1.get(e);if(void 0===n)return void 0;const r=ln$1.get(n);if(void 0===r)return void 0;const i=r-1;i>=0||t(164),sn$1.delete(e),ln$1.set(n,i),0===i&&n.removeEventListener("selectionchange",Mn);const o=Po(e);Ao(o)?(!function(t){if(null!==t._parentEditor){const e=is(t),n=e[e.length-1]._key;On$1.get(n)===t&&On$1.delete(n);}else On$1.delete(t._key);}(o),e.__lexicalEditor=null):o&&t(198);const s=En$1(e);for(let t=0;t<s.length;t++)s[t]();e.__lexicalEventHandles=[];}function Ln(t,e,n){xi();const r=t.__key,i=t.getParent();if(null===i)return;const o=function(t){const e=Qr();if(!Fr(e)||!Wi(t))return e;const{anchor:n,focus:r}=e,i=n.getNode(),o=r.getNode();As(i,t)&&n.set(t.__key,0,"element");As(o,t)&&r.set(t.__key,0,"element");return e}(t);let s=false;if(Fr(o)&&e){const e=o.anchor,n=o.focus;e.key===r&&(ni(e,t,i,t.getPreviousSibling(),t.getNextSibling()),s=true),n.key===r&&(ni(n,t,i,t.getPreviousSibling(),t.getNextSibling()),s=true);}else Ir(o)&&e&&t.isSelected()&&t.selectPrevious();if(Fr(o)&&e&&!s){const e=t.getIndexWithinParent();Jo(t),ti(o,i,e,-1);}else Jo(t);n||Is(i)||i.canBeEmpty()||!i.isEmpty()||Ln(i,e),e&&o&&Vi(i)&&i.isEmpty()&&i.selectEnd();}function In(t){return t}const Kn$1=Symbol.for("ephemeral");function zn(t){return t[Kn$1]||false}let Rn$1 = class Rn{__type;__key;__parent;__prev;__next;__state;static getType(){const{ownNodeType:e}=ul(this);return void 0===e&&t(64,this.name),e}static clone(e){t(65,this.name);}$config(){return {}}config(t,e){const n=e.extends||Object.getPrototypeOf(this.constructor);return Object.assign(e,{extends:n,type:t}),{[t]:e}}afterCloneFrom(t){this.__key===t.__key?(this.__parent=t.__parent,this.__next=t.__next,this.__prev=t.__prev,this.__state=t.__state):t.__state&&(this.__state=t.__state.getWritable(this));}resetOnCopyNodeFrom(t){this.__state&&(this.__state=this.__state.getWritable(this).resetOnCopyNode());}static importDOM;constructor(t){this.__type=this.constructor.getType(),this.__parent=null,this.__prev=null,this.__next=null,Object.defineProperty(this,"__state",{configurable:true,enumerable:false,value:void 0,writable:true}),$o(this,t);}getType(){return this.__type}isInline(){t(137,this.constructor.name);}isAttached(){let t=this.__key;for(;null!==t;){if("root"===t)return true;const e=Yo(t);if(null===e)break;t=e.__parent;}return false}isSelected(t){const e=t||Qr();if(null==e)return false;
7324const n=e.getNodes().some(t=>t.__key===this.__key);if(Tr(this))return n;if(Fr(e)&&"element"===e.anchor.type&&"element"===e.focus.type){if(e.isCollapsed())return false;const t=this.getParent();if(ji(this)&&this.isInline()&&t){const n=e.isBackward()?e.focus:e.anchor;if(t.is(n.getNode())&&n.offset===t.getChildrenSize()&&this.is(t.getLastChild()))return false}}return n}getKey(){return this.__key}getIndexWithinParent(){const t=this.getParent();if(null===t)return -1;let e=t.getFirstChild(),n=0;for(;null!==e;){if(this.is(e))return n;n++,e=e.getNextSibling();}return -1}getParent(){const t=this.getLatest().__parent;return null===t?null:Yo(t)}getParentOrThrow(){const e=this.getParent();return null===e&&t(66,this.__key),e}getTopLevelElement(){let e=this;for(;null!==e;){const n=e.getParent();if(Is(n))return Wi(e)||e===this&&ji(e)||t(194),e;e=n;}return null}getTopLevelElementOrThrow(){const e=this.getTopLevelElement();return null===e&&t(67,this.__key),e}getParents(){const t=[];let e=this.getParent();for(;null!==e;)t.push(e),e=e.getParent();return t}getParentKeys(){const t=[];let e=this.getParent();for(;null!==e;)t.push(e.__key),e=e.getParent();return t}getPreviousSibling(){const t=this.getLatest().__prev;return null===t?null:Yo(t)}getPreviousSiblings(){const t=[],e=this.getParent();if(null===e)return t;let n=e.getFirstChild();for(;null!==n&&!n.is(this);)t.push(n),n=n.getNextSibling();return t}getNextSibling(){const t=this.getLatest().__next;return null===t?null:Yo(t)}getNextSiblings(){const t=[];let e=this.getNextSibling();for(;null!==e;)t.push(e),e=e.getNextSibling();return t}getCommonAncestor(t){const e=Wi(this)?this:this.getParent(),n=Wi(t)?t:t.getParent(),r=e&&n?Yl(e,n):null;return r?r.commonAncestor:null}is(t){return null!=t&&this.__key===t.__key}isBefore(e){const n=Yl(this,e);return null!==n&&("descendant"===n.type||("branch"===n.type?-1===jl(n):("same"!==n.type&&"ancestor"!==n.type&&t(279),false)))}isParentOf(t){const e=Yl(this,t);return null!==e&&"ancestor"===e.type}getNodesBetween(e){const n=this.isBefore(e),r=[],i=new Set;let o=this;for(;null!==o;){const s=o.__key;if(i.has(s)||(i.add(s),r.push(o)),o===e)break;const l=Wi(o)?n?o.getFirstChild():o.getLastChild():null;if(null!==l){o=l;continue}const c=n?o.getNextSibling():o.getPreviousSibling();if(null!==c){o=c;continue}const a=o.getParentOrThrow();if(i.has(a.__key)||r.push(a),a===e)break;let u=null,f=a;do{if(null===f&&t(68),u=n?f.getNextSibling():f.getPreviousSibling(),f=f.getParent(),null===f)break;null!==u||i.has(f.__key)||r.push(f);}while(null===u);o=u;}return n||r.reverse(),r}isDirty(){const t=vi()._dirtyLeaves;return null!==t&&t.has(this.__key)}getLatest(){if(zn(this))return this;const e=Yo(this.__key);return null===e&&t(113),e}getWritable(){if(zn(this))return this;xi();const t=Si(),e=vi(),n=t._nodeMap,r=this.__key,i=this.getLatest(),o=e._cloneNotNeeded,s=Qr();if(null!==s&&s.setCachedNodes(null),o.has(r))return jo(i),i;const l=il(i);return o.add(r),jo(l),n.set(r,l),l}getTextContent(){return ""}getTextContentSize(){return this.getTextContent().length}createDOM(e,n){t(70);}updateDOM(e,n,r){t(71);}exportDOM(t){return {element:this.createDOM(t._config,t)}}exportJSON(){const t=this.__state?this.__state.toJSON():void 0;return {type:this.__type,version:1,...t}}static importJSON(e){t(18,this.name);}updateFromJSON(t){return function(t,e){const n=t.getWritable(),r=e.$;let i=r;for(const t of dt$3(n).flatKeys)t in e&&(void 0!==i&&i!==r||(i={...r}),i[t]=e[t]);return (n.__state||i)&&ft$2(t).updateFromJSON(i),n}(this,t)}static transform(){return null}remove(t){Ln(this,true,t);}replace(e,n){xi();let r=Qr();null!==r&&(r=r.clone()),Rs(this,e);const i=this.getLatest(),o=this.__key,s=e.__key,l=e.getWritable(),c=this.getParentOrThrow().getWritable(),a=c.__size;Jo(l);const u=i.getPreviousSibling(),f=i.getNextSibling(),d=i.__prev,h=i.__next,g=i.__parent;if(Ln(i,false,true),null===u)c.__first=s;else {u.getWritable().__next=s;}if(l.__prev=d,null===f)c.__last=s;else {f.getWritable().__prev=s;}if(l.__next=h,l.__parent=g,c.__size=a,n&&(Wi(this)&&Wi(l)||t(139),this.getChildren().forEac
7324h(t=>{l.append(t);})),Fr(r)){es(r);const t=r.anchor,e=r.focus;t.key===o&&Dr(t,l),e.key===o&&Dr(e,l);}return Vo()===o&&Uo(s),l}insertAfter(t,e=true){xi(),Rs(this,t);const n=this.getWritable(),r=t.getWritable(),i=r.getParent(),o=Qr();let s=false,l=false;if(null!==i){const e=t.getIndexWithinParent();if(Jo(r),Fr(o)){const t=i.__key,n=o.anchor,r=o.focus;s="element"===n.type&&n.key===t&&n.offset===e+1,l="element"===r.type&&r.key===t&&r.offset===e+1;}}const c=this.getNextSibling(),a=this.getParentOrThrow().getWritable(),u=r.__key,f=n.__next;if(null===c)a.__last=u;else {c.getWritable().__prev=u;}if(a.__size++,n.__next=u,r.__next=f,r.__prev=n.__key,r.__parent=n.__parent,e&&Fr(o)){const t=this.getIndexWithinParent();ti(o,a,t+1);const e=a.__key;s&&o.anchor.set(e,t+2,"element"),l&&o.focus.set(e,t+2,"element");}return t}insertBefore(t,e=true){xi(),Rs(this,t);const n=this.getWritable(),r=t.getWritable(),i=r.__key;Jo(r);const o=this.getPreviousSibling(),s=this.getParentOrThrow().getWritable(),l=n.__prev,c=this.getIndexWithinParent();if(null===o)s.__first=i;else {o.getWritable().__next=i;}s.__size++,n.__prev=i,r.__prev=l,r.__next=n.__key,r.__parent=n.__parent;const a=Qr();if(e&&Fr(a)){ti(a,this.getParentOrThrow(),c);}return t}isParentRequired(){return false}createParentElementNode(){return eo()}selectStart(){return this.selectPrevious()}selectEnd(){return this.selectNext(0,0)}selectPrevious(t,e){xi();const n=this.getPreviousSibling(),r=this.getParentOrThrow();if(null===n)return r.select(0,0);if(Wi(n))return n.select();if(!Tr(n)){const t=n.getIndexWithinParent()+1;return r.select(t,t)}return n.select(t,e)}selectNext(t,e){xi();const n=this.getNextSibling(),r=this.getParentOrThrow();if(null===n)return r.select();if(Wi(n))return n.select(0,0);if(!Tr(n)){const t=n.getIndexWithinParent();return r.select(t,t)}return n.select(t,e)}markDirty(){this.getWritable();}reconcileObservedMutation(t,e){this.markDirty();}};function Bn(t){return t instanceof Rn$1}const Wn$1="historic",$n$1="history-push",Jn="history-merge",jn="paste",Un="collaboration",Vn="skip-collab",Yn="skip-scroll-into-view",qn="skip-dom-selection",Hn="skip-selection-focus",Gn="composition-start",Xn="composition-end",Qn=/\s*!important\s*$/i;function Zn(t){const e={};if(!t)return e;let n="",r="",i=null,o=false,s=false,l=false,c=0;for(let a=0;a<t.length;a++){const u=t[a];if(o)"*"===u&&"/"===t[a+1]&&(o=false,a++);else if(s)l?r+=u:n+=u,s=false;else if(null===i)if("/"!==u||"*"!==t[a+1])if('"'!==u&&"'"!==u)if("("!==u)if(")"!==u)if(l||":"!==u||0!==c){if(";"===u&&0===c){const t=n.trim(),i=r.trim();""!==t&&""!==i&&(e[t]=i),n="",r="",l=false;continue}l?r+=u:n+=u;}else l=true;else c=Math.max(0,c-1),l?r+=u:n+=u;else c++,l?r+=u:n+=u;else i=u,l?r+=u:n+=u;else o=true,a++;else l?r+=u:n+=u,"\\"===u?s=true:u===i&&(i=null);}const a=n.trim(),u=r.trim();return ""!==a&&""!==u&&(e[a]=u),e}function tr(t,e,n){const r=Qn.test(n)?"important":"",i=""===r?n:n.replace(Qn,"").trim();t.setProperty(e,i,r);}function er(t,e){for(const n in e){const r=e[n];null==r?t.removeProperty(n):tr(t,n,r);}}function nr(t,e,n=""){if(e===n)return;const r=Zn(n),i=Zn(e);for(const e in i)delete r[e],tr(t,e,i[e]);for(const e in r)t.removeProperty(e);}class rr extends Rn$1{static getType(){return "linebreak"}static clone(t){return new rr(t.__key)}constructor(t){super(t);}getTextContent(){return "\n"}createDOM(){return document.createElement("br")}updateDOM(){return false}isInline(){return true}static importDOM(){return {br:t=>function(t){const e=t.parentElement;if(null!==e&&Xs(e)){const n=e.firstChild;if(n===t||n.nextSibling===t&&lr(n)){const n=e.lastChild;if(n===t||n.previousSibling===t&&lr(n))return true}}return false}(t)||function(t){const e=t.parentElement;if(null!==e&&Xs(e)){const n=e.firstChild;if(n===t||n.nextSibling===t&&lr(n))return false;const r=e.lastChild;if(r===t||r.previousSibling===t&&lr(r))return true}return false}(t)?null:{conversion:ir,priority:0}}}static importJSON(t){return or().updateFromJSON(t)}}function ir(t){return {node:or()}}function or(){return zs(new rr)}function sr(t){return t instanceof rr}function lr(t){return Ko(t)&&/^( |\t|\r?\n)+$/.test(t.textContent||"")}function cr(t,e){return 16&e?"code":e&k$3?"mark":32&e?"sub":64&e?"sup":null}function ar(t,e){return 1&e?"strong":2&e?"em":"span"}function ur(t,e,n,r,i){const o=r.classList;let s=ms(i,"base");void 0!==s&&o.add(...s),s=ms(i,"underlineStrikethrough");let l=false;const c=8&e&&4&e;void 0!==s&&(8&n&&4&n?(l=true,c||o.add(...s)):c&&o.remove(...s));for(const t in z$7){const r=z$7[t];if(s=ms(i,t),void 0!==s)if(n&r){if(l&&("underline"===t||"strikethrough"===t)){e&r&&o.remove(...s);continue}(0===(e&r)||c&&"underline"===t||"strikethrough"===t)&&o.add(...s);}else e&r&&o.remove(...s);}}function fr(t,e,n){const r=e.firstChild,i=n.isComposing(),s=t+(i?A$3:"");if(null==r)e.textContent=s;else {const t=r.nodeValue;if(t!==s)if(i||o$1){const[e,n,i]=function(t,e){const n=t.length,r=e.length;let i=0,o=0;for(;i<n&&i<r&&t[i]===e[i];)i++;for(;o+i<n&&o+i<r&&t[n-o-1]===e[r-o-1];)o++;return [i,n-i-o,e.slice(i,r-o)]}(t,s);0!==n&&r.deleteData(e,n),r.insertData(e,i);}else r.nodeValue=s;}}function dr(t,e,n,r,i,o){fr(i,t,e);const s=o.theme.text;void 0!==s&&ur(0,0,r,t,s);}function hr(t,e){const n=document.createElement(e);return n.appendChild(t),n}class gr extends Rn$1{__text;__format;__style;__mode;__detail;static getType(){return "text"}static clone(t){return new gr(t.__text,t.__key)}afterCloneFrom(t){super.afterCloneFrom(t),this.__text=t.__text,this.__format=t.__format,this.__style=t.__style,this.__mode=t.__mode,this.__detail=t.__detail;}constructor(t="",e){super(e),this.__text=t,this.__format=0,this.__style="",this.__mode=0,this.__detail=0;}getFormat(){return this.getLatest().__format}getDetail(){return this.getLatest().__detail}getMode(){const t=this.getLatest();return J$7[t.__mode]}getStyle(){return this.getLatest().__style}isToken(){return 1===this.getLatest().__mode}isComposing(){return this.__key===Vo()}isSegmented(){return 2===this.getLatest().__mode}isDirectionless(){return !!(1&this.getLatest().__detail)}isUnmergeable(){return !!(2&this.getLatest().__detail)}hasFormat(t){const e=z$7[t];return 0!==(this.getFormat()&e)}isSimpleText(){return "text"===this.__type&&0===this.__mode}getTextContent(){return this.getLatest().__text}getFormatFlags(t,e){return Bo(this.getLatest().__format,t,e)}canHaveFormat(){return true}isInline(){return true}createDOM(t,e){const n=this.__format,r=cr(0,n),i=ar(0,n),o=null===r?i:r,s=document.createElement(o);let l=s;
7324this.hasFormat("code")&&s.setAttribute("spellcheck","false"),null!==r&&(l=document.createElement(i),s.appendChild(l));dr(l,this,0,n,this.__text,t);const c=this.__style;return ""!==c&&nr(s.style,c),s}updateDOM(e,n,r){const i=this.__text,o=e.__format,s=this.__format,l=cr(0,o),c=cr(0,s),a=ar(0,o),u=ar(0,s);if((null===l?a:l)!==(null===c?u:c))return true;if(l===c&&a!==u){const e=n.firstChild;null==e&&t(48);const o=document.createElement(u);return dr(o,this,0,s,i,r),n.replaceChild(o,e),false}let f=n;null!==c&&null!==l&&(f=n.firstChild,null==f&&t(49)),fr(i,f,this);const d=r.theme.text;void 0!==d&&o!==s&&ur(0,o,s,f,d);const h=e.__style,g=this.__style;return h!==g&&nr(n.style,g,h),false}static importDOM(){return {"#text":()=>({conversion:xr,priority:0}),b:()=>({conversion:pr,priority:0}),code:()=>({conversion:vr,priority:0}),em:()=>({conversion:vr,priority:0}),i:()=>({conversion:vr,priority:0}),mark:()=>({conversion:vr,priority:0}),s:()=>({conversion:vr,priority:0}),span:()=>({conversion:_r,priority:0}),strong:()=>({conversion:vr,priority:0}),sub:()=>({conversion:vr,priority:0}),sup:()=>({conversion:vr,priority:0}),u:()=>({conversion:vr,priority:0})}}static importJSON(t){return kr().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setTextContent(t.text).setFormat(t.format).setDetail(t.detail).setMode(t.mode).setStyle(t.style)}exportDOM(e){let{element:n}=super.exportDOM(e);return Ys(n)||t(132),n.style.whiteSpace="pre-wrap",this.hasFormat("lowercase")?n.style.textTransform="lowercase":this.hasFormat("uppercase")?n.style.textTransform="uppercase":this.hasFormat("capitalize")&&(n.style.textTransform="capitalize"),this.hasFormat("bold")&&(n=hr(n,"b")),this.hasFormat("italic")&&(n=hr(n,"i")),this.hasFormat("strikethrough")&&(n=hr(n,"s")),this.hasFormat("underline")&&(n=hr(n,"u")),{element:n}}exportJSON(){return {detail:this.getDetail(),format:this.getFormat(),mode:this.getMode(),style:this.getStyle(),text:this.getTextContent(),...super.exportJSON()}}selectionTransform(t,e){}setFormat(t){const e=this.getWritable();return e.__format="string"==typeof t?z$7[t]:t,e}setDetail(t){const e=this.getWritable();return e.__detail="string"==typeof t?R$4[t]:t,e}setStyle(t){const e=this.getWritable();return e.__style=t,e}toggleFormat(t){const e=Bo(this.getFormat(),t,null);return this.setFormat(e)}toggleDirectionless(){const t=this.getWritable();return t.__detail^=1,t}toggleUnmergeable(){const t=this.getWritable();return t.__detail^=2,t}setMode(t){const e=$$4[t];if(this.__mode===e)return this;const n=this.getWritable();return n.__mode=e,n}setTextContent(t){if(this.__text===t)return this;const e=this.getWritable();return e.__text=t,e}select(t,e){xi();let n=t,r=e;const i=Qr(),o=this.getTextContent(),s=this.__key;if("string"==typeof o){const t=o.length;void 0===n&&(n=t),void 0===r&&(r=t);}else n=0,r=0;if(!Fr(i))return Yr(s,n,s,r,"text","text");{const t=Vo();t!==i.anchor.key&&t!==i.focus.key||Uo(s),i.setTextNodeRange(this,n,this,r);}return i}selectStart(){return this.select(0,0)}selectEnd(){const t=this.getTextContentSize();return this.select(t,t)}spliceText(t,e,n,r){const i=this.getWritable(),o=i.__text,s=n.length;let l=t;l<0&&(l=s+l,l<0&&(l=0));const c=Qr();if(r&&Fr(c)){const e=t+s;c.setTextNodeRange(i,e,i,e);}const a=o.slice(0,l)+n+o.slice(l+e);return i.__text=a,i}canInsertTextBefore(){return true}canInsertTextAfter(){return true}splitText(...t){xi();const e=this.getLatest(),n=e.getTextContent();if(""===n)return [];const r=e.__key,i=Vo(),o=n.length;t.sort((t,e)=>t-e),t.push(o);const s=[],l=t.length;for(let e=0,r=0;e<o&&r<=l;r++){const i=t[r];i>e&&(s.push(n.slice(e,i)),e=i);}const c=s.length;if(1===c)return [e];const a=s[0],u=e.getParent();let f;const d=e.getFormat(),h=e.getStyle(),g=e.__detail;let _=false,p=null,y=null;const m=Qr();if(Fr(m)){const[t,e]=m.isBackward()?[m.focus,m.anchor]:[m.anchor,m.focus];"text"===t.type&&t.key===r&&(p=t),"text"===e.type&&e.key===r&&(y=e);}e.isSegmented()?(f=kr(a),f.__format=d,f.__style=h,f.__detail=g,f.__state=yt$6(e,f),_=true):f=e.setTextContent(a);const x=[f];for(let t=1;t<c;t++){const n=kr(s[t]);n.__format=d,n.__style=h,n.__detail=g,n.__state=yt$6(e,n);const o=n.__key;i===r&&Uo(o),x.push(n);}const C=p?p.offset:null,S=y?y.offset:null;let v=0;for(const t of x){if(!p&&!y)break;const e=v+t.getTextContentSize();if(null!==p&&null!==C&&C<=e&&C>=v&&(p.set(t.getKey(),C-v,"text"),C<e&&(p=null)),null!==y&&null!==S&&S<=e&&S>=v){y.set(t.getKey(),S-v,"text");break}v=e;}if(null!==u){!function(t){const e=t.getPreviousSibling(),n=t.getNextSibling();null!==e&&jo(e);null!==n&&jo(n);}(this);const t=u.getWritable(),e=this.getIndexWithinParent();_?(t.splice(e,0,x),this.remove()):t.splice(e,1,x),Fr(m)&&ti(m,u,e,c-1);}return x}mergeWithSibling(e){const n=e===this.getPreviousSibling();n||e===this.getNextSibling()||t(50);const r=this.__key,i=e.__key,o=this.__text,s=o.length;Vo()===i&&Uo(r);const l=Qr();if(Fr(l)){const t=l.anchor,o=l.focus;null!==t&&t.key===i&&ri(t,n,r,e,s),null!==o&&o.key===i&&ri(o,n,r,e,s);}const c=e.__text,a=n?c+o:o+c;this.setTextContent(a);const u=this.getWritable();return e.remove(),u}isTextEntity(){return false}}function _r(t){return {forChild:Nr(t.style),node:null}}function pr(t){const e=t,n="normal"===e.style.fontWeight;return {forChild:Nr(e.style,n?void 0:"bold"),node:null}}const yr=new WeakMap;function mr(t){if(!Ys(t))return false;if("PRE"===t.nodeName)return true;const e=t.style.whiteSpace;return "string"==typeof e&&e.startsWith("pre")}function xr(e){const n=e;null===e.parentElement&&t(129);let r=n.textContent||"";if(null!==function(t){let e,n=t.parentNode;const r=[t];for(;null!==n&&void 0===(e=yr.get(n))&&!mr(n);)r.push(n),n=n.parentNode;const i=void 0===e?n:e;for(let t=0;t<r.length;t++)yr.set(r[t],i);return i}(n)){const t=r.split(/(\r?\n|\t)/),e=[],n=t.length;for(let r=0;r<n;r++){const n=t[r];"\n"===n||"\r\n"===n?e.push(or()):"\t"===n?e.push(wr()):""!==n&&e.push(kr(n));}return {node:e}}if(r=r.replace(/\r/g,"").replace(/[ \t\n]+/g," "),""===r)return {node:null};if(" "===r[0]){let t=n,e=true;for(;null!==t&&null!==(t=Cr(t,false));){const n=t.textContent||"";if(n.length>0){/[ \t\n]$/.test(n)&&(r=r.slice(1)),e=false;break}}e&&(r=r.slice(1));}if(" "===r[r.length-1]){let t=n,e=true;for(;null!==t&&null!==(t=Cr(t,true));){if((t.textContent||"").replace(/^( |\t|\r?\n)+/,"").length>0){e=false;break}}e&&(r=r.slice(0,r.length-1));}return ""===r?{node:null}
7324:{node:kr(r)}}function Cr(t,e){let n=t;for(;;){let t;for(;null===(t=e?n.nextSibling:n.previousSibling);){const t=n.parentElement;if(null===t)return null;n=t;}if(n=t,Ys(n)){const t=n.style.display;if(""===t&&!Gs(n)||""!==t&&!t.startsWith("inline"))return null}let r=n;for(;null!==(r=e?n.firstChild:n.lastChild);)n=r;if(Ko(n))return n;if("BR"===n.nodeName)return null}}const Sr={code:"code",em:"italic",i:"italic",mark:"highlight",s:"strikethrough",strong:"bold",sub:"subscript",sup:"superscript",u:"underline"};function vr(t){const e=Sr[t.nodeName.toLowerCase()];return void 0===e?{node:null}:{forChild:Nr(t.style,e),node:null}}function kr(t=""){return zs(new gr(t))}function Tr(t){return t instanceof gr}function Nr(t,e){const n=t.fontWeight,r=t.textDecoration.split(" "),i="700"===n||"bold"===n,o=r.includes("line-through"),s="italic"===t.fontStyle,l=r.includes("underline"),c=t.verticalAlign;return t=>Tr(t)?(i&&!t.hasFormat("bold")&&t.toggleFormat("bold"),o&&!t.hasFormat("strikethrough")&&t.toggleFormat("strikethrough"),s&&!t.hasFormat("italic")&&t.toggleFormat("italic"),l&&!t.hasFormat("underline")&&t.toggleFormat("underline"),"sub"!==c||t.hasFormat("subscript")||t.toggleFormat("subscript"),"super"!==c||t.hasFormat("superscript")||t.toggleFormat("superscript"),e&&!t.hasFormat(e)&&t.toggleFormat(e),t):t}class br extends gr{static getType(){return "tab"}static clone(t){return new br(t.__key)}constructor(t){super("\t",t),this.__detail=2;}static importDOM(){return null}createDOM(t){const e=super.createDOM(t),n=ms(t.theme,"tab");if(void 0!==n){e.classList.add(...n);}return e}static importJSON(t){return wr().updateFromJSON(t)}setTextContent(t){return "\t"!==t&&""!==t&&e(126),super.setTextContent("\t")}spliceText(e,n,r,i){return ""===r&&0===n||"\t"===r&&1===n||t(286),this}setDetail(e){return 2!==e&&t(127),this}setMode(e){return "normal"!==e&&t(128),this}canInsertTextBefore(){return false}canInsertTextAfter(){return false}}function wr(){return zs(new br)}function Er(t){return t instanceof br}class Or{key;offset;type;_selection;constructor(t,e,n){this._selection=null,this.key=t,this.offset=e,this.type=n;}is(t){return this.key===t.key&&this.offset===t.offset&&this.type===t.type}isBefore(t){if(this.key===t.key)return this.offset<t.offset;return Jl(rc(ql(this,"next")),rc(ql(t,"next")))<0}getNode(){const e=Yo(this.key);return null===e&&t(20),e}set(t,e,n,r){const i=this._selection,o=this.key;r&&this.key===t&&this.offset===e&&this.type===n||(this.key=t,this.offset=e,this.type=n,mi()||(Vo()===o&&Uo(t),null!==i&&(i.setCachedNodes(null),i.dirty=true)));}}function Mr(t,e,n){return new Or(t,e,n)}function Ar(t,e){let n=e.__key,r=t.offset,i="element";if(Tr(e)){i="text";const t=e.getTextContentSize();r>t&&(r=t);}else if(!Wi(e)){const t=e.getNextSibling();if(Tr(t))n=t.__key,r=0,i="text";else {const t=e.getParent();t&&(n=t.__key,r=e.getIndexWithinParent()+1);}}t.set(n,r,i);}function Dr(t,e){if(Wi(e)){const n=e.getLastDescendant();Wi(n)||Tr(n)?Ar(t,n):Ar(t,e);}else Ar(t,e);}class Pr{_nodes;_cachedNodes;dirty;constructor(t){this._cachedNodes=null,this._nodes=t,this.dirty=false;}getCachedNodes(){return this._cachedNodes}setCachedNodes(t){this._cachedNodes=t;}is(t){if(!Ir(t))return false;const e=this._nodes,n=t._nodes;return e.size===n.size&&Array.from(e).every(t=>n.has(t))}isCollapsed(){return false}isBackward(){return false}getStartEndPoints(){return null}add(t){this.dirty=true,this._nodes.add(t),this._cachedNodes=null;}delete(t){this.dirty=true,this._nodes.delete(t),this._cachedNodes=null;}clear(){this.dirty=true,this._nodes.clear(),this._cachedNodes=null;}has(t){return this._nodes.has(t)}clone(){return new Pr(new Set(this._nodes))}extract(){return this.getNodes()}insertRawText(t){}insertText(){}insertNodes(t){const e=this.getNodes(),n=e.length,r=e[n-1];let i;if(Tr(r))i=r.select();else {const t=r.getIndexWithinParent()+1;i=r.getParentOrThrow().select(t,t);}i.insertNodes(t);for(let t=0;t<n;t++)e[t].remove();}getNodes(){const t=this._cachedNodes;if(null!==t)return t;const e=this._nodes,n=[];for(const t of e){const e=Yo(t);null!==e&&n.push(e);}return mi()||(this._cachedNodes=n),n}getTextContent(){const t=this.getNodes();let e="";for(let n=0;n<t.length;n++)e+=t[n].getTextContent();return e}deleteNodes(){const t=this.getNodes();if((Qr()||Zr())===this&&t[0]){const e=Ol(t[0],"next");Gl(Wl(e,e));}for(const e of t)e.remove();}}function Fr(t){return t instanceof Lr}class Lr{format;style;anchor;focus;_cachedNodes;dirty;constructor(t,e,n,r){this.anchor=t,this.focus=e,t._selection=this,e._selection=this,this._cachedNodes=null,this.format=n,this.style=r,this.dirty=false;}getCachedNodes(){return this._cachedNodes}setCachedNodes(t){this._cachedNodes=t;}is(t){return !!Fr(t)&&(this.anchor.is(t.anchor)&&this.focus.is(t.focus)&&this.format===t.format&&this.style===t.style)}isCollapsed(){return this.anchor.is(this.focus)}getNodes(){const t=this._cachedNodes;if(null!==t)return t;const e=function(t){const e=[],[n,r]=t.getTextSlices();n&&e.push(n.caret.origin);const i=new Set,o=new Set;for(const n of t)if(Nl(n)){const{origin:t}=n;
73240===e.length?i.add(t):(o.add(t),e.push(t));}else {const{origin:t}=n;Wi(t)&&o.has(t)||e.push(t);}r&&e.push(r.caret.origin);if(Tl(t.focus)&&Wi(t.focus.origin)&&null===t.focus.getNodeAtCaret())for(let n=Pl(t.focus.origin,"previous");Nl(n)&&i.has(n.origin)&&!n.origin.isEmpty()&&n.origin.is(e[e.length-1]);n=Ll(n))i.delete(n.origin),e.pop();for(;e.length>1;){const t=e[e.length-1];if(!Wi(t)||o.has(t)||t.isEmpty()||i.has(t))break;e.pop();}if(0===e.length&&t.isCollapsed()){const n=rc(t.anchor),r=rc(t.anchor.getFlipped()),i=t=>vl(t)?t.origin:t.getNodeAtCaret(),o=i(n)||i(r)||(t.anchor.getNodeAtCaret()?n.origin:r.origin);e.push(o);}return e}(sc(Ql(this),"next"));return mi()||(this._cachedNodes=e),e}setTextNodeRange(t,e,n,r){this.anchor.set(t.__key,e,"text"),this.focus.set(n.__key,r,"text");}getTextContent(){const t=this.getNodes();if(0===t.length)return "";const e=t[0],n=t[t.length-1],r=this.anchor,i=this.focus,o=r.isBefore(i),[s,l]=zr(this);let c="",a=true;for(let u=0;u<t.length;u++){const f=t[u];if(Wi(f)&&!f.isInline())a||(c+="\n"),a=!f.isEmpty();else if(a=false,Tr(f)){let t=f.getTextContent();f===e?f===n?"element"===r.type&&"element"===i.type&&i.offset!==r.offset||(t=s<l?t.slice(s,l):t.slice(l,s)):t=o?t.slice(s):t.slice(l):f===n&&(t=o?t.slice(0,l):t.slice(0,s)),c+=t;}else !ji(f)&&!sr(f)||f===n&&this.isCollapsed()||(c+=f.getTextContent());}return c}applyDOMRange(t){const e=vi(),n=e.getEditorState()._selection,r=Ur(t.startContainer,t.startOffset,t.endContainer,t.endOffset,e,n);if(null===r)return;const[i,o]=r;this.anchor.set(i.key,i.offset,i.type,true),this.focus.set(o.key,o.offset,o.type,true),St$3(this);}clone(){const t=this.anchor,e=this.focus;return new Lr(Mr(t.key,t.offset,t.type),Mr(e.key,e.offset,e.type),this.format,this.style)}toggleFormat(t){this.format=Bo(this.format,t,null),this.dirty=true;}setFormat(t){this.format=t,this.dirty=true;}setStyle(t){this.style=t,this.dirty=true;}hasFormat(t){const e=z$7[t];return 0!==(this.format&e)}insertRawText(t){const e=t.split(/(\r?\n|\t)/),n=[],r=e.length;for(let t=0;t<r;t++){const r=e[t];"\n"===r||"\r\n"===r?n.push(or()):"\t"===r?n.push(wr()):n.push(kr(r));}this.insertNodes(n);}insertText(e){const n=this.anchor,r=this.focus,i=this.format,o=this.style;let s=n,l=r;!this.isCollapsed()&&r.isBefore(n)&&(s=r,l=n),"element"===s.type&&function(t,e,n,r){const i=t.getNode(),o=i.getChildAtIndex(t.offset),s=kr();if(s.setFormat(n),s.setStyle(r),no(o))o.splice(0,0,[s]);else {const t=Vi(i)?eo().append(s):s;null===o?i.append(t):o.insertBefore(t);}t.is(e)&&e.set(s.__key,0,"text"),t.set(s.__key,0,"text");}(s,l,i,o),"element"===l.type&&Hl(l,rc(ql(l,"next")));const c=s.offset;let a=l.offset;const u=this.getNodes(),f=u.length;let d=u[0];Tr(d)||t(26);const h=d.getTextContent().length,g=d.getParentOrThrow();let _=u[f-1];if(1===f&&"element"===l.type&&(a=h,l.set(s.key,a,"text")),this.isCollapsed()&&c===h&&(Io(d)||!d.canInsertTextAfter()||!g.canInsertTextAfter()&&null===d.getNextSibling())){let t=d.getNextSibling();if(Tr(t)&&t.canInsertTextBefore()&&!Io(t)||(t=kr(),t.setFormat(i),t.setStyle(o),g.canInsertTextAfter()?d.insertAfter(t):g.insertAfter(t)),t.select(0,0),d=t,""!==e)return void this.insertText(e)}else if(this.isCollapsed()&&0===c&&(Io(d)||!d.canInsertTextBefore()||!g.canInsertTextBefore()&&null===d.getPreviousSibling())){let t=d.getPreviousSibling();if(Tr(t)&&!Io(t)||(t=kr(),t.setFormat(i),g.canInsertTextBefore()?d.insertBefore(t):g.insertBefore(t)),t.select(),d=t,""!==e)return void this.insertText(e)}else if(d.isSegmented()&&c!==h){const t=kr(d.getTextContent());t.setFormat(i),d.replace(t),d=t;}else if(!this.isCollapsed()&&""!==e){const t=_.getParent();if(!g.canInsertTextBefore()||!g.canInsertTextAfter()||Wi(t)&&(!t.canInsertTextBefore()||!t.canInsertTextAfter()))return this.insertText(""),jr(this.anchor,this.focus),void this.insertText(e)}if(1===f){if(Lo(d)){const t=kr(e);return t.select(),void d.replace(t)}const t=d.getFormat(),n=d.getStyle();if(c!==a||t===i&&n===o){if(Er(d)){const t=kr(e);return t.setFormat(i),t.setStyle(o),t.select(),void d.replace(t)}}else {if(""!==d.getTextContent()){const t=kr(e);
7324if(t.setFormat(i),t.setStyle(o),t.select(),0===c)d.insertBefore(t,false);else {const[e]=d.splitText(c);e.insertAfter(t,false);}return void(t.isComposing()&&"text"===this.anchor.type&&(this.anchor.offset-=e.length))}d.setFormat(i),d.setStyle(o);}const r=a-c;d=d.spliceText(c,r,e,true),""===d.getTextContent()?d.remove():"text"===this.anchor.type&&(this.format=t,this.style=n,d.isComposing()&&(this.anchor.offset-=e.length));}else {const t=new Set([...d.getParentKeys(),..._.getParentKeys()]),n=Wi(d)?d:d.getParentOrThrow();let r=Wi(_)?_:_.getParentOrThrow(),i=_;if(!n.is(r)&&r.isInline())do{i=r,r=r.getParentOrThrow();}while(r.isInline());if("text"===l.type&&(0!==a||""===_.getTextContent())||"element"===l.type&&_.getIndexWithinParent()<a)if(Tr(_)&&!Lo(_)&&a!==_.getTextContentSize()){if(_.isSegmented()){const t=kr(_.getTextContent());_.replace(t),_=t;}Vi(l.getNode())||"text"!==l.type||(_=_.spliceText(0,a,"")),t.add(_.__key);}else {const t=_.getParentOrThrow();t.canBeEmpty()||1!==t.getChildrenSize()?_.remove():t.remove();}else t.add(_.__key);const o=r.getChildren(),s=new Set(u),g=n.is(r),p=n.isInline()&&null===d.getNextSibling()?n:d;for(let t=o.length-1;t>=0;t--){const e=o[t];
7324if(e.is(d)||Wi(e)&&e.isParentOf(d))break;e.isAttached()&&(!s.has(e)||e.is(i)?g||p.insertAfter(e,false):e.remove());}if(!g){let e=r,n=null;for(;null!==e;){const r=e.getChildren(),i=r.length;(0===i||r[i-1].is(n))&&(t.delete(e.__key),n=e),e=e.getParent();}}if(Lo(d))if(c===h)d.select();else {const t=kr(e);t.select(),d.replace(t);}else d=d.spliceText(c,h-c,e,true),""===d.getTextContent()?d.remove():"text"===this.anchor.type&&(this.format=d.getFormat(),this.style=d.getStyle(),d.isComposing()&&(this.anchor.offset-=e.length));for(let e=1;e<f;e++){const n=u[e],r=n.__key;t.has(r)||n.remove();}}}removeText(){const t=Qr()===this;Xl(this,nc(Ql(this))),t&&Qr()!==this&&es(this);}formatText(t,e=null){if(this.isCollapsed())return this.toggleFormat(t),void Uo(null);const n=this.getNodes(),r=[];for(const t of n)Tr(t)&&r.push(t);const i=e=>{n.forEach(n=>{if(Wi(n)){const r=n.getFormatFlags(t,e);n.setTextFormat(r);}});},o=r.length;if(0===o)return this.toggleFormat(t),Uo(null),void i(e);const s=this.anchor,l=this.focus,c=this.isBackward(),a=c?l:s,u=c?s:l;let f=0,d=r[0],h="element"===a.type?0:a.offset;if("text"===a.type&&h===d.getTextContentSize()&&(f=1,d=r[1],h=0),null==d)return;const g=d.getFormatFlags(t,e);i(g);const _=o-1;let p=r[_];const y="text"===u.type?u.offset:p.getTextContentSize();if(d.is(p)){if(h===y)return;if(Io(d)||0===h&&y===d.getTextContentSize())d.setFormat(g);else {const t=d.splitText(h,y),e=0===h?t[0]:t[1];e.setFormat(g),"text"===a.type&&a.set(e.__key,0,"text"),"text"===u.type&&u.set(e.__key,y-h,"text");}return void(this.format=g)}0===h||Io(d)||([,d]=d.splitText(h),h=0),d.setFormat(g);const m=p.getFormatFlags(t,g);y>0&&(y===p.getTextContentSize()||Io(p)||([p]=p.splitText(y)),p.setFormat(m));for(let e=f+1;e<_;e++){const n=r[e],i=n.getFormatFlags(t,m);n.setFormat(i);}"text"===a.type&&a.set(d.__key,h,"text"),"text"===u.type&&u.set(p.__key,y,"text"),this.format=g|m;}insertNodes(e){if(0===e.length)return;if(this.isCollapsed()||this.removeText(),"root"===this.anchor.key){this.insertParagraph();const n=Qr();return Fr(n)||t(134),n.insertNodes(e)}const n=(this.isBackward()?this.focus:this.anchor).getNode(),r=dl(n,Qs),i=e[e.length-1];if(Wi(r)&&"__language"in r){if("__language"in e[0])this.insertText(e[0].getTextContent());else {const t=ai(this);r.splice(t,0,e),i.selectEnd();}return}if(!e.some(t=>(Wi(t)||ji(t))&&!t.isInline())){Wi(r)||t(211,n.constructor.name,n.getType());const o=ai(this);return r.splice(o,0,e),void i.selectEnd()}const o=function(t){const e=eo();let n=null;for(let r=0;r<t.length;r++){const i=t[r],o=sr(i);if(o||ji(i)&&i.isInline()||Wi(i)&&i.isInline()||Tr(i)||i.isParentRequired()){if(null===n&&(n=i.createParentElementNode(),e.append(n),o))continue;null!==n&&n.append(i);}else e.append(i),n=null;}return e}(e),s=o.getLastDescendant(),l=o.getChildren(),c=!Wi(r)||!r.isEmpty()?this.insertParagraph():null,a=l[l.length-1];let u=l[0];var f;Wi(f=u)&&Qs(f)&&!f.isEmpty()&&Wi(r)&&(!r.isEmpty()||r.canMergeWhenEmpty())&&(Wi(r)||t(211,n.constructor.name,n.getType()),r.append(...u.getChildren()),u=l[1]),u&&(null===r&&t(212,n.constructor.name,n.getType()),function(e,n){const r=n.getParentOrThrow().getLastChild();let i=n;const o=[n];for(;i!==r;)i.getNextSibling()||t(140),i=i.getNextSibling(),o.push(i);let s=e;for(const t of o)s=s.insertAfter(t);}(r,u));const d=dl(s,Qs);c&&Wi(d)&&(c.canMergeWhenEmpty()||Qs(a))&&(d.append(...c.getChildren()),c.remove()),Wi(r)&&r.isEmpty()&&r.remove(),s.selectEnd();const h=Wi(r)?r.getLastChild():null;sr(h)&&d!==r&&h.remove();}insertParagraph(){if("root"===this.anchor.key){const t=eo();return Zo().splice(this.anchor.offset,0,[t]),t.select(),t}const e=ai(this),n=dl(this.anchor.getNode(),Qs);Wi(n)||t(213);const r=n.getChildAtIndex(e),i=r?[r,...r.getNextSiblings()]:[],o=n.insertNewAfter(this,false);return o?(o.append(...i),o.selectStart(),o):null}insertLineBreak(t){const e=or();if(this.insertNodes([e]),t){const t=e.getParentOrThrow(),n=e.getIndexWithinParent();t.select(n,n);}}extract(){const t=[...this.getNodes()],e=t.length;let n=t[0],r=t[e-1];const[i,o]=zr(this),s=this.isBackward(),[l,c]=s?[this.focus,this.anchor]:[this.anchor,this.focus],[a,u]=s?[o,i]:[i,o];if(0===e)return [];if(1===e){if(Tr(n)&&!this.isCollapsed()){const t=n.splitText(a,u),e=0===a?t[0]:t[1];return e?(l.set(e.getKey(),0,"text"),c.set(e.getKey(),e.getTextContentSize(),"text"),[e]):[]}return [n]}if(Tr(n)&&(a===n.getTextContentSize()?t.shift():0!==a&&([,n]=n.splitText(a),t[0]=n,l.set(n.getKey(),0,"text"))),Tr(r)){const e=r.getTextContent().length;0===u?t.pop():u!==e&&([r]=r.splitText(u),t[t.length-1]=r,c.set(r.getKey(),r.getTextContentSize(),"text"));}return t}modify(t,e,n){if(fi(this,t,e,n))return;const r="move"===t,i=vi(),o=Js(Ps(i));if(!o)return;const s=i._blockCursorElement,l=i._rootElement,c=this.focus.getNode();if(null===l||null===s||!Wi(c)||c.isInline()||c.canBeEmpty()||$s(s,i,l),this.dirty){let t=Ns(i,this.anchor.key),e=Ns(i,this.focus.key);"text"===this.anchor.type&&(t=Ro(t)),"text"===this.focus.type&&(e=Ro(e)),t&&e&&ii(o,t,this.anchor.offset,e,this.focus.offset);}if(function(t,e,n,r){t.modify(e,n,r);}(o,t,e?"backward":"forward",n),o.rangeCount>0){const t=o.getRangeAt(0),n=this.anchor.getNode(),i=Vi(n)?n:Ls(n);if(this.applyDOMRange(t),this.dirty=true,!r){const n=this.getNodes(),r=[];let s=false;for(let t=0;t<n.length;t++){const e=n[t];As(e,i)?r.push(e):s=true;}if(s&&r.length>0)if(e){const t=r[0];Wi(t)?t.selectStart():t.getParentOrThrow().selectStart();}else {const t=r[r.length-1];Wi(t)?t.selectEnd():t.getParentOrThrow().selectEnd();}
7324o.anchorNode===t.startContainer&&o.anchorOffset===t.startOffset||function(t){const e=t.focus,n=t.anchor,r=n.key,i=n.offset,o=n.type;n.set(e.key,e.offset,e.type,true),e.set(r,i,o,true);}(this);}}"lineboundary"===n&&fi(this,t,e,n,"decorators");}forwardDeletion(t,e,n){if(!n&&("element"===t.type&&Wi(e)&&t.offset===e.getChildrenSize()||"text"===t.type&&t.offset===e.getTextContentSize())){const t=e.getParent(),n=e.getNextSibling()||(null===t?null:t.getNextSibling());if(Wi(n)&&n.isShadowRoot())return true}return false}deleteCharacter(t){const e=this.isCollapsed();if(this.isCollapsed()){const e=this.anchor;let n=e.getNode();if(this.forwardDeletion(e,n,t))return;const r=Rl(ql(e,t?"previous":"next"));if(r.getTextSlices().every(t=>null===t||0===t.distance)){let t={type:"initial"};for(const e of r.iterNodeCarets("shadowRoot"))if(Nl(e))if(e.origin.isInline());else {if(e.origin.isShadowRoot()){if("merge-block"===t.type)break;if(Wi(r.anchor.origin)&&r.anchor.origin.isEmpty()){const t=rc(e);Xl(this,Wl(t,t)),r.anchor.origin.remove();}return}"merge-next-block"!==t.type&&"merge-block"!==t.type||(t={block:t.block,caret:e,type:"merge-block"});}else {if("merge-block"===t.type)break;if(Tl(e)){if(Wi(e.origin)){if(e.origin.isInline()){if(!e.origin.isParentOf(r.anchor.origin))break}else t={block:e.origin,type:"merge-next-block"};continue}if(ji(e.origin)){if(e.origin.isIsolated());else if("merge-next-block"===t.type&&(e.origin.isKeyboardSelectable()||!e.origin.isInline())&&Wi(r.anchor.origin)&&r.anchor.origin.isEmpty()){r.anchor.origin.remove();const t=Hr();t.add(e.origin.getKey()),es(t);}else e.origin.remove();return}break}}if("merge-block"===t.type){const{caret:e,block:n}=t;return Xl(this,Wl(!e.origin.isEmpty()&&n.isEmpty()?Zl(Ol(n,e.direction)):r.anchor,e)),this.removeText()}}const i=this.focus;if(this.modify("extend",t,"character"),this.isCollapsed()){if(t&&0===e.offset&&Rr(this,e.getNode()))return}else {const r="text"===i.type?i.getNode():null;if(n="text"===e.type?e.getNode():null,null!==r&&r.isSegmented()){const e=i.offset,o=r.getTextContentSize();if(r.is(n)||t&&e!==o||!t&&0!==e)return void Wr(r,t,e)}else if(null!==n&&n.isSegmented()){const i=e.offset,o=n.getTextContentSize();if(n.is(r)||t&&0!==i||!t&&i!==o)return void Wr(n,t,i)}!function(t,e){const n=t.anchor,r=t.focus,i=n.getNode(),o=r.getNode();if(i===o&&"text"===n.type&&"text"===r.type){const t=n.offset,o=r.offset,s=t<o,l=s?t:o,c=s?o:t,a=c-1;if(l!==a){(function(t){return !(rs(t)||Br(t))})(i.getTextContent().slice(l,c))&&(e?r.set(r.key,a,r.type):n.set(n.key,a,n.type));}}}(this,t);}}if(this.removeText(),t&&!e&&this.isCollapsed()&&"element"===this.anchor.type&&0===this.anchor.offset){const t=this.anchor.getNode();t.isEmpty()&&Vi(t.getParent())&&null===t.getPreviousSibling()&&Rr(this,t);}}deleteLine(t){this.isCollapsed()&&this.modify("extend",t,"lineboundary"),this.isCollapsed()?this.deleteCharacter(t):this.removeText();}deleteWord(t){if(this.isCollapsed()){const e=this.anchor,n=e.getNode();if(this.forwardDeletion(e,n,t))return;this.modify("extend",t,"word");}this.isCollapsed()?this.deleteCharacter(t):this.removeText();}isBackward(){return this.focus.isBefore(this.anchor)}getStartEndPoints(){return [this.anchor,this.focus]}}function Ir(t){return t instanceof Pr}function Kr(t){const e=t.offset;if("text"===t.type)return e;const n=t.getNode();return e===n.getChildrenSize()?n.getTextContent().length:0}function zr(t){const e=t.getStartEndPoints();if(null===e)return [0,0];const[n,r]=e;return "element"===n.type&&"element"===r.type&&n.key===r.key&&n.offset===r.offset?[0,0]:[Kr(n),Kr(r)]}function Rr(t,e){for(let n=e;n;n=n.getParent()){if(Wi(n)){if(n.collapseAtStart(t))return true;if(Is(n))break}if(n.getPreviousSibling())break}return false}const Br=(()=>{try{const t=new RegExp("\\p{Emoji}","u"),e=t.test.bind(t);if(e("\u2764\ufe0f")&&e("#\ufe0f\u20e3")&&e("\u{1f44d}"))return e}catch(t){}return ()=>false})();function Wr(t,e,n){const r=t,i=r.getTextContent().split(/(?=\s)/g),o=i.length;let s=0,l=0;for(let t=0;t<o;t++){const r=t===o-1;if(l=s,s+=i[t].length,e&&s===n||s>n||r){i.splice(t,1),r&&(l=void 0);break}}const c=i.join("").trim();""===c?r.remove():(r.setTextContent(c),r.select(l,l));}function $r(e,n,r,i){let o,s=n;if(Ys(e)){let l=false;const c=e.childNodes,a=c.length,u=i._blockCursorElement;s===a&&(l=true,s=a-1);let f=c[s],d=false;if(f===u)f=c[s+1],d=true;else if(null!==u){const t=u.parentNode;if(e===t){n>Array.prototype.indexOf.call(t.children,u)&&s--;}}if(o=ns(f),Tr(o))s=Al(o,l?"next":"previous");else {let c=ns(e);if(null===c)return null;if(Wi(c)){const a=i.getElementByKey(c.getKey());null===a&&t(214);const u=tl(i).$getDOMSlot(c,a,i);
7324[c,s]=u.resolveChildIndex(c,a,e,n),Wi(c)||t(215),l&&s>=c.getChildrenSize()&&(s=Math.max(0,c.getChildrenSize()-1));let f=c.getChildAtIndex(s);if(Wi(f)&&function(t,e,n){const r=t.getParent();return null===n||null===r||!r.canBeEmpty()||r!==n.getNode()}(f,0,r)){const t=l?f.getLastDescendant():f.getFirstDescendant();null===t?c=f:(f=t,c=Wi(f)?f:f.getParentOrThrow()),s=0;}Tr(f)?(o=f,c=null,s=Al(f,l?"next":"previous")):f!==c&&l&&!d&&(Wi(c)||t(216),s=Math.min(c.getChildrenSize(),s+1));}else {const t=c.getIndexWithinParent();s=0===n&&ji(c)&&ns(e)===c?t:t+1,c=c.getParentOrThrow();}if(Wi(c))return Mr(c.__key,s,"element")}}else o=ns(e);return Tr(o)?Mr(o.__key,Al(o,s,"clamp"),"text"):null}function Jr(t,e,n){const r=t.offset,i=t.getNode();if(0===r){const r=i.getPreviousSibling(),o=i.getParent();if(e){if((n||!e)&&null===r&&Wi(o)&&o.isInline()){const e=o.getPreviousSibling();Tr(e)&&t.set(e.__key,e.getTextContent().length,"text");}}else Wi(r)&&!n&&r.isInline()?t.set(r.__key,r.getChildrenSize(),"element"):Tr(r)&&t.set(r.__key,r.getTextContent().length,"text");}else if(r===i.getTextContent().length){const r=i.getNextSibling(),o=i.getParent();if(e&&Wi(r)&&r.isInline())t.set(r.__key,0,"element");else if((n||e)&&null===r&&Wi(o)&&o.isInline()&&!o.canInsertTextAfter()){const e=o.getNextSibling();Tr(e)&&t.set(e.__key,0,"text");}}}function jr(t,e,n){if("text"===t.type&&"text"===e.type){const n=t.isBefore(e),r=t.is(e);Jr(t,n,r),Jr(e,!n,r),r&&e.set(t.key,t.offset,t.type);}}function Ur(t,e,n,r,i,o){if(null===t||null===n||!Mo(i,t,n))return null;const s=$r(t,e,Fr(o)?o.anchor:null,i);if(null===s)return null;const l=$r(n,r,Fr(o)?o.focus:null,i);if(null===l)return null;if("element"===s.type&&"element"===l.type){const e=ns(t),r=ns(n);if(ji(e)&&ji(r))return null}return jr(s,l),[s,l]}function Vr(t){return Wi(t)&&!t.isInline()}function Yr(t,e,n,r,i,o){const s=Si(),l=new Lr(Mr(t,e,i),Mr(n,r,o),0,"");return l.dirty=true,s._selection=l,l}function qr(){const t=Mr("root",0,"element"),e=Mr("root",0,"element");return new Lr(t,e,0,"")}function Hr(){return new Pr(new Set)}function Gr(t,e){return Xr(null,t,e,null)}function Xr(t,e,n,r){const i=n._window;if(null===i)return null;const o=r||i.event,s=o?o.type:void 0,l="selectionchange"===s,c=!q$7&&(l||"beforeinput"===s||"compositionstart"===s||"compositionend"===s||"click"===s&&o&&3===o.detail||"drop"===s||void 0===s);let a,u,f,d;if(Fr(t)&&!c)return t.clone();if(null===e)return null;if(a=e.anchorNode,u=e.focusNode,f=e.anchorOffset,d=e.focusOffset,(l||void 0===s)&&Fr(t)&&!Mo(n,a,u))return t.clone();const h=Ur(a,f,u,d,n,t);if(null===h)return null;const[g,_]=h;let p=0,y="";if(Fr(t)){const e=t.anchor;if(g.key===e.key)p=t.format,y=t.style;else {const t=g.getNode();Tr(t)?(p=t.getFormat(),y=t.getStyle()):Wi(t)&&(p=t.getTextFormat(),y=t.getTextStyle());}}return new Lr(g,_,p,y)}function Qr(){return Si()._selection}function Zr(){return vi()._editorState._selection}function ti(t,e,n,r=1){const i=t.anchor,o=t.focus,s=i.getNode(),l=o.getNode();if(!e.is(s)&&!e.is(l))return;const c=e.__key;if(t.isCollapsed()){const e=i.offset;if(n<=e&&r>0||n<e&&r<0){const n=Math.max(0,e+r);i.set(c,n,"element"),o.set(c,n,"element"),ei(t);}}else {const s=t.isBackward(),l=s?o:i,a=l.getNode(),u=s?i:o,f=u.getNode();if(e.is(a)){const t=l.offset;(n<=t&&r>0||n<t&&r<0)&&l.set(c,Math.max(0,t+r),"element");}if(e.is(f)){const t=u.offset;(n<=t&&r>0||n<t&&r<0)&&u.set(c,Math.max(0,t+r),"element");}}ei(t);}function ei(t){const e=t.anchor,n=e.offset,r=t.focus,i=r.offset,o=e.getNode(),s=r.getNode();if(t.isCollapsed()){if(!Wi(o))return;const t=o.getChildrenSize(),i=n>=t,s=i?o.getChildAtIndex(t-1):o.getChildAtIndex(n);if(Tr(s)){let t=0;i&&(t=s.getTextContentSize()),e.set(s.__key,t,"text"),r.set(s.__key,t,"text");}return}if(Wi(o)){const t=o.getChildrenSize(),r=n>=t,i=r?o.getChildAtIndex(t-1):o.getChildAtIndex(n);if(Tr(i)){let t=0;r&&(t=i.getTextContentSize()),e.set(i.__key,t,"text");}}if(Wi(s)){const t=s.getChildrenSize(),e=i>=t,n=e?s.getChildAtIndex(t-1):s.getChildAtIndex(i);if(Tr(n)){let t=0;e&&(t=n.getTextContentSize()),r.set(n.__key,t,"text");}}}function ni(t,e,n,r,i){let o=null,s=0,l=null;null!==r?(o=r.__key,Tr(r)?(s=r.getTextContentSize(),l="text"):Wi(r)&&(s=r.getChildrenSize(),l="element")):null!==i&&(o=i.__key,Tr(i)?l="text":Wi(i)&&(l="element")),null!==o&&null!==l?t.set(o,s,l):(s=e.getIndexWithinParent(),-1===s&&(s=n.getChildrenSize()),t.set(n.__key,s,"element"));}function ri(t,e,n,r,i){"text"===t.type?t.set(n,t.offset+(e?0:i),"text"):t.offset>r.getIndexWithinParent()&&t.set(t.key,t.offset-1,"element");}function ii(t,e,n,r,i){try{t.setBaseAndExtent(e,n,r,i);}catch(t){}}function oi(t,e,n){const r=Ns(t,e.getKey());if(Wi(e)){const i=tl(t).$getDOMSlot(e,r,t);return [i.element,n+i.getFirstChildOffset()]}return [r,n]}function si(t,e,n,r,i,s,l){const c=r.anchorNode,a=r.focusNode,u=r.anchorOffset,f=r.focusOffset,d=document.activeElement;if(i.has(Un)&&d!==s||null!==d&&Oo(d))return;if(!Fr(e))return void(null!==t&&Mo(n,c,a)&&r.removeAllRanges());const h=e.anchor,g=e.focus,_=h.getNode(),p=g.getNode(),[y,m]=oi(n,_,h.offset),[x,C]=oi(n,p,g.offset),S=e.format,v=e.style,k=e.isCollapsed();let T=y,N=x,b=false;var w,E,O,M,A;if(("text"===h.type?(T=Ro(y),b=_.getFormat()!==S||_.getStyle()!==v):Fr(t)&&"text"===t.anchor.type&&(b=true),"text"===g.type&&(N=Ro(x)),null!==T&&null!==N)&&(k&&(null===t||b||Fr(t)&&(t.format!==S||t.style!==v))&&(w=S,E=v,O=m,M=h.key,A=performance.now(),_n$1=[w,E,O,M,A]),u!==m||f!==C||c!==T||a!==N||"Range"===r.type&&k||(null!==d&&s.contains(d)||i.has(Hn)||s.focus({preventScroll:true}),"element"===h.type))){if(ii(r,T,m,N,C),!o$1||!e.isCollapsed()||null===s||i.has(Hn)||null!==document.activeElement&&s.contains(document.activeElement)||s.focus({preventScroll:true}),!i.has(Yn)&&e.isCollapsed()&&null!==s&&s===document.activeElement){const t=Fr(e)&&"element"===e.anchor.type?T.childNodes[m]||null:r.rangeCount>0?r.getRangeAt(0):null;if(null!==t){let e;if(t instanceof Text){const n=document.createRange();n.selectNode(t),e=n.getBoundingClientRect();}else e=t.getBoundingClientRect();!function(t,e,n){const r=ws(n),i=Ds(r);if(null===r||null===i)return;let{top:o,bottom:s}=e,l=0,c=0,a=n;for(;null!==a;){const e=a===r.body;if(e){l=0,c=Ps(t).innerHeight;const e=i.getComputedStyle(r.documentElement),n=parseFloat(e.scrollPaddingTop),o=parseFloat(e.scrollPaddingBottom);
7324isFinite(n)&&(l+=n),isFinite(o)&&(c-=o);}else {const t=a.getBoundingClientRect();l=t.top,c=t.bottom;}let n=0;if(o<l?n=-(l-o):s>c&&(n=s-c),0!==n)if(e)i.scrollBy(0,n);else {const t=a.scrollTop;a.scrollTop+=n;const e=a.scrollTop-t;o-=e,s-=e;}if(e)break;a=bs(a);}}(n,e,s);}}cn$1=true;}}function li(t){let e=Qr()||Zr();null===e&&(e=Zo().selectEnd()),e.insertNodes(t);}function ci(){const t=Qr();return null===t?"":t.getTextContent()}function ai(e){let n=e;e.isCollapsed()||n.removeText();const r=Qr();Fr(r)&&(n=r),Fr(n)||t(161);const i=n.anchor;let o=i.getNode(),s=i.offset;for(;!Qs(o);){const t=o;if([o,s]=ui(o,s),t.is(o))break}return s}function ui(t,e){const n=t.getParent();if(!n){const t=eo();return Zo().append(t),t.select(),[Zo(),0]}if(Tr(t)){const r=t.splitText(e);if(0===r.length)return [n,t.getIndexWithinParent()];const i=0===e?0:1;return [n,r[0].getIndexWithinParent()+i]}if(!Wi(t)||0===e)return [n,t.getIndexWithinParent()];const r=t.getChildAtIndex(e);if(r){const n=new Lr(Mr(t.__key,e,"element"),Mr(t.__key,e,"element"),0,""),i=t.insertNewAfter(n);i&&i.append(r,...r.getNextSiblings());}return [n,t.getIndexWithinParent()+1]}function fi(t,e,n,r,i="decorators-and-blocks"){if("move"===e&&"character"===r&&!t.isCollapsed()){const[e,r]=n===t.isBackward()?[t.focus,t.anchor]:[t.anchor,t.focus];return r.set(e.key,e.offset,e.type),true}const o=ql(t.focus,n?"previous":"next"),s="lineboundary"===r,l="move"===e;let c=o,a="decorators-and-blocks"===i;if(!ic(c)){for(const t of c){a=false;const{origin:e}=t;if(!ji(e)||e.isIsolated()||(c=t,!s||!e.isInline()))break}if(a)for(const t of Rl(o).iterNodeCarets("extend"===e?"shadowRoot":"root")){if(Nl(t))t.origin.isInline()||(c=t);else {if(Wi(t.origin))continue;ji(t.origin)&&!t.origin.isInline()&&(c=t);}break}}if(c===o)return false;if(l&&!s&&ji(c.origin)&&c.origin.isKeyboardSelectable()){const t=Hr();return t.add(c.origin.getKey()),es(t),true}return c=rc(c),l&&Hl(t.anchor,c),Hl(t.focus,c),a||!s}let di=null,hi=null,gi=false,_i=false,pi=0;const yi={characterData:true,childList:true,subtree:true};function mi(){return gi||null!==di&&di._readOnly}function xi(){gi&&t(13);}function Ci(){pi>99&&t(14);}function Si(){return null===di&&t(195,ki()),di}function vi(){return null===hi&&t(337,ki()),hi}function ki(){let t=0;const e=new Set,n=Co.version;if("undefined"!=typeof window)for(const r of document.querySelectorAll("[contenteditable]")){const i=Po(r);if(Ao(i))t++;else if(i){let t=String(i.constructor.version||"<0.17.1");t===n&&(t+=" (separately built, likely a bundler configuration issue)"),e.add(t);}}let r=` Detected on the page: ${t} compatible editor(s) with version ${n}`;return e.size&&(r+=` and incompatible editors with versions ${Array.from(e).join(", ")}`),r}function Ti(){return hi}function Ni(t,e,n){const r=e.__type,i=No(t,r);let o=n.get(r);void 0===o&&(o=Array.from(i.transforms),n.set(r,o));const s=o.length;for(let t=0;t<s&&(o[t](e),e.isAttached());t++);}function bi(t,e){return void 0!==t&&t.__key!==e&&t.isAttached()}function wi(t,e){if(!e)return;const n=t._updateTags;let r=e;Array.isArray(e)||(r=[e]);for(const t of r)n.add(t);}function Ei(t){return Oi(t,vi()._nodes)}function Oi(e,n){const r=e.type,i=n.get(r);void 0===i&&t(17,r);const o=i.klass;e.type!==o.getType()&&t(18,o.name);const s=o.importJSON(e),l=e.children;if(Wi(s)&&Array.isArray(l))for(let t=0;t<l.length;t++){const e=Oi(l[t],n);s.append(e);}return s}function Mi(t,e,n){const r=di,i=gi,o=hi;di=e,gi=true,hi=t;try{return n()}finally{di=r,gi=i,hi=o;}}function Ai(t,e){const n=t._pendingEditorState,r=t._rootElement,i=t._headless||null===r;if(null===n)return void(t._deferred.length>0&&Fi(t,t._deferred));const o=t._editorState,s=o._selection,l=n._selection,c=0!==t._dirtyType,a=di,u=gi,f=hi,d=t._updating,h=t._observer;let g=null;if(t._pendingEditorState=null,t._editorState=n,!i&&c&&null!==h){hi=t,di=n,gi=false,t._updating=true;try{const e=t._dirtyType,r=t._dirtyElements,i=t._dirtyLeaves;h.disconnect(),g=ee$4(o,n,t,e,r,i);}catch(e){if(e instanceof Error&&t._onError(e),_i)throw e;return go(t,null,r,n),rt$4(t),t._dirtyType=2,_i=true,Ai(t,o),void(_i=false)}finally{h.observe(r,yi),t._updating=d,di=a,gi=u,hi=f;}}n._readOnly||(n._readOnly=true);const _=t._dirtyLeaves,p=t._dirtyElements,y=t._normalizedNodes,m=t._updateTags,x=t._deferred;c&&(t._dirtyType=0,t._cloneNotNeeded.clear(),t._dirtyLeaves=new Set,t._dirtyElements=new Map,t._normalizedNodes=new Set,t._updateTags=new Set),function(t,e){const n=t._decorators;let r=t._pendingDecorators||n;const i=e._nodeMap;let o;
7324for(o in r)i.has(o)||(r===n&&(r=Xo(t)),delete r[o]);}(t,n);const C=i?null:Js(Ps(t));if(t._editable&&null!==C&&(c||null===l||l.dirty||!l.is(s))&&null!==r&&!m.has(qn)){hi=t,di=n;try{if(null!==h&&h.disconnect(),c||null===l||l.dirty){const e=t._blockCursorElement;null!==e&&$s(e,t,r),si(s,l,t,C,m,r);}!function(t,e,n){let r=t._blockCursorElement;if(Fr(n)&&n.isCollapsed()&&"element"===n.anchor.type&&e.contains(document.activeElement)){const i=n.anchor,o=i.getNode(),s=i.offset;let l=!1,c=null;if(s===o.getChildrenSize()){Ws(o.getChildAtIndex(s-1))&&(l=!0);}else {const e=o.getChildAtIndex(s);if(null!==e&&Ws(e)){const n=e.getPreviousSibling();(null===n||Ws(n))&&(l=!0,c=t.getElementByKey(e.__key));}}if(l){const n=t.getElementByKey(o.__key);return null===r&&(t._blockCursorElement=r=function(t){const e=t.theme,n=document.createElement("div");n.contentEditable="false",n.setAttribute("data-lexical-cursor","true");let r=e.blockCursor;if(void 0!==r){if("string"==typeof r){const t=yc(r);r=e.blockCursor=t;}void 0!==r&&n.classList.add(...r);}return n}(t._config)),e.style.caretColor="transparent",void(null===c?n.appendChild(r):n.insertBefore(r,c))}}null!==r&&$s(r,t,e);}(t,r,l);}finally{null!==h&&h.observe(r,yi),hi=f,di=a;}}null!==g&&function(t,e,n,r,i){const o=Array.from(t._listeners.mutation),s=o.length;for(let t=0;t<s;t++){const[s,l]=o[t];for(const t of l){const o=e.get(t);void 0!==o&&s(o,{dirtyLeaves:r,prevEditorState:i,updateTags:n});}}}(t,g,m,_,o),Fr(l)||null===l||null!==s&&s.is(l)||t.dispatchCommand(ie$4,void 0);const S=t._pendingDecorators;null!==S&&(t._decorators=S,t._pendingDecorators=null,Di("decorator",t,true,S)),function(t,e,n){const r=Qo(e),i=Qo(n);r!==i&&Di("textcontent",t,true,i);}(t,e||o,n),Di("update",t,true,{dirtyElements:p,dirtyLeaves:_,editorState:n,mutatedNodes:g,normalizedNodes:y,prevEditorState:e||o,tags:m}),Fi(t,x),function(t){const e=t._updates;if(0!==e.length){const n=e.shift();if(n){const[e,r]=n;Ii(t,e,r);}}}(t);}function Di(t,e,n,...r){const i=e._updating;e._updating=n;try{const n=e._listeners[t],i=Array.from(n);for(const[t,e]of i){e&&e();const i=t(...r);n.has(t)?n.set(t,i):i&&i();}}finally{e._updating=i;}}function Pi(t,e,n,r){const i=is(t);let o;for(let t=4;t>=0;t--)for(let s=0;s<i.length;s++){const l=i[s];if(s>0&&l._updating){o=l;break}const c=l._commands.get(e);if(void 0!==c){const e=c[t];if(e.size>0){let t=false;if(Ki(l,()=>{for(const i of e)if(i(n,r))return void(t=true)}),t)return t}}}return o&&o.update(()=>{Pi(o,e,n,r);}),false}function Fi(t,e){if(t._deferred=[],0!==e.length){const n=t._updating;t._updating=true;try{for(let t=0;t<e.length;t++)e[t]();}finally{t._updating=n;}}}function Li(e,n){const r=e._updates;let i=n||false;for(;0!==r.length;){const n=r.shift();if(n){const[r,o]=n,s=e._pendingEditorState;let l;void 0!==o&&(l=o.onUpdate,o.skipTransforms&&(i=true),o.discrete&&(null===s&&t(191),s._flushSync=true),l&&e._deferred.push(l),wi(e,o.tag)),null==s?Ii(e,r,o):r();}}return i}function Ii(e,n,r){const i=e._updateTags;let o,s=false,l=false;void 0!==r&&(o=r.onUpdate,wi(e,r.tag),s=r.skipTransforms||false,l=r.discrete||false),o&&e._deferred.push(o);const c=e._editorState;let a=e._pendingEditorState,u=false;(null===a||a._readOnly)&&(a=e._pendingEditorState=Yi(a||c),u=true),a._flushSync=l;const f=di,d=gi,h=hi,g=e._updating;di=a,gi=false,e._updating=true,hi=e;const _=e._headless||null===e.getRootElement();vo(null);try{u&&(_?null!==c._selection&&(a._selection=c._selection.clone()):a._selection=function(t,e){const n=t.getEditorState()._selection,r=Js(Ps(t));return Fr(n)||null==n?Xr(n,r,t,e):n.clone()}(e,r&&r.event||null));const i=e._compositionKey;n(),s=Li(e,s),function(t,e){const n=e.getEditorState()._selection,r=t._selection;if(Fr(r)){const t=r.anchor,e=r.focus;let i;if("text"===t.type&&(i=t.getNode(),i.selectionTransform(n,r)),"text"===e.type){const t=e.getNode();i!==t&&t.selectionTransform(n,r);}}}(a,e),0!==e._dirtyType&&(s?function(t,e){const n=e._dirtyLeaves,r=t._nodeMap;for(const t of n){const e=r.get(t);Tr(e)&&e.isAttached()&&e.isSimpleText()&&!e.isUnmergeable()&&Ct$2(e);}}(a,e):function(t,e){const n=e._dirtyLeaves,r=e._dirtyElements,i=t._nodeMap,o=Vo(),s=new Map;let l=n,c=l.size,a=r,u=a.size;
7324for(;c>0||u>0;){if(c>0){e._dirtyLeaves=new Set;for(const t of l){const r=i.get(t);Tr(r)&&r.isAttached()&&r.isSimpleText()&&!r.isUnmergeable()&&Ct$2(r),void 0!==r&&bi(r,o)&&Ni(e,r,s),n.add(t);}if(l=e._dirtyLeaves,c=l.size,c>0){pi++;continue}}e._dirtyLeaves=new Set,e._dirtyElements=new Map,a.delete("root")&&a.set("root",!0);for(const t of a){const n=t[0],l=t[1];if(r.set(n,l),!l)continue;const c=i.get(n);void 0!==c&&bi(c,o)&&Ni(e,c,s);}l=e._dirtyLeaves,c=l.size,a=e._dirtyElements,u=a.size,pi++;}e._dirtyLeaves=n,e._dirtyElements=r;}(a,e),Li(e),function(t,e,n,r){const i=t._nodeMap,o=e._nodeMap,s=[];for(const[t]of r){const e=o.get(t);void 0!==e&&(e.isAttached()||(Wi(e)&&Y$5(e,t,i,o,s,r),i.has(t)||r.delete(t),s.push(t)));}for(const t of s)o.delete(t);for(const t of n){const e=o.get(t);void 0===e||e.isAttached()||(i.has(t)||n.delete(t),o.delete(t));}}(c,a,e._dirtyLeaves,e._dirtyElements));i!==e._compositionKey&&(a._flushSync=!0);const o=a._selection;if(Fr(o)){const e=a._nodeMap,n=o.anchor.key,r=o.focus.key;void 0!==e.get(n)&&void 0!==e.get(r)||t(19);}else Ir(o)&&0===o._nodes.size&&(a._selection=null);}catch(t){return t instanceof Error&&e._onError(t),e._pendingEditorState=c,e._dirtyType=2,e._cloneNotNeeded.clear(),e._dirtyLeaves=new Set,e._dirtyElements.clear(),void Ai(e)}finally{di=f,gi=d,hi=h,e._updating=g,pi=0;}const p=0!==e._dirtyType||e._deferred.length>0||function(t,e){const n=e.getEditorState()._selection,r=t._selection;if(null!==r){if(r.dirty||!r.is(n))return true}else if(null!==n)return true;return false}(a,e);p?a._flushSync?(a._flushSync=false,Ai(e)):u&&wo(()=>{Ai(e);}):(a._flushSync=false,u&&(i.clear(),e._deferred=[],e._pendingEditorState=null));}function Ki(t,e,n){hi===t&&void 0===n?e():Ii(t,e,n);}class zi{element;before;after;constructor(t,e,n){this.element=t,this.before=e||null,this.after=n||null;}withBefore(t){return new zi(this.element,t,this.after)}withAfter(t){return new zi(this.element,this.before,t)}withElement(t){return this.element===t?this:new zi(t,this.before,this.after)}insertChild(e){const n=this.before||this.getManagedLineBreak();return null!==n&&n.parentElement!==this.element&&t(222),this.element.insertBefore(e,n),this}removeChild(e){return e.parentElement!==this.element&&t(223),this.element.removeChild(e),this}replaceChild(e,n){return n.parentElement!==this.element&&t(224),this.element.replaceChild(e,n),this}getFirstChild(){const t=this.after?this.after.nextSibling:this.element.firstChild;return t===this.before||t===this.getManagedLineBreak()?null:t}getManagedLineBreak(){return this.element.__lexicalLineBreak||null}setManagedLineBreak(t){if(null===t)this.removeManagedLineBreak();else {const e="decorator"===t&&(d$1||l||a$1);this.insertManagedLineBreak(e);}}removeManagedLineBreak(){const t=this.getManagedLineBreak();if(t){const e=this.element,n="IMG"===t.nodeName?t.nextSibling:null;n&&e.removeChild(n),e.removeChild(t),e.__lexicalLineBreak=void 0;}}insertManagedLineBreak(t){const e=this.getManagedLineBreak();if(e){if(t===("IMG"===e.nodeName))return;this.removeManagedLineBreak();}const n=this.element,r=this.before,i=document.createElement("br");if(n.insertBefore(i,r),t){const t=document.createElement("img");t.setAttribute("data-lexical-linebreak","true"),t.style.setProperty("display","inline","important"),t.style.setProperty("border","0px","important"),t.style.setProperty("margin","0px","important"),t.alt="",n.insertBefore(t,i),n.__lexicalLineBreak=t;}else n.__lexicalLineBreak=i;}getFirstChildOffset(){let t=0;for(let e=this.after;null!==e;e=e.previousSibling)t++;return t}resolveChildIndex(t,e,n,r){if(n===this.element){const e=this.getFirstChildOffset();return [t,Math.min(e+t.getChildrenSize(),Math.max(e,r))]}const i=Ri(e,n);i.push(r);const o=Ri(e,this.element);let s=t.getIndexWithinParent();for(let t=0;t<o.length;t++){const e=i[t],n=o[t];if(void 0===e||e<n)break;if(e>n){s+=1;break}}return [t.getParentOrThrow(),s]}}function Ri(e,n){const r=[];let i=n;for(;i!==e&&null!==i;i=i.parentNode){let t=0;for(let e=i.previousSibling;null!==e;e=e.previousSibling)t++;r.push(t);}return i!==e&&t(225),r.reverse()}class Bi extends Rn$1{__first;__last;__size;__format;__style;__indent;__dir;__textFormat;__textStyle;constructor(t){super(t),this.__first=null,this.__last=null,this.__size=0,this.__format=0,this.__style="",this.__indent=0,this.__dir=null,this.__textFormat=0,this.__textStyle="";}afterCloneFrom(t){super.afterCloneFrom(t),this.__key===t.__key&&(this.__first=t.__first,this.__last=t.__last,this.__size=t.__size),this.__indent=t.__indent,this.__format=t.__format,this.__style=t.__style,this.__dir=t.__dir,this.__textFormat=t.__textFormat,this.__textStyle=t.__textStyle;}getFormat(){return this.getLatest().__format}getFormatType(){const t=this.getFormat();return W$5[t]||""}getStyle(){return this.getLatest().__style}getIndent(){return this.getLatest().__indent}getChildren(){const t=[];let e=this.getFirstChild();for(;null!==e;)t.push(e),e=e.getNextSibling();return t}getChildrenKeys(){const t=[];let e=this.getFirstChild();for(;null!==e;)t.push(e.__key),e=e.getNextSibling();return t}getChildrenSize(){return this.getLatest().__size}isEmpty(){return 0===this.getChildrenSize()}isDirty(){const t=vi()._dirtyElements;return null!==t&&t.has(this.__key)}isLastChild(){const t=this.getLatest(),e=this.getParentOrThrow().getLastChild();return null!==e&&e.is(t)}getAllTextNodes(){const t=[];let e=this.getFirstChild();for(;null!==e;){if(Tr(e)&&t.push(e),Wi(e)){const n=e.getAllTextNodes();t.push(...n);}e=e.getNextSibling();}return t}getFirstDescendant(){let t=this.getFirstChild();for(;Wi(t);){const e=t.getFirstChild();if(null===e)break;t=e;}return t}getLastDescendant(){let t=this.getLastChild();for(;Wi(t);){const e=t.getLastChild();if(null===e)break;t=e;}return t}getDescendantByIndex(t){const e=this.getChildren(),n=e.length;if(t>
vendor: 2,106 bytes, line 7324
7324=n){const t=e[n-1];return Wi(t)&&t.getLastDescendant()||t||null}const r=e[t];return Wi(r)&&r.getFirstDescendant()||r||null}getFirstChild(){const t=this.getLatest().__first;return null===t?null:Yo(t)}getFirstChildOrThrow(){const e=this.getFirstChild();return null===e&&t(45,this.__key),e}getLastChild(){const t=this.getLatest().__last;return null===t?null:Yo(t)}getLastChildOrThrow(){const e=this.getLastChild();return null===e&&t(96,this.__key),e}getChildAtIndex(t){const e=this.getChildrenSize();let n,r;if(t<e/2){for(n=this.getFirstChild(),r=0;null!==n&&r<=t;){if(r===t)return n;n=n.getNextSibling(),r++;}return null}for(n=this.getLastChild(),r=e-1;null!==n&&r>=t;){if(r===t)return n;n=n.getPreviousSibling(),r--;}return null}getTextContent(){let t="";const e=this.getChildren(),n=e.length;for(let r=0;r<n;r++){const i=e[r];t+=i.getTextContent(),Wi(i)&&r!==n-1&&!i.isInline()&&(t+=D$4);}return t}getTextContentSize(){let t=0;const e=this.getChildren(),n=e.length;for(let r=0;r<n;r++){const i=e[r];t+=i.getTextContentSize(),Wi(i)&&r!==n-1&&!i.isInline()&&(t+=2);}return t}getDirection(){return this.getLatest().__dir}getTextFormat(){return this.getLatest().__textFormat}hasFormat(t){if(""!==t){const e=B$5[t];return 0!==(this.getFormat()&e)}return false}hasTextFormat(t){const e=z$7[t];return 0!==(this.getTextFormat()&e)}getFormatFlags(t,e){return Bo(this.getLatest().__textFormat,t,e)}getTextStyle(){return this.getLatest().__textStyle}select(t,e){xi();const n=Qr();let r=t,i=e;const o=this.getChildrenSize();if(!this.canBeEmpty())if(0===t&&0===e){const t=this.getFirstChild();if(Tr(t)||Wi(t))return t.select(0,0)}else if(!(void 0!==t&&t!==o||void 0!==e&&e!==o)){const t=this.getLastChild();if(Tr(t)||Wi(t))return t.select()} void 0===r&&(r=o),void 0===i&&(i=o);const s=this.__key;return Fr(n)?(n.anchor.set(s,r,"element"),n.focus.set(s,i,"element"),n.dirty=true,n):Yr(s,r,s,i,"element","element")}selectStart(){const t=this.getFirstDescendant();return t?t.selectStart():this.select()}selectEnd(){const t=this.getLastDescendant();return t?t.selectEnd():this.select()}clear(){const t=this.getWritable();
7324return this.getChildren().forEach(t=>t.remove()),t}append(...t){return this.splice(this.getChildrenSize(),0,t)}setDirection(t){const e=this.getWritable();return e.__dir=t,e}setFormat(t){return this.getWritable().__format=""!==t&&B$5[t]||0,this}setStyle(t){return this.getWritable().__style=t||"",this}setTextFormat(t){const e=this.getWritable();return e.__textFormat=t,e}setTextStyle(t){const e=this.getWritable();return e.__textStyle=t,e}setIndent(t){return this.getWritable().__indent=t,this}splice(e,n,r){zn(this)&&t(324,this.__key,this.__type);const i=this.getChildrenSize(),o=this.getWritable();e+n<=i||t(226,String(e),String(n),String(i));const s=o.__key,l=[],c=[],a=this.getChildAtIndex(e+n);let u=null,f=i-n+r.length;if(0!==e)if(e===i)u=this.getLastChild();else {const t=this.getChildAtIndex(e);null!==t&&(u=t.getPreviousSibling());}if(n>0){let e=null===u?this.getFirstChild():u.getNextSibling();for(let r=0;r<n;r++){null===e&&t(100);const n=e.getNextSibling(),r=e.__key;Jo(e.getWritable()),c.push(r),e=n;}}let d=u;for(const e of r){null!==d&&e.is(d)&&(u=d=d.getPreviousSibling());const n=e.getWritable();n.__parent===s&&f--,Jo(n);const r=e.__key;if(null===d)o.__first=r,n.__prev=null;else {const t=d.getWritable();t.__next=r,n.__prev=t.__key;}e.__key===s&&t(76),n.__parent=s,l.push(r),d=e;}if(e+n===i){if(null!==d){d.getWritable().__next=null,o.__last=d.__key;}}else if(null!==a){const t=a.getWritable();if(null!==d){const e=d.getWritable();t.__prev=d.__key,e.__next=a.__key;}else t.__prev=null;}if(o.__size=f,c.length){const t=Qr();if(Fr(t)){const e=new Set(c),n=new Set(l),{anchor:r,focus:i}=t;$i(r,e,n)&&ni(r,r.getNode(),this,u,a),$i(i,e,n)&&ni(i,i.getNode(),this,u,a),0!==f||this.canBeEmpty()||Is(this)||this.remove();}}return o}getDOMSlot(t){return new zi(t)}exportDOM(t){const{element:e}=super.exportDOM(t);if(Ys(e)){const t=this.getIndent();t>0&&(e.style.paddingInlineStart=40*t+"px");const n=this.getDirection();n&&(e.dir=n);}return {element:e}}exportJSON(){const t={children:[],direction:this.getDirection(),format:this.getFormatType(),indent:this.getIndent(),...super.exportJSON()},e=this.getTextFormat(),n=this.getTextStyle();return 0===e&&""===n||Is(this)||this.getChildren().some(Tr)||(0!==e&&(t.textFormat=e),""!==n&&(t.textStyle=n)),t}updateFromJSON(t){return super.updateFromJSON(t).setFormat(t.format).setIndent(t.indent).setDirection(t.direction).setTextFormat(t.textFormat||0).setTextStyle(t.textStyle||"")}insertNewAfter(t,e){return null}canIndent(){return true}collapseAtStart(t){return false}excludeFromCopy(t){return false}canReplaceWith(t){return true}canInsertAfter(t){return true}canBeEmpty(){return true}canInsertTextBefore(){return true}canInsertTextAfter(){return true}isInline(){return false}isShadowRoot(){return false}canMergeWith(t){return false}extractWithChild(t,e,n){return false}canMergeWhenEmpty(){return false}reconcileObservedMutation(t,e){const n=tl(e).$getDOMSlot(this,t,e);let r=n.getFirstChild();for(let t=this.getFirstChild();t;t=t.getNextSibling()){const i=e.getElementByKey(t.getKey());null!==i&&(null==r?(n.insertChild(i),r=i):r!==i&&n.replaceChild(i,r),r=r.nextSibling);}}}function Wi(t){return t instanceof Bi}function $i(t,e,n){let r=t.getNode();for(;r;){const t=r.__key;if(e.has(t)&&!n.has(t))return true;r=r.getParent();}return false}class Ji extends Rn$1{decorate(t,e){return null}isIsolated(){return false}isInline(){return true}isKeyboardSelectable(){return true}}function ji(t){return t instanceof Ji}class Ui extends Bi{__cachedText;static getType(){return "root"}static clone(){return new Ui}constructor(){super("root"),this.__cachedText=null;}getTopLevelElementOrThrow(){t(51);}getTextContent(){const t=this.__cachedText;return !mi()&&0!==vi()._dirtyType||null===t?super.getTextContent():t}remove(){t(52);}replace(e){t(53);}insertBefore(e){t(54);}insertAfter(e){t(55);}updateDOM(t,e){return false}splice(e,n,r){for(const e of r)Wi(e)||ji(e)||t(282);return super.splice(e,n,r)}static importJSON(t){return Zo().updateFromJSON(t)}collapseAtStart(){return true}}function Vi(t){return t instanceof Ui}function Yi(t){return new Xi(new Map(t._nodeMap))}function qi(){return new Xi(new Map([["root",new Ui]]))}function Hi(e){const n=e.exportJSON(),r=e.constructor;if(n.type!==r.getType()&&t(130,r.name),Wi(e)){const i=n.children;Array.isArray(i)||t(59,r.name);const o=e.getChildren();for(let t=0;t<o.length;t++){const e=Hi(o[t]);i.push(e);}}return n}function Gi(t){return t instanceof Xi}class Xi{_nodeMap;_selection;_flushSync;_readOnly;constructor(t,e){this._nodeMap=t,this._selection=e||null,this._flushSync=false,this._readOnly=false;}isEmpty(){return 1===this._nodeMap.size&&null===this._selection}read(t,e){return Mi(e&&e.editor||null,this,t)}clone(t){const e=new Xi(this._nodeMap,void 0===t?this._selection:t);return e._readOnly=true,e}toJSON(){return Mi(null,this,()=>({root:Hi(Zo())}))}}class Qi extends Bi{static getType(){return "artificial"}createDOM(t){return document.createElement("div")}}class Zi extends Bi{static getType(){return "paragraph"}static clone(t){return new Zi(t.__key)}createDOM(t){const e=document.createElement("p"),n=ms(t.theme,"paragraph");if(void 0!==n){e.classList.add(...n);}return e}updateDOM(t,e,n){return false}static importDOM(){return {p:t=>({conversion:to,priority:0})}}exportDOM(t){const{element:e}=super.exportDOM(t);if(Ys(e)){this.isEmpty()&&e.append(document.createElement("br"));const t=this.getFormatType();t&&(e.style.textAlign=t);}return {element:e}}static importJSON(t){return eo().updateFromJSON(t)}exportJSON(){const t=super.exportJSON();if(void 0===t.textFormat||void 0===t.textStyle){const e=this.getChildren().find(Tr);e?(t.textFormat=e.getFormat(),t.textStyle=e.getStyle()):(t.textFormat=this.getTextFormat(),t.textStyle=this.getTextStyle());}return t}insertNewAfter(t,e){const n=eo();n.setTextFormat(t.format),n.setTextStyle(t.style);const r=this.getDirection();return n.setDirection(r),n.setFormat(this.getFormatType()),n.setStyle(this.getStyle()),this.insertAfter(n,e),n}collapseAtStart(){const t=this.getChildren();if(0===t.length||Tr(t[0])&&""===t[0].getTextContent().trim()){if(null!==this.getNextSibling())return this.selectNext(),this.remove(),true;if(null!==this.getPreviousSibling())return this.selectPrevious(),this.remove(),true}return false}}function to(t){const e=eo();if(t.style&&(e.setFormat(t.style.textAlign),sl(t,e)),""===e.getFormatType()){const n=t.getAttribute("align");n&&n&&n in B$5&&e.setFormat(n);}return {node:e}}function eo(){return zs(new Zi)}function no(t){return t instanceof Zi}const ro=0,io=1,oo=2,so=3,lo=4,co=-8,ao=-7,uo=-6,fo=-5,ho=-4;function go(t,e,n,r){const i=t._keyToDOMMap;i.clear(),t._editorState=qi(),t._pendingEditorState=r,t._compositionKey=null,t._dirtyType=0,t._cloneNotNeeded.clear(),t._dirtyLeaves=new Set,t._dirtyElements.clear(),t._normalizedNodes=new Set,t._updateTags=new Set,t._updates=[],t._blockCursorElement=null;const o=t._observer;null!==o&&(o.disconnect(),t._observer=null),null!==e&&(e.textContent=""),null!==n&&(n.textContent="",i.set("root",n));}function _o(t){const e=new Set,n=new Set;let r=t;for(;r;){const{ownNodeConfig:t}=ul(r),i=r.transform;if(!n.has(i)){n.add(i);const t=r.transform();t&&e.add(t);}if(t){const n=t.$transform;n&&e.add(n),r=t.extends;}else {const t=Object.getPrototypeOf(r);r=t.prototype instanceof Rn$1&&t!==Rn$1?t:void 0;}}return e}const po={$createDOM:(t,e)=>t.createDOM(e._config,e),$decorateDOM:(t,e,n,r)=>{},$exportDOM:(t,e)=>{const n=bo(e,t.getType());return n&&void 0!==n.exportDOM?n.exportDOM(e,t):t.exportDOM(e)},$extractWithChild:(t,e,n,r,i)=>Wi(t)&&t.extractWithChild(e,n,r),$getDOMSlot:(e,n,r)=>(Wi(e)||t(336,e.getKey(),e.getType()),e.getDOMSlot(n)),$shouldExclude:(t,e,n)=>Wi(t)&&t.excludeFromCopy("html"),$shouldInclude:(t,e,n)=>!e||t.isSelected(e),$updateDOM:(t,e,n,r)=>t.updateDOM(e,n,r._config)};function yo(t){const e=t||{},n=Ti(),r=e.theme||{},i=void 0===t?n:e.parentEditor||null,o=e.disableEvents||false,s=qi(),l=e.namespace||(null!==i?i._config.namespace:os()),c=e.editorState,a=[Ui,gr,rr,br,Zi,Qi,...e.nodes||[]],{onError:u,html:f}=e,d=void 0===e.editable||e.editable;let h;if(void 0===t&&null!==n)h=n._nodes;else {h=new Map;for(let t=0;t<a.length;t++){let e=a[t],n=null,r=null;if("function"!=typeof e){const t=e;e=t.replace,n=t.with,r=t.withKlass||null;}ul(e);const i=e.getType(),o=_o(e);h.set(i,{exportDOM:f&&f.export?f.export.get(e):void 0,klass:e,replace:n,replaceWithKlass:r,sharedNodeState:at$3(a[t]),transforms:o});}}const g=new Co(s,i,h,{disableEvents:o,dom:{...po,...t&&t.dom},namespace:l,theme:r},u||console.error,function(t,e){const n=new Map,r=new Set,i=t=>
7324{Object.keys(t).forEach(e=>{let r=n.get(e);void 0===r&&(r=[],n.set(e,r)),r.push(t[e]);});};return t.forEach(t=>{const e=t.klass.importDOM;if(null==e||r.has(e))return;r.add(e);const n=e.call(t.klass);null!==n&&i(n);}),e&&i(e),n}(h,f?f.import:void 0),d,t);return void 0!==c&&(g._pendingEditorState=c,g._dirtyType=2),function(t){t.registerCommand(le$3,vn$1,ro),t.registerCommand(ce$4,kn$1,ro),t.registerCommand(ae$4,Tn$1,ro),t.registerCommand(ue$4,Nn$1,ro),t.registerCommand(ve$2,wn$1,ro);}(g),g}function mo(t,e){const n=t.get(e);t.delete(e),n&&n();}function xo(t,e,n){return t.set(e,n),mo.bind(null,t,e)}class Co{static version;_headless;_parentEditor;_rootElement;_editorState;_pendingEditorState;_compositionKey;_deferred;_keyToDOMMap;_updates;_updating;_listeners;_commands;_nodes;_decorators;_pendingDecorators;_config;_dirtyType;_cloneNotNeeded;_dirtyLeaves;_dirtyElements;_normalizedNodes;_updateTags;_observer;_key;_onError;_htmlConversions;_window;_editable;_blockCursorElement;_createEditorArgs;constructor(t,e,n,r,i,o,s,l){this._createEditorArgs=l,this._parentEditor=e,this._rootElement=null,this._editorState=t,this._pendingEditorState=null,this._compositionKey=null,this._deferred=[],this._keyToDOMMap=new Map,this._updates=[],this._updating=false,this._listeners={decorator:new Map,editable:new Map,mutation:new Map,root:new Map,textcontent:new Map,update:new Map},this._commands=new Map,this._config=r,this._nodes=n,this._decorators={},this._pendingDecorators=null,this._dirtyType=0,this._cloneNotNeeded=new Set,this._dirtyLeaves=new Set,this._dirtyElements=new Map,this._normalizedNodes=new Set,this._updateTags=new Set,this._observer=null,this._key=os(),this._onError=i,this._htmlConversions=o,this._editable=s,this._headless=null!==e&&e._headless,this._window=null,this._blockCursorElement=null;}isComposing(){return null!=this._compositionKey}registerUpdateListener(t){return xo(this._listeners.update,t)}registerEditableListener(t){return xo(this._listeners.editable,t)}registerDecoratorListener(t){return xo(this._listeners.decorator,t)}registerTextContentListener(t){return xo(this._listeners.textcontent,t)}registerRootListener(t){const e=this._listeners.root;return Cc(xo(e,t,t(this._rootElement,null)||void 0),()=>function(t,e,n){const r=t.get(e);r&&r(),t.set(e,e(...n)||void 0);}(e,t,[null,this._rootElement]))}registerCommand(e,n,r){ void 0===r&&t(35);const i=this._commands;i.has(e)||i.set(e,[new V$7,new V$7,new V$7,new V$7,new V$7]);const o=i.get(e);void 0===o&&t(36,String(e));const s=function(t){return 7&t}(r),l=o[s];return s!==r?l.addFront(n):l.addBack(n),()=>{l.delete(n),o.every(t=>0===t.size)&&i.delete(e);}}registerMutationListener(t,e,n){const r=this.resolveRegisteredNodeAfterReplacements(this.getRegisteredNode(t)).klass,i=this._listeners.mutation;let o=i.get(e);void 0===o&&(o=new Set,i.set(e,o)),o.add(r);const s=n&&n.skipInitialization;return void 0!==s&&s||this.initializeMutationListener(e,r),()=>{o.delete(r),0===o.size&&i.delete(e);}}getRegisteredNode(e){const n=this._nodes.get(e.getType());return void 0===n&&t(37,e.name),n}resolveRegisteredNodeAfterReplacements(t){for(;t.replaceWithKlass;)t=this.getRegisteredNode(t.replaceWithKlass);return t}initializeMutationListener(t,e){const n=this._editorState,r=rl(n).get(e.getType());if(!r)return;const i=new Map;for(const t of r.keys())i.set(t,"created");i.size>0&&t(i,{dirtyLeaves:new Set,prevEditorState:n,updateTags:new Set(["registerMutationListener"])});}registerNodeTransformToKlass(t,e){const n=this.getRegisteredNode(t);return n.transforms.add(e),n}registerNodeTransform(t,e){const n=this.registerNodeTransformToKlass(t,e),r=[n],i=n.replaceWithKlass;if(null!=i){const t=this.registerNodeTransformToKlass(i,e);r.push(t);}return function(t,e){const n=rl(t.getEditorState()),r=[];for(const t of e){const e=n.get(t);e&&r.push(e);}if(0===r.length)return;t.update(()=>{for(const t of r)for(const e of t.keys()){const t=Yo(e);t&&t.markDirty();}},null===t._pendingEditorState?{tag:Jn}:void 0);}(this,r.map(t=>t.klass.getType())),()=>{r.forEach(t=>t.transforms.delete(e));}}hasNode(t){return this._nodes.has(t.getType())}hasNodes(t){return t.every(this.hasNode.bind(this))}dispatchCommand(t,e){return Ts(this,t,e)}getDecorators(){return this._decorators}getRootElement(){return this._rootElement}getKey(){return this._key}setRootElement(t){const e=this._rootElement;
7324if(t!==e){const n=ms(this._config.theme,"root"),r=this._pendingEditorState||this._editorState;if(this._rootElement=t,go(this,e,t,r),null!==e&&(this._config.disableEvents||Fn$1(e),null!=n&&e.classList.remove(...n)),null!==t){const e=Ds(t),r=t.style;r.userSelect="text",r.whiteSpace="pre-wrap",r.wordBreak="break-word",t.setAttribute("data-lexical-editor","true"),this._window=e,this._dirtyType=2,rt$4(this),this._updateTags.add(Jn),Ai(this),this._config.disableEvents||function(t,e){const n=t.ownerDocument;sn$1.set(t,n);const r=ln$1.get(n)??0;r<1&&n.addEventListener("selectionchange",Mn),ln$1.set(n,r+1),t.__lexicalEditor=e;const i=En$1(t);for(let n=0;n<tn$1.length;n++){const[r,o]=tn$1[n],s="function"==typeof o?t=>{Dn(t)||(An$1(t),(e.isEditable()||"click"===r)&&o(t,e));}:t=>{if(Dn(t))return;An$1(t);const n=e.isEditable();switch(r){case "cut":return n&&Ts(e,je$2,t);case "copy":return Ts(e,Je$2,t);case "paste":return n&&Ts(e,_e$2,t);case "dragstart":return n&&Ts(e,Be$2,t);case "dragover":return n&&Ts(e,We$2,t);case "dragend":return n&&Ts(e,$e$2,t);case "focus":return n&&Ts(e,Ge$2,t);case "blur":return n&&Ts(e,Xe$2,t);case "drop":return n&&Ts(e,ze$2,t)}};t.addEventListener(r,s),i.push(()=>{t.removeEventListener(r,s);});}}(t,this),null!=n&&t.classList.add(...n);}else this._window=null,this._updateTags.add(Jn),Ai(this);Di("root",this,false,t,e);}}getElementByKey(t){return this._keyToDOMMap.get(t)||null}getEditorState(){return this._editorState}setEditorState(e,n){e.isEmpty()&&t(38);let r=e;r._readOnly&&(r=Yi(e),r._selection=e._selection?e._selection.clone():null),nt$4(this);const i=this._pendingEditorState,o=this._updateTags,s=void 0!==n?n.tag:null;null===i||i.isEmpty()||(null!=s&&o.add(s),Ai(this)),this._pendingEditorState=r,this._dirtyType=2,this._dirtyElements.set("root",false),this._compositionKey=null,null!=s&&o.add(s),this._updating||Ai(this);}parseEditorState(t,e){return function(t,e,n){const r=qi(),i=di,o=gi,s=hi,l=e._dirtyElements,c=e._dirtyLeaves,a=e._cloneNotNeeded,u=e._dirtyType;e._dirtyElements=new Map,e._dirtyLeaves=new Set,e._cloneNotNeeded=new Set,e._dirtyType=0,di=r,gi=false,hi=e,vo(null);try{const i=e._nodes;Oi(t.root,i),n&&n(),r._readOnly=!0;}catch(t){t instanceof Error&&e._onError(t);}finally{e._dirtyElements=l,e._dirtyLeaves=c,e._cloneNotNeeded=a,e._dirtyType=u,di=i,gi=o,hi=s;}return r}("string"==typeof t?JSON.parse(t):t,this,e)}read(t){return Ai(this),this.getEditorState().read(t,{editor:this})}update(t,e){!function(t,e,n){t._updating?t._updates.push([e,n]):Ii(t,e,n);}(this,t,e);}focus(t,e={}){const n=this._rootElement;null!==n&&(n.setAttribute("autocapitalize","off"),Ki(this,()=>{const r=Qr(),i=Zo();null!==r?r.dirty||es(r.clone()):0!==i.getChildrenSize()&&("rootStart"===e.defaultSelection?i.selectStart():i.selectEnd()),Os("focus"),Ms(()=>{n.removeAttribute("autocapitalize"),t&&t();});}),null===this._pendingEditorState&&n.removeAttribute("autocapitalize"));}blur(){const t=this._rootElement;null!==t&&t.blur();const e=Js(this._window);null!==e&&e.removeAllRanges();}isEditable(){return this._editable}setEditable(t){this._editable!==t&&(this._editable=t,Di("editable",this,true,t));}toJSON(){return {editorState:this._editorState.toJSON()}}}Co.version="0.44.0+prod.esm";let So=null;function vo(t){So=t;}let ko=1;function To(){ko=1;}function No(e,n){const r=bo(e,n);return void 0===r&&t(30,n),r}function bo(t,e){return t._nodes.get(e)}const wo="function"==typeof queueMicrotask?queueMicrotask:t=>{Promise.resolve().then(t);};function Eo(t){return ji(Go(t))}function Oo(t){const e=document.activeElement;if(!Ys(e))return false;const n=e.nodeName;return ji(Go(t))&&("INPUT"===n||"TEXTAREA"===n||"true"===e.contentEditable&&null==Po(e))}function Mo(t,e,n){const r=t.getRootElement();try{return null!==r&&r.contains(e)&&r.contains(n)&&null!==e&&!Oo(e)&&Do(e)===t}catch(t){return false}}function Ao(t){return t instanceof Co}function Do(t){let e=t;for(;null!=e;){const t=Po(e);if(Ao(t))return t;e=bs(e);}return null}function Po(t){return t?t.__lexicalEditor:null}function Fo(t){return I$6.test(t)?"rtl":K$4.test(t)?"ltr":null}function Lo(t){return Er(t)||t.isToken()}function Io(t){return Lo(t)||t.isSegmented()}function Ko(t){return qs(t)&&3===t.nodeType}function zo(t){return qs(t)&&9===t.nodeType}function Ro(t){let e=t;for(;null!=e;){if(Ko(e))return e;e=e.firstChild;}return null}function Bo(t,e,n){const r=z$7[e];if(null!==n&&(t&r)===(n&r))return t;let i=t^r;return "subscript"===e?i&=~z$7.superscript:"superscript"===e?i&=~z$7.subscript:"lowercase"===e?(i&=~z$7.uppercase,i&=~z$7.capitalize):"uppercase"===e?(i&=~z$7.lowercase,i&=~z$7.capitalize):"capitalize"===e&&(i&=~z$7.lowercase,i&=~z$7.uppercase),i}function Wo(t){return Tr(t)||sr(t)||ji(t)}function $o(t,e){const n=function(){const t=So;return So=null,t}();if(null!=(e=e||n&&n.__key))return void(t.__key=e);xi(),Ci();const r=vi(),i=Si(),o=""+ko++;i._nodeMap.set(o,t),Wi(t)?r._dirtyElements.set(o,true):r._dirtyLeaves.add(o),r._cloneNotNeeded.add(o),r._dirtyType=1,t.__key=o;}function Jo(t){const e=t.getParent();if(null!==e){const n=t.getWritable(),r=e.getWritable(),i=t.getPreviousSibling(),o=t.getNextSibling(),s=null!==o?o.__key:null,l=null!==i?i.__key:null,c=null!==i?i.getWritable():null,a=null!==o?o.getWritable():null;null===i&&(r.__first=s),null===o&&(r.__last=l),null!==c&&(c.__next=s),null!==a&&(a.__prev=l),n.__prev=null,n.__next=null,n.__parent=null,r.__size--;}}function jo(e){Ci(),zn(e)&&t(323,e.__key,e.__type);const n=e.getLatest(),r=n.__parent,i=Si(),o=vi(),s=i._nodeMap,l=o._dirtyElements;null!==r&&function(t,e,n){let r=t;for(;null!==r;){if(n.has(r))return;const t=e.get(r);if(void 0===t)break;n.set(r,false),r=t.__parent;}}(r,s,l);const c=n.__key;o._dirtyType=1,Wi(e)?l.set(c,true):o._dirtyLeaves.add(c);}function Uo(t){xi();const e=vi(),n=e._compositionKey;if(t!==n){if(e._compositionKey=t,null!==n){const t=Yo(n);null!==t&&t.getWritable();}if(null!==t){const e=Yo(t);null!==e&&e.getWritable();}}}function Vo(){if(mi())return null;return vi()._compositionKey}function Yo(t,e){const n=(e||Si())._nodeMap.get(t);return void 0===n?null:n}function qo(t,e){const n=Ho(t,vi());return void 0!==n?Yo(n,e):null}function Ho(t,e){return t[`__lexicalKey_${e._key}`]}function Go(t,e){let n=t;for(;null!=n;){const t=qo(n,e);if(null!==t)return t;n=bs(n);}return null}function Xo(t){const e=t._decorators,n=Object.assign({},e);return t._pendingDecorators=n,n}function Qo(t){return t.read(()=>Zo().getTextContent())}function Zo(){return ts(Si())}function ts(t){return t._nodeMap.get("root")}function es(t){xi();const e=Si();null!==t&&(t.dirty=true,t.setCachedNodes(null)),e._selection=t;}function ns(t){const e=vi(),n=function(t,e){let n=t;for(;null!=n;){const t=Ho(n,e);if(void 0!==t)return t;n=bs(n);}return null}(t,e);if(null===n){return t===e.getRootElement()?Yo("root"):null}return Yo(n)}function rs(t){return /[\uD800-\uDBFF][\uDC00-\uDFFF]/g.test(t)}function is(t){const e=[];for(let n=t;null!==n;n=n._parentEditor)e.push(n);return e}function os(){return Math.random().toString(36).replace(/[^a-z]+/g,"").substring(0,5)}function ss(t){return Ko(t)?t.nodeValue:null}function ls(t,e,n){const r=Js(Ps(e));if(null===r)return;const i=r.anchorNode;let{anchorOffset:o,focusOffset:s}=r;if(null!==i){let e=ss(i);const r=Go(i);if(null!==e&&Tr(r)){if((e===A$3||e===P$3)&&n){const t=n.length;e=n,o=t,s=t;}null!==e&&cs(r,e,o,s,t);}}}function cs(t,e,n,r,i){let o=t;if(o.isAttached()&&(i||!o.isDirty())){const s=o.isComposing();let c=e;if((s||i)&&(e.endsWith(A$3)&&(c=e.slice(0,-A$3.length)),i)){const t=P$3;let e;for(;-1!==(e=c.indexOf(t));)c=c.slice(0,e)+c.slice(e+t.length),null!==n&&n>e&&(n=Math.max(e,n-t.length)),null!==r&&r>e&&(r=Math.max(e,r-t.length));}const u=o.getTextContent();if(i||c!==u){if(""===c){if(Uo(null),a$1||l||d$1)o.remove();else {const t=vi();setTimeout(()=>{t.update(()=>{o.isAttached()&&o.remove();});},20);}return}const e=o.getParent(),i=Zr(),u=o.getTextContentSize(),f=Vo(),h=o.getKey();if(o.isToken()||null!==f&&h===f&&!s||Fr(i)&&(null!==e&&!e.canInsertTextBefore()&&0===i.anchor.offset||i.anchor.key===t.__key&&0===i.anchor.offset&&!o.canInsertTextBefore()&&!s||i.focus.key===t.__key&&i.focus.offset===u&&!o.canInsertTextAfter()&&!s))return void o.markDirty();const g=Qr();if(!Fr(g)||null===n||null===r)return void as(o,c,g);if(g.setTextNodeRange(o,n,o,r),o.isSegmented()){const t=kr(o.getTextContent());o.replace(t),o=t;}as(o,c,g);}}}function as(t,e,n){if(t.setTextContent(e),Fr(n)){const e=t.getKey();for(const r of ["anchor","focus"]){const i=n[r];"text"===i.type&&i.key===e&&(i.offset=Al(t,i.offset,"clamp"));}}}function us(t,e,n){const r=e[n]||false;return "any"===r||r===t[n]}function fs(t,e){return us(t,e,"altKey")&&us(t,e,"ctrlKey")&&us(t,e,"shiftKey")&&us(t,e,"metaKey")}function ds(t,e,n){if(!fs(t,n))return false;if(t.key.toLowerCase()===e.toLowerCase())return true;if(e.length>1)return false;
7324if(1===t.key.length&&t.key.charCodeAt(0)<=127)return false;if(t.code.startsWith("Digit")&&/^\d$/.test(e))return t.code===`Digit${e}`;const r="Key"+e.toUpperCase();return t.code===r}const hs={ctrlKey:!i,metaKey:i},gs={altKey:i,ctrlKey:!i};function _s(t){return "Backspace"===t.key}function ps(t){return ds(t,"a",hs)}function ys(t){const e=Zo();if(Fr(t)){const e=t.anchor,n=t.focus,r=e.getNode().getTopLevelElementOrThrow().getParentOrThrow();return e.set(r.getKey(),0,"element"),n.set(r.getKey(),r.getChildrenSize(),"element"),St$3(t),t}{const t=e.select(0,e.getChildrenSize());return es(St$3(t)),t}}function ms(t,e){ void 0===t.__lexicalClassNameCache&&(t.__lexicalClassNameCache={});const n=t.__lexicalClassNameCache,r=n[e];if(void 0!==r)return r;const i=t[e];if("string"==typeof i){const t=yc(i);return n[e]=t,t}return i}function xs(e,n,r,i,o){if(0===r.size)return;const s=i.__type,l=i.__key,c=n.get(s);void 0===c&&t(33,s);const a=c.klass;let u=e.get(a);void 0===u&&(u=new Map,e.set(a,u));const f=u.get(l),d="destroyed"===f&&"created"===o;(void 0===f||d)&&u.set(l,d?"updated":o);}function Cs(t){const e=t.getType(),n=Si();if(n._readOnly){const t=rl(n).get(e);return t?Array.from(t.values()):[]}const r=n._nodeMap,i=[];for(const[,n]of r)n instanceof t&&n.__type===e&&n.isAttached()&&i.push(n);return i}function Ss(t,e,n){const r=t.getParent();let i=n,o=t;return null!==r&&(e&&0===n?(i=o.getIndexWithinParent(),o=r):e||n!==o.getChildrenSize()||(i=o.getIndexWithinParent()+1,o=r)),o.getChildAtIndex(e?i-1:i)}function vs(t,e){const n=t.offset;if("element"===t.type){return Ss(t.getNode(),e,n)}{const r=t.getNode();if(e&&0===n||!e&&n===r.getTextContentSize()){const t=e?r.getPreviousSibling():r.getNextSibling();return null===t?Ss(r.getParentOrThrow(),e,r.getIndexWithinParent()+(e?0:1)):t}}return null}function ks(t){const e=Ps(t).event,n=e&&e.inputType;return "insertFromPaste"===n||"insertFromPasteAsQuotation"===n}function Ts(t,e,n){return Pi(t,e,n,t)}function Ns(e,n){const r=e._keyToDOMMap.get(n);return void 0===r&&t(75,n),r}function bs(t){const e=t.assignedSlot||t.parentElement;return Hs(e)?e.host:e}function ws(t){return zo(t)?t:Ys(t)?t.ownerDocument:null}function Es(t){return vi()._updateTags.has(t)}function Os(t){xi();vi()._updateTags.add(t);}function Ms(t){xi();vi()._deferred.push(t);}function As(t,e){let n=t.getParent();for(;null!==n;){if(n.is(e))return true;n=n.getParent();}return false}function Ds(t){const e=ws(t);return e?e.defaultView:null}function Ps(e){const n=e._window;return null===n&&t(78),n}function Fs(t){return Wi(t)&&t.isInline()||ji(t)&&t.isInline()}function Ls(t){let e=t.getParentOrThrow();for(;null!==e;){if(Is(e))return e;e=e.getParentOrThrow();}return e}function Is(t){return Vi(t)||Wi(t)&&t.isShadowRoot()}function Ks(t,e=false){const n=t.constructor.clone(t);return $o(n,null),n.afterCloneFrom(t),e||n.resetOnCopyNodeFrom(t),n}function zs(e){const n=vi(),r=e.getType(),i=bo(n,r);void 0===i&&t(200,e.constructor.name,r);const{replace:o,replaceWithKlass:s}=i;if(null!==o){const n=o(e),i=n.constructor;return null!==s?n instanceof s||t(201,s.name,s.getType(),i.name,i.getType(),e.constructor.name,r):n instanceof e.constructor&&i!==e.constructor||t(202,i.name,i.getType(),e.constructor.name,r),n.__key===e.__key&&t(203,e.constructor.name,r,i.name,i.getType()),n}return e}function Rs(e,n){!Vi(e.getParent())||Wi(n)||ji(n)||t(99);}function Bs(e){const n=Yo(e);return null===n&&t(63,e),n}function Ws(t){return (ji(t)||Wi(t)&&!t.canBeEmpty())&&!t.isInline()}function $s(t,e,n){n.style.removeProperty("caret-color"),e._blockCursorElement=null;const r=t.parentElement;null!==r&&r.removeChild(t);}function Js(t){return n?(t||window).getSelection():null}function js(t){const e=Ds(t);return e?e.getSelection():null}function Us(e,n){let r=e.getChildAtIndex(n);null==r&&(r=e),Is(e)&&t(102);const i=e=>{const n=e.getParentOrThrow(),o=Is(n),s=e!==r||o?Ks(e):e;if(o)return Wi(e)&&Wi(s)||t(133),e.insertAfter(s),[e,s,s];{const[t,r,o]=i(n),l=e.getNextSiblings();return o.append(s,...l),[t,r,s]}},[o,s]=i(r);return [o,s]}function Vs(t){return Ys(t)&&"A"===t.tagName}function Ys(t){return qs(t)&&1===t.nodeType}function qs(t){return "object"==typeof t&&null!==t&&"nodeType"in t&&"number"==typeof t.nodeType}function Hs(t){return qs(t)&&11===t.nodeType}function Gs(t){const e=new RegExp(/^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|mark|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var|#text)$/,"i");return null!==t.nodeName.match(e)}function Xs(t){const e=new RegExp(/^(address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hr|li|main|nav|noscript|ol|p|pre|section|table|td|tfoot|ul|video)$/,"i");return null!==t.nodeName.match(e)}function Qs(t){if(ji(t)&&!t.isInline())return true;if(!Wi(t)||Is(t))return false;
7324const e=t.getFirstChild(),n=null===e||sr(e)||Tr(e)||e.isInline();return !t.isInline()&&false!==t.canBeEmpty()&&n}function Zs(){return vi()}function tl(t=Zs()){return t._config.dom||po}const el=new WeakMap,nl=new Map;function rl(e){if(!e._readOnly&&e.isEmpty())return nl;e._readOnly||t(192);let n=el.get(e);return n||(n=function(t){const e=new Map;for(const[n,r]of t._nodeMap){const t=r.__type;let i=e.get(t);i||(i=new Map,e.set(t,i)),i.set(n,r);}return e}(e),el.set(e,n)),n}function il(t){const e=t.constructor.clone(t);return e.afterCloneFrom(t),e}function ol(t){return (e=il(t))[Kn$1]=true,e;var e;}function sl(t,e){const n=parseInt(t.style.paddingInlineStart,10)||0,r=Math.round(n/40);e.setIndent(r);}function ll(t){t.__lexicalUnmanaged=true;}function cl(t){return true===t.__lexicalUnmanaged}function al(t,e){return function(t,e){return Object.prototype.hasOwnProperty.call(t,e)}(t,e)&&t[e]!==Rn$1[e]}function ul(e){const n=U$6 in e.prototype?e.prototype[U$6]():void 0,r=function(e){if(!(e===Rn$1||e.prototype instanceof Rn$1)){let n="<unknown>",r="<unknown>";try{n=e.getType();}catch(t){}try{Co.version&&(r=JSON.parse(Co.version));}catch(t){}t(290,e.name,n,r);}return e===Ji||e===Bi||e===Rn$1}(e),i=!r&&al(e,"getType")?e.getType():void 0;let o,s=i;if(n)if(i)o=n[i];else for(const[t,e]of Object.entries(n))s=t,o=e;if(!r&&s&&(al(e,"getType")||(e.getType=()=>s),al(e,"clone")||(e.clone=t=>(vo(t),new e)),al(e,"importJSON")||(e.importJSON=o&&o.$importJSON||(t=>(new e).updateFromJSON(t))),!al(e,"importDOM")&&o)){const{importDOM:t}=o;t&&(e.importDOM=()=>t);}return {ownNodeConfig:o,ownNodeType:s}}function fl(t){const e=Zs();xi();return new(e.resolveRegisteredNodeAfterReplacements(e.getRegisteredNode(t)).klass)}const dl=(t,e)=>{let n=t;for(;null!=n&&!Vi(n);){if(e(n))return n;n=n.getParent();}return null};function hl(e,n){const r=[];let i=e.__first;for(;null!==i;){const e=null===n?Yo(i):n.get(i);null==e&&t(174),r.push(i),i=e.__next;}return r}const gl={next:"previous",previous:"next"};class _l{origin;constructor(t){this.origin=t;}
vendor: 14,286 bytes, lines 7324-7396
7324[Symbol.iterator](){return $l({hasNext:Tl,initial:this.getAdjacentCaret(),map:t=>t,step:t=>t.getAdjacentCaret()})}getAdjacentCaret(){return Ol(this.getNodeAtCaret(),this.direction)}getSiblingCaret(){return Ol(this.origin,this.direction)}remove(){const t=this.getNodeAtCaret();return t&&t.remove(),this}replaceOrInsert(t,e){const n=this.getNodeAtCaret();return t.is(this.origin)||t.is(n)||(null===n?this.insert(t):n.replace(t,e)),this}splice(e,n,r="next"){const i=r===this.direction?n:Array.from(n).reverse();let o=this;const s=this.getParentAtCaret(),l=new Map;for(let t=o.getAdjacentCaret();null!==t&&l.size<e;t=t.getAdjacentCaret()){const e=t.origin.getWritable();l.set(e.getKey(),e);}for(const e of i){if(l.size>0){const n=o.getNodeAtCaret();if(n)if(l.delete(n.getKey()),l.delete(e.getKey()),n.is(e)||o.origin.is(e));else {const t=e.getParent();t&&t.is(s)&&e.remove(),n.replace(e);}else null===n&&t(263,Array.from(l).join(" "));}else o.insert(e);o=Ol(e,this.direction);}for(const t of l.values())t.remove();return this}}class pl extends _l{type="child";getLatest(){const t=this.origin.getLatest();return t===this.origin?this:Pl(t,this.direction)}getParentCaret(t="root"){return Ol(xl(this.getParentAtCaret(),t),this.direction)}getFlipped(){const t=ml(this.direction);return Ol(this.getNodeAtCaret(),t)||Pl(this.origin,t)}getParentAtCaret(){return this.origin}getChildCaret(){return this}isSameNodeCaret(t){return t instanceof pl&&this.direction===t.direction&&this.origin.is(t.origin)}isSamePointCaret(t){return this.isSameNodeCaret(t)}}const yl={root:Vi,shadowRoot:Is};function ml(t){return gl[t]}function xl(t,e="root"){return yl[e](t)?null:t}class Cl extends _l{type="sibling";getLatest(){const t=this.origin.getLatest();return t===this.origin?this:Ol(t,this.direction)}getSiblingCaret(){return this}getParentAtCaret(){return this.origin.getParent()}getChildCaret(){return Wi(this.origin)?Pl(this.origin,this.direction):null}getParentCaret(t="root"){return Ol(xl(this.getParentAtCaret(),t),this.direction)}getFlipped(){const t=ml(this.direction);return Ol(this.getNodeAtCaret(),t)||Pl(this.origin.getParentOrThrow(),t)}isSamePointCaret(t){return t instanceof Cl&&this.direction===t.direction&&this.origin.is(t.origin)}isSameNodeCaret(t){return (t instanceof Cl||t instanceof Sl)&&this.direction===t.direction&&this.origin.is(t.origin)}}class Sl extends _l{type="text";offset;constructor(t,e){super(t),this.offset=e;}getLatest(){const t=this.origin.getLatest();return t===this.origin?this:Ml(t,this.direction,this.offset)}getParentAtCaret(){return this.origin.getParent()}getChildCaret(){return null}getParentCaret(t="root"){return Ol(xl(this.getParentAtCaret(),t),this.direction)}getFlipped(){return Ml(this.origin,ml(this.direction),this.offset)}isSamePointCaret(t){return t instanceof Sl&&this.direction===t.direction&&this.origin.is(t.origin)&&this.offset===t.offset}isSameNodeCaret(t){return (t instanceof Cl||t instanceof Sl)&&this.direction===t.direction&&this.origin.is(t.origin)}getSiblingCaret(){return Ol(this.origin,this.direction)}}function vl(t){return t instanceof Sl}function kl(t){return t instanceof _l}function Tl(t){return t instanceof Cl}function Nl(t){return t instanceof pl}const bl={next:class extends Sl{direction="next";getNodeAtCaret(){return this.origin.getNextSibling()}insert(t){return this.origin.insertAfter(t),this}},previous:class extends Sl{direction="previous";getNodeAtCaret(){return this.origin.getPreviousSibling()}insert(t){return this.origin.insertBefore(t),this}}},wl={next:class extends Cl{direction="next";getNodeAtCaret(){return this.origin.getNextSibling()}insert(t){return this.origin.insertAfter(t),this}},previous:class extends Cl{direction="previous";getNodeAtCaret(){return this.origin.getPreviousSibling()}insert(t){return this.origin.insertBefore(t),this}}},El={next:class extends pl{direction="next";getNodeAtCaret(){return this.origin.getFirstChild()}insert(t){return this.origin.splice(0,0,[t]),this}},previous:class extends pl{direction="previous";getNodeAtCaret(){return this.origin.getLastChild()}insert(t){return this.origin.splice(this.origin.getChildrenSize(),0,[t]),this}}};function Ol(t,e){return t?new wl[e](t):null}function Ml(t,e,n){return t?new bl[e](t,Al(t,n)):null}function Al(t,n,r="error"){const i=t.getTextContentSize();let o="next"===n?i:"previous"===n?0:n;return (o<0||o>i)&&("clamp"!==r&&e(284,String(n),String(i),t.getKey()),o=o<0?0:i),o}function Dl(t,e){return new Kl(t,e)}function Pl(t,e){return Wi(t)?new El[e](t):null}function Fl(t){return t&&t.getChildCaret()||t}function Ll(t){return t&&Fl(t.getAdjacentCaret())}class Il{type="node-caret-range";direction;anchor;focus;constructor(t,e,n){this.anchor=t,this.focus=e,this.direction=n;}getLatest(){const t=this.anchor.getLatest(),e=this.focus.getLatest();return t===this.anchor&&e===this.focus?this:new Il(t,e,this.direction)}isCollapsed(){return this.anchor.isSamePointCaret(this.focus)}getTextSlices(){const t=t=>{const e=this[t].getLatest();return vl(e)?function(t,e){const{direction:n,origin:r}=t,i=Al(r,"focus"===e?ml(n):n);return Dl(t,i-t.offset)}(e,t):null},e=t("anchor"),n=t("focus");if(e&&n){const{caret:t}=e,{caret:r}=n;if(t.isSameNodeCaret(r))return [Dl(t,r.offset-t.offset),null]}return [e,n]}iterNodeCarets(t="root"){const e=vl(this.anchor)?this.anchor.getSiblingCaret():this.anchor.getLatest(),n=this.focus.getLatest(),r=vl(n),i=e=>e.isSameNodeCaret(n)?null:Ll(e)||e.getParentCaret(t);return $l({hasNext:t=>null!==t&&!(r&&n.isSameNodeCaret(t)),initial:e.isSameNodeCaret(n)?null:i(e),map:t=>t,step:i})}[Symbol.iterator](){return this.iterNodeCarets("root")}}class Kl{type="slice";caret;distance;constructor(t,e){this.caret=t,this.distance=e;}getSliceIndices(){const{distance:t,caret:{offset:e}}=this,n=e+t;return n<e?[n,e]:[e,n]}getTextContent(){const[t,e]=this.getSliceIndices();return this.caret.origin.getTextContent().slice(t,e)}getTextContentSize(){return Math.abs(this.distance)}removeTextSlice(){const{caret:{origin:t,direction:e}}=this,[n,r]=this.getSliceIndices(),i=t.getTextContent();return Ml(t.setTextContent(i.slice(0,n)+i.slice(r)),e,n)}}function zl(t){return t instanceof Kl}function Rl(t){return Wl(t,Ol(Zo(),t.direction))}function Bl(t){return Wl(t,t)}function Wl(e,n){return e.direction!==n.direction&&t(265),new Il(e,n,e.direction)}function $l(t){const{initial:e,hasNext:n,step:r,map:i}=t;let o=e;return {[Symbol.iterator](){return this},next(){if(!n(o))return {done:true,value:void 0};const t={done:false,value:i(o)};return o=r(o),t}}}function Jl(e,n){const r=Yl(e.origin,n.origin);switch(null===r&&t(275,e.origin.getKey(),n.origin.getKey()),r.type){case "same":{const t="text"===e.type,r="text"===n.type;return t&&r?function(t,e){return Math.sign(t-e)}(e.offset,n.offset):e.type===n.type?0:t?-1:r?1:"child"===e.type?-1:1}case "ancestor":return "child"===e.type?-1:1;case "descendant":return "child"===n.type?1:-1;case "branch":return jl(r)}}function jl(t){const{a:e,b:n}=t,r=e.__key,i=n.__key;let o=e,s=n;for(;o&&s;o=o.getNextSibling(),s=s.getNextSibling()){if(o.__key===i)return -1;if(s.__key===r)return 1}return null===o?1:-1}function Ul(t,e){return e.is(t)}function Vl(t){return Wi(t)?[t.getLatest(),null]:[t.getParent(),t.getLatest()]}function Yl(e,n){if(e.is(n))return {commonAncestor:e,type:"same"};const r=new Map;for(let[t,n]=Vl(e);t;n=t,t=t.getParent())r.set(t,n);for(let[i,o]=Vl(n);i;o=i,i=i.getParent()){const s=r.get(i);if(void 0!==s)return null===s?(Ul(e,i)||t(276),{commonAncestor:i,type:"ancestor"}):null===o?(Ul(n,i)||t(277),{commonAncestor:i,type:"descendant"}):((Wi(s)||Ul(e,s))&&(Wi(o)||Ul(n,o))&&i.is(s.getParent())&&i.is(o.getParent())||t(278),{a:s,b:o,commonAncestor:i,type:"branch"})}return null}function ql(e,n){const{type:r,key:i,offset:o}=e,s=Bs(e.key);return "text"===r?(Tr(s)||t(266,s.getType(),i),Ml(s,n,o)):(Wi(s)||t(267,s.getType(),i),lc(s,e.offset,n))}function Hl(e,n){const{origin:r,direction:i}=n,o="next"===i;vl(n)?e.set(r.getKey(),n.offset,"text"):Tl(n)?Tr(r)?e.set(r.getKey(),Al(r,i),"text"):e.set(r.getParentOrThrow().getKey(),r.getIndexWithinParent()+(o?1:0),"element"):(Nl(n)&&Wi(r)||t(268),e.set(r.getKey(),o?0:r.getChildrenSize(),"element"));}function Gl(t){const e=Qr(),n=Fr(e)?e:qr();return Xl(n,t),es(n),n}function Xl(t,e){Hl(t.anchor,e.anchor),Hl(t.focus,e.focus);}function Ql(t){const{anchor:e,focus:n}=t,r=ql(e,"next"),i=ql(n,"next"),o=Jl(r,i)<=0?"next":"previous";return Wl(oc(r,o),oc(i,o))}function Zl(t){const{direction:e,origin:n}=t,r=Ol(n,ml(e)).getNodeAtCaret();return r?Ol(r,e):Pl(n.getParentOrThrow(),e)}function tc(t,e="root"){const n=[t];for(let r=Nl(t)?t.getParentCaret(e):t.getSiblingCaret();null!==r;r=r.getParentCaret(e))n.push(Zl(r));return n}function ec(t){return !!t&&t.origin.isAttached()}function nc(e,n="removeEmptySlices"){if(e.isCollapsed())return e;const r="root",i="next";let o=n;const s=sc(e,i),l=tc(s.anchor,r),c=tc(s.focus.getFlipped(),r),a=new Set,u=[];for(const t of s.iterNodeCarets(r))if(Nl(t))a.add(t.origin.getKey());else if(Tl(t)){const{origin:e}=t;Wi(e)&&!a.has(e.getKey())||u.push(e);}for(const t of u)t.remove();for(const t of s.getTextSlices()){if(!t)continue;const{origin:e}=t.caret,n=e.getTextContentSize(),r=Zl(Ol(e,i)),s=e.getMode();if(Math.abs(t.distance)===n&&"removeEmptySlices"===o||"token"===s&&0!==t.distance)r.remove();else if(0!==t.distance){o="removeEmptySlices";let e=t.removeTextSlice();const n=t.caret.origin;if("segmented"===s){const t=e.origin,n=kr(t.getTextContent()).setStyle(t.getStyle()).setFormat(t.getFormat());r.replaceOrInsert(n),e=Ml(n,i,e.offset);}n.is(l[0].origin)&&(l[0]=e),n.is(c[0].origin)&&(c[0]=e.getFlipped());}}let f,d;for(const t of l)if(ec(t)){f=rc(t);break}for(const t of c)if(ec(t)){d=rc(t);break}const h=function(t,e,n){if(!t||!e)return null;const r=t.getParentAtCaret(),i=e.getParentAtCaret();if(!r||!i)return null;const o=r.getParents().reverse();o.push(r);const s=i.getParents().reverse();s.push(i);const l=Math.min(o.length,s.length);let c;for(c=0;c<l&&o[c]===s[c];c++);const a=(t,e)=>{let n;for(let r=c;r<t.length;r++){const i=t[r];if(Is(i))return;!n&&e(i)&&(n=i);}return n},u=a(o,Qs),f=u&&a(s,t=>n.has(t.getKey())&&Qs(t));return u&&f?[u,f]:null}(f,d,a);if(h){const[t,e]=h;Pl(t,"previous").splice(0,e.getChildren());let n=e.getParent();for(e.remove(true);n&&n.isEmpty();){const t=n;n=n.getParent(),t.remove(true);}}const g=[f,d,...l,...c].find(ec);if(g){return Bl(oc(rc(g),e.direction))}t(269,JSON.stringify(l.map(t=>t.origin.__key)));}function rc(t){const e=function(t){let e=t;for(;Nl(e);){const t=Ll(e);if(!Nl(t))break;e=t;}return e}(t.getLatest()),{direction:n}=e;if(Tr(e.origin))return vl(e)?e:Ml(e.origin,n,n);const r=e.getAdjacentCaret();return Tl(r)&&Tr(r.origin)?Ml(r.origin,n,ml(n)):e}function ic(t){return vl(t)&&t.offset!==Al(t.origin,t.direction)}function oc(t,e){return t.direction===e?t:t.getFlipped()}function sc(t,e){return t.direction===e?t:Wl(oc(t.focus,e),oc(t.anchor,e))}function lc(t,e,n){let r=Pl(t,"next");for(let t=0;t<e;t++){const t=r.getAdjacentCaret();if(null===t)break;r=t;}return oc(r,n)}function cc(t,e="root"){let n=0,r=t,i=Ll(r);for(;null===i;){if(n--,i=r.getParentCaret(e),!i)return null;r=i,i=Ll(r);}return i&&[i,n]}function ac(e){const{origin:n,offset:r,direction:i}=e;if(r===Al(n,i))return e.getSiblingCaret();if(r===Al(n,ml(i)))return Zl(e.getSiblingCaret());const[o]=n.splitText(r);return Tr(o)||t(281),oc(Ol(o,"next"),i)}function uc(t,e){return true}function fc(t,{$copyElementNode:e=Ks,$splitTextPointCaretNext:n=ac,rootMode:r="shadowRoot",$shouldSplit:i=uc,removeEmptyDestination:o=false}={}){if(vl(t))return n(t);const s=t.getParentCaret(r);if(s){const{origin:n}=s;if(Nl(t)){const t=Zl(s);if(o&&n.isEmpty())return n.remove(),t;if(!n.canBeEmpty()||!i(n,"first"))return t}const r=function(t){const e=[];for(let n=t.getAdjacentCaret();n;n=n.getAdjacentCaret())e.push(n.origin);return e}(t);(r.length>0||!o&&n.canBeEmpty()&&i(n,"last"))&&s.insert(e(n).splice(0,0,r));}return s}function dc(t){return t}function hc(...t){return t}function gc(t,e){return [t,e]}function _c(t){return t}function pc(t,e){if(!e||t===e)return t;for(const n in e)if(t[n]!==e[n])return {...t,...e};return t}function yc(...t){const e=[];for(const n of t)if(n&&"string"==typeof n)for(const[t]of n.matchAll(/\S+/g))e.push(t);return e}function mc(t,...e){const n=yc(...e);n.length>0&&t.classList.add(...n);}function xc(t,...e){const n=yc(...e);n.length>0&&t.classList.remove(...n);}function Cc(...t){return ()=>{for(let e=t.length-1;e>=0;e--)t[e]();t.length=0;}} 7325 7326var Lexical_prod = /*#__PURE__*/Object.freeze({ 7327 __proto__: null, 7328 $addUpdateTag: Os, 7329 $applyNodeReplacement: zs, 7330 $caretFromPoint: ql, 7331 $caretRangeFromSelection: Ql, 7332 $cloneWithProperties: il, 7333 $cloneWithPropertiesEphemeral: ol, 7334 $comparePointCaretNext: Jl, 7335 $copyNode: Ks, 7336 $create: fl, 7337 $createChildrenArray: hl, 7338 $createLineBreakNode: or, 7339 $createNodeSelection: Hr, 7340 $createParagraphNode: eo, 7341 $createPoint: Mr, 7342 $createRangeSelection: qr, 7343 $createRangeSelectionFromDom: Gr, 7344 $createTabNode: wr, 7345 $createTextNode: kr, 7346 $extendCaretToRange: Rl, 7347 $findMatchingParent: dl, 7348 $getAdjacentChildCaret: Ll, 7349 $getAdjacentNode: vs, 7350 $getAdjacentSiblingOrParentSiblingCaret: cc, 7351 $getCaretInDirection: oc, 7352 $getCaretRange: Wl, 7353 $getCaretRangeInDirection: sc, 7354 $getCharacterOffsets: zr, 7355 $getChildCaret: Pl, 7356 $getChildCaretAtIndex: lc, 7357 $getChildCaretOrSelf: Fl, 7358 $getCollapsedCaretRange: Bl, 7359 $getCommonAncestor: Yl, 7360 $getCommonAncestorResultBranchOrder: jl, 7361 $getEditor: Zs, 7362 $getEditorDOMRenderConfig: tl, 7363 $getNearestNodeFromDOMNode: Go, 7364 $getNearestRootOrShadowRoot: Ls, 7365 $getNodeByKey: Yo, 7366 $getNodeByKeyOrThrow: Bs, 7367 $getNodeFromDOMNode: qo, 7368 $getPreviousSelection: Zr, 7369 $getRoot: Zo, 7370 $getSelection: Qr, 7371 $getSiblingCaret: Ol, 7372 $getState: st$2, 7373 $getStateChange: lt$3, 7374 $getTextContent: ci, 7375 $getTextNodeOffset: Al, 7376 $getTextPointCaret: Ml, 7377 $getTextPointCaretSlice: Dl, 7378 $getWritableNodeState: ft$2, 7379 $hasAncestor: As, 7380 $hasUpdateTag: Es, 7381 $insertNodes: li, 7382 $isBlockElementNode: Vr, 7383 $isChildCaret: Nl, 7384 $isDecoratorNode: ji, 7385 $isEditorState: Gi, 7386 $isElementNode: Wi, 7387 $isExtendableTextPointCaret: ic, 7388 $isInlineElementOrDecoratorNode: Fs, 7389 $isLeafNode: Wo, 7390 $isLexicalNode: Bn, 7391 $isLineBreakNode: sr, 7392 $isNodeCaret: kl, 7393 $isNodeSelection: Ir, 7394 $isParagraphNode: no, 7395 $isRangeSelection: Fr, 7396 $isRootNode: Vi,
7397 $isRootOrShadowRoot: Is, 7398 $isSiblingCaret: Tl, 7399 $isTabNode: Er, 7400 $isTextNode: Tr, 7401 $isTextPointCaret: vl, 7402 $isTextPointCaretSlice: zl, 7403 $isTokenOrSegmented: Io, 7404 $isTokenOrTab: Lo, 7405 $nodesOfType: Cs, 7406 $normalizeCaret: rc, 7407 $normalizeSelection__EXPERIMENTAL: St$3, 7408 $onUpdate: Ms, 7409 $parseSerializedNode: Ei, 7410 $removeTextFromCaretRange: nc, 7411 $rewindSiblingCaret: Zl, 7412 $selectAll: ys, 7413 $setCompositionKey: Uo, 7414 $setPointFromCaret: Hl, 7415 $setSelection: es, 7416 $setSelectionFromCaretRange: Gl, 7417 $setState: ct$2, 7418 $splitAtPointCaretNext: fc, 7419 $splitNode: Us, 7420 $updateRangeSelectionFromCaretRange: Xl, 7421 ArtificialNode__DO_NOT_USE: Qi, 7422 BEFORE_INPUT_COMMAND: le$3, 7423 BLUR_COMMAND: Xe$2, 7424 CAN_REDO_COMMAND: qe$2, 7425 CAN_UNDO_COMMAND: He$2, 7426 CLEAR_EDITOR_COMMAND: Ve$2, 7427 CLEAR_HISTORY_COMMAND: Ye$1, 7428 CLICK_COMMAND: se$5, 7429 COLLABORATION_TAG: Un, 7430 COMMAND_PRIORITY_BEFORE_CRITICAL: ho, 7431 COMMAND_PRIORITY_BEFORE_EDITOR: co, 7432 COMMAND_PRIORITY_BEFORE_HIGH: fo, 7433 COMMAND_PRIORITY_BEFORE_LOW: ao, 7434 COMMAND_PRIORITY_BEFORE_NORMAL: uo, 7435 COMMAND_PRIORITY_CRITICAL: lo, 7436 COMMAND_PRIORITY_EDITOR: ro, 7437 COMMAND_PRIORITY_HIGH: so, 7438 COMMAND_PRIORITY_LOW: io, 7439 COMMAND_PRIORITY_NORMAL: oo, 7440 COMPOSITION_END_COMMAND: ue$4, 7441 COMPOSITION_END_TAG: Xn, 7442 COMPOSITION_START_COMMAND: ae$4, 7443 COMPOSITION_START_TAG: Gn, 7444 CONTROLLED_TEXT_INSERTION_COMMAND: ge$3, 7445 COPY_COMMAND: Je$2, 7446 CUT_COMMAND: je$2, 7447 DEFAULT_EDITOR_DOM_CONFIG: po, 7448 DELETE_CHARACTER_COMMAND: fe$4, 7449 DELETE_LINE_COMMAND: me$3,
7450 DELETE_WORD_COMMAND: ye$2, 7451 DRAGEND_COMMAND: $e$2, 7452 DRAGOVER_COMMAND: We$2, 7453 DRAGSTART_COMMAND: Be$2, 7454 DROP_COMMAND: ze$2, 7455 DecoratorNode: Ji, 7456 ElementNode: Bi, 7457 FOCUS_COMMAND: Ge$2, 7458 FORMAT_ELEMENT_COMMAND: Re$1, 7459 FORMAT_TEXT_COMMAND: xe, 7460 HISTORIC_TAG: Wn$1, 7461 HISTORY_MERGE_TAG: Jn, 7462 HISTORY_PUSH_TAG: $n$1, 7463 INDENT_CONTENT_COMMAND: Ie$3, 7464 INPUT_COMMAND: ce$4, 7465 INSERT_LINE_BREAK_COMMAND: de$4, 7466 INSERT_PARAGRAPH_COMMAND: he$3, 7467 INSERT_TAB_COMMAND: Le$2, 7468 INTERNAL_$isBlock: Qs, 7469 IS_ALL_FORMATTING: T$2, 7470 IS_BOLD: p, 7471 IS_CODE: C$4, 7472 IS_HIGHLIGHT: k$3, 7473 IS_ITALIC: y$1, 7474 IS_STRIKETHROUGH: m$1, 7475 IS_SUBSCRIPT: S$1, 7476 IS_SUPERSCRIPT: v$1, 7477 IS_UNDERLINE: x$1, 7478 KEY_ARROW_DOWN_COMMAND: Ee$3, 7479 KEY_ARROW_LEFT_COMMAND: Ne$1, 7480 KEY_ARROW_RIGHT_COMMAND: ke$2, 7481 KEY_ARROW_UP_COMMAND: we$1, 7482 KEY_BACKSPACE_COMMAND: Ae$3, 7483 KEY_DELETE_COMMAND: Pe$2, 7484 KEY_DOWN_COMMAND: ve$2, 7485 KEY_ENTER_COMMAND: Oe$2, 7486 KEY_ESCAPE_COMMAND: De$2, 7487 KEY_MODIFIER_COMMAND: Qe$1, 7488 KEY_SPACE_COMMAND: Me$2, 7489 KEY_TAB_COMMAND: Fe$2, 7490 LineBreakNode: rr, 7491 MOVE_TO_END: Te$2, 7492 MOVE_TO_START: be$1, 7493 NODE_STATE_KEY: j$7, 7494 OUTDENT_CONTENT_COMMAND: Ke$2, 7495 PASTE_COMMAND: _e$2, 7496 PASTE_TAG: jn, 7497 ParagraphNode: Zi, 7498 REDO_COMMAND: Se$2, 7499 REMOVE_TEXT_COMMAND: pe$3, 7500 RootNode: Ui, 7501 SELECTION_CHANGE_COMMAND: ie$4, 7502 SELECTION_INSERT_CLIPBOARD_NODES_COMMAND: oe$6, 7503 SELECT_ALL_COMMAND: Ue$2, 7504 SKIP_COLLAB_TAG: Vn, 7505 SKIP_DOM_SELECTION_TAG: qn, 7506 SKIP_SCROLL_INTO_VIEW_TAG: Yn, 7507 SKIP_SELECTION_FOCUS_TAG: Hn, 7508 TEXT_TYPE_TO_FORMAT: z$7, 7509 TabNode: br, 7510 TextNode: gr, 7511 UNDO_COMMAND: Ce$2, 7512 addClassNamesToElement: mc, 7513 buildImportMap: In, 7514 configExtension: hc, 7515 createCommand: re$5, 7516 createEditor: yo, 7517 createSharedNodeState: at$3, 7518 createState: ot$3, 7519 declarePeerDependency: gc, 7520 defineExtension: dc, 7521 flipDirection: ml, 7522 getDOMOwnerDocument: ws, 7523 getDOMSelection: Js, 7524 getDOMSelectionFromTarget: js, 7525 getDOMTextNode: Ro, 7526 getEditorPropertyFromDOMNode: Po, 7527 getNearestEditorFromDOMNode: Do, 7528 getRegisteredNode: bo, 7529 getRegisteredNodeOrThrow: No, 7530 getStaticNodeConfig: ul, 7531 getStyleObjectFromCSS: Zn, 7532 getTextDirection: Fo, 7533 getTransformSetFromKlass: _o, 7534 isBlockDomNode: Xs, 7535 isCurrentlyReadOnlyMode: mi, 7536 isDOMDocumentNode: zo, 7537 isDOMNode: qs, 7538 isDOMTextNode: Ko, 7539 isDOMUnmanaged: cl, 7540 isDocumentFragment: Hs, 7541 isExactShortcutMatch: ds, 7542 isHTMLAnchorElement: Vs, 7543 isHTMLElement: Ys, 7544 isInlineDomNode: Gs, 7545 isLexicalEditor: Ao, 7546 isModifierMatch: fs, 7547 isSelectionCapturedInDecoratorInput: Oo, 7548 isSelectionWithinEditor: Mo, 7549 makeStepwiseIterator: $l, 7550 mergeRegister: Cc, 7551 normalizeClassNames: yc, 7552 removeClassNamesFromElement: xc, 7553 removeFromParent: Jo, 7554 resetRandomKey: To, 7555 safeCast: _c, 7556 setDOMStyleFromCSS: nr, 7557 setDOMStyleObject: er, 7558 setDOMUnmanaged: ll, 7559 setNodeIndentFromDOM: sl, 7560 shallowMergeConfig: pc, 7561 toggleTextFormatType: Bo 7562}); 7563 7564/** 7565 * Copyright (c) Meta Platforms, Inc. and affiliates. 7566 * 7567 * This source code is licensed under the MIT license found in the 7568 * LICENSE file in the root directory of this source tree. 7569 * 7570 */ 7571 7572function E$3(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function F$6(e){let t="";for(const n in e)n&&(t+=`${n}: ${e[n]};`);return t}function b$2(e){const n=Zs().getElementByKey(e.getKey());if(null===n)return null;const o=n.ownerDocument.defaultView;return null===o?null:o.getComputedStyle(n)}function z$6(e){return b$2(Vi(e)?e:e.getParentOrThrow())}function O$3(e){const t=z$6(e);return null!==t&&"rtl"===t.direction}function R$3(e,t,n="self"){const o=e.getStartEndPoints();if(t.isSelected(e)&&!Io(t)&&null!==o){const[l,r]=o,s=e.isBackward(),i=l.getNode(),u=r.getNode(),g=t.is(i),a=t.is(u);if(g||a){const[o,l]=zr(e),r=i.is(u),g=t.is(s?u:i),a=t.is(s?i:u);let d,p=0;if(r)p=o>l?l:o,d=o>l?o:l;else if(g){p=s?l:o,d=void 0;}else if(a){p=0,d=s?o:l;}const h=t.__text.slice(p,d);h!==t.__text&&("clone"===n&&(t=ol(t)),t.__text=h);}}return t}function A$2(e){if("text"===e.type)return e.offset===e.getNode().getTextContentSize();const t=e.getNode();return Wi(t)||E$3(177),e.offset===t.getChildrenSize()}
7572function M$4(t,n){(Fr(t)?t.isCollapsed():Tr(t)||Wi(t))||E$3(280);const o=Zn(Fr(t)?t.style:Tr(t)?t.getStyle():t.getTextStyle()),r=F$6(Object.entries(n).reduce((e,[n,l])=>("function"==typeof l?e[n]=l(o[n],t):null===l?delete e[n]:e[n]=l,e),{...o}));Fr(t)||Tr(t)?t.setStyle(r):t.setTextStyle(r);}function $$3(e,t){if(Fr(e)&&e.isCollapsed()){M$4(e,t);const n=e.anchor.getNode();Wi(n)&&n.isEmpty()&&M$4(n,t);}D$3(e=>{M$4(e,t);});const n=e.getNodes();if(n.length>0){const e=new Set;for(const o of n){if(!Wi(o)||!o.canBeEmpty()||0!==o.getChildrenSize())continue;const n=o.getKey();e.has(n)||(e.add(n),M$4(o,t));}}}function D$3(t){const n=Qr();if(!n)return;const i=new Map,c=e=>i.get(e.getKey())||[0,e.getTextContentSize()];if(Fr(n))for(const e of Ql(n).getTextSlices())e&&i.set(e.caret.origin.getKey(),e.getSliceIndices());const f=n.getNodes();for(const n of f){if(!Tr(n)||!n.canHaveFormat())continue;const[o,l]=c(n);if(l!==o)if(Io(n)||0===o&&l===n.getTextContentSize())t(n);else {t(n.splitText(o,l)[0===o?0:1]);}}Fr(n)&&"text"===n.anchor.type&&"text"===n.focus.type&&n.anchor.key===n.focus.key&&j$6(n);}function j$6(e){if(e.isBackward()){const{anchor:t,focus:n}=e,{key:o,offset:l,type:r}=t;t.set(n.key,n.offset,n.type),n.set(o,l,r);}}function U$5(e,t){const n=e.getFormatType(),o=e.getIndent();n!==t.getFormatType()&&t.setFormat(n),o!==t.getIndent()&&t.setIndent(o);}function H$6(e,t,n=U$5){if(null===e)return;const l=e.getStartEndPoints(),r=new Map;let s=null;if(l){const[e,t]=l;s=qr(),s.anchor.set(e.key,e.offset,e.type),s.focus.set(t.key,t.offset,t.type);const n=dl(e.getNode(),Qs),o=dl(t.getNode(),Qs);Wi(n)&&r.set(n.getKey(),n),Wi(o)&&r.set(o.getKey(),o);}for(const t of e.getNodes())if(Wi(t)&&Qs(t))r.set(t.getKey(),t);else if(null===l){const e=dl(t,Qs);Wi(e)&&r.set(e.getKey(),e);}for(const[e,o]of r){const l=t();n(o,l),o.replace(l,true),s&&(e===s.anchor.key&&s.anchor.set(l.getKey(),s.anchor.offset,s.anchor.type),e===s.focus.key&&s.focus.set(l.getKey(),s.focus.offset,s.focus.type));}s&&e.is(Qr())&&es(s);}function G$9(e){const t=J$6(e);return null!==t&&"vertical-rl"===t.writingMode}function J$6(e){const t=e.anchor.getNode();return Wi(t)?b$2(t):z$6(t)}function Q$8(e,t){let n=G$9(e)?!t:t;Z$4(e)&&(n=!n);const o=ql(e.focus,n?"previous":"next");if(ic(o))return false;for(const e of Rl(o)){if(Nl(e))return !e.origin.isInline();if(!Wi(e.origin)){if(ji(e.origin))return true;break}}return false}function Y$4(e,t,n,o){e.modify(t?"extend":"move",n,o);}function Z$4(e){const t=J$6(e);return null!==t&&"rtl"===t.direction}function ee$3(e,t,n){const o=Z$4(e);let l;l=G$9(e)||o?!n:n,Y$4(e,t,l,"character");}function te$4(e,t,n){const o=e.getStyle(),l=Zn(o);return null!==l&&l[t]||n}function ne$4(t,n,o=""){let r=null;const s=t.getNodes(),i=t.anchor,c=t.focus,f=t.isBackward(),u=f?c.getNode():i.getNode(),g=f?i.getNode():c.getNode(),a=f?c.offset:i.offset,p=f?i.offset:c.offset;if(Fr(t)&&t.isCollapsed()&&""!==t.style){const e=t.style,o=Zn(e);if(null!==o&&n in o)return o[n]}for(let t=0;t<s.length;t++){const l=s[t];if((0!==t||!l.is(u)||!Tr(l)||a!==l.getTextContentSize())&&((0===t||!l.is(g)||0!==p)&&Tr(l))){const e=te$4(l,n,o);if(null===r)r=e;else if(r!==e){r="";break}}}return null===r?o:r}const oe$5=Zn; 7573 7574function deepMerge(target, source) { 7575 const result = { ...target, ...source }; 7576 for (const [ key, value ] of Object.entries(source)) { 7577 if (arePlainHashes(target[key], value)) { 7578 result[key] = deepMerge(target[key], value); 7579 } 7580 } 7581 7582 return result 7583} 7584 7585function arePlainHashes(...values) { 7586 return values.every(value => value && value.constructor == Object) 7587} 7588 7589class Configuration { 7590 #tree = {} 7591 7592 constructor(...configs) { 7593 this.merge(...configs); 7594 } 7595 7596 merge(...configs) { 7597 return this.#tree = configs.reduce(deepMerge, this.#tree) 7598 } 7599 7600 get(path) { 7601 const keys = path.split("."); 7602 return keys.reduce((node, key) => node[key], this.#tree) 7603 } 7604} 7605 7606function range(from, to) { 7607 return [ ...Array(1 + to - from).keys() ].map(i => i + from) 7608} 7609 7610const global$1 = new Configuration({ 7611 attachmentTagName: "action-text-attachment", 7612 attachmentContentTypeNamespace: "actiontext", 7613 authenticatedUploads: false, 7614 extensions: [] 7615}); 7616 7617const presets = new Configuration({ 7618 default: { 7619 attachments: true, 7620 markdown: true, 7621 multiLine: true, 7622 permittedAttachmentTypes: null, 7623 richText: true, 7624 toolbar: { 7625 upload: "both" 7626 }, 7627 headings: [ "h2", "h3", "h4" ], 7628 highlight: { 7629 buttons: { 7630 color: range(1, 9).map(n => `var(--highlight-${n})`), 7631 "background-color": range(1, 9).map(n => `var(--highlight-bg-${n})`), 7632 }, 7633 permit: { 7634 color: [], 7635 "background-color": [] 7636 } 7637 } 7638 } 7639}); 7640 7641var Lexxy = { 7642 global: global$1, 7643 presets, 7644 configure({ global: newGlobal, ...newPresets }) { 7645 if (newGlobal) { 7646 global$1
vendor: 10,186 bytes, lines 7646-7838
7646.merge(newGlobal); 7647 } 7648 presets.merge(newPresets); 7649 } 7650}; 7651 7652// An attachment's `url` ends up as an <img src> (action_text_attachment_node 7653// reads it into `this.src`, which is assigned to img.src). DOMPurify already 7654// permits a data: URI on img[src] â img is in its DATA_URI_TAGS â but it has no 7655// way to know that a custom element's `url` feeds the same sink, so it applies 7656// the plain URI check and drops it. 7657// 7658// Until 3.3.2 that never came up: attributes admitted by a *functional* ADD_ATTR 7659// skipped URI validation entirely (GHSA-cjmm-f4jc-qw8r), which is how data: 7660// URLs worked here â and, less happily, how `url="javascript:â¦"` survived too. 7661// The fix restored validation for both. The bypass was reported to us by 7662// @petitpois via HackerOne. 7663// 7664// So `url` is marked URI-safe, which hands the decision to this hook. The hook 7665// only ever removes an attribute â it never force-keeps one â so scoping stays 7666// with the ADD_ATTR predicate, and a `url` on a tag that never declared it is 7667// dropped as it always was. 7668// 7669// The data: exception is scoped to the attachment element, not to the attribute 7670// name. ADD_URI_SAFE_ATTR is attribute-name-wide: it takes `url` out of 7671// DOMPurify's URI checking on every tag, not just ours. Extensions may declare 7672// arbitrary attributes on arbitrary tags â home/docs/extensions.md's own worked 7673// example is an <iframe> â so an extension declaring `url` would otherwise 7674// inherit an exception granted because *an attachment's* url becomes an img src. 7675// Nothing about a third party's element supports that, and `data:text/html` in a 7676// navigational sink is script execution. Everything else gets the standard 7677// policy, which is what it would have had if we had never touched `url`. 7678// 7679// That argument is about an attribute feeding a URL sink, not about 7680// ADD_URI_SAFE_ATTR as such. The inert text attributes beside `url` in that list 7681// â `caption`, `filename` â keep the attribute-name-wide exemption, and need it: 7682// ordinary prose like "Q4: results" is not a URI any regex here would accept. 7683const URI_BEARING_ATTACHMENT_ATTRIBUTES = [ "url" ]; 7684 7685// DOMPurify's own IS_ALLOWED_URI scheme list, reproduced rather than narrowed, so 7686// `url` on a non-attachment tag is treated exactly as DOMPurify would have treated 7687// it. Kept as a source string so allowedUriRegexp() can widen it with an editor's 7688// declared schemes without re-deriving the rest of the pattern. 7689const BASE_URI_SCHEMES = "(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix"; 7690 7691// A scheme name (not a full pattern), so a caller can't inject regexp syntax. 7692const SCHEME_NAME = /^[a-z][a-z0-9+.-]*$/; 7693 7694// The executable schemes, by DOMPurify's own IS_SCRIPT_OR_DATA definition 7695// (/^(?:\w+script|data):/i): javascript, vbscript, â¦script, and data. Widening the 7696// allowlist to admit one would let it survive on href/object[data], which the 7697// override otherwise defeats â DOMPurify does not re-block a scheme its 7698// ALLOWED_URI_REGEXP accepts. A caller declaring one is dropped, so it stays 7699// refused. This is a closed set (the schemes a browser executes), not a growing 7700// denylist. 7701const EXECUTABLE_SCHEME = /^(?:\w+script|data)$/i; 7702 7703// Builds DOMPurify's default IS_ALLOWED_URI, optionally with extra schemes folded 7704// into the scheme alternation. Widening the recognised-safe scheme set is how a 7705// custom-scheme identifier (a mention's `gid://â¦`) passes validation without 7706// exempting any attribute from it. Passing no schemes reproduces DOMPurify's 7707// default exactly. 7708function allowedUriRegexp(extraSchemes = []) { 7709 const extra = extraSchemes 7710 .map(scheme => String(scheme).toLowerCase()) 7711 .filter(scheme => SCHEME_NAME.test(scheme) && !EXECUTABLE_SCHEME.test(scheme)) 7712 .map(scheme => scheme.replace(/[.+-]/g, "\\$&")); 7713 7714 const schemes = [ BASE_URI_SCHEMES, ...extra ].join("|"); 7715 7716 return new RegExp(`^(?:(?:${schemes}):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))`, "i") 7717} 7718 7719const ALLOWED_URI = allowedUriRegexp(); 7720 7721// eslint-disable-next-line no-control-regex -- mirrors DOMPurify's own ATTR_WHITESPACE 7722const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; 7723 7724// Tested against the value as given, never the whitespace-stripped copy, so a 7725// scheme smuggled at a nonzero offset is refused. DOMPurify draws the same line: 7726// its data: allowance is a prefix test on the un-stripped value, which is why 7727// this is a second step rather than one more scheme in ALLOWED_URI. 7728// 7729// One deliberate difference from DOMPurify's img[src] handling remains, stated 7730// because the earlier claim of matching it "exactly" was not true: DOMPurify 7731// tests for a literal lowercase `data:` and this is case-insensitive, so `DATA:` 7732// passes here too. That matches how browsers resolve schemes, which is what 7733// actually decides whether the URL loads. 7734const ATTACHMENT_DATA_URI = /^data:/i; 7735 7736function isAttachmentTag(tag) { 7737 return tag === Lexxy.global.get("attachmentTagName") 7738} 7739 7740function attachmentUriFilterHook(currentNode, hookEvent) { 7741 if (!URI_BEARING_ATTACHMENT_ATTRIBUTES.includes(hookEvent.attrName)) return 7742 7743 // DOMPurify keeps an empty value â its chain ends `else if (value) { return 7744 // false } else ;` â while every alternation here needs at least one character. 7745 if (!hookEvent.attrValue) return 7746 7747 const value = String(hookEvent.attrValue); 7748 7749 if (ALLOWED_URI.test(value.replace(ATTR_WHITESPACE, ""))) return 7750 if (isAttachmentTag(currentNode?.nodeName?.toLowerCase()) && ATTACHMENT_DATA_URI.test(value)) return 7751 7752 hookEvent.keepAttr = false; 7753} 7754 7755// Lexxy's own DOMPurify instance, deliberately not the shared default export. 7756// 7757// dompurify's default export is a singleton, and both its config and its hooks 7758// are global to every consumer in the bundle. That makes configuring it from an 7759// editor's connectedCallback actively dangerous for the host app: DOMPurify 7760// treats a persistent config as final, so once setConfig() has run, every 7761// later `sanitize(html, config)` anywhere in the app silently ignores its own 7762// config argument. An app sanitizing untrusted HTML with, say, 7763// `{ ALLOW_DATA_ATTR: false }` would keep passing that option and stop getting 7764// it the moment a Lexxy editor connected â with no error and no visible change 7765// at the call site. 7766// 7767// Calling the default export with a window returns a fresh, independent 7768// instance. This one carries the hooks and config below; nothing we do here can 7769// reach the app's instance, and nothing it does can reach ours. 7770// 7771// Under Trusted Types, every DOMPurify instance tries to create a policy named 7772// `dompurify` on its first sanitize, and TT rejects a duplicate name â so the 7773// second instance on the page gets none. That matters, and not because it throws: 7774// DOMPurify hands its input to DOMParser.parseFromString, which is itself a TT 7775// sink, but `_initDocument` swallows that throw and the innerHTML throw from its 7776// createDocument fallback, and `sanitize` then returns "" for the body it never 7777// got. An unsigned instance silently drops all content, with nothing in the host's 7778// error tracker to say why â and which sanitizer goes silent depends on which one 7779// ran first. 7780// 7781// So we create our own, under our own name, and hand it to DOMPurify rather than 7782// letting it try. Lazily, because resolving it at import would fire a CSP 7783// violation report on every page load of an app that imports Lexxy and never 7784// renders an editor, and at most once, because TT throws on a duplicate name. 7785// Guarded too, because creating a policy the CSP hasn't allowlisted throws: if 7786// that happens we're back to no policy, which is exactly where this stood before. 7787// An app enforcing `require-trusted-types-for 'script'` should add `lexxy` to its 7788// `trusted-types` directive. 7789// 7790// What this does NOT do is make Lexxy work under enforced Trusted Types. It 7791// stops *our* sanitizer from taking the host's policy name and breaking the 7792// host's; it does nothing about Lexxy's own unwrapped sinks, and there are 7793// several. `parseHtml` in helpers/html_helper.js hands a plain string to 7794// DOMParser.parseFromString on the initial-value path, so the editor throws 7795// before it finishes connecting â verified in Chromium under 7796// `require-trusted-types-for 'script'`, with `lexxy` allowlisted and without. 7797// `createElement` in the same file is a second sink in it, writing its `content` 7798// argument through innerHTML for the two callers that pass one â the wrapped-table 7799// figure and the table tools' count. `highlightElement` in 7800// helpers/code_highlighting_helper.js writes Prism's output the same way, and both 7801// it and highlightCode are exported from src/index.js â so that one throws for a 7802// host app calling Lexxy's highlighting API directly, outside any editor. The 7803// `insertAdjacentHTML` in nodes/custom_action_text_attachment_node.js and the 7804// `innerHTML` writes across elements/ â the toolbar, the dropdowns, the node 7805// delete button â are in the same position. Making the editor usable under TT is a 7806// separate piece of work; this is a prerequisite for it, not the whole of it. 7807let trustedTypesPolicyResolved = false; 7808let resolvedTrustedTypesPolicy = null; 7809 7810function trustedTypesPolicy() { 7811 if (!trustedTypesPolicyResolved) { 7812 resolvedTrustedTypesPolicy = createTrustedTypesPolicy(); 7813 trustedTypesPolicyResolved = true; 7814 } 7815 7816 return resolvedTrustedTypesPolicy 7817} 7818 7819function createTrustedTypesPolicy() { 7820 // Feature-detected below, so browsers without Trusted Types simply get no 7821 // policy â the same path as a CSP that doesn't allowlist ours. 7822 // eslint-disable-next-line compat/compat 7823 const trustedTypes = window.trustedTypes; 7824 7825 if (typeof trustedTypes?.createPolicy !== "function") return null 7826 7827 try { 7828 return trustedTypes.createPolicy("lexxy", { createHTML: (html) => html, createScriptURL: (url) => url }) 7829 } catch { 7830 // Warned rather than swallowed, matching what DOMPurify does when its own 7831 // policy is refused. The fallback is a silent loss of Trusted Types coverage 7832 // otherwise, and the CSP violation report alone doesn't name us. 7833 console.warn("TrustedTypes policy lexxy could not be created."); 7834 return null 7835 } 7836} 7837 7838const DOMPurify =
vendor: 1,234 bytes, lines 7838-7866
7838purify(window); 7839 7840// alt is inert on every element it can appear on, so it sits in the blanket 7841// list. srcset is deliberately absent â it carries URLs, so it belongs to a 7842// consumer that declares it. 7843const ALLOWED_HTML_ATTRIBUTES = [ "alt", "class", "contenteditable", "href", "src", "style", "title" ]; 7844 7845// width/height are scoped to img rather than allowlisted globally, because 7846// ALLOWED_ATTR is not per-tag: putting them there would also permit 7847// `<table width="100000">` and `<td height="500">` in attachment content, which 7848// is layout the editor previously stripped. An image needs them to hold its 7849// place while it loads; nothing else here does. 7850const DEFAULT_TAG_ATTRIBUTES = { img: [ "width", "height" ] }; 7851 7852const ALLOWED_STYLE_PROPERTIES = [ "color", "background-color" ]; 7853 7854function styleFilterHook(_currentNode, hookEvent) { 7855 if (hookEvent.attrName === "style" && hookEvent.attrValue) { 7856 const styles = { ...oe$5(hookEvent.attrValue) }; 7857 const sanitizedStyles = { }; 7858 7859 for (const property in styles) { 7860 if (ALLOWED_STYLE_PROPERTIES.includes(property)) { 7861 sanitizedStyles[property] = styles[property]; 7862 } 7863 } 7864 7865 if (Object.keys(sanitizedStyles).length) { 7866 hookEvent.attrValue = F$6
vendor: 9,476 bytes, lines 7866-8099
7866(sanitizedStyles); 7867 } else { 7868 hookEvent.keepAttr = false; 7869 } 7870 } 7871} 7872 7873DOMPurify.addHook("uponSanitizeAttribute", styleFilterHook); 7874DOMPurify.addHook("uponSanitizeAttribute", attachmentUriFilterHook); 7875 7876const FORBIDDEN_STIMULUS_ATTRIBUTES = [ "data-controller", "data-action" ]; 7877 7878// Stimulus behavior attributes must never survive sanitization, whatever an 7879// extension's allowedElements declares. On dompurify 3.4.13 FORBID_ATTR already 7880// carries that on its own: _isValidAttribute opens with it, ahead of the 7881// functional ADD_ATTR Lexxy builds from the public allowedElements API. So this 7882// hook is defence in depth rather than the barrier, and it is kept because it 7883// holds without reference to the config â the prohibition is a class-level one, 7884// and a FORBID_ATTR entry lives or dies with whatever rebuilds the config. 7885function stimulusAttributeFilterHook(_currentNode, hookEvent) { 7886 if (FORBIDDEN_STIMULUS_ATTRIBUTES.includes(hookEvent.attrName)) { 7887 hookEvent.keepAttr = false; 7888 } 7889} 7890 7891DOMPurify.addHook("uponSanitizeAttribute", stimulusAttributeFilterHook); 7892 7893DOMPurify.addHook("uponSanitizeElement", (node, data) => { 7894 if (data.tagName === "strong" || data.tagName === "em") { 7895 node.removeAttribute("class"); 7896 } 7897}); 7898 7899// Called with no allowedElements for a sanitizer that has no allowlist to apply, 7900// which is not the same thing as an empty one â see EditorSanitizer's fallback. 7901function buildConfig(allowedElements = null) { 7902 const config = { 7903 ADD_URI_SAFE_ATTR: [ "caption", "filename", ...URI_BEARING_ATTACHMENT_ATTRIBUTES ], 7904 SAFE_FOR_XML: false, // So that it does not strip attributes that contains serialized HTML (like content) 7905 // Stimulus behavior attributes must never survive sanitization: they let stored content 7906 // wire up arbitrary controllers/actions in the viewer's session. FORBID_ATTR wins over 7907 // ALLOWED_ATTR/ADD_ATTR/ALLOW_DATA_ATTR in DOMPurify, so this holds even though other 7908 // data-* attributes (data-language, data-trix-*, etc.) are otherwise allowed through. 7909 FORBID_ATTR: [ "data-controller", "data-action" ] 7910 }; 7911 7912 // Left out rather than emptied when there is no allowlist, so DOMPurify's own 7913 // default tag and attribute policy stands. `ALLOWED_TAGS: []` would not be a 7914 // default, it would be a refusal: it strips every tag. An editor that declares 7915 // an empty allowlist still gets that refusal, because it asked for it. 7916 // 7917 // uriSafeSchemes widens the scheme validation rather than exempting an attribute 7918 // from it: ALLOWED_URI_REGEXP is set only when an editor declares custom schemes, 7919 // so a value like a mention's `gid://â¦` passes while javascript:/data: stay 7920 // refused on every attribute â including href and object[data]. Nothing is taken 7921 // out of URI checking, so there is no attribute to guard against exempting. 7922 if (allowedElements) { 7923 const { uriSafeSchemes, ...tagPolicy } = allowlistFor(allowedElements); 7924 if (uriSafeSchemes.length) config.ALLOWED_URI_REGEXP = allowedUriRegexp(uriSafeSchemes); 7925 Object.assign(config, tagPolicy); 7926 } 7927 7928 // Always assigned, including when we have no policy â `null` is what 7929 // trustedTypesPolicy() returns then, and `TRUSTED_TYPES_POLICY: null` is 7930 // DOMPurify's documented per-call opt-out: sign nothing, create nothing. 7931 // 7932 // Leaving the key out is a different thing entirely, and the wrong one. With no 7933 // key DOMPurify falls through to _getDefaultTrustedTypesPolicy() and asks the 7934 // browser for `dompurify` â the very name this exists to stop competing for â so 7935 // an omitted key would disarm the sanitizer of a host shipping 7936 // `trusted-types dompurify` on the one path where we couldn't get our own. 7937 // Present-and-`undefined` lands in that same fallthrough, so it is not a 7938 // substitute for `null` either. 7939 config.TRUSTED_TYPES_POLICY = trustedTypesPolicy(); 7940 7941 return config 7942} 7943 7944function allowlistFor(allowedElements) { 7945 // Null prototype, so a declared tag can never read through to an 7946 // Object.prototype key: `tagAttributes["constructor"]` would answer with a 7947 // function, and ADD_ATTR would call .includes on it. 7948 const tagAttributes = Object.create(null); 7949 const uriSafeSchemes = []; 7950 7951 // Lowercased, because DOMPurify lowercases ALLOWED_TAGS and calls ADD_ATTR 7952 // with the lowercased tag and attribute names. Keeping the caller's casing 7953 // makes allowedElements silently partial: `[ "IMG" ]` allows the element but 7954 // drops the width/height below, and `[ { tag: "img", attributes: [ "GID" ] } ]` 7955 // drops the attribute it declares. 7956 for (const element of allowedElements) { 7957 const tag = String(element.tag ?? element).toLowerCase(); 7958 const attributes = (element.attributes ?? []).map(attribute => attribute.toLowerCase()); 7959 7960 tagAttributes[tag] ||= []; 7961 tagAttributes[tag].push(...attributes); 7962 7963 // A custom scheme a caller declares is folded into the editor's URI-scheme 7964 // allowlist (ALLOWED_URI_REGEXP in buildConfig), so a value like a mention's 7965 // `gid="gid://â¦"` â which DOMPurify otherwise drops as an unknown scheme, even 7966 // once the `gid` name is allowed â passes validation. It widens the recognised 7967 // schemes, it does not exempt an attribute: javascript:/data: stay refused 7968 // everywhere, so there is no navigational attribute to guard. Declared per 7969 // element for locality, but a scheme is editor-wide once allowed. 7970 uriSafeSchemes.push(...(element.uriSafeSchemes ?? [])); 7971 } 7972 7973 // Only for tags the caller already permits â this widens what an allowed 7974 // element may carry, never which elements are allowed. 7975 for (const [ tag, attributes ] of Object.entries(DEFAULT_TAG_ATTRIBUTES)) { 7976 if (tagAttributes[tag]) tagAttributes[tag].push(...attributes); 7977 } 7978 7979 return { 7980 ALLOWED_TAGS: Object.keys(tagAttributes), 7981 ALLOWED_ATTR: ALLOWED_HTML_ATTRIBUTES, 7982 ADD_ATTR: (attribute, tag) => tagAttributes[tag]?.includes(attribute), 7983 uriSafeSchemes 7984 } 7985} 7986 7987function getNonce() { 7988 const element = document.head.querySelector("meta[name=csp-nonce]"); 7989 return element?.content 7990} 7991 7992// Register an event listener with a return function to deregister the listener. Both the element and 7993// the listener are WeakRefs so neither is pinned in memory by the deregister function. 7994function registerEventListener(element, type, listener, options) { 7995 element.addEventListener(type, listener, options); 7996 const elementRef = new WeakRef(element); 7997 const listenerRef = new WeakRef(listener); 7998 7999 return function deregisterListener() { 8000 const listener = listenerRef.deref(); 8001 if (listener) elementRef.deref()?.removeEventListener(type, listener, options); 8002 } 8003} 8004 8005class ListenerBin { 8006 #listeners = [] 8007 8008 track(...listeners) { 8009 this.#listeners.push(...listeners); 8010 } 8011 8012 dispose() { 8013 while (this.#listeners.length) { 8014 const teardown = this.#listeners.pop(); 8015 teardown(); 8016 } 8017 } 8018} 8019 8020function handlingDefault(handler) { 8021 return event => { 8022 const handled = handler(event); 8023 if (handled) event.preventDefault(); 8024 return handled 8025 } 8026} 8027 8028function createElement(name, properties, content = "") { 8029 const element = document.createElement(name); 8030 for (const [ key, value ] of Object.entries(properties || {})) { 8031 if (key === "dataset") { 8032 Object.entries(value).forEach(([ key, value ]) => (element.dataset[key] = value)); 8033 } else if (key in element) { 8034 element[key] = value; 8035 } else if (value !== null && value !== undefined) { 8036 element.setAttribute(key, value); 8037 } 8038 } 8039 if (content) { 8040 element.innerHTML = content; 8041 } 8042 return element 8043} 8044 8045function parseHtml(html) { 8046 const parser = new DOMParser(); 8047 return parser.parseFromString(html, "text/html") 8048} 8049 8050function createAttachmentFigure(contentType, isPreviewable, fileName) { 8051 const extension = fileName ? fileName.split(".").pop().toLowerCase() : "unknown"; 8052 return createElement("figure", { 8053 className: `attachment attachment--${isPreviewable ? "preview" : "file"} attachment--${extension}`, 8054 "data-content-type": contentType 8055 }) 8056} 8057 8058function isPreviewableImage(contentType) { 8059 return contentType.startsWith("image/") && !contentType.includes("svg") 8060} 8061 8062function dispatch(element, eventName, detail = null, cancelable = false) { 8063 return element.dispatchEvent(new CustomEvent(eventName, { bubbles: true, detail, cancelable })) 8064} 8065 8066function addBlockSpacing(doc) { 8067 const selector = "body > :not(h1, h2, h3, h4, h5, h6) + *, blockquote > :not(h1, h2, h3, h4, h5, h6) + *"; 8068 for (const block of doc.querySelectorAll(selector)) { 8069 const spacer = doc.createElement("p"); 8070 spacer.appendChild(doc.createElement("br")); 8071 block.before(spacer); 8072 } 8073} 8074 8075function generateDomId(prefix) { 8076 const randomPart = Math.random().toString(36).slice(2, 10); 8077 return `${prefix}-${randomPart}` 8078} 8079 8080function extractPlainTextFromHtml(innerHtml = "") { 8081 return parseHtml(innerHtml).body.textContent.trim() 8082} 8083 8084function isActiveAndVisible(element) { 8085 return element && !element.disabled && checkVisibility(element) 8086} 8087 8088// no `checkVisibility` in Safari < 17.4 8089// https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility#browser_compatibility 8090function checkVisibility(element, options) { 8091 if (element.checkVisibility) { 8092 return element.checkVisibility(options) 8093 } else { 8094 // Will not work for body or a fixed position element child of the body 8095 // which is OK since that doesn't apply in the toolbar where this is used 8096 return Boolean(element.offsetParent) 8097 } 8098} 8099
vendor: 1,874 bytes, lines 8100-8178
8100function handleRollingTabIndex(elements, event) { 8101 const previousActiveElement = document.activeElement; 8102 8103 if (elements.includes(previousActiveElement)) { 8104 const finder = new NextElementFinder(elements, event.key); 8105 8106 if (finder.selectNext(previousActiveElement)) { 8107 event.preventDefault(); 8108 } 8109 } 8110} 8111 8112class NextElementFinder { 8113 constructor(elements, key) { 8114 this.elements = elements; 8115 this.key = key; 8116 } 8117 8118 selectNext(fromElement) { 8119 const nextElement = this.#findNextElement(fromElement); 8120 8121 if (nextElement) { 8122 const inactiveElements = this.elements.filter(element => element !== nextElement); 8123 this.#unsetTabIndex(inactiveElements); 8124 this.#focusWithActiveTabIndex(nextElement); 8125 return true 8126 } 8127 8128 return false 8129 } 8130 8131 #findNextElement(fromElement) { 8132 switch (this.key) { 8133 case "ArrowRight": 8134 case "ArrowDown": 8135 return this.#findNextSibling(fromElement) 8136 8137 case "ArrowLeft": 8138 case "ArrowUp": 8139 return this.#findPreviousSibling(fromElement) 8140 8141 case "Home": 8142 return this.#findFirst() 8143 8144 case "End": 8145 return this.#findLast() 8146 } 8147 } 8148 8149 #findFirst(elements = this.elements) { 8150 return elements.find(isActiveAndVisible) 8151 } 8152 8153 #findLast(elements = this.elements) { 8154 return elements.findLast(isActiveAndVisible) 8155 } 8156 8157 #findNextSibling(element) { 8158 const afterElements = this.elements.slice(this.#indexOf(element) + 1); 8159 return this.#findFirst(afterElements) 8160 } 8161 8162 #findPreviousSibling(element) { 8163 const beforeElements = this.elements.slice(0, this.#indexOf(element)); 8164 return this.#findLast(beforeElements) 8165 } 8166 8167 #indexOf(element) { 8168 return this.elements.indexOf(element) 8169 } 8170 8171 #focusWithActiveTabIndex(element) { 8172 if (isActiveAndVisible(element)) { 8173 element.tabIndex = 0; 8174 element.focus(); 8175 } 8176 } 8177 8178 #unsetTabIndex(elements) {
8179 elements.forEach(element => element.tabIndex = -1); 8180 } 8181} 8182 8183var ToolbarIcons = { 8184 "bold": 8185 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8186 <path fill-rule="evenodd" clip-rule="evenodd" d="M9.05273 1.88232C10.6866 1.88237 12.0033 2.20353 12.9529 2.89673L13.1272 3.0293C13.974 3.70864 14.4008 4.63245 14.4009 5.76562C14.4008 6.49354 14.2316 7.15281 13.8845 7.73145C13.6683 8.09188 13.3997 8.40162 13.0818 8.66016C13.5902 8.92606 14.0196 9.28599 14.3635 9.74121C14.8586 10.3834 15.0945 11.1743 15.0945 12.0879C15.0944 13.3698 14.5922 14.3931 13.5879 15.1106L13.5857 15.1128C12.5967 15.805 11.196 16.125 9.43799 16.125H3.10547V1.88232L9.05273 1.88232ZM6.36108 13.4084H9.28418C10.224 13.4084 10.8634 13.2491 11.2581 12.9851C11.6259 12.7389 11.8198 12.3768 11.8198 11.8367C11.8197 11.2968 11.6259 10.9351 11.2581 10.689C10.8634 10.425 10.2241 10.2649 9.28418 10.2649H6.36108V13.4084ZM6.36108 7.56812H8.78247C9.5163 7.56809 10.0547 7.45371 10.429 7.25757L10.5791 7.16895C10.9438 6.92178 11.1255 6.57934 11.1255 6.09302C11.1254 5.59017 10.9414 5.25227 10.5835 5.02002L10.5784 5.01636L10.5732 5.01343C10.1994 4.75387 9.61878 4.59818 8.78247 4.59814H6.36108V7.56812Z"/> 8187 </svg>`, 8188 8189 "italic": 8190 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8191 <path d="M14.1379 3.91187L14.1086 4.06421H11.4668L9.49805 13.9431H12.0981L11.7473 15.7852L11.7188 15.9375H4.16675L4.51758 14.0955L4.54614 13.9431H7.18799L9.17505 4.06421H6.55664L6.90747 2.22217L6.93677 2.06982H14.4888L14.1379 3.91187Z"/> 8192 </svg>`, 8193 8194 "strikethrough": 8195 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8196 <path d="M14.3723 11.8015C14.3771 11.8858 14.3811 11.9756 14.3811 12.0681C14.3811 12.811 14.1777 13.4959 13.7725 14.1174L13.7717 14.1189C13.3624 14.7329 12.7463 15.2162 11.9377 15.5742L11.9348 15.5757C11.1214 15.9223 10.1306 16.092 8.96997 16.092C7.9356 16.092 6.93308 15.9348 5.96338 15.6204L5.96045 15.6189C5.00593 15.292 4.24112 14.8699 3.67676 14.3459L3.57568 14.2522L3.63501 14.1277L4.45605 12.397L4.64282 12.5654C5.13492 13.0083 5.76733 13.3759 6.54492 13.6648C7.33475 13.9406 8.14322 14.0786 8.96997 14.0786C10.0731 14.0786 10.8638 13.8932 11.3708 13.5513C11.8757 13.1982 12.1172 12.7464 12.1172 12.1838C12.1172 12.0662 12.1049 11.9556 12.0828 11.8513L12.0344 11.625H14.3621L14.3723 11.8015Z"/> 8197 <path d="M9.2981 1.91602C10.111 1.91604 10.9109 2.02122 11.6975 2.23096C12.4855 2.44111 13.1683 2.74431 13.7417 3.14429L13.8655 3.23071L13.8083 3.36987L13.1726 4.91235L13.0869 5.1189L12.8987 4.99878C12.3487 4.64881 11.761 4.38633 11.1365 4.21143L11.1328 4.20996C10.585 4.04564 10.0484 3.95419 9.52295 3.93384L9.2981 3.92944C8.22329 3.92944 7.44693 4.12611 6.94043 4.49121C6.44619 4.85665 6.20874 5.31616 6.20874 5.88135L6.21533 6.03296C6.24495 6.37662 6.37751 6.65526 6.61011 6.87964L6.72144 6.97632C6.98746 7.19529 7.30625 7.37584 7.68018 7.51538L8.05151 7.63184C8.45325 7.75061 8.94669 7.87679 9.53247 8.01123L9.53467 8.01196C10.1213 8.15305 10.6426 8.29569 11.0991 8.4375H15C15.5178 8.4375 15.9375 8.85723 15.9375 9.375C15.9375 9.89277 15.5178 10.3125 15 10.3125H3C2.48223 10.3125 2.0625 9.89277 2.0625 9.375C2.0625 8.85723 2.48223 8.4375 3 8.4375H4.93726C4.83783 8.34526 4.74036 8.24896 4.64795 8.146L4.64502 8.14233C4.1721 7.58596 3.94482 6.85113 3.94482 5.95825C3.94483 5.20441 4.14059 4.51965 4.53369 3.90967L4.53516 3.90747C4.94397 3.29427 5.55262 2.81114 6.34863 2.45288C7.15081 2.0919 8.13683 1.91602 9.2981 1.91602Z"/> 8198 </svg>`, 8199 8200 "underline": 8201 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8202 <path d="M14 14C14.5523 14 15 14.4477 15 15C15 15.5523 14.5523 16 14 16H4C3.44772 16 3 15.5523 3 15C3 14.4477 3.44772 14 4 14H14Z"/> 8203 <path d="M12.625 1.59375C13.25 1.59375 13.625 1.97656 13.625 2.64062V9.02344C13.625 11.4844 11.8516 13.1875 8.99219 13.1875C6.14062 13.1875 4.35938 11.4844 4.35938 9.02344V2.64062C4.35938 1.97656 4.74219 1.59375 5.36719 1.59375C6 1.59375 6.375 1.97656 6.375 2.64062V8.84375C6.375 10.3828 7.32031 11.4297 8.99219 11.4297C10.6641 11.4297 11.6172 10.3828 11.6172 8.84375V2.64062C11.6172 1.97656 11.9922 1.59375 12.625 1.59375Z"/> 8204 </svg>`, 8205 8206 "heading": 8207 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8208 <path d="M11.5 2C12.0523 2 12.5 2.44772 12.5 3V3.5C12.5 4.05228 12.0523 4.5 11.5 4.5H8V15C8 15.5523 7.55228 16 7 16H6.5C5.94772 16 5.5 15.5523 5.5 15V4.5H2C1.44772 4.5 1 4.05228 1 3.5V3C1 2.44772 1.44772 2 2 2H11.5ZM16 7C16.5523 7 17 7.44772 17 8V8.5C17 9.05228 16.5523 9.5 16 9.5H15V15C15 15.5523 14.5523 16 14 16H13.5C12.9477 16 12.5 15.5523 12.5 15V9.5H11.5C10.9477 9.5 10.5 9.05228 10.5 8.5V8C10.5 7.44772 10.9477 7 11.5 7H16Z"/> 8209 </svg>`, 8210 8211 "h1": 8212 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8213 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM13.8418 4.125H14.8271C15.543 4.125 16.0449 4.56934 16.0449 5.23828V12.7207C16.0449 13.4111 15.6348 13.8486 14.9854 13.8486C14.336 13.8486 13.9395 13.418 13.9395 12.7207V6.11133H13.8887L12.9541 6.74219C12.7354 6.88574 12.5303 6.95312 12.3047 6.95312C11.7646 6.95312 11.3955 6.58398 11.3955 6.06445C11.3955 5.69531 11.5801 5.42578 11.9766 5.15625L13.4023 4.32031C13.5459 4.23633 13.6826 4.17578 13.8418 4.125Z"/> 8214 </svg>`, 8215 8216 "h2": 8217 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8218 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM13.6445 4.19824C15.5244 4.19824 16.8984 5.34668 16.8984 6.91211C16.8984 7.8759 16.4335 8.7237 15.292 9.84473L13.3438 11.8135V11.9092H16.1875C16.8232 11.9092 17.2197 12.251 17.2197 12.8115C17.2196 13.3651 16.83 13.7002 16.187
82185 13.7002H11.5117C10.8487 13.7002 10.4112 13.3241 10.4111 12.75C10.4111 12.3399 10.6368 11.9843 11.3203 11.3145L13.6855 8.88086C14.4169 8.13583 14.7245 7.64349 14.7246 7.12402C14.7246 6.4541 14.2393 6.00293 13.5215 6.00293C12.9404 6.00293 12.5166 6.29688 12.2158 6.90527C11.9151 7.37002 11.6552 7.54785 11.2588 7.54785C10.7188 7.54785 10.3429 7.17861 10.3428 6.65918C10.3428 5.3877 11.7783 4.19824 13.6445 4.19824Z"/> 8219 </svg>`, 8220 8221 "h3": 8222 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8223 <path d="M13.5967 4.19824C15.5928 4.19824 16.9873 5.23047 16.9873 6.7002C16.9872 7.705 16.2421 8.60059 15.2988 8.7168V8.86719C16.4199 8.94923 17.2607 9.89942 17.2607 11.0889C17.2606 12.7362 15.7362 13.9053 13.583 13.9053C11.6827 13.9053 10.1925 12.873 10.1924 11.7041C10.1924 11.1846 10.5547 10.8154 11.0537 10.8154C11.3818 10.8154 11.6553 10.9727 11.9629 11.3555C12.3799 11.9159 12.92 12.2031 13.583 12.2031C14.4853 12.2031 15.0731 11.7313 15.0732 11C15.0732 10.2754 14.4785 9.7832 13.5898 9.7832H13.0361C12.5645 9.7832 12.2159 9.4208 12.2158 8.92188C12.2158 8.44336 12.5576 8.07422 13.0361 8.07422H13.5693C14.3075 8.07422 14.8544 7.60928 14.8545 6.97363C14.8545 6.33789 14.3213 5.90039 13.5557 5.90039C12.9678 5.90039 12.5029 6.16016 12.0859 6.71387C11.8399 7.03508 11.5527 7.17871 11.1973 7.17871C10.671 7.17871 10.295 6.82314 10.2949 6.31738C10.2949 5.18945 11.751 4.19824 13.5967 4.19824ZM8.0332 4.30078C8.75781 4.30078 9.16797 4.74512 9.16797 5.51758V12.5518C9.1679 13.3241 8.75776 13.7686 8.0332 13.7686C7.30865 13.7686 6.90534 13.3309 6.90527 12.5518V9.87207H3.48047V12.5518C3.4804 13.3241 3.07026 13.7686 2.3457 13.7686C1.62115 13.7686 1.21784 13.3309 1.21777 12.5518V5.51758C1.21777 4.73828 1.62109 4.30078 2.3457 4.30078C3.07031 4.30078 3.48047 4.74512 3.48047 5.51758V8.07422H6.90527V5.51758C6.90527 4.73828 7.30859 4.30078 8.0332 4.30078Z"/> 8224 </svg>`, 8225 8226 "h4": 8227 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8228 <path d="M14.6357 4.22559C15.7432 4.22559 16.4336 4.80664 16.4336 5.73633V10.3164H16.7275C17.2881 10.3164 17.6436 10.6787 17.6436 11.2256C17.6435 11.7655 17.3017 12.1006 16.7275 12.1006H16.4336V12.6611C16.4335 13.3515 16.0234 13.7891 15.374 13.7891C14.7247 13.7891 14.3282 13.3583 14.3281 12.6611V12.1006H11.04C10.2335 12.1006 9.76863 11.6766 9.76855 10.918C9.76855 10.5762 9.85064 10.3026 10.1104 9.74219C10.7666 8.42289 11.5733 7.0146 12.5713 5.54492C13.2549 4.56738 13.7812 4.22559 14.6357 4.22559ZM7.88965 4.30078C8.61426 4.30078 9.02441 4.74512 9.02441 5.51758V12.5518C9.02435 13.3241 8.6142 13.7686 7.88965 13.7686C7.1651 13.7686 6.76178 13.3309 6.76172 12.5518V9.87207H3.33691V12.5518C3.33685 13.3241 2.9267 13.7686 2.20215 13.7686C1.4776 13.7686 1.07428 13.3309 1.07422 12.5518V5.51758C1.07422 4.73828 1.47754 4.30078 2.20215 4.30078C2.92676 4.30078 3.33691 4.74512 3.33691 5.51758V8.07422H6.76172V5.51758C6.76172 4.73828 7.16504 4.30078 7.88965 4.30078ZM14.2188 6.07812C13.6035 7.02841 12.2158 9.48929 11.7988 10.2686V10.3164H14.3281V6.07812H14.2188Z"/> 8229 </svg>`, 8230 8231 "h5": 8232 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8233 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM16.1191 4.30078C16.6934 4.30078 17.0762 4.63672 17.0762 5.16602C17.0762 5.69531 16.6934 6.03125 16.1191 6.03125H13.3457L12.9219 8.25586H13.0176C13.248 8.03711 13.6855 7.84375 14.2871 7.84375C15.9277 7.84375 17.1445 9.07422 17.1445 10.7832C17.1445 12.5605 15.8184 13.9053 13.7695 13.9053C11.9512 13.9053 10.6934 12.9277 10.5566 11.7178C10.5566 11.2021 10.9121 10.8193 11.4277 10.8193C11.8379 10.8193 12.1328 11.0244 12.3516 11.4893C12.625 12.0361 13.1133 12.2549 13.7285 12.2549C14.5488 12.2549 15.1367 11.6533 15.1367 10.7695C15.1367 9.92188 14.5625 9.31348 13.7559 9.31348C13.1953 9.31348 12.7578 9.56055 12.4629 10.0254C12.2168 10.3887 11.9355 10.5527 11.5527 10.5527C10.9648 10.5527 10.5684 10.1699 10.5684 9.55469C10.5684 9.42773 10.582 9.30762 10.6094 9.17383L11.2383 5.55273C11.3516 4.88379 11.7207 4.30078 12.6797 4.30078H16.1191Z"/> 8234 </svg>`, 8235 8236 "h6": 8237 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8238 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM13.6719 13.9258C15.5518 13.9258 17.1445 12.37306 17.1445 10.35451V10.05763C17.1445 8.10744 16.6016 6.59574 15.5928 5.58694C14.8613 4.85544 13.8975 4.42384 12.7285 4.25294C12.4199 4.21194 12.1592 4.19824 11.8643 4.19824C11.2627 4.19824 10.8389 4.59474 10.8389 5.14164C10.8389 5.65724 11.2354 6.02054 11.7783 6.04784C12.1758 6.06834 12.4844 6.10944 12.7656 6.19144C13.5176 6.42384 14.0742 6.95314 14.3965 7.75974L14.4922 8.00584H14.3828C14.0605 7.56834 13.4863 7.25974 12.6523 7.25974C11.1406 7.25974 10.0674 8.42384 10.0674 10.
823802345V10.27736C10.0674 12.2549 11.4668 13.9258 13.6719 13.9258ZM13.5215 12.24123C12.6797 12.24123 12.0918 11.48244 12.0918 10.4131V10.1592C12.0918 9.26174 12.6523 8.71291 13.5352 8.71291C14.3965 8.71291 14.9844 9.27638 14.9844 10.1592V10.4131C14.9844 11.48244 14.3828 12.24123 13.5215 12.24123Z"/> 8239 </svg>`, 8240 8241 "paragraph": 8242 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8243 <path d="M9 12C9.55228 12 10 12.4477 10 13C10 13.5523 9.55228 14 9 14H3C2.44772 14 2 13.5523 2 13C2 12.4477 2.44772 12 3 12H9ZM15 8C15.5523 8 16 8.44772 16 9C16 9.55228 15.5523 10 15 10H3C2.44772 10 2 9.55228 2 9C2 8.44772 2.44772 8 3 8H15ZM15 4C15.5523 4 16 4.44772 16 5C16 5.55228 15.5523 6 15 6H3C2.44772 6 2 5.55228 2 5C2 4.44772 2.44772 4 3 4H15Z"/> 8244 </svg>`, 8245 8246 "clearFormatting": 8247 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8248 <path d="M10.0607 2.07533C10.8417 1.29432 12.1078 1.2943 12.8888 2.07533L16.424 5.61049C17.205 6.39154 17.205 7.65854 16.424 8.43959L9.44937 15.4142C9.07435 15.7891 8.5656 16.0001 8.03531 16.0001H5.0148C4.55074 16.0001 4.10309 15.8385 3.74722 15.547L3.60074 15.4142L1.57534 13.3888C0.79431 12.6078 0.794336 11.3417 1.57534 10.5607L10.0607 2.07533ZM2.98941 11.9747L5.0148 14.0001H8.03531L9.71792 12.3165L6.18179 8.78139L2.98941 11.9747Z"/> 8249 </svg>`, 8250 8251 "highlight": 8252 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8253 <path d="M16.4564 14.4272C17.1356 15.5592 16.3204 17.0002 15.0003 17.0004C13.68 17.0004 12.864 15.5593 13.5433 14.4272L15.0003 12.0004L16.4564 14.4272ZM5.1214 1.70746C5.51192 1.31693 6.14494 1.31693 6.53546 1.70746L9.7171 4.8891L13.2532 8.42426C14.2295 9.40056 14.2295 10.9841 13.2532 11.9604L9.7171 15.4955C8.74078 16.4718 7.15822 16.4718 6.18195 15.4955L2.64679 11.9604C1.67048 10.9841 1.67048 9.40057 2.64679 8.42426L6.18195 4.8891C6.30299 4.76805 6.43323 4.66177 6.57062 4.57074L5.1214 3.12152C4.73091 2.73104 4.73099 2.09799 5.1214 1.70746ZM8.30304 6.30316C8.10776 6.10815 7.79119 6.10799 7.59601 6.30316L4.06085 9.83929L3.9964 9.91742C3.88661 10.0838 3.88645 10.3019 3.9964 10.4682L4.02277 10.5004H11.8763C12.0312 10.3043 12.02 10.0205 11.8392 9.83929L8.30304 6.30316Z"/> 8254 </svg>`, 8255 8256 "link": 8257 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8258 <path d="M12.8885 7.23091L13.9479 6.17155C14.5337 5.58576 14.5337 4.63602 13.9479 4.05023C13.3621 3.46444 12.4124 3.46444 11.8266 4.05023L8.29235 7.58446C7.9263 7.95051 7.90312 8.52994 8.2233 8.92271L8.36141 9.07463C8.68158 9.4674 8.65841 10.0468 8.29235 10.4129C7.90183 10.8034 7.26866 10.8034 6.87814 10.4129C5.70657 9.24131 5.70657 7.34182 6.87814 6.17025L10.4124 2.63602C11.7792 1.26918 13.9953 1.26918 15.3621 2.63602C16.729 4.00285 16.729 6.21893 15.3621 7.58576L14.3028 8.64512C13.9122 9.03564 13.2791 9.03564 12.8885 8.64512C12.498 8.2546 12.498 7.62143 12.8885 7.23091Z"/> 8259 <path d="M5.11038 10.7664L4.04843 11.8284C3.46264 12.4142 3.46264 13.3639 4.04842 13.9497C4.63421 14.5355 5.58396 14.5355 6.16975 13.9497L9.70657 10.4129C10.0726 10.0468 10.0958 9.46741 9.77563 9.07464L9.63752 8.92272C9.31734 8.52995 9.34052 7.95052 9.70657 7.58446C10.0971 7.19394 10.7303 7.19394 11.1208 7.58446C12.2924 8.75604 12.2924 10.6555 11.1208 11.8271L7.58396 15.3639C6.21712 16.7308 4.00105 16.7308 2.63421 15.3639C1.26738 13.9971 1.26738 11.781 2.63421 10.4142L3.69617 9.35223C4.08669 8.96171 4.71986 8.96171 5.11038 9.35223C5.5009 9.74275 5.5009 10.3759 5.11038 10.7664Z"/> 8260 </svg>`, 8261 8262 "quote": 8263 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8264 <path d="M4.96387 4.23438C6.8769 4.23438 8.42767 5.78522 8.42773 7.69824C8.42773 8.32925 8.25769 8.92015 7.96289 9.42969L7.96387 9.43066L5.11816 14.3584C4.77659 14.95 4.02038 15.153 3.42871 14.8115C2.83701 14.4699 2.63397 13.7128 2.97559 13.1211L4.16113 11.0674C2.63532 10.7052 1.5 9.33485 1.5 7.69824C1.50006 5.78524 3.05086 4.2344 4.96387 4.23438ZM13.0361 4.23438C14.9491 4.23449 16.4999 5.7853 16.5 7.69824C16.5 8.32921 16.3299 8.92017 16.0352 9.42969L16.0361 9.43066L13.1904 14.3584C12.8488 14.9501 12.0917 15.1531 11.5 14.8115C10.9085 14.4698 10.7063 13.7127 11.0479 13.1211L12.2324 11.0674C10.7069 10.7049 9.57227 9.33461 9.57227 7.69824C9.57233 5.78522 11.1231 4.23438 13.0361 4.23438Z"/> 8265 </svg>`, 8266 8267 "code": 8268 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8269 <path d="M6.29289 3.79295C6.68342 3.40243 7.31643 3.40243 7.70696 3.79295C8.09748 4.18348 8.09748 4.81649 7.70696 5.20702L3.91399 8.99999L7.70696 12.793C8.09748 13.1835 8.09748 13.8165 7.70696 14.207C7.31643 14.597
82695 6.68342 14.5975 6.29289 14.207L1.79289 9.70702C1.40237 9.31649 1.40237 8.68348 1.79289 8.29295L6.29289 3.79295Z"/> 8270 <path d="M11.707 3.79295C11.3164 3.40243 10.6834 3.40243 10.2929 3.79295C9.90237 4.18348 9.90237 4.81649 10.2929 5.20702L14.0859 8.99999L10.2929 12.793C9.90237 13.1835 9.90237 13.8165 10.2929 14.207C10.6834 14.5975 11.3164 14.5975 11.707 14.207L16.207 9.70702C16.5975 9.31649 16.5975 8.68348 16.207 8.29295L11.707 3.79295Z"/> 8271 </svg>`, 8272 8273 "ul": 8274 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8275 <path d="M3 12.5C3.82843 12.5 4.5 13.1716 4.5 14C4.5 14.8284 3.82843 15.5 3 15.5C2.17157 15.5 1.5 14.8284 1.5 14C1.5 13.1716 2.17157 12.5 3 12.5ZM15.5 13C16.0523 13 16.5 13.4477 16.5 14C16.5 14.5523 16.0523 15 15.5 15H7C6.44772 15 6 14.5523 6 14C6 13.4477 6.44772 13 7 13H15.5ZM3 7.5C3.82843 7.5 4.5 8.17157 4.5 9C4.5 9.82843 3.82843 10.5 3 10.5C2.17157 10.5 1.5 9.82843 1.5 9C1.5 8.17157 2.17157 7.5 3 7.5ZM15.5 8C16.0523 8 16.5 8.44772 16.5 9C16.5 9.55228 16.0523 10 15.5 10H7C6.44772 10 6 9.55228 6 9C6 8.44772 6.44772 8 7 8H15.5ZM3 2.5C3.82843 2.5 4.5 3.17157 4.5 4C4.5 4.82843 3.82843 5.5 3 5.5C2.17157 5.5 1.5 4.82843 1.5 4C1.5 3.17157 2.17157 2.5 3 2.5ZM15.5 3C16.0523 3 16.5 3.44772 16.5 4C16.5 4.55228 16.0523 5 15.5 5H7C6.44772 5 6 4.55228 6 4C6 3.44772 6.44772 3 7 3H15.5Z"/> 8276 </svg>`, 8277 8278 "ol": 8279 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8280 <path d="M15.5 13C16.0523 13 16.5 13.4477 16.5 14C16.5 14.5523 16.0523 15 15.5 15H7C6.44772 15 6 14.5523 6 14C6 13.4477 6.44772 13 7 13H15.5ZM15.5 8C16.0523 8 16.5 8.44772 16.5 9C16.5 9.55228 16.0523 10 15.5 10H7C6.44772 10 6 9.55228 6 9C6 8.44772 6.44772 8 7 8H15.5ZM15.5 3C16.0523 3 16.5 3.44772 16.5 4C16.5 4.55228 16.0523 5 15.5 5H7C6.44772 5 6 4.55228 6 4C6 3.44772 6.44772 3 7 3H15.5Z"/> 8281 <path d="M2.98657 16.0967C2.68042 16.0967 2.41187 16.0465 2.18091 15.9463C1.95174 15.846 1.77002 15.7046 1.63574 15.522C1.50146 15.3376 1.42448 15.1227 1.40479 14.8774L1.4021 14.8452H2.34204L2.34741 14.8748C2.35815 14.9589 2.39038 15.035 2.44409 15.103C2.49959 15.1711 2.5721 15.2248 2.66162 15.2642C2.75293 15.3035 2.86035 15.3232 2.98389 15.3232C3.10563 15.3232 3.21037 15.3027 3.2981 15.2615C3.38761 15.2185 3.45654 15.1603 3.50488 15.0869C3.55322 15.0135 3.57739 14.9294 3.57739 14.8345V14.8291C3.57739 14.6715 3.51921 14.5516 3.40283 14.4692C3.28646 14.3869 3.12085 14.3457 2.90601 14.3457H2.48706V13.677H2.90063C3.02775 13.677 3.13607 13.6582 3.22559 13.6206C3.31689 13.583 3.38672 13.5302 3.43506 13.4622C3.48519 13.3941 3.51025 13.3153 3.51025 13.2258V13.2205C3.51025 13.1256 3.48877 13.0441 3.4458 12.9761C3.40462 12.9062 3.34375 12.8534 3.26318 12.8176C3.18441 12.78 3.08952 12.7612 2.97852 12.7612C2.86572 12.7612 2.76636 12.7809 2.68042 12.8203C2.59627 12.8579 2.52913 12.9125 2.479 12.9841C2.43066 13.054 2.40112 13.1363 2.39038 13.2312L2.3877 13.2581H1.49341L1.49609 13.2205C1.514 12.977 1.58561 12.7666 1.71094 12.5894C1.83805 12.4103 2.00903 12.2725 2.22388 12.1758C2.44051 12.0773 2.69206 12.0281 2.97852 12.0281C3.27393 12.0281 3.52995 12.0728 3.74658 12.1624C3.96322 12.2501 4.13062 12.3727 4.24878 12.5303C4.36694 12.6878 4.42603 12.8722 4.42603 13.0835V13.0889C4.42603 13.2518 4.38932 13.3941 4.31592 13.5159C4.2443 13.6358 4.14762 13.7343 4.02588 13.8113C3.90592 13.8883 3.77254 13.942 3.62573 13.9724V13.9912C3.91756 14.0199 4.14941 14.1121 4.32129 14.2678C4.49316 14.4236 4.5791 14.6295 4.5791 14.8855V14.8909C4.5791 15.1344 4.51375 15.3474 4.38306 15.53C4.25236 15.7109 4.06795 15.8505 3.82983 15.949C3.59172 16.0474 3.31063 16.0967 2.98657 16.0967Z"/> 8282 <path d="M1.54443 11V10.342L2.76099 9.20874C2.95076 9.03507 3.09757 8.89274 3.20142 8.78174C3.30705 8.66895 3.37956 8.57316 3.41895 8.49438C3.46012 8.41382 3.48071 8.33415 3.48071 8.25537V8.24463C3.48071 8.14795 3.46012 8.0638 3.41895 7.99219C3.37777 7.92057 3.31779 7.86507 3.23901 7.82568C3.16024 7.7863 3.06714 7.7666 2.95972 7.7666C2.84692 7.7666 2.74756 7.78988 2.66162 7.83643C2.57747 7.88298 2.51123 7.94743 2.46289 8.02979C2.41455 8.11035 2.39038 8.20345 2.39038 8.30908V8.33057L1.48804 8.32788V8.31177C1.48804 8.05396 1.5507 7.82837 1.67603 7.63501C1.80314 7.44165 1.97949 7.29126 2.20508 7.18384C2.43245 7.07463 2.69653 7.02002 2.99731 7.02002C3.28556 7.02002 3.53711 7.06836 3.75195 7.16504C3.96859 7.25993 4.13688 7.39331 4.25684 7.56519C4.37858 7.73706 4.43945 7.93758 4.43945 8.16675V8.18018C4.43945 8.3252 4.40902 8.46932 4.34814 8.61255C4.28727 8.75578 4.18701 8.90885 4.04736 9.07178C3.90771 9.23291 3.71883 9.41642 3.48071 9.62231L2.58374 10.4092L2.85498 9.98486V10.4092L2.58374 10.2319H4.49048V11H1.54443Z"/> 8283 <path d="M2.84155 6V3.01367H2.79053L1.85596 3.64478V2.79614L2.84155 2.12476H3.82715V6H2.84155Z"/> 8284 </svg>`, 8285 8286 "image": 8287 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8288 <path d="M14 2C15.6569 2 17 3.34315 17 5V13C17 14.6569 15.6569
828816 14 16H4C2.34315 16 1 14.6569 1 13V5C1 3.34315 2.34315 2 4 2H14ZM3.06348 13.3496C3.2053 13.7294 3.57078 14 4 14H13.5859L11 11.4141L9.70703 12.707C9.31651 13.0976 8.68349 13.0976 8.29297 12.707C7.90244 12.3165 7.90244 11.6835 8.29297 11.293L8.58594 11L7 9.41406L3.06348 13.3496ZM4 4C3.44772 4 3 4.44772 3 5V10.5859L6.29297 7.29297L6.36914 7.22461C6.76191 6.90427 7.34092 6.92686 7.70703 7.29297L10 9.58594L10.293 9.29297L10.3691 9.22461C10.7619 8.90427 11.3409 8.92686 11.707 9.29297L15 12.5859V5C15 4.44772 14.5523 4 14 4H4ZM12.5 5C13.3284 5 14 5.67157 14 6.5C14 7.32843 13.3284 8 12.5 8C11.6716 8 11 7.32843 11 6.5C11 5.67157 11.6716 5 12.5 5Z"/> 8289 </svg>`, 8290 8291 "attachment": 8292 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8293 <path d="M13 13.5V6C13 4.067 11.433 2.5 9.5 2.5C7.567 2.5 6 4.067 6 6V13.5C6 14.6046 6.89543 15.5 8 15.5H8.23047C9.20759 15.5 10 14.7076 10 13.7305V7C10 6.72386 9.77614 6.5 9.5 6.5C9.22386 6.5 9 6.72386 9 7V12.5C9 13.0523 8.55228 13.5 8 13.5C7.44772 13.5 7 13.0523 7 12.5V7C7 5.61929 8.11929 4.5 9.5 4.5C10.8807 4.5 12 5.61929 12 7V13.7305C12 15.8122 10.3122 17.5 8.23047 17.5H8C5.79086 17.5 4 15.7091 4 13.5V6C4 2.96243 6.46243 0.5 9.5 0.5C12.5376 0.5 15 2.96243 15 6V13.5C15 14.0523 14.5523 14.5 14 14.5C13.4477 14.5 13 14.0523 13 13.5Z"/> 8294 </svg>`, 8295 8296 "table": 8297 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8298 <path d="M15 1C16.1046 1 17 1.89543 17 3V15C17 16.1046 16.1046 17 15 17H3C1.89543 17 1 16.1046 1 15V3C1 1.89543 1.89543 1 3 1H15ZM3 15H8V10H3V15ZM10 10V15H15V10H10ZM10 8H15V3H10V8ZM3 8H8V3H3V8Z"/> 8299 </svg>`, 8300 8301 "hr": 8302 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8303 <path d="M12.75 12C13.1642 12 13.5 12.3358 13.5 12.75V14.25C13.5 14.6642 13.1642 15 12.75 15H5.25C4.83579 15 4.5 14.6642 4.5 14.25V12.75C4.5 12.3358 4.83579 12 5.25 12H12.75ZM15.4863 8C16.0461 8 16.5 8.44771 16.5 9C16.5 9.55229 16.0461 10 15.4863 10H2.51367C1.95392 10 1.5 9.55229 1.5 9C1.5 8.44771 1.95392 8 2.51367 8H15.4863ZM12.75 3C13.1642 3 13.5 3.33579 13.5 3.75V5.25C13.5 5.66421 13.1642 6 12.75 6H5.25C4.83579 6 4.5 5.66421 4.5 5.25V3.75C4.5 3.33579 4.83579 3 5.25 3H12.75Z"/> 8304 </svg>`, 8305 8306 "undo": 8307 `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> 8308 <path d="M8.36612 5.36612C8.85427 4.87796 9.64554 4.87796 10.1337 5.36612C10.6218 5.85428 10.6218 6.64557 10.1337 7.13369L7.26748 9.9999H15.2499C18.1494 9.99996 20.4999 12.3504 20.4999 15.2499V19.2499C20.4999 19.9402 19.9402 20.4999 19.2499 20.4999C18.5596 20.4999 18 19.9402 17.9999 19.2499V15.2499C17.9999 13.7312 16.7686 12.5 15.2499 12.4999H7.26748L10.1337 15.3661C10.6218 15.8543 10.6218 16.6456 10.1337 17.1337C9.64557 17.6218 8.85428 17.6218 8.36612 17.1337L3.36612 12.1337C2.87796 11.6455 2.87796 10.8543 3.36612 10.3661L8.36612 5.36612Z"/> 8309 </svg>`, 8310 8311 "redo": 8312 `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> 8313 <path d="M15.6338 5.1163C15.1456 4.62814 14.3543 4.62814 13.8662 5.1163C13.3781 5.60446 13.3781 6.39575 13.8662 6.88388L16.7324 9.75009H8.74997C5.85052 9.75014 3.49997 12.1006 3.49997 15.0001V19.0001C3.50002 19.6904 4.05969 20.25 4.74997 20.2501C5.4403 20.2501 5.99992 19.6904 5.99997 19.0001V15.0001C5.99997 13.4813 7.23123 12.2501 8.74997 12.2501H16.7324L13.8662 15.1163C13.3781 15.6045 13.3781 16.3958 13.8662 16.8839C14.3543 17.372 15.1456 17.3719 15.6338 16.8839L20.6338 11.8839C21.1219 11.3957 21.1219 10.6045 20.6338 10.1163L15.6338 5.1163Z" /> 8314 </svg>`, 8315 8316 "overflow": 8317 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 8318 <path d="M3 6.75C4.24264 6.75 5.25 7.75736 5.25 9C5.25 10.2426 4.24264 11.25 3 11.25C1.75736 11.25 0.75 10.2426 0.75 9C0.75 7.75736 1.75736 6.75 3 6.75ZM9 6.75C10.2426 6.75 11.25 7.75736 11.25 9C11.25 10.2426 10.2426 11.25 9 11.25C7.75736 11.25 6.75 10.2426 6.75 9C6.75 7.75736 7.75736 6.75 9 6.75ZM15 6.75C16.2426 6.75 17.25 7.75736 17.25 9C17.25 10.2426 16.2426 11.25 15 11.25C13.7574 11.25 12.75 10.2426 12.75 9C12.75 7.75736 13.7574 6.75 15 6.75Z"/> 8319 </svg>` 8320}; 8321 8322class LexicalToolbarElement extends HTMLElement { 8323 static observedAttributes = [ "connected" ] 8324 #listeners = new ListenerBin() 8325 #refreshToolbarAF = null 8326 8327 constructor() { 8328 super(); 8329 this.internals = this.attachInternals(); 8330 this.internals.role = "toolbar"; 8331 8332 this.#createEditorPromise(); 8333 } 8334 8335 connectedCallback() { 8336 this.requestOverflowRefresh(); 8337 this.setAttribute("role", "toolbar"); 8338 this.#installResizeObserver(); 8339 } 8340 8341 disconnectedCallback() { 8342 this.dispose(); 8343 } 8344 8345 dispose() { 8346 this.#listeners.dispose(); 8347 8348 cancelAnimationFrame(this.#refreshToolbarAF); 8349 8350 this.editorElement = null; 8351 this.editor = null; 8352 this.selection = null; 8353 this.#refreshToolbarAF = null; 8354 8355 this.#createEditorPromise(); 8356 } 8357 8358 attributeChangedCallback(name, oldValue, newValue) { 8359 if (name === "connected" && this.isConnected && oldValue != null && oldValue !== newValue) { 8360 requestAnimationFrame(() => this.#reconnect()); 8361 } 8362 } 8363 8364 configure(config) { 8365 if (typeof config === "object" && config !== null) { 8366 for (const [ button, value ] of Object.entries(config)) { 8367 this.setAttribute(`data-${button}`, value); 8368 } 8369 } 8370 } 8371 8372 setEditor(editorElement) { 8373 this.editorElement = editorElement; 8374 this.editor = editorElement.editor; 8375 this.selection = editorElement.selection; 8376 this.#bindButtons(); 8377 this.#bindHotkeys(); 8378 this.#resetTabIndexValues(); 8379 this.#monitorSelectionChanges(); 8380 this.#monitorHistoryChanges(); 8381 this.requestOverflowRefresh(); 8382 this.#bindFocusListeners(); 8383 8384 this.resolveEditorPromise(editorElement); 8385 8386 this.toggleAttribute("connected", true); 8387 } 8388 8389 async getEditorElement() { 8390 return this.editorElement || await this.editorPromise 8391 } 8392 8393 requestOverflowRefresh() { 8394 if (this.#refreshToolbarAF != null) return 8395 8396 this.#refreshToolbarAF = requestAnimationFrame(() => { 8397 this.#refreshOverflow(); 8398 this.#refreshToolbarAF = null; 8399 }); 8400 } 8401 8402 closeDropdowns({ except } = {}) { 8403 this.#dropdowns.forEach((dropdown) => { 8404 if (dropdown !== except) { 8405 dropdown.close({ focusEditor: false }); 8406 } 8407 }); 8408 } 8409 8410 #reconnect() { 8411 this.disconnectedCallback(); 8412 this.connectedCallback(); 8413 } 8414 8415 async #createEditorPromise() { 8416 this.editorPromise = new Promise((resolve) => { 8417 this.resolveEditorPromise = resolve; 8418 }); 8419 8420 this.editorElement = await this.editorPromise; 8421 } 8422 8423 #installResizeObserver() { 8424 const resizeObserver = new ResizeObserver(() => this.requestOverflowRefresh()); 8425 resizeObserver.observe(this); 8426 this.#listeners.track(() => resizeObserver.disconnect()); 8427 } 8428 8429 #bindButtons() { 8430 this.#listeners.track(registerEventListener(this, "click", this.#handleButtonClicked)); 8431 } 8432 8433 #handleButtonClicked = (event) => { 8434 this.#handleTargetClicked(event, "[data-command]", this.#dispatchButtonCommand.bind(this)); 8435 } 8436 8437 #handleTargetClicked(event, selector, callback) { 8438 const button = event.target.closest(selector); 8439 if (button) { 8440 callback(event, button); 8441 } 8442 } 8443 8444 #dispatchButtonCommand(event, { dataset: { command, payload } }) { 8445 const isKeyboard = event instanceof PointerEvent && event.pointerId === -1; 8446 8447 this.editor.update(() => { 8448 this.editor.dispatchCommand(command, payload); 8449 }, { tag: isKeyboard ? qn : undefined }); 8450 8451 if (!isKeyboard) this.editor.focus(); 8452 } 8453 8454 #bindHotkeys() { 8455 this.#listeners.track(registerEventListener(this.editorElement, "keydown", this.#handleHotkey)); 8456 } 8457 8458 #handleHotkey = (event) => { 8459 const buttons = this.querySelectorAll("[data-hotkey]"); 8460 buttons.forEach((button) => { 8461 const hotkeys = button.dataset.hotkey.toLowerCase().split(/\s+/); 8462 if (hotkeys.includes(this.#keyCombinationFor(event))) { 8463 event.preventDefault(); 8464 event.stopPropagation(); 8465 button.click(); 8466 } 8467 }); 8468 } 8469 8470 #keyCombinationFor(event) { 8471 const pressedKey = event.key.toLowerCase(); 8472 const modifiers = [ 8473 event.ctrlKey ? "ctrl" : null, 8474 event.metaKey ? "cmd" : null, 8475 event.altKey ? "alt" : null, 8476 event.shiftKey ? "shift" : null,
vendor: 8,058 bytes, lines 8477-8722
8477 ].filter(Boolean); 8478 8479 return [ ...modifiers, pressedKey ].join("+") 8480 } 8481 8482 #bindFocusListeners() { 8483 this.#listeners.track( 8484 registerEventListener(this.editorElement, "lexxy:focus", this.#handleEditorFocus), 8485 registerEventListener(this.editorElement, "lexxy:blur", this.#handleEditorBlur), 8486 registerEventListener(this, "keydown", this.#handleKeydown) 8487 ); 8488 } 8489 8490 #handleEditorFocus = () => { 8491 const firstVisible = this.#buttons.find(isActiveAndVisible); 8492 if (firstVisible) firstVisible.tabIndex = 0; 8493 } 8494 8495 #handleEditorBlur = () => { 8496 this.#resetTabIndexValues(); 8497 } 8498 8499 #handleKeydown = (event) => { 8500 handleRollingTabIndex(this.#buttons, event); 8501 } 8502 8503 #resetTabIndexValues() { 8504 this.#buttons.forEach((button) => { 8505 button.tabIndex = -1; 8506 }); 8507 } 8508 8509 #monitorSelectionChanges() { 8510 this.#listeners.track(this.editor.registerUpdateListener(({ editorState }) => { 8511 editorState.read(() => { 8512 this.#updateButtonStates(); 8513 this.closeDropdowns(); 8514 }); 8515 })); 8516 } 8517 8518 #monitorHistoryChanges() { 8519 this.#listeners.track( 8520 this.editor.registerCommand(He$2, (enabled) => { this.#setButtonDisabled("undo", !enabled); }, io), 8521 this.editor.registerCommand(qe$2, (enabled) => { this.#setButtonDisabled("redo", !enabled); }, io), 8522 ); 8523 } 8524 8525 #updateButtonStates() { 8526 const selection = Qr(); 8527 if (!Fr(selection)) return 8528 8529 const anchorNode = selection.anchor.getNode(); 8530 if (!anchorNode.getParent()) { return } 8531 8532 const { isBold, isItalic, isStrikethrough, isUnderline, isHighlight, isInLink, isInQuote, isInHeading, 8533 headingTag, isInCode, isInList, listType, isInTable } = this.selection.getFormat(); 8534 8535 this.#setButtonPressed("bold", isBold); 8536 this.#setButtonPressed("italic", isItalic); 8537 this.#setButtonPressed("strikethrough", isStrikethrough); 8538 this.#setButtonPressed("underline", isUnderline); 8539 8540 this.#setButtonPressed("format", isInHeading); 8541 this.#setButtonPressed("paragraph", !isInHeading); 8542 8543 this.querySelector("lexxy-heading-dropdown") 8544 ?.updateActiveHeading(headingTag); 8545 8546 this.#setButtonPressed("lists", isInList); 8547 this.#setButtonPressed("unordered-list", isInList && listType === "bullet"); 8548 this.#setButtonPressed("ordered-list", isInList && listType === "number"); 8549 8550 this.#setButtonPressed("highlight", isHighlight); 8551 this.#setButtonPressed("link", isInLink); 8552 this.#setButtonPressed("quote", isInQuote); 8553 this.#setButtonPressed("code", isInCode); 8554 8555 this.#setButtonPressed("table", isInTable); 8556 } 8557 8558 #setButtonPressed(name, isPressed) { 8559 const button = this.querySelector(`[name="${name}"]`); 8560 if (button) { 8561 const next = isPressed.toString(); 8562 if (button.getAttribute("aria-pressed") !== next) { 8563 button.setAttribute("aria-pressed", next); 8564 } 8565 } 8566 } 8567 8568 #setButtonDisabled(name, isDisabled) { 8569 const button = this.querySelector(`[name="${name}"]`); 8570 if (button) { 8571 if (button.disabled !== isDisabled) { 8572 button.disabled = isDisabled; 8573 } 8574 const next = isDisabled.toString(); 8575 if (button.getAttribute("aria-disabled") !== next) { 8576 button.setAttribute("aria-disabled", next); 8577 } 8578 } 8579 } 8580 8581 #refreshOverflow() { 8582 this.#hideOverflowMenuButton(); 8583 this.#resetToolbarOverflow(); 8584 this.#reindexToolbarItems(); 8585 this.#compactMenu(); 8586 8587 const isOverflowing = this.#overflowMenuDropdown.children.length > 0; 8588 8589 this.toggleAttribute("overflowing", isOverflowing); 8590 this.#setOverflowMenuNonce(); 8591 this.#showOverflowMenuButton(isOverflowing); 8592 } 8593 8594 #resetToolbarOverflow() { 8595 const items = Array.from(this.#overflowMenuDropdown.children); 8596 items.sort((a, b) => this.#itemPosition(b) - this.#itemPosition(a)); 8597 8598 for (const item of items) { 8599 const nextItem = this.querySelector(`[data-position="${this.#itemPosition(item) + 1}"]`) ?? this.#overflowMenuButton; 8600 item.removeAttribute("role"); 8601 this.insertBefore(item, nextItem); 8602 } 8603 } 8604 8605 #showOverflowMenuButton(show = true) { 8606 this.#overflowMenuDropdown.toggleAttribute("disabled", !show); 8607 this.#overflowMenuButton.style.display = show ? "block" : "none"; 8608 } 8609 8610 #hideOverflowMenuButton() { 8611 this.#showOverflowMenuButton(false); 8612 } 8613 8614 #itemPosition(item) { 8615 return parseInt(item.dataset.position ?? "999") 8616 } 8617 8618 #reindexToolbarItems() { 8619 this.#toolbarItems.forEach((item, index) => { 8620 item.dataset.position = index; 8621 }); 8622 } 8623 8624 #compactMenu() { 8625 const overflowWidth = this.#getOverflowWidth(); 8626 8627 if (overflowWidth > 0) { 8628 this.#showOverflowMenuButton(); 8629 const gap = this.#getToolbarGap(); 8630 const spaceForOverflow = gap + this.#overflowMenuButton.offsetWidth; 8631 this.#reclaimWidth(overflowWidth + spaceForOverflow, { gap }); 8632 } 8633 } 8634 8635 #getOverflowWidth() { 8636 return this.scrollWidth - this.clientWidth 8637 } 8638 8639 #reclaimWidth(overflowWidth, { gap }) { 8640 const buttons = this.#overflowableButtons; 8641 const overflowButtons = []; 8642 let recoveredWidth = 0; 8643 8644 while (recoveredWidth < overflowWidth && buttons.length) { 8645 const button = buttons.pop(); 8646 8647 overflowButtons.push(button); 8648 button.role = "menuitem"; 8649 recoveredWidth += button.offsetWidth + gap; 8650 } 8651 8652 this.#overflowMenuDropdown.append(...overflowButtons.reverse()); 8653 } 8654 8655 #setOverflowMenuNonce() { 8656 this.#overflowMenuButton.setAttribute("nonce", getNonce()); 8657 } 8658 8659 #getToolbarGap() { 8660 return parseFloat(window.getComputedStyle(this).columnGap) || 0 8661 } 8662 8663 get #dropdowns() { 8664 return this.querySelectorAll(":scope .lexxy-editor__toolbar-dropdown") 8665 } 8666 8667 get #overflowMenuButton() { 8668 return this.querySelector(".lexxy-editor__toolbar-overflow") 8669 } 8670 8671 get #overflowMenuDropdown() { 8672 return this.#overflowMenuButton?.querySelector(":scope > [data-dropdown-panel]") 8673 } 8674 8675 get #overflowableButtons() { 8676 return Array.from(this.querySelectorAll(":scope > button:not([data-prevent-overflow])")) 8677 } 8678 8679 get #buttons() { 8680 return Array.from(this.querySelectorAll(":scope button")) 8681 } 8682 8683 get #toolbarItems() { 8684 return Array.from(this.querySelectorAll(":scope > *:not(.lexxy-editor__toolbar-overflow)")) 8685 } 8686 8687 static get defaultTemplate() { 8688 const linkInputId = generateDomId("lexxy-link-url"); 8689 8690 return ` 8691 <button class="lexxy-editor__toolbar-button" type="button" name="image" data-command="uploadImage" data-prevent-overflow="true" title="Add images and video"> 8692 ${ToolbarIcons.image} 8693 </button> 8694 8695 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="file" data-command="uploadFile" title="Upload files"> 8696 ${ToolbarIcons.attachment} 8697 </button> 8698 8699 <button class="lexxy-editor__toolbar-button" type="button" name="bold" data-command="bold" title="Bold"> 8700 ${ToolbarIcons.bold} 8701 </button> 8702 8703 <button class="lexxy-editor__toolbar-button" type="button" name="italic" data-command="italic" title="Italic"> 8704 ${ToolbarIcons.italic} 8705 </button> 8706 8707 <button class="lexxy-editor__toolbar-button" type="button" name="strikethrough" data-command="strikethrough" title="Strikethrough"> 8708 ${ToolbarIcons.strikethrough} 8709 </button> 8710 8711 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="underline" data-command="underline" title="Underline"> 8712 ${ToolbarIcons.underline} 8713 </button> 8714 8715 <lexxy-toolbar-dropdown class="lexxy-editor__toolbar-dropdown"> 8716 <button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--chevron" type="button" name="format" title="Text formatting" aria-haspopup="menu" aria-expanded="false"> 8717 ${ToolbarIcons.heading} 8718 </button> 8719 <div data-dropdown-panel role="menu" class="lexxy-editor__toolbar-dropdown-list" hidden> 8720 <button type="button" name="paragraph" data-command="setFormatParagraph" title="Paragraph" role="menuitem"> 8721 ${ToolbarIcons.paragraph} <span>Normal</span> 8722 </button>
8723 <lexxy-heading-dropdown> 8724 <div class="lexxy-heading-options"></div> 8725 </lexxy-heading-dropdown> 8726 <div class="lexxy-editor__toolbar-separator" role="separator"></div> 8727 <button type="button" name="clear-formatting" data-command="clearFormatting" title="Clear formatting" role="menuitem"> 8728 ${ToolbarIcons.clearFormatting} <span>Clear formatting</span> 8729 </button> 8730 </div> 8731 </lexxy-toolbar-dropdown> 8732 8733 <lexxy-highlight-dropdown class="lexxy-editor__toolbar-dropdown lexxy-editor__toolbar-dropdown--highlight"> 8734 <button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--chevron" type="button" name="highlight" title="Color highlight" aria-haspopup="menu" aria-expanded="false"> 8735 ${ToolbarIcons.highlight} 8736 </button> 8737 <div data-dropdown-panel role="menu" hidden> 8738 <div class="lexxy-highlight-colors"></div> 8739 <button data-command="removeHighlight" type="button" class="lexxy-editor__toolbar-button lexxy-editor__toolbar-dropdown-reset" role="menuitem">Remove all coloring</button> 8740 </div> 8741 </lexxy-highlight-dropdown> 8742 8743 <lexxy-link-dropdown class="lexxy-editor__toolbar-dropdown lexxy-editor__toolbar-dropdown--link"> 8744 <button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="link" title="Link" data-hotkey="cmd+k ctrl+k" aria-haspopup="dialog" aria-expanded="false"> 8745 ${ToolbarIcons.link} 8746 </button> 8747 <div data-dropdown-panel role="dialog" aria-label="Link" hidden> 8748 <input type="url" placeholder="Enter a URLâ¦" class="input" id="${linkInputId}"> 8749 <div class="lexxy-editor__toolbar-dropdown-actions"> 8750 <button type="button" class="lexxy-editor__toolbar-button" value="link">Link</button> 8751 <button type="button" class="lexxy-editor__toolbar-button" value="unlink">Unlink</button> 8752 </div> 8753 </div> 8754 </lexxy-link-dropdown> 8755 8756 <button class="lexxy-editor__toolbar-button" type="button" name="quote" data-command="insertQuoteBlock" title="Quote"> 8757 ${ToolbarIcons.quote} 8758 </button> 8759 8760 <button class="lexxy-editor__toolbar-button" type="button" name="code" data-command="insertCodeBlock" title="Code"> 8761 ${ToolbarIcons.code} 8762 </button> 8763 8764 <button class="lexxy-editor__toolbar-button" type="button" name="unordered-list" data-command="insertUnorderedList" title="Bullet list"> 8765 ${ToolbarIcons.ul} 8766 </button> 8767 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="ordered-list" data-command="insertOrderedList" title="Numbered list"> 8768 ${ToolbarIcons.ol} 8769 </button> 8770 8771 <button class="lexxy-editor__toolbar-button" type="button" name="table" data-command="insertTable" title="Insert a table"> 8772 ${ToolbarIcons.table} 8773 </button> 8774 8775 <button class="lexxy-editor__toolbar-button" type="button" name="divider" data-command="insertHorizontalDivider" title="Insert a divider"> 8776 ${ToolbarIcons.hr} 8777 </button> 8778 8779 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--push-right" type="button" name="undo" data-command="undo" title="Undo" disabled aria-disabled="true"> 8780 ${ToolbarIcons.undo} 8781 </button> 8782 8783 <button class="lexxy-editor__toolbar-button" type="button" name="redo" data-command="redo" title="Redo" disabled aria-disabled="true"> 8784 ${ToolbarIcons.redo} 8785 </button> 8786 8787 <lexxy-toolbar-dropdown class="lexxy-editor__toolbar-dropdown lexxy-editor__toolbar-button--push-right lexxy-editor__toolbar-overflow"> 8788 <button data-dropdown-trigger class="lexxy-editor__toolbar-button" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Show more toolbar buttons"> 8789 ${ToolbarIcons.overflow} 8790 </button> 8791 <div data-dropdown-panel role="menu" class="lexxy-editor__toolbar-overflow-menu" aria-label="More toolbar buttons" hidden></div> 8792 </lexxy-toolbar-dropdown> 8793 ` 8794 } 8795} 8796 8797function debounce(fn, wait) { 8798 let timeout; 8799 8800 return (...args) => { 8801 clearTimeout(timeout); 8802 timeout = setTimeout(() => fn(...args), wait); 8803 } 8804} 8805 8806function debounceAsync(fn, wait) { 8807 let timeout; 8808 8809 return (...args) => { 8810 clearTimeout(timeout); 8811 8812 return new Promise((resolve, reject) => { 8813 timeout = setTimeout(async () => { 8814 try { 8815 const result = await fn(...args); 8816 resolve(result); 8817 } catch (err) { 8818 reject(err); 8819 } 8820 }, wait); 8821 }) 8822 } 8823} 8824 8825function delay(ms) { 8826 return new Promise((resolve) => setTimeout(resolve, ms)) 8827} 8828 8829function nextFrame() { 8830 return new Promise(requestAnimationFrame) 8831} 8832 8833class ToolbarDropdown extends HTMLElement { 8834 #listeners = new ListenerBin() 8835 8836 connectedCallback() { 8837 this.#onToolbarEditor(() => { 8838 this.#registerListeners(); 8839 this.editorReady(); 8840 }); 8841 } 8842 8843 disconnectedCallback() { 8844 this.#listeners.dispose(); 8845 } 8846 8847 editorReady() {} 8848 onOpen() {} 8849 onClose() {} 8850 8851 get trigger() { 8852 return this.querySelector(":scope > [data-dropdown-trigger]") 8853 } 8854 8855 get panel() { 8856 return this.querySelector(":scope > [data-dropdown-panel]") 8857 } 8858 8859 get toolbar() { 8860 return this.closest("lexxy-toolbar") 8861 } 8862 8863 get editorElement() { 8864 return this.toolbar?.editorElement 8865 } 8866 8867 get editor() { 8868 return this.toolbar?.editor 8869 } 8870 8871 get isOpen() { 8872 return this.panel.hidden === false 8873 } 8874 8875 get isClosed() { 8876 return !this.isOpen 8877 } 8878 8879 track(...listeners) { 8880 this.#listeners.track(...listeners); 8881 } 8882 8883 open() { 8884 if (this.isOpen) return 8885 this.trigger.setAttribute("aria-expanded", "true"); 8886 this.panel.hidden = false;
vendor: 3,722 bytes, lines 8887-9042
8887 this.onOpen(); 8888 this.#focusFirstInteractive(); 8889 } 8890 8891 close({ focusEditor = true } = {}) { 8892 if (focusEditor) this.editor?.focus(); 8893 8894 if (this.isClosed) return 8895 this.trigger.setAttribute("aria-expanded", "false"); 8896 this.panel.hidden = true; 8897 this.onClose(); 8898 } 8899 8900 #registerListeners() { 8901 this.#listeners.track( 8902 registerEventListener(this, "keydown", this.#handleKeyDown), 8903 registerEventListener(this.trigger, "click", this.#handleTriggerClick) 8904 ); 8905 } 8906 8907 #handleTriggerClick = () => { 8908 if (this.isOpen) { 8909 this.close({ focusEditor: false }); 8910 } else { 8911 this.toolbar?.closeDropdowns({ except: this }); 8912 this.open(); 8913 } 8914 } 8915 8916 async #onToolbarEditor(callback) { 8917 if (!this.toolbar) return 8918 8919 await this.toolbar.getEditorElement(); 8920 if (this.isConnected && this.toolbar) callback(); 8921 } 8922 8923 #handleKeyDown = (event) => { 8924 if (event.key === "Escape") { 8925 event.stopPropagation(); 8926 this.close(); 8927 } 8928 } 8929 8930 async #focusFirstInteractive() { 8931 this.#interactiveElements[0]?.focus(); 8932 await this.#resetTabIndexValues(); 8933 } 8934 8935 async #resetTabIndexValues() { 8936 await nextFrame(); 8937 this.#buttons.forEach((element, index) => { 8938 element.setAttribute("tabindex", index === 0 ? 0 : "-1"); 8939 }); 8940 } 8941 8942 get #interactiveElements() { 8943 return Array.from(this.panel.querySelectorAll("button, input")) 8944 } 8945 8946 get #buttons() { 8947 return Array.from(this.panel.querySelectorAll("button")) 8948 } 8949} 8950 8951const HEADING_BUTTON_SELECTOR = "button.lexxy-heading-button"; 8952 8953const HEADING_PRESETS = [ 8954 { label: "Large Heading", name: "heading-large", command: "setFormatHeadingLarge" }, 8955 { label: "Medium Heading", name: "heading-medium", command: "setFormatHeadingMedium" }, 8956 { label: "Small Heading", name: "heading-small", command: "setFormatHeadingSmall" } 8957]; 8958 8959class HeadingDropdown extends HTMLElement { 8960 static labelFor(tag, index) { 8961 if (index < HEADING_PRESETS.length) { 8962 return HEADING_PRESETS[index].label 8963 } else { 8964 const level = tag.match(/^h(\d+)$/)?.[1]; 8965 if (level) { 8966 return `Heading ${level}` 8967 } else { 8968 return tag.toUpperCase() 8969 } 8970 } 8971 } 8972 8973 static nameFor(tag, index) { 8974 if (index < HEADING_PRESETS.length) { 8975 return HEADING_PRESETS[index].name 8976 } else { 8977 const level = tag.match(/^h(\d+)$/)?.[1]; 8978 if (level) { 8979 return `heading-${level}` 8980 } else { 8981 return `heading-${tag}` 8982 } 8983 } 8984 } 8985 8986 static commandFor(index) { 8987 if (index < HEADING_PRESETS.length) { 8988 return HEADING_PRESETS[index].command 8989 } else { 8990 return "applyHeadingFormat" 8991 } 8992 } 8993 8994 #listeners = new ListenerBin() 8995 8996 connectedCallback() { 8997 this.style.display = "contents"; 8998 8999 this.#onToolbarEditor(() => { 9000 this.#buttonContainer.style.display = "contents"; 9001 this.#setUpButtons(); 9002 this.#registerButtonHandlers(); 9003 this.#syncActiveHeading(); 9004 }); 9005 } 9006 9007 disconnectedCallback() { 9008 this.#listeners.dispose(); 9009 } 9010 9011 updateActiveHeading(tag) { 9012 this.#headingButtons.forEach(button => { 9013 const next = (button.dataset.heading === tag).toString(); 9014 if (button.getAttribute("aria-pressed") !== next) { 9015 button.setAttribute("aria-pressed", next); 9016 } 9017 }); 9018 } 9019 9020 get #toolbar() { 9021 return this.closest("lexxy-toolbar") 9022 } 9023 9024 get #editorElement() { 9025 return this.#toolbar?.editorElement 9026 } 9027 9028 get #editor() { 9029 return this.#toolbar?.editor 9030 } 9031 9032 async #onToolbarEditor(callback) { 9033 const toolbar = this.#toolbar; 9034 if (!toolbar) return 9035 9036 await toolbar.getEditorElement(); 9037 if (this.isConnected && this.#toolbar) callback(); 9038 } 9039 9040 #setUpButtons() { 9041 this.#buttonContainer.innerHTML = ""; 9042
9043 this.#configuredHeadings.forEach((tag, index) => { 9044 this.#buttonContainer.appendChild(this.#createButton(tag, index)); 9045 }); 9046 } 9047 9048 #createButton(tag, index) { 9049 const label = HeadingDropdown.labelFor(tag, index); 9050 const name = HeadingDropdown.nameFor(tag, index); 9051 const icon = ToolbarIcons[tag] || ""; 9052 9053 const button = document.createElement("button"); 9054 button.type = "button"; 9055 button.dataset.heading = tag; 9056 button.dataset.command = HeadingDropdown.commandFor(index); 9057 button.classList.add("lexxy-heading-button"); 9058 button.name = name; 9059 button.title = label; 9060 button.setAttribute("role", "menuitem"); 9061 button.innerHTML = `${icon} <span>${label}</span>`; 9062 return button 9063 } 9064 9065 #registerButtonHandlers() { 9066 this.#headingButtons.forEach(button => { 9067 this.#listeners.track(registerEventListener(button, "click", (event) => { 9068 if (!this.#editor) return 9069 9070 event.preventDefault(); 9071 this.#editor.dispatchCommand(button.dataset.command, button.dataset.heading); 9072 this.#editor.focus(); 9073 })); 9074 }); 9075 } 9076 9077 #syncActiveHeading() { 9078 const { headingTag } = this.#editor.read(() => this.#editorElement.selection.getFormat()); 9079 this.updateActiveHeading(headingTag ?? null); 9080 } 9081 9082 get #configuredHeadings() { 9083 return this.#editorElement.config.get("headings") 9084 } 9085 9086 get #buttonContainer() { 9087 return this.querySelector(".lexxy-heading-options") 9088 } 9089 9090 get #headingButtons() { 9091 return Array.from(this.querySelectorAll(HEADING_BUTTON_SELECTOR)) 9092 } 9093} 9094 9095const APPLY_HIGHLIGHT_SELECTOR = "button.lexxy-highlight-button"; 9096const REMOVE_HIGHLIGHT_SELECTOR = "[data-command='removeHighlight']"; 9097 9098// Use Symbol instead of null since $getSelectionStyleValueForProperty 9099// responds differently for backward selections if null is the default 9100// see https://github.com/facebook/lexical/issues/8013 9101const NO_STYLE = Symbol("no_style"); 9102 9103class HighlightDropdown extends ToolbarDropdown { 9104 editorReady() { 9105 this.#setUpButtons(); 9106 this.#registerButtonHandlers(); 9107 } 9108 9109 onOpen() { 9110 this.editor.getEditorState().read(() => { 9111 this.#updateColorButtonStates(Qr()); 9112 }); 9113 } 9114 9115 #registerButtonHandlers() { 9116 this.#colorButtons.forEach(button => { 9117 this.track(registerEventListener(button, "click", this.#handleColorButtonClick)); 9118 }); 9119 } 9120 9121 #setUpButtons() { 9122 this.#buttonContainer.innerHTML = ""; 9123 9124 const colorGroups = this.editorElement.config.get("highlight.buttons"); 9125 9126 this.#populateButtonGroup("color", colorGroups.color); 9127 this.#populateButtonGroup("background-color", colorGroups["background-color"]); 9128 9129 const maxNumberOfColors = Math.max(colorGroups.color.length, colorGroups["background-color"].length); 9130 this.panel.style.setProperty("--max-colors", maxNumberOfColors); 9131 } 9132 9133 #populateButtonGroup(attribute, values) { 9134 values.forEach((value, index) => { 9135 this.#buttonContainer.appendChild(this.#createButton(attribute, value, index)); 9136 }); 9137 } 9138 9139 #createButton(attribute, value, index) { 9140 return createElement("button", { 9141 type: "button", 9142 dataset: { value, style: attribute }, 9143 style: `${attribute}: ${value}`, 9144 class: "lexxy-editor__toolbar-button lexxy-highlight-button", 9145 name: `${attribute}-${index}`, 9146 role: "menuitem" 9147 }) 9148 } 9149 9150 #handleColorButtonClick = (event) => { 9151 event.preventDefault(); 9152 9153 const button = event.target.closest(APPLY_HIGHLIGHT_SELECTOR); 9154 if (!button) return 9155 9156 const { style, value } = button.dataset; 9157 9158 this.editor.dispatchCommand("toggleHighlight", { [style]: value }); 9159 this.close(); 9160 } 9161 9162 #updateColorButtonStates(selection) { 9163 if (!Fr(selection)) { return } 9164 9165 // Use non-"" default, so "" indicates mixed highlighting 9166 const textColor = ne$4(selection, "color", NO_STYLE); 9167 const backgroundColor = ne$4(selection, "background-color", NO_STYLE); 9168 9169 this.#colorButtons.forEach(button => { 9170 const matchesSelection = button.dataset.value === textColor || button.dataset.value === backgroundColor; 9171 const next = matchesSelection.toString(); 9172 if (button.getAttribute("aria-pressed") !== next) { 9173 button.setAttribute("aria-pressed", next); 9174 } 9175 }); 9176 9177 const hasHighlight = textColor !== NO_STYLE || backgroundColor !== NO_STYLE; 9178 this.panel.querySelector(REMOVE_HIGHLIGHT_SELECTOR).disabled = !hasHighlight; 9179 } 9180 9181 get #buttonContainer() { 9182 return this.panel.querySelector(".lexxy-highlight-colors") 9183 } 9184 9185 get #colorButtons() { 9186 return Array.from(this.panel.querySelectorAll(APPLY_HIGHLIGHT_SELECTOR)) 9187 } 9188} 9189 9190/** 9191 * Copyright (c) Meta Platforms, Inc. and affiliates. 9192 * 9193 * This source code is licensed under the MIT license found in the 9194 * LICENSE file in the root directory of this source tree. 9195 * 9196 */ 9197 9198function F$5(t,...e){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",t);for(const t of e)o.append("v",t);throw n.search=o.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}const I$5="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,O$2=I$5&&"documentMode"in document?document.documentMode:null,D$2=I$5&&/Mac|iPod|iPhone|iPad/.test(navigator.platform);!(!I$5||!("InputEvent"in window)||O$2)&&"getTargetRanges"in new window.InputEvent("input");const lt$2=D$2;function pt$2(t,e){return Array.from(vt$2(t))}function vt$2(t,e){return wt$2("next",t)}function yt$5(t,e){const n=cc(Ol(t,e));return n&&n[0]}function wt$2(t,e,n){const o=Zo(),i=e||o,l=Wi(i)?Pl(i,t):Ol(i,t),s=Et$3(i),c=yt$5(i,t);let g=s;
9198return $l({hasNext:t=>null!==t,initial:l,map:t=>({depth:g,node:t.origin}),step:t=>{if(t.isSameNodeCaret(c))return null;Nl(t)&&g++;const e=cc(t);return !e||e[0].isSameNodeCaret(c)?null:(g+=e[1],e[0])}})}function Et$3(t){let e=-1;for(let n=t;null!==n;n=n.getParent())e++;return e}function At$2(t,e){let n=t;for(;null!=n;){if(n instanceof e)return n;n=n.getParent();}return null}function Nt$2(t){const e=dl(t,t=>Wi(t)&&!t.isInline());return Wi(e)||F$5(4,t.__key),e}function Pt$3(t){const e=Qr()||Zr();let r;if(Fr(e))r=ql(e.focus,"next");else {if(null!=e){const t=e.getNodes(),n=t[t.length-1];n&&(r=Ol(n,"next"));}r=r||Pl(Zo(),"previous").getFlipped().insert(eo());}const i=Rt$3(t,r),l=Ll(i),s=Nl(l)?rc(l):i;return Gl(Bl(s)),t.getLatest()}function Rt$3(t,e,n){let o=oc(e,"next");vl(o)&&(0===o.offset?o=Ol(o.origin,"previous").getFlipped():o.offset===o.origin.getTextContentSize()&&(o=Ol(o.origin,"next"))),o.origin.is(t)&&(Tl(o)||F$5(342,t.getKey(),t.getType()),o=Zl(o)),(t.is(o.getNodeAtCaret())||t.is(o.getFlipped().getNodeAtCaret()))&&t.remove(true);for(let t=o;t;t=fc(t,n))o=t;return vl(o)&&F$5(283),o.insert(t.isInline()?eo().append(t):t),oc(Ol(t.getLatest(),"next"),e.direction)}function Tt$4(t,e){const n=e();return t.replace(n),n.append(t),n}function Bt$3(t,e){return null!==t&&Object.getPrototypeOf(t).constructor.name===e.name}function _t$2(t){const e=Qr();if(!Fr(e))return false;const i=new Set,l=e.getNodes();for(let e=0;e<l.length;e++){const n=l[e],o=n.getKey();if(i.has(o))continue;const s=dl(n,t=>Wi(t)&&!t.isInline());if(null===s)continue;const u=s.getKey();s.canIndent()&&!i.has(u)&&(i.add(u),t(s));}return i.size>0}function $t$2(t,e){Pl(t,"next").insert(e);}function Ot$3(t,e){return Dt$4(t,e,null)}function Dt$4(t,e,n){let o=false;for(const i of zt$4(t))e(i)?null!==n&&n(i):(o=true,Wi(i)&&Dt$4(i,e,n||(t=>i.insertAfter(t))),i.remove());return o}function Ht$3(t,e){const n=[],o=Array.from(t).reverse();for(let t=o.pop();void 0!==t;t=o.pop())if(e(t))n.push(t);else if(Wi(t))for(const e of zt$4(t))o.push(e);return n}function jt$2(t){return Ut$3(Pl(t,"next"))}function zt$4(t){return Ut$3(Pl(t,"previous"))}function Ut$3(t){return $l({hasNext:Tl,initial:t.getAdjacentCaret(),map:t=>t.origin.getLatest(),step:t=>t.getAdjacentCaret()})} 9199 9200/** 9201 * Copyright (c) Meta Platforms, Inc. and affiliates. 9202 * 9203 * This source code is licensed under the MIT license found in the 9204 * LICENSE file in the root directory of this source tree. 9205 * 9206 */ 9207 9208const Q$7=Symbol.for("preact-signals");function X$5(){if(ot$2>1)return void ot$2--;let t,e=false;for(!function(){let t=it$1;for(it$1=void 0;void 0!==t;)t.S.v===t.v&&(t.S.i=t.i),t=t.o;}();void 0!==et$1;){let n=et$1;for(et$1=void 0,st$1++;void 0!==n;){const i=n.u;if(n.u=void 0,n.f&=-3,!(8&n.f)&<$1(n))try{n.c();}catch(n){e||(t=n,e=true);}n=i;}}if(st$1=0,ot$2--,e)throw t}function Y$3(t){if(ot$2>0)return t();ct$1=++rt$3,ot$2++;try{return t()}finally{X$5();}}let tt$3,et$1;function nt$3(t){const e=tt$3;tt$3=void 0;try{return t()}finally{tt$3=e;}}let it$1,ot$2=0,st$1=0,rt$3=0,ct$1=0,at$2=0;function dt$2(t){if(void 0===tt$3)return;let e=t.n;return void 0===e||e.t!==tt$3?(e={i:0,S:t,p:tt$3.s,n:void 0,t:tt$3,e:void 0,x:void 0,r:e},void 0!==tt$3.s&&(tt$3.s.n=e),tt$3.s=e,t.n=e,32&tt$3.f&&t.S(e),e):-1===e.i?(e.i=0,void 0!==e.n&&(e.n.p=e.p,void 0!==e.p&&(e.p.n=e.n),e.p=tt$3.s,e.n=void 0,tt$3.s.n=e,tt$3.s=e),e):void 0}function ut$2(t,e){this.v=t,this.i=0,this.n=void 0,this.t=void 0,this.l=0,this.W=null==e?void 0:e.watched,this.Z=null==e?void 0:e.unwatched,this.name=null==e?void 0:e.name;}function ft$1(t,e){return new ut$2(t,e)}function lt$1(t){for(let e=t.s;void 0!==e;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return true;return false}function ht$2(t){for(let e=t.s;void 0!==e;e=e.n){const n=e.S.n;if(void 0!==n&&(e.r=n),e.S.n=e,e.i=-1,void 0===e.n){t.s=e;break}}}function gt$2(t){let e,n=t.s;for(;void 0!==n;){const t=n.p;-1===n.i?(n.S.U(n),void 0!==t&&(t.n=n.n),void 0!==n.n&&(n.n.p=t)):e=n,n.S.n=n.r,void 0!==n.r&&(n.r=void 0),n=t;}t.s=e;}function pt$1(t,e){ut$2.call(this,void 0),this.x=t,this.s=void 0,this.g=at$2-1,this.f=4,this.W=null==e?void 0:e.watched,this.Z=null==e?void 0:e.unwatched,this.name=null==e?void 0:e.name;}function vt$1(t){const e=t.m;if(t.m=void 0,"function"==typeof e){ot$2++;const n=tt$3;tt$3=void 0;try{e();}catch(e){throw t.f&=-2,t.f|=8,xt$2(t),e}finally{tt$3=n,X$5();}}}function xt$2(t){for(let e=t.s;void 0!==e;
9208e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,vt$1(t);}function yt$4(t){if(tt$3!==this)throw new Error("Out-of-order effect");gt$2(this),tt$3=t,this.f&=-2,8&this.f&&xt$2(this),X$5();}function Et$2(t,e){this.x=t,this.m=void 0,this.s=void 0,this.u=void 0,this.f=32,this.name=null==e?void 0:e.name;}function St$2(t,e){const n=new Et$2(t,e);try{n.c();}catch(t){throw n.d(),t}const i=n.d.bind(n);return i[Symbol.dispose]=i,i}function bt$2(t,e={}){const n={};for(const i in t){const o=e[i],s=ft$1(void 0===o?t[i]:o);n[i]=s;}return n}ut$2.prototype.brand=Q$7,ut$2.prototype.h=function(){return true},ut$2.prototype.S=function(t){const e=this.t;e!==t&&void 0===t.e&&(t.x=e,this.t=t,void 0!==e?e.e=t:nt$3(()=>{var t;null==(t=this.W)||t.call(this);}));},ut$2.prototype.U=function(t){if(void 0!==this.t){const e=t.e,n=t.x;void 0!==e&&(e.x=n,t.e=void 0),void 0!==n&&(n.e=e,t.x=void 0),t===this.t&&(this.t=n,void 0===n&&nt$3(()=>{var t;null==(t=this.Z)||t.call(this);}));}},ut$2.prototype.subscribe=function(t){return St$2(()=>{const e=this.value,n=tt$3;tt$3=void 0;try{t(e);}finally{tt$3=n;}},{name:"sub"})},ut$2.prototype.valueOf=function(){return this.value},ut$2.prototype.toString=function(){return this.value+""},ut$2.prototype.toJSON=function(){return this.value},ut$2.prototype.peek=function(){const t=tt$3;tt$3=void 0;try{return this.value}finally{tt$3=t;}},Object.defineProperty(ut$2.prototype,"value",{get(){const t=dt$2(this);return void 0!==t&&(t.i=this.i),this.v},set(t){if(t!==this.v){if(st$1>100)throw new Error("Cycle detected");!function(t){0!==ot$2&&0===st$1&&t.l!==ct$1&&(t.l=ct$1,it$1={S:t,v:t.v,i:t.i,o:it$1});}(this),this.v=t,this.i++,at$2++,ot$2++;try{for(let t=this.t;void 0!==t;t=t.x)t.t.N();}finally{X$5();}}}}),pt$1.prototype=new ut$2,pt$1.prototype.h=function(){if(this.f&=-3,1&this.f)return false;if(32==(36&this.f))return true;if(this.f&=-5,this.g===at$2)return true;if(this.g=at$2,this.f|=1,this.i>0&&!lt$1(this))return this.f&=-2,true;const t=tt$3;try{ht$2(this),tt$3=this;const t=this.x();(16&this.f||this.v!==t||0===this.i)&&(this.v=t,this.f&=-17,this.i++);}catch(t){this.v=t,this.f|=16,this.i++;}return tt$3=t,gt$2(this),this.f&=-2,true},pt$1.prototype.S=function(t){if(void 0===this.t){this.f|=36;for(let t=this.s;void 0!==t;t=t.n)t.S.S(t);}ut$2.prototype.S.call(this,t);},pt$1.prototype.U=function(t){if(void 0!==this.t&&(ut$2.prototype.U.call(this,t),void 0===this.t)){this.f&=-33;for(let t=this.s;void 0!==t;t=t.n)t.S.U(t);}},pt$1.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(let t=this.t;void 0!==t;t=t.x)t.t.N();}}
9208,Object.defineProperty(pt$1.prototype,"value",{get(){if(1&this.f)throw new Error("Cycle detected");const t=dt$2(this);if(this.h(),void 0!==t&&(t.i=this.i),16&this.f)throw this.v;return this.v}}),Et$2.prototype.c=function(){const t=this.S();try{if(8&this.f)return;if(void 0===this.x)return;const t=this.x();"function"==typeof t&&(this.m=t);}finally{t();}},Et$2.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,vt$1(this),ht$2(this),ot$2++;const t=tt$3;return tt$3=this,yt$4.bind(this,t)},Et$2.prototype.N=function(){2&this.f||(this.f|=2,this.u=et$1,et$1=this);},Et$2.prototype.d=function(){this.f|=8,1&this.f||xt$2(this);},Et$2.prototype.dispose=function(){this.d();};function Ct$1(t){const e=new Set,n=new Set;for(const i of Dt$3(t)){const t="function"==typeof i?i:i.replace;ul(t),e.add(t.getType()),n.add(t);}return {nodes:n,types:e}}function Dt$3(t){return ("function"==typeof t.nodes?t.nodes():t.nodes)||[]}ot$3("format",{parse:t=>"number"==typeof t?t:0});function zt$3(t,...e){const n=new URL("https://lexical.dev/docs/error"),i=new URLSearchParams;i.append("code",t);for(const t of e)i.append("v",t);throw n.search=i.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function Lt$3(t,e){if(t&&e&&!Array.isArray(e)&&"object"==typeof t&&"object"==typeof e){const n=t,i=e;for(const t in i)n[t]=Lt$3(n[t],i[t]);return t}return e}const Ut$2=0,Tt$3=1,Bt$2=2,Wt$3=3,Gt$2=4,Vt$2=5,Zt$2=6,Jt$3=7;function Ht$2(t){return t.id===Ut$2}function qt$3(t){return t.id===Bt$2}function Qt$2(t){return function(t){return t.id===Tt$3}(t)||zt$3(305,String(t.id),String(Tt$3)),Object.assign(t,{id:Bt$2})}const Xt$3=new Set;let Yt$2 = class Yt{builder;configs;_dependency;_peerNameSet;extension;state;_signal;constructor(t,e){this.builder=t,this.extension=e,this.configs=new Set,this.state={id:Ut$2};}mergeConfigs(){let t=this.extension.config||{};const e=this.extension.mergeConfig?this.extension.mergeConfig.bind(this.extension):pc;for(const n of this.configs)t=e(t,n);return t}init(t){const e=this.state;qt$3(e)||zt$3(306,String(e.id));const n={getDependency:this.getInitDependency.bind(this),getDirectDependentNames:this.getDirectDependentNames.bind(this),getPeer:this.getInitPeer.bind(this),getPeerNameSet:this.getPeerNameSet.bind(this)},i={...n,getDependency:this.getDependency.bind(this),getInitResult:this.getInitResult.bind(this),getPeer:this.getPeer.bind(this)},o=function(t,e,n){return Object.assign(t,{config:e,id:Wt$3,registerState:n})}(e,this.mergeConfigs(),n);let s;this.state=o,this.extension.init&&(s=this.extension.init(t,o.config,n)),this.state=function(t,e,n){return Object.assign(t,{id:Gt$2,initResult:e,registerState:n})}(o,s,i);}build(t){const e=this.state;let n;e.id!==Gt$2&&zt$3(307,String(e.id),String(Vt$2)),this.extension.build&&(n=this.extension.build(t,e.config,e.registerState));const i={...e.registerState,getOutput:()=>n,getSignal:this.getSignal.bind(this)};this.state=function(t,e,n){return Object.assign(t,{id:Vt$2,output:e,registerState:n})}(e,n,i);}register(t,e){this._signal=e;const n=this.state;n.id!==Vt$2&&zt$3(308,String(n.id),String(Vt$2));const i=this.extension.register&&this.extension.register(t,n.config,n.registerState);return this.state=function(t){return Object.assign(t,{id:Zt$2})}(n),()=>{const t=this.state;t.id!==Jt$3&&zt$3(309,String(n.id),String(Jt$3)),this.state=function(t){return Object.assign(t,{id:Vt$2})}(t),i&&i();}}afterRegistration(t){const e=this.state;let n;return e.id!==Zt$2&&zt$3(310,String(e.id),String(Zt$2)),this.extension.afterRegistration&&(n=this.extension.afterRegistration(t,e.config,e.registerState)),this.state=function(t){return Object.assign(t,{id:Jt$3})}(e),n}getSignal(){return void 0===this._signal&&zt$3(311),this._signal}getInitResult(){ void 0===this.extension.init&&zt$3(312,this.extension.name);const t=this.state;return function(t){return t.id>=Gt$2}(t)||zt$3(313,String(t.id),String(Gt$2)),t.initResult}getInitPeer(t){const e=this.builder.extensionNameMap.get(t);return e?e.getExtensionInitDependency():void 0}getExtensionInitDependency(){const t=this.state;return function(t){return t.id>=Wt$3}(t)||zt$3(314,String(t.id),String(Wt$3)),{config:t.config}}getPeer(t){const e=this.builder.extensionNameMap.get(t);return e?e.getExtensionDependency():void 0}getInitDependency(t){const e=this.builder.getExtensionRep(t);return void 0===e&&zt$3(315,this.extension.name,t.name),e.getExtensionInitDependency()}getDependency(t){const e=this.builder.getExtensionRep(t);return void 0===e&&zt$3(315,this.extension.name,t.name),e.getExtensionDependency()}getState(){const t=this.state;return function(t){return t.id>=Jt$3}(t)||zt$3(316,String(t.id),String(Jt$3)),t}getDirectDependentNames(){return this.builder.incomingEdges.get(this.extension.name)||Xt$3}getPeerNameSet(){let t=this._peerNameSet;
9208return t||(t=new Set((this.extension.peerDependencies||[]).map(([t])=>t)),this._peerNameSet=t),t}getExtensionDependency(){if(!this._dependency){const t=this.state;((function(t){return t.id>=Vt$2}))(t)||zt$3(317,this.extension.name),this._dependency={config:t.config,init:t.initResult,output:t.output};}return this._dependency}};const te$3={tag:Jn};function ee$2(){const t=Zo();t.isEmpty()&&t.append(eo());}const ne$3=dc({config:_c({setOptions:te$3,updateOptions:te$3}),init:({$initialEditorState:t=ee$2})=>({$initialEditorState:t,initialized:false}),afterRegistration(t,{updateOptions:e,setOptions:n},i){const o=i.getInitResult();if(!o.initialized){o.initialized=true;const{$initialEditorState:i}=o;if(Gi(i))t.setEditorState(i,n);else if("function"==typeof i)t.update(()=>{i(t);},e);else if(i&&("string"==typeof i||"object"==typeof i)){const e=t.parseEditorState(i);t.setEditorState(e,n);}}return ()=>{}},name:"@lexical/extension/InitialState",nodes:[Ui,gr,rr,br,Zi]}),ie$3=Symbol.for("@lexical/extension/LexicalBuilder");function oe$4(...t){return de$3.fromExtensions(t).buildEditor()}function se$4(){}function re$4(t){throw t}function ce$3(t){return Array.isArray(t)?t:[t]}const ae$3="0.44.0+prod.esm";let de$3 = class de{roots;extensionNameMap;outgoingConfigEdges;incomingEdges;conflicts;_sortedExtensionReps;PACKAGE_VERSION;constructor(t){this.outgoingConfigEdges=new Map,this.incomingEdges=new Map,this.extensionNameMap=new Map,this.conflicts=new Map,this.PACKAGE_VERSION=ae$3,this.roots=t;for(const e of t)this.addExtension(e);}static fromExtensions(t){const e=[ce$3(ne$3)];for(const n of t)e.push(ce$3(n));return new de(e)}static maybeFromEditor(t){const e=t[ie$3];return e&&(e.PACKAGE_VERSION!==ae$3&&zt$3(292,e.PACKAGE_VERSION,ae$3),e instanceof de||zt$3(293)),e}static fromEditor(t){const e=de.maybeFromEditor(t);return void 0===e&&zt$3(294),e}constructEditor(){const{$initialEditorState:t,onError:e,...n}=this.buildCreateEditorArgs(),i=Object.assign(yo({...n,...e?{onError:t=>{e(t,i);}}:{}}),{[ie$3]:this});for(const t of this.sortedExtensionReps())t.build(i);return i}buildEditor(){let t=se$4;function e(){try{t();}finally{t=se$4;}}const n=Object.assign(this.constructEditor(),{dispose:e,[Symbol.dispose]:e});
9208return t=Cc(this.registerEditor(n),()=>n.setRootElement(null)),n}hasExtensionByName(t){return this.extensionNameMap.has(t)}getExtensionRep(t){const e=this.extensionNameMap.get(t.name);if(e)return e.extension!==t&&zt$3(295,t.name),e}addEdge(t,e,n){const i=this.outgoingConfigEdges.get(t);i?i.set(e,n):this.outgoingConfigEdges.set(t,new Map([[e,n]]));const o=this.incomingEdges.get(e);o?o.add(t):this.incomingEdges.set(e,new Set([t]));}addExtension(t){ void 0!==this._sortedExtensionReps&&zt$3(296);const e=ce$3(t),[n]=e;"string"!=typeof n.name&&zt$3(297,typeof n.name);let i=this.extensionNameMap.get(n.name);if(void 0!==i&&i.extension!==n&&zt$3(298,n.name),!i){i=new Yt$2(this,n),this.extensionNameMap.set(n.name,i);const t=this.conflicts.get(n.name);"string"==typeof t&&zt$3(299,n.name,t);for(const t of n.conflictsWith||[])this.extensionNameMap.has(t)&&zt$3(299,n.name,t),this.conflicts.set(t,n.name);for(const t of n.dependencies||[]){const e=ce$3(t);this.addEdge(n.name,e[0].name,e.slice(1)),this.addExtension(e);}for(const[t,e]of n.peerDependencies||[])this.addEdge(n.name,t,e?[e]:[]);}}sortedExtensionReps(){if(this._sortedExtensionReps)return this._sortedExtensionReps;const t=[],e=(n,i)=>{let o=n.state;if(qt$3(o))return;const s=n.extension.name;var r;Ht$2(o)||zt$3(300,s,i||"[unknown]"),Ht$2(r=o)||zt$3(304,String(r.id),String(Ut$2)),o=Object.assign(r,{id:Tt$3}),n.state=o;const c=this.outgoingConfigEdges.get(s);if(c)for(const t of c.keys()){const n=this.extensionNameMap.get(t);n&&e(n,s);}o=Qt$2(o),n.state=o,t.push(n);};for(const t of this.extensionNameMap.values())Ht$2(t.state)&&e(t);for(const e of t)for(const[t,n]of this.outgoingConfigEdges.get(e.extension.name)||[])if(n.length>0){const e=this.extensionNameMap.get(t);if(e)for(const t of n)e.configs.add(t);}for(const[t,...e]of this.roots)if(e.length>0){const n=this.extensionNameMap.get(t.name);void 0===n&&zt$3(301,t.name);for(const t of e)n.configs.add(t);}return this._sortedExtensionReps=t,this._sortedExtensionReps}registerEditor(t){const e=this.sortedExtensionReps(),n=new AbortController,i=[()=>n.abort()],o=n.signal;for(const n of e){const e=n.register(t,o);e&&i.push(e);}for(const n of e){const e=n.afterRegistration(t);e&&i.push(e);}return Cc(...i)}buildCreateEditorArgs(){const t={},e=new Set,n=new Map,i=new Map,o={},s={},r=this.sortedExtensionReps();for(const c of r){const{extension:r}=c;if(void 0!==r.onError&&(t.onError=r.onError),void 0!==r.disableEvents&&(t.disableEvents=r.disableEvents),void 0!==r.parentEditor&&(t.parentEditor=r.parentEditor),void 0!==r.editable&&(t.editable=r.editable),void 0!==r.namespace&&(t.namespace=r.namespace),void 0!==r.$initialEditorState&&(t.$initialEditorState=r.$initialEditorState),r.nodes)for(const t of Dt$3(r)){if("function"!=typeof t){const e=n.get(t.replace);e&&zt$3(302,r.name,t.replace.name,e.extension.name),n.set(t.replace,c);}e.add(t);}if(r.html){if(r.html.export)for(const[t,e]of r.html.export.entries())i.set(t,e);r.html.import&&Object.assign(o,r.html.import);}r.theme&&Lt$3(s,r.theme);}Object.keys(s).length>0&&(t.theme=s),e.size&&(t.nodes=[...e]);const c=Object.keys(o).length>0,a=i.size>0;(c||a)&&(t.html={},c&&(t.html.import=o),a&&(t.html.export=i));for(const e of r)e.init(t);return t.onError||(t.onError=re$4),t}};function ue$3(t,e){const n=de$3.fromEditor(t).getExtensionRep(e);return void 0===n&&zt$3(303,e.name),n.getExtensionDependency()}function fe$3(t,e){const n=de$3.maybeFromEditor(t);if(!n)return;const i=n.extensionNameMap.get(e);return i?i.getExtensionDependency():void 0} 9209 9210/** 9211 * Copyright (c) Meta Platforms, Inc. and affiliates. 9212 * 9213 * This source code is licensed under the MIT license found in the 9214 * LICENSE file in the root directory of this source tree. 9215 * 9216 */ 9217 9218const M$3=new Set(["http:","https:","mailto:","sms:","tel:"]);let F$4 = class F extends Bi{__url;__target;__rel;__title;static getType(){return "link"}static clone(t){return new F(t.__url,{rel:t.__rel,target:t.__target,title:t.__title},t.__key)}constructor(t="",e={},n){super(n);const{target:r=null,rel:i=null,title:s=null}=e;this.__url=t,this.__target=r,this.__rel=i,this.__title=s;}afterCloneFrom(t){super.afterCloneFrom(t),this.__url=t.__url,this.__rel=t.__rel,this.__target=t.__target,this.__title=t.__title;}createDOM(e){const n=document.createElement("a");return this.updateLinkDOM(null,n,e),mc(n,e.theme.link),n}updateLinkDOM(t,n,r){if(Vs(n)){t&&t.__url===this.__url||(n.href=this.sanitizeUrl(this.__url));for(const e of ["target","rel","title"]){const r=`__${e}`,i=this[r];t&&t[r]===i||(i?n[e]=i:n.removeAttribute(e));}}}updateDOM(t,e,n){return this.updateLinkDOM(t,e,n),false}static importDOM(){return {a:t=>({conversion:K$3,priority:1})}}static importJSON(t){return $$2().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setURL(t.url).setRel(t.rel||null).setTarget(t.target||null).setTitle(t.title||null)}sanitizeUrl(t){t=X$4(t);try{const e=new URL(X$4(t));if(!M$3.has(e.protocol))return "about:blank"}catch(e){return t}return t}exportJSON(){return {...super.exportJSON(),rel:this.getRel(),target:this.getTarget(),title:this.getTitle(),url:this.getURL()}}getURL(){return this.getLatest().__url}setURL(t){const e=this.getWritable();return e.__url=t,e}getTarget(){return this.getLatest().__target}setTarget(t){const e=this.getWritable();return e.__target=t,e}getRel(){return this.getLatest().__rel}setRel(t){const e=this.getWritable();return e.__rel=t,e}getTitle(){return this.getLatest().__title}setTitle(t){const e=this.getWritable();return e.__title=t,e}insertNewAfter(t,e=true){const n=Ks(this);return this.insertAfter(n,e),n}canInsertTextBefore(){return false}canInsertTextAfter(){return false}canBeEmpty(){return false}isInline(){return true}extractWithChild(t,e,n){if(!Fr(e))return false;
9218const r=e.anchor.getNode(),i=e.focus.getNode();return this.isParentOf(r)&&this.isParentOf(i)&&e.getTextContent().length>0}isEmailURI(){return this.__url.startsWith("mailto:")}isWebSiteURI(){return this.__url.startsWith("https://")||this.__url.startsWith("http://")}shouldMergeAdjacentLink(t){return this.getType()===t.getType()&&this.__url===t.__url&&this.__target===t.__target&&this.__rel===t.__rel&&this.__title===t.__title}};function K$3(t){let n=null;if(Vs(t)){const e=t.textContent;(null!==e&&""!==e||t.children.length>0)&&(n=$$2(t.getAttribute("href")||"",{rel:t.getAttribute("rel"),target:t.getAttribute("target"),title:t.getAttribute("title")}));}return {node:n}}function $$2(t="",e){return zs(new F$4(t,e))}function z$5(t){return t instanceof F$4}let j$5 = class j extends F$4{__isUnlinked;constructor(t="",e={},n){super(t,e,n),this.__isUnlinked=void 0!==e.isUnlinked&&null!==e.isUnlinked&&e.isUnlinked;}afterCloneFrom(t){super.afterCloneFrom(t),this.__isUnlinked=t.__isUnlinked;}static getType(){return "autolink"}static clone(t){return new j(t.__url,{isUnlinked:t.__isUnlinked,rel:t.__rel,target:t.__target,title:t.__title},t.__key)}shouldMergeAdjacentLink(t){return false}getIsUnlinked(){return this.__isUnlinked}setIsUnlinked(t){const e=this.getWritable();return e.__isUnlinked=t,e}createDOM(t){return this.__isUnlinked?document.createElement("span"):super.createDOM(t)}updateDOM(t,e,n){return super.updateDOM(t,e,n)||t.__isUnlinked!==this.__isUnlinked}static importJSON(t){return H$5().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setIsUnlinked(t.isUnlinked||false)}static importDOM(){return null}exportJSON(){return {...super.exportJSON(),isUnlinked:this.__isUnlinked}}insertNewAfter(t,e=true){const n=H$5(this.__url,{isUnlinked:this.__isUnlinked,rel:this.__rel,target:this.__target,title:this.__title});return this.insertAfter(n,e),n}};function H$5(t="",e){return zs(new j$5(t,e))}function G$8(t){return t instanceof j$5}function q$6(t,e){if("element"===t.type){const n=t.getNode();Wi(n)||function(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);throw n.search=r.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(252);return n.getChildren()[t.offset+e]||null}return null}function Q$6(t,e={}){let r;if(t&&"object"==typeof t){const{url:n,...i}=t;r=n,e={...i,...e};}else r=t;const{target:i,title:s}=e,l=void 0===e.rel?"noreferrer":e.rel,a=Qr();if(null===a||!Fr(a)&&!Ir(a))return;if(Ir(a)){const t=a.getNodes();if(0===t.length)return;return void t.forEach(t=>{if(null===r){const e=dl(t,t=>!G$8(t)&&z$5(t));e&&(e.insertBefore(t),0===e.getChildren().length&&e.remove());}else {const e=dl(t,t=>!G$8(t)&&z$5(t));if(e)e.setURL(r),void 0!==i&&e.setTarget(i),void 0!==l&&e.setRel(l);else {const e=$$2(r,{rel:l,target:i});t.insertBefore(e),e.append(t);}}})}if(a.isCollapsed()&&null===r)for(const t of a.getNodes()){const e=dl(t,t=>!G$8(t)&&z$5(t));
9218return void(null!==e&&(e.getChildren().forEach(t=>{e.insertBefore(t);}),e.remove()))}const c=a.extract();if(null===r){const t=new Set;return void c.forEach(e=>{const r=dl(e,t=>!G$8(t)&&z$5(t));if(null!==r){const e=r.getKey();if(t.has(e))return;!function(t,e){const n=new Set(e.filter(e=>t.isParentOf(e)).map(t=>t.getKey())),r=t.getChildren(),i=r=>n.has(r.getKey())||Wi(r)&&e.some(e=>t.isParentOf(e)&&r.isParentOf(e)),s=r.filter(i);if(s.length===r.length)return r.forEach(e=>t.insertBefore(e)),void t.remove();const l=r.findIndex(i),u=r.findLastIndex(i),a=0===l,c=u===r.length-1;if(a)s.forEach(e=>t.insertBefore(e));else if(c)for(let e=s.length-1;e>=0;e--)t.insertAfter(s[e]);else {for(let e=s.length-1;e>=0;e--)t.insertAfter(s[e]);const e=r.slice(u+1);if(e.length>0){const n=Ks(t);s[s.length-1].insertAfter(n),e.forEach(t=>n.append(t));}}}(r,c),t.add(e);}})}const _=new Set,m=t=>{_.has(t.getKey())||(_.add(t.getKey()),t.setURL(r),void 0!==i&&t.setTarget(i),void 0!==l&&t.setRel(l),void 0!==s&&t.setTitle(s));};if(1===c.length){const t=c[0],e=dl(t,z$5);if(null!==e)return m(e)}!function(t){const e=Qr();if(!Fr(e))return t();const n=St$3(e),r=n.isBackward(),i=q$6(n.anchor,r?-1:0),s=q$6(n.focus,r?0:-1);t();if(i||s){const t=Qr();if(Fr(t)){const e=t.clone();if(i){const t=i.getParent();t&&e.anchor.set(t.getKey(),i.getIndexWithinParent()+(r?1:0),"element");}if(s){const t=s.getParent();t&&e.focus.set(t.getKey(),s.getIndexWithinParent()+(r?0:1),"element");}es(St$3(e));}}}(()=>{let t=null;for(const e of c){if(!e.isAttached())continue;const o=dl(e,z$5);if(o){m(o);continue}if(Wi(e)){if(!e.isInline())continue;if(z$5(e)){if(!(G$8(e)||null!==t&&t.getParentOrThrow().isParentOf(e))){m(e),t=e;continue}for(const t of e.getChildren())e.insertBefore(t);e.remove();continue}}const u=e.getPreviousSibling();z$5(u)&&u.is(t)?u.append(e):(t=$$2(r,{rel:l,target:i,title:s}),e.insertAfter(t),t.append(e));}});}const V$6=/^\+?[0-9\s()-]{5,}$/;function X$4(t){return t.match(/^[a-z][a-z0-9+.-]*:/i)||t.match(/^[/#.]/)?t:t.includes("@")?`mailto:${t}`:V$6.test(t)?`tel:${t}`:`https://${t}`} 9219 9220class LinkDropdown extends ToolbarDropdown { 9221 editorReady() { 9222 this.input = this.panel.querySelector("input"); 9223 9224 this.track( 9225 registerEventListener(this.input, "keydown", this.#handleEnter), 9226 registerEventListener(this.linkButton, "click", this.#handleLink), 9227 registerEventListener(this.unlinkButton, "click", this.#handleUnlink) 9228 ); 9229 } 9230 9231 onOpen() { 9232 this.input.value = this.#selectedLinkUrl; 9233 this.input.required = true; 9234 } 9235 9236 onClose() { 9237 this.input.required = false; 9238 } 9239 9240 get linkButton() { 9241 return this.panel.querySelector("[value='link']") 9242 } 9243 9244 get unlinkButton() { 9245 return this.panel.querySelector("[value='unlink']") 9246 } 9247 9248 #handleEnter = (event) => { 9249 if (event.key === "Enter") { 9250 event.preventDefault(); 9251 event.stopPropagation(); 9252 this.#handleLink(event); 9253 } 9254 } 9255 9256 #handleLink = () => { 9257 if (!this.input.checkValidity()) { 9258 this.input.reportValidity(); 9259 return 9260 } 9261 9262 this.editor.dispatchCommand("link", this.input.value); 9263 this.close(); 9264 } 9265 9266 #handleUnlink = () => { 9267 this.editor.dispatchCommand("unlink"); 9268 this.close(); 9269 } 9270 9271 get #selectedLinkUrl() { 9272 return this.editor.getEditorState().read(() => { 9273 const linkNode = this.editorElement.selection.nearestNodeOfType(F$4); 9274 return linkNode?.getURL() ?? "" 9275 }) 9276 } 9277} 9278 9279/** 9280 * Copyright (c) Meta Platforms, Inc. and affiliates. 9281 * 9282 * This source code is licensed under the MIT license found in the 9283 * LICENSE file in the root directory of this source tree. 9284 * 9285 */ 9286 9287function q$5(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function G$7(e){let t=1,n=e.getParent();for(;null!=n;){if(pe$2(n)){const e=n.getParent();if(Se$1(e)){t++,n=e.getParent();continue}q$5(40);}return t}return t}function Q$5(e){let t=e.getParent();Se$1(t)||q$5(40);let n=t;for(;null!==n;)n=n.getParent(),Se$1(n)&&(t=n);return t}function Y$2(e){let t=[];const n=e.getChildren().filter(pe$2);for(let e=0;e<n.length;e++){const r=n[e],i=r.getFirstChild();Se$1(i)?t=t.concat(Y$2(i)):t.push(r);}return t}function Z$3(e){return pe$2(e)&&Se$1(e.getFirstChild())}function ee$1(e){return fe$2().append(e)}function te$2(e,t){return pe$2(e)&&(0===t.length||1===t.length&&e.is(t[0])&&0===e.getChildrenSize())}function ne$2(e){const t=Qr();if(null!==t){let n=t.getNodes();if(Fr(t)){const r=t.getStartEndPoints();null===r&&q$5(143);const[i]=r,s=i.getNode(),o=s.getParent();if(Is(s)){const e=s.getFirstChild();if(e)n=e.selectStart().getNodes();else {const e=eo();s.append(e),n=e.select().getNodes();}}else if(te$2(s,n)){const t=Te$1(e);if(Is(o)){s.replace(t);const e=fe$2();Wi(s)&&(e.setFormat(s.getFormatType()),e.setIndent(s.getIndent())),t.append(e);}else if(pe$2(s)){const e=s.getParentOrThrow();re$3(t,e.getChildren()),e.replace(t);}return}}const r=new Set;for(let t=0;t<n.length;t++){const i=n[t];if(Wi(i)&&i.isEmpty()&&!pe$2(i)&&!r.has(i.getKey())){ie$2(i,e);continue}let s=Wo(i)?i.getParent():pe$2(i)&&i.isEmpty()?i:null;for(;null!=s;){const t=s.getKey();if(Se$1(s)){if(!r.has(t)){const n=Te$1(e);re$3(n,s.getChildren()),s.replace(n),r.add(t);}break}{const n=s.getParent();if(Is(n)&&!r.has(t)){r.add(t),ie$2(s,e);break}s=n;}}}}}function re$3(e,t){e.splice(e.getChildrenSize(),0,t);}function ie$2(e,t){if(Se$1(e))return e;const n=e.getPreviousSibling(),r=e.getNextSibling(),i=fe$2();let s;if(re$3(i,e.getChildren()),Se$1(n)&&t===n.getListType())n.append(i),Se$1(r)&&t===r.getListType()&&(re$3(n,r.getChildren()),r.remove()),s=n;else if(Se$1(r)&&t===r.getListType())r.getFirstChildOrThrow().insertBefore(i),s=r;else {const n=Te$1(t);n.append(i),e.replace(n),s=n;}i.setFormat(e.getFormatType()),i.setIndent(e.getIndent());const o=Qr();return Fr(o)&&(s.getKey()===o.anchor.key&&o.anchor.set(i.getKey(),o.anch
9287or.offset,"element"),s.getKey()===o.focus.key&&o.focus.set(i.getKey(),o.focus.offset,"element")),e.remove(),s}function se$3(e,t){const n=e.getLastChild(),r=t.getFirstChild();n&&r&&Z$3(n)&&Z$3(r)&&(se$3(n.getFirstChild(),r.getFirstChild()),r.remove());const i=t.getChildren();i.length>0&&e.append(...i),t.remove();}function oe$3(){const e=Qr();if(Fr(e)){const t=new Set,r=e.getNodes(),i=e.anchor.getNode();if(te$2(i,r))t.add(Q$5(i));else for(let e=0;e<r.length;e++){const i=r[e];if(Wo(i)){const e=At$2(i,ge$2);null!=e&&t.add(Q$5(e));}}for(const n of t){let t=n;const r=Y$2(n);for(const n of r){const r=eo().setTextStyle(e.style).setTextFormat(e.format);re$3(r,n.getChildren()),t.insertAfter(r),t=r,n.__key===e.anchor.key&&Hl(e.anchor,rc(Pl(r,"next"))),n.__key===e.focus.key&&Hl(e.focus,rc(Pl(r,"next"))),n.remove();}n.remove();}}}function le$2(e){const t="check"!==e.getListType();let n=e.getStart();for(const r of e.getChildren())pe$2(r)&&(r.getValue()!==n&&r.setValue(n),t&&null!=r.getLatest().__checked&&r.setChecked(void 0),Se$1(r.getFirstChild())||n++);}function ce$2(e){const t=new Set;if(Z$3(e)||t.has(e.getKey()))return;const n=e.getParent(),r=e.getNextSibling(),i=e.getPreviousSibling();if(Z$3(r)&&Z$3(i)){const n=i.getFirstChild();if(Se$1(n)){n.append(e);const i=r.getFirstChild();if(Se$1(i)){re$3(n,i.getChildren()),r.remove(),t.add(r.getKey());}}}else if(Z$3(r)){const t=r.getFirstChild();if(Se$1(t)){const n=t.getFirstChild();null!==n&&n.insertBefore(e);}}else if(Z$3(i)){const t=i.getFirstChild();Se$1(t)&&t.append(e);}else if(Se$1(n)){const t=Ks(e),s=Ks(n);t.append(s),s.append(e),i?i.insertAfter(t):r?r.insertBefore(t):n.append(t);}}function ae$2(e){if(Z$3(e))return;const t=e.getParent(),n=t?t.getParent():void 0;if(Se$1(n?n.getParent():void 0)&&pe$2(n)&&Se$1(t)){const r=t?t.getFirstChild():void 0,i=t?t.getLastChild():void 0;if(e.is(r))n.insertBefore(e),t.isEmpty()&&n.remove();else if(e.is(i))n.insertAfter(e),t.isEmpty()&&n.remove();else {const r=Ks(e),i=Ks(t);
9287r.append(i),e.getPreviousSiblings().forEach(e=>i.append(e));const s=Ks(e),o=Ks(t);s.append(o),re$3(o,e.getNextSiblings()),n.insertBefore(r),n.insertAfter(s),n.replace(e);}}}function ue$2(e=false){const t=Qr();if(!Fr(t)||!t.isCollapsed())return false;const n=t.anchor.getNode();let r=null;if(pe$2(n)&&0===n.getChildrenSize())r=n;else if(Tr(n)){const e=n.getParent();pe$2(e)&&e.getChildren().every(e=>Tr(e)&&""===e.getTextContent().trim())&&(r=e);}if(null===r)return false;const i=Q$5(r),s=r.getParent();Se$1(s)||q$5(40);const o=s.getParent();let l;if(Is(o))l=eo(),i.insertAfter(l);else {if(!pe$2(o))return false;l=Ks(o),o.insertAfter(l);}l.setTextStyle(t.style).setTextFormat(t.format).select();const c=r.getNextSiblings();if(c.length>0){const t=e?function(e,t){return e.getStart()+t.getIndexWithinParent()}(s,r):1,n=Ks(s).setStart(t);if(pe$2(l)){const e=Ks(l);e.append(n),l.insertAfter(e);}else l.insertAfter(n);n.append(...c);}return function(e){let t=e;for(;null==t.getNextSibling()&&null==t.getPreviousSibling();){const e=t.getParent();if(null==e||!pe$2(e)&&!Se$1(e))break;t=e;}t.remove();}(r),true}let ge$2 = class ge extends Bi{__value;__checked;$config(){return this.config("listitem",{$transform:e=>{const t=e.getParent();if(Se$1(t))"check"!==t.getListType()&&null!=e.getChecked()&&e.setChecked(void 0);else if(t){const n=e.createParentElementNode();Se$1(n)||q$5(340);const i=[e];for(const t of ["previous","next"]){i.reverse();for(const{origin:n}of Ol(e,t)){if(!pe$2(n))break;i.push(n);}}e.insertBefore(n),n.splice(0,0,i),Is(t)||(Rt$3(n,Zl(Ol(n,"next")),{$shouldSplit:()=>false,removeEmptyDestination:true}),t.isEmpty()&&t.isAttached()&&t.remove());}},extends:Bi,importDOM:In({li:()=>({conversion:he$2,priority:0})})})}constructor(e=1,t=void 0,n){super(n),this.__value=void 0===e?1:e,this.__checked=t;}afterCloneFrom(e){super.afterCloneFrom(e),this.__value=e.__value,this.__checked=e.__checked;}createDOM(e){const t=document.createElement("li");return this.updateListItemDOM(null,t,e),t}updateListItemDOM(e,t,n){!function(e,t,n){const r=t.getParent();!Se$1(r)||"check"!==r.getListType()||Se$1(t.getFirstChild())?(e.removeAttribute("role"),e.removeAttribute("tabIndex"),e.removeAttribute("aria-checked")):(e.setAttribute("role","checkbox"),e.setAttribute("tabIndex","-1"),n&&t.__checked===n.__checked||e.setAttribute("aria-checked",t.getChecked()?"true":"false"));}(t,this,e),t.value=this.__value,function(e,t,n){const r=[],o=[],l=t.list,c=l?l.listitem:void 0;let a;l&&l.nested&&(a=l.nested.listitem);void 0!==c&&r.push(...yc(c));if(l){const e=n.getParent(),t=Se$1(e)&&"check"===e.getListType(),i=n.getChecked();t&&!i||o.push(l.listitemUnchecked),t&&i||o.push(l.listitemChecked),t&&r.push(i?l.listitemChecked:l.listitemUnchecked);}if(void 0!==a){const e=yc(a);n.getChildren().some(e=>Se$1(e))?r.push(...e):o.push(...e);}o.length>0&&xc(e,...o);r.length>0&&mc(e,...r);}(t,n.theme,this);const r=e?e.__style:"",o=this.__style;r!==o&&nr(t.style,o,r),function(e,t,n){const r=t.__textStyle,i=n?n.__textStyle:"";if(null!==n&&i===r)return;const s=Zn(r);for(const t in s)e.style.setProperty(`--listitem-marker-${t}`,s[t]);if(""!==i)for(const t in Zn(i))t in s||e.style.removeProperty(`--listitem-marker-${t}`);}(t,this,e);}updateDOM(e,t,n){const r=t;return this.updateListItemDOM(e,r,n),false}updateFromJSON(e){return super.updateFromJSON(e).setValue(e.value).setChecked(e.checked)}exportDOM(e){const t=this.createDOM(e._config),n=this.getFormatType();n&&(t.style.textAlign=n);const r=this.getDirection();return r&&(t.dir=r),Z$3(this)?{after(e){if(Ys(e)){const t=e.previousElementSibling;if(Ys(t)&&"LI"===t.nodeName){for(;e.firstChild;)t.append(e.firstChild);e.remove();}}return e},element:t}:{element:t}}exportJSON(){return {...super.exportJSON(),checked:this.getChecked(),value:this.getValue()}}append(...e){for(let t=0;t<e.length;t++){const n=e[t];if(Wi(n)&&this.canMergeWith(n)){const e=n.getChildren();this.append(...e),n.remove();}else super.append(n);}return this}replace(e,t){if(pe$2(e))return super.replace(e);this.setIndent(0);const n=this.getParentOrThrow();if(!Se$1(n))return e;if(n.__first===this.getKey())n.insertBefore(e);else if(n.__last===this.getKey())n.insertAfter(e);else {const t=Ks(n);let r=this.getNextSibling();for(;r;){const e=r;r=r.getNextSibling(),t.append(e);}n.insertAfter(e),e.insertAfter(t);}
9287return t&&(Wi(e)||q$5(139),this.getChildren().forEach(t=>{e.append(t);})),this.remove(),0===n.getChildrenSize()&&n.remove(),e}insertAfter(e,t=true){const n=this.getParentOrThrow();if(Se$1(n)||q$5(39),pe$2(e))return super.insertAfter(e,t);const r=this.getNextSiblings();if(n.insertAfter(e,t),0!==r.length){const i=Ks(n);r.forEach(e=>i.append(e)),e.insertAfter(i,t);}return e}remove(e){const t=this.getPreviousSibling(),n=this.getNextSibling();super.remove(e),t&&n&&Z$3(t)&&Z$3(n)&&(se$3(t.getFirstChild(),n.getFirstChild()),n.remove());}resetOnCopyNodeFrom(e){super.resetOnCopyNodeFrom(e),e.getChecked()&&this.setChecked(false);}insertNewAfter(e,t=true){const n=Ks(this);return this.insertAfter(n,t),n}collapseAtStart(e){const t=eo();this.getChildren().forEach(e=>t.append(e));const n=this.getParentOrThrow(),r=n.getParentOrThrow(),i=pe$2(r);if(1===n.getChildrenSize())if(i)n.remove(),r.select();else {n.insertBefore(t),n.remove();const r=e.anchor,i=e.focus,s=t.getKey();"element"===r.type&&r.getNode().is(this)&&r.set(s,r.offset,"element"),"element"===i.type&&i.getNode().is(this)&&i.set(s,i.offset,"element");}else n.insertBefore(t),this.remove();return true}getValue(){return this.getLatest().__value}setValue(e){const t=this.getWritable();return t.__value=e,t}getChecked(){const e=this.getLatest();let t;const n=this.getParent();return Se$1(n)&&(t=n.getListType()),"check"===t?Boolean(e.__checked):void 0}setChecked(e){const t=this.getWritable();return t.__checked=e,t}toggleChecked(){const e=this.getWritable();return e.setChecked(!e.__checked)}getIndent(){const e=this.getParent();if(null===e||!this.isAttached())return this.getLatest().__indent;let t=e.getParentOrThrow(),n=0;for(;pe$2(t);)t=t.getParentOrThrow().getParentOrThrow(),n++;return n}setIndent(e){"number"!=typeof e&&q$5(117),(e=Math.floor(e))>=0||q$5(199);let t=this.getIndent();for(;t!==e;)t<e?(ce$2(this),t++):(ae$2(this),t--);return this}canInsertAfter(e){return pe$2(e)}canReplaceWith(e){return pe$2(e)}canMergeWith(e){return pe$2(e)||no(e)}extractWithChild(e,t){if(!Fr(t))return false;const n=t.anchor.getNode(),r=t.focus.getNode();return this.isParentOf(n)&&this.isParentOf(r)&&this.getTextContent().length===t.getTextContent().length}isParentRequired(){return true}createParentElementNode(){return Te$1("bullet")}canMergeWhenEmpty(){return true}};function he$2(e){if(e.classList.contains("task-list-item"))for(const t of e.children)if("INPUT"===t.tagName)return de$2(t);if(e.classList.contains("joplin-checkbox"))for(const t of e.children)if(t.classList.contains("checkbox-wrapper")&&t.children.length>0&&"INPUT"===t.children[0].tagName)return de$2(t.children[0]);const t=e.getAttribute("aria-checked");return {node:fe$2("true"===t||"false"!==t&&void 0)}}function de$2(e){if(!("checkbox"===e.getAttribute("type")))return {node:null};return {node:fe$2(e.hasAttribute("checked"))}}function fe$2(e){return zs(new ge$2(void 0,e))}function pe$2(e){return e instanceof ge$2}let me$2 = class me extends Bi{__tag;__start;__listType;$config(){return this.config("list",{$transform:e=>{!function(e){const t=e.getNextSibling();Se$1(t)&&e.getListType()===t.getListType()&&se$3(e,t);}(e),le$2(e);},extends:Bi,importDOM:In({ol:()=>({conversion:ye$1,priority:0}),ul:()=>({conversion:ye$1,priority:0})})})}constructor(e="number",t=1,n){super(n);const r=ve$1[e]||e;this.__listType=r,this.__tag="number"===r?"ol":"ul",this.__start=t;}afterCloneFrom(e){super.afterCloneFrom(e),this.__listType=e.__listType,this.__tag=e.__tag,this.__start=e.__start;}getTag(){return this.getLatest().__tag}setListType(e){const t=this.getWritable();return t.__listType=e,t.__tag="number"===e?"ol":"ul",t}getListType(){return this.getLatest().__listType}getStart(){return this.getLatest().__start}setStart(e){const t=this.getWritable();return t.__start=e,t}createDOM(e,t){const n=this.__tag,r=document.createElement(n);return 1!==this.__start&&r.setAttribute("start",String(this.__start)),r.__lexicalListType=this.__listType,_e$1(r,e.theme,this),r}updateDOM(e,t,n){return e.__tag!==this.__tag||e.__listType!==this.__listType||(_e$1(t,n.theme,this),e.__start!==this.__start&&t.setAttribute("start",String(this.__start)),false)}updateFromJSON(e){return super.updateFromJSON(e).setListType(e.listType).setStart(e.start)}exportDOM(e){const t=this.createDOM(e._config,e);return Ys(t)&&(1!==this.__start&&t.setAttribute("start",String(this.__start)),"check"===this.__listType&&t.setAttribute("__lexicalListType","check")),{element:t}}exportJSON(){return {...super.exportJSON(),listType:this.getListType(),start:this.getStart(),tag:this.getTag()}}canBeEmpty(){return false}canIndent(){return false}splice(e,t,n){const r=n.find(pe$2)??this.getChildren().find(pe$2),i=r?()=>Ks(r):fe$2;let s=n;for(let e=0;e<n.length;e++){const t=n[e];pe$2(t)||(s===n&&(s=[...n]),s[e]=i().append(!Wi(t)||Se$1(t)||t.isInline()?t:kr(t.getTextContent())));}return super.splice(e,t,s)}extractWithChild(e){return pe$2(e)}};
9287function _e$1(e,t,n){const r=[],o=[],l=t.list;if(void 0!==l){const e=l[`${n.__tag}Depth`]||[],t=G$7(n)-1,i=t%e.length,s=e[i],c=l[n.__tag];let a;const u=l.nested,g=l.checklist;if(void 0!==u&&u.list&&(a=u.list),void 0!==c&&r.push(c),void 0!==g&&"check"===n.__listType&&r.push(g),void 0!==s){r.push(...yc(s));for(let t=0;t<e.length;t++)t!==i&&o.push(n.__tag+t);}if(void 0!==a){const e=yc(a);t>1?r.push(...e):o.push(...e);}}o.length>0&&xc(e,...o),r.length>0&&mc(e,...r);}function Ce$1(e){const t=[];for(let n=0;n<e.length;n++){const r=e[n];if(pe$2(r)){t.push(r);const e=r.getChildren();e.length>1&&e.forEach(e=>{Se$1(e)&&t.push(ee$1(e));});}else t.push(ee$1(r));}return t}function ye$1(e){const t=e.nodeName.toLowerCase();let n=null;if("ol"===t){n=Te$1("number",e.start);}else "ul"===t&&(n=function(e){if("check"===e.getAttribute("__lexicallisttype")||e.classList.contains("contains-task-list")||"1"===e.getAttribute("data-is-checklist"))return true;for(const t of e.childNodes)if(Ys(t)&&t.hasAttribute("aria-checked"))return true;return false}(e)?Te$1("check"):Te$1("bullet"));return {after:Ce$1,node:n}}const ve$1={ol:"number",ul:"bullet"};function Te$1(e="number",t=1){return zs(new me$2(e,t))}function Se$1(e){return e instanceof me$2}const Fe$1=re$5("UPDATE_LIST_START_COMMAND"),Ee$2=re$5("INSERT_UNORDERED_LIST_COMMAND"),Oe$1=re$5("INSERT_ORDERED_LIST_COMMAND"),Ae$2=re$5("REMOVE_LIST_COMMAND");function Ie$2(e,t){return Cc(e.registerCommand(Oe$1,()=>(ne$2("number"),true),io),e.registerCommand(Fe$1,e=>{const{listNodeKey:t,newStart:n}=e,r=Yo(t);return !!Se$1(r)&&("number"===r.getListType()&&(r.setStart(n),le$2(r)),true)},io),e.registerCommand(Ee$2,()=>(ne$2("bullet"),true),io),e.registerCommand(Ae$2,()=>(oe$3(),true),io),e.registerCommand(he$3,()=>ue$2(false),io),e.registerNodeTransform(ge$2,e=>{const t=e.getFirstChild();if(t){if(Tr(t)){const n=t.getStyle(),r=t.getFormat();e.getTextStyle()!==n&&e.setTextStyle(n),e.getTextFormat()!==r&&e.setTextFormat(r);}}else {const t=Qr();Fr(t)&&(t.style!==e.getTextStyle()||t.format!==e.getTextFormat())&&t.isCollapsed()&&e.is(t.anchor.getNode())&&e.setTextStyle(t.style).setTextFormat(t.format);}}),e.registerNodeTransform(gr,e=>{const t=e.getParent();if(pe$2(t)&&e.is(t.getFirstChild())){const n=e.getStyle(),r=e.getFormat();n===t.getTextStyle()&&r===t.getTextFormat()||t.setTextStyle(n).setTextFormat(r);}}))} 9288 9289/** 9290 * Copyright (c) Meta Platforms, Inc. and affiliates. 9291 * 9292 * This source code is licensed under the MIT license found in the 9293 * LICENSE file in the root directory of this source tree. 9294 * 9295 */ 9296 9297function D$1(t,...n){const e=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",t);for(const t of n)o.append("v",t);throw e.search=o.toString(),Error(`Minified Lexical error #${t}; visit ${e.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}let C$3;function A$1(t,n){const{key:e}=n;return t&&e in t?t[e]:n.defaultValue}function E$2(t){return C$3&&C$3.editor===t?C$3:void 0}function N$2(t,n){if("cfg"in n){const{cfg:e,updater:o}=n;return [e,o(A$1(t,e))]}return n}function P$2(t,n){let e=n;for(const o of t){const[t,r]=N$2(e,o),c=t.key;if(e===n&&A$1(e,t)===r)continue;const s=e||T$1(n);s[c]=r,e=s;}return e}function T$1(t){return Object.create(t||null)}function j$4(t,n){return [t,n]}const L$4="@lexical/html/DOM",F$3=Symbol.for("@lexical/html/DOMExportContext"),I$4=()=>true;function R$2(t){return n=>n instanceof t}function W$4(t,{nodes:n}){if("*"===n)return I$4;let e={};const o=[];for(const r of n)if("getType"in r){const n=r.getType();if(e){const o=t[n];void 0===o&&D$1(339,r.name,n),e=Object.assign(e,o.types);}o.push(R$2(r));}else e=void 0,o.push(r);return e||(1===o.length?o[0]:t=>{for(const n of o)if(n(t))return true;return false})}function q$4(t){return (n,e,o)=>t(n,o)}function B$4(t){return (n,e,o,r)=>t(n,e,r)}function U$4(t){return (n,e,o,r,c)=>t(n,e,o,c)}function V$5(t){return (n,e,o,r,c,s)=>t(n,e,o,r,s)}function H$4(t,n){return (e,o)=>{const r=()=>t(e,o),c=n(e);return c?c(e,r,o):r()}}function Y$1(t,n){return (e,o,r)=>{const c=()=>t(e,o,r),s=n(e);return s?s(e,o,c,r):c()}}function _$2(t,n){return (e,o,r,c)=>{const s=()=>t(e,o,r,c),u=n(e);return u?u(e,o,r,s,c):s()}}function z$4(t,n){return (e,o,r,c,s)=>{const u=()=>t(e,o,r,c,s),i=n(e);return i?i(e,o,r,c,u,s):u()}}function G$6(t,n){return (e,o,r,c)=>{t(e,o,r,c);const s=n(e);s&&s(e,o,r,c);}}function J$5(t,n,e,o,r){let c=e[n];for(const e of t[n])if("function"==typeof e[0]){const[t,n]=e;c=o(c,e=>t(e)&&n||void 0);}else {const t=e[1],n={};for(const e in t){const r=t[e];r&&(n[e]=r.reduce((t,n)=>o(t,()=>n),c));}c=o(c,t=>{const e=n[t.getType()];return e&&r(e)});}e[n]=c;}function K$2(t,n,e,o){if(!o)return;const r=t[n];if("function"==typeof e)r.push([e,o]);else {const t=r[r.length-1];let n;t&&"types"===t[0]?n=t[1]:(n={},r.push(["types",n]));for(const t in e){const e=n[t]||[];n[t]=e,e.push(o);}}
9297}function Q$4(t){return "*"===t.nodes}function X$3(t,n){const e=function(t){const n={},{nodes:e}=Ct$1(t);for(const t of e)n[t.getType()]={klass:t,types:{}};for(const t of Object.values(n))if(t){const e=t.klass.getType();for(let{klass:o}=t;Bn(o.prototype);o=Object.getPrototypeOf(o)){const{ownNodeType:t}=ul(o),r=t&&n[t];r&&(r.types[e]=true);}}return n}(t),o={$createDOM:[],$decorateDOM:[],$exportDOM:[],$extractWithChild:[],$getDOMSlot:[],$shouldExclude:[],$shouldInclude:[],$updateDOM:[]};for(const t of function(t){const n=[],e=[],o=[];for(const c of t)if(Q$4(c))n.push(c);else if(Array.isArray(c.nodes))for(const t of c.nodes)Bn(t.prototype)?o.push(1===c.nodes.length?c:{...c,nodes:[t]}):e.push(1===c.nodes.length?c:{...c,nodes:[t]});const c=new Map,s=t=>{let n=c.get(t);if(void 0===n){n=0;for(let e=t;Bn(e.prototype);e=Object.getPrototypeOf(e))n++;c.set(t,n);}return n};return o.sort((t,n)=>s(t.nodes[0])-s(n.nodes[0])),[...o,...e,...n]}(n)){const n=W$4(e,t);for(const e in o){K$2(o,e,n,t[e]);}}return o}function Z$2(t){return t}const tt$2=dc({build:(t,n,e)=>({defaults:P$2(n.contextDefaults,void 0)}),config:{contextDefaults:[],overrides:[]},html:{export:new Map([[Ui,()=>{const t=document.createElement("div");return t.role="textbox",{element:t}}]])},init(t,n){t.dom=function(t,{overrides:n}){const e=X$3(t,n),r={...po,...t.dom};return J$5(e,"$createDOM",r,H$4,q$4),J$5(e,"$exportDOM",r,H$4,q$4),J$5(e,"$extractWithChild",r,z$4,V$5),J$5(e,"$getDOMSlot",r,Y$1,B$4),J$5(e,"$shouldExclude",r,Y$1,B$4),J$5(e,"$shouldInclude",r,Y$1,B$4),J$5(e,"$updateDOM",r,_$2,U$4),J$5(e,"$decorateDOM",r,G$6,Z$2),r}(t,n);},mergeConfig(t,n){const e=pc(t,n);for(const o of ["overrides","contextDefaults"])n[o]&&(e[o]=[...t[o],...n[o]]);return e},name:L$4});function nt$2(t,n,o){return function(t,n,o,r){return Object.assign(ot$3(Symbol(n),{isEqual:r,parse:o}),{[t]:true})}(F$3,t,n,o)}nt$2("root",Boolean);const ot$1=nt$2("isExport",Boolean);function rt$2(t){const n=de$3.maybeFromEditor(t);return n&&n.hasExtensionByName(L$4)?ue$3(t,tt$2).output.defaults:void 0}const ut$1=function(t,e=()=>{}){return (o,r=Zs())=>c=>{const s=E$2(r),u=s&&s[t],i=P$2(o,u||e(r));return i&&i!==u?function(t,e,o,r=Zs()){const c=C$3,s=E$2(r);try{return C$3={...s,editor:r,[t]:e},o()}finally{C$3=c;}}(t,i,c,r):c()}}(F$3,rt$2);function lt(t){return t.constructor.name===CSSStyleRule.name}const ft=new Set(["STYLE","SCRIPT"]);function dt$1(t,n){zo(n)&&function(t){if(null===t.querySelector("style"))return;const n=new Map;function e(t){let e=n.get(t);if(void 0===e){e=new Set;for(let n=0;n<t.style.length;n++)e.add(t.style[n]);n.set(t,e);}return e}try{for(const n of Array.from(t.styleSheets)){let o;try{o=n.cssRules;}catch(t){continue}for(const n of Array.from(o)){if(!lt(n))continue;let o;try{o=t.querySelectorAll(n.selectorText);}catch(t){continue}for(const t of Array.from(o)){if(!Ys(t))continue;const o=e(t);for(let e=0;e<n.style.length;e++){const r=n.style[e];o.has(r)||t.style.setProperty(r,n.style.getPropertyValue(r),n.style.getPropertyPriority(r));}}}}}catch(t){}}(n);const e=zo(n)?n.body.childNodes:n.childNodes,o=[],r=[];for(const n of e)if(!ft.has(n.nodeName)){const e=gt$1(n,t,r,false);if(null!==e)for(const t of e)o.push(t);}return function(t){for(const n of t)n.getParent()&&n.getNextSibling()instanceof Qi&&n.insertAfter(or());for(const n of t){const t=n.getParent();t&&t.splice(n.getIndexWithinParent(),1,n.getChildren());}}(r),o}function at$1(t,e=null,o=Zs()){return ut$1([j$4(ot$1,true)],o)(()=>{const n=Zo(),r=tl(o),c=t.append.bind(t);for(const t of n.getChildren())yt$3(o,t,c,e,r);return t})}function ht$1(t,n=null){return ("undefined"==typeof document||"undefined"==typeof window&&void 0===global.window)&&D$1(338),at$1(document.createElement("div"),n,t).innerHTML}function yt$3(n,e,o,r=null,c=tl(n)){let s=c.$shouldInclude(e,r,n);const u=c.$shouldExclude(e,r,n);let i=e;null!==r&&Tr(e)&&(i=R$3(r,e,"clone"));const l=c.$exportDOM(i,n),{element:d,after:g,append:m,$getChildNodes:x}=l;if(!d)return false;const v=document.createDocumentFragment(),$=x?x():Wi(i)?i.getChildren():[],b=v.append.bind(v);for(const t of $){const o=yt$3(n,t,b,r,c);!s&&o&&c.$extractWithChild(e,t,r,"html",n)&&(s=true);}if(s&&!u){if((Ys(d)||Hs(d))&&(m?m(v):d.append(v)),o(d),g){const t=g.call(i,d);t&&(Hs(d)?d.replaceChildren(t):d.replaceWith(t));}}else o(v);return s}function gt$1(t,n,e,o,r=new Map,c){const s=[];if(ft.has(t.nodeName))return s;let u=null;const i=function(t,n){const{nodeName:e}=t,o=n._htmlConversions.get(e.toLowerCase());let r=null;if(void 0!==o)for(const n of o){const e=n(t);null!==e&&(null===r||(r.priority||0)<=(e.priority||0))&&(r=e);}return null!==r?r.conversion:null}(t,n),l=i?i(t):null;let f=null;if(null!==l){f=l.after;const n=l.node;if(u=Array.isArray(n)?n[n.length-1]:n,null!==u){for(const[,t]of r)if(u=t(u,c),!u)break;u&&s.push(...Array.isArray(n)?n:[u]);}null!=l.forChild&&r.set(t.nodeName,l.forChild);}const d=t.childNodes;let a=[];const h=(null==u||!Is(u))&&(null!=u&&Vr(u)||o);for(let t=0;t<d.length;t++)a.push(...gt$1(d[t],n,e,h,new Map(r),u));if(null!=f&&(a=f(a)),Xs(t)&&(a=mt$2(t,a,h?()=>{const t=new Qi;return e.push(t),t}:eo)),null==u)if(a.length>0)for(const t of a)s.push(t);else Xs(t)&&function(t){if(null==t.nextSibling||null==t.previousSibling)return false;return Gs(t.nextSibling)&&Gs(t.previousSibling)}(t)&&s.push(or());else Wi(u)&&u.append(...a);return s}function mt$2(t,n,e){const o=t.style.textAlign,r=[];let c=[];for(let t=0;t<n.length;t++){const s=n[t];if(Vr(s))o&&!s.getFormat()&&s.setFormat(o),r.push(s);else if(c.push(s),t===n.length-1||t<n.length-1&&Vr(n[t+1])){const t=e();t.setFormat(o),t.append(...c),r.push(t),c=[];}}return r} 9298 9299/** 9300 * Copyright (c) Meta Platforms, Inc. and affiliates. 9301 * 9302 * This source code is licensed under the MIT license found in the 9303 * LICENSE file in the root directory of this source tree. 9304 * 9305 */ 9306 9307function _$1(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);throw n.search=r.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function J$4(t,e=Qr()){return null==e&&_$1(166),Fr(e)&&e.isCollapsed()||0===e.getNodes().length?"":ht$1(t,e)}function L$3(t,e=Qr()){return null==e&&_$1(166),Fr(e)&&e.isCollapsed()||0===e.getNodes().length?null:JSON.stringify(X$2(t,e))}function j$3(t,e){const n=t.getData("text/plain")||t.getData("text/uri-l
9307ist");null!=n&&e.insertRawText(n);}function I$3(t,e,n){const o=t.getData("application/x-lexical-editor");if(o)try{const t=JSON.parse(o);if(t.namespace===n._config.namespace&&Array.isArray(t.nodes)){return z$3(n,Y(t.nodes),e)}}catch(t){console.error(t);}const i=t.getData("text/html"),l=t.getData("text/plain");if(i&&l!==i)try{const t=(new DOMParser).parseFromString(function(t){if(window.trustedTypes&&window.trustedTypes.createPolicy){return window.trustedTypes.createPolicy("lexical",{createHTML:t=>t}).createHTML(t)}return t}(i),"text/html");return z$3(n,dt$1(n,t),e)}catch(t){console.error(t);}const u=l||t.getData("text/uri-list");if(null!=u)if(Fr(e)){const t=u.split(/(\r?\n|\t)/);""===t[t.length-1]&&t.pop();for(let e=0;e<t.length;e++){const n=Qr();if(Fr(n)){const r=t[e];"\n"===r||"\r\n"===r?n.insertParagraph():"\t"===r?n.insertNodes([wr()]):n.insertText(r);}}}else e.insertRawText(u);}const k$2="application/x-lexical-drag";function B$3(t,e){const n={editorKey:e.getKey()};t.setData(k$2,JSON.stringify(n));}function H$3(t){const e=function(t,e){if(void 0!==document.caretRangeFromPoint){const n=document.caretRangeFromPoint(t,e);return null===n?null:{node:n.startContainer,offset:n.startOffset}}if("undefined"!==document.caretPositionFromPoint){const n=document.caretPositionFromPoint(t,e);return null===n?null:{node:n.offsetNode,offset:n.offset}}return null}(t.clientX,t.clientY);if(null===e)return null;const n=Go(e.node);if(null===n)return null;if(Tr(n))return Ml(n,"next",e.offset);if(Wi(n))return lc(n,e.offset,"next");const r=n.getParent();return null===r?null:lc(r,n.getIndexWithinParent()+1,"next")}function U$3(t,e,n){const r=t.dataTransfer;if(null===r)return false;const o=function(t){const e=t.getData(k$2);if(!e)return null;let n;try{n=JSON.parse(e);}catch(t){return null}return null!==(r=n)&&"object"==typeof r&&"editorKey"in r&&"string"==typeof r.editorKey?n:null;var r;}(r);if(null===o)return false;const i=H$3(t);if(null===i)return false;const l=fc(i);if(null===l)return false;const a=o.editorKey===e.getKey(),u=Qr();if(a){if(!Fr(u)||u.isCollapsed())return false;if(function(t,e){const{anchor:n,focus:r}=sc(Ql(e),"next");return Jl(n,t)<0&&Jl(t,r)<0}(i,u))return t.preventDefault(),true;u.removeText();}if(!l.origin.isAttached())return t.preventDefault(),true;if(n(r,Gl(Bl(l)),e),!a){const t=e.getRootElement(),n=t?t.ownerDocument:null,r=n?function(t,e){const n=e.querySelectorAll('[data-lexical-editor="true"]');for(const e of Array.from(n)){const n=e.__lexicalEditor;if(n&&n.getKey()===t)return e}return null}(o.editorKey,n):null;null!==r&&r.dispatchEvent(new InputEvent("beforeinput",{bubbles:true,cancelable:true,inputType:"deleteByDrag"}));}return t.preventDefault(),true}function W$3(t,e){return U$3(t,e,I$3)}function q$3(t,e){return U$3(t,e,(t,e)=>j$3(t,e))}function z$3(t,e,n){t.dispatchCommand(oe$6,{nodes:e,selection:n})||(n.insertNodes(e),function(t){if(Fr(t)&&t.isCollapsed()){const e=t.anchor;let n=null;const r=ql(e,"previous");if(r)if(vl(r))n=r.origin;else {const t=Wl(r,Pl(Zo(),"next").getFlipped());for(const e of t){if(Tr(e.origin)){n=e.origin;break}if(Wi(e.origin)&&!e.origin.isInline())break}}if(n&&Tr(n)){const e=n.getFormat(),r=n.getStyle();t.format===e&&t.style===r||(t.format=e,t.style=r,t.dirty=true);}}}(n));}function G$5(t,e,n,r=[]){let o=null===e||n.isSelected(e);const l=Wi(n)&&n.excludeFromCopy("html");let c=n;null!==e&&Tr(c)&&(c=R$3(e,c,"clone"));const s=Wi(c)?c.getChildren():[],a=function(t){const e=t.exportJSON(),n=t.constructor;if(e.type!==n.getType()&&_$1(58,n.name),Wi(t)){const t=e.children;Array.isArray(t)||_$1(59,n.name);}return e}(c);Tr(c)&&0===c.getTextContentSize()&&(o=false);for(let r=0;r<s.length;r++){const i=s[r],l=G$5(t,e,i,a.children);!o&&Wi(n)&&l&&n.extractWithChild(i,e,"clone")&&(o=true);}if(o&&!l)r.push(a);else if(Array.isArray(a.children))for(let t=0;t<a.children.length;t++){const e=a.children[t];r.push(e);}return o}function X$2(t,e){const n=[],r=Zo().getChildren();for(let o=0;o<r.length;o++){G$5(t,e,r[o],n);}return {namespace:t._config.namespace,nodes:n}}function Y(t){const e=[];for(let n=0;n<t.length;n++){const r=t[n],i=Ei(r);e.push(i);}return e}let Q$3=null;async function V$4(t,e,n){if(null!==Q$3)return false;if(null!==e)return new Promise((r,o)=>{t.update(()=>{r(Z$1(t,e,n));});});const r=t.getRootElement(),o=t._window||window,i=o.document,c=Js(o);if(null===r||null===c)return false;
9307const s=i.createElement("span");s.style.position="fixed",s.style.top="-1000px",s.append(i.createTextNode("#")),r.append(s);const a=new Range;return a.setStart(s,0),a.setEnd(s,1),c.removeAllRanges(),c.addRange(a),new Promise((e,r)=>{const c=t.registerCommand(Je$2,r=>(Bt$3(r,ClipboardEvent)&&(c(),null!==Q$3&&(o.clearTimeout(Q$3),Q$3=null),e(Z$1(t,r,n))),true),lo);Q$3=o.setTimeout(()=>{c(),Q$3=null,e(false);},50),i.execCommand("copy"),s.remove();})}function Z$1(t,e,n){if(void 0===n){const e=Js(t._window),r=Qr();if(!r||r.isCollapsed())return false;if(!e)return false;const o=e.anchorNode,i=e.focusNode;if(null!==o&&null!==i&&!Mo(t,o,i))return false;n=et(r);}e.preventDefault();const r=e.clipboardData;return null!==r&&(nt$1(r,n),true)}const tt$1=[["text/html",J$4],["application/x-lexical-editor",L$3]];function et(n=Qr()){return function(t,e){const n={"text/plain":""};for(const[r,o]of Object.entries(t)){const t=ot(o,e);null!==t&&(n[r]=t);}return n}(function(){const n=Zs(),r=de$3.maybeFromEditor(n);if(r&&r.hasExtensionByName(it.name))return ue$3(n,it).output;return rt$1}(),n)}function nt$1(t,e){for(const[n]of tt$1) void 0===e[n]&&t.setData(n,"");for(const n in e){const r=e[n];void 0!==r&&t.setData(n,r);}}const rt$1={"application/x-lexical-editor":[(t,e)=>t?L$3(Zs(),t):e()],"text/html":[(t,e)=>t?J$4(Zs(),t):e()],"text/plain":[(t,e)=>t?t.getTextContent():e()]};function ot(t,e){const n=r=>t[r]?t[r](e,n.bind(null,r-1)):null;return n(t.length-1)}const it=dc({build:(t,e,n)=>e.$exportMimeType,config:_c({$exportMimeType:rt$1}),mergeConfig(t,e){const n=pc(t,e);if(e.$exportMimeType){const r={...t.$exportMimeType};for(const[t,n]of Object.entries(e.$exportMimeType))r[t]=[...r[t],...n];n.$exportMimeType=r;}return n},name:"@lexical/clipboard/GetClipboardData"}); 9308 9309/** 9310 * Copyright (c) Meta Platforms, Inc. and affiliates. 9311 * 9312 * This source code is licensed under the MIT license found in the 9313 * LICENSE file in the root directory of this source tree. 9314 * 9315 */ 9316 9317function s(e){const t=window.location.origin,n=n=>{if(n.origin!==t)return;const o=e.getRootElement();if(document.activeElement!==o)return;const s=n.data;if("string"==typeof s){let t;try{t=JSON.parse(s);}catch(e){return}if(t&&"nuanria_messaging"===t.protocol&&"request"===t.type){const o=t.payload;if(o&&"makeChanges"===o.functionId){const t=o.args;if(t){const[o,s,d,c,g]=t;e.update(()=>{const e=Qr();if(Fr(e)){const t=e.anchor;let i=t.getNode(),a=0,l=0;if(Tr(i)&&o>=0&&s>=0&&(a=o,l=o+s,e.setTextNodeRange(i,a,i,l)),a===l&&""===d||(e.insertRawText(d),i=t.getNode()),Tr(i)){a=c,l=c+g;const t=i.getTextContentSize();a=a>t?t:a,l=l>t?t:l,e.setTextNodeRange(i,a,i,l);}n.stopImmediatePropagation();}});}}}}};return window.addEventListener("message",n,true),()=>{window.removeEventListener("message",n,true);}}const d=dc({build:(e,n,o)=>bt$2(n),config:_c({disabled:"undefined"==typeof window}),name:"@lexical/dragon",register:(t,n,o)=>St$2(()=>o.getOutput().disabled.value?void 0:s(t))}); 9318 9319/** 9320 * Copyright (c) Meta Platforms, Inc. and affiliates. 9321 * 9322 * This source code is licensed under the MIT license found in the 9323 * LICENSE file in the root directory of this source tree. 9324 * 9325 */ 9326 9327const W$2="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,B$2=W$2&&"documentMode"in document?document.documentMode:null,I$2=W$2&&/Mac|iPod|iPhone|iPad/.test(navigator.platform),R$1=!(!W$2||!("InputEvent"in window)||B$2)&&"getTargetRanges"in new window.InputEvent("input"),V$3=W$2&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,j$2=W$2&&/Android/.test(navigator.userAgent),q$2=W$2&&/Version\/[\d.]+.*Safari/.test(navigator.userAgent)&&!j$2,z$2=W$2&&/^(?=.*Chrome).*/i.test(navigator.userAgent),F$2=W$2&&/AppleWebKit\/[\d.]+/.test(navigator.userAgent)&&I$2&&!z$2;function G$4(e,t){t.update(()=>{if(null!==e){const n=Bt$3(e,KeyboardEvent)?null:e.clipboardData,o=Qr();if(null!==o&&!o.isCollapsed()&&null!=n){e.preventDefault();const i=J$4(t);null!==i&&n.setData("text/html",i),n.setData("text/plain",o.getTextContent());}}});}function H$2(r){return Cc(r.registerCommand(fe$4,e=>{const t=Qr();return !!Fr(t)&&(t.deleteCharacter(e),true)},ro),r.registerCommand(ye$2,e=>{const t=Qr();return !!Fr(t)&&(t.deleteWord(e),true)},ro),r.registerCommand(me$3,e=>{const t=Qr();return !!Fr(t)&&(t.deleteLine(e),true)},ro),r.registerCommand(ge$3,t=>{const n=Qr();if(!Fr(n))return false;if("string"==typeof t)n.insertText(t);else {const r=t.dataTransfer;if(null!=r)j$3(r,n);else {const e=t.data;e&&n.insertText(e);}}return true},ro),r.registerCommand(pe$3,()=>{const e=Qr();return !!Fr(e)&&(e.removeText(),true)},ro),r.registerCommand(de$4,e=>{const t=Qr();return !!Fr(t)&&(t.insertLineBreak(e),true)},ro),r.registerCommand(he$3,()=>{const e=Qr();return !!Fr(e)&&(e.insertLineBreak(),true)},ro),r.registerCommand(Ne$1,e=>{const t=Qr();if(!Fr(t))return false;
9327const n=e,r=n.shiftKey;return !!Q$8(t,true)&&(n.preventDefault(),ee$3(t,r,true),true)},ro),r.registerCommand(ke$2,e=>{const t=Qr();if(!Fr(t))return false;const n=e,r=n.shiftKey;return !!Q$8(t,false)&&(n.preventDefault(),ee$3(t,r,false),true)},ro),r.registerCommand(Ae$3,e=>{const t=Qr();return !!Fr(t)&&((!V$3||"ko-KR"!==navigator.language)&&(e.preventDefault(),r.dispatchCommand(fe$4,true)))},ro),r.registerCommand(Pe$2,e=>{const t=Qr();return !!Fr(t)&&(e.preventDefault(),r.dispatchCommand(fe$4,false))},ro),r.registerCommand(Oe$2,e=>{const t=Qr();if(!Fr(t))return false;if(null!==e){if((V$3||q$2||F$2)&&R$1)return false;e.preventDefault();}return r.dispatchCommand(de$4,false)},ro),r.registerCommand(Ue$2,()=>(ys(),true),ro),r.registerCommand(Je$2,e=>{const t=Qr();return !!Fr(t)&&(G$4(e,r),true)},ro),r.registerCommand(je$2,e=>{const t=Qr();return !!Fr(t)&&(function(e,t){G$4(e,t),t.update(()=>{const e=Qr();Fr(e)&&e.removeText();});}(e,r),true)},ro),r.registerCommand(_e$2,t=>{const n=Qr();return !!Fr(n)&&(function(t,n){t.preventDefault(),n.update(()=>{const n=Qr(),r=Bt$3(t,ClipboardEvent)?t.clipboardData:null;null!=r&&Fr(n)&&j$3(r,n);},{tag:jn});}(t,r),true)},ro),r.registerCommand(ze$2,e=>q$3(e,r),ro),r.registerCommand(Be$2,e=>{const t=Qr();return !!Fr(t)&&(t.isCollapsed()||null===e.dataTransfer||B$3(e.dataTransfer,r),true)},ro))} 9328 9329/** 9330 * Copyright (c) Meta Platforms, Inc. and affiliates. 9331 * 9332 * This source code is licensed under the MIT license found in the 9333 * LICENSE file in the root directory of this source tree. 9334 * 9335 */ 9336 9337function yt$2(t,e){if(void 0!==document.caretRangeFromPoint){const n=document.caretRangeFromPoint(t,e);return null===n?null:{node:n.startContainer,offset:n.startOffset}}if("undefined"!==document.caretPositionFromPoint){const n=document.caretPositionFromPoint(t,e);return null===n?null:{node:n.offsetNode,offset:n.offset}}return null}const xt$1="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,Dt$2=xt$1&&"documentMode"in document?document.documentMode:null,_t$1=xt$1&&/Mac|iPod|iPhone|iPad/.test(navigator.platform),Nt$1=!(!xt$1||!("InputEvent"in window)||Dt$2)&&"getTargetRanges"in new window.InputEvent("input"),wt$1=xt$1&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,Tt$2=xt$1&&/Android/.test(navigator.userAgent),Et$1=xt$1&&/Version\/[\d.]+.*Safari/.test(navigator.userAgent)&&!Tt$2,Ft$2=xt$1&&/^(?=.*Chrome).*/i.test(navigator.userAgent),Ot$2=xt$1&&/AppleWebKit\/[\d.]+/.test(navigator.userAgent)&&_t$1&&!Ft$2,Pt$2=re$5("DRAG_DROP_PASTE_FILE");let At$1 = class At extends Bi{static getType(){return "quote"}static clone(t){return new At(t.__key)}createDOM(t){const e=document.createElement("blockquote");return mc(e,t.theme.quote),e}updateDOM(t,e){return false}static importDOM(){return {blockquote:t=>({conversion:kt$2,priority:0})}}exportDOM(t){const{element:e}=super.exportDOM(t);if(Ys(e)){this.isEmpty()&&e.append(document.createElement("br"));const t=this.getFormatType();t&&(e.style.textAlign=t);const n=this.getDirection();n&&(e.dir=n);}return {element:e}}static importJSON(t){return St$1().updateFromJSON(t)}insertNewAfter(t,e){const n=eo(),r=this.getDirection();return n.setDirection(r),this.insertAfter(n,e),n}collapseAtStart(){const t=eo();
9337return this.getChildren().forEach(e=>t.append(e)),this.replace(t),true}canMergeWhenEmpty(){return true}};function St$1(){return zs(new At$1)}function Mt$2(t){return t instanceof At$1}let It$1 = class It extends Bi{__tag;static getType(){return "heading"}static clone(t){return new It(t.__tag,t.__key)}afterCloneFrom(t){super.afterCloneFrom(t),this.__tag=t.__tag;}constructor(t="h1",e){super(e),this.__tag=t;}getTag(){return this.getLatest().__tag}setTag(t){const e=this.getWritable();return e.__tag=t,e}createDOM(t){const e=this.__tag,n=document.createElement(e),r=t.theme.heading;if(void 0!==r){const t=r[e];mc(n,t);}return n}updateDOM(t,e,n){return t.__tag!==this.__tag}static importDOM(){return {h1:t=>({conversion:Kt$2,priority:0}),h2:t=>({conversion:Kt$2,priority:0}),h3:t=>({conversion:Kt$2,priority:0}),h4:t=>({conversion:Kt$2,priority:0}),h5:t=>({conversion:Kt$2,priority:0}),h6:t=>({conversion:Kt$2,priority:0}),p:t=>{const e=t.firstChild;return null!==e&&bt$1(e)?{conversion:()=>({node:null}),priority:3}:null},span:t=>bt$1(t)?{conversion:t=>({node:Jt$2("h1")}),priority:3}:null}}exportDOM(t){const{element:e}=super.exportDOM(t);if(Ys(e)){this.isEmpty()&&e.append(document.createElement("br"));const t=this.getFormatType();t&&(e.style.textAlign=t);const n=this.getDirection();n&&(e.dir=n);}return {element:e}}static importJSON(t){return Jt$2(t.tag).updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setTag(t.tag)}exportJSON(){return {...super.exportJSON(),tag:this.getTag()}}insertNewAfter(t,e=true){const n=t?t.anchor.offset:0,r=this.getLastDescendant(),o=!r||t&&t.anchor.key===r.getKey()&&n===r.getTextContentSize()||!t?eo():Jt$2(this.getTag()),i=this.getDirection();if(o.setDirection(i),this.insertAfter(o,e),0===n&&!this.isEmpty()&&t){const t=eo();t.select(),this.replace(t,true);}return o}collapseAtStart(){const t=this.isEmpty()?eo():Jt$2(this.getTag());
9337return this.getChildren().forEach(e=>t.append(e)),this.replace(t),true}extractWithChild(){return true}};function bt$1(t){return "span"===t.nodeName.toLowerCase()&&"26pt"===t.style.fontSize}function Kt$2(t){const e=t.nodeName.toLowerCase();let n=null;return "h1"!==e&&"h2"!==e&&"h3"!==e&&"h4"!==e&&"h5"!==e&&"h6"!==e||(n=Jt$2(e),null!==t.style&&(sl(t,n),n.setFormat(t.style.textAlign))),{node:n}}function kt$2(t){const e=St$1();return null!==t.style&&(e.setFormat(t.style.textAlign),sl(t,e)),{node:e}}function Jt$2(t="h1"){return zs(new It$1(t))}function Lt$2(t){return t instanceof It$1}function Wt$2(t){let e=null;if(Bt$3(t,DragEvent)?e=t.dataTransfer:Bt$3(t,ClipboardEvent)&&(e=t.clipboardData),null===e)return [false,[],false];const n=e.types,r=n.includes("Files"),o=n.includes("text/html")||n.includes("text/plain");return [r,Array.from(e.files),o]}function Rt$2(t){const e=Go(t);return ji(e)}function qt$2(t){for(const e of ["lowercase","uppercase","capitalize"])t.hasFormat(e)&&t.toggleFormat(e);}function zt$2(s){return Cc(s.registerCommand(se$5,t=>{const e=Qr();return !!Ir(e)&&(e.clear(),true)},ro),s.registerCommand(fe$4,t=>{const e=Qr();return Fr(e)?(e.deleteCharacter(t),true):!!Ir(e)&&(e.deleteNodes(),true)},ro),s.registerCommand(ye$2,t=>{const e=Qr();return !!Fr(e)&&(e.deleteWord(t),true)},ro),s.registerCommand(me$3,t=>{const e=Qr();return !!Fr(e)&&(e.deleteLine(t),true)},ro),s.registerCommand(ge$3,e=>{const n=Qr();if("string"==typeof e)null!==n&&n.insertText(e);else {if(null===n)return false;const r=e.dataTransfer;if(null!=r)I$3(r,n,s);else if(Fr(n)){const t=e.data;return t&&n.insertText(t),true}}return true},ro),s.registerCommand(pe$3,()=>{const t=Qr();return !!Fr(t)&&(t.removeText(),true)},ro),s.registerCommand(xe,t=>{const e=Qr();return !!Fr(e)&&(e.formatText(t),true)},ro),s.registerCommand(Re$1,t=>{const e=Qr();if(!Fr(e)&&!Ir(e))return false;const n=e.getNodes();for(const e of n){const n=dl(e,t=>Wi(t)&&!t.isInline());null!==n&&n.setFormat(t);}return true},ro),s.registerCommand(de$4,t=>{const e=Qr();return !!Fr(e)&&(e.insertLineBreak(t),true)},ro),s.registerCommand(he$3,()=>{const t=Qr();return !!Fr(t)&&(t.insertParagraph(),true)},ro),s.registerCommand(Le$2,()=>{const t=wr(),e=Qr();return Fr(e)&&(t.setFormat(e.format),t.setStyle(e.style)),li([t]),true},ro),s.registerCommand(Ie$3,()=>_t$2(t=>{const e=t.getIndent();t.setIndent(e+1);}),ro),s.registerCommand(Ke$2,()=>_t$2(t=>{const e=t.getIndent();e>0&&t.setIndent(Math.max(0,e-1));}),ro),s.registerCommand(we$1,t=>{const e=Qr();if(Ir(e)){const n=e.getNodes();if(n.length>0)return t.preventDefault(),n[0].selectPrevious(),true}else if(Fr(e)){const n=vs(e.focus,true);if(!t.shiftKey&&ji(n)&&!n.isIsolated()&&!n.isInline())return n.selectPrevious(),t.preventDefault(),true}return false},ro),s.registerCommand(Ee$3,t=>{const e=Qr();if(Ir(e)){const n=e.getNodes();if(n.length>0)return t.preventDefault(),n[0].selectNext(0,0),true}else if(Fr(e)){if(function(t){const e=t.focus;return "root"===e.key&&e.offset===Zo().getChildrenSize()}(e))return t.preventDefault(),true;const n=vs(e.focus,false);if(!t.shiftKey&&ji(n)&&!n.isIsolated()&&!n.isInline())return n.selectNext(),t.preventDefault(),true}return false},ro),s.registerCommand(Ne$1,t=>{const e=Qr();if(Ir(e)){const n=e.getNodes();if(n.length>0)return t.preventDefault(),O$3(n[0])?n[0].selectNext(0,0):n[0].selectPrevious(),true}if(!Fr(e))return false;if(Q$8(e,true)){const n=t.shiftKey;return t.preventDefault(),ee$3(e,n,true),true}return false},ro),s.registerCommand(ke$2,t=>{const e=Qr();if(Ir(e)){const n=e.getNodes();if(n.length>0)return t.preventDefault(),O$3(n[0])?n[0].selectPrevious():n[0].selectNext(0,0),true}if(!Fr(e))return false;const n=t.shiftKey;return !!Q$8(e,false)&&(t.preventDefault(),ee$3(e,n,false),true)},ro),s.registerCommand(Ae$3,t=>{if(Rt$2(t.target))return false;const e=Qr();if(Fr(e)){if(function(t){if(!t.isCollapsed())return false;const{anchor:e}=t;if(0!==e.offset)return false;const n=e.getNode();if(Vi(n))return false;const r=Nt$2(n);return r.getIndent()>0&&(r.is(n)||n.is(r.getFirstDescendant()))}(e))return t.preventDefault(),s.dispatchCommand(Ke$2,void 0);if(wt$1&&"ko-KR"===navigator.language)return false}else if(!Ir(e))return false;return t.preventDefault(),s.dispatchCommand(fe$4,true)},ro),s.registerCommand(Pe$2,t=>{if(Rt$2(t.target))return false;
9337const e=Qr();return !(!Fr(e)&&!Ir(e))&&(t.preventDefault(),s.dispatchCommand(fe$4,false))},ro),s.registerCommand(Oe$2,t=>{const e=Qr();if(!Fr(e))return false;if(qt$2(e),null!==t){if((wt$1||Et$1||Ot$2)&&Nt$1)return false;if(t.preventDefault(),t.shiftKey)return s.dispatchCommand(de$4,false)}return s.dispatchCommand(he$3,void 0)},ro),s.registerCommand(De$2,()=>{const t=Qr();return !!Fr(t)&&(s.blur(),true)},ro),s.registerCommand(ze$2,t=>{const[,n]=Wt$2(t);if(n.length>0){const e=yt$2(t.clientX,t.clientY);if(null!==e){const{offset:t,node:r}=e,o=Go(r);if(null!==o){const e=qr();if(Tr(o))e.anchor.set(o.getKey(),t,"text"),e.focus.set(o.getKey(),t,"text");else {const t=o.getParentOrThrow().getKey(),n=o.getIndexWithinParent()+1;e.anchor.set(t,n,"element"),e.focus.set(t,n,"element");}const n=St$3(e);es(n);}s.dispatchCommand(Pt$2,n);}return t.preventDefault(),true}return W$3(t,s)},ro),s.registerCommand(Be$2,t=>{const[e]=Wt$2(t),i=Qr();return !(e&&!Fr(i))&&(Fr(i)&&!i.isCollapsed()&&null!==t.dataTransfer&&(nt$1(t.dataTransfer,et(i)),B$3(t.dataTransfer,s)),true)},ro),s.registerCommand(We$2,t=>{const[e]=Wt$2(t),n=Qr();if(e&&!Fr(n))return false;const r=yt$2(t.clientX,t.clientY);if(null!==r){const e=Go(r.node);ji(e)&&t.preventDefault();}return true},ro),s.registerCommand(Ue$2,()=>(ys(),true),ro),s.registerCommand(Je$2,t=>(V$4(s,Bt$3(t,ClipboardEvent)?t:null),true),ro),s.registerCommand(je$2,t=>(async function(t,e){await V$4(e,Bt$3(t,ClipboardEvent)?t:null),e.update(()=>{const t=Qr();Fr(t)?t.removeText():Ir(t)&&t.getNodes().forEach(t=>t.remove());});}(t,s),true),ro),s.registerCommand(_e$2,e=>{const[,n,r]=Wt$2(e);if(n.length>0&&!r)return s.dispatchCommand(Pt$2,n),true;if(qs(e.target)&&Oo(e.target))return false;return null!==Qr()&&(function(e,n){e.preventDefault(),n.update(()=>{const r=Qr(),o=Bt$3(e,InputEvent)||Bt$3(e,KeyboardEvent)?null:e.clipboardData;null!=o&&null!==r&&I$3(o,r,n);},{tag:jn});}(e,s),true)},ro),s.registerCommand(Me$2,t=>{const e=Qr();return Fr(e)&&qt$2(e),false},ro),s.registerCommand(Fe$2,t=>{const e=Qr();return Fr(e)&&qt$2(e),false},ro))}const Xt$2=dc({conflictsWith:["@lexical/plain-text"],dependencies:[d],name:"@lexical/rich-text",nodes:()=>[It$1,At$1],register:zt$2}); 9338 9339// An editor's sanitizer: the allowlist it was registered with, applied to a 9340// string. 9341// 9342// The allowlist is per editor, and passed to each sanitize() call. Neither of 9343// those is incidental. This used to be a module-level config installed with 9344// DOMPurify.setConfig() on the shared singleton, which had two distinct 9345// consequences: 9346// 9347// 1. A persistent config is final â DOMPurify ignores the per-call config once 9348// one is set â so it silently disarmed the sanitizing of any host app that 9349// also imports dompurify. See config/dom_purify for why we now own our 9350// instance; keeping the config per-call means there is no global sanitizer 9351// state left even on that instance. 9352// 9353// 2. One config for the whole module meant the last editor to connect decided 9354// how every other editor on the page sanitized. That is not cosmetic: an 9355// editor's `value` is sanitized on read, so a rich editor sharing a page with 9356// a plain one would silently drop its own headings, lists and links from the 9357// value it submits. 9358// 9359// Sanitizers are keyed by the Lexical editor, which is the identity both call 9360// sites have: the element registers with it and keeps the result as 9361// `this.sanitizer`, while nodes only receive it as createDOM()'s second argument 9362// and resolve their sanitizer with for(). 9363class EditorSanitizer { 9364 static #instances = new WeakMap() 9365 9366 // Only reached for an editor that never registered, which is a supported case: 9367 // CustomActionTextAttachmentNode is exported from src/index.js, so it can be 9368 // registered in a Lexical editor Lexxy did not build. 9369 // 9370 // Fixed, and never reassigned. Pointing it at whichever sanitizer registered 9371 // most recently would make an unregistered consumer's allowlist depend on 9372 // which Lexxy editor happened to initialise last â the last-editor-wins bug 9373 // this class exists to remove, reintroduced on the one path that has no editor 9374 // to key on, and unobservable from the consumer's own code. 9375 // 9376 // It declares no allowlist, so DOMPurify's own default policy applies. An 9377 // empty allowlist would be deterministic too and strips every tag, which 9378 // silently drops markup a standalone consumer used to keep. It holds no 9379 // editor either, so nothing here pins a disconnected editor's DOM. 9380 // 9381 // A consumer wanting its own allowlist registers for it: register() needs only 9382 // the Lexical editor and is reachable as EditorSanitizer from src/index.js. 9383 // 9384 // Built on first use rather than as a static field initializer, which would run 9385 // buildConfig at import: src/index.js exports this class, so that would create 9386 // the Trusted Types policy â and, unallowlisted, report a CSP violation â on 9387 // every page load of an app that never renders an editor. 9388 static #fallback 9389 9390 static #fallbackSanitizer() { 9391 return this.#fallback ||= new EditorSanitizer() 9392 } 9393 9394 static register(editor, allowedElements = []) { 9395 const sanitizer = new EditorSanitizer(this.#allowedElementsFor(editor, allowedElements)); 9396 this.#instances.set(editor, sanitizer); 9397 9398 return sanitizer 9399 } 9400 9401 static for(editor) { 9402 return this.#instances.get(editor) ?? this.#fallbackSanitizer() 9403 } 9404 9405 // An editor can import every tag it can convert from HTML, plus whatever its 9406 // extensions declare. Lexical registers the conversions while building the 9407 // editor, so they are already in place when $initialEditorState registers us. 9408 static #allowedElementsFor(editor, allowedElements) { 9409 return this.#importableTags(editor).concat(allowedElements) 9410 } 9411 9412 static #importableTags(editor) { 9413 const tags = Array.from(editor._htmlConversions.keys()); 9414 return tags.filter(tag => !tag.startsWith("#")) 9415 } 9416 9417 #config 9418 9419 constructor(allowedElements = null) { 9420 this.#config = buildConfig(allowedElements); 9421 } 9422 9423 // safeForXml opts into DOMPurify's mXSS-safe mode, for a caller re-inflating 9424 // stored content. It is off by default, and the reason is not that the default 9425 // hop is trustworthy â the value an editor reads back carries the attacker's 9426 // stored `content` verbatim. The reason is that strictness there is destructive: 9427 // SAFE_FOR_XML drops any attribute whose value could close a comment, a 9428 // serialized `content` full of Rails view annotations is exactly that, and 9429 // CustomActionTextAttachmentNode.importDOM returns null for an attachment with no 9430 // `content` â so the attachment vanishes on the next edit. Verified: strict on the 9431 // value hop leaves `<action-text-attachment sgid content-type>` and re-editing that 9432 // renders nothing. 9433 // 9434 // The strict config is this instance's own, spread rather than rebuilt, so the 9435 // per-editor allowlist and everything else buildConfig put there â the Trusted 9436 // Types policy, ADD_URI_SAFE_ATTR â survive the flip. 9437 sanitize(html, { safeForXml = false } = {}) { 9438 if (safeForXml) { 9439 return DOMPurify.sanitize(html, { ...this.#config, SAFE_FOR_XML: true }) 9440 } 9441 9442 return DOMPurify.sanitize(html, this.#config) 9443 } 9444} 9445 9446function bytesToHumanSize(bytes) { 9447 if (bytes === 0) return "0 B" 9448 const sizes = [ "B", "KB", "MB", "GB", "TB", "PB" ]; 9449 const i = Math.floor(Math.log(bytes) / Math.log(1024)); 9450 const value = bytes / Math.pow(1024, i); 9451 return `${ value.toFixed(2) } ${ sizes[i] }` 9452} 9453 9454function extractFileName(string) { 9455 return string.split("/").pop() 9456} 9457 9458// The content attribute is raw HTML (matching Trix/ActionText). Older Lexxy 9459// versions JSON-encoded it, so try JSON.parse first for backward compatibility. 9460function parseAttachmentContent(content) { 9461 try { 9462 return JSON.parse(content) 9463 } catch { 9464 return content 9465 } 9466} 9467 9468function mimeTypeToExtension(mimeType) { 9469 if (!mimeType) return null 9470 9471 const extension = mimeType.split("/")[1]; 9472 return extension 9473}
vendor: 2,951 bytes, lines 9473-9553
9473 9474 9475class CustomActionTextAttachmentNode extends Ji { 9476 static getType() { 9477 return "custom_action_text_attachment" 9478 } 9479 9480 static clone(node) { 9481 return new CustomActionTextAttachmentNode({ ...node }, node.__key) 9482 } 9483 9484 static importJSON(serializedNode) { 9485 return new CustomActionTextAttachmentNode({ ...serializedNode }) 9486 } 9487 9488 static importDOM() { 9489 return { 9490 [this.TAG_NAME]: (element) => { 9491 if (!element.getAttribute("content")) { 9492 return null 9493 } 9494 9495 return { 9496 conversion: (attachment) => { 9497 // Preserve initial space if present since Lexical removes it 9498 const nodes = []; 9499 const previousSibling = attachment.previousSibling; 9500 if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE && /\s$/.test(previousSibling.textContent)) { 9501 nodes.push(kr(" ")); 9502 } 9503 9504 const innerHtml = parseAttachmentContent(attachment.getAttribute("content")); 9505 9506 nodes.push(new CustomActionTextAttachmentNode({ 9507 sgid: attachment.getAttribute("sgid"), 9508 innerHtml, 9509 plainText: attachment.textContent.trim() || extractPlainTextFromHtml(innerHtml), 9510 contentType: attachment.getAttribute("content-type") 9511 })); 9512 9513 const nextSibling = attachment.nextSibling; 9514 if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE && /^\s/.test(nextSibling.textContent)) { 9515 nodes.push(kr(" ")); 9516 } 9517 9518 return { node: nodes } 9519 }, 9520 priority: 2 9521 } 9522 } 9523 } 9524 } 9525 9526 static get TAG_NAME() { 9527 return Lexxy.global.get("attachmentTagName") 9528 } 9529 9530 constructor({ tagName, sgid, contentType, innerHtml, plainText } = {}, key) { 9531 super(key); 9532 9533 const contentTypeNamespace = Lexxy.global.get("attachmentContentTypeNamespace"); 9534 9535 this.tagName = tagName || CustomActionTextAttachmentNode.TAG_NAME; 9536 this.sgid = sgid; 9537 this.contentType = contentType || `application/vnd.${contentTypeNamespace}.unknown`; 9538 this.innerHtml = innerHtml; 9539 this.plainText = plainText ?? extractPlainTextFromHtml(innerHtml); 9540 } 9541 9542 createDOM(_config, editor) { 9543 const figure = createElement(this.tagName, { "content-type": this.contentType, "data-lexxy-decorator": true, draggable: true }); 9544 figure.dataset.lexicalNodeKey = this.__key; 9545 9546 // Resolved from the editor so this content is sanitized with its own 9547 // allowlist rather than whichever editor connected most recently. 9548 // 9549 // this.innerHtml is untrusted stored content being re-inflated into the editor, 9550 // so it goes through DOMPurify's mXSS-safe mode. Strictness is free here because 9551 // of where the `content` attribute that has to survive is sanitized, which is not 9552 // this hop: it is produced by exportDOM and by the server-side pass in 9553 // lib/lexxy/rich_text_area_tag.rb, and it is only ever sanitized on the lax hop
9554 // where an editor reads its own value back. 9555 // 9556 // The decoded inner markup can carry a `content` attribute of its own â nested 9557 // attachment markup does, and the attribute is allowlisted on the attachment tag 9558 // in extensions/attachments_extension.js â and mXSS-safe mode drops it. That loss 9559 // is cosmetic: it is a nested attachment's rendering inside this one, not the 9560 // attribute anything re-imports from. 9561 figure.insertAdjacentHTML("beforeend", EditorSanitizer.for(editor).sanitize(this.innerHtml, { safeForXml: true })); 9562 9563 const deleteButton = createElement("lexxy-node-delete-button"); 9564 figure.appendChild(deleteButton); 9565 9566 return figure 9567 } 9568 9569 updateDOM() { 9570 return false 9571 } 9572 9573 getTextContent() { 9574 return "\ufeff" 9575 } 9576 9577 getReadableTextContent() { 9578 return this.plainText || `[${this.contentType}]` 9579 } 9580 9581 isInline() { 9582 return true 9583 } 9584 9585 exportDOM() { 9586 const attachment = createElement(this.tagName, { 9587 sgid: this.sgid, 9588 content: this.innerHtml, 9589 "content-type": this.contentType 9590 }); 9591 9592 return { element: attachment } 9593 } 9594 9595 exportJSON() { 9596 return { 9597 type: "custom_action_text_attachment", 9598 version: 1, 9599 tagName: this.tagName, 9600 sgid: this.sgid, 9601 contentType: this.contentType, 9602 innerHtml: this.innerHtml, 9603 plainText: this.plainText 9604 } 9605 } 9606 9607 decorate() { 9608 return null 9609 } 9610} 9611 9612function $isCustomActionTextAttachmentNode(node) { 9613 return node instanceof CustomActionTextAttachmentNode 9614} 9615 9616function dasherize(value) { 9617 return value.replace(/([A-Z])/g, (_, char) => `-${char.toLowerCase()}`) 9618} 9619 9620function isAutolinkableURL(string) { 9621 return /^(?:[a-z0-9]+:\/\/|www\.)[^\s]+$/i.test(string) 9622} 9623 9624function normalizeFilteredText(string) { 9625 return string 9626 .toLowerCase() 9627 .normalize("NFD").replace(/[\u0300-\u036f]/g, "") // Remove diacritics 9628} 9629 9630function filterMatchPosition(text, potentialMatch) { 9631 const normalizedText = normalizeFilteredText(text); 9632 const normalizedMatch = normalizeFilteredText(potentialMatch); 9633 9634 if (!normalizedMatch) return 0 9635 9636 const match = normalizedText.match(new RegExp(`(?<![\\p{L}\\p{N}])${escapeForRegExp(normalizedMatch)}`, "u")); 9637 return match ? match.index : -1 9638} 9639 9640function upcaseFirst(string) { 9641 return string.charAt(0).toUpperCase() + string.slice(1) 9642} 9643 9644function escapeForRegExp(string) { 9645 return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") 9646} 9647 9648// Parses a value that may arrive as a boolean or as a string (e.g. from DOM 9649// getAttribute) into a proper boolean. Ensures "false" doesn't evaluate as truthy. 9650function parseBoolean(value) { 9651 if (typeof value === "string") return value === "true" 9652 return Boolean(value) 9653} 9654 9655/** 9656 * Copyright (c) Meta Platforms, Inc. and affiliates. 9657 * 9658 * This source code is licensed under the MIT license found in the 9659 * LICENSE file in the root directory of this source tree. 9660 * 9661 */ 9662 9663function C$2(t,e,n,r,o){if(null===t||0===n.size&&0===r.size&&!o)return 0;const i=e._selection,a=t._selection;if(o)return 1;if(!(Fr(i)&&Fr(a)&&a.isCollapsed()&&i.isCollapsed()))return 0;const s=function(t,e,n){const r=t._nodeMap,o=[];for(const t of e){const e=r.get(t);void 0!==e&&o.push(e);}for(const[t,e]of n){if(!e)continue;const n=r.get(t);void 0===n||Vi(n)||o.push(n);}return o}(e,n,r);if(0===s.length)return 0;if(s.length>1){const n=e._nodeMap,r=n.get(i.anchor.key),o=n.get(a.anchor.key);return r&&o&&!t._nodeMap.has(r.__key)&&Tr(r)&&1===r.__text.length&&1===i.anchor.offset?2:0}const d=s[0],l=t._nodeMap.get(d.__key);if(!Tr(l)||!Tr(d)||l.__mode!==d.__mode)return 0;const u=l.__text,c=d.__text;if(u===c)return 0;const f=i.anchor,p=a.anchor;if(f.key!==p.key||"text"!==f.type)return 0;const h=f.offset,m=p.offset,g=c.length-u.length;return 1===g&&m===h-1?2:-1===g&&m===h+1?3:-1===g&&m===h?4:0}function b$1(t,e,n){let r=n(),o=0,i=r,a=0,s=null;return (d,l,u,c,f,p)=>{const h=n();if(p.has(Gn)&&(i=r,a=o,s=d),p.has(Wn$1))return o=0,r=h,2;p.has(Xn)&&s&&(r=i,o=a,d=s);const x=C$2(d,l,c,f,t.isComposing()),b=(()=>{const n=null===u||u.editor===t,i=p.has($n$1);if(!i&&n&&p.has(Jn))return 0;if(1===x)return 2;if(null===d)return 1;const a=l._selection;if(!(c.size>0||f.size>0))return null!==a?0:2;const s="number"==typeof e?e:e.peek();if(false===i&&0!==x&&x===o&&h<r+s&&n)return 0;if(1===c.size){if(function(t,e,n){const r=e._nodeMap.get(t),o=n._nodeMap.get(t),i=e._selection,a=n._selection;return !(Fr(i)&&Fr(a)&&"element"===i.anchor.type&&"element"===i.focus.type&&"text"===a.anchor.type&&"text"===a.focus.type||!Tr(r)||!Tr(o)||r.__parent!==o.__parent)&&JSON.stringify(e.read(()=>r.exportJSON()))===JSON.stringify(n.read(()=>o.exportJSON()))}(Array.from(c)[0],d,l))return 0}return 1})();return r=h,o=x,b}}function w$2(t){t.undoStack=[],t.redoStack=[],t.current=null;}
9663function E$1(t,e,n,r=Date.now){const i=b$1(t,n,r);return Cc(t.registerCommand(Ce$2,()=>(function(t,e){const n=e.redoStack,r=e.undoStack;if(0!==r.length){const o=e.current,i=r.pop();null!==o&&(n.push(o),t.dispatchCommand(qe$2,true)),0===r.length&&t.dispatchCommand(He$2,false),e.current=i||null,i&&i.editor.setEditorState(i.editorState,{tag:Wn$1});}}(t,e),true),ro),t.registerCommand(Se$2,()=>(function(t,e){const n=e.redoStack,r=e.undoStack;if(0!==n.length){const o=e.current;null!==o&&(r.push(o),t.dispatchCommand(He$2,true));const i=n.pop();0===n.length&&t.dispatchCommand(qe$2,false),e.current=i||null,i&&i.editor.setEditorState(i.editorState,{tag:Wn$1});}}(t,e),true),ro),t.registerCommand(Ve$2,()=>(w$2(e),false),ro),t.registerCommand(Ye$1,()=>(w$2(e),t.dispatchCommand(qe$2,false),t.dispatchCommand(He$2,false),true),ro),t.registerUpdateListener(({editorState:n,prevEditorState:r,dirtyLeaves:o,dirtyElements:a,tags:s})=>{const d=e.current,l=e.redoStack,u=e.undoStack,c=null===d?null:d.editorState;if(null!==d&&n===c)return;const f=i(r,n,d,o,a,s);if(1===f)0!==l.length&&(e.redoStack=[],t.dispatchCommand(qe$2,false)),null!==d&&(u.push({...d}),t.dispatchCommand(He$2,true));else if(2===f)return;e.current={editor:t,editorState:n};}))}function M$2(){return {current:null,redoStack:[],undoStack:[]}}const O$1=dc({build:(t,{delay:n,createInitialHistoryState:r,disabled:o,now:i})=>bt$2({delay:n,disabled:o,historyState:r(t),now:i}),config:_c({createInitialHistoryState:M$2,delay:300,disabled:"undefined"==typeof window,now:Date.now}),name:"@lexical/history/History",register:(e,n,r)=>{const o=r.getOutput();return St$2(()=>o.disabled.value?void 0:E$1(e,o.historyState.value,o.delay,()=>o.now.peek()()))}});dc({build:(t,{disabled:n,parentEditor:r})=>bt$2({disabled:n,parentEditor:r||t._parentEditor}),config:_c({disabled:false,parentEditor:null}),dependencies:[hc(O$1,{disabled:true})],name:"@lexical/history/SharedHistory",register:(e,o,i)=>St$2(()=>{const{disabled:t,parentEditor:e}=i.getOutput();if(!t.value){const{output:t}=i.getDependency(O$1),o=function(t){return t?fe$3(t,O$1.name):null}(e.value);if(!o)return;const a=o.output;Y$3(()=>{t.delay.value=a.delay.value,t.historyState.value=a.historyState.value,t.now.value=a.now.value,t.disabled.value=a.disabled.value;});}})}); 9664 9665class LexxyExtension { 9666 #editorElement 9667 9668 constructor(editorElement) { 9669 this.#editorElement = editorElement; 9670 } 9671 9672 get editorElement() { 9673 return this.#editorElement 9674 } 9675 9676 get editorConfig() { 9677 return this.#editorElement.config 9678 } 9679 9680 // optional: defaults to true 9681 get enabled() { 9682 return true 9683 } 9684 9685 get lexicalExtension() { 9686 return null 9687 } 9688 9689 get allowedElements() { 9690 return [] 9691 } 9692 9693 defineExtension(...args) { 9694 return dc(...args) 9695 } 9696 9697 initializeToolbar(_lexxyToolbar) { 9698 } 9699 9700 setEditorValidity(flags, message) { 9701 this.editorElement.setElementValidity(this, flags, message); 9702 } 9703 9704 dispose() { 9705 } 9706} 9707 9708function $containsRangeSelection(node, selection = Qr()) { 9709 if (Fr(selection)) { 9710 const { commonAncestor } = Yl(selection.focus.getNode(), selection.anchor.getNode()); 9711 return dl(commonAncestor, parent => parent.is(node)) 9712 } else { 9713 return false 9714 } 9715} 9716 9717function $createNodeSelectionWith(...nodes) { 9718 const selection = Hr(); 9719 nodes.forEach(node => selection.add(node.getKey())); 9720 return selection 9721} 9722 9723function $isShadowRoot(node) { 9724 return Wi(node) && Is(node) && !Vi(node) 9725} 9726 9727function $isSafeForRoot(node) { 9728 return (Wi(node) || ji(node)) && !node.isParentRequired() 9729} 9730 9731function $makeSafeForRoot(node) { 9732 if ($isSafeForRoot(node)) { 9733 return node 9734 } else if (node.getParent()) { 9735 return Tt$4(node, () => node.createParentElementNode()) 9736 } else { 9737 // Detached nodes (e.g. clipboard nodes being inserted) can't be `replace`d in place, 9738 // so append them into a fresh required parent instead. 9739 return node.createParentElementNode().append(node) 9740 } 9741} 9742 9743function getListType(node) { 9744 const list = At$2(node, me$2); 9745 return list?.getListType() ?? null 9746} 9747 9748function isEditorFocused(editor) { 9749 const rootElement = editor.getRootElement(); 9750 return rootElement !== null && rootElement.contains(document.activeElement) 9751} 9752 9753function $isAtNodeEdge(point, atStart = null) { 9754 if (atStart === null) { 9755 return $isAtNodeEdge(point, true) || $isAtNodeEdge(point, false) 9756 } else { 9757 return atStart ? $isAtNodeStart(point) : A$2(point) 9758 } 9759} 9760 9761function $isAtNodeStart(point) { 9762 return point.offset === 0 9763} 9764 9765function extendTextNodeConversion(conversionName, ...callbacks) { 9766 return extendConversion(gr, conversionName, (conversionOutput, element) => ({ 9767 ...conversionOutput, 9768 forChild: (lexicalNode, parentNode) => { 9769 const originalForChild = conversionOutput?.forChild ?? (x => x); 9770 let childNode = originalForChild(lexicalNode, parentNode); 9771 9772 9773 if (Tr(childNode)) { 9774 childNode = callbacks.reduce( 9775 (childNode, callback) => callback(childNode, element) ?? childNode, 9776 childNode 9777 ); 9778 return childNode 9779 } 9780 } 9781 })) 9782} 9783 9784function extendConversion(nodeKlass, conversionName, callback = (output => output)) { 9785 return (element) => { 9786 const converter = nodeKlass.importDOM()?.[conversionName]?.(element); 9787 if (!converter) return null 9788 9789 const conversionOutput = converter.conversion(element); 9790 if (!conversionOutput) return conversionOutput 9791 9792 return callback(conversionOutput, element) ?? conversionOutput 9793 } 9794} 9795 9796function $isCursorOnLastLine(selection) { 9797 const anchorNode = selection.anchor.getNode(); 9798 const elementNode = Wi(anchorNode) ? anchorNode : anchorNode.getParentOrThrow(); 9799 const children = elementNode.getChildren(); 9800 if (children.length === 0) return true 9801 9802 const lastChild = children[children.length - 1]; 9803 9804 if (anchorNode === elementNode.getLatest() && selection.anchor.offset === children.length) return true 9805 if (anchorNode === lastChild) return true 9806
vendor: 24,061 bytes, lines 9807-10579
9807 const lastLineBreakIndex = children.findLastIndex(child => sr(child)); 9808 if (lastLineBreakIndex === -1) return true 9809 9810 const anchorIndex = children.indexOf(anchorNode); 9811 return anchorIndex > lastLineBreakIndex 9812} 9813 9814function $isBlankNode(node) { 9815 if (node.getTextContent().trim() !== "") return false 9816 9817 const children = node.getChildren?.(); 9818 if (!children || children.length === 0) return true 9819 9820 return children.every(child => { 9821 if (sr(child)) return true 9822 return $isBlankNode(child) 9823 }) 9824} 9825 9826function $trimTrailingBlankNodes(parent) { 9827 for (const child of zt$4(parent)) { 9828 if ($isBlankNode(child)) { 9829 child.remove(); 9830 } else { 9831 break 9832 } 9833 } 9834} 9835 9836// A list item is structurally empty if it contains no meaningful content. 9837// Unlike getTextContent().trim() === "", this walks descendants to ensure 9838// decorator nodes (mentions, attachments whose getTextContent() may return 9839// invisible characters like \ufeff) are treated as non-empty content. 9840function $isListItemStructurallyEmpty(listItem) { 9841 const children = listItem.getChildren(); 9842 for (const child of children) { 9843 if (ji(child)) return false 9844 if (sr(child)) continue 9845 if (Tr(child)) { 9846 if (child.getTextContent().trim() !== "") return false 9847 } else if (Wi(child)) { 9848 if (child.getTextContent().trim() !== "") return false 9849 } 9850 } 9851 return true 9852} 9853 9854// Returns the document text up to `offset` inside `targetNode`. Non-inline 9855// element siblings are joined with `\n\n`, matching Lexical's own 9856// ElementNode.getTextContent behavior. 9857function $textBeforeOffset(targetNode, offset) { 9858 const parts = []; 9859 let done = false; 9860 9861 function visit(node) { 9862 if (done) return 9863 if (node === targetNode) { 9864 parts.push(node.getTextContent().slice(0, offset)); 9865 done = true; 9866 return 9867 } 9868 if (Wi(node)) { 9869 const children = node.getChildren(); 9870 for (let i = 0; i < children.length; i++) { 9871 visit(children[i]); 9872 if (done) return 9873 const child = children[i]; 9874 if (Wi(child) && !child.isInline() && i < children.length - 1) { 9875 parts.push("\n\n"); 9876 } 9877 } 9878 } else { 9879 parts.push(node.getTextContent()); 9880 } 9881 } 9882 9883 visit(Zo()); 9884 return parts.join("") 9885} 9886 9887function isAttachmentSpacerTextNode(node, previousNode, index, childCount) { 9888 return Tr(node) 9889 && node.getTextContent() === " " 9890 && index === childCount - 1 9891 && previousNode instanceof CustomActionTextAttachmentNode 9892} 9893 9894function $splitSelectedParagraphsAtInnerLineBreaks(selection) { 9895 const topLevelElements = new Set(); 9896 for (const node of selection.getNodes()) { 9897 const topLevel = node.getTopLevelElement(); 9898 if (topLevel) topLevelElements.add(topLevel); 9899 } 9900 9901 for (const element of topLevelElements) { 9902 if (!no(element)) continue 9903 9904 const children = element.getChildren(); 9905 if (!children.some(sr)) continue 9906 9907 const groups = [ [] ]; 9908 for (const child of children) { 9909 if (sr(child)) { 9910 groups.push([]); 9911 child.remove(); 9912 } else { 9913 groups[groups.length - 1].push(child); 9914 } 9915 } 9916 9917 for (const group of groups) { 9918 if (group.length === 0) continue 9919 const paragraph = eo(); 9920 group.forEach(child => paragraph.append(child)); 9921 element.insertBefore(paragraph); 9922 } 9923 if (groups.some(group => group.length > 0)) element.remove(); 9924 } 9925} 9926 9927function $expandSelectionToLineBreaksAndSplitAtEdges(selection, fallbackAncestor = (node) => node.getTopLevelElement()) { 9928 j$6(selection); 9929 $shrinkSelectionPastBlockEdges(selection); 9930 9931 const focusCaret = ql(selection.focus, "next"); 9932 const anchorCaret = ql(selection.anchor, "previous"); 9933 9934 // A collapsed cursor adjacent to a <br> would claim it from both sides via 9935 // inward-edge; force outward-only walks so each side finds its own boundary. 9936 const skipInwardEdge = selection.isCollapsed(); 9937 const focusBrCaret = $getCaretAtLineBreakBoundary(focusCaret, skipInwardEdge); 9938 let anchorBrCaret = $getCaretAtLineBreakBoundary(anchorCaret, skipInwardEdge); 9939 9940 if (focusBrCaret?.origin.is(anchorBrCaret?.origin)) { 9941 anchorBrCaret = null; 9942 } 9943 9944 // Splitting focus first keeps the anchor <br>'s position stable. 9945 const focusOuter = focusBrCaret && $splitAroundLineBreak(focusBrCaret); 9946 const anchorOuter = anchorBrCaret && $splitAroundLineBreak(anchorBrCaret); 9947 9948 const innerStart = anchorOuter?.getNextSibling() ?? fallbackAncestor(selection.anchor.getNode()); 9949 const innerEnd = focusOuter?.getPreviousSibling() ?? fallbackAncestor(selection.focus.getNode()); 9950 if (!innerStart || !innerEnd) return 9951 9952 Gl(Wl( 9953 rc(Pl(innerStart, "next")), 9954 oc( 9955 rc(Pl(innerEnd, "previous")), 9956 "next", 9957 ), 9958 )); 9959} 9960 9961// A selection whose anchor sits at the very end of one block while its focus 9962// lives in a later block (e.g. selecting a pasted paragraph when the browser 9963// anchors at the end of the line above) contributes nothing from the anchor's 9964// block. Pull each endpoint that is flush against a block edge into the block 9965// that actually holds the selected content, so we don't wrap the empty edge 9966// block too. 9967function $shrinkSelectionPastBlockEdges(selection) { 9968 if (selection.isCollapsed()) return 9969 9970 const anchorBlock = selection.anchor.getNode().getTopLevelElement(); 9971 const focusBlock = selection.focus.getNode().getTopLevelElement(); 9972 if (!anchorBlock || !focusBlock || anchorBlock.is(focusBlock)) return 9973 9974 if ($isAtBlockEnd(selection.anchor, anchorBlock)) { 9975 const nextBlock = $nearestElementSibling(anchorBlock, "next"); 9976 if (nextBlock) selection.anchor.set(nextBlock.getKey(), 0, "element"); 9977 } 9978 9979 if ($isAtBlockStart(selection.focus, focusBlock)) { 9980 const previousBlock = $nearestElementSibling(focusBlock, "previous"); 9981 if (previousBlock) selection.focus.set(previousBlock.getKey(), previousBlock.getChildrenSize(), "element"); 9982 } 9983 9984 // Shrinking moves the endpoints toward each other, so they can cross when 9985 // both were flush against block edges; callers assume a forward selection. 9986 j$6(selection); 9987} 9988 9989// Top-level decorator blocks (attachments, horizontal dividers) can't hold a 9990// selection point, so walk past them to the nearest element sibling. Returns 9991// null when no element sibling exists in that direction. 9992function $nearestElementSibling(block, direction) { 9993 let sibling = block; 9994 do { 9995 sibling = direction === "next" ? sibling.getNextSibling() : sibling.getPreviousSibling(); 9996 } while (sibling && !Wi(sibling)) 9997 return sibling 9998} 9999 10000function $isAtBlockEnd(point, block) { 10001 return $isAtBlockBoundary(ql(point, "next"), block) 10002} 10003 10004function $isAtBlockStart(point, block) { 10005 return $isAtBlockBoundary(ql(point, "previous"), block) 10006} 10007 10008// A text point sitting mid-node still has content ahead of it in the caret's 10009// direction, even though that content is not a sibling node. $getNodeAtCaret 10010// only sees siblings, so check the text edge before walking the block. 10011function $isAtBlockBoundary(caret, block) { 10012 if (vl(caret) && ic(caret)) return false 10013 10014 let cursor = rc(caret); 10015 while (cursor && block.isParentOf(cursor.origin)) { 10016 if (cursor.getNodeAtCaret()) return false 10017 cursor = cursor.getParentCaret(); 10018 } 10019 return true 10020} 10021 10022function $getCaretAtLineBreakBoundary(caret, skipInwardEdge = false) { 10023 const paragraph = caret.origin.getTopLevelElement(); 10024 if (!paragraph || !no(paragraph)) return null 10025 10026 const lineBreak = (skipInwardEdge ? null : $inwardEdgeLineBreak(caret, paragraph)) 10027 ?? $outwardLineBreak(caret, paragraph); 10028 10029 return lineBreak ? Ol(lineBreak, caret.direction) : null 10030} 10031 10032// Prefer a <br> the cursor is sitting flush against, except when a further <br> 10033// also exists outward â that one is the real paragraph break for this side. 10034function $inwardEdgeLineBreak(caret, paragraph) { 10035 let candidateCaret; 10036 10037 if ( 10038 (Nl(caret) && caret.origin.is(paragraph)) || 10039 (vl(caret) && ic(caret.getFlipped())) 10040 ) { 10041 candidateCaret = null; 10042 } else if (Tl(caret) && caret.getParentAtCaret().is(paragraph)) { 10043 candidateCaret = caret; 10044 } else { 10045 const childCaret = $paragraphChildCaretAtInwardEdge(caret, paragraph); 10046 candidateCaret = childCaret ? Zl(childCaret) : null; 10047 } 10048 10049 if (candidateCaret && sr(candidateCaret.origin)) { 10050 return $candidateUnlessShadowed(candidateCaret) 10051 } else { 10052 return null 10053 } 10054} 10055 10056function $candidateUnlessShadowed(candidateCaret) { 10057 const outward = candidateCaret.getNodeAtCaret(); 10058 return sr(outward) ? null : candidateCaret.origin 10059} 10060 10061function $outwardLineBreak(caret, paragraph) { 10062 const startCaret = $outwardWalkStartCaret(caret, paragraph); 10063 if (!startCaret) return null 10064 10065 for (const { origin } of startCaret) { 10066 if (!origin.getParent().is(paragraph)) break 10067 if (sr(origin)) return origin 10068 } 10069 return null 10070} 10071 10072function $outwardWalkStartCaret(caret, paragraph) { 10073 if (caret.getParentAtCaret().is(paragraph)) { 10074 return caret 10075 } else { 10076 return $paragraphChildCaretContaining(caret, paragraph) 10077 } 10078} 10079 10080function $paragraphChildCaretContaining(caret, paragraph) { 10081 let cursor = caret.getSiblingCaret(); 10082 while (cursor && !cursor.origin.getParent()?.is(paragraph)) { 10083 cursor = cursor.getParentCaret(); 10084 } 10085 return cursor?.origin.getParent()?.is(paragraph) ? cursor : null 10086} 10087 10088// Only succeeds when the cursor is flush against the inward edge of every 10089// ancestor between itself and the paragraph child. 10090function $paragraphChildCaretAtInwardEdge(caret, paragraph) { 10091 let cursor = caret.getSiblingCaret(); 10092 while (cursor && !cursor.origin.getParent()?.is(paragraph)) { 10093 if (cursor.getNodeAtCaret()) return null 10094 cursor = cursor.getParentCaret(); 10095 } 10096 return cursor?.origin.getParent()?.is(paragraph) ? cursor : null 10097} 10098 10099function $splitAroundLineBreak(lineBreakCaret) { 10100 let outer = null; 10101 10102 if (lineBreakCaret.getNodeAtCaret() === null) { 10103 lineBreakCaret.origin.remove(); 10104 } else { 10105 const lineBreak = lineBreakCaret.origin; 10106 const splitCaret = oc(Zl(lineBreakCaret), "next"); 10107 10108 fc(splitCaret); 10109 outer = lineBreak.getTopLevelElement(); 10110 lineBreak.remove(); 10111 } 10112 10113 return outer 10114} 10115 10116// Lexical's RangeSelection.insertNodes/insertLineBreak require every selection point to have a 10117// block ancestor with inline children. An element point on a container of block nodes â e.g. a 10118// quote holding paragraphs â has none, so Lexical throws invariant #211 or #212. This detects 10119// such a point so callers can descend it to a leaf before inserting. 10120function $isPointOnBlockContainer(point) { 10121 if (point.type !== "element") return false 10122 10123 const firstChild = point.getNode().getFirstChild(); 10124 return (Wi(firstChild) || ji(firstChild)) && !firstChild.isInline() 10125} 10126 10127function $hasPointOnBlockContainer(selection) { 10128 return Fr(selection) && 10129 [ selection.anchor, selection.focus ].some($isPointOnBlockContainer) 10130} 10131 10132// Descend any block-container element point in the selection to a leaf position, so a subsequent 10133// Lexical insert (insertNodes, insertLineBreak, INSERT_PARAGRAPH) doesn't throw invariant #211/#212. 10134function $normalizeBlockContainerSelection(selection = Qr()) { 10135 if (!$hasPointOnBlockContainer(selection)) return false 10136 10137 St$3(selection); 10138 return true 10139} 10140 10141function $consecutiveSiblingGroups(blocks) { 10142 const ordered = [ ...blocks ].sort((a, b) => a.getIndexWithinParent() - b.getIndexWithinParent()); 10143 const groups = []; 10144 10145 for (const block of ordered) { 10146 const lastGroup = groups.at(-1); 10147 const previous = lastGroup?.at(-1); 10148 10149 if (previous && previous.getParent().is(block.getParent()) && previous.getNextSibling()?.is(block)) { 10150 lastGroup.push(block); 10151 } else { 10152 groups.push([ block ]); 10153 } 10154 } 10155 10156 return groups 10157} 10158 10159// Payload: Record<nodeKey, { patch?, replace? }> 10160// - patch: plain object, shallow-merged into the existing node's properties 10161// - replace: a LexicalNode instance that replaces the node 10162const REWRITE_HISTORY_COMMAND = re$5("REWRITE_HISTORY_COMMAND"); 10163 10164class RewritableHistoryExtension extends LexxyExtension { 10165 #historyState = null 10166 10167 get lexicalExtension() { 10168 return dc({ 10169 name: "lexxy/rewritable-history", 10170 dependencies: [ O$1 ], 10171 register: (editor, _config, state) => { 10172 const historyOutput = state.getDependency(O$1).output; 10173 this.#historyState = historyOutput.historyState.value; 10174 10175 return editor.registerCommand( 10176 REWRITE_HISTORY_COMMAND, 10177 (rewrites) => this.#rewriteHistory(rewrites), 10178 ro 10179 ) 10180 } 10181 }) 10182 } 10183 10184 get historyState() { 10185 return this.#historyState 10186 } 10187 10188 get #allHistoryEntries() { 10189 const entries = Array.from(this.#historyState.undoStack); 10190 if (this.#historyState.current) entries.push(this.#historyState.current); 10191 return entries.concat(this.#historyState.redoStack) 10192 } 10193 10194 #rewriteHistory(rewrites) { 10195 this.#applyRewritesImmediatelyToCurrentState(rewrites); 10196 this.#applyRewritesToHistory(rewrites); 10197 10198 return true 10199 } 10200 10201 #applyRewritesImmediatelyToCurrentState(rewrites) { 10202 Zs().update(() => { 10203 for (const [ nodeKey, { patch, replace } ] of Object.entries(rewrites)) { 10204 const node = Yo(nodeKey); 10205 if (!node) continue 10206 10207 if (patch) Object.assign(node.getWritable(), patch); 10208 if (replace) node.replace(replace); 10209 } 10210 }, { discrete: true, tag: this.#getBackgroundUpdateTags() }); 10211 } 10212 10213 #applyRewritesToHistory(rewrites) { 10214 const nodeKeys = Object.keys(rewrites); 10215 10216 for (const entry of this.#allHistoryEntries) { 10217 if (!this.#entryHasSomeKeys(entry, nodeKeys)) continue 10218 10219 const editorState = entry.editorState = safeCloneEditorState(entry.editorState); 10220 10221 for (const [ nodeKey, { patch, replace } ] of Object.entries(rewrites)) { 10222 const node = editorState._nodeMap.get(nodeKey); 10223 if (!node) continue 10224 10225 if (patch) { 10226 this.#patchNodeInEditorState(editorState, node, patch); 10227 } else if (replace) { 10228 this.#replaceNodeInEditorState(editorState, node, replace); 10229 } 10230 } 10231 } 10232 } 10233 10234 #entryHasSomeKeys(entry, nodeKeys) { 10235 return nodeKeys.some(key => entry.editorState._nodeMap.has(key)) 10236 } 10237 10238 #getBackgroundUpdateTags() { 10239 const tags = [ Jn, Yn ]; 10240 if (!isEditorFocused(this.editorElement.editor)) { tags.push(qn); } 10241 return tags 10242 } 10243 10244 #patchNodeInEditorState(editorState, node, patch) { 10245 editorState._nodeMap.set(node.__key, $cloneNodeWithPatch(node, patch)); 10246 } 10247 10248 #replaceNodeInEditorState(editorState, node, replaceWith) { 10249 editorState._nodeMap.set(node.__key, $cloneNodeAdoptingKeys(replaceWith, node)); 10250 } 10251} 10252 10253function $cloneNodeWithPatch(node, patch) { 10254 const clone = il(node); 10255 Object.assign(clone, patch); 10256 return clone 10257} 10258 10259function $cloneNodeAdoptingKeys(node, previousNode) { 10260 const clone = il(node); 10261 clone.__key = previousNode.__key; 10262 clone.__parent = previousNode.__parent; 10263 clone.__prev = previousNode.__prev; 10264 clone.__next = previousNode.__next; 10265 return clone 10266} 10267 10268// EditorState#clone() keeps the same map reference. 10269// A new Map is needed to prevent editing Lexical's internal map 10270// Warning: this bypasses DEV's safety map freezing 10271function safeCloneEditorState(editorState) { 10272 const clone = editorState.clone(); 10273 clone._nodeMap = new Map(editorState._nodeMap); 10274 return clone 10275} 10276 10277const INITIAL_PREVIEW_POLL_DELAY_MS = 3000; 10278const MAX_PREVIEW_POLL_DELAY_MS = 120000; 10279const MAX_PREVIEW_POLL_ATTEMPTS = 20; 10280 10281 10282class ActionTextAttachmentNode extends Ji { 10283 static getType() { 10284 return "action_text_attachment" 10285 } 10286 10287 static clone(node) { 10288 return new ActionTextAttachmentNode({ ...node }, node.__key) 10289 } 10290 10291 static importJSON(serializedNode) { 10292 return new ActionTextAttachmentNode({ ...serializedNode }) 10293 } 10294 10295 static importDOM() { 10296 return { 10297 [this.TAG_NAME]: () => { 10298 return { 10299 conversion: (attachment) => ({ 10300 node: new ActionTextAttachmentNode({ 10301 sgid: attachment.getAttribute("sgid"), 10302 src: attachment.getAttribute("url"), 10303 previewable: attachment.getAttribute("previewable"), 10304 altText: attachment.getAttribute("alt"), 10305 caption: attachment.getAttribute("caption"), 10306 contentType: attachment.getAttribute("content-type"), 10307 fileName: attachment.getAttribute("filename"), 10308 fileSize: attachment.getAttribute("filesize"), 10309 width: attachment.getAttribute("width"), 10310 height: attachment.getAttribute("height") 10311 }) 10312 }), priority: 1 10313 } 10314 }, 10315 "img": () => { 10316 return { 10317 conversion: (img) => { 10318 const fileName = extractFileName(img.getAttribute("src") ?? ""); 10319 return { 10320 node: new ActionTextAttachmentNode({ 10321 src: img.getAttribute("src"), 10322 fileName: fileName, 10323 caption: img.getAttribute("alt") || "", 10324 contentType: "image/*", 10325 width: img.getAttribute("width"), 10326 height: img.getAttribute("height") 10327 }) 10328 } 10329 }, priority: 1 10330 } 10331 }, 10332 "video": () => { 10333 return { 10334 conversion: (video) => { 10335 const videoSource = video.getAttribute("src") || video.querySelector("source")?.src; 10336 const fileName = videoSource?.split("/")?.pop(); 10337 const contentType = video.querySelector("source")?.getAttribute("content-type") || "video/*"; 10338 10339 return { 10340 node: new ActionTextAttachmentNode({ 10341 src: videoSource, 10342 fileName: fileName, 10343 contentType: contentType 10344 }) 10345 } 10346 }, priority: 1 10347 } 10348 } 10349 } 10350 } 10351 10352 static get TAG_NAME() { 10353 return Lexxy.global.get("attachmentTagName") 10354 } 10355 10356 constructor({ tagName, sgid, src, previewSrc, previewable, previewStatusUrl, pendingPreview, altText, caption, contentType, fileName, fileSize, width, height, uploadError } = {}, key) { 10357 super(key); 10358 10359 this.tagName = tagName || ActionTextAttachmentNode.TAG_NAME; 10360 this.sgid = sgid; 10361 this.src = src; 10362 this.previewSrc = previewSrc; 10363 this.previewable = parseBoolean(previewable); 10364 this.previewStatusUrl = previewStatusUrl; 10365 this.pendingPreview = pendingPreview; 10366 this.altText = altText || ""; 10367 this.caption = caption || ""; 10368 this.contentType = contentType || ""; 10369 this.fileName = fileName || ""; 10370 this.fileSize = fileSize; 10371 this.width = width; 10372 this.height = height; 10373 this.uploadError = uploadError; 10374 10375 this.editor = Zs(); 10376 } 10377 10378 createDOM() { 10379 if (this.uploadError) return this.createDOMForError() 10380 if (this.pendingPreview) return this.#createDOMForPendingPreview() 10381 10382 const figure = this.createAttachmentFigure(); 10383 10384 if (this.isPreviewableAttachment) { 10385 figure.appendChild(this.#createDOMForImage()); 10386 figure.appendChild(this.#createEditableCaption()); 10387 } else if (this.isVideo) { 10388 figure.appendChild(this.#createDOMForFile()); 10389 figure.appendChild(this.#createEditableCaption()); 10390 } else { 10391 figure.appendChild(this.#createDOMForFile()); 10392 figure.appendChild(this.#createDOMForNotImage()); 10393 } 10394 10395 return figure 10396 } 10397 10398 updateDOM(prevNode, dom) { 10399 if (this.uploadError !== prevNode.uploadError) return true 10400 10401 const caption = dom.querySelector("figcaption textarea"); 10402 if (caption && this.caption) { 10403 caption.value = this.caption; 10404 } 10405 10406 return false 10407 } 10408 10409 getTextContent() { 10410 return `[${this.caption || this.fileName}]\n\n` 10411 } 10412 10413 isInline() { 10414 return this.isAttached() && !this.getParent().is(Ls(this)) 10415 } 10416 10417 exportDOM() { 10418 const attachment = createElement(this.tagName, { 10419 sgid: this.sgid, 10420 previewable: this.previewable || null, 10421 url: this.src, 10422 alt: this.altText, 10423 caption: this.caption, 10424 "content-type": this.contentType, 10425 filename: this.fileName, 10426 filesize: this.fileSize, 10427 width: this.width, 10428 height: this.height, 10429 presentation: "gallery" 10430 }); 10431 10432 return { element: attachment } 10433 } 10434 10435 exportJSON() { 10436 return { 10437 type: "action_text_attachment", 10438 version: 1, 10439 tagName: this.tagName, 10440 sgid: this.sgid, 10441 src: this.src, 10442 previewable: this.previewable, 10443 previewStatusUrl: this.previewStatusUrl, 10444 pendingPreview: this.pendingPreview, 10445 altText: this.altText, 10446 caption: this.caption, 10447 contentType: this.contentType, 10448 fileName: this.fileName, 10449 fileSize: this.fileSize, 10450 width: this.width, 10451 height: this.height 10452 } 10453 } 10454 10455 decorate() { 10456 return null 10457 } 10458 10459 createDOMForError() { 10460 const figure = this.createAttachmentFigure(); 10461 figure.classList.add("attachment--error"); 10462 figure.appendChild(createElement("div", { innerText: `Error uploading ${this.fileName || "file"}` })); 10463 return figure 10464 } 10465 10466 createAttachmentFigure(previewable = this.isPreviewableAttachment) { 10467 const figure = createAttachmentFigure(this.contentType, previewable, this.fileName); 10468 figure.draggable = true; 10469 figure.dataset.lexicalNodeKey = this.__key; 10470 10471 const deleteButton = createElement("lexxy-node-delete-button"); 10472 figure.appendChild(deleteButton); 10473 10474 return figure 10475 } 10476 10477 get isPreviewableAttachment() { 10478 return this.isPreviewableImage || this.previewable 10479 } 10480 10481 get isPreviewableImage() { 10482 return isPreviewableImage(this.contentType) 10483 } 10484 10485 get isVideo() { 10486 return this.contentType.startsWith("video/") 10487 } 10488 10489 #createDOMForPendingPreview() { 10490 const figure = this.createAttachmentFigure(false); 10491 figure.appendChild(this.#createDOMForFile()); 10492 figure.appendChild(this.#createDOMForNotImage()); 10493 this.#pollForPreview(figure); 10494 return figure 10495 } 10496 10497 patchAndRewriteHistory(patch) { 10498 this.editor.dispatchCommand(REWRITE_HISTORY_COMMAND, { 10499 [this.getKey()]: { patch } 10500 }); 10501 } 10502 10503 replaceAndRewriteHistory(node) { 10504 this.editor.dispatchCommand(REWRITE_HISTORY_COMMAND, { 10505 [this.getKey()]: { replace: node } 10506 }); 10507 } 10508 10509 #createDOMForImage(options = {}) { 10510 const initialSrc = this.previewSrc || this.src; 10511 const img = createElement("img", { src: initialSrc, draggable: false, alt: this.altText, ...this.#imageDimensions, ...options }); 10512 10513 if (this.previewable && !this.isPreviewableImage) { 10514 img.onerror = () => this.#swapPreviewToFileDOM(img); 10515 } 10516 10517 if (this.previewSrc) { 10518 this.#preloadAndSwapSrc(img); 10519 } 10520 10521 const container = createElement("div", { className: "attachment__container" }); 10522 container.appendChild(img); 10523 return container 10524 } 10525 10526 #preloadAndSwapSrc(img) { 10527 const previewSrc = this.previewSrc; 10528 const serverImage = new Image(); 10529 10530 serverImage.onload = () => this.#handleImageLoaded(img, previewSrc); 10531 serverImage.onerror = () => this.#handleImageLoadError(previewSrc); 10532 serverImage.src = this.src; 10533 } 10534 10535 #handleImageLoaded(img, previewSrc) { 10536 img.src = this.src; 10537 this.patchAndRewriteHistory({ previewSrc: null }); 10538 this.#revokePreviewSrc(previewSrc); 10539 } 10540 10541 #handleImageLoadError(previewSrc) { 10542 this.patchAndRewriteHistory({ 10543 previewSrc: null, 10544 uploadError: true 10545 }); 10546 this.#revokePreviewSrc(previewSrc); 10547 } 10548 10549 #revokePreviewSrc(previewSrc) { 10550 if (previewSrc?.startsWith("blob:")) URL.revokeObjectURL(previewSrc); 10551 } 10552 10553 #swapPreviewToFileDOM(img) { 10554 const figure = img.closest("figure.attachment"); 10555 if (!figure) return 10556 10557 this.#swapFigureContent(figure, "attachment--preview", "attachment--file", () => { 10558 figure.appendChild(this.#createDOMForFile()); 10559 figure.appendChild(this.#createDOMForNotImage()); 10560 }); 10561 } 10562 10563 // While the file-icon is shown, watch for the preview to become ready. 10564 // With a status URL, poll it (2xx = processing, anything else = ready). 10565 // Without one, preload the preview URL once and swap on load. 10566 #pollForPreview(figure) { 10567 if (this.previewStatusUrl) { 10568 this.#waitForPreviewByPollingStatus(figure); 10569 } else { 10570 this.#waitForPreviewByPreloadingImage(figure); 10571 } 10572 } 10573 10574 #waitForPreviewByPollingStatus(figure) { 10575 let attempt = 0; 10576 10577 const tryStatus = async () => { 10578 if (!this.editor.read(() => this.isAttached())) return 10579
10580 try { 10581 // redirect: "manual" prevents fetch from transparently following a 10582 // 3xx response â without it, a status endpoint that redirected to, 10583 // say, the preview URL would resolve to a 200 and look like 10584 // "still processing." The contract is "any non-2xx means done." 10585 const response = await fetch(this.previewStatusUrl, { credentials: "include", redirect: "manual" }); 10586 10587 if (!this.editor.read(() => this.isAttached())) return 10588 10589 if (response.ok) { 10590 retry(); 10591 } else { 10592 this.#swapToPreviewDOM(figure, this.src); 10593 } 10594 } catch { 10595 retry(); 10596 } 10597 }; 10598 10599 const retry = () => { 10600 attempt++; 10601 if (attempt < MAX_PREVIEW_POLL_ATTEMPTS && this.editor.read(() => this.isAttached())) { 10602 const delay = Math.min(2000 * Math.pow(1.5, attempt), MAX_PREVIEW_POLL_DELAY_MS); 10603 setTimeout(tryStatus, delay); 10604 } 10605 }; 10606 10607 // Give the server time to start processing before the first attempt 10608 setTimeout(tryStatus, INITIAL_PREVIEW_POLL_DELAY_MS); 10609 } 10610 10611 #waitForPreviewByPreloadingImage(figure) { 10612 const img = new Image(); 10613 img.onload = () => { 10614 if (!this.editor.read(() => this.isAttached())) return 10615 this.#swapToPreviewDOM(figure, this.src); 10616 }; 10617 img.onerror = () => { 10618 // Clear pendingPreview so undo/redo or any JSON round-trip doesn't 10619 // re-enter the pending flow and issue another fetch. The file icon 10620 // stays as the stable fallback. 10621 if (!this.editor.read(() => this.isAttached())) return 10622 this.patchAndRewriteHistory({ pendingPreview: false }); 10623 }; 10624 img.src = this.src; 10625 } 10626 10627 #swapToPreviewDOM(figure, previewSrc) { 10628 this.#swapFigureContent(figure, "attachment--file", "attachment--preview", () => { 10629 const img = createElement("img", { src: previewSrc, draggable: false, alt: this.altText }); 10630 img.onerror = () => this.#swapPreviewToFileDOM(img); 10631 const container = createElement("div", { className: "attachment__container" }); 10632 container.appendChild(img); 10633 figure.appendChild(container); 10634 figure.appendChild(this.#createEditableCaption()); 10635 }); 10636 10637 this.patchAndRewriteHistory({ pendingPreview: false }); 10638 } 10639 10640 #swapFigureContent(figure, fromClass, toClass, renderContent) { 10641 figure.className = figure.className.replace(fromClass, toClass); 10642 10643 for (const child of [ ...figure.querySelectorAll(".attachment__container, .attachment__icon, figcaption") ]) { 10644 child.remove(); 10645 } 10646 10647 renderContent(); 10648 } 10649 10650 get #imageDimensions() { 10651 if (this.width && this.height) { 10652 return { width: this.width, height: this.height } 10653 } else { 10654 return {} 10655 } 10656 } 10657 10658 #createDOMForFile() { 10659 const extension = this.fileName ? this.fileName.split(".").pop().toLowerCase() : "unknown"; 10660 return createElement("span", { className: "attachment__icon", textContent: `${extension}` }) 10661 } 10662 10663 #createDOMForNotImage() { 10664 const figcaption = createElement("figcaption", { className: "attachment__caption" }); 10665 10666 const nameTag = createElement("strong", { className: "attachment__name", textContent: this.caption || this.fileName }); 10667 10668 figcaption.appendChild(nameTag); 10669 10670 if (this.fileSize) { 10671 const sizeSpan = createElement("span", { className: "attachment__size", textContent: bytesToHumanSize(this.fileSize) }); 10672 figcaption.appendChild(sizeSpan); 10673 } 10674 10675 return figcaption 10676 } 10677 10678 #createEditableCaption() { 10679 const caption = createElement("figcaption", { className: "attachment__caption" }); 10680 const input = createElement("textarea", { 10681 value: this.caption, 10682 placeholder: this.fileName, 10683 rows: "1" 10684 }); 10685 10686 input.addEventListener("focusin", () => input.placeholder = "Add caption..."); 10687 input.addEventListener("blur", (event) => this.#handleCaptionInputBlurred(event)); 10688 input.addEventListener("keydown", (event) => this.#handleCaptionInputKeydown(event)); 10689 input.addEventListener("copy", (event) => event.stopPropagation()); 10690 input.addEventListener("cut", (event) => event.stopPropagation()); 10691 input.addEventListener("paste", (event) => event.stopPropagation()); 10692 10693 caption.appendChild(input); 10694 10695 return caption 10696 } 10697 10698 #handleCaptionInputBlurred(event) { 10699 this.#updateCaptionValueFromInput(event.target); 10700 } 10701 10702 #updateCaptionValueFromInput(input) { 10703 input.placeholder = this.fileName; 10704 this.editor.update(() => { 10705 this.getWritable().caption = input.value; 10706 }); 10707 } 10708 10709 #handleCaptionInputKeydown(event) { 10710 if (event.key === "Enter") { 10711 event.preventDefault(); 10712 event.target.blur(); 10713 10714 this.editor.update(() => { 10715 // Place the cursor after the current image 10716 this.selectNext(0, 0); 10717 }, { 10718 tag: Jn 10719 }); 10720 } 10721 10722 // Stop all keydown events from bubbling to the Lexical root element. 10723 // The caption textarea is outside Lexical's content model and should 10724 // handle its own keyboard events natively (Ctrl+A, Ctrl+C, Ctrl+X, etc.). 10725 event.stopPropagation(); 10726 } 10727} 10728 10729function $createActionTextAttachmentNode(...args) { 10730 return new ActionTextAttachmentNode(...args) 10731} 10732 10733function $isActionTextAttachmentNode(node) { 10734 return node instanceof ActionTextAttachmentNode 10735} 10736 10737function filterDisallowedAttachmentNodes(nodes, editorElement) { 10738 return nodes 10739 .filter(node => !isDisallowedAttachment(node, editorElement)) 10740 .map(node => { 10741 Ht$3([ node ], descendant => isDisallowedAttachment(descendant, editorElement)) 10742 .forEach(descendant =>
10742 descendant.remove()); 10743 return node 10744 }) 10745} 10746 10747function isDisallowedAttachment(node, editorElement) { 10748 const isAttachmentNode = 10749 node instanceof CustomActionTextAttachmentNode || 10750 node instanceof ActionTextAttachmentNode; 10751 return isAttachmentNode && 10752 !editorElement.permitsAttachmentContentType(node.contentType) 10753} 10754 10755// Replaces inline `data:image/...` attachments with upload nodes that flow through the normal 10756// file upload pipeline. 10757// 10758// Without this step, pasted-from-Google-Docs-style content lands in the editor with the entire 10759// base64 image embedded in the attachment's `src`, which then persists into the saved HTML and 10760// bloats the stored document. 10761// 10762// Each conversion dispatches the cancelable `lexxy:file-accept` event so the host's allowlist (and 10763// any other listener) can refuse the synthesized File before it's accepted into the upload 10764// pipeline; on refusal, the node is dropped silently â matching how `Contents#uploadFiles` handles 10765// file-picker rejections. 10766function $convertInlineImageDataURIs(nodes, editorElement) { 10767 const topLevel = nodes 10768 .map(node => isInlineImageDataURIAttachment(node) ? $tryCreateUploadFromDataURI(node, editorElement) : node) 10769 .filter(node => node !== null); 10770 10771 for (const node of topLevel) { 10772 for (const desc of Ht$3([ node ], isInlineImageDataURIAttachment)) { 10773 const upload = $tryCreateUploadFromDataURI(desc, editorElement); 10774 if (upload) { 10775 desc.replace(upload); 10776 } else { 10777 desc.remove(); 10778 } 10779 } 10780 } 10781 10782 return topLevel 10783} 10784 10785function isInlineImageDataURIAttachment(node) { 10786 return node instanceof ActionTextAttachmentNode && 10787 /^data:image\/[^,]*;base64,/i.test(node.src ?? "") 10788} 10789 10790function $tryCreateUploadFromDataURI(node, editorElement) { 10791 const file = dataURIToFile(node.src); 10792 if (file && editorElement.acceptsFile(file)) { 10793 return editorElement.contents.$createUploadNode(file) 10794 } 10795 return null 10796} 10797 10798function dataURIToFile(dataURI) { 10799 try { 10800 const [ header, data ] = dataURI.split(","); 10801 10802 // https://datatracker.ietf.org/doc/html/rfc6838#section-4.2 10803 const mimeType = header.match(/^data:(image\/[A-Za-z0-9][A-Za-z0-9!#$&\-^_.+]*)/)?.[1]; 10804 if (mimeType) { 10805 const bytes = Uint8Array.from(atob(data), (c) => c.charCodeAt(0)); 10806 const extension = mimeTypeToExtension(mimeType) ?? "png"; 10807 return new File([ bytes ], `pasted-image-${Date.now()}.${extension}`, { type: mimeType }) 10808 } else { 10809 return null 10810 } 10811 } catch { 10812 return null 10813 } 10814} 10815 10816/** 10817 * Copyright (c) Meta Platforms, Inc. and affiliates. 10818 * 10819 * This source code is licensed under the MIT license found in the 10820 * LICENSE file in the root directory of this source tree. 10821 * 10822 */ 10823 10824function C$1(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);throw n.search=r.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function N$1(t,e){let r=t;for(let o=Ol(t,e);o&&(X$1(o.origin)||Er(o.origin));o=o.getAdjacentCaret())r=o.origin;return r}function O(t){return N$1(t,"previous")}function A(t){return N$1(t,"next")}function H$1(n){const r=O(n),i=A(n);let o=r;for(;null!==o;){if(X$1(o)){const e=Fo(o.getTextContent());if(null!==e)return e}if(o===i)break;o=o.getNextSibling();}const s=r.getParent();if(Wi(s)){const t=s.getDirection();if("ltr"===t||"rtl"===t)return t}return null}function L$2(t,e){let i=null,o=null,s=t,l=e,u=t.getTextContent();for(;;){if(0===l){if(s=s.getPreviousSibling(),null===s)break;if(X$1(s)||Er(s)||sr(s)||C$1(167),sr(s)){i={node:s,offset:1};break}l=Math.max(0,s.getTextContentSize()-1),u=s.getTextContent();}else l--;const t=u[l];X$1(s)&&" "!==t&&(o={node:s,offset:l});}if(null!==o)return o;let g=null;if(e<t.getTextContentSize())X$1(t)&&(g=t.getTextContent()[e]);else {const e=t.getNextSibling();X$1(e)&&(g=e.getTextContent()[0]);}if(null!==g&&" "!==g)return i;{const n=function(t,e){let n=t,i=e,o=t.getTextContent(),s=t.getTextContentSize();for(;;){if(!X$1(n)||i===s){if(n=n.getNextSibling(),null===n||sr(n))return null;X$1(n)&&(i=0,o=n.getTextContent(),s=n.getTextContentSize());}if(X$1(n)){if(" "!==o[i])return {node:n,offset:i};i++;}}}(t,e);return null!==n?n:i}}function F$1(t){const e=A(t);return sr(e)&&C$1(168),e}const J$3="javascript";function M$1(t,e){for(const n of t.childNodes){if(Ys(n)&&n.tagName===e)return true;M$1(n,e);}return false}
10824const k$1="data-language",w$1="data-highlight-language",P$1="data-theme";let z$1 = class z extends Bi{__language;__theme;__isSyntaxHighlightSupported;static getType(){return "code"}static clone(t){return new z(t.__language,t.__key)}constructor(t,e){super(e),this.__language=t||void 0,this.__isSyntaxHighlightSupported=false,this.__theme=void 0;}afterCloneFrom(t){super.afterCloneFrom(t),this.__language=t.__language,this.__theme=t.__theme,this.__isSyntaxHighlightSupported=t.__isSyntaxHighlightSupported;}createDOM(t){const e=document.createElement("code");mc(e,t.theme.code),e.setAttribute("spellcheck","false");const n=this.getLanguage();n&&(e.setAttribute(k$1,n),this.getIsSyntaxHighlightSupported()&&e.setAttribute(w$1,n));const r=this.getTheme();r&&e.setAttribute(P$1,r);const i=this.getStyle();return i&&nr(e.style,i),e}updateDOM(t,e,n){const r=this.__language,i=t.__language;r?r!==i&&e.setAttribute(k$1,r):i&&e.removeAttribute(k$1);const o=this.__isSyntaxHighlightSupported;t.__isSyntaxHighlightSupported&&i?o&&r?r!==i&&e.setAttribute(w$1,r):e.removeAttribute(w$1):o&&r&&e.setAttribute(w$1,r);const s=this.__theme,l=t.__theme;s?s!==l&&e.setAttribute(P$1,s):l&&e.removeAttribute(P$1);const g=this.__style,a=t.__style;return g!==a&&nr(e.style,g,a),false}exportDOM(t){const e=document.createElement("pre");mc(e,t._config.theme.code),e.setAttribute("spellcheck","false");const n=this.getLanguage();n&&(e.setAttribute(k$1,n),this.getIsSyntaxHighlightSupported()&&e.setAttribute(w$1,n));const r=this.getTheme();r&&e.setAttribute(P$1,r);const i=this.getStyle();return i&&nr(e.style,i),{element:e}}static importDOM(){return {code:t=>null!=t.textContent&&(/\r?\n/.test(t.textContent)||M$1(t,"BR"))?{conversion:j$1,priority:1}:null,div:()=>({conversion:R,priority:1}),pre:()=>({conversion:j$1,priority:0}),table:t=>q$1(t)?{conversion:B$1,priority:3}:null,td:t=>{const e=t,n=e.closest("table");return e.classList.contains("js-file-line")||n&&q$1(n)?{conversion:U$2,priority:3}:null},tr:t=>{const e=t.closest("table");return e&&q$1(e)?{conversion:U$2,priority:3}:null}}}static importJSON(t){return I$1().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setLanguage(t.language).setTheme(t.theme)}exportJSON(){return {...super.exportJSON(),language:this.getLanguage(),theme:this.getTheme()}}insertNewAfter(t,e=true){if(!fe$3(Zs(),"@lexical/code")){const e=G$3(t);if(e)return e}const{anchor:r,focus:i}=t,o=(r.isBefore(i)?r:i).getNode();if(Tr(o)){let t=O(o);const e=[];for(;;)if(Er(t))e.push(wr()),t=t.getNextSibling();else {if(!X$1(t))break;{let n=0;const r=t.getTextContent(),i=t.getTextContentSize();for(;n<i&&" "===r[n];)n++;if(0!==n&&e.push(V$2(" ".repeat(n))),n!==i)break;t=t.getNextSibling();}}const i=o.splitText(r.offset)[0],s=0===r.offset?0:1,l=i.getIndexWithinParent()+s,u=o.getParentOrThrow(),g=[or(),...e];u.splice(l,0,g);const a=e[e.length-1];a?a.select():0===r.offset?i.selectPrevious():i.getNextSibling().selectNext(0,0);}if(W$1(o)){const{offset:e}=t.anchor;o.splice(e,0,[or()]),o.select(e+1,e+1);}return null}canIndent(){return false}collapseAtStart(){const t=eo();
10824return this.getChildren().forEach(e=>t.append(e)),this.replace(t),true}setLanguage(t){const e=this.getWritable();return e.__language=t||void 0,e}getLanguage(){return this.getLatest().__language}setIsSyntaxHighlightSupported(t){const e=this.getWritable();return e.__isSyntaxHighlightSupported=t,e}getIsSyntaxHighlightSupported(){return this.getLatest().__isSyntaxHighlightSupported}setTheme(t){const e=this.getWritable();return e.__theme=t||void 0,e}getTheme(){return this.getLatest().__theme}};function I$1(t,e){return fl(z$1).setLanguage(t).setTheme(e)}function W$1(t){return t instanceof z$1}function j$1(t){return {node:I$1(t.getAttribute(k$1))}}function R(t){const e=t,n=$$1(e);return n||function(t){let e=t.parentElement;for(;null!==e;){if($$1(e))return true;e=e.parentElement;}return false}(e)?{node:n?I$1():null}:{node:null}}function B$1(){return {node:I$1()}}function U$2(){return {node:null}}function $$1(t){return null!==t.style.fontFamily.match("monospace")}function q$1(t){return t.classList.contains("js-file-line-container")}function G$3(t){const{anchor:e}=t;if(t.isCollapsed()&&"element"===e.type){const t=e.getNode();if(W$1(t)){const n=t.getChildrenSize();if(n>=2&&e.offset===n){const e=t.getLastChild();if(sr(e)&&sr(e.getPreviousSibling())){const e=eo();return t.splice(n-2,2,[]).insertAfter(e,false),e.select(),e}}}}return null}let K$1 = class K extends gr{__highlightType;constructor(t="",e,n){super(t,n),this.__highlightType=e;}static getType(){return "code-highlight"}static clone(t){return new K(t.__text,t.__highlightType||void 0,t.__key)}afterCloneFrom(t){super.afterCloneFrom(t),this.__highlightType=t.__highlightType;}getHighlightType(){return this.getLatest().__highlightType}setHighlightType(t){const e=this.getWritable();return e.__highlightType=t||void 0,e}canHaveFormat(){return false}createDOM(t){const e=super.createDOM(t),n=Q$2(t.theme,this.__highlightType);return mc(e,n),e}updateDOM(t,e,n){const r=super.updateDOM(t,e,n),i=Q$2(n.theme,t.__highlightType),o=Q$2(n.theme,this.__highlightType);return i!==o&&(i&&xc(e,i),o&&mc(e,o)),r}static importJSON(t){return V$2().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setHighlightType(t.highlightType)}exportJSON(){return {...super.exportJSON(),highlightType:this.getHighlightType()}}setFormat(t){return this}isParentRequired(){return true}createParentElementNode(){return I$1()}};function Q$2(t,e){return e&&t&&t.codeHighlight&&t.codeHighlight[e]}function V$2(t="",e){return zs(new K$1(t,e))}function X$1(t){return t instanceof K$1} 10825 10826/** 10827 * Copyright (c) Meta Platforms, Inc. and affiliates. 10828 * 10829 * This source code is licensed under the MIT license found in the 10830 * LICENSE file in the root directory of this source tree. 10831 * 10832 */ 10833 10834function J$2(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}!function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach(function(n){var r=t[n],o=[];/^\w+$/.test(n)||o.push(/\w+/.exec(n)[0]),"diff"===n&&o.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:o,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:true},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}};}),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t});}(Prism);const U$1=globalThis.Prism||window.Prism,Q$1={c:"C",clike:"C-like",cpp:"C++",css:"CSS",html:"HTML",java:"Java",js:"JavaScript",markdown:"Markdown",objc:"Objective-C",plain:"Plain Text",powershell:"PowerShell",py:"Python",rust:"Rust",sql:"SQL",swift:"Swift",typescript:"TypeScript",xml:"XML"},G$2={cpp:"cpp",java:"java",javascript:"js",md:"markdown",plaintext:"plain",python:"py",text:"plain",ts:"typescript"};function V$1(e){return G$2[e]||e}function te$1(e){const t=function(e){const t=/^diff-([\w-]+)/i.exec(e);return t?t[1]:null}(e),n=t||e;try{return !!n&&U$1.languages.hasOwnProperty(n)}catch(e){return false}}
10834async function ne$1(e,t,n){}function re$2(e){return "string"==typeof e?e:Array.isArray(e)?e.map(re$2).join(""):re$2(e.content)}function oe$2(e,t){const n=/^diff-([\w-]+)/i.exec(t),r=e.getTextContent();let o=U$1.tokenize(r,U$1.languages[n?"diff":t]);return n&&(o=function(e,t){const n=t,r=U$1.languages[n],o={tokens:e},s=U$1.languages.diff.PREFIXES;for(const e of o.tokens){if("string"==typeof e||!(e.type in s)||!Array.isArray(e.content))continue;const t=e.type;let n=0;const o=()=>(n++,new U$1.Token("prefix",s[t],t.replace(/^(\w+).*/,"$1"))),i=e.content.filter(e=>"string"==typeof e||"prefix"!==e.type),c=e.content.length-i.length,l=U$1.tokenize(re$2(i),r);l.unshift(o());const a=/\r\n|\n/g,f=e=>{const t=[];a.lastIndex=0;let r,s=0;for(;n<c&&(r=a.exec(e));){const n=r.index+r[0].length;t.push(e.slice(s,n)),s=n,t.push(o());}if(0!==t.length)return s<e.length&&t.push(e.slice(s)),t},u=e=>{for(let t=0;t<e.length&&n<c;t++){const n=e[t];if("string"==typeof n){const r=f(n);r&&(e.splice(t,1,...r),t+=r.length-1);}else if("string"==typeof n.content){const e=f(n.content);e&&(n.content=e);}else Array.isArray(n.content)?u(n.content):u([n.content]);}};u(l),n<c&&l.push(o()),e.content=l;}return o.tokens}(o,n[1])),se$2(o)}function se$2(t,n){const r=[];for(const o of t)if("string"==typeof o){const t=o.split(/(\n|\t)/),s=t.length;for(let o=0;o<s;o++){const s=t[o];"\n"===s||"\r\n"===s?r.push(or()):"\t"===s?r.push(wr()):s.length>0&&r.push(V$2(s,n));}}else {const{content:e,alias:t}=o;"string"==typeof e?r.push(...se$2([e],"prefix"===o.type&&"string"==typeof t?t:o.type)):Array.isArray(e)&&r.push(...se$2(e,"unchanged"===o.type?void 0:o.type));}return r}const ie$1={$tokenize(e,t){return oe$2(e,t||this.defaultLanguage)},defaultLanguage:J$3,tokenize(e,t){return U$1.tokenize(e,U$1.languages[t||""]||U$1.languages[this.defaultLanguage])}};function ce$1(e,t,o,s){const i=s.getParent();W$1(i)?ae$1(e,t,o,i):X$1(s)&&s.replace(kr(s.__text));}function le$1(e,t){const n=t.getElementByKey(e.getKey());if(null===n)return;const r=e.getChildren(),o=r.length;if(o===n.__cachedChildrenLength)return;n.__cachedChildrenLength=o;let s="1",i=1;for(let e=0;e<o;e++)sr(r[e])&&(s+="\n"+ ++i);n.setAttribute("data-gutter",s);}function ae$1(e,t,r,o){const{nodesCurrentlyHighlighting:s}=r,i=o.getKey();void 0===o.getLanguage()&&o.setLanguage(t.defaultLanguage);const c=o.getLanguage()||t.defaultLanguage;if(!te$1(c))return o.getIsSyntaxHighlightSupported()&&o.setIsSyntaxHighlightSupported(false),void ne$1();o.getIsSyntaxHighlightSupported()||o.setIsSyntaxHighlightSupported(true),s.has(i)||(s.add(i),r.didTransform||(r.didTransform=true,Ms(()=>{r.didTransform=false,s.clear();})),function(e,t){const r=Yo(e);if(!W$1(r)||!r.isAttached())return;const o=Qr();if(!Fr(o))return void t();const s=o.anchor,i=s.offset,c="element"===s.type&&sr(r.getChildAtIndex(s.offset-1));let l=0;if(!c){const e=s.getNode();l=i+e.getPreviousSiblings().reduce((e,t)=>e+t.getTextContentSize(),0);}if(!t())return;if(c)return void s.getNode().select(i,i);r.getChildren().some(e=>{const t=Tr(e);if(t||sr(e)){const n=e.getTextContentSize();if(t&&n>=l)return e.select(l,l),true;l-=n;}return false});}(i,()=>{const e=Yo(i);if(!W$1(e)||!e.isAttached())return false;const r=e.getLanguage()||t.defaultLanguage,s=t.$tokenize(e,r),c=function(e,t){let n=0;for(;n<e.length&&fe$1(e[n],t[n]);)n++;const r=e.length,o=t.length,s=Math.min(r,o)-n;let i=0;for(;i<s;)if(i++,!fe$1(e[r-i],t[o-i])){i--;break}const c=n,l=r-i,a=t.slice(n,o-i);return {from:c,nodesForReplacement:a,to:l}}(e.getChildren(),s),{from:l,to:a,nodesForReplacement:f}=c;return !(l===a&&!f.length)&&(o.splice(l,a-l,f),true)}));}function fe$1(e,t){return X$1(e)&&X$1(t)&&e.__text===t.__text&&e.__highlightType===t.__highlightType||Er(e)&&Er(t)||sr(e)&&sr(t)}function ue$1(e){if(!Fr(e))return false;const t=e.anchor.getNode(),r=W$1(t)?t:t.getParent(),o=e.focus.getNode(),s=W$1(o)?o:o.getParent();return W$1(r)&&r.is(s)}function ge$1(e){const t=e.getNodes(),o=[];if(1===t.length&&W$1(t[0]))return o;let s=[];for(let e=0;e<t.length;e++){const n=t[e];X$1(n)||Er(n)||sr(n)||J$2(169),sr(n)?s.length>0&&(o.push(s),s=[]):s.push(n);}if(s.length>
108340){const t=e.isBackward()?e.anchor:e.focus,n=Mr(s[0].getKey(),0,"text");t.is(n)||o.push(s);}return o}function pe$1(e){const t=Qr();if(!Fr(t)||!ue$1(t))return false;const n=ge$1(t),r=n.length;if(0===r&&t.isCollapsed())return e===Ie$3&&t.insertNodes([wr()]),true;if(0===r&&e===Ie$3&&"\n"===t.getTextContent()){const e=wr(),n=or(),r=t.isBackward()?"previous":"next";return t.insertNodes([e,n]),Gl(sc(Wl(Ml(e,"next",0),rc(Ol(n,"next"))),r)),true}for(let s=0;s<r;s++){const r=n[s];if(r.length>0){let n=r[0];if(0===s&&(n=O(n)),e===Ie$3){const e=wr();if(n.insertBefore(e),0===s){const r=t.isBackward()?"focus":"anchor",o=Mr(n.getKey(),0,"text");t[r].is(o)&&t[r].set(e.getKey(),0,"text");}}else Er(n)&&n.remove();}}return true}function de$1(e,t){const n=Qr();if(!Fr(n))return false;const{anchor:i,focus:c}=n,l=i.offset,a=c.offset,f=i.getNode(),u=c.getNode(),g=e===we$1;if(!ue$1(n)||!X$1(f)&&!Er(f)||!X$1(u)&&!Er(u))return false;if(!t.altKey){if(n.isCollapsed()){const e=f.getParentOrThrow();if(g&&0===l&&null===f.getPreviousSibling()){if(null===e.getPreviousSibling())return e.selectPrevious(),t.preventDefault(),true}else if(!g&&l===f.getTextContentSize()&&null===f.getNextSibling()){if(null===e.getNextSibling())return e.selectNext(),t.preventDefault(),true}}return false}let p,d;if(f.isBefore(u)?(p=O(f),d=A(u)):(p=O(u),d=A(f)),null==p||null==d)return false;const m=p.getNodesBetween(d);for(let e=0;e<m.length;e++){const t=m[e];if(!X$1(t)&&!Er(t)&&!sr(t))return false}t.preventDefault(),t.stopPropagation();const h=g?p.getPreviousSibling():d.getNextSibling();if(!sr(h))return true;const x=g?h.getPreviousSibling():h.getNextSibling();if(null==x)return true;const j=X$1(x)||Er(x)||sr(x)?g?O(x):A(x):null;let w=null!=j?j:x;return h.remove(),m.forEach(e=>e.remove()),e===we$1?(m.forEach(e=>w.insertBefore(e)),w.insertBefore(h)):(w.insertAfter(h),w=h,m.forEach(e=>{w.insertAfter(e),w=e;})),n.setTextNodeRange(f,l,u,a),true}function me$1(e,t){const n=Qr();if(!Fr(n))return false;const{anchor:o,focus:s}=n,a=o.getNode(),f=s.getNode(),u=e===be$1;if(!ue$1(n)||!X$1(a)&&!Er(a)||!X$1(f)&&!Er(f))return false;const g=f;if("rtl"===H$1(g)?!u:u){const e=L$2(g,s.offset);if(null!==e){const{node:t,offset:r}=e;sr(t)?t.selectNext(0,0):n.setTextNodeRange(t,r,t,r);}else g.getParentOrThrow().selectStart();}else {F$1(g).select();}return t.preventDefault(),t.stopPropagation(),true}function he$1(e,t){if(!e.hasNodes([z$1,K$1]))throw new Error("CodeHighlightPlugin: CodeNode or CodeHighlightNode not registered on editor");null==t&&(t=ie$1);const n=[];true!==e._headless&&n.push(e.registerMutationListener(z$1,t=>{e.getEditorState().read(()=>{for(const[n,r]of t)if("destroyed"!==r){const t=Yo(n);null!==t&&le$1(t,e);}});},{skipInitialization:false}));const r={didTransform:false,nodesCurrentlyHighlighting:new Set};return n.push(e.registerNodeTransform(z$1,ae$1.bind(null,e,t,r)),e.registerNodeTransform(gr,ce$1.bind(null,e,t,r)),e.registerNodeTransform(K$1,ce$1.bind(null,e,t,r)),e.registerCommand(Fe$2,t=>{const n=function(e){const t=Qr();if(!Fr(t)||!ue$1(t))return null;const n=e?Ke$2:Ie$3,r=e?Ke$2:Le$2,i=t.anchor,c=t.focus;if(i.is(c))return r;const l=ge$1(t);if(1!==l.length)return n;const a=l[0];let f,u;0===a.length&&J$2(285),t.isBackward()?(f=c,u=i):(f=i,u=c);const g=O(a[0]),p=A(a[0]),d=Mr(g.getKey(),0,"text"),m=Mr(p.getKey(),p.getTextContentSize(),"text");return f.isBefore(d)||m.isBefore(u)?n:d.isBefore(f)||u.isBefore(m)?r:n}(t.shiftKey);return null!==n&&(t.preventDefault(),e.dispatchCommand(n,void 0),true)},io),e.registerCommand(Le$2,()=>!!ue$1(Qr())&&(li([wr()]),true),io),e.registerCommand(Ie$3,e=>pe$1(Ie$3),io),e.registerCommand(Ke$2,e=>pe$1(Ke$2),io),e.registerCommand(we$1,e=>{const t=Qr();if(!Fr(t)||!ue$1(t))return false;const n=Zo().getFirstDescendant(),{anchor:r}=t,o=r.getNode();return (!n||!o||n.getKey()!==o.getKey())&&de$1(we$1,e)},io),e.registerCommand(Ee$3,e=>{const t=Qr();if(!Fr(t)||!ue$1(t))return false;const n=Zo().getLastDescendant(),{anchor:r}=t,o=r.getNode();return (!n||!o||n.getKey()!==o.getKey())&&de$1(Ee$3,e)},io),e.registerCommand(be$1,e=>me$1(be$1,e),io),e.registerCommand(Te$2,e=>me$1(Te$2,e),io)),Cc(...n)} 10835 10836/** 10837 * Copyright (c) Meta Platforms, Inc. and affiliates. 10838 * 10839 * This source code is licensed under the MIT license found in the 10840 * LICENSE file in the root directory of this source tree. 10841 * 10842 */ 10843 10844const o=Q$1,a=V$1,r=ie$1,L$1=he$1; 10845 10846/** 10847 * Copyright (c) Meta Platforms, Inc. and affiliates. 10848 * 10849 * This source code is licensed under the MIT license found in the 10850 * LICENSE file in the root directory of this source tree. 10851 * 10852 */ 10853 10854function G$1(t,e){const n={};for(const o of t){const t=e(o);t&&(n[t]?n[t].push(o):n[t]=[o]);}return n}function H(t){const e=G$1(t,t=>t.type);return {element:e.element||[],multilineElement:e["multiline-element"]||[],textFormat:e["text-format"]||[],textMatch:e["text-match"]||[]}}const J$1=/[!-/:-@[-`{-~\s]/;function Z(t){return t.replace(/\\([!-/:-@[-`{-~])/g,"$1").replace(/&#(\d+);/g,(t,e)=>String.fromCodePoint(Number(e)))}function at(t){return Tr(t)&&!t.hasFormat("code")}function ht(t,...e){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",t);for(const t of e)o.append("v",t);throw n.search=o.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}const xt=/^(\s*)(\d{1,})\.\s/,mt$1=/^(\s*)[-*+]\s/,Tt$1=/^(#{1,6})\s/,$t$1=/^>\s/,vt=/^([ \t]*`{3,})([\w-]+)?[ \t]?/,yt$1=/^[ \t]*`{3,}$/,Ft$1=ot$3("mdListMarker",{parse:t=>"string"==typeof t&&/^[-*+]$/.test(t)?t:"-",resetOnCopyNode:true}),Lt$1=ot$3("mdCodeFence",{parse:t=>"string"==typeof t&&/^`{3,}$/.test(t)?t:"```",resetOnCopyNode:true}),kt$1=t=>(e,n,o,r)=>{const s=t(o);s.append(...n),e.replace(s),r||s.select(0,0);};const Rt$1=t=>(e,n,o,r)=>{const s=e.getPreviousSibling(),i=e.getNextSibling(),l=fe$2("check"===t?"x"===o[3]:void 0),c=o[0].trim()[0],a="bullet"!==t&&"check"!==t||c!==Ft$1.parse(c)?void 0:c;if(Se$1(i)&&i.getListType()===t){a&&ct$2(i,Ft$1,a);const t=i.getFirstChild();null!==t?t.insertBefore(l):i.append(l),e.remove();}else if(Se$1(s)&&s.getListType()===t)a&&ct$2(s,Ft$1,a),s.append(l),e.remove();else {const n=Te$1(t,"number"===t?Number(o[2]):void 0);a&&ct$2(n,Ft$1,a),n.append(l),e.replace(n);}l.append(...n),r||l.select(0,0);const f=function(t){const e=t.match(/\t/g),n=t.match(/ /g);let o=0;return e&&(o+=e.length),n&&(o+=Math.floor(n.length/4)),o}(o[1]);f&&l.setIndent(f);},Mt$1=(t,e,n)=>{const o=[],r=t.getChildren();let s=0;for(const i of r)if(pe$2(i)){if(1===i.getChildrenSize()){const t=i.getFirstChild();if(Se$1(t)){o.push(Mt$1(t,e,n+1));continue}}const r=" ".repeat(4*n),l=t.getListType(),c=st$2(t,Ft$1),a="number"===l?`${t.getStart()+s}. `:"check"===l?`${c} [${i.getChecked()?"x":" "}] `:c+" ";let f=e(i);"number"!==l&&(f=f.replace(/^(\s{0,3}\d+)(\.\s)/,"$1\\$2")),o.push(r+a+f),s++;}return o.join("\n")},_t={dependencies:[It$1],export:(t,e)=>{if(!Lt$2(t))return null;const n=Number(t.getTag().slice(1));return "#".repeat(n)+" "+e(t)},regExp:Tt$1,replace:kt$1(t=>{const e="h"+t[1].length;return Jt$2(e)}),type:"element"}
10854,Bt$1={dependencies:[At$1],export:(t,e)=>{if(!Mt$2(t))return null;const n=e(t).split("\n"),o=[];for(const t of n)o.push("> "+t);return o.join("\n")},regExp:$t$1,replace:(t,e,n,o)=>{if(o){const n=t.getPreviousSibling();if(Mt$2(n))return n.splice(n.getChildrenSize(),0,[or(),...e]),void t.remove()}const r=St$1();r.append(...e),t.replace(r),o||r.select(0,0);},type:"element"},Ot$1={dependencies:[z$1],export:t=>{if(!W$1(t))return null;const e=t.getTextContent();let n=st$2(t,Lt$1);if(e.indexOf(n)>-1){const t=e.match(/`{3,}/g);if(t){const e=Math.max(...t.map(t=>t.length));n="`".repeat(e+1);}}return n+(t.getLanguage()||"")+(e?"\n"+e:"")+"\n"+n},handleImportAfterStartMatch:({lines:t,rootNode:e,startLineIndex:n,startMatch:o})=>{const r=o[1],s=r.trim().length,i=t[n],l=o.index+r.length,c=i.slice(l),a=new RegExp(`\`{${s},}$`);if(a.test(c)){const t=c.match(a),r=c.slice(0,c.lastIndexOf(t[0])),s=[...o];return s[2]="",Ot$1.replace(e,null,s,t,[r],true),[true,n]}const f=new RegExp(`^[ \\t]*\`{${s},}$`);for(let r=n+1;r<t.length;r++){const s=t[r];if(f.test(s)){const l=s.match(f),c=t.slice(n+1,r),a=i.slice(o[0].length);return a.length>0&&c.unshift(a),Ot$1.replace(e,null,o,l,c,true),[true,r]}}const u=t.slice(n+1),g=i.slice(o[0].length);return g.length>0&&u.unshift(g),Ot$1.replace(e,null,o,null,u,true),[true,t.length-1]},regExpEnd:{optional:true,regExp:yt$1},regExpStart:vt,replace:(t,e,n,o,r,s)=>{let i,c;const a=n[1]?n[1].trim():"```",f=n[2]||void 0;if(!e&&r){if(1===r.length)o?(i=I$1(f),c=r[0]):(i=I$1(f),c=r[0].startsWith(" ")?r[0].slice(1):r[0]);else {for(i=I$1(f),r.length>0&&(0===r[0].trim().length?r.shift():r[0].startsWith(" ")&&(r[0]=r[0].slice(1)));r.length>0&&!r[r.length-1].length;)r.pop();c=r.join("\n");}ct$2(i,Lt$1,a);const e=kr(c);i.append(e),t.append(i);}else e&&kt$1(t=>I$1(t?t[2]:void 0))(t,e,n,s);},type:"multiline-element"},jt$1={dependencies:[me$2,ge$2],export:(t,e)=>Se$1(t)?Mt$1(t,e,0):null,regExp:mt$1,replace:Rt$1("bullet"),type:"element"},Pt$1={dependencies:[me$2,ge$2],export:(t,e)=>Se$1(t)?Mt$1(t,e,0):null,regExp:xt,replace:Rt$1("number"),type:"element"},zt$1={format:["code"],tag:"`",type:"text-format"},Ut$1={format:["highlight"],tag:"==",type:"text-format"},Wt$1={format:["bold","italic"],tag:"***",type:"text-format"},Dt$1={format:["bold","italic"],intraword:false,tag:"___",type:"text-format"},Kt$1={format:["bold"],tag:"**",type:"text-format"},qt$1={format:["bold"],intraword:false,tag:"__",type:"text-format"},Gt$1={format:["strikethrough"],tag:"~~",type:"text-format"},Ht$1={format:["italic"],tag:"*",type:"text-format"},Jt$1={format:["italic"],intraword:false,tag:"_",type:"text-format"},Qt$1={dependencies:[F$4],export:(t,e,n)=>{if(!z$5(t)||G$8(t))return null;const o=e(t);let r=t.getTitle();null!=r&&(r=r.replace(/([\\"])/g,"\\$1"));return r?`[${o}](${t.getURL()} "${r}")`:`[${o}](${t.getURL()})`},importRegExp:/(?:\[(.+?)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/,regExp:/(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,replace:(t,e)=>{if(dl(t,z$5))return;const[,n,o,r]=e,s=null!=o?Z(o):void 0,i=null!=r?Z(r):void 0,c=$$2(s,{title:i}),a=n.split("[").length-1,f=n.split("]").length-1;let u=n,g="";if(a<f)return;if(a>f){const t=n.split("[");g="["+t[0],u=t.slice(1).join("[");}const d=kr(u);return d.setFormat(t.getFormat()),c.append(d),t.replace(c),g&&c.insertBefore(kr(g)),d},trigger:")",type:"text-match"},Vt$1=[_t,Bt$1,jt$1,Pt$1],Xt$1=[Ot$1],Yt$1=[zt$1,Wt$1,Dt$1,Kt$1,qt$1,Ut$1,Ht$1,Jt$1,Gt$1],Zt$1=[Qt$1],te=[...Vt$1,...Xt$1,...Yt$1,...Zt$1];function ee(t,e,n,o,r){const s=t.getParent();if(!Is(s)||t.getFirstChild()!==e)return false;const i=e.getTextContent();if(!r&&" "!==i[n-1])return false;for(const{regExpStart:s,replace:l,regExpEnd:c}of o){if(c&&!("optional"in c)||c&&"optional"in c&&!c.optional)continue;const o=i.match(s);if(o){const s=r||o[0].endsWith(" ")?n:n-1;if(o[0].length!==s)continue;const i=e.getNextSiblings(),[c,a]=e.splitText(n);if(false!==l(t,a?[a,...i]:i,o,null,null,false))return c.remove(),true}}return false}function ne(t,e){let n=0;const o=t.getTextContent();for(let t=0;t<e;t++)"`"===o[t]&&n++;return n%2!=0}function oe$1(t,e,n){const o=n.length;for(let r=e;r>=o;r--){const e=r-o;if(re$1(t,e,n,0,o)&&" "!==t[e+o])return e}return -1}function re$1(t,e,n,o,r){for(let s=0;s<r;s++)if(t[e+s]!==n[o+s])return false;return true}function se$1(t,n=te){const o=H(n),r=G$1(o.textFormat,({tag:t})=>t[t.length-1]),l=G$1(o.textMatch,({trigger:t})=>t);for(const e of n){const n=e.type;if("element"===n||"text-match"===n||"multiline-element"===n){const n=e.dependencies;
10854for(const e of n)t.hasNode(e)||ht(173,e.getType());}}const c=(t,n,c)=>!!function(t,e,n,o){const r=t.getParent();if(!Is(r)||t.getFirstChild()!==e)return false;const s=e.getTextContent();if(" "!==s[n-1])return false;for(const{regExp:r,replace:i}of o){const o=s.match(r);if(o&&o[0].length===(o[0].endsWith(" ")?n:n-1)){const r=e.getNextSiblings(),[s,l]=e.splitText(n);if(false!==i(t,l?[l,...r]:r,o,false))return s.remove(),true}}return false}(t,n,c,o.element)||(!!ee(t,n,c,o.multilineElement)||(!!function(t,e,n){let o=t.getTextContent();const r=n[o[e-1]];if(null==r)return false;e<o.length&&(o=o.slice(0,e));for(const e of r){if(!e.replace||!e.regExp)continue;const n=o.match(e.regExp);if(null===n)continue;const r=n.index||0,s=r+n[0].length;let i;return 0===r?[i]=t.splitText(s):[,i]=t.splitText(r,s),i.selectNext(0,0),e.replace(i,n),true}return false}(n,c,l)||!!function(t,n,o){const r=t.getTextContent(),l=n-1,c=r[l],a=o[c];if(!a)return false;for(const n of a){const{tag:o}=n,a=o.length,f=l-a+1;if(a>1&&!re$1(r,f,o,0,a))continue;if(" "===r[f-1])continue;const u=r[l+1];if(false===n.intraword&&u&&!J$1.test(u))continue;const g=t;let d=g,p=oe$1(r,f,o),h=d;for(;p<0&&(h=h.getPreviousSibling())&&!sr(h);)if(Tr(h)){if(h.hasFormat("code"))continue;const t=h.getTextContent();d=h,p=oe$1(t,t.length,o);}if(p<0)continue;if(d===g&&p+a===f)continue;const x=d.getTextContent();if(p>0&&x[p-1]===c)continue;const m=x[p-1];if(false===n.intraword&&m&&!J$1.test(m))continue;if(!n.format.includes("code")&&ne(d,p))continue;const T=g.getTextContent(),$=T.slice(0,f)+T.slice(l+1);g.setTextContent($);const v=d===g?$:x;d.setTextContent(v.slice(0,p)+v.slice(p+a));const y=Qr(),E=qr();es(E);const S=l-a*(d===g?2:1)+1;E.anchor.set(d.__key,p,"text"),E.focus.set(g.__key,S,"text");for(const t of n.format)E.hasFormat(t)||E.formatText(t);E.anchor.set(E.focus.key,E.focus.offset,E.focus.type);for(const t of n.format)E.hasFormat(t)&&E.toggleFormat(t);return Fr(y)&&(E.format=y.format),true}return false}(n,c,r)));return Cc(t.registerUpdateListener(({tags:n,dirtyLeaves:o,editorState:r,prevEditorState:s})=>{if(n.has(Un)||n.has(Wn$1))return;if(t.isComposing())return;const l=r.read(Qr),a=s.read(Qr);if(!Fr(a)||!Fr(l)||!l.isCollapsed()||l.is(a))return;const f=l.anchor.key,u=l.anchor.offset,g=r._nodeMap.get(f);!Tr(g)||!o.has(f)||1!==u&&u>a.anchor.offset+1||t.update(()=>{if(!at(g))return;const t=g.getParent();null===t||W$1(t)||c(t,g,l.anchor.offset)&&Os($n$1);});}),t.registerCommand(Oe$2,t=>{if(null!==t&&t.shiftKey)return false;const n=Qr();if(!Fr(n)||!n.isCollapsed())return false;const r=n.anchor.offset,s=n.anchor.getNode();if(!Tr(s)||!at(s))return false;const l=s.getParent();if(null===l||W$1(l))return false;return r===s.getTextContent().length&&(!!ee(l,s,r,o.multilineElement,true)&&(null!==t&&t.preventDefault(),true))},io))} 10855 10856class HorizontalDividerNode extends Ji { 10857 static getType() { 10858 return "horizontal_divider" 10859 } 10860 10861 static clone(node) { 10862 return new HorizontalDividerNode(node.__key) 10863 } 10864 10865 static importJSON(serializedNode) { 10866 return new HorizontalDividerNode() 10867 } 10868 10869 static importDOM() { 10870 return { 10871 "hr": (hr) => { 10872 return { 10873 conversion: () => ({ 10874 node: new HorizontalDividerNode() 10875 }), 10876 priority: 1 10877 } 10878 } 10879 } 10880 } 10881 10882 constructor(key) { 10883 super(key); 10884 } 10885 10886 createDOM() { 10887 const figure = createElement("figure", { className: "horizontal-divider" }); 10888 const hr = createElement("hr"); 10889 10890 figure.appendChild(hr); 10891 10892 const deleteButton = createElement("lexxy-node-delete-button"); 10893 figure.appendChild(deleteButton); 10894 10895 return figure 10896 } 10897 10898 updateDOM() { 10899 return true 10900 } 10901 10902 getTextContent() { 10903 return "â\n\n" 10904 } 10905 10906 isInline() { 10907 return false 10908 } 10909 10910 exportDOM() { 10911 const hr = createElement("hr"); 10912 return { element: hr } 10913 } 10914 10915 exportJSON() { 10916 return { 10917 type: "horizontal_divider", 10918 version: 1 10919 } 10920 } 10921 10922 decorate() { 10923 return null 10924 } 10925} 10926 10927const HORIZONTAL_DIVIDER = { 10928 dependencies: [ HorizontalDividerNode ], 10929 export: (node) => { 10930 return node instanceof HorizontalDividerNode ? "---" : null 10931 }, 10932 regExpStart: /^-{3,}\s?$/, 10933 replace: (parentNode, children, match, endMatch, linesInBetween, isImport) => { 10934 const hrNode = new HorizontalDividerNode(); 10935 parentNode.replace(hrNode); 10936 10937 if (!isImport) { 10938 const paragraph = eo(); 10939 hrNode.insertAfter(paragraph); 10940 paragraph.select(); 10941 } 10942 }, 10943 type: "multiline-element" 10944}; 10945 10946const PUNCTUATION_OR_SPACE = /[^\w]/; 10947 10948// Supplements Lexical's built-in registerMarkdownShortcuts to handle the case 10949// where a user types a leading tag before text that already ends with a 10950// trailing tag (e.g. typing ` before `hello`` or ** before **hello**). 10951// 10952// Lexical's markdown shortcut handler only triggers format transformations when 10953// the closing tag is the character just typed. When the opening tag is typed 10954// instead (e.g. typing ` before `hello`` to form ``hello``), the built-in 10955// handler doesn't match because it looks backward from the cursor for an 10956// opening tag, but the cursor is right after it. 10957// 10958// This listener detects that scenario for ALL text format transformers 10959// (backtick, bold, italic, strikethrough, etc.) and applies the appropriate 10960// format. 10961function registerMarkdownLeadingTagHandler(editor, transformers) { 10962 const textFormatTransformers = transformers 10963 .filter(t => t.type === "text-format") 10964 .sort((a, b) => b.tag.length - a.tag.length); // Longer tags first 10965 10966 return editor.registerUpdateListener(({ tags, dirtyLeaves, editorState, prevEditorState }) => { 10967 if (tags.has("historic") || tags.has("collaboration")) return 10968 if (editor.isComposing()) return 10969 10970 const selection = editorState.read(Qr); 10971 const prevSelection = prevEditorState.read(Qr); 10972 10973 if (!Fr(prevSelection) || !Fr(selection) || !selection.isCollapsed()) return 10974 10975 const anchorKey = selection.anchor.key; 10976 const anchorOffset = selection.anchor.offset; 10977 10978 if (!dirtyLeaves.has(anchorKey)) return 10979 10980 const anchorNode = editorState.read(() => Yo(anchorKey)); 10981 if (!Tr(anchorNode)) return 10982 10983 // Only trigger when cursor moved forward (typing) 10984 const prevOffset = prevSelection.anchor.key === anchorKey ? prevSelection.anchor.offset : 0; 10985 if (anchorOffset <= prevOffset) return 10986 10987 const textContent = editorState.read(() => anchorNode.getTextContent()); 10988 10989 // Try each transformer, longest tags first 10990 for (const transformer of textFormatTransformers) { 10991 const tag = transformer.tag; 10992 const tagLen = tag.length; 10993 10994 // The typed characters must end at the cursor position and form the opening tag 10995 const openTagStart = anchorOffset - tagLen; 10996 if (openTagStart < 0) continue 10997 10998 const candidateOpenTag = textContent.slice(openTagStart, anchorOffset); 10999 if (candidateOpenTag !== tag) continue 11000 11001 // Disambiguate from longer tags: if the character before the opening tag 11002 // is the same as the tag character, this might be part of a longer tag 11003 // (e.g. seeing `*` when the user is actually typing `**`) 11004 const tagChar = tag[0]; 11005 if (openTagStart > 0 && textContent[openTagStart - 1] === tagChar) continue 11006 11007 // Check intraword constraint: if intraword is false, the character before 11008 // the opening tag must be a space, punctuation, or the start of the text 11009 if (transformer.intraword === false && openTagStart > 0) { 11010 const beforeChar = textContent[openTagStart - 1]; 11011 if (beforeChar && !PUNCTUATION_OR_SPACE.test(beforeChar)) continue 11012 } 11013 11014 // Search forward for a closing tag in the same text node 11015 const searchStart = anchorOffset; 11016 const closeTagIndex = textContent.indexOf(tag, searchStart); 11017 if (closeTagIndex < 0) continue 11018 11019 // Disambiguate closing tag from longer tags: if the character r
vendor: 4,204 bytes, lines 11019-11139
11019ight after 11020 // the closing tag is the same as the tag character, skip 11021 // (e.g. `*hello**` â the first `*` at index 6 is part of `**`) 11022 if (textContent[closeTagIndex + tagLen] === tagChar) continue 11023 11024 // Also check if the character before the closing tag start is the same 11025 // tag character (e.g. the closing tag might be a suffix of a longer sequence) 11026 if (closeTagIndex > 0 && textContent[closeTagIndex - 1] === tagChar) continue 11027 11028 // There must be content between the tags (not just empty or whitespace-adjacent) 11029 const innerStart = anchorOffset; 11030 const innerEnd = closeTagIndex; 11031 if (innerEnd <= innerStart) continue 11032 11033 // No space immediately after opening tag 11034 if (textContent[innerStart] === " ") continue 11035 11036 // No space immediately before closing tag 11037 if (textContent[innerEnd - 1] === " ") continue 11038 11039 // Check intraword constraint for closing tag 11040 if (transformer.intraword === false) { 11041 const afterCloseChar = textContent[closeTagIndex + tagLen]; 11042 if (afterCloseChar && !PUNCTUATION_OR_SPACE.test(afterCloseChar)) continue 11043 } 11044 11045 editor.update(() => { 11046 const node = Yo(anchorKey); 11047 if (!node || !Tr(node)) return 11048 11049 const parent = node.getParent(); 11050 if (parent === null || W$1(parent)) return 11051 11052 $applyFormatFromLeadingTag(node, openTagStart, transformer); 11053 }); 11054 11055 break // Only apply the first (longest) matching transformer 11056 } 11057 }) 11058} 11059 11060function $applyFormatFromLeadingTag(anchorNode, openTagStart, transformer) { 11061 const tag = transformer.tag; 11062 const tagLen = tag.length; 11063 const textContent = anchorNode.getTextContent(); 11064 11065 const innerStart = openTagStart + tagLen; 11066 const closeTagIndex = textContent.indexOf(tag, innerStart); 11067 if (closeTagIndex < 0) return 11068 11069 const inner = textContent.slice(innerStart, closeTagIndex); 11070 if (inner.length === 0) return 11071 11072 // Remove both tags and apply format 11073 const before = textContent.slice(0, openTagStart); 11074 const after = textContent.slice(closeTagIndex + tagLen); 11075 11076 anchorNode.setTextContent(before + inner + after); 11077 11078 const nextSelection = qr(); 11079 es(nextSelection); 11080 11081 // Select the inner text to apply formatting 11082 nextSelection.anchor.set(anchorNode.getKey(), openTagStart, "text"); 11083 nextSelection.focus.set(anchorNode.getKey(), openTagStart + inner.length, "text"); 11084 11085 for (const format of transformer.format) { 11086 if (!nextSelection.hasFormat(format)) { 11087 nextSelection.formatText(format); 11088 } 11089 } 11090 11091 // Collapse selection to end of formatted text and clear the format 11092 // so subsequent typing is plain text 11093 nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type); 11094 11095 for (const format of transformer.format) { 11096 if (nextSelection.hasFormat(format)) { 11097 nextSelection.toggleFormat(format); 11098 } 11099 } 11100} 11101 11102var theme = { 11103 text: { 11104 bold: "lexxy-content__bold", 11105 italic: "lexxy-content__italic", 11106 strikethrough: "lexxy-content__strikethrough", 11107 underline: "lexxy-content__underline", 11108 highlight: "lexxy-content__highlight" 11109 }, 11110 tableCellHeader: "lexxy-content__table-cell--header", 11111 tableCellSelected: "lexxy-content__table-cell--selected", 11112 tableSelection: "lexxy-content__table--selection", 11113 tableScrollableWrapper: "lexxy-content__table-wrapper", 11114 tableCellHighlight: "lexxy-content__table-cell--highlight", 11115 tableCellFocus: "lexxy-content__table-cell--focus", 11116 list: { 11117 nested: { 11118 listitem: "lexxy-nested-listitem", 11119 } 11120 }, 11121 codeHighlight: { 11122 addition: "code-token__selector", 11123 atrule: "code-token__attr", 11124 attr: "code-token__attr", 11125 "attr-name": "code-token__attr", 11126 "attr-value": "code-token__selector", 11127 boolean: "code-token__property", 11128 bold: "code-token__variable", 11129 builtin: "code-token__selector", 11130 cdata: "code-token__comment", 11131 char: "code-token__selector", 11132 class: "code-token__function", 11133 "class-name": "code-token__function", 11134 color: "code-token__property", 11135 comment: "code-token__comment", 11136 constant: "code-token__property", 11137 coord: "code-token__comment", 11138 decorator: "code-token__function", 11139 deleted: "code-token__operator",
11140 deletion: "code-token__operator", 11141 directive: "code-token__attr", 11142 "directive-hash": "code-token__property", 11143 doctype: "code-token__comment", 11144 entity: "code-token__operator", 11145 function: "code-token__function", 11146 hexcode: "code-token__property", 11147 important: "code-token__function", 11148 inserted: "code-token__selector", 11149 italic: "code-token__comment", 11150 keyword: "code-token__attr", 11151 line: "code-token__selector", 11152 namespace: "code-token__variable", 11153 number: "code-token__property", 11154 macro: "code-token__function", 11155 operator: "code-token__operator", 11156 parameter: "code-token__variable", 11157 prolog: "code-token__comment", 11158 property: "code-token__property", 11159 punctuation: "code-token__punctuation", 11160 "raw-string": "code-token__operator", 11161 regex: "code-token__variable", 11162 script: "code-token__function", 11163 selector: "code-token__selector", 11164 string: "code-token__selector", 11165 style: "code-token__function", 11166 symbol: "code-token__property", 11167 tag: "code-token__property", 11168 title: "code-token__function", 11169 "type-definition": "code-token__function", 11170 url: "code-token__operator", 11171 variable: "code-token__variable", 11172 } 11173}; 11174 11175class UploadRequests { 11176 #requestsByKey = new Map() 11177 11178 track(key, request) { 11179 this.#requestsByKey.set(key, request); 11180 } 11181 11182 forget(key) { 11183 this.#requestsByKey.delete(key); 11184 } 11185 11186 abort(key) { 11187 const request = this.#requestsByKey.get(key); 11188 if (request) { 11189 this.#requestsByKey.delete(key); 11190 request.abort(); 11191 } 11192 } 11193 11194 clear() { 11195 this.#requestsByKey.clear(); 11196 } 11197} 11198 11199/** 11200 * Copyright (c) Meta Platforms, Inc. and affiliates. 11201 * 11202 * This source code is licensed under the MIT license found in the 11203 * LICENSE file in the root directory of this source tree. 11204 * 11205 */ 11206 11207const Ke$1=/^(\d+(?:\.\d+)?)px$/,Ae$1={BOTH:3,COLUMN:2,NO_STATUS:0,ROW:1};let Ee$1 = class Ee extends Bi{__colSpan;__rowSpan;__headerState;__width;__backgroundColor;__verticalAlign;static getType(){return "tablecell"}static clone(e){return new Ee(e.__headerState,e.__colSpan,e.__width,e.__key)}afterCloneFrom(e){super.afterCloneFrom(e),this.__rowSpan=e.__rowSpan,this.__backgroundColor=e.__backgroundColor,this.__verticalAlign=e.__verticalAlign,this.__colSpan=e.__colSpan,this.__headerState=e.__headerState,this.__width=e.__width;}static importDOM(){return {td:e=>({conversion:Me$1,priority:0}),th:e=>({conversion:Me$1,priority:0})}}static importJSON(e){return $e$1().updateFromJSON(e)}updateFromJSON(e){return super.updateFromJSON(e).setHeaderStyles(e.headerState).setColSpan(e.colSpan||1).setRowSpan(e.rowSpan||1).setWidth(e.width||void 0).setBackgroundColor(e.backgroundColor||null).setVerticalAlign(e.verticalAlign||void 0)}constructor(e=Ae$1.NO_STATUS,t=1,n,o){super(o),this.__colSpan=t,this.__rowSpan=1,this.__headerState=e,this.__width=n,this.__backgroundColor=null,this.__verticalAlign=void 0;}createDOM(t){const n=document.createElement(this.getTag());return this.__width&&(n.style.width=`${this.__width}px`),this.__colSpan>1&&(n.colSpan=this.__colSpan),this.__rowSpan>1&&(n.rowSpan=this.__rowSpan),null!==this.__backgroundColor&&(n.style.backgroundColor=this.__backgroundColor),ke$1(this.__verticalAlign)&&(n.style.verticalAlign=this.__verticalAlign),mc(n,t.theme.tableCell,this.hasHeader()&&t.theme.tableCellHeader),n}exportDOM(e){const t=super.exportDOM(e);if(Ys(t.element)){const e=t.element;e.setAttribute("data-temporary-table-cell-lexical-key",this.getKey()),e.style.border="1px solid black",this.__colSpan>1&&(e.colSpan=this.__colSpan),this.__rowSpan>1&&(e.rowSpan=this.__rowSpan),e.style.width=`${this.getWidth()||75}px`,e.style.verticalAlign=this.getVerticalAlign()||"top",e.style.textAlign="start",null===this.__backgroundColor&&this.hasHeader()&&(e.style.backgroundColor="#f2f3f5");}return t}exportJSON(){return {...super.exportJSON(),...ke$1(this.__verticalAlign)&&{verticalAlign:this.__verticalAlign},backgroundColor:this.getBackgroundColor(),colSpan:this.__colSpan,headerState:this.__headerState,rowSpan:this.__rowSpan,width:this.getWidth()}}getColSpan(){return this.getLatest().__colSpan}setColSpan(e){const t=this.getWritable();return t.__colSpan=e,t}getRowSpan(){return this.getLatest().__rowSpan}setRowSpan(e){const t=this.getWritable();return t.__rowSpan=e,t}getTag(){return this.hasHeader()?"th":"td"}setHeaderStyles(e,t=Ae$1.BOTH){const n=this.getWritable();return n.__headerState=e&t|n.__headerState&~t,n}getHeaderStyles(){return this.getLatest().__headerState}setWidth(e){const t=this.getWritable();return t.__width=e,t}getWidth(){return this.getLatest().__width}
11207getBackgroundColor(){return this.getLatest().__backgroundColor}setBackgroundColor(e){const t=this.getWritable();return t.__backgroundColor=e,t}getVerticalAlign(){return this.getLatest().__verticalAlign}setVerticalAlign(e){const t=this.getWritable();return t.__verticalAlign=e||void 0,t}toggleHeaderStyle(e){const t=this.getWritable();return (t.__headerState&e)===e?t.__headerState-=e:t.__headerState+=e,t}hasHeaderState(e){return (this.getHeaderStyles()&e)===e}hasHeader(){return this.getLatest().__headerState!==Ae$1.NO_STATUS}updateDOM(e){return e.__headerState!==this.__headerState||e.__width!==this.__width||e.__colSpan!==this.__colSpan||e.__rowSpan!==this.__rowSpan||e.__backgroundColor!==this.__backgroundColor||e.__verticalAlign!==this.__verticalAlign}isShadowRoot(){return true}collapseAtStart(){return true}canBeEmpty(){return false}canIndent(){return false}};function ke$1(e){return "middle"===e||"bottom"===e}function Me$1(e){const t=e,n=e.nodeName.toLowerCase();let o;Ke$1.test(t.style.width)&&(o=parseFloat(t.style.width));let r=Ae$1.NO_STATUS;if("th"===n){const e=t.getAttribute("scope");if("col"===e)r=Ae$1.COLUMN;else if("row"===e)r=Ae$1.ROW;else {const e=t.parentElement,n=Ys(e)&&"tr"===e.nodeName.toLowerCase()&&Ys(e.parentElement)&&("thead"===e.parentElement.nodeName.toLowerCase()||0===e.rowIndex),o=0===t.cellIndex;n&&(r|=Ae$1.ROW),o&&(r|=Ae$1.COLUMN),r===Ae$1.NO_STATUS&&(r=Ae$1.ROW);}}const l=$e$1(r,t.colSpan,o);l.__rowSpan=t.rowSpan;const s=t.style.backgroundColor;""!==s&&(l.__backgroundColor=s);const i=t.style.verticalAlign;ke$1(i)&&(l.__verticalAlign=i);const c=t.style,a=(c&&c.textDecoration||"").split(" "),u="700"===c.fontWeight||"bold"===c.fontWeight,h=a.includes("line-through"),C="italic"===c.fontStyle,_=a.includes("underline"),S=c.color;return {after:e=>{const t=[];let n=null;const o=()=>{if(n){const e=n.getFirstChild();sr(e)&&1===n.getChildrenSize()&&e.remove();}};for(const r of e)if(Fs(r)||Tr(r)||sr(r)){if(Tr(r)&&(u&&r.toggleFormat("bold"),h&&r.toggleFormat("strikethrough"),C&&r.toggleFormat("italic"),_&&r.toggleFormat("underline"),S)){const e=r.getStyle();e.includes("color:")||r.setStyle(e+`color: ${S};`);}n?n.append(r):(n=eo().append(r),t.push(n));}else t.push(r),o(),n=null;return o(),0===t.length&&t.push(eo()),t},node:l}}function $e$1(e=Ae$1.NO_STATUS,t=1,n){return zs(new Ee$1(e,t,n))}function We$1(e){return e instanceof Ee$1}const ze$1=re$5("INSERT_TABLE_COMMAND");function Le$1(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}let He$1 = class He extends Bi{__height;static getType(){return "tablerow"}static clone(e){return new He(e.__height,e.__key)}afterCloneFrom(e){super.afterCloneFrom(e),this.__height=e.__height;}static importDOM(){return {tr:e=>({conversion:Be$1,priority:0})}}static importJSON(e){return Pe$1().updateFromJSON(e)}updateFromJSON(e){return super.updateFromJSON(e).setHeight(e.height)}constructor(e,t){super(t),this.__height=e;}exportJSON(){const e=this.getHeight();return {...super.exportJSON(),...void 0===e?void 0:{height:e}}}createDOM(t){const n=document.createElement("tr");return this.__height&&(n.style.height=`${this.__height}px`),mc(n,t.theme.tableRow),n}extractWithChild(e,t,n){return "html"===n}isShadowRoot(){return true}setHeight(e){const t=this.getWritable();return t.__height=e,t}getHeight(){return this.getLatest().__height}updateDOM(e){return e.__height!==this.__height}canBeEmpty(){return false}canIndent(){return false}};function Be$1(e){const n=e;let o;return Ke$1.test(n.style.height)&&(o=parseFloat(n.style.height)),{after:e=>Ht$3(e,We$1),node:Pe$1(o)}}function Pe$1(e){return zs(new He$1(e))}function De$1(e){return e instanceof He$1}const Ie$1="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,Ue$1=Ie$1&&"documentMode"in document?document.documentMode:null,Je$1=Ie$1&&/^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);function Xe$1(e,t,n=true){const o=Fn();for(let r=0;r<e;r++){const e=Pe$1();for(let o=0;o<t;o++){let t=Ae$1.NO_STATUS;"object"==typeof n?(0===r&&n.rows&&(t|=Ae$1.ROW),0===o&&n.columns&&(t|=Ae$1.COLUMN)):n&&(0===r&&(t|=Ae$1.ROW),0===o&&(t|=Ae$1.COLUMN));const l=$e$1(t),s=eo();s.append(kr()),l.append(s),e.append(l);}o.append(e);}return o}function Ye(e){const t=dl(e,e=>We$1(e));return We$1(t)?t:null}function qe$1(e){const t=dl(e,e=>De$1(e));if(De$1(t))return t;throw new Error("Expected table cell to be inside of table row.")}function je$1(e){const t=dl(e,e=>Rn(e));if(Rn(t))return t;throw new Error("Expected table cell to be inside of table.")}function Ve$1(e){const t=qe$1(e);return je$1(t).getChildren().findIndex(e=>e.is(t))}function Ge$1(e){return qe$1(e).getChildren().findIndex(t=>t.is(e))}Ie$1&&"InputEvent"in window&&!Ue$1&&new window.InputEvent("input");const tt=(e,t)=>e===Ae$1.BOTH||e===t?t:Ae$1.NO_STATUS;function nt(e=true){const t=Qr();Fr(t)||Ot(t)||Le$1(188);const n=t.anchor.getNode(),o=t.focus.getNode(),[r]=yt(n),[l,,s]=yt(o),[,i,c]=wt(s,l,r),{startRow:a}=c,{startRow:u}=i;return e?rt(a+r.__rowSpan>u+l.__rowSpan?r:l,true):rt(u<a?l:r,false)}function rt(e,t=true){const[,,n]=yt(e),[o,r]=wt(n,e,e),l=o[0].length,{startRow:s}=r;let i=null;if(t){const t=s+e.__rowSpan-1,r=o[t],c=Pe$1();for(let e=0;e<l;e++){const{cell:n,startRow:o}=r[e];if(o+n.__rowSpan-1<=t){const t=r[e].cell.__headerState,n=tt(t,Ae$1.COLUMN);c.append($e$1(n).append(eo()));}else n.setRowSpan(n.__rowSpan+1);}const a=n.getChildAtIndex(t);De$1(a)||Le$1(256),a.insertAfter(c),i=c;}else {const e=s,t=o[e],r=Pe$1();for(let n=0;n<l;n++){const{cell:o,startRow:l}=t[n];if(l===e){const e=t[n].cell.__headerState,o=tt(e,Ae$1.COLUMN);r.append($e$1(o).append(eo()));}else o.setRowSpan(o.__rowSpan+1);}const c=n.getChildAtIndex(e);De$1(c)||Le$1(257),c.insertBefore(r),i=r;}return i}function st(e=true){const t=Qr();Fr(t)||Ot(t)||Le$1(188);const n=t.anchor.getNode(),o=t.focus.getNode(),[r]=yt(n),[l,,s]=yt(o),[,i,c]=wt(s,l,r),{startColumn:a}=c,{startColumn:u}=i;return e?ct(a+r.__colSpan>u+l.__colSpan?r:l,true):ct(u<a?l:r,false)}
11207function ct(e,t=true,n=true){const[,,o]=yt(e),[r,l]=wt(o,e,e),s=r.length,{startColumn:i}=l,c=t?i+e.__colSpan-1:i-1,a=o.getFirstChild();De$1(a)||Le$1(120);let u=null;function h(e=Ae$1.NO_STATUS){const t=$e$1(e).append(eo());return null===u&&(u=t),t}let d=a;e:for(let e=0;e<s;e++){if(0!==e){const e=d.getNextSibling();De$1(e)||Le$1(121),d=e;}const t=r[e],n=t[c<0?0:c].cell.__headerState,o=tt(n,Ae$1.ROW);if(c<0){mt(d,h(o));continue}const{cell:l,startColumn:s,startRow:i}=t[c];if(s+l.__colSpan-1<=c){let n=l,r=i,s=c;for(;r!==e&&n.__rowSpan>1;){if(s-=l.__colSpan,!(s>=0)){d.append(h(o));continue e}{const{cell:e,startRow:o}=t[s];n=e,r=o;}}n.insertAfter(h(o));}else l.setColSpan(l.__colSpan+1);}null!==u&&n&>(u);const f=o.getColWidths();if(f){const e=[...f],t=c<0?0:c,n=e[t];e.splice(t,0,n),o.setColWidths(e);}return u}function ut(){const e=Qr();Fr(e)||Ot(e)||Le$1(188);const[t,n]=e.isBackward()?[e.focus.getNode(),e.anchor.getNode()]:[e.anchor.getNode(),e.focus.getNode()],[o,,r]=yt(t),[l]=yt(n),[s,i,c]=wt(r,o,l),{startRow:a}=i,{startRow:u}=c,h=u+l.__rowSpan-1;if(s.length===h-a+1)return void r.remove();const d=s[0].length,f=s[h+1],g=r.getChildAtIndex(h+1);for(let e=h;e>=a;e--){for(let t=d-1;t>=0;t--){const{cell:n,startRow:o,startColumn:r}=s[e][t];if(r===t){if(o<a||o+n.__rowSpan-1>h){const e=Math.max(o,a),t=Math.min(n.__rowSpan+o-1,h),r=e<=t?t-e+1:0;n.setRowSpan(n.__rowSpan-r);}if(o>=a&&o+n.__rowSpan-1>h&&e===h){null===g&&Le$1(122);let o=null;for(let n=0;n<t;n++){const t=f[n],r=t.cell;t.startRow===e+1&&(o=r),r.__colSpan>1&&(n+=r.__colSpan-1);}null===o?mt(g,n):o.insertAfter(n);}}}const t=r.getChildAtIndex(e);De$1(t)||Le$1(206,String(e)),t.remove();}if(void 0!==f){const{cell:e}=f[0];gt(e);}else {const e=s[a-1],{cell:t}=e[0];gt(t);}}function dt(){const e=Qr();Fr(e)||Ot(e)||Le$1(188);const t=e.anchor.getNode(),n=e.focus.getNode(),[o,,r]=yt(t),[l]=yt(n),[s,i,c]=wt(r,o,l),{startColumn:a}=i,{startRow:u,startColumn:h}=c,d=Math.min(a,h),f=Math.max(a+o.__colSpan-1,h+l.__colSpan-1),g=f-d+1;if(s[0].length===f-d+1)return r.selectPrevious(),void r.remove();const m=s.length;for(let e=0;e<m;e++)for(let t=d;t<=f;t++){const{cell:n,startColumn:o}=s[e][t];if(o<d){if(t===d){const e=d-o;n.setColSpan(n.__colSpan-Math.min(g,n.__colSpan-e));}}else if(o+n.__colSpan-1>f){if(t===f){const e=f-o+1;n.setColSpan(n.__colSpan-e);}}else n.remove();}const p=s[u],C=a>h?p[a+o.__colSpan]:p[h+l.__colSpan];if(void 0!==C){const{cell:e}=C;gt(e);}else {const e=h<a?p[h-1]:p[a-1],{cell:t}=e;gt(t);}const _=r.getColWidths();if(_){const e=[..._];e.splice(d,g),r.setColWidths(e);}}function gt(e){const t=e.getFirstDescendant();null==t?e.selectStart():t.getParentOrThrow().selectStart();}function mt(e,t){const n=e.getFirstChild();null!==n?n.insertBefore(t):e.append(t);}function pt(e){if(0===e.length)return null;const t=je$1(e[0]),[n]=bt(t,null,null);let o=1/0,r=-1/0,l=1/0,s=-1/0;const i=new Set;for(const t of n)for(const n of t){if(!n||!n.cell)continue;const t=n.cell.getKey();if(!i.has(t)&&e.some(e=>e.is(n.cell))){i.add(t);const e=n.startRow,c=n.startColumn,a=n.cell.__rowSpan||1,u=n.cell.__colSpan||1;o=Math.min(o,e),r=Math.max(r,e+a-1),l=Math.min(l,c),s=Math.max(s,c+u-1);}}if(o===1/0||l===1/0)return null;const c=r-o+1,a=s-l+1,u=n[o][l];if(!u.cell)return null;const h=u.cell;h.setColSpan(a),h.setRowSpan(c);const d=new Set([h.getKey()]);for(let e=o;e<=r;e++)for(let t=l;t<=s;t++){const o=n[e][t];if(!o.cell)continue;const r=o.cell,l=r.getKey();if(!d.has(l)){d.add(l);Ct(r)||h.append(...r.getChildren()),r.remove();}}return 0===h.getChildrenSize()&&h.append(eo()),h}function Ct(e){if(1!==e.getChildrenSize())return false;const t=e.getFirstChildOrThrow();return !(!no(t)||!t.isEmpty())}function St(e){const[t,n,o]=yt(e),r=t.__colSpan,l=t.__rowSpan;if(1===r&&1===l)return;const[s,i]=wt(o,t,t),{startColumn:c,startRow:a}=i,u=t.__headerState&Ae$1.COLUMN,h=Array.from({length:r},(e,t)=>{let n=u;for(let e=0;0!==n&&e<s.length;e++)n&=s[e][t+c].cell.__headerState;return n}),d=t.__headerState&Ae$1.ROW,f=Array.from({length:l},(e,t)=>{let n=d;for(let e=0;0!==n&&e<s[0].length;e++)n&=s[t+a][e].cell.__headerState;return n});if(r>1){for(let e=1;e<r;e++)t.insertAfter($e$1(h[e]|f[0]).append(eo()));t.setColSpan(1);}if(l>1){let e;for(let t=1;t<l;t++){const o=a+t,l=s[o];e=(e||n).getNextSibling(),De$1(e)||Le$1(125);let i=null;for(let e=0;e<c;e++){const t=l[e],n=t.cell;t.startRow===o&&(i=n),n.__colSpan>1&&(e+=n.__colSpan-1);}if(null===i)for(let n=r-1;n>=0;n--)mt(e,$e$1(h[n]|f[t]).append(eo()));else for(let e=r-1;e>=0;e--)i.insertAfter($e$1(h[e]|f[t]).append(eo()));}t.setRowSpan(1);}}function wt(e,t,n){const[o,r,l]=bt(e,t,n);return null===r&&Le$1(207),null===l&&Le$1(208),[o,r,l]}function bt(e,t,n){const o=[];let r=null,l=null;function s(e){let t=o[e];return void 0===t&&(o[e]=t=[]),t}const i=e.getChildren();for(let e=0;e<i.length;e++){const o=i[e];De$1(o)||Le$1(209);const c=s(e);for(let a=o.getFirstChild(),u=0;null!=a;a=a.getNextSibling()){for(We$1(a)||Le$1(147);void 0!==c[u];)u++;const o={cell:a,startColumn:u,startRow:e},{__rowSpan:h,__colSpan:d}=a;for(let t=0;t<h&&!(e+t>=i.length);t++){const n=s(e+t);for(let e=0;e<d;e++)n[u+e]=o;}null!==t&&null===r&&t.is(a)&&(r=o),null!==n&&null===l&&n.is(a)&&(l=o);}}return [o,r,l]}function yt(e){let t;if(e instanceof Ee$1)t=e;else if("__type"in e){const o=dl(e,We$1);
vendor: 4,886 bytes, line 11207
11207We$1(o)||Le$1(148),t=o;}else {const o=dl(e.getNode(),We$1);We$1(o)||Le$1(148),t=o;}const o=t.getParent();De$1(o)||Le$1(149);const r=o.getParent();return Rn(r)||Le$1(210),[t,o,r]}function Nt(e,t,n){let o,r=Math.min(t.startColumn,n.startColumn),l=Math.min(t.startRow,n.startRow),s=Math.max(t.startColumn+t.cell.__colSpan-1,n.startColumn+n.cell.__colSpan-1),i=Math.max(t.startRow+t.cell.__rowSpan-1,n.startRow+n.cell.__rowSpan-1);do{o=false;for(let t=0;t<e.length;t++)for(let n=0;n<e[0].length;n++){const c=e[t][n];if(!c)continue;const a=c.startColumn+c.cell.__colSpan-1,u=c.startRow+c.cell.__rowSpan-1,h=c.startColumn<=s&&a>=r,d=c.startRow<=i&&u>=l;if(h&&d){const e=Math.min(r,c.startColumn),t=Math.max(s,a),n=Math.min(l,c.startRow),h=Math.max(i,u);e===r&&t===s&&n===l&&h===i||(r=e,s=t,l=n,i=h,o=true);}}}while(o);return {maxColumn:s,maxRow:i,minColumn:r,minRow:l}}function Tt(e){const[t,,n]=yt(e),o=n.getChildren(),r=o.length,l=o[0].getChildren().length,s=new Array(r);for(let e=0;e<r;e++)s[e]=new Array(l);for(let e=0;e<r;e++){const n=o[e].getChildren();let r=0;for(let o=0;o<n.length;o++){for(;s[e][r];)r++;const l=n[o],i=l.__rowSpan||1,c=l.__colSpan||1;for(let t=0;t<i;t++)for(let n=0;n<c;n++)s[e+t][r+n]=l;if(t===l)return {colSpan:c,columnIndex:r,rowIndex:e,rowSpan:i};r+=c;}}return null}function Ft(e){const[[t,o,r,l],[s,i,c,a]]=["anchor","focus"].map(t=>{const o=e[t].getNode(),r=dl(o,We$1);We$1(r)||Le$1(238,t,o.getKey(),o.getType());const l=r.getParent();De$1(l)||Le$1(239,t);const s=l.getParent();return Rn(s)||Le$1(240,t),[o,r,l,s]});return l.is(a)||Le$1(241),{anchorCell:o,anchorNode:t,anchorRow:r,anchorTable:l,focusCell:i,focusNode:s,focusRow:c,focusTable:a}}class Rt{tableKey;anchor;focus;_cachedNodes;dirty;constructor(e,t,n){this.anchor=t,this.focus=n,t._selection=this,n._selection=this,this._cachedNodes=null,this.dirty=false,this.tableKey=e;}getStartEndPoints(){return [this.anchor,this.focus]}isValid(){if("root"===this.tableKey||"root"===this.anchor.key||"element"!==this.anchor.type||"root"===this.focus.key||"element"!==this.focus.type)return false;const e=Yo(this.tableKey),t=Yo(this.anchor.key),n=Yo(this.focus.key);return null!==e&&null!==t&&null!==n}isBackward(){return this.focus.isBefore(this.anchor)}getCachedNodes(){return this._cachedNodes}setCachedNodes(e){this._cachedNodes=e;}is(e){return Ot(e)&&this.tableKey===e.tableKey&&this.anchor.is(e.anchor)&&this.focus.is(e.focus)}set(e,t,n){this.dirty=this.dirty||e!==this.tableKey||t!==this.anchor.key||n!==this.focus.key,this.tableKey=e,this.anchor.key=t,this.focus.key=n,this._cachedNodes=null;}clone(){return new Rt(this.tableKey,Mr(this.anchor.key,this.anchor.offset,this.anchor.type),Mr(this.focus.key,this.focus.offset,this.focus.type))}isCollapsed(){return false}extract(){return this.getNodes()}insertRawText(e){}insertText(){}hasFormat(e){let t=0;this.getNodes().filter(We$1).forEach(e=>{const n=e.getFirstChild();no(n)&&(t|=n.getTextFormat());});const n=z$7[e];return 0!==(t&n)}insertNodes(e){const t=this.focus.getNode();Wi(t)||Le$1(151);St$3(t.select(0,t.getChildrenSize())).insertNodes(e);}getShape(){const{anchorCell:e,focusCell:t}=Ft(this),n=Tt(e);null===n&&Le$1(153);const o=Tt(t);null===o&&Le$1(155);const r=Math.min(n.columnIndex,o.columnIndex),l=Math.max(n.columnIndex+n.colSpan-1,o.columnIndex+o.colSpan-1),s=Math.min(n.rowIndex,o.rowIndex),i=Math.max(n.rowIndex+n.rowSpan-1,o.rowIndex+o.rowSpan-1);return {fromX:Math.min(r,l),fromY:Math.min(s,i),toX:Math.max(r,l),toY:Math.max(s,i)}}getNodes(){if(!this.isValid())return [];const e=this._cachedNodes;if(null!==e)return e;const{anchorTable:t,anchorCell:n,focusCell:o}=Ft(this),r=o.getParents()[1];if(r!==t){if(t.isParentOf(o)){const e=r.getParent();null==e&&Le$1(159),this.set(this.tableKey,o.getKey(),e.getKey());}else {const e=t.getParent();null==e&&Le$1(158),this.set(this.tableKey,e.getKey(),o.getKey());}return this.getNodes()}const[l,s,i]=wt(t,n,o),{minColumn:c,maxColumn:a,minRow:u,maxRow:h}=Nt(l,s,i),d=new Map([[t.getKey(),t]]);let f=null;for(let e=u;e<=h;e++)for(let t=c;t<=a;t++){const{cell:n}=l[e][t],o=n.getParent();De$1(o)||Le$1(160),o!==f&&(d.set(o.getKey(),o),f=o),d.has(n.getKey())||Et(n,e=>{d.set(e.getKey(),e);});}const g=Array.from(d.values());return mi()||(this._cachedNodes=g),g}getTextContent(){const e=this.getNodes().filter(e=>We$1(e));let t="";for(let n=0;n<e.length;n++){const o=e[n],r=o.__parent,l=(e[n+1]||{}).__parent;t+=o.getTextContent()+(l!==r?"\n":"\t");}return t}}function Ot(e){return e instanceof Rt}function Kt(){const e=Mr("root",0,"element"),t=Mr("root",0,"element");return new Rt("root",e,t)}function At(e,t,n){e.getKey(),t.getKey(),n.getKey();const o=Qr(),r=Ot(o)?o.clone():Kt();return r.set(e.getKey(),t.getKey(),n.getKey()),r}function Et(e,t){const n=[[e]];for(let e=n.at(-1);void 0!==e&&n.length>0;e=n.at(-1)){const o=e.pop();void 0===o?n.pop():false!==t(o)&&Wi(o)&&n.push(o.getChildren());}}
11207function kt(e,t=Zs()){const n=Yo(e);Rn(n)||Le$1(231,e);const o=Lt(n,t.getElementByKey(e));return null===o&&Le$1(232,e),{tableElement:o,tableNode:n}}class Mt{observers;nextFocus;shouldCheckSelectionForTable;constructor(){this.observers=new Map,this.nextFocus=null,this.shouldCheckSelectionForTable=null;}setNextFocus(e){this.nextFocus=e;}getAndClearNextFocus(){const{nextFocus:e}=this;return null!==e&&(this.nextFocus=null),e}setShouldCheckSelectionForTable(e){this.shouldCheckSelectionForTable=e;}getAndClearShouldCheckSelectionForTable(){const{shouldCheckSelectionForTable:e}=this;return e?(this.shouldCheckSelectionForTable=null,e):null}}class $t{focusX;focusY;listenersToRemove;table;isHighlightingCells;anchorX;anchorY;tableNodeKey;anchorCell;focusCell;anchorCellNodeKey;focusCellNodeKey;editor;tableSelection;hasHijackedSelectionStyles;isSelecting;pointerType;abortController;listenerOptions;constructor(e,t){this.isHighlightingCells=false,this.anchorX=-1,this.anchorY=-1,this.focusX=-1,this.focusY=-1,this.listenersToRemove=new Set,this.tableNodeKey=t,this.editor=e,this.table={columns:0,domRows:[],rows:0},this.tableSelection=null,this.anchorCellNodeKey=null,this.focusCellNodeKey=null,this.anchorCell=null,this.focusCell=null,this.hasHijackedSelectionStyles=false,this.isSelecting=false,this.pointerType=null,this.abortController=new AbortController,this.listenerOptions={signal:this.abortController.signal},this.trackTable();}getTable(){return this.table}removeListeners(){this.abortController.abort("removeListeners"),Array.from(this.listenersToRemove).forEach(e=>e()),this.listenersToRemove.clear();}$lookup(){return kt(this.tableNodeKey,this.editor)}trackTable(){const e=new MutationObserver(e=>{this.editor.getEditorState().read(()=>{let t=false;for(let n=0;n<e.length;n++){const o=e[n].target.nodeName;if("TABLE"===o||"TBODY"===o||"THEAD"===o||"TR"===o){t=true;break}}if(!t)return;const{tableNode:n,tableElement:o}=this.$lookup();this.table=Gt(n,o);},{editor:this.editor});});this.editor.getEditorState().read(()=>{const{tableNode:t,tableElement:n}=this.$lookup();this.table=Gt(t,n),e.observe(n,{attributes:true,childList:true,subtree:true});},{editor:this.editor});}$clearHighlight(e=true){const t=this.editor;this.isHighlightingCells=false,this.anchorX=-1,this.anchorY=-1,this.focusX=-1,this.focusY=-1,this.tableSelection=null,this.anchorCellNodeKey=null,this.focusCellNodeKey=null,this.anchorCell=null,this.focusCell=null,this.hasHijackedSelectionStyles=false,this.$enableHighlightStyle();const{tableNode:n,tableElement:o}=this.$lookup();Qt(t,Gt(n,o),null),e&&null!==Qr()&&(es(null),t.dispatchCommand(ie$4,void 0));}$enableHighlightStyle(){const e=this.editor,{tableElement:t}=this.$lookup();xc(t,e._config.theme.tableSelection),t.classList.remove("disable-selection"),this.hasHijackedSelectionStyles=false;}$disableHighlightStyle(){const{tableElement:t}=this.$lookup();mc(t,this.editor._config.theme.tableSelection),this.hasHijackedSelectionStyles=true;}$updateTableTableSelection(e){if(null!==e){e.tableKey!==this.tableNodeKey&&Le$1(233,e.tableKey,this.tableNodeKey);const t=this.editor;this.tableSelection=e,this.isHighlightingCells=true,this.$disableHighlightStyle(),this.updateDOMSelection(),Qt(t,this.table,this.tableSelection);}else this.$clearHighlight();}updateDOMSelection(){if(null!==this.anchorCell&&null!==this.focusCell){const e=Js(this.editor._window);e&&e.rangeCount>0&&e.removeAllRanges();}}$setFocusCellForSelection(e,t=false){const n=this.editor,{tableNode:o}=this.$lookup(),r=e.x,l=e.y;if(this.focusCell=e,!this.isHighlightingCells){(t||this.anchorX!==r||this.anchorY!==l||null!=this.tableSelection&&null!=this.anchorCellNodeKey)&&(this.isHighlightingCells=true,this.$disableHighlightStyle());}if(-1!==this.focusX&&-1!==this.focusY&&r===this.focusX&&l===this.focusY)return false;if(this.focusX=r,this.focusY=l,this.isHighlightingCells){const s=_n(o,e.elem);if(null!=this.tableSelection&&null!=this.anchorCellNodeKey){let e=s;if(null===e&&t&&(e=o.getCellNodeFromCords(r,l,this.table)),null!==e){const t=this.$getAnchorTableCellOrThrow();return this.focusCellNodeKey=e.getKey(),this.tableSelection=At(o,t,e),es(this.tableSelection),n.dispatchCommand(ie$4,void 0),Qt(n,this.table,this.tableSelection),true}}}return false}$getAnchorTableCell(){return this.anchorCellNodeKey?Yo(this.anchorCellNodeKey):null}$getAnchorTableCellOrThrow(){const e=this.$getAnchorTableCell();return null===e&&Le$1(234),e}$getFocusTableCell(){return this.focusCellNodeKey?Yo(this.focusCellNodeKey):null}$getFocusTableCellOrThrow(){const e=this.$getFocusTableCell();return null===e&&Le$1(235),e}
11207$setAnchorCellForSelection(e){this.isHighlightingCells=false,this.anchorCell=e,this.anchorX=e.x,this.anchorY=e.y,this.focusX=-1,this.focusY=-1,this.focusCell=null,this.focusCellNodeKey=null;const{tableNode:t}=this.$lookup(),n=_n(t,e.elem);if(null!==n){const e=n.getKey();null!=this.tableSelection?(this.tableSelection=this.tableSelection.clone(),this.tableSelection.set(t.getKey(),e,e)):this.tableSelection=At(t,n,n),this.anchorCellNodeKey=e;}}$formatCells(e){const t=Qr();Ot(t)||Le$1(236);const n=qr(),o=n.anchor,r=n.focus,l=t.getNodes().filter(We$1);l.length>0||Le$1(237);const s=l[0].getFirstChild(),i=no(s)?s.getFormatFlags(e,null):null;l.forEach(t=>{o.set(t.getKey(),0,"element"),r.set(t.getKey(),t.getChildrenSize(),"element"),n.formatText(e,i);}),es(t),this.editor.dispatchCommand(ie$4,void 0);}$clearText(){const{editor:e}=this,t=Yo(this.tableNodeKey);if(!Rn(t))throw new Error("Expected TableNode.");const n=Qr();Ot(n)||Le$1(253);const o=n.getNodes().filter(We$1),r=t.getFirstChild(),l=t.getLastChild();if(o.length>0&&null!==r&&null!==l&&De$1(r)&&De$1(l)&&o[0]===r.getFirstChild()&&o[o.length-1]===l.getLastChild()){t.selectPrevious();const n=t.getParent();return t.remove(),void(Vi(n)&&n.isEmpty()&&e.dispatchCommand(he$3,void 0))}o.forEach(e=>{if(Wi(e)){const t=eo(),n=kr();
11207t.append(n),e.append(t),e.getChildren().forEach(e=>{e!==t&&e.remove();});}}),Qt(e,this.table,null),es(null),e.dispatchCommand(ie$4,void 0);}}const Wt="__lexicalTableSelection";function zt(e){return Ys(e)&&"TABLE"===e.nodeName}function Lt(e,t){if(!t)return t;const n=zt(t)?t:t.querySelector("table");return zt(n)||Le$1(341,e.constructor.name,e.getType(),e.getKey(),t.nodeName),n}function Ht(e){return e._window}function Bt(e,t){for(let n=t,o=null;null!==n;n=n.getParent()){if(e.is(n))return o;We$1(n)&&(o=n);}return null}const Pt=[[Ee$3,"down"],[we$1,"up"],[Ne$1,"backward"],[ke$2,"forward"]],Dt=[ye$2,me$3,fe$4],It=[Ae$3,Pe$2];function Ut(e,t){const n=e.getRootElement(),o=e._window;if(!n||!o)return ()=>{};const r=o=>{const r=o.target;if(0!==o.button||!qs(r)||!n.contains(r))return;const l=function(e){const t=jt(e);if(null===t)return null;let n=t.elem;for(;null!=n;){if("TABLE"===n.nodeName&&Wt in n&&n[Wt])return {cellElement:t,tableElement:n,tableObserver:n[Wt]};n=n.parentNode;}return null}(r);e.update(()=>{if(Ot(Qr())){for(const[e]of t.observers.values())e.$clearHighlight(false);es(null),e.dispatchCommand(ie$4,void 0);}if(!l)return;const{tableObserver:n,tableElement:r,cellElement:s}=l;!function(e,t,n,o,r,l){const s=e._window;if(!s)return;const i=t=>{if(r.isSelecting)return;r.isSelecting=true,null!==t&&null===r.anchorCell&&e.update(()=>
11207{r.$setAnchorCellForSelection(t);});const n=()=>{r.isSelecting=false,s.removeEventListener("pointerup",n),s.removeEventListener("pointermove",i);},i=t=>{if(!(e=>!(1&~e.buttons))(t)&&r.isSelecting)return r.isSelecting=false,s.removeEventListener("pointerup",n),void s.removeEventListener("pointermove",i);if(!qs(t.target))return;let c=null;const a=!(Je$1||o.contains(t.target));if(a)c=Vt(o,t.target);else for(const e of document.elementsFromPoint(t.clientX,t.clientY))if(c=Vt(o,e),c)break;if(c){const t=c;null===r.anchorCell&&e.update(()=>{r.$setAnchorCellForSelection(t);}),null!==r.focusCell&&c.elem===r.focusCell.elem||(l.setNextFocus({focusCell:c,override:a,tableKey:r.tableNodeKey}),e.dispatchCommand(ie$4,void 0));}};s.addEventListener("pointerup",n,r.listenerOptions),s.addEventListener("pointermove",i,r.listenerOptions);};r.pointerType=t.pointerType;const c=Bs(r.tableNodeKey),a=Zr();if(Je$1&&t.shiftKey&&ln(a,c)&&(Fr(a)||Ot(a))){const e=a.anchor.getNode(),o=Bt(c,a.anchor.getNode());if(o)r.$setAnchorCellForSelection(Cn(r,o)),r.$setFocusCellForSelection(n),gn(t);else {(c.isBefore(e)?c.selectStart():c.selectEnd()).anchor.set(a.anchor.key,a.anchor.offset,a.anchor.type);}}
11207else "touch"!==t.pointerType&&r.$setAnchorCellForSelection(n);i(n);}(e,o,s,r,n,t);});};return o.addEventListener("pointerdown",r),()=>{o.removeEventListener("pointerdown",r);}}function Jt(e,t,o,l,s){const i=o.getRootElement(),c=Ht(o);null!==i&&null!==c||Le$1(246);const a=new $t(o,e.getKey()),u=Lt(e,t);!function(e,t){null!==qt(e)&&Le$1(205);e[Wt]=t;}(u,a),a.listenersToRemove.add(()=>function(e,t){qt(e)===t&&delete e[Wt];}(u,a));const h=e=>{if(e.detail>=3&&qs(e.target)){null!==jt(e.target)&&e.preventDefault();}};u.addEventListener("mousedown",h,a.listenerOptions),a.listenersToRemove.add(()=>{u.removeEventListener("mousedown",h);});for(const[t,n]of Pt)a.listenersToRemove.add(o.registerCommand(t,t=>fn(o,t,n,e,a,s),so));a.listenersToRemove.add(o.registerCommand(De$2,t=>{const n=Qr();if(Ot(n)){const o=Bt(e,n.focus.getNode());if(null!==o)return gn(t),o.selectEnd(),true}return false},so));const d=t=>()=>{const o=Qr();if(!ln(o,e))return false;if(Ot(o))return a.$clearText(),true;if(Fr(o)){if(!We$1(Bt(e,o.anchor.getNode())))return false;const r=o.anchor.getNode(),l=o.focus.getNode(),s=e.isParentOf(r),i=e.isParentOf(l);if(s&&!i||i&&!s)return a.$clearText(),true;const c=dl(o.anchor.getNode(),e=>Wi(e)),u=c&&dl(c,e=>Wi(e)&&We$1(e.getParent()));if(!Wi(u)||!Wi(c))return false;if(t===me$3&&null===u.getPreviousSibling())return true}return false};for(const e of Dt)a.listenersToRemove.add(o.registerCommand(e,d(e),so));const f=t=>{const n=Qr();if(!Ot(n)&&!Fr(n))return false;const o=e.isParentOf(n.anchor.getNode());if(o!==e.isParentOf(n.focus.getNode())){const t=o?"anchor":"focus",r=o?"focus":"anchor",{key:l,offset:s,type:i}=n[r];return e[n[t].isBefore(n[r])?"selectPrevious":"selectNext"]()[r].set(l,s,i),false}return !!ln(n,e)&&(!!Ot(n)&&(t&&(t.preventDefault(),t.stopPropagation()),a.$clearText(),true))};for(const e of It)a.listenersToRemove.add(o.registerCommand(e,f,so));return a.listenersToRemove.add(o.registerCommand(je$2,e=>{const t=Qr();if(t){if(!Ot(t)&&!Fr(t))return false;V$4(o,Bt$3(e,ClipboardEvent)?e:null,et(t));const n=f(e);return Fr(t)?(t.removeText(),true):n}return false},so)),a.listenersToRemove.add(o.registerCommand(xe,t=>{const o=Qr();if(!ln(o,e))return false;if(Ot(o))return a.$formatCells(t),true;if(Fr(o)){const e=dl(o.anchor.getNode(),e=>We$1(e));if(!We$1(e))return false}return false},so)),a.listenersToRemove.add(o.registerCommand(Re$1,t=>{const n=Qr();if(!Ot(n)||!ln(n,e))return false;const o=n.anchor.getNode(),r=n.focus.getNode();if(!We$1(o)||!We$1(r))return false;if(function(e,t){if(Ot(e)){const n=e.anchor.getNode(),o=e.focus.getNode();if(t&&n&&o){const[e]=wt(t,n,o);return n.getKey()===e[0][0].cell.getKey()&&o.getKey()===e[e.length-1].at(-1).cell.getKey()}}return false}(n,e))return e.setFormat(t),true;const[l,s,i]=wt(e,o,r),c=Math.max(s.startRow+s.cell.__rowSpan-1,i.startRow+i.cell.__rowSpan-1),a=Math.max(s.startColumn+s.cell.__colSpan-1,i.startColumn+i.cell.__colSpan-1),u=Math.min(s.startRow,i.startRow),h=Math.min(s.startColumn,i.startColumn),d=new Set;for(let e=u;e<=c;e++)for(let n=h;n<=a;n++){const o=l[e][n].cell;if(d.has(o))continue;d.add(o),o.setFormat(t);const r=o.getChildren();for(let e=0;e<r.length;e++){const n=r[e];Wi(n)&&!n.isInline()&&n.setFormat(t);}}return true},so)),a.listenersToRemove.add(o.registerCommand(ge$3,t=>{const r=Qr();if(!ln(r,e))return false;if(Ot(r))return a.$clearHighlight(),false;if(Fr(r)){const l=dl(r.anchor.getNode(),e=>We$1(e));if(!We$1(l))return false;if("string"==typeof t){const n=pn(o,r,e);if(n)return mn(n,e,[kr(t)]),true}}return false},so)),l&&a.listenersToRemove.add(o.registerCommand(Fe$2,t=>{const o=Qr();if(!Fr(o)||!o.isCollapsed()||!ln(o,e))return false;const r=un(o.anchor.getNode());return !(null===r||!e.is(hn(r)))&&(gn(t),function(e,t){const o="next"===t?"getNextSibling":"getPreviousSibling",r="next"===t?"getFirstChild":"getLastChild",l=e[o]();if(Wi(l))return l.selectEnd();const s=dl(e,De$1);null===s&&Le$1(247);for(let e=s[o]();De$1(e);e=e[o]()){const t=e[r]();if(Wi(t))return t.selectEnd()}const i=dl(s,Rn);null===i&&Le$1(248);"next"===t?i.selectNext():i.selectPrevious();}(r,t.shiftKey?"previous":"next"),true)},so)),a.listenersToRemove.add(o.registerCommand(Ge$2,t=>e.isSelected(),so)),a.listenersToRemove.add(o.registerCommand(he$3,()=>{const t=Qr();if(!Fr(t)||!t.isCollapsed()||!ln(t,e))return false;
11207const n=pn(o,t,e);return !!n&&(mn(n,e),true)},so)),a}function Xt(e,t){const o=Qr(),r=Zr(),l=e.getAndClearNextFocus();if(null!==l){const{tableKey:t,focusCell:n}=l,r=e.observers.get(t);r||Le$1(335,t);const[s]=r;if(Ot(o)&&o.tableKey===s.tableNodeKey)return (n.x!==s.focusX||n.y!==s.focusY)&&(s.$setFocusCellForSelection(n),true);if(null!==s.anchorCell&&null!==s.anchorCellNodeKey&&n.elem!==s.anchorCell.elem&&null!==s.tableSelection)return s.$setFocusCellForSelection(n,true),true}const s=e.getAndClearShouldCheckSelectionForTable();if(s&&Fr(r)&&Fr(o)&&o.isCollapsed()){const e=Bs(s),t=o.anchor.getNode(),r=e.getFirstChild(),l=un(t);if(null!==l&&De$1(r)){const t=r.getFirstChild();if(We$1(t)&&e.is(dl(l,n=>n.is(e)||n.is(t))))return t.selectStart(),true}}Ot(o)&&function(e,t){const n=Ht(e),o=Zr();if(!t.is(o))return;const r=Bs(t.tableKey),l=Js(n);if(l&&l.anchorNode&&l.focusNode){const n=Go(l.focusNode),o=n&&!r.isParentOf(n),s=Go(l.anchorNode),i=s&&r.isParentOf(s);if(o&&i&&l.rangeCount>0){const n=Gr(l,e);n&&(n.anchor.set(r.getKey(),t.isBackward()?r.getChildrenSize():0,"element"),l.removeAllRanges(),es(n));}}}(t,o),Fr(o)&&function(e,t){const n=Zr(),{anchor:o,focus:r}=e,l=o.getNode(),s=r.getNode(),i=un(l),c=un(s),a=i?hn(i):null,u=c?hn(c):null,h=e.isBackward(),d=i&&c&&a&&u&&a.is(u),f=u&&(!a||a.isParentOf(u)),g=a&&(!u||u.isParentOf(a));if(f){const t=e.clone(),[n]=wt(u,c,c),o=n[0][0].cell,r=n[n.length-1].at(-1).cell;t.focus.set(h?o.getKey():r.getKey(),h?0:r.getChildrenSize(),"element"),es(t);}else if(g){const t=e.clone(),[n]=wt(a,i,i),o=n[0][0].cell,r=n[n.length-1].at(-1).cell;t.anchor.set(h?r.getKey():o.getKey(),h?r.getChildrenSize():0,"element"),es(t);}else if(d){const o=t.observers.get(a.getKey());o||Le$1(335,a.getKey());const[r]=o;if(i.is(c)||(r.$setAnchorCellForSelection(Cn(r,i)),r.$setFocusCellForSelection(Cn(r,c),true)),"touch"===r.pointerType&&r.isSelecting&&e.isCollapsed()&&Fr(n)&&n.isCollapsed()){const e=un(n.anchor.getNode());e&&!e.is(c)&&(r.$setAnchorCellForSelection(Cn(r,e)),r.$setFocusCellForSelection(Cn(r,c),true),r.pointerType=null);}}}(o,e);const i=Array.from(e.observers.entries()).map(([e,[t]])=>({tableNode:Bs(e),tableObserver:t}));for(const{tableNode:e,tableObserver:n}of i)Yt(t,e,n);return false}function Yt(e,t,n){const o=Qr(),r=Zr();o&&!o.is(r)&&(Ot(o)||Ot(r))&&n.tableSelection&&!n.tableSelection.is(r)&&(Ot(o)&&o.tableKey===n.tableNodeKey?n.$updateTableTableSelection(o):!Ot(o)&&Ot(r)&&r.tableKey===n.tableNodeKey&&n.$updateTableTableSelection(null)),n.hasHijackedSelectionStyles&&!t.isSelected()?function(e,t){t.$enableHighlightStyle(),Zt(t.table,t=>{const n=t.elem;t.highlighted=false,an(e,t),n.getAttribute("style")||n.removeAttribute("style");});}(e,n):!n.hasHijackedSelectionStyles&&t.isSelected()&&function(e,t){t.$disableHighlightStyle(),Zt(t.table,t=>{t.highlighted=true,cn(e,t);});}(e,n);}function qt(e){return e[Wt]||null}function jt(e){let t=e;for(;null!=t;){const e=t.nodeName;if("TD"===e||"TH"===e){const e=t._cell;return void 0===e?null:e}t=t.parentNode;}return null}function Vt(e,t){if(!e.contains(t))return null;let n=null;for(let o=t;null!=o;o=o.parentNode){if(o===e)return n;const t=o.nodeName;"TD"!==t&&"TH"!==t||(n=o._cell||null);}return null}function Gt(e,t){const n=[],o={columns:0,domRows:n,rows:0};let r=Lt(e,t).querySelector("tr"),l=0,s=0;for(n.length=0;null!=r;){const e=r.nodeName;if("TD"===e||"TH"===e){const e={elem:r,hasBackgroundColor:""!==r.style.backgroundColor,highlighted:false,x:l,y:s};r._cell=e;let t=n[s];void 0===t&&(t=n[s]=[]),t[l]=e;}else {const e=r.firstChild;if(null!=e){r=e;continue}}const t=r.nextSibling;if(null!=t){l++,r=t;continue}const o=r.parentNode;if(null!=o){const e=o.nextSibling;if(null==e)break;s++,l=0,r=e;}}return o.columns=l+1,o.rows=s+1,o}function Qt(e,t,n){const o=new Set(n?n.getNodes():[]);Zt(t,(t,n)=>{const r=t.elem;o.has(n)?(t.highlighted=true,cn(e,t)):(t.highlighted=false,an(e,t),r.getAttribute("style")||r.removeAttribute("style"));});}function Zt(e,t){const{domRows:n}=e;for(let e=0;e<n.length;e++){const o=n[e];if(o)for(let n=0;n<o.length;n++){const r=o[n];if(!r)continue;const l=Go(r.elem);null!==l&&t(r,l,{x:n,y:e});}}}const en=(e,t,n,o,r)=>{const l="forward"===r;switch(r){case "backward":case "forward":return n!==(l?e.table.columns-1:0)?sn(t.getCellNodeFromCordsOrThrow(n+(l?1:-1),o,e.table),l):o!==(l?e.table.rows-1:0)?sn(t.getCellNodeFromCordsOrThrow(l?0:e.table.columns-1,o+(l?1:-1),e.table),l):l?t.selectNext():t.selectPrevious(),true;case "up":return 0!==o?sn(t.getCellNodeFromCordsOrThrow(n,o-1,e.table),false):t.selectPrevious(),true;case "down":return o!==e.table.rows-1?sn(t.getCellNodeFromCordsOrThrow(n,o+1,e.table),true):t.selectNext(),true;default:return false}};function tn(e,t){let n,o;
11207if(t.startColumn===e.minColumn)n="minColumn";else {if(t.startColumn+t.cell.__colSpan-1!==e.maxColumn)return null;n="maxColumn";}if(t.startRow===e.minRow)o="minRow";else {if(t.startRow+t.cell.__rowSpan-1!==e.maxRow)return null;o="maxRow";}return [n,o]}function nn([e,t]){return ["minColumn"===e?"maxColumn":"minColumn","minRow"===t?"maxRow":"minRow"]}function on(e,t,[n,o]){const r=t[o],l=e[r];void 0===l&&Le$1(250,o,String(r));const s=t[n],i=l[s];return void 0===i&&Le$1(250,n,String(s)),i}function rn(e,t,n,o,r){const l=Nt(t,n,o),s=function(e,t){const{minColumn:n,maxColumn:o,minRow:r,maxRow:l}=t;let s=1,i=1,c=1,a=1;const u=e[r],h=e[l];for(let e=n;e<=o;e++)s=Math.max(s,u[e].cell.__rowSpan),a=Math.max(a,h[e].cell.__rowSpan);for(let t=r;t<=l;t++)i=Math.max(i,e[t][n].cell.__colSpan),c=Math.max(c,e[t][o].cell.__colSpan);return {bottomSpan:a,leftSpan:i,rightSpan:c,topSpan:s}}(t,l),{topSpan:i,leftSpan:c,bottomSpan:a,rightSpan:u}=s,h=function(e,t){const n=tn(e,t);return null===n&&Le$1(249,t.cell.getKey()),n}(l,n),[d,f]=nn(h);let g=l[d],m=l[f];"forward"===r?g+="maxColumn"===d?1:c:"backward"===r?g-="minColumn"===d?1:u:"down"===r?m+="maxRow"===f?1:i:"up"===r&&(m-="minRow"===f?1:a);const p=t[m];if(void 0===p)return false;const C=p[g];if(void 0===C)return false;const[_,S]=function(e,t,n){const o=Nt(e,t,n),r=tn(o,t);if(r)return [on(e,o,r),on(e,o,nn(r))];const l=tn(o,n);if(l)return [on(e,o,nn(l)),on(e,o,l)];const s=["minColumn","minRow"];return [on(e,o,s),on(e,o,nn(s))]}(t,n,C),w=Cn(e,_.cell),b=Cn(e,S.cell);return e.$setAnchorCellForSelection(w),e.$setFocusCellForSelection(b,true),true}function ln(e,t){if(Fr(e)||Ot(e)){const n=t.isParentOf(e.anchor.getNode()),o=t.isParentOf(e.focus.getNode());return n&&o}return false}function sn(e,t){t?e.selectStart():e.selectEnd();}function cn(t,n){const o=n.elem,r=t._config.theme;We$1(Go(o))||Le$1(131),mc(o,r.tableCellSelected);}function an(e,t){const n=t.elem;We$1(Go(n))||Le$1(131);const r=e._config.theme;xc(n,r.tableCellSelected);}function un(e){const t=dl(e,We$1);return We$1(t)?t:null}function hn(e){const t=dl(e,Rn);return Rn(t)?t:null}function dn(e,t,o,r,l,s,i){const c=ql(o.focus,l?"previous":"next");if(ic(c))return false;let a=c;for(const e of Rl(c).iterNodeCarets("shadowRoot")){if(!Tl(e)||!Wi(e.origin))return false;a=e;}const u=a.getParentAtCaret();if(!We$1(u))return false;const h=u,d=function(e){for(const t of Rl(e).iterNodeCarets("root")){const{origin:n}=t;if(We$1(n)){if(Nl(t))return Pl(n,e.direction)}else if(!De$1(n))break}return null}(Ol(h,a.direction)),f=dl(h,Rn);if(!f||!f.is(s))return false;const g=e.getElementByKey(h.getKey()),m=jt(g);if(!g||!m)return false;const p=xn(e,f);if(i.table=p,d)if("extend"===r){const t=jt(e.getElementByKey(d.origin.getKey()));if(!t)return false;i.$setAnchorCellForSelection(m),i.$setFocusCellForSelection(t,true);}else {const e=rc(d);Hl(o.anchor,e),Hl(o.focus,e);}else if("extend"===r)i.$setAnchorCellForSelection(m),i.$setFocusCellForSelection(m,true);else {const e=function(e){const t=Ll(e);return Nl(t)?rc(t):e}(Ol(f,c.direction));Hl(o.anchor,e),Hl(o.focus,e);}return gn(t),true}function fn(e,t,o,r,l,s){if(("up"===o||"down"===o)&&function(e){const t=e.getRootElement();if(!t)return false;return t.hasAttribute("aria-controls")&&"typeahead-menu"===t.getAttribute("aria-controls")}(e))return false;const i=Qr();if(!ln(i,r)){if(Fr(i)){if("backward"===o){if(i.focus.offset>0)return false;const e=function(e){for(let t=e,n=e;null!==n;t=n,n=n.getParent())if(Wi(n)){if(n!==t&&n.getFirstChild()!==t)return null;if(!n.isInline())return n}return null}(i.focus.getNode());if(!e)return false;const n=e.getPreviousSibling();return !!Rn(n)&&(gn(t),t.shiftKey?i.focus.set(n.getParentOrThrow().getKey(),n.getIndexWithinParent(),"element"):n.selectEnd(),true)}if(t.shiftKey&&("up"===o||"down"===o)){const e=i.focus.getNode();if(!i.isCollapsed()&&("up"===o&&!i.isBackward()||"down"===o&&i.isBackward())){let l=dl(e,e=>Rn(e));if(We$1(l)&&(l=dl(l,Rn)),l!==r)return false;if(!l)return false;const s="down"===o?l.getNextSibling():l.getPreviousSibling();if(!s)return false;let c=0;"up"===o&&Wi(s)&&(c=s.getChildrenSize());let a=s;if("up"===o&&Wi(s)){const e=s.getLastChild();a=e||s,c=Tr(a)?a.getTextContentSize():0;}const u=i.clone();return u.focus.set(a.getKey(),c,Tr(a)?"text":"element"),es(u),gn(t),true}if(Is(e)){const e="up"===o?i.getNodes()[i.getNodes().length-1]:i.getNodes()[0];if(e){if(null!==Bt(r,e)){const e=r.getFirstDescendant(),t=r.getLastDescendant();if(!e||!t)return false;
11207const[n]=yt(e),[o]=yt(t),s=r.getCordsFromCellNode(n,l.table),i=r.getCordsFromCellNode(o,l.table),c=r.getDOMCellFromCordsOrThrow(s.x,s.y,l.table),a=r.getDOMCellFromCordsOrThrow(i.x,i.y,l.table);return l.$setAnchorCellForSelection(c),l.$setFocusCellForSelection(a,true),true}}return false}{let r=dl(e,e=>Wi(e)&&!e.isInline());if(We$1(r)&&(r=dl(r,Rn)),!r)return false;const s="down"===o?r.getNextSibling():r.getPreviousSibling();if(Rn(s)&&l.tableNodeKey===s.getKey()){const e=s.getFirstDescendant(),n=s.getLastDescendant();if(!e||!n)return false;const[r]=yt(e),[l]=yt(n),c=i.clone();return c.focus.set(("up"===o?r:l).getKey(),"up"===o?0:l.getChildrenSize(),"element"),gn(t),es(c),true}}}}return "down"===o&&yn(e)&&s.setShouldCheckSelectionForTable(r.getKey()),false}if(Fr(i)){if("backward"===o||"forward"===o){return dn(e,t,i,t.shiftKey?"extend":"move","backward"===o,r,l)}if(i.isCollapsed()){const{anchor:c,focus:a}=i,u=dl(c.getNode(),We$1),h=dl(a.getNode(),We$1);if(!We$1(u)||!u.is(h))return false;const d=hn(u);if(d!==r&&null!=d){const n=Lt(d,e.getElementByKey(d.getKey()));if(null!=n)return l.table=Gt(d,n),fn(e,t,o,d,l,s)}const f=e.getElementByKey(u.__key),g=e.getElementByKey(c.key);if(null==g||null==f)return false;let m;if("element"===c.type)m=g.getBoundingClientRect();else {const t=Js(Ht(e));if(null===t||0===t.rangeCount)return false;m=t.getRangeAt(0).getBoundingClientRect();}const p="up"===o?u.getFirstChild():u.getLastChild();if(null==p)return false;const C=e.getElementByKey(p.__key);if(null==C)return false;const _=C.getBoundingClientRect();if("up"===o?_.top>m.top-m.height:m.bottom+m.height>_.bottom){gn(t);const e=r.getCordsFromCellNode(u,l.table);if(!t.shiftKey)return en(l,r,e.x,e.y,o);{const t=r.getDOMCellFromCordsOrThrow(e.x,e.y,l.table);l.$setAnchorCellForSelection(t),l.$setFocusCellForSelection(t,true);}return true}}}else if(Ot(i)){const{anchor:s,focus:c}=i,a=dl(s.getNode(),We$1),u=dl(c.getNode(),We$1),[h]=i.getNodes();Rn(h)||Le$1(251);const d=Lt(h,e.getElementByKey(h.getKey()));if(!We$1(a)||!We$1(u)||!Rn(h)||null==d)return false;l.$updateTableTableSelection(i);const f=Gt(h,d),g=r.getCordsFromCellNode(a,f),m=r.getDOMCellFromCordsOrThrow(g.x,g.y,f);
11207if(l.$setAnchorCellForSelection(m),gn(t),t.shiftKey){const[e,t,n]=wt(r,a,u);return rn(l,e,t,n,o)}return u.selectEnd(),true}return false}function gn(e){e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation();}function mn(e,t,n){const o=eo();"first"===e?t.insertBefore(o):t.insertAfter(o),o.append(...n||[]),o.selectEnd();}function pn(e,t,o){const r=o.getParent();if(!r)return;const l=Js(Ht(e));if(!l)return;const s=l.anchorNode,i=e.getElementByKey(r.getKey()),c=Lt(o,e.getElementByKey(o.getKey()));if(!s||!i||!c||!i.contains(s)||c.contains(s))return;const a=dl(t.anchor.getNode(),e=>We$1(e));if(!a)return;const u=dl(a,e=>Rn(e));if(!Rn(u)||!u.is(o))return;const[h,d]=wt(o,a,a),f=h[0][0],g=h[h.length-1][h[0].length-1],{startRow:m,startColumn:p}=d,C=m===f.startRow&&p===f.startColumn,_=m===g.startRow&&p===g.startColumn;return C?"first":_?"last":void 0}function Cn(e,t){const{tableNode:n}=e.$lookup(),o=n.getCordsFromCellNode(t,e.table);return n.getDOMCellFromCordsOrThrow(o.x,o.y,e.table)}function _n(e,t,n){return Bt(e,Go(t,n))}function Sn(e,t,n){const o=e.querySelector("colgroup");if(!o)return;const r=[];for(let e=0;e<t;e++){const t=document.createElement("col"),o=n&&n[e];o&&(t.style.width=`${o}px`),r.push(t);}o.replaceChildren(...r);}function wn(t,n,r){if(!n.theme.tableAlignment)return;const l=[],s=[];for(const e of ["center","right"]){const t=n.theme.tableAlignment[e];t&&(e===r?s:l).push(t);}xc(t,...l),mc(t,...s);}const bn=new WeakSet;function yn(e=Zs()){return bn.has(e)}function Nn(e,t){bn.add(e);}class vn extends Bi{__rowStriping;__frozenColumnCount;__frozenRowCount;__colWidths;static getType(){return "table"}getColWidths(){return this.getLatest().__colWidths}setColWidths(e){const t=this.getWritable();return t.__colWidths=e,t}static clone(e){return new vn(e.__key)}afterCloneFrom(e){super.afterCloneFrom(e),this.__colWidths=e.__colWidths,this.__rowStriping=e.__rowStriping,this.__frozenColumnCount=e.__frozenColumnCount,this.__frozenRowCount=e.__frozenRowCount;}static importDOM(){return {table:e=>({conversion:Tn,priority:1})}}static importJSON(e){return Fn().updateFromJSON(e)}updateFromJSON(e){return super.updateFromJSON(e).setRowStriping(e.rowStriping||false).setFrozenColumns(e.frozenColumnCount||0).setFrozenRows(e.frozenRowCount||0).setColWidths(e.colWidths)}constructor(e){super(e),this.__rowStriping=false,this.__frozenColumnCount=0,this.__frozenRowCount=0,this.__colWidths=void 0;}exportJSON(){return {...super.exportJSON(),colWidths:this.getColWidths(),frozenColumnCount:this.__frozenColumnCount?this.__frozenColumnCount:void 0,frozenRowCount:this.__frozenRowCount?this.__frozenRowCount:void 0,rowStriping:this.__rowStriping?this.__rowStriping:void 0}}extractWithChild(e,t,n){return "html"===n}getDOMSlot(e){const t=zt(e)?e:e.querySelector("table");return zt(t)||Le$1(229),super.getDOMSlot(e).withElement(t).withAfter(t.querySelector("colgroup"))}createDOM(t,n){const o=document.createElement("table");this.__style&&nr(o.style,this.__style);const r=document.createElement("colgroup");if(o.appendChild(r),ll(r),mc(o,t.theme.table),this.updateTableElement(null,o,t),yn(n)){const n=document.createElement("div"),r=t.theme.tableScrollableWrapper;return r?mc(n,r):n.style.overflowX="auto",n.appendChild(o),this.updateTableWrapper(null,n,o,t),n}return o}updateTableWrapper(t,n,r,l){this.__frozenColumnCount!==(t?t.__frozenColumnCount:0)&&function(t,n,r,l){l>0?(mc(t,r.theme.tableFrozenColumn),n.setAttribute("data-lexical-frozen-column","true")):(xc(t,r.theme.tableFrozenColumn),n.removeAttribute("data-lexical-frozen-column"));}(n,r,l,this.__frozenColumnCount),this.__frozenRowCount!==(t?t.__frozenRowCount:0)&&function(t,n,r,l){l>0?(mc(t,r.theme.tableFrozenRow),n.setAttribute("data-lexical-frozen-row","true")):(xc(t,r.theme.tableFrozenRow),n.removeAttribute("data-lexical-frozen-row"));}(n,r,l,this.__frozenRowCount);}updateTableElement(t,n,r){this.__style!==(t?t.__style:"")&&nr(n.style,this.__style,t?t.__style:""),this.__rowStriping!==(!!t&&t.__rowStriping)&&function(t,n,r){r?(mc(t,n.theme.tableRowStriping),t.setAttribute("data-lexical-row-striping","true")):(xc(t,n.theme.tableRowStriping),t.removeAttribute("data-lexical-row-striping"));}(n,r,this.__rowStriping);const l=t?t.getColumnCount():0,s=t?t.__colWidths:void 0;this.getColumnCount()===l&&this.getColWidths()===s||Sn(n,this.getColumnCount(),this.getColWidths()),wn(n,r,this.getFormatType());}updateDOM(e,t,n){const o=Lt(this,t);return t===o===yn()||(Ys(r=t)&&"DIV"===r.nodeName&&this.updateTableWrapper(e,t,o,n),this.updateTableElement(e,o,n),false);var r;}scaleDOMColWidths(e,t){const n=this.getColWidths();if(!n)return;Sn(Lt(this,e),this.getColumnCount(),n.map(e=>e*t));}exportDOM(e){const t=super.exportDOM(e),{element:n}=t;return {after:n=>{if(t.after&&(n=t.after(n)),!zt(n)&&Ys(n)&&(n=n.querySelector("table")),!zt(n))return null;wn(n,e._config,this.getFormatType());const[o]=bt(this,null,null),r=new Map;for(const e of o)for(const t of e){const e=t.cell.getKey();r.has(e)||r.set(e,{colSpan:t.cell.getColSpan(),startColumn:t.startColumn});}const s=new Set;for(const e of n.querySelectorAll(":scope > tr > [data-temporary-table-cell-lexical-key]")){const t=e.getAttribute("data-temporary-table-cell-lexical-key");if(t){const n=r.get(t);if(e.removeAttribute("data-temporary-table-cell-lexical-key"),n){r.delete(t);for(let e=0;e<n.colSpan;e++)s.add(e+n.startColumn);}}}const i=n.querySelector(":scope > colgroup");if(i){const e=Array.from(n.querySelectorAll(":scope > colgroup > col")).filter((e,t)=>
11207s.has(t));i.replaceChildren(...e);}const c=n.querySelectorAll(":scope > tr");if(c.length>0){const e=document.createElement("tbody");for(const t of c)e.appendChild(t);n.append(e);}return n},element:!zt(n)&&Ys(n)?n.querySelector("table"):n}}canBeEmpty(){return false}isShadowRoot(){return true}getCordsFromCellNode(e,t){const{rows:n,domRows:o}=t;for(let t=0;t<n;t++){const n=o[t];if(null!=n)for(let o=0;o<n.length;o++){const r=n[o];if(null==r)continue;const{elem:l}=r,s=_n(this,l);if(null!==s&&e.is(s))return {x:o,y:t}}}throw new Error("Cell not found in table.")}getDOMCellFromCords(e,t,n){const{domRows:o}=n,r=o[t];if(null==r)return null;const l=r[e<r.length?e:r.length-1];return null==l?null:l}getDOMCellFromCordsOrThrow(e,t,n){const o=this.getDOMCellFromCords(e,t,n);if(!o)throw new Error("Cell not found at cords.");return o}getCellNodeFromCords(e,t,n){const o=this.getDOMCellFromCords(e,t,n);if(null==o)return null;const r=Go(o.elem);return We$1(r)?r:null}getCellNodeFromCordsOrThrow(e,t,n){const o=this.getCellNodeFromCords(e,t,n);if(!o)throw new Error("Node at cords not TableCellNode.");return o}getRowStriping(){return Boolean(this.getLatest().__rowStriping)}setRowStriping(e){const t=this.getWritable();return t.__rowStriping=e,t}setFrozenColumns(e){const t=this.getWritable();return t.__frozenColumnCount=e,t}getFrozenColumns(){return this.getLatest().__frozenColumnCount}setFrozenRows(e){const t=this.getWritable();return t.__frozenRowCount=e,t}getFrozenRows(){return this.getLatest().__frozenRowCount}canSelectBefore(){return true}canIndent(){return false}getColumnCount(){const e=this.getFirstChild();if(!e)return 0;let t=0;
11207return e.getChildren().forEach(e=>{We$1(e)&&(t+=e.getColSpan());}),t}}function xn(e,t){const n=e.getElementByKey(t.getKey());return null===n&&Le$1(230),Gt(t,n)}function Tn(e){const n=Fn();e.hasAttribute("data-lexical-row-striping")&&n.setRowStriping(true),e.hasAttribute("data-lexical-frozen-column")&&n.setFrozenColumns(1),e.hasAttribute("data-lexical-frozen-row")&&n.setFrozenRows(1);const o=e.querySelector(":scope > colgroup");if(o){let e=[];for(const t of o.querySelectorAll(":scope > col")){let n=t.style.width||"";if(!Ke$1.test(n)&&(n=t.getAttribute("width")||"",!/^\d+$/.test(n))){e=void 0;break}e.push(parseFloat(n));}e&&n.setColWidths(e);}return {after:e=>Ht$3(e,De$1),node:n}}function Fn(){return zs(new vn)}function Rn(e){return e instanceof vn}function On(e){De$1(e.getParent())?e.isEmpty()&&e.append(eo()):e.remove();}function Kn(e){Rn(e.getParent())?Ot$3(e,We$1):e.remove();}function An(e){Ot$3(e,De$1);const[t]=bt(e,null,null),n=t.reduce((e,t)=>Math.max(e,t.length),0),o=e.getChildren();for(let e=0;e<t.length;++e){const r=o[e];if(!r)continue;De$1(r)||Le$1(254,r.constructor.name,r.getType());const l=t[e].reduce((e,t)=>t?1+e:e,0);if(l!==n)for(let e=l;e<n;++e){const e=$e$1();e.append(eo()),r.append(e);}}const r=e.getColWidths(),l=e.getColumnCount();if(r&&r.length!==l){let t;if(l<r.length)t=r.slice(0,l);else if(r.length>0){const e=r[r.length-1];t=[...r,...Array(l-r.length).fill(e)];}e.setColWidths(t);}}function En(e){if(e.detail<3||!qs(e.target))return false;const t=Go(e.target);if(null===t)return false;const o=dl(t,e=>Wi(e)&&!e.isInline());if(null===o)return false;return !!We$1(o.getParent())&&(o.select(0),true)}function kn(){const e=Qr();if(!Fr(e))return false;const t=hn(e.anchor.getNode());if(null===t)return false;const n=Zo();if(!n.is(t.getParent())||1!==n.getChildrenSize())return false;const[o]=bt(t,null,null);if(0===o.length||0===o[0].length)return false;const r=o[0][0];if(!r||!r.cell)return false;const l=o[o.length-1],s=l[l.length-1];if(!s||!s.cell)return false;const i=At(t,r.cell,s.cell);return es(i),true}function $n(e,t=true){const n=new Mt,o=(o,r,l)=>{const s=Lt(o,l),i=Jt(o,s,e,t,n);n.observers.set(r,[i,s]);};return Cc(Ut(e,n),e.registerCommand(ie$4,()=>Xt(n,e),so),e.registerMutationListener(vn,t=>{e.getEditorState().read(()=>{for(const[e,r]of t){const t=n.observers.get(e);if("created"===r||"updated"===r){const{tableNode:r,tableElement:l}=kt(e);void 0===t?o(r,e,l):l!==t[1]&&(t[0].removeListeners(),n.observers.delete(e),o(r,e,l));}else "destroyed"===r&&void 0!==t&&(t[0].removeListeners(),n.observers.delete(e));}},{editor:e});},{skipInitialization:false}),()=>{for(const[,[e]]of n.observers)e.removeListeners();})}function Wn(e,t){e.hasNodes([vn])||Le$1(255);const{hasNestedTables:o=ft$1(false)}={};return Cc(e.registerCommand(ze$1,e=>function({rows:e,columns:t,includeHeaders:n},o){const r=Qr()||Zr();if(!r||!Fr(r))return false;if(!o&&hn(r.anchor.getNode()))return false;const l=Xe$1(Number(e),Number(t),n);Pt$3(l);const s=l.getFirstDescendant();return Tr(s)&&s.select(),true}(e,o.peek()),ro),e.registerCommand(oe$6,(t,r)=>e===r&&function(e,t){const{nodes:o,selection:r}=e;if(!o.some(e=>Rn(e)||pt$2(e).some(e=>Rn(e.node))))return false;const l=Ot(r),s=Fr(r);if(!(s&&null!==dl(r.anchor.getNode(),e=>We$1(e))&&null!==dl(r.focus.getNode(),e=>We$1(e))||l))return false;if(1===o.length&&Rn(o[0]))return function(e,t){const o=t.getStartEndPoints(),r=Ot(t);if(null===o)return false;const[l,s]=o,[i,c,a]=yt(l),u=dl(s.getNode(),e=>We$1(e));if(!(We$1(i)&&We$1(u)&&De$1(c)&&Rn(a)))return false;const[h,d,f]=wt(a,i,u),[m]=bt(e,null,null),C=h.length,_=C>0?h[0].length:0;let S=d.startRow,w=d.startColumn,b=m.length,y=b>0?m[0].length:0;if(r){const e=Nt(h,d,f),t=e.maxRow-e.minRow+1,n=e.maxColumn-e.minColumn+1;S=e.minRow,w=e.minColumn,b=Math.min(b,t),y=Math.min(y,n);}let N=false;const v=Math.min(C,S+b)-1,x=Math.min(_,w+y)-1,T=new Set;for(let e=S;e<=v;e++)for(let t=w;t<=x;t++){const n=h[e][t];T.has(n.cell.getKey())||(1===n.cell.__rowSpan&&1===n.cell.__colSpan||(St(n.cell),T.add(n.cell.getKey()),N=true));}let[F]=bt(a.getWritable(),null,null);const R=b-C+S;for(let e=0;e<R;e++){rt(F[C-1][0].cell);}const O=y-_+w;for(let e=0;e<O;e++){ct(F[0][_-1].cell,true,false);}[F]=bt(a.getWritable(),null,null);for(let e=S;e<S+b;e++)for(let t=w;t<w+y;t++){const n=e-S,o=t-w,r=m[n][o];if(r.startRow!==n||r.startColumn!==o)continue;const l=r.cell;if(1!==l.__rowSpan||1!==l.__colSpan){const n=[],o=Math.min(e+l.__rowSpan,S+b)-1,r=Math.min(t+l.__colSpan,w+y)-1;for(let l=e;l<=o;l++)for(let e=t;e<=r;e++){const t=F[l][e];n.push(t.cell);}pt(n),N=true;}const{cell:s}
11207=F[e][t],i=l.getBackgroundColor();null!=i&&s.setBackgroundColor(i);const c=s.getChildren();l.getChildren().forEach(e=>{if(Tr(e)){eo().append(e),s.append(e);}else s.append(e);}),c.forEach(e=>e.remove());}if(r&&N){const[e]=bt(a.getWritable(),null,null);e[d.startRow][d.startColumn].cell.selectEnd();}return true}(o[0],r);if(s&&t.peek()&&!function(e){if(Ot(e)&&!e.focus.getNode().is(e.anchor.getNode()))return true;if(Fr(e)&&We$1(e.anchor.getNode())&&!e.anchor.getNode().is(e.focus.getNode()))return true;return false}(r))return false;return true}(t,o),ro),e.registerCommand(Ue$2,kn,io),e.registerCommand(se$5,En,ro),e.registerNodeTransform(vn,An),e.registerNodeTransform(He$1,Kn),e.registerNodeTransform(Ee$1,On))} 11208 11209// Shared, strictly-contained element used to attach ephemeral nodes when we 11210// need to read computed styles (e.g. canonicalizing style values, resolving 11211// CSS custom properties). The container is created once and attached to 11212// `document.body` once; subsequent child mutations happen *inside* the 11213// contained subtree so they do not invalidate style on the rest of the page. 11214// 11215// Without this, `document.body.appendChild(...)` / `element.remove()` calls 11216// forced the browser to re-evaluate every ancestor-dependent selector (`:has()`, 11217// descendant combinators, universal sibling rules) across the document on each 11218// invocation â a 13,000+ element style recalc per call on a typical Basecamp 11219// page. 11220 11221let resolverRoot = null; 11222 11223function styleResolverRoot() { 11224 if (resolverRoot && resolverRoot.isConnected) return resolverRoot 11225 11226 resolverRoot = document.createElement("div"); 11227 resolverRoot.setAttribute("aria-hidden", "true"); 11228 resolverRoot.setAttribute("data-lexxy-style-resolver", ""); 11229 // `contain: strict` (size, layout, paint, style) isolates everything.
vendor: 82,247 bytes, lines 11230-13999
11230 // The root itself paints nothing (visibility hidden), has zero 11231 // geometric impact (position fixed, intrinsic size via contain), and 11232 // never leaks style invalidation to its ancestors. 11233 resolverRoot.style.cssText = "contain: strict; position: fixed; top: 0; left: 0; visibility: hidden; pointer-events: none; width: 0; height: 0;"; 11234 document.body.appendChild(resolverRoot); 11235 return resolverRoot 11236} 11237 11238function isSelectionHighlighted(selection) { 11239 if (!Fr(selection)) return false 11240 11241 if (selection.isCollapsed()) { 11242 return hasHighlightStyles(selection.style) 11243 } else { 11244 return selection.hasFormat("highlight") 11245 } 11246} 11247 11248function getHighlightStyles(selection) { 11249 if (!Fr(selection)) return null 11250 11251 let styles = oe$5(selection.style); 11252 if (!styles.color && !styles["background-color"]) { 11253 const anchorNode = selection.anchor.getNode(); 11254 if (Tr(anchorNode)) { 11255 styles = oe$5(anchorNode.getStyle()); 11256 } 11257 } 11258 11259 const color = styles.color || null; 11260 const backgroundColor = styles["background-color"] || null; 11261 if (!color && !backgroundColor) return null 11262 11263 return { color, backgroundColor } 11264} 11265 11266function hasHighlightStyles(cssOrStyles) { 11267 const styles = typeof cssOrStyles === "string" ? oe$5(cssOrStyles) : cssOrStyles; 11268 return !!(styles.color || styles["background-color"]) 11269} 11270 11271function applyCanonicalizers(styles, canonicalizers = []) { 11272 return canonicalizers.reduce((css, canonicalizer) => { 11273 return canonicalizer.applyCanonicalization(css) 11274 }, styles) 11275} 11276 11277class StyleCanonicalizer { 11278 constructor(property, allowedValues= []) { 11279 this._property = property; 11280 this._allowedValues = allowedValues; 11281 this._canonicalValues = this.#allowedValuesIdentityObject; 11282 } 11283 11284 applyCanonicalization(css) { 11285 const styles = { ...oe$5(css) }; 11286 11287 styles[this._property] = this.getCanonicalAllowedValue(styles[this._property]); 11288 if (!styles[this._property]) { 11289 delete styles[this._property]; 11290 } 11291 11292 return F$6(styles) 11293 } 11294 11295 getCanonicalAllowedValue(value) { 11296 return this._canonicalValues[value] ||= this.#resolveCannonicalValue(value) 11297 } 11298 11299 // Private 11300 11301 get #allowedValuesIdentityObject() { 11302 return this._allowedValues.reduce((object, value) => ({ ...object, [value]: value }), {}) 11303 } 11304 11305 #resolveCannonicalValue(value) { 11306 let index = this.#computedAllowedValues.indexOf(value); 11307 if (index === -1) { 11308 index = this.#computedAllowedValues.indexOf(computeStyleValues(this._property, [ value ])[0]); 11309 } 11310 return index === -1 ? null : this._allowedValues[index] 11311 } 11312 11313 get #computedAllowedValues() { 11314 return this._computedAllowedValues ||= computeStyleValues(this._property, this._allowedValues) 11315 } 11316} 11317 11318// Separates DOM writes from layout reads to avoid forced reflows, and attaches 11319// resolver elements to a strictly-contained root (outside the normal document 11320// flow) so neither the attach nor the detach invalidate styles on the rest of 11321// the page. Without containment, appending to `document.body` triggered a 11322// page-wide style recalc on every canonicalization pass. 11323function computeStyleValues(property, values) { 11324 const fragment = document.createDocumentFragment(); 11325 11326 const elements = values.map(value => { 11327 const element = createElement("span", { style: `display: none; ${property}: ${value};` }); 11328 fragment.appendChild(element); 11329 return element 11330 }); 11331 11332 styleResolverRoot().appendChild(fragment); 11333 11334 const computed = elements.map(element => 11335 window.getComputedStyle(element).getPropertyValue(property) 11336 ); 11337 11338 elements.forEach(element => element.remove()); 11339 return computed 11340} 11341 11342const TOGGLE_HIGHLIGHT_COMMAND = re$5(); 11343const REMOVE_HIGHLIGHT_COMMAND = re$5(); 11344const BLANK_STYLES = { "color": null, "background-color": null }; 11345 11346const hasPastedStylesState = ot$3("hasPastedStyles", { 11347 parse: (value) => value || false 11348}); 11349 11350// Stores pending highlight ranges extracted during HTML import, keyed by CodeNode key. 11351// The highlight-preserving tokenizer consumes this map when the code retokenizer 11352// first tokenizes the block. Scoped per editor instance so entries don't leak 11353// across editors or outlive a torn-down editor. 11354const pendingCodeHighlights = new WeakMap(); 11355 11356class HighlightExtension extends LexxyExtension { 11357 get enabled() { 11358 return this.editorElement.supportsRichText 11359 } 11360 11361 get lexicalExtension() { 11362 const extension = dc({ 11363 dependencies: [ Xt$2 ], 11364 name: "lexxy/highlight", 11365 config: { 11366 color: { buttons: [], permit: [] }, 11367 "background-color": { buttons: [], permit: [] } 11368 }, 11369 html: { 11370 import: { 11371 mark: $markConversion 11372 } 11373 }, 11374 register(editor, config) { 11375 // keep the ref to the canonicalizers for optimized css conversion 11376 const canonicalizers = buildCanonicalizers(config); 11377 11378 // Register the <pre> converter directly in the conversion cache so it 11379 // coexists with other extensions' "pre" converters (the extension-level 11380 // html.import uses Object.assign, which means only one "pre" per key). 11381 $registerPreConversion(editor); 11382 11383 return Cc( 11384 editor.registerCommand(TOGGLE_HIGHLIGHT_COMMAND, (styles) => $toggleSelectionStyles(editor, styles), oo), 11385 editor.registerCommand(REMOVE_HIGHLIGHT_COMMAND, () => $toggleSelectionStyles(editor, BLANK_STYLES), oo), 11386 editor.registerNodeTransform(gr, $syncHighlightWithStyle), 11387 editor.registerNodeTransform(K$1, $syncHighlightWithCodeHighlightNode), 11388 editor.registerNodeTransform(gr, (textNode) => $canonicalizePastedStyles(textNode, canonicalizers)) 11389 ) 11390 } 11391 }); 11392 11393 return [ extension, this.editorConfig.get("highlight") ] 11394 } 11395} 11396 11397function $applyHighlightStyle(textNode, element) { 11398 const elementStyles = { 11399 color: element.style?.color, 11400 "background-color": element.style?.backgroundColor 11401 }; 11402 11403 if (Es(jn)) { $setPastedStyles(textNode); } 11404 const highlightStyle = F$6(elementStyles); 11405 11406 if (highlightStyle.length) { 11407 return textNode.setStyle(textNode.getStyle() + highlightStyle) 11408 } 11409} 11410 11411function $markConversion() { 11412 return { 11413 conversion: extendTextNodeConversion("mark", $applyHighlightStyle), 11414 priority: 1 11415 } 11416} 11417 11418// Register a custom <pre> converter directly in the editor's HTML conversion 11419// cache. We can't use the extension-level html.import because Object.assign 11420// merges all extensions' converters by tag, and a later extension (e.g. 11421// TrixContentExtension) would overwrite ours. 11422function $registerPreConversion(editor) { 11423 if (!editor._htmlConversions) return 11424 11425 let preEntries = editor._htmlConversions.get("pre"); 11426 if (!preEntries) { 11427 preEntries = []; 11428 editor._htmlConversions.set("pre", preEntries); 11429 } 11430 preEntries.push($preConversionWithHighlightsFactory(editor)); 11431} 11432 11433// Returns a <pre> converter factory scoped to a specific editor instance. 11434// The factory extracts highlight ranges from <mark> elements before the code 11435// retokenizer can destroy them. The ranges are stored in pendingCodeHighlights 11436// and restored by the highlight-preserving tokenizer during retokenization. 11437function $preConversionWithHighlightsFactory(editor) { 11438 return function $preConversionWithHighlights(domNode) { 11439 const highlights = extractHighlightRanges(domNode); 11440 if (highlights.length === 0) return null 11441 11442 return { 11443 conversion: (domNode) => { 11444 const language = domNode.getAttribute("data-language"); 11445 const codeNode = I$1(language); 11446 $getPendingHighlights(editor).set(codeNode.getKey(), highlights); 11447 return { node: codeNode } 11448 }, 11449 priority: 2 11450 } 11451 } 11452} 11453 11454// Walk the DOM tree inside a <pre> element and build a list of 11455// { start, end, style } ranges for every <mark> element found. 11456function extractHighlightRanges(preElement) { 11457 const ranges = []; 11458 const codeElement = preElement.querySelector("code") || preElement; 11459 11460 let offset = 0; 11461 11462 function walk(node) { 11463 if (node.nodeType === Node.TEXT_NODE) { 11464 offset += node.textContent.length; 11465 } else if (node.nodeType === Node.ELEMENT_NODE) { 11466 // <br> maps to a LineBreakNode (1 character) in Lexical 11467 if (node.tagName === "BR") { 11468 offset += 1; 11469 return 11470 } 11471 11472 const isMark = node.tagName === "MARK"; 11473 const start = offset; 11474 11475 for (const child of node.childNodes) { 11476 walk(child); 11477 } 11478 11479 if (isMark) { 11480 const style = extractHighlightStyleFromElement(node); 11481 if (style) { 11482 ranges.push({ start, end: offset, style }); 11483 } 11484 } 11485 } 11486 } 11487 11488 for (const child of codeElement.childNodes) { 11489 walk(child); 11490 } 11491 11492 return ranges 11493} 11494 11495function $getPendingHighlights(editor) { 11496 let map = pendingCodeHighlights.get(editor); 11497 if (!map) { 11498 map = new Map(); 11499 pendingCodeHighlights.set(editor, map); 11500 } 11501 return map 11502} 11503 11504function extractHighlightStyleFromElement(element) { 11505 const styles = {}; 11506 if (element.style?.color) styles.color = element.style.color; 11507 if (element.style?.backgroundColor) styles["background-color"] = element.style.backgroundColor; 11508 const css = F$6(styles); 11509 return css.length > 0 ? css : null 11510} 11511 11512// The code retokenizer replaces a code block's children with freshly created 11513// tokens that carry no styles, which would drop color highlights on every 11514// edit. This tokenizer wraps the stock Prism tokenizer to restore them: it 11515// recovers the block's highlight ranges â staged during HTML import, or read 11516// from the children the fresh tokens are about to replace â and reapplies 11517// them to the fresh tokens before the retokenizer splices them in. 11518function buildHighlightPreservingTokenizer(editor) { 11519 return { 11520 defaultLanguage: r.defaultLanguage, 11521 tokenize(code, language) { 11522 return r.tokenize(code, language) 11523 }, 11524 $tokenize(codeNode, language) { 11525 const tokens = r.$tokenize(codeNode, language); 11526 const highlights = $takeHighlightRanges(editor, codeNode); 11527 return $applyHighlightRangesToTokens(tokens, highlights) 11528 } 11529 } 11530} 11531 11532function $takeHighlightRanges(editor, codeNode) { 11533 const pending = $getPendingHighlights(editor); 11534 const key = codeNode.getKey(); 11535 11536 if (pending.has(key)) { 11537 const highlights = pending.get(key); 11538 pending.delete(key); 11539 return highlights 11540 } else if (codeNode.getChildren().some(X$1)) { 11541 return $extractHighlightRangesFromCodeNode(codeNode) 11542 } else { 11543 // A block that was never tokenized has only plain text children. Styles 11544 // on those come from import paths that didn't stage ranges (e.g. colored 11545 // spans in Trix HTML), and the first tokenization discards them. 11546 return [] 11547 } 11548} 11549 11550function $applyHighlightRangesToTokens(tokens, highlights) { 11551 if (highlights.length === 0) return tokens 11552 11553 const styledTokens = []; 11554 let offset = 0; 11555 11556 for (const token of tokens) { 11557 if (X$1(token)) { 11558 styledTokens.push(...$splitTokenAtHighlightBoundaries(token, offset, highlights)); 11559 } else { 11560 styledTokens.push(token); 11561 } 11562 offset += token.getTextContentSize(); 11563 } 11564 11565 return styledTokens 11566} 11567 11568// Split a token into segments at highlight boundaries, styling the covered 11569// segments. We can't use TextNode.splitText() because the fresh tokens aren't 11570// attached to the tree yet, so we create CodeHighlightNode replacements. 11571function $splitTokenAtHighlightBoundaries(token, tokenStart, highlights) { 11572 const text = token.getTextContent(); 11573 const segments = segmentTextByHighlights(text, tokenStart, highlights); 11574 11575 if (segments.length === 1) { 11576 const [ segment ] = segments; 11577 if (segment.style) { 11578 $applyHighlightStyleToToken(token, segment.style); 11579 } 11580 return [ token ] 11581 } else { 11582 return segments.map((segment) => { 11583 const segmentToken = V$2(text.slice(segment.start, segment.end), token.getHighlightType()); 11584 if (segment.style) { 11585 $applyHighlightStyleToToken(segmentToken, segment.style); 11586 } 11587 return segmentToken 11588 }) 11589 } 11590} 11591 11592// Partition a token's text into consecutive { start, end, style } segments, 11593// where offsets are relative to the token and style is null for the stretches 11594// no highlight covers. 11595function segmentTextByHighlights(text, tokenStart, highlights) { 11596 const segments = []; 11597 let cursor = 0; 11598 11599 for (const { start, end, style } of highlights) { 11600 const from = Math.max(start - tokenStart, cursor); 11601 const to = Math.min(end - tokenStart, text.length); 11602 11603 if (from < to) { 11604 if (from > cursor) { 11605 segments.push({ start: cursor, end: from, style: null }); 11606 } 11607 segments.push({ start: from, end: to, style }); 11608 cursor = to; 11609 } 11610 } 11611 11612 if (cursor < text.length) { 11613 segments.push({ start: cursor, end: text.length, style: null }); 11614 } 11615 11616 return segments 11617} 11618 11619function $applyHighlightStyleToToken(token, style) { 11620 token.setStyle(style); 11621 $setCodeHighlightFormat(token, true); 11622} 11623 11624function $buildChildRanges(codeNode) { 11625 const childRanges = []; 11626 let charOffset = 0; 11627 11628 for (const child of codeNode.getChildren()) { 11629 if (X$1(child) || Tr(child)) { 11630 const text = child.getTextContent(); 11631 childRanges.push({ node: child, start: charOffset, end: charOffset + text.length }); 11632 charOffset += text.length; 11633 } else { 11634 // LineBreakNode, TabNode - count as 1 character each (\n, \t) 11635 charOffset += 1; 11636 } 11637 } 11638 11639 return childRanges 11640} 11641 11642// Extract highlight ranges from the Lexical node tree of a CodeNode. 11643// This mirrors extractHighlightRanges (which works on DOM elements during 11644// HTML import) but reads from live CodeHighlightNode children instead. 11645function $extractHighlightRangesFromCodeNode(codeNode) { 11646 const ranges = []; 11647 const childRanges = $buildChildRanges(codeNode); 11648 11649 for (const { node, start, end } of childRanges) { 11650 const style = node.getStyle(); 11651 if (style && hasHighlightStyles(style)) { 11652 ranges.push({ start, end, style }); 11653 } 11654 } 11655 11656 return ranges 11657} 11658 11659function buildCanonicalizers(config) { 11660 return [ 11661 new StyleCanonicalizer("color", [ ...config.buttons.color, ...config.permit.color ]), 11662 new StyleCanonicalizer("background-color", [ ...config.buttons["background-color"], ...config.permit["background-color"] ]) 11663 ] 11664} 11665 11666function $toggleSelectionStyles(editor, styles) { 11667 const selection = Qr(); 11668 if (!Fr(selection)) return 11669 11670 const patch = {}; 11671 for (const property in styles) { 11672 const oldValue = ne$4(selection, property); 11673 patch[property] = toggleOrReplace(oldValue, styles[property]); 11674 } 11675 11676 if ($selectionIsInCodeBlock(selection)) { 11677 $patchCodeHighlightStyles(editor, selection, patch); 11678 } else { 11679 $$3(selection, patch); 11680 } 11681} 11682 11683function $selectionIsInCodeBlock(selection) { 11684 const nodes = selection.getNodes(); 11685 return nodes.some((node) => { 11686 // A text node inside a code block may be either a CodeHighlightNode 11687 // (after retokenization) or a plain TextNode (after splitText or before 11688 // the retokenizer has run). Check the parent in both cases. 11689 if (X$1(node) || Tr(node)) { 11690 return W$1(node.getParent()) 11691 } 11692 return W$1(node) 11693 }) 11694} 11695 11696function $patchCodeHighlightStyles(editor, selection, patch) { 11697 // Capture selection state and node keys before the nested update. 11698 // Accept both CodeHighlightNode and TextNode children of a CodeNode 11699 // because splitText creates TextNode instances and the retokenizer 11700 // may not have converted them back to CodeHighlightNodes yet. 11701 const nodeKeys = selection.getNodes() 11702 .filter((node) => (X$1(node) || Tr(node)) && W$1(node.getParent())) 11703 .map((node) => ({ 11704 key: node.getKey(), 11705 startOffset: $getNodeSelectionOffsets(node, selection)[0], 11706 endOffset: $getNodeSelectionOffsets(node, selection)[1], 11707 textSize: node.getTextContentSize() 11708 })); 11709 11710 // Use skipTransforms so the retokenizer doesn't rebuild the block in the 11711 // middle of the toggle, and discrete to force a synchronous commit so the 11712 // styles are in place before editor.focus() triggers a second update cycle. 11713 editor.update(() => { 11714 for (const { key, startOffset, endOffset, textSize } of nodeKeys) { 11715 const node = Yo(key); 11716 if (!node) continue 11717 11718 const parent = node.getParent(); 11719 if (!W$1(parent)) continue 11720 if (startOffset === endOffset) continue 11721 11722 if (startOffset === 0 && endOffset === textSize) { 11723 $applyStylePatchToNode(node, patch); 11724 } else { 11725 const splitNodes = node.splitText(startOffset, endOffset); 11726 const targetNode = splitNodes[startOffset === 0 ? 0 : 1]; 11727 $applyStylePatchToNode(targetNode, patch); 11728 } 11729 } 11730 }, { skipTransforms: true, discrete: true }); 11731} 11732 11733function $getNodeSelectionOffsets(node, selection) { 11734 const nodeKey = node.getKey(); 11735 const anchorKey = selection.anchor.key; 11736 const focusKey = selection.focus.key; 11737 const textSize = node.getTextContentSize(); 11738 11739 const isAnchor = nodeKey === anchorKey; 11740 const isFocus = nodeKey === focusKey; 11741 11742 // Determine if selection is forward or backward 11743 const isForward = selection.isBackward() === false; 11744 11745 let start = 0; 11746 let end = textSize; 11747 11748 if (isForward) { 11749 if (isAnchor) start = selection.anchor.offset; 11750 if (isFocus) end = selection.focus.offset; 11751 } else { 11752 if (isFocus) start = selection.focus.offset; 11753 if (isAnchor) end = selection.anchor.offset; 11754 } 11755 11756 return [ start, end ] 11757} 11758 11759function $applyStylePatchToNode(node, patch) { 11760 const prevStyles = oe$5(node.getStyle()); 11761 const newStyles = { ...prevStyles }; 11762 11763 for (const [ key, value ] of Object.entries(patch)) { 11764 if (value === null) { 11765 delete newStyles[key]; 11766 } else { 11767 newStyles[key] = value; 11768 } 11769 } 11770 11771 const newCSSText = F$6(newStyles); 11772 node.setStyle(newCSSText); 11773 11774 // Sync the highlight format using TextNode's setFormat to bypass 11775 // CodeHighlightNode's no-op override 11776 const shouldHaveHighlight = hasHighlightStyles(newCSSText); 11777 const hasHighlight = node.hasFormat("highlight"); 11778 11779 if (shouldHaveHighlight !== hasHighlight) { 11780 $setCodeHighlightFormat(node, shouldHaveHighlight); 11781 } 11782} 11783 11784function $setCodeHighlightFormat(node, shouldHaveHighlight) { 11785 const writable = node.getWritable(); 11786 const IS_HIGHLIGHT = 1 << 7; 11787 11788 if (shouldHaveHighlight) { 11789 writable.__format |= IS_HIGHLIGHT; 11790 } else { 11791 writable.__format &= ~IS_HIGHLIGHT; 11792 } 11793} 11794 11795function toggleOrReplace(oldValue, newValue) { 11796 return oldValue === newValue ? null : newValue 11797} 11798 11799function $syncHighlightWithStyle(textNode) { 11800 if (hasHighlightStyles(textNode.getStyle()) !== textNode.hasFormat("highlight")) { 11801 textNode.toggleFormat("highlight"); 11802 } 11803} 11804 11805function $syncHighlightWithCodeHighlightNode(node) { 11806 const parent = node.getParent(); 11807 if (!W$1(parent)) return 11808 11809 const shouldHaveHighlight = hasHighlightStyles(node.getStyle()); 11810 const hasHighlight = node.hasFormat("highlight"); 11811 11812 if (shouldHaveHighlight !== hasHighlight) { 11813 $setCodeHighlightFormat(node, shouldHaveHighlight); 11814 } 11815} 11816 11817function $canonicalizePastedStyles(textNode, canonicalizers = []) { 11818 if ($hasPastedStyles(textNode)) { 11819 $setPastedStyles(textNode, false); 11820 11821 const canonicalizedCSS = applyCanonicalizers(textNode.getStyle(), canonicalizers); 11822 textNode.setStyle(canonicalizedCSS); 11823 11824 const selection = Qr(); 11825 if (textNode.isSelected(selection)) { 11826 selection.setStyle(textNode.getStyle()); 11827 selection.setFormat(textNode.getFormat()); 11828 } 11829 } 11830} 11831 11832function $setPastedStyles(textNode, value = true) { 11833 ct$2(textNode, hasPastedStylesState, value); 11834} 11835 11836function $hasPastedStyles(textNode) { 11837 return st$2(textNode, hasPastedStylesState) 11838} 11839 11840const COMMANDS = [ 11841 "bold", 11842 "italic", 11843 "strikethrough", 11844 "underline", 11845 "link", 11846 "unlink", 11847 "toggleHighlight", 11848 "removeHighlight", 11849 "setFormatHeadingLarge", 11850 "setFormatHeadingMedium", 11851 "setFormatHeadingSmall", 11852 "setFormatParagraph", 11853 "applyHeadingFormat", 11854 "clearFormatting", 11855 "insertUnorderedList", 11856 "insertOrderedList", 11857 "insertQuoteBlock", 11858 "insertCodeBlock", 11859 "setCodeLanguage", 11860 "insertHorizontalDivider", 11861 "uploadImage", 11862 "uploadFile", 11863 11864 "insertTable", 11865 11866 "undo", 11867 "redo" 11868]; 11869 11870class CommandDispatcher { 11871 #selectionBeforeDrag = null 11872 #listeners = new ListenerBin() 11873 11874 static configureFor(editorElement) { 11875 return new CommandDispatcher(editorElement) 11876 } 11877 11878 constructor(editorElement) { 11879 this.editorElement = editorElement; 11880 this.editor = editorElement.editor; 11881 this.selection = editorElement.selection; 11882 this.contents = editorElement.contents; 11883 11884 this.#registerCommands(); 11885 this.#registerKeyboardCommands(); 11886 this.#registerDragAndDropHandlers(); 11887 } 11888 11889 dispatchBold() { 11890 this.editor.dispatchCommand(xe, "bold"); 11891 } 11892 11893 dispatchItalic() { 11894 this.editor.dispatchCommand(xe, "italic"); 11895 } 11896 11897 dispatchStrikethrough() { 11898 this.editor.dispatchCommand(xe, "strikethrough"); 11899 } 11900 11901 dispatchUnderline() { 11902 this.editor.dispatchCommand(xe, "underline"); 11903 } 11904 11905 dispatchToggleHighlight(styles) { 11906 this.editor.dispatchCommand(TOGGLE_HIGHLIGHT_COMMAND, styles); 11907 } 11908 11909 dispatchRemoveHighlight() { 11910 this.editor.dispatchCommand(REMOVE_HIGHLIGHT_COMMAND); 11911 } 11912 11913 dispatchLink(url) { 11914 this.editor.update(() => { 11915 const selection = Qr(); 11916 if (!Fr(selection)) return 11917 11918 const anchorNode = selection.anchor.getNode(); 11919 11920 if (selection.isCollapsed() && !At$2(anchorNode, F$4)) { 11921 const autoLinkNode = H$5(url); 11922 const textNode = kr(url); 11923 autoLinkNode.append(textNode); 11924 selection.insertNodes([ autoLinkNode ]); 11925 } else { 11926 Q$6(url); 11927 } 11928 }); 11929 } 11930 11931 dispatchUnlink() { 11932 this.editor.update(() => { 11933 // Let adapters signal whether unlink should target a frozen link key. 11934 if (this.editorElement.adapter.unlinkFrozenNode?.()) { 11935 return 11936 } 11937 11938 Q$6(null); 11939 }); 11940 } 11941 11942 dispatchInsertUnorderedList() { 11943 const selection = Qr(); 11944 if (!Fr(selection)) return 11945 11946 const anchorNode = selection.anchor.getNode(); 11947 11948 if (this.selection.isInsideList && anchorNode && getListType(anchorNode) === "bullet") { 11949 this.contents.applyParagraphFormat(); 11950 } else { 11951 this.contents.applyUnorderedListFormat(); 11952 } 11953 } 11954 11955 dispatchInsertOrderedList() { 11956 const selection = Qr(); 11957 if (!Fr(selection)) return 11958 11959 const anchorNode = selection.anchor.getNode(); 11960 11961 if (this.selection.isInsideList && anchorNode && getListType(anchorNode) === "number") { 11962 this.contents.applyParagraphFormat(); 11963 } else { 11964 this.contents.applyOrderedListFormat(); 11965 } 11966 } 11967 11968 dispatchInsertQuoteBlock() { 11969 this.contents.toggleBlockquote(); 11970 } 11971 11972 dispatchInsertCodeBlock() { 11973 if (this.selection.hasSelectedWordsInSingleLine) { 11974 this.#toggleInlineCode(); 11975 } else { 11976 this.contents.toggleCodeBlock(); 11977 } 11978 } 11979 11980 #toggleInlineCode() { 11981 const selection = Qr(); 11982 if (!Fr(selection)) return 11983 11984 if (!selection.isCollapsed()) { 11985 const textNodes = selection.getNodes().filter(Tr); 11986 const applyingCode = !textNodes.every((node) => node.hasFormat("code")); 11987 11988 if (applyingCode) { 11989 this.#stripInlineFormattingFromSelection(selection, textNodes); 11990 } 11991 } 11992 11993 this.editor.dispatchCommand(xe, "code"); 11994 } 11995 11996 // Strip all inline formatting (bold, italic, etc.) from the selected text 11997 // nodes so that applying code produces a single merged <code> element instead 11998 // of one per differently-formatted span. 11999 #stripInlineFormattingFromSelection(selection, textNodes) { 12000 const isBackward = selection.isBackward(); 12001 const startPoint = isBackward ? selection.focus : selection.anchor; 12002 const endPoint = isBackward ? selection.anchor : selection.focus; 12003 12004 for (let i = 0; i < textNodes.length; i++) { 12005 const node = textNodes[i]; 12006 if (node.getFormat() === 0) continue 12007 12008 const isFirst = i === 0; 12009 const isLast = i === textNodes.length - 1; 12010 const startOffset = isFirst && startPoint.type === "text" ? startPoint.offset : 0; 12011 const endOffset = isLast && endPoint.type === "text" ? endPoint.offset : node.getTextContentSize(); 12012 12013 if (startOffset === 0 && endOffset === node.getTextContentSize()) { 12014 node.setFormat(0); 12015 } else { 12016 const splits = node.splitText(startOffset, endOffset); 12017 const target = startOffset === 0 ? splits[0] : splits[1]; 12018 target.setFormat(0); 12019 12020 if (isFirst && startPoint.type === "text") { 12021 startPoint.set(target.getKey(), 0, "text"); 12022 } 12023 if (isLast && endPoint.type === "text") { 12024 endPoint.set(target.getKey(), endOffset - startOffset, "text"); 12025 } 12026 } 12027 } 12028 } 12029 12030 dispatchSetCodeLanguage(language) { 12031 this.editor.update(() => { 12032 if (!this.selection.isInsideCodeBlock) return 12033 12034 const codeNode = this.selection.nearestNodeOfType(z$1); 12035 if (!codeNode) return 12036 12037 codeNode.setLanguage(language); 12038 }); 12039 } 12040 12041 dispatchInsertHorizontalDivider() { 12042 Pt$3(new HorizontalDividerNode); 12043 } 12044 12045 dispatchSetFormatHeadingLarge() { 12046 this.#applyConfiguredHeadingFormat(0); 12047 } 12048 12049 dispatchSetFormatHeadingMedium() { 12050 this.#applyConfiguredHeadingFormat(1); 12051 } 12052 12053 dispatchSetFormatHeadingSmall() { 12054 this.#applyConfiguredHeadingFormat(2); 12055 } 12056 12057 dispatchSetFormatParagraph() { 12058 this.contents.applyParagraphFormat(); 12059 } 12060 12061 dispatchApplyHeadingFormat(tag) { 12062 this.contents.applyHeadingFormat(tag); 12063 } 12064 12065 dispatchClearFormatting() { 12066 this.contents.clearFormatting(); 12067 } 12068 12069 dispatchUploadImage() { 12070 this.#dispatchUploadAttachment("image/*,video/*"); 12071 } 12072 12073 dispatchUploadFile() { 12074 this.#dispatchUploadAttachment(); 12075 } 12076 12077 #dispatchUploadAttachment(accept = null) { 12078 const attributes = { 12079 type: "file", 12080 multiple: true, 12081 style: "display: none;", 12082 onchange: ({ target: { files } }) => { 12083 this.contents.uploadFiles(files, { selectLast: true }); 12084 } 12085 }; 12086 12087 if (accept) attributes.accept = accept; 12088 12089 const input = createElement("input", attributes); 12090 12091 // Append and remove to make testable 12092 this.editorElement.appendChild(input); 12093 input.click(); 12094 setTimeout(() => input.remove(), 1000); 12095 } 12096 12097 dispatchInsertTable() { 12098 this.editor.dispatchCommand(ze$1, { "rows": 3, "columns": 3, "includeHeaders": true }); 12099 } 12100 12101 dispatchUndo() { 12102 this.editor.dispatchCommand(Ce$2, undefined); 12103 } 12104 12105 dispatchRedo() { 12106 this.editor.dispatchCommand(Se$2, undefined); 12107 } 12108 12109 dispose() { 12110 this.#listeners.dispose(); 12111 } 12112 12113 #applyConfiguredHeadingFormat(index) { 12114 const tag = this.editorElement.config.get("headings")[index]; 12115 if (tag) this.contents.applyHeadingFormat(tag); 12116 } 12117 12118 #registerCommands() { 12119 for (const command of COMMANDS) { 12120 const methodName = `dispatch${capitalize(command)}`; 12121 this.#registerCommandHandler(command, 0, this[methodName].bind(this)); 12122 } 12123 } 12124 12125 #registerCommandHandler(command, priority, handler) { 12126 this.#listeners.track(this.editor.registerCommand(command, handler, priority)); 12127 } 12128 12129 #registerKeyboardCommands() { 12130 this.#registerCommandHandler(ke$2, oo, this.#handleArrowRightKey.bind(this)); 12131 this.#registerCommandHandler(Fe$2, oo, this.#handleTabKey.bind(this)); 12132 12133 // Run before Lexical's built-in insert handlers to descend an element point on a 12134 // block container to a leaf, avoiding error #211 on Enter / Shift+Enter in a quote. 12135 this.#registerCommandHandler(de$4, so, this.#normalizeBlockContainerSelection.bind(this)); 12136 this.#registerCommandHandler(he$3, so, this.#normalizeBlockContainerSelection.bind(this)); 12137 } 12138 12139 #normalizeBlockContainerSelection() { 12140 $normalizeBlockContainerSelection(); 12141 return false 12142 } 12143 12144 #handleArrowRightKey(event) { 12145 const selection = Qr(); 12146 if (!Fr(selection) || !selection.isCollapsed()) return false 12147 if (this.selection.isInsideCodeBlock || !selection.hasFormat("code")) return false 12148 12149 const anchorNode = selection.anchor.getNode(); 12150 if (!Tr(anchorNode) || selection.anchor.offset !== anchorNode.getTextContentSize()) return false 12151 if (anchorNode.getNextSibling() !== null) return false 12152 12153 event.preventDefault(); 12154 selection.toggleFormat("code"); 12155 return true 12156 } 12157 12158 #registerDragAndDropHandlers() { 12159 if (this.editorElement.supportsAttachments) { 12160 this.dragCounter = 0; 12161 this.#listeners.track( 12162 this.editor.registerRootListener((rootElement) => { 12163 if (rootElement) { 12164 const teardowns = [ 12165 registerEventListener(rootElement, "dragover", this.#handleDragOver.bind(this)), 12166 registerEventListener(rootElement, "drop", this.#handleDrop.bind(this)), 12167 registerEventListener(rootElement, "dragenter", this.#handleDragEnter.bind(this)), 12168 registerEventListener(rootElement, "dragleave", this.#handleDragLeave.bind(this)) 12169 ]; 12170 return () => teardowns.forEach((teardown) => teardown()) 12171 } 12172 }) 12173 ); 12174 } 12175 } 12176 12177 #handleDragEnter(event) { 12178 if (this.#isInternalDrag(event)) return 12179 12180 this.dragCounter++; 12181 if (this.dragCounter === 1) { 12182 this.#saveSelectionBeforeDrag(); 12183 this.editor.getRootElement().classList.add("lexxy-editor--drag-over"); 12184 } 12185 } 12186 12187 #handleDragLeave(event) { 12188 if (this.#isInternalDrag(event)) return 12189 12190 this.dragCounter--; 12191 if (this.dragCounter === 0) { 12192 this.#selectionBeforeDrag = null; 12193 this.editor.getRootElement().classList.remove("lexxy-editor--drag-over"); 12194 } 12195 } 12196 12197 #handleDragOver(event) { 12198 if (this.#isInternalDrag(event)) return 12199 12200 event.preventDefault(); 12201 } 12202 12203 #handleDrop(event) { 12204 if (this.#isInternalDrag(event)) return 12205 12206 event.preventDefault(); 12207 12208 this.dragCounter = 0; 12209 this.editor.getRootElement().classList.remove("lexxy-editor--drag-over"); 12210 12211 const dataTransfer = event.dataTransfer; 12212 if (!dataTransfer) return 12213 12214 const files = Array.from(dataTransfer.files); 12215 if (!files.length) return 12216 12217 this.#restoreSelectionBeforeDrag(); 12218 this.contents.uploadFiles(files, { selectLast: true }); 12219 12220 this.editor.focus(); 12221 } 12222 12223 #saveSelectionBeforeDrag() { 12224 this.editor.getEditorState().read(() => { 12225 this.#selectionBeforeDrag = Qr()?.clone(); 12226 }); 12227 } 12228 12229 #restoreSelectionBeforeDrag() { 12230 if (!this.#selectionBeforeDrag) return 12231 12232 this.editor.update(() => { 12233 es(this.#selectionBeforeDrag); 12234 }); 12235 12236 this.#selectionBeforeDrag = null; 12237 } 12238 12239 #isInternalDrag(event) { 12240 return event.dataTransfer?.types.some((type) => type.startsWith("application/x-lexxy-")) 12241 } 12242 12243 #handleTabKey(event) { 12244 if (this.selection.isInsideList) { 12245 return this.#handleTabForList(event) 12246 } else if (this.selection.isInsideCodeBlock) { 12247 return this.#handleTabForCode() 12248 } 12249 return false 12250 } 12251 12252 #handleTabForList(event) { 12253 if (event.shiftKey && !this.selection.isIndentedList) return false 12254 12255 event.preventDefault(); 12256 const command = event.shiftKey? Ke$2 : Ie$3; 12257 return this.editor.dispatchCommand(command) 12258 } 12259 12260 #handleTabForCode() { 12261 const selection = Qr(); 12262 return Fr(selection) && selection.isCollapsed() 12263 } 12264 12265} 12266 12267function capitalize(str) { 12268 return str.charAt(0).toUpperCase() + str.slice(1) 12269} 12270 12271class Selection { 12272 #listeners = new ListenerBin() 12273 12274 constructor(editorElement) { 12275 this.editorElement = editorElement; 12276 this.editorContentElement = editorElement.editorContentElement; 12277 this.editor = this.editorElement.editor; 12278 this.previouslySelectedKeys = new Set(); 12279 12280 this.#listenForNodeSelections(); 12281 this.#processSelectionChangeCommands(); 12282 this.#containEditorFocus(); 12283 this.#clearStaleInlineCodeFormat(); 12284 } 12285 12286 get hasNodeSelection() { 12287 return this.editor.getEditorState().read(() => { 12288 const selection = Qr(); 12289 return selection !== null && Ir(selection) 12290 }) 12291 } 12292 12293 get cursorPosition() { 12294 let position = null; 12295 12296 this.editor.getEditorState().read(() => { 12297 const range = this.#getValidSelectionRange(); 12298 if (!range) return 12299 12300 const rect = this.#getReliableRectFromRange(range); 12301 if (this.#isRectUnreliable(rect)) return 12302 12303 position = this.#calculateCursorPosition(rect, range); 12304 }); 12305 12306 return position 12307 } 12308 12309 placeCursorAtTheEnd() { 12310 this.editor.update(() => { 12311 const root = Zo(); 12312 const lastDescendant = root.getLastDescendant(); 12313 12314 if (lastDescendant && Tr(lastDescendant)) { 12315 lastDescendant.selectEnd(); 12316 } else { 12317 root.selectEnd(); 12318 } 12319 }); 12320 } 12321 12322 selectedNodeWithOffset() { 12323 const selection = Qr(); 12324 if (!selection) return { node: null, offset: 0 } 12325 12326 if (Fr(selection)) { 12327 return { 12328 node: selection.anchor.getNode(), 12329 offset: selection.anchor.offset 12330 } 12331 } else if (Ir(selection)) { 12332 const [ node ] = selection.getNodes(); 12333 return { 12334 node, 12335 offset: 0 12336 } 12337 } 12338 12339 return { node: null, offset: 0 } 12340 } 12341 12342 getFormat() { 12343 const selection = Qr(); 12344 if (!Fr(selection)) return {} 12345 12346 const anchorNode = selection.anchor.getNode(); 12347 if (!anchorNode.getParent()) return {} 12348 12349 const topLevelElement = anchorNode.getTopLevelElementOrThrow(); 12350 const listType = getListType(anchorNode); 12351 const headingNode = this.#getNearestHeadingNode(anchorNode); 12352 12353 return { 12354 isBold: selection.hasFormat("bold"), 12355 isItalic: selection.hasFormat("italic"), 12356 isStrikethrough: selection.hasFormat("strikethrough"), 12357 isUnderline: selection.hasFormat("underline"), 12358 isHighlight: isSelectionHighlighted(selection), 12359 isInLink: At$2(anchorNode, F$4) !== null, 12360 isInQuote: Mt$2(topLevelElement), 12361 isInHeading: headingNode !== null, 12362 isInCode: this.#isInCode(selection, anchorNode), 12363 headingTag: headingNode?.getTag() ?? null, 12364 isInList: listType !== null, 12365 listType, 12366 isInTable: Ye(anchorNode) !== null 12367 } 12368 } 12369 12370 nearestNodeOfType(nodeType) { 12371 const anchorNode = Qr()?.anchor?.getNode(); 12372 return At$2(anchorNode, nodeType) 12373 } 12374 12375 get hasSelectedWordsInSingleLine() { 12376 const selection = Qr(); 12377 if (!Fr(selection)) return false 12378 12379 if (selection.isCollapsed()) return false 12380 12381 const anchorNode = selection.anchor.getNode(); 12382 const focusNode = selection.focus.getNode(); 12383 12384 if (anchorNode.getTopLevelElement() !== focusNode.getTopLevelElement()) { 12385 return false 12386 } 12387 12388 const anchorElement = anchorNode.getTopLevelElement(); 12389 if (!anchorElement) return false 12390 12391 // When anchor and focus are in different block-level children of the same 12392 // top-level element (e.g. two paragraphs inside a blockquote), this is a 12393 // multi-line selection, not a single-line one. 12394 const anchorBlock = Wi(anchorNode) ? anchorNode : anchorNode.getParent(); 12395 const focusBlock = Wi(focusNode) ? focusNode : focusNode.getParent(); 12396 if (anchorBlock !== focusBlock && anchorBlock !== anchorElement) { 12397 return false 12398 } 12399 12400 const nodes = selection.getNodes(); 12401 for (const node of nodes) { 12402 if (sr(node)) { 12403 return false 12404 } 12405 } 12406 12407 return true 12408 } 12409 12410 get isInsideList() { 12411 return this.nearestNodeOfType(ge$2) 12412 } 12413 12414 get isInsideBlockQuote() { 12415 return this.nearestNodeOfType(At$1) 12416 } 12417 12418 get isIndentedList() { 12419 const closestListNode = this.nearestNodeOfType(me$2); 12420 return closestListNode && (G$7(closestListNode) > 1) 12421 } 12422 12423 get isInsideCodeBlock() { 12424 return this.nearestNodeOfType(z$1) !== null 12425 } 12426 12427 get isTableCellSelected() { 12428 const selection = Qr(); 12429 const { anchor, focus } = selection; 12430 if (!Fr(selection) || anchor.key !== focus.key) return false 12431 12432 return this.nearestNodeOfType(Ee$1) !== null 12433 } 12434 12435 get isOnPreviewableImage() { 12436 return this.previewableImageNode != null 12437 } 12438 12439 get previewableImageNode() { 12440 const firstNode = Qr()?.getNodes().at(0); 12441 return $isActionTextAttachmentNode(firstNode) && firstNode.isPreviewableImage ? firstNode : null 12442 } 12443 12444 get isAtNodeStart() { 12445 const { anchorNode, offset } = this.#getCollapsedSelectionData(); 12446 return anchorNode && offset === 0 12447 } 12448 12449 get nodeAfterCursor() { 12450 const { anchorNode, offset } = this.#getCollapsedSelectionData(); 12451 if (!anchorNode) return null 12452 12453 if (Tr(anchorNode)) { 12454 return this.#getNodeAfterTextNode(anchorNode, offset) 12455 } 12456 12457 if (Wi(anchorNode)) { 12458 return this.#getNodeAfterElementNode(anchorNode, offset) 12459 } 12460 12461 return this.#findNextSiblingUp(anchorNode) 12462 } 12463 12464 get topLevelNodeAfterCursor() { 12465 const { anchorNode, offset } = this.#getCollapsedSelectionData(); 12466 if (!anchorNode) return null 12467 12468 if (Tr(anchorNode)) { 12469 if (offset === anchorNode.getTextContentSize()) return this.#getNextNodeFromTextEnd(anchorNode) 12470 if (this.#isCursorOnLastVisualLineOfBlock(anchorNode)) { 12471 const topLevelElement = anchorNode.getTopLevelElement(); 12472 return topLevelElement ? topLevelElement.getNextSibling() : null 12473 } 12474 return null 12475 } 12476 12477 if (Wi(anchorNode)) { 12478 return this.#getNodeAfterElementNode(anchorNode, offset) 12479 } 12480 12481 return this.#findNextSiblingUp(anchorNode) 12482 } 12483 12484 get nodeBeforeCursor() { 12485 const { anchorNode, offset } = this.#getCollapsedSelectionData(); 12486 if (!anchorNode) return null 12487 12488 if (Tr(anchorNode)) { 12489 return this.#getNodeBeforeTextNode(anchorNode, offset) 12490 } 12491 12492 if (Wi(anchorNode)) { 12493 return this.#getNodeBeforeElementNode(anchorNode, offset) 12494 } 12495 12496 return this.#findPreviousSiblingUp(anchorNode) 12497 } 12498 12499 get topLevelNodeBeforeCursor() { 12500 const { anchorNode, offset } = this.#getCollapsedSelectionData(); 12501 if (!anchorNode) return null 12502 12503 if (Tr(anchorNode)) { 12504 if (offset === 0) return this.#getPreviousNodeFromTextStart(anchorNode) 12505 if (this.#isCursorOnFirstVisualLineOfBlock(anchorNode)) { 12506 const topLevelElement = anchorNode.getTopLevelElement(); 12507 return topLevelElement ? topLevelElement.getPreviousSibling() : null 12508 } 12509 return null 12510 } 12511 12512 if (Wi(anchorNode)) { 12513 return this.#getNodeBeforeElementNode(anchorNode, offset) 12514 } 12515 12516 return this.#findPreviousSiblingUp(anchorNode) 12517 } 12518 12519 dispose() { 12520 this.editorElement = null; 12521 this.editorContentElement = null; 12522 this.editor = null; 12523 this.previouslySelectedKeys = null; 12524 12525 this.#listeners.dispose(); 12526 } 12527 12528 // When all inline code text is deleted, Lexical's selection retains the stale 12529 // code format flag. Verify the flag is backed by actual code-formatted content: 12530 // a code block ancestor or a text node that carries the code format. 12531 #isInCode(selection, anchorNode) { 12532 if (At$2(anchorNode, z$1) !== null) return true 12533 if (!selection.hasFormat("code")) return false 12534 12535 return Tr(anchorNode) && anchorNode.hasFormat("code") 12536 } 12537 12538 // After deleting all inline code text, Lexical preserves the code format on 12539 // the selection even though no code-formatted content remains. This listener 12540 // detects that stale state and clears it so newly typed text won't be 12541 // code-formatted. 12542 #clearStaleInlineCodeFormat() { 12543 this.#listeners.track(this.editor.registerUpdateListener(({ editorState, tags }) => { 12544 if (tags.has("history-merge") || tags.has("skip-dom-selection")) return 12545 12546 let isStale = false; 12547 12548 editorState.read(() => { 12549 const selection = Qr(); 12550 if (!Fr(selection) || !selection.isCollapsed()) return 12551 if (!selection.hasFormat("code")) return 12552 12553 const anchorNode = selection.anchor.getNode(); 12554 if (this.#isInCode(selection, anchorNode)) return 12555 12556 isStale = true; 12557 }); 12558 12559 if (isStale) { 12560 setTimeout(() => { 12561 this.editor.update(() => { 12562 const selection = Qr(); 12563 if (!Fr(selection) || !selection.hasFormat("code")) return 12564 12565 const anchorNode = selection.anchor.getNode(); 12566 if (this.#isInCode(selection, anchorNode)) return 12567 12568 selection.toggleFormat("code"); 12569 }); 12570 }, 0); 12571 } 12572 })); 12573 } 12574 12575 get #currentlySelectedKeys() { 12576 if (this.currentlySelectedKeys) { return this.currentlySelectedKeys } 12577 12578 this.currentlySelectedKeys = new Set(); 12579 12580 const selection = Qr(); 12581 if (selection && Ir(selection)) { 12582 for (const node of selection.getNodes()) { 12583 this.currentlySelectedKeys.add(node.getKey()); 12584 } 12585 } 12586 12587 return this.currentlySelectedKeys 12588 } 12589 12590 #processSelectionChangeCommands() { 12591 this.#listeners.track( 12592 this.editor.registerCommand(Ne$1, handlingDefault(this.#selectPreviousNode.bind(this)), io), 12593 this.editor.registerCommand(ke$2, handlingDefault(this.#selectNextNode.bind(this)), io), 12594 this.editor.registerCommand(we$1, handlingDefault(this.#selectPreviousTopLevelNode.bind(this)), io), 12595 this.editor.registerCommand(Ee$3, handlingDefault(this.#selectNextTopLevelNode.bind(this)), io), 12596 12597 this.editor.registerCommand(fe$4, this.#selectDecoratorNodeBeforeDeletion.bind(this), io), 12598 12599 this.editor.registerCommand(ie$4, () => { 12600 this.#syncSelectedClasses(); 12601 }, io), 12602 12603 this.editor.registerCommand(ie$4, () => { 12604 this.#preserveFocusOfOtherFields(); 12605 return false 12606 }, lo) 12607 ); 12608 } 12609 12610 // Firefox (152+) keeps window.getSelection() anchored inside the editor after focus 12611 // moves to another field, and fires document selectionchange for every keystroke 12612 // typed there. Lexical reads that stale selection, reconciles, and pulls focus back 12613 // into the editor â stealing it mid-typing. When another text-entry field owns focus, 12614 // tag the update so Lexical leaves the DOM selection (and with it, focus) alone. 12615 #preserveFocusOfOtherFields() { 12616 if (this.#anotherFieldIsFocused) { 12617 Os(qn); 12618 } 12619 } 12620 12621 get #anotherFieldIsFocused() { 12622 const rootElement = this.editor.getRootElement(); 12623 const activeElement = rootElement?.ownerDocument.activeElement; 12624 12625 return activeElement && !rootElement.contains(activeElement) && 12626 (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable) 12627 } 12628 12629 #listenForNodeSelections() { 12630 this.#listeners.track(this.editor.registerCommand(se$5, ({ target }) => { 12631 if (!qs(target)) return false 12632 12633 const targetNode = Go(target); 12634 return ji(targetNode) && this.#selectInLexical(targetNode) 12635 }, io)); 12636 12637 this.#listeners.track( 12638 this.editor.registerRootListener((rootElement) => { 12639 if (rootElement) { 12640 return registerEventListener(rootElement, "lexxy:internal:move-to-next-line", () => this.#selectOrAppendNextLine()) 12641 } 12642 }) 12643 ); 12644 } 12645 12646 #containEditorFocus() { 12647 // Workaround for a bizarre Chrome bug where the cursor abandons the editor to focus on not-focusable elements 12648 // above when navigating UP/DOWN when Lexical shows its fake cursor on custom decorator nodes. 12649 this.#listeners.track( 12650 this.editor.registerRootListener((rootElement) => { 12651 if (rootElement) { 12652 const handler = (event) => this.#handleArrowKeyOnLexicalCursor(event); 12653 rootElement.addEventListener("keydown", handler, true); 12654 return () => rootElement.removeEventListener("keydown", handler, true) 12655 } 12656 }) 12657 ); 12658 } 12659 12660 #handleArrowKeyOnLexicalCursor(event) { 12661 if (event.key === "ArrowUp") { 12662 const lexicalCursor = this.editor.getRootElement().querySelector("[data-lexical-cursor]"); 12663 12664 if (lexicalCursor) { 12665 let currentElement = lexicalCursor.previousElementSibling; 12666 while (currentElement && currentElement.hasAttribute("data-lexical-cursor")) { 12667 currentElement = currentElement.previousElementSibling; 12668 } 12669 12670 if (!currentElement) { 12671 event.preventDefault(); 12672 } 12673 } 12674 } 12675 12676 if (event.key === "ArrowDown") { 12677 const lexicalCursor = this.editor.getRootElement().querySelector("[data-lexical-cursor]"); 12678 12679 if (lexicalCursor) { 12680 let currentElement = lexicalCursor.nextElementSibling; 12681 while (currentElement && currentElement.hasAttribute("data-lexical-cursor")) { 12682 currentElement = currentElement.nextElementSibling; 12683 } 12684 12685 if (!currentElement) { 12686 event.preventDefault(); 12687 } 12688 } 12689 } 12690 } 12691 12692 #syncSelectedClasses() { 12693 this.#clearPreviouslyHighlightedItems(); 12694 this.#highlightNewItems(); 12695 12696 this.previouslySelectedKeys = this.#currentlySelectedKeys; 12697 this.currentlySelectedKeys = null; 12698 } 12699 12700 #clearPreviouslyHighlightedItems() { 12701 for (const key of this.previouslySelectedKeys) { 12702 if (!this.#currentlySelectedKeys.has(key)) { 12703 const dom = this.editor.getElementByKey(key); 12704 if (dom) dom.classList.remove("node--selected"); 12705 } 12706 } 12707 } 12708 12709 #highlightNewItems() { 12710 for (const key of this.#currentlySelectedKeys) { 12711 if (!this.previouslySelectedKeys.has(key)) { 12712 const nodeElement = this.editor.getElementByKey(key); 12713 if (nodeElement) nodeElement.classList.add("node--selected"); 12714 } 12715 } 12716 } 12717 12718 #selectPreviousNode(event) { 12719 if (event.shiftKey) { 12720 return this.#withCurrentNodeSelectionNode((currentNode) => { 12721 const selection = this.#rangeSelectDecorator(currentNode, "forward"); 12722 12723 // Can't rely on native pass-through with Playwright on firefox 12724 selection.modify("extend", true, "character"); 12725 return true 12726 }) 12727 } else { 12728 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.selectPrevious()) 12729 || this.#selectInLexical(this.nodeBeforeCursor) 12730 } 12731 } 12732 12733 #selectNextNode(event) { 12734 if (event.shiftKey) { 12735 return this.#withCurrentNodeSelectionNode((currentNode) => { 12736 const selection = this.#rangeSelectDecorator(currentNode, "forward"); 12737 12738 // Can't rely on native pass-through with Playwright on firefox 12739 selection.modify("extend", false, "character"); 12740 return true 12741 }) 12742 } else { 12743 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.selectNext(0, 0)) 12744 || this.#selectInLexical(this.nodeAfterCursor) 12745 } 12746 } 12747 12748 #selectPreviousTopLevelNode() { 12749 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.getTopLevelElement().selectPrevious()) 12750 || this.#selectInLexical(this.topLevelNodeBeforeCursor) 12751 } 12752 12753 #selectNextTopLevelNode() { 12754 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.getTopLevelElement().selectNext(0, 0)) 12755 || this.#selectInLexical(this.topLevelNodeAfterCursor) 12756 } 12757 12758 #withCurrentNodeSelectionNode(fn) { 12759 if (this.hasNodeSelection) { 12760 return fn(Qr().getNodes()[0]) 12761 } 12762 } 12763 12764 #rangeSelectDecorator(node, direction = "forward") { 12765 if (ji(node)) { 12766 const [ anchorOffset, focusOffset ] = direction === "forward" ? [ 0, 1 ] : [ 1, 0 ]; 12767 const indexAtNode = node.getIndexWithinParent(); 12768 12769 return node.getParent().select(indexAtNode + anchorOffset, indexAtNode + focusOffset) 12770 } 12771 } 12772 12773 async #selectOrAppendNextLine() { 12774 this.editor.update(() => { 12775 const topLevelElement = this.#getTopLevelElementFromSelection(); 12776 if (!topLevelElement) return 12777 12778 this.#moveToOrCreateNextLine(topLevelElement); 12779 }); 12780 } 12781 12782 #getTopLevelElementFromSelection() { 12783 const selection = Qr(); 12784 if (!selection) return null 12785 12786 if (Ir(selection)) { 12787 return this.#getTopLevelFromNodeSelection(selection) 12788 } 12789 12790 if (Fr(selection)) { 12791 return this.#getTopLevelFromRangeSelection(selection) 12792 } 12793 12794 return null 12795 } 12796 12797 #getTopLevelFromNodeSelection(selection) { 12798 const nodes = selection.getNodes(); 12799 return nodes.length > 0 ? nodes[0].getTopLevelElement() : null 12800 } 12801 12802 #getTopLevelFromRangeSelection(selection) { 12803 const anchorNode = selection.anchor.getNode(); 12804 return anchorNode.getTopLevelElement() 12805 } 12806 12807 #getNearestHeadingNode(anchorNode) { 12808 const topLevelElement = anchorNode.getTopLevelElementOrThrow(); 12809 12810 let headingNode = Lt$2(topLevelElement) ? topLevelElement : null; 12811 if (!headingNode) { 12812 let current = anchorNode.getParent(); 12813 while (current) { 12814 if (Lt$2(current)) { 12815 headingNode = current; 12816 break 12817 } 12818 current = current.getParent(); 12819 } 12820 } 12821 12822 return headingNode 12823 } 12824 12825 #moveToOrCreateNextLine(topLevelElement) { 12826 const nextSibling = topLevelElement.getNextSibling(); 12827 12828 if (nextSibling) { 12829 nextSibling.selectStart(); 12830 } else { 12831 this.#createAndSelectNewParagraph(); 12832 } 12833 } 12834 12835 #createAndSelectNewParagraph() { 12836 const root = Zo(); 12837 const newParagraph = eo(); 12838 root.append(newParagraph); 12839 newParagraph.selectStart(); 12840 } 12841 12842 #selectInLexical(node) { 12843 if (ji(node)) { 12844 Os(Jn); 12845 const selection = $createNodeSelectionWith(node); 12846 es(selection); 12847 return selection 12848 } else { 12849 return false 12850 } 12851 } 12852 12853 #selectDecoratorNodeBeforeDeletion(backwards) { 12854 if (backwards && this.#removeEmptyListItem()) return true 12855 12856 const node = backwards ? this.nodeBeforeCursor : this.nodeAfterCursor; 12857 if (!ji(node)) return false 12858 12859 if (this.#collapseListItemToParagraph(node)) return true 12860 12861 this.#removeEmptyElementAnchorNode(); 12862 12863 const selection = this.#selectInLexical(node); 12864 return Boolean(selection) 12865 } 12866 12867 // When backspace is pressed on an empty list item that has siblings, 12868 // handle the deletion appropriately: 12869 // 12870 // - Middle/end items (has previous sibling): remove the empty item and 12871 // place the cursor at the end of the previous sibling. Without this, 12872 // Lexical's default collapseAtStart converts the empty item into a 12873 // paragraph above the list, causing the cursor to jump away. 12874 // 12875 // - First item (no previous sibling): convert to a paragraph above the 12876 // list, matching the standard "unwrap list formatting" behavior that 12877 // users expect from pressing backspace at the start of a list item. 12878 // Inside a blockquote we instead just remove the empty item and move 12879 // the cursor into the next one â stranding a paragraph there would 12880 // leave the blank line the user is trying to close. 12881 // 12882 // When the empty item is the last/only one in the list, we return false 12883 // and let Lexical's default (convert to paragraph) provide the standard 12884 // "exit list" behavior. 12885 #removeEmptyListItem() { 12886 const selection = Qr(); 12887 if (!Fr(selection) || !selection.isCollapsed()) return false 12888 12889 const anchorNode = selection.anchor.getNode(); 12890 const listItem = At$2(anchorNode, ge$2); 12891 if (!listItem) return false 12892 12893 if (!$isListItemStructurallyEmpty(listItem)) return false 12894 12895 const nextSibling = listItem.getNextSibling(); 12896 if (!nextSibling) return false 12897 12898 const previousSibling = listItem.getPreviousSibling(); 12899 const listNode = At$2(listItem, me$2); 12900 if (!listNode) return false 12901 12902 if (previousSibling) { 12903 previousSibling.selectEnd(); 12904 listItem.remove(); 12905 } else if (Mt$2(listNode.getParent())) { 12906 nextSibling.selectStart(); 12907 listItem.remove(); 12908 } else { 12909 const paragraph = eo(); 12910 listNode.insertBefore(paragraph); 12911 listItem.remove(); 12912 paragraph.selectStart(); 12913 } 12914 12915 return true 12916 } 12917 12918 // When the cursor is inside a list item, collapse the list item into a 12919 // paragraph instead of selecting the decorator. This lets the user 12920 // delete a list that immediately follows an attachment without the 12921 // attachment becoming selected. Only applies when the decorator is 12922 // outside the list item (e.g. a block attachment before the list), 12923 // not when it's an inline mention inside the list item. 12924 #collapseListItemToParagraph(decoratorNode) { 12925 const anchorNode = Qr()?.anchor?.getNode(); 12926 const listItem = anchorNode && At$2(anchorNode, ge$2); 12927 if (!listItem) return false 12928 12929 if (listItem.isParentOf(decoratorNode)) return false 12930 12931 const listNode = At$2(listItem, me$2); 12932 if (!listNode) return false 12933 12934 const paragraph = eo(); 12935 const children = listItem.getChildren(); 12936 children.forEach(child => paragraph.append(child)); 12937 12938 if (listNode.getChildrenSize() === 1) { 12939 listNode.insertBefore(paragraph); 12940 listNode.remove(); 12941 } else { 12942 listNode.insertBefore(paragraph); 12943 listItem.remove(); 12944 } 12945 12946 paragraph.selectStart(); 12947 return true 12948 } 12949 12950 #removeEmptyElementAnchorNode(anchor = Qr()?.anchor) { 12951 const anchorNode = anchor?.getNode(); 12952 if (Wi(anchorNode) && anchorNode?.isEmpty()) anchorNode.remove(); 12953 } 12954 12955 #getValidSelectionRange() { 12956 const lexicalSelection = Qr(); 12957 if (!lexicalSelection || !lexicalSelection.isCollapsed()) return null 12958 12959 const nativeSelection = window.getSelection(); 12960 if (!nativeSelection || nativeSelection.rangeCount === 0) return null 12961 12962 return nativeSelection.getRangeAt(0) 12963 } 12964 12965 #getReliableRectFromRange(range) { 12966 let rect = range.getBoundingClientRect(); 12967 12968 if (this.#isRectUnreliable(rect)) { 12969 const marker = this.#createAndInsertMarker(range); 12970 rect = marker.getBoundingClientRect(); 12971 this.#restoreSelectionAfterMarker(marker); 12972 marker.remove(); 12973 } 12974 12975 return rect 12976 } 12977 12978 #isRectUnreliable(rect) { 12979 return rect.width === 0 && rect.height === 0 || rect.top === 0 && rect.left === 0 12980 } 12981 12982 #createAndInsertMarker(range) { 12983 const marker = this.#createMarker(); 12984 range.insertNode(marker); 12985 return marker 12986 } 12987 12988 #createMarker() { 12989 const marker = document.createElement("span"); 12990 marker.textContent = "\u200b"; 12991 marker.style.display = "inline-block"; 12992 marker.style.width = "1px"; 12993 marker.style.height = "1em"; 12994 marker.style.lineHeight = "normal"; 12995 marker.setAttribute("nonce", getNonce()); 12996 return marker 12997 } 12998 12999 #restoreSelectionAfterMarker(marker) { 13000 const nativeSelection = window.getSelection(); 13001 nativeSelection.removeAllRanges(); 13002 const newRange = document.createRange(); 13003 newRange.setStartAfter(marker); 13004 newRange.collapse(true); 13005 nativeSelection.addRange(newRange); 13006 } 13007 13008 #calculateCursorPosition(rect, range) { 13009 const rootRect = this.editor.getRootElement().getBoundingClientRect(); 13010 const x = rect.left - rootRect.left; 13011 let y = rect.top - rootRect.top; 13012 13013 const fontSize = this.#getFontSizeForCursor(range); 13014 if (!isNaN(fontSize)) { 13015 y += fontSize; 13016 } 13017 13018 return { x, y, fontSize } 13019 } 13020 13021 #getFontSizeForCursor(range) { 13022 const nativeSelection = window.getSelection(); 13023 const anchorNode = nativeSelection.anchorNode; 13024 const parentElement = this.#getElementFromNode(anchorNode); 13025 13026 if (parentElement instanceof HTMLElement) { 13027 const computed = window.getComputedStyle(parentElement); 13028 return parseFloat(computed.fontSize) 13029 } 13030 13031 return 0 13032 } 13033 13034 #getElementFromNode(node) { 13035 return node?.nodeType === Node.TEXT_NODE ? node.parentElement : node 13036 } 13037 13038 #getCollapsedSelectionData() { 13039 const selection = Qr(); 13040 if (!Fr(selection) || !selection.isCollapsed()) { 13041 return { anchorNode: null, offset: 0 } 13042 } 13043 13044 const { anchor } = selection; 13045 return { anchorNode: anchor.getNode(), offset: anchor.offset } 13046 } 13047 13048 #getNodeAfterTextNode(anchorNode, offset) { 13049 if (offset === anchorNode.getTextContentSize()) { 13050 return this.#getNextNodeFromTextEnd(anchorNode) 13051 } 13052 return null 13053 } 13054 13055 #getNextNodeFromTextEnd(anchorNode) { 13056 const nextSibling = anchorNode.getNextSibling(); 13057 if (ji(nextSibling)) { 13058 return nextSibling 13059 } 13060 if (nextSibling != null) { 13061 return null 13062 } 13063 const parent = anchorNode.getParent(); 13064 return parent ? parent.getNextSibling() : null 13065 } 13066 13067 #getNodeAfterElementNode(anchorNode, offset) { 13068 if (offset < anchorNode.getChildrenSize()) { 13069 return anchorNode.getChildAtIndex(offset) 13070 } 13071 return this.#findNextSiblingUp(anchorNode) 13072 } 13073 13074 #getNodeBeforeTextNode(anchorNode, offset) { 13075 if (offset === 0) { 13076 return this.#getPreviousNodeFromTextStart(anchorNode) 13077 } 13078 return null 13079 } 13080 13081 #getPreviousNodeFromTextStart(anchorNode) { 13082 const previousSibling = anchorNode.getPreviousSibling(); 13083 if (ji(previousSibling)) { 13084 return previousSibling 13085 } 13086 if (previousSibling != null) { 13087 return null 13088 } 13089 const parent = anchorNode.getParent(); 13090 return parent ? parent.getPreviousSibling() : null 13091 } 13092 13093 #getNodeBeforeElementNode(anchorNode, offset) { 13094 if (offset > 0) { 13095 return anchorNode.getChildAtIndex(offset - 1) 13096 } 13097 return this.#findPreviousSiblingUp(anchorNode) 13098 } 13099 13100 #findNextSiblingUp(node) { 13101 let current = node; 13102 while (current && current.getNextSibling() == null) { 13103 current = current.getParent(); 13104 } 13105 return current ? current.getNextSibling() : null 13106 } 13107 13108 #findPreviousSiblingUp(node) { 13109 let current = node; 13110 while (current && current.getPreviousSibling() == null) { 13111 current = current.getParent(); 13112 } 13113 return current ? current.getPreviousSibling() : null 13114 } 13115 13116 #isCursorOnFirstVisualLineOfBlock(anchorNode) { 13117 return this.#isCursorOnEdgeLineOfBlock(anchorNode, "first") 13118 } 13119 13120 #isCursorOnLastVisualLineOfBlock(anchorNode) { 13121 return this.#isCursorOnEdgeLineOfBlock(anchorNode, "last") 13122 } 13123 13124 // Check whether the cursor sits on the first or last visual line of its 13125 // top-level block by comparing the Y position of the cursor with the Y 13126 // position of the block's start (first line) or end (last line). 13127 #isCursorOnEdgeLineOfBlock(anchorNode, edge) { 13128 const topLevelElement = anchorNode.getTopLevelElement(); 13129 if (!topLevelElement) return false 13130 13131 const domElement = this.editor.getElementByKey(topLevelElement.getKey()); 13132 if (!domElement) return false 13133 13134 const nativeSelection = window.getSelection(); 13135 if (!nativeSelection?.rangeCount) return false 13136 13137 const cursorRect = this.#getReliableRectFromRange(nativeSelection.getRangeAt(0)); 13138 if (!cursorRect || this.#isRectUnreliable(cursorRect)) return false 13139 13140 const edgeRect = this.#getEdgeCharRect(domElement, edge); 13141 if (!edgeRect || this.#isRectUnreliable(edgeRect)) return false 13142 13143 const tolerance = edgeRect.height > 0 ? edgeRect.height * 0.5 : 5; 13144 return Math.abs(cursorRect.top - edgeRect.top) < tolerance 13145 } 13146 13147 // Get a reliable bounding rect for the first or last character in a DOM 13148 // element by creating a non-collapsed range around it. 13149 #getEdgeCharRect(element, edge) { 13150 const walker = document.createTreeWalker(element, 4 /* NodeFilter.SHOW_TEXT */); 13151 let textNode; 13152 13153 if (edge === "first") { 13154 textNode = walker.nextNode(); 13155 } else { 13156 while (walker.nextNode()) textNode = walker.currentNode; 13157 } 13158 13159 if (!textNode || textNode.length === 0) return null 13160 13161 const range = document.createRange(); 13162 if (edge === "first") { 13163 range.setStart(textNode, 0); 13164 range.setEnd(textNode, 1); 13165 } else { 13166 range.setStart(textNode, textNode.length - 1); 13167 range.setEnd(textNode, textNode.length); 13168 } 13169 13170 return range.getBoundingClientRect() 13171 } 13172} 13173 13174class EditorConfiguration { 13175 #editorElement 13176 #config 13177 13178 constructor(editorElement) { 13179 this.#editorElement = editorElement; 13180 this.#config = new Configuration( 13181 Lexxy.presets.get("default"), 13182 Lexxy.presets.get(editorElement.preset), 13183 this.#overrides 13184 ); 13185 } 13186 13187 get(path) { 13188 return this.#config.get(path) 13189 } 13190 13191 get #overrides() { 13192 const overrides = {}; 13193 for (const option of this.#defaultOptions) { 13194 const attribute = dasherize(option); 13195 if (this.#editorElement.hasAttribute(attribute)) { 13196 overrides[option] = this.#parseAttribute(attribute); 13197 } 13198 } 13199 return overrides 13200 } 13201 13202 get #defaultOptions() { 13203 return Object.keys(Lexxy.presets.get("default")) 13204 } 13205 13206 #parseAttribute(attribute) { 13207 const value = this.#editorElement.getAttribute(attribute); 13208 try { 13209 return JSON.parse(value) 13210 } catch { 13211 return value 13212 } 13213 } 13214} 13215 13216class ImageGalleryNode extends Bi { 13217 $config() { 13218 return this.config("image_gallery", { 13219 extends: Bi, 13220 }) 13221 } 13222 13223 static transform() { 13224 return (gallery) => { 13225 gallery.unwrapEmptyNode() 13226 || gallery.replaceWithSingularChild() 13227 || gallery.splitAroundInvalidChild(); 13228 } 13229 } 13230 13231 static importDOM() { 13232 return { 13233 div: (element) => { 13234 if (!this.#isGalleryElement(element)) return null 13235 13236 return { 13237 conversion: () => { 13238 return { 13239 node: $createImageGalleryNode() 13240 } 13241 }, 13242 priority: 2 13243 } 13244 } 13245 } 13246 } 13247 13248 static canCollapseWith(node) { 13249 return $isImageGalleryNode(node) || this.isValidChild(node) 13250 } 13251 13252 static isValidChild(node) { 13253 return $isActionTextAttachmentNode(node) && node.isPreviewableImage 13254 } 13255 13256 static #isGalleryElement(element) { 13257 const attachmentChildren = element.querySelectorAll(`:scope > :is(${this.#attachmentTags.join()})`); 13258 return element.textContent.trim() === "" 13259 && attachmentChildren.length > 0 13260 && element.children.length === attachmentChildren.length 13261 } 13262 13263 static get #attachmentTags() { 13264 return Object.keys(ActionTextAttachmentNode.importDOM()) 13265 } 13266 13267 createDOM() { 13268 const div = document.createElement("div"); 13269 div.className = this.#galleryClassNames; 13270 return div 13271 } 13272 13273 updateDOM(_prevNode, dom) { 13274 dom.className = this.#galleryClassNames; 13275 return false 13276 } 13277 13278 canBeEmpty() { 13279 // Return `true` to conform to `$isBlock(node)` 13280 // We clean-up empty galleries with a transform 13281 return true 13282 } 13283 13284 collapseAtStart(_selection) { 13285 return true 13286 } 13287 13288 insertNewAfter(selection, restoreSelection) { 13289 const selectionBeforeLastChild = selection.anchor.getNode().is(this) && selection.anchor.offset == this.getChildrenSize() - 1; 13290 if (selectionBeforeLastChild) { 13291 const paragraph = eo(); 13292 this.insertAfter(paragraph, false); 13293 paragraph.insertAfter(this.getLastChild(), false); 13294 paragraph.selectEnd(); 13295 13296 // return null as selection has been managed 13297 return null 13298 } 13299 13300 const newNode = $createImageGalleryNode(); 13301 this.insertAfter(newNode, restoreSelection); 13302 return newNode 13303 } 13304 13305 getImageAttachments() { 13306 const children = this.getChildren(); 13307 return children.filter($isActionTextAttachmentNode) 13308 } 13309 13310 exportDOM() { 13311 const div = document.createElement("div"); 13312 div.className = this.#galleryClassNames; 13313 return { element: div } 13314 } 13315 13316 collapseWith(node, backwards) { 13317 if (!ImageGalleryNode.canCollapseWith(node)) return false 13318 13319 if (backwards) { 13320 $t$2(this, node); 13321 } else { 13322 this.append(node); 13323 } 13324 13325 Ot$3(this, ImageGalleryNode.isValidChild); 13326 13327 return true 13328 } 13329 13330 unwrapEmptyNode() { 13331 if (this.isEmpty()) { 13332 const paragraph = eo(); 13333 return this.replace(paragraph) 13334 } 13335 } 13336 13337 replaceWithSingularChild() { 13338 if (this.#hasSingularChild) { 13339 const child = this.getFirstChild(); 13340 return this.replace($makeSafeForRoot(child)) 13341 } 13342 } 13343 13344 splitAroundInvalidChild() { 13345 for (const child of jt$2(this)) { 13346 if (ImageGalleryNode.isValidChild(child)) continue 13347 13348 const poppedNode = $makeSafeForRoot(child); 13349 const [ topGallery, secondGallery ] = this.splitAtIndex(poppedNode.getIndexWithinParent()); 13350 topGallery.insertAfter(poppedNode); 13351 poppedNode.selectEnd(); 13352 13353 // remove an empty gallery rather than let it unwrap to a paragraph 13354 if (secondGallery.isEmpty()) secondGallery.remove(); 13355 13356 break 13357 } 13358 } 13359 13360 splitAtIndex(index) { 13361 return Us(this, index) 13362 } 13363 13364 get #hasSingularChild() { 13365 return this.getChildrenSize() === 1 13366 } 13367 13368 get #galleryClassNames() { 13369 return `attachment-gallery attachment-gallery--${this.getChildrenSize()}` 13370 } 13371} 13372 13373function $createImageGalleryNode() { 13374 return new ImageGalleryNode() 13375} 13376 13377function $isImageGalleryNode(node) { 13378 return node instanceof ImageGalleryNode 13379} 13380 13381function $findOrCreateGalleryForImage(node) { 13382 if (!ImageGalleryNode.canCollapseWith(node)) return null 13383 13384 const existingGallery = At$2(node, ImageGalleryNode); 13385 return existingGallery ?? Tt$4(node, $createImageGalleryNode) 13386} 13387 13388class Uploader { 13389 #files 13390 13391 static for(editorElement, files, options = {}) { 13392 const UploaderKlass = GalleryUploader.handle(editorElement, files) ? GalleryUploader : Uploader; 13393 return new UploaderKlass(editorElement, files, options) 13394 } 13395 13396 constructor(editorElement, files, options = {}) { 13397 this.#files = files; 13398 this.options = options; 13399 13400 this.editorElement = editorElement; 13401 this.contents = editorElement.contents; 13402 this.selection = editorElement.selection; 13403 } 13404 13405 get files() { 13406 return Array.from(this.#files) 13407 } 13408 13409 $uploadFiles() { 13410 this.$createUploadNodes(); 13411 this.$insertUploadNodes(); 13412 } 13413 13414 $createUploadNodes() { 13415 this.nodes = this.files.map(file => this.#createUploadNode(file)); 13416 } 13417 13418 #createUploadNode(file) { 13419 return this.options.pending 13420 ? this.contents.$createPendingUploadNode(file) 13421 : this.contents.$createUploadNode(file) 13422 } 13423 13424 $insertUploadNodes() { 13425 this.contents.insertAtCursor(...this.nodes); 13426 } 13427} 13428 13429class GalleryUploader extends Uploader { 13430 #gallery 13431 13432 static handle(editorElement, files) { 13433 return this.isMultipleImageUpload(files) || this.gallerySelection(editorElement.selection) 13434 } 13435 13436 static isMultipleImageUpload(files) { 13437 let imageFileCount = 0; 13438 for (const file of files) { 13439 if (isPreviewableImage(file.type)) imageFileCount++; 13440 if (imageFileCount > 1) return true 13441 } 13442 return false 13443 } 13444 13445 static gallerySelection(selection) { 13446 return selection.isOnPreviewableImage || this.selectionIsAfterGalleryEdge(selection) 13447 } 13448 13449 static selectionIsAfterGalleryEdge(selection) { 13450 return selection.isAtNodeStart && ImageGalleryNode.canCollapseWith(selection.nodeBeforeCursor) 13451 } 13452 13453 $insertUploadNodes() { 13454 this.#findOrCreateGallery(); 13455 this.#insertImagesInGallery(); 13456 this.#insertNonImagesAfterGallery(); 13457 } 13458 13459 #findOrCreateGallery() { 13460 if (this.selection.isOnPreviewableImage) { 13461 // Resolve from the previewable image itself (the selection's first node), not from 13462 // #selectedNode (the anchor) â those differ when the selection runs from an image 13463 // into following text, and the anchor text node can't join a gallery (returns null). 13464 this.#gallery = $findOrCreateGalleryForImage(this.selection.previewableImageNode); 13465 } else if (this.#selectionIsAfterGalleryEdge) { 13466 this.#gallery = $findOrCreateGalleryForImage(this.selection.nodeBeforeCursor); 13467 } else { 13468 this.#gallery = $createImageGalleryNode(); 13469 this.contents.insertAtCursor(this.#gallery); 13470 } 13471 } 13472 13473 get #selectionIsAfterGalleryEdge() { 13474 return this.constructor.selectionIsAfterGalleryEdge(this.selection) 13475 } 13476 13477 get #selectedNode() { 13478 const { node } = this.selection.selectedNodeWithOffset(); 13479 return node 13480 } 13481 13482 get #galleryInsertPosition() { 13483 if (this.#selectionIsAfterGalleryEdge) return this.#gallery.getChildrenSize() 13484 13485 const anchor = Qr()?.anchor; 13486 const galleryHasElementSelection = anchor?.getNode().is(this.#gallery); 13487 if (galleryHasElementSelection) return anchor.offset 13488 13489 const selectedNode = this.#selectedNode; 13490 const childIndex = this.#gallery.isParentOf(selectedNode) && selectedNode.getIndexWithinParent(); 13491 return childIndex !== false ? (childIndex + 1) : 0 13492 } 13493 13494 get #imageNodes() { 13495 return this.nodes.filter(node => ImageGalleryNode.isValidChild(node)) 13496 } 13497 13498 get #nonImageNodes() { 13499 return this.nodes.filter(node => !ImageGalleryNode.isValidChild(node)) 13500 } 13501 13502 #insertImagesInGallery() { 13503 this.#gallery.splice(this.#galleryInsertPosition, 0, this.#imageNodes); 13504 } 13505 13506 #insertNonImagesAfterGallery() { 13507 let beforeNode = this.#gallery; 13508 13509 for (const node of this.#nonImageNodes) { 13510 beforeNode.insertAfter(node); 13511 beforeNode = node; 13512 } 13513 } 13514} 13515 13516async function loadFileIntoImage(file, image) { 13517 return new Promise((resolve) => { 13518 const reader = new FileReader(); 13519 13520 image.addEventListener("load", () => { 13521 resolve(image); 13522 }); 13523 13524 reader.onload = (event) => { 13525 image.src = event.target.result || null; 13526 }; 13527 13528 reader.readAsDataURL(file); 13529 }) 13530} 13531 13532class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode { 13533 static getType() { 13534 return "action_text_attachment_upload" 13535 } 13536 13537 static clone(node) { 13538 return new ActionTextAttachmentUploadNode({ ...node }, node.__key) 13539 } 13540 13541 static importJSON(serializedNode) { 13542 return new ActionTextAttachmentUploadNode({ ...serializedNode }) 13543 } 13544 13545 // Should never run since this is a transient node. Defined to remove console warning. 13546 static importDOM() { 13547 return null 13548 } 13549 13550 constructor(node = {}, key) { 13551 const { file, uploadUrl, blobUrlTemplate, progress, width, height, uploadError, fileName, contentType } = node; 13552 super({ ...node, contentType: file?.type ?? contentType }, key); 13553 this.file = file ?? null; 13554 this.fileName = file?.name ?? fileName; 13555 this.uploadUrl = uploadUrl; 13556 this.blobUrlTemplate = blobUrlTemplate; 13557 this.progress = progress ?? null; 13558 this.width = width; 13559 this.height = height; 13560 this.uploadError = uploadError; 13561 } 13562 13563 createDOM() { 13564 if (this.uploadError) return this.createDOMForError() 13565 13566 // This side-effect is trigged on DOM load to fire only once and avoid multiple 13567 // uploads through cloning. The upload is guarded from restarting in case the 13568 // node is reloaded from saved state such as from history. 13569 this.#startUploadIfNeeded(); 13570 13571 // Bridge-managed uploads (uploadUrl is null) and restored or remote 13572 // instances (no local File) don't have file data to show an image 13573 // preview, so always show the file icon during upload. 13574 const canPreviewFile = this.isPreviewableAttachment && this.uploadUrl != null && this.file != null; 13575 const figure = this.createAttachmentFigure(canPreviewFile); 13576 13577 if (canPreviewFile) { 13578 const img = figure.appendChild(this.#createDOMForImage()); 13579 13580 // load file locally to set dimensions and prevent vertical shifting 13581 loadFileIntoImage(this.file, img).then(img => this.#setDimensionsFromImage(img)); 13582 } else { 13583 figure.appendChild(this.#createDOMForFile()); 13584 } 13585 13586 figure.appendChild(this.#createCaption()); 13587 figure.appendChild(this.#createProgressBar()); 13588 13589 return figure 13590 } 13591 13592 updateDOM(prevNode, dom) { 13593 if (this.uploadError !== prevNode.uploadError) return true 13594 13595 if (prevNode.progress !== this.progress) { 13596 const progress = dom.querySelector("progress"); 13597 progress.value = this.progress ?? 0; 13598 } 13599 13600 return false 13601 } 13602 13603 exportDOM() { 13604 return { element: null } 13605 } 13606 13607 exportJSON() { 13608 return { 13609 ...super.exportJSON(), 13610 type: "action_text_attachment_upload", 13611 version: 1, 13612 fileName: this.fileName, 13613 contentType: this.contentType, 13614 uploadUrl: this.uploadUrl, 13615 blobUrlTemplate: this.blobUrlTemplate, 13616 progress: this.progress, 13617 width: this.width, 13618 height: this.height, 13619 uploadError: this.uploadError 13620 } 13621 } 13622 13623 get #uploadStarted() { 13624 return this.progress !== null 13625 } 13626 13627 #createDOMForImage() { 13628 return createElement("img") 13629 } 13630 13631 #createDOMForFile() { 13632 const extension = this.#getFileExtension(); 13633 const span = createElement("span", { className: "attachment__icon", textContent: extension }); 13634 return span 13635 } 13636 13637 #getFileExtension() { 13638 return (this.fileName || "").split(".").pop().toLowerCase() 13639 } 13640 13641 #createCaption() { 13642 const figcaption = createElement("figcaption", { className: "attachment__caption" }); 13643 13644 const nameSpan = createElement("span", { className: "attachment__name", textContent: this.caption || this.fileName || "" }); 13645 figcaption.appendChild(nameSpan); 13646 13647 if (this.file) { 13648 const sizeSpan = createElement("span", { className: "attachment__size", textContent: bytesToHumanSize(this.file.size) }); 13649 figcaption.appendChild(sizeSpan); 13650 } 13651 13652 return figcaption 13653 } 13654 13655 #createProgressBar() { 13656 return createElement("progress", { value: this.progress ?? 0, max: 100 }) 13657 } 13658 13659 #setDimensionsFromImage({ width, height }) { 13660 if (this.#hasDimensions) return 13661 13662 this.patchAndRewriteHistory({ width, height }); 13663 } 13664 13665 get #hasDimensions() { 13666 return Boolean(this.width && this.height) 13667 } 13668 13669 async #startUploadIfNeeded() { 13670 if (this.#uploadStarted) return 13671 if (!this.uploadUrl) return // Bridge-managed upload â skip DirectUpload 13672 if (!this.file) return // Restored or remote instance â no local File to upload 13673 13674 this.#setUploadStarted(); 13675 13676 const { DirectUpload } = await import('@rails/activestorage'); 13677 13678 const upload = new DirectUpload(this.file, this.uploadUrl, this); 13679 upload.delegate = this.#createUploadDelegate(); 13680 13681 this.#dispatchEvent("lexxy:upload-start", { file: this.file }); 13682 13683 upload.create((error, blob) => { 13684 this.#forgetUploadRequest(); 13685 13686 if (error) { 13687 this.#dispatchEvent("lexxy:upload-end", { file: this.file, error }); 13688 this.#handleUploadError(error); 13689 } else { 13690 this.#dispatchEvent("lexxy:upload-end", { file: this.file, error: null }); 13691 this.editor.update(() => { 13692 this.$showUploadedAttachment(blob); 13693 }); 13694 } 13695 }); 13696 } 13697 13698 #createUploadDelegate() { 13699 const shouldAuthenticateUploads = Lexxy.global.get("authenticatedUploads"); 13700 13701 return { 13702 directUploadWillCreateBlobWithXHR: (request) => { 13703 if (shouldAuthenticateUploads) request.withCredentials = true; 13704 }, 13705 directUploadWillStoreFileWithXHR: (request) => { 13706 if (shouldAuthenticateUploads) request.withCredentials = true; 13707 13708 this.#rememberUploadRequest(request); 13709 13710 const uploadProgressHandler = (event) => this.#handleUploadProgress(event, request); 13711 request.upload.addEventListener("progress", uploadProgressHandler); 13712 } 13713 } 13714 } 13715 13716 #forgetUploadRequest() { 13717 this.#editorElement?.uploadRequests.forget(this.getKey()); 13718 } 13719 13720 #rememberUploadRequest(request) { 13721 this.#editorElement?.uploadRequests.track(this.getKey(), request); 13722 } 13723 13724 get #editorElement() { 13725 return this.editor.getRootElement()?.closest("lexxy-editor") 13726 } 13727 13728 #setUploadStarted() { 13729 this.#setProgress(1); 13730 } 13731 13732 #handleUploadProgress(event, request) { 13733 const progress = Math.round(event.loaded / event.total * 100); 13734 try { 13735 this.#setProgress(progress); 13736 this.#dispatchEvent("lexxy:upload-progress", { file: this.file, progress }); 13737 } catch { 13738 request.abort(); 13739 } 13740 } 13741 13742 #setProgress(progress) { 13743 this.patchAndRewriteHistory({ progress }); 13744 } 13745 13746 #handleUploadError(error) { 13747 console.warn(`Upload error for ${this.file?.name ?? "file"}: ${error}`); 13748 13749 this.patchAndRewriteHistory({ uploadError: true }); 13750 } 13751 13752 $showUploadedAttachment(blob) { 13753 const previewSrc = this.isPreviewableImage && this.file ? URL.createObjectURL(this.file) : null; 13754 13755 const replacementNode = this.#toActionTextAttachmentNodeWith(blob, previewSrc); 13756 this.replaceAndRewriteHistory(replacementNode); 13757 13758 return replacementNode.getKey() 13759 } 13760 13761 #toActionTextAttachmentNodeWith(blob, previewSrc) { 13762 const conversion = new AttachmentNodeConversion(this, blob, previewSrc); 13763 return conversion.toAttachmentNode() 13764 } 13765 13766 #dispatchEvent(name, detail) { 13767 const figure = this.editor.getElementByKey(this.getKey()); 13768 if (figure) dispatch(figure, name, detail); 13769 } 13770} 13771 13772class AttachmentNodeConversion { 13773 constructor(uploadNode, blob, previewSrc) { 13774 this.uploadNode = uploadNode; 13775 this.blob = blob; 13776 this.previewSrc = previewSrc; 13777 } 13778 13779 toAttachmentNode() { 13780 return new ActionTextAttachmentNode({ 13781 ...this.uploadNode, 13782 ...this.#propertiesFromBlob, 13783 src: this.#src, 13784 previewSrc: this.previewSrc, 13785 pendingPreview: this.blob.previewable && !this.uploadNode.isPreviewableImage 13786 }) 13787 } 13788 13789 get #propertiesFromBlob() { 13790 const { blob } = this; 13791 return { 13792 sgid: blob.attachable_sgid, 13793 altText: blob.filename, 13794 contentType: blob.content_type, 13795 fileName: blob.filename, 13796 fileSize: blob.byte_size, 13797 previewable: blob.previewable, 13798 previewStatusUrl: blob.preview_status_url 13799 } 13800 } 13801 13802 get #src() { 13803 return this.blob.previewable ? this.blob.url : this.#blobSrc 13804 } 13805 13806 get #blobSrc() { 13807 return this.uploadNode.blobUrlTemplate 13808 .replace(":signed_id", this.blob.signed_id) 13809 .replace(":filename", encodeURIComponent(this.blob.filename)) 13810 } 13811} 13812 13813function $createActionTextAttachmentUploadNode(...args) { 13814 return new ActionTextAttachmentUploadNode(...args) 13815} 13816 13817class BaseNodeInserter { 13818 constructor(selection) { 13819 this.selection = selection; 13820 } 13821} 13822 13823class CodeNodeInserter extends BaseNodeInserter { 13824 static handles(selection) { 13825 return At$2(selection.anchor?.getNode(), z$1) 13826 } 13827 13828 insertNodes(nodes) { 13829 if (!this.selection.isCollapsed()) { this.selection.removeText(); } 13830 13831 j$6(this.selection); 13832 const focusNode = this.selection.focus.getNode(); 13833 const codeNode = At$2(focusNode, z$1); 13834 const insertionIndex = focusNode.is(codeNode) ? 0 : focusNode.getIndexWithinParent(); 13835 13836 const caret = lc(codeNode, insertionIndex + 1, "previous"); 13837 13838 // Nodes that are already in the document come from the format-toggle path (existing 13839 // content converted into this code block). Brand-new nodes (dropped/pasted content) 13840 // were never attached. 13841 const existingNodes = new Set(nodes.filter(node => node.isAttached())); 13842 const trailingNodes = []; 13843 13844 for (const node of nodes) { 13845 if (existingNodes.has(node)) { 13846 if (!node.isAttached()) continue // already pulled in when a converted ancestor was removed 13847 } else if (!this.#canJoinCodeBlock(node)) { 13848 trailingNodes.push(node); // e.g. a dropped attachment, which a code block can't hold 13849 continue 13850 } 13851 13852 if (caret.getNodeAtCaret() && Wi(node)) { caret.insert(or()); } 13853 caret.insert(this.#convertNodeToCodeChild(node)); 13854 } 13855 13856 const lastTrailingNode = this.#insertAfterCodeBlock(codeNode, trailingNodes); 13857 const nodeToSelect = lastTrailingNode ?? caret.getNodeAtCaret(); 13858 nodeToSelect?.selectEnd(); 13859 } 13860 13861 #canJoinCodeBlock(node) { 13862 return Tr(node) || sr(node) 13863 } 13864 13865 #insertAfterCodeBlock(codeNode, nodes) { 13866 let previousNode = codeNode; 13867 for (const node of nodes) { 13868 previousNode.insertAfter(node); 13869 previousNode = node; 13870 } 13871 return nodes.at(-1) 13872 } 13873 13874 #convertNodeToCodeChild(node) { 13875 if (sr(node)) { 13876 return node 13877 } else { 13878 node.remove(); 13879 return kr(node.getTextContent()) 13880 } 13881 } 13882} 13883 13884class ShadowRootNodeInserter extends BaseNodeInserter { 13885 static handles(selection) { 13886 return $isShadowRoot(selection?.anchor?.getNode()) 13887 } 13888 13889 insertNodes(nodes) { 13890 const anchorNode = this.selection.anchor.getNode(); 13891 const paragraph = eo(); 13892 anchorNode.append(paragraph); 13893 13894 paragraph.selectStart().insertNodes(nodes); 13895 } 13896} 13897 13898class NodeSelectionNodeInserter extends BaseNodeInserter { 13899 static handles(selection) { 13900 return Ir(selection) && selection.getNodes().length > 0 13901 } 13902 13903 insertNodes(nodes) { 13904 // Overrides Lexical's default behavior of _removing_ the currently selected nodes 13905 // https://github.com/facebook/lexical/blob/v0.38.2/packages/lexical/src/LexicalSelection.ts#L412 13906 let lastNode = this.selection.getNodes().at(-1); 13907 13908 for (const node of nodes) { 13909 // Inserting after a top-level node would make this one a root child. Inline nodes 13910 // can't live there (Lexical error #99), so wrap them in their required parent first. 13911 const nodeToInsert = this.#insertsIntoRoot(lastNode) ? $makeSafeForRoot(node) : node; 13912 lastNode = lastNode.insertAfter(nodeToInsert); 13913 } 13914 } 13915 13916 #insertsIntoRoot(node) { 13917 return node.is(node.getTopLevelElement()) 13918 } 13919} 13920 13921// A list item can only hold inline content, so a block node (such as an image 13922// attachment) dropped into one corrupts the list: Lexical lifts it into the 13923// wrong list item and orphans an empty bullet. Block nodes belong at the top 13924// level instead, splitting the list around the cursor. Inline content keeps 13925// Lexical's default behavior and stays within the list item. 13926class ListItemNodeInserter extends BaseNodeInserter { 13927 static handles(selection) { 13928 return Fr(selection) && 13929 At$2(selection.anchor.getNode(), ge$2) 13930 } 13931 13932 insertNodes(nodes) { 13933 if (nodes.some(node => this.#isBlockDecorator(node))) { 13934 this.#insertAroundList(nodes); 13935 } else { 13936 this.selection.insertNodes(nodes); 13937 } 13938 } 13939 13940 #insertAroundList(nodes) { 13941 if (!this.selection.isCollapsed()) { this.selection.removeText(); } 13942 13943 // Break out of any nesting to the outermost list. Splitting an inner list 13944 // would leave the block stranded inside an ancestor list item, which is the 13945 // very corruption we are avoiding. The block must land at the list's level. 13946 const anchorNode = this.selection.anchor.getNode(); 13947 const outerList = this.#outermostList(anchorNode); 13948 const topItem = this.#topLevelItemFor(anchorNode, outerList); 13949 13950 // A blank top-level bullet is just the insertion point (e.g. the user pressed 13951 // Enter to leave the list); break out of it entirely. A bullet with content â 13952 // including one wrapping a nested list â splits so its content stays in the list. 13953 const splitAfterItem = $isBlankNode(topItem) ? topItem.getPreviousSibling() : topItem; 13954 const splitIndex = splitAfterItem ? splitAfterItem.getIndexWithinParent() + 1 : 0; 13955 const [ listBefore, listAfter ] = Us(outerList, splitIndex); 13956 if ($isBlankNode(topItem)) { topItem.remove(); } 13957 13958 let anchor = listBefore ?? listAfter; 13959 for (const node of nodes) { 13960 anchor.insertAfter(node); 13961 anchor = node; 13962 } 13963 13964 this.#removeEmptyList(listBefore); 13965 this.#removeEmptyList(listAfter); 13966 nodes.at(-1).selectNext(); 13967 } 13968 13969 #outermostList(node) { 13970 return [ node, ...node.getParents() ].reverse().find(Se$1) 13971 } 13972 13973 #topLevelItemFor(node, outerList) { 13974 return [ node, ...node.getParents() ].find(ancestor => 13975 pe$2(ancestor) && ancestor.getParent()?.is(outerList) 13976 ) 13977 } 13978 13979 #removeEmptyList(list) { 13980 if (Se$1(list) && list.isEmpty()) list.remove(); 13981 } 13982 13983 // Only block decorator nodes (image/file attachments) are intercepted. A list 13984 // item cannot hold them, so they must break out. Pasted element blocks 13985 // (paragraphs, quotes) keep Lexical's own list-escape semantics. 13986 #isBlockDecorator(node) { 13987 return ji(node) && !node.isInline() 13988 } 13989} 13990 13991// Lexical's RangeSelection.insertNodes requires every selection point to have a block 13992// ancestor with inline children. An element point on a container of block nodes â e.g. 13993// a quote holding paragraphs â has none, so Lexical throws invariant #211 or #212. 13994// Descend such points to a leaf position before inserting. 13995class BlockContainerNodeInserter extends BaseNodeInserter { 13996 static handles(selection) { 13997 return $hasPointOnBlockContainer(selection) 13998 } 13999
14000 insertNodes(nodes) { 14001 St$3
vendor: 13,995 bytes, lines 14001-14413
14001(this.selection); 14002 this.selection.insertNodes(nodes); 14003 } 14004} 14005 14006const INSERTERS = [ 14007 CodeNodeInserter, 14008 ShadowRootNodeInserter, 14009 NodeSelectionNodeInserter, 14010 ListItemNodeInserter, 14011 BlockContainerNodeInserter 14012]; 14013 14014// Defined here rather than on the base class so the base can stay free of any 14015// dependency on its subclasses (they import the base), avoiding an import cycle. 14016BaseNodeInserter.for = (selection) => { 14017 const inserterClass = INSERTERS.find(inserter => inserter.handles(selection)); 14018 return inserterClass ? new inserterClass(selection) : selection 14019}; 14020 14021// Word and Outlook never emit <ul>/<ol>/<li>. They simulate lists with flat 14022// paragraphs that declare their depth in an inline `mso-list:l0 level2 lfo1` 14023// and carry the bullet or number glyph in a <span style="mso-list:Ignore">. 14024// Nothing downstream understands either, so the items land as plain paragraphs 14025// with the marker baked into the text. Rebuild real lists from the level each 14026// paragraph declares. 14027// 14028// Everything this reads lives in inline attributes, so it stays correct after 14029// the pasted content formatter has dropped Office's style sheet. 14030class OfficeFormatter { 14031 constructor(doc) { 14032 this.doc = doc; 14033 } 14034 14035 format() { 14036 for (const run of this.#listRuns()) { 14037 this.#replaceWithLists(run); 14038 } 14039 } 14040 14041 // A run is a stretch of Office list paragraphs that are siblings with nothing 14042 // but whitespace and Word's conditional comments between them. Anything else 14043 // in between (a heading, a plain paragraph) ends one list and starts another. 14044 #listRuns() { 14045 const runs = []; 14046 const claimed = new Set(); 14047 14048 for (const paragraph of this.doc.querySelectorAll("p[style*='mso-list']")) { 14049 if (claimed.has(paragraph) || this.#listLevel(paragraph) === null) continue 14050 14051 const run = []; 14052 let node = paragraph; 14053 while (node) { 14054 run.push(node); 14055 claimed.add(node); 14056 node = this.#nextListParagraph(node); 14057 } 14058 runs.push(run); 14059 } 14060 14061 return runs 14062 } 14063 14064 #nextListParagraph(paragraph) { 14065 let sibling = paragraph.nextSibling; 14066 while (sibling && this.#isIgnorableBetweenListParagraphs(sibling)) { 14067 sibling = sibling.nextSibling; 14068 } 14069 14070 if (sibling && sibling.nodeType === Node.ELEMENT_NODE && this.#listLevel(sibling) !== null) { 14071 return sibling 14072 } 14073 14074 return null 14075 } 14076 14077 #isIgnorableBetweenListParagraphs(node) { 14078 if (node.nodeType === Node.COMMENT_NODE) { 14079 return true 14080 } 14081 return node.nodeType === Node.TEXT_NODE && node.textContent.trim() === "" 14082 } 14083 14084 // Word numbers levels from 1, but a copied selection often starts partway down 14085 // a list, so every paragraph declares level3 with no level1 above it. Anchoring 14086 // the run at its own shallowest level is what keeps the result from arriving 14087 // needlessly deep. 14088 #replaceWithLists(paragraphs) { 14089 const levels = paragraphs.map((paragraph) => this.#listLevel(paragraph)); 14090 const baseLevel = Math.min(...levels); 14091 const roots = []; 14092 const stack = []; 14093 14094 paragraphs.forEach((paragraph, index) => { 14095 const depth = levels[index] - baseLevel + 1; 14096 const tagName = this.#listTagName(paragraph); 14097 14098 while (stack.length > depth) { 14099 stack.pop(); 14100 } 14101 if (stack.length === depth && stack[depth - 1].tagName !== tagName.toUpperCase()) { 14102 stack.pop(); 14103 } 14104 14105 while (stack.length < depth) { 14106 const list = this.doc.createElement(tagName); 14107 if (stack.length === 0) { 14108 roots.push(list); 14109 } else { 14110 this.#lastItemOf(stack[stack.length - 1]).appendChild(list); 14111 } 14112 stack.push(list); 14113 } 14114 14115 stack[stack.length - 1].appendChild(this.#createListItem(paragraph)); 14116 }); 14117 14118 paragraphs[0].replaceWith(...roots); 14119 for (const paragraph of paragraphs.slice(1)) { 14120 paragraph.remove(); 14121 } 14122 } 14123 14124 #lastItemOf(list) { 14125 if (!list.lastElementChild) { 14126 list.appendChild(this.doc.createElement("li")); 14127 } 14128 return list.lastElementChild 14129 } 14130 14131 // Word writes bullets as the raw glyph of the marker font (Symbol's "·", 14132 // Wingdings' "§", Courier New's "o") and numbers as the rendered counter 14133 // ("1.", "a)", "iv)"). A bare letter with no delimiter after it is Courier 14134 // New's bullet, not a counter, so the delimiter is what tells them apart. 14135 #listTagName(paragraph) { 14136 const marker = paragraph.querySelector("[style*='mso-list:Ignore']"); 14137 const text = marker?.textContent || ""; 14138 14139 if (/\d/.test(text) || /^\(?[A-Za-z]+[.)]/.test(text)) { 14140 return "ol" 14141 } 14142 return "ul" 14143 } 14144 14145 #createListItem(paragraph) { 14146 for (const marker of paragraph.querySelectorAll("[style*='mso-list:Ignore']")) { 14147 marker.remove(); 14148 } 14149 14150 const item = this.doc.createElement("li"); 14151 item.append(...paragraph.childNodes); 14152 return item 14153 } 14154 14155 #listLevel(element) { 14156 const match = /mso-list:[^;"']*\blevel(\d+)/.exec(element.getAttribute("style") || ""); 14157 if (match) { 14158 return parseInt(match[1], 10) 14159 } 14160 return null 14161 } 14162} 14163 14164// Properties worth rescuing from a foreign style sheet before #stripStyleElements 14165// drops it, keyed by the elements that carry them. Word and Outlook declare 14166// paragraph spacing in the sheet (p.MsoNormal { margin: 0cm }) and never inline, 14167// so once the sheet goes there is nothing left to say how tightly the author's 14168// paragraphs sat, and hosts that turn pasted paragraph margins into explicit 14169// blank lines read tight Office paragraphs as spaced ones and multiply every 14170// line break. 14171const PRESERVABLE_STYLES = { 14172 p: [ "margin-top", "margin-bottom" ] 14173}; 14174 14175class PastedContentFormatter { 14176 constructor(doc) { 14177 this.doc = doc; 14178 } 14179 14180 format() { 14181 this.#inlinePreservableStyles(); 14182 this.#stripStyleElements(); 14183 this.#unwrapPlaceholderAnchors(); 14184 this.#stripTableCellColorStyles(); 14185 new OfficeFormatter(this.doc).format(); 14186 this.#unwrapWrappedListChildren(); 14187 this.#nestStrayListChildren(); 14188 this.#stripStrayListChildren(); 14189 this.#replaceGmailEmojiImgTags(); 14190 return this.doc 14191 } 14192 14193 // Runs before #stripStyleElements, to inline anything we still need 14194 // from an external style before we remove it 14195 #inlinePreservableStyles() { 14196 const rules = this.#styleRules(); 14197 if (rules.length === 0) return 14198 14199 for (const [ selector, properties ] of Object.entries(PRESERVABLE_STYLES)) { 14200 for (const element of this.doc.querySelectorAll(selector)) { 14201 this.#inlineDeclaredStyles(element, properties, rules); 14202 } 14203 } 14204 } 14205 14206 // Spreadsheets (e.g. Excel) copy a <style> block whose rules (td { color: 14207 // black }, .xlNN { ... }) cascade onto the imported text. That color rides 14208 // in through the cascade rather than an inline style, so it slips past both 14209 // the cell-level stripping below and the paste style canonicalizer, leaving 14210 // pasted tables with foreign text colors that don't adapt to the theme. Drop 14211 // foreign style sheets so nothing cascades into imported content. 14212 #stripStyleElements() { 14213 for (const style of this.doc.querySelectorAll("style")) { 14214 style.remove(); 14215 } 14216 } 14217 14218 // Anchors with non-meaningful hrefs (e.g. "#", "") appear in content copied 14219 // from rendered views where mentions and interactive elements are wrapped in 14220 // <a href="#"> tags. Unwrap them so their text content pastes as plain text 14221 // and real links are preserved. 14222 #unwrapPlaceholderAnchors() { 14223 for (const anchor of this.doc.querySelectorAll("a")) { 14224 const href = anchor.getAttribute("href") || ""; 14225 if (href === "" || href === "#") { 14226 anchor.replaceWith(...anchor.childNodes); 14227 } 14228 } 14229 } 14230 14231 // Table cells copied from a page inherit the source theme's inline color 14232 // styles (e.g. dark-mode backgrounds). Strip them so pasted tables adopt 14233 // the current theme instead of carrying stale colors. 14234 #stripTableCellColorStyles() { 14235 for (const cell of this.doc.querySelectorAll("td, th")) { 14236 cell.style.removeProperty("background-color"); 14237 cell.style.removeProperty("background"); 14238 cell.style.removeProperty("color"); 14239 } 14240 } 14241 14242 // Some sources wrap runs of <li>s in a stray element (e.g. a <div> directly 14243 // inside the list). Dissolve such wrappers so their items become direct 14244 // list children and any nested list they hide becomes visible to 14245 // #nestStrayListChildren below. 14246 #unwrapWrappedListChildren() { 14247 for (const list of this.doc.querySelectorAll("ol, ul")) { 14248 let wrapper = this.#wrappedListChild(list); 14249 while (wrapper) { 14250 wrapper.replaceWith(...wrapper.childNodes); 14251 wrapper = this.#wrappedListChild(list); 14252 } 14253 } 14254 } 14255 14256 #wrappedListChild(list) { 14257 for (const child of list.children) { 14258 if (child.tagName !== "LI" && !this.#isNestedList(child) && this.#containsListItems(child)) { 14259 return child 14260 } 14261 } 14262 return null 14263 } 14264 14265 // Some sources (e.g. Gmail) nest a sublist as a direct child of the parent 14266 // <ol>/<ul> instead of inside a <li>. Move each nested list into its 14267 // preceding <li> so the import preserves the nesting instead of dropping it. 14268 #nestStrayListChildren() { 14269 for (const list of this.doc.querySelectorAll("ol, ul")) { 14270 for (const child of Array.from(list.children)) { 14271 if (child.tagName !== "OL" && child.tagName !== "UL") continue 14272 14273 const previousItem = child.previousElementSibling; 14274 if (previousItem && previousItem.tagName === "LI") { 14275 previousItem.appendChild(child); 14276 } 14277 } 14278 } 14279 } 14280 14281 // Only <li> is a valid child of a list. Unwrap remaining stray children 14282 // that still hold list items (a nested list with no preceding <li> to nest 14283 // under) so the items survive, and drop stray <br>/whitespace so the import 14284 // doesn't wrap them into an empty leading item. 14285 #stripStrayListChildren() { 14286 for (const list of this.doc.querySelectorAll("ol, ul")) { 14287 let stray = this.#firstStrayListChild(list); 14288 while (stray) { 14289 if (this.#containsListItems(stray)) { 14290 stray.replaceWith(...stray.childNodes); 14291 } else { 14292 stray.remove(); 14293 } 14294 14295 stray = this.#firstStrayListChild(list); 14296 } 14297 } 14298 } 14299 14300 // Read the rules from a sheet we build rather than from this.doc.styleSheets: the 14301 // document came from DOMParser, so it has no browsing context, and WebKit leaves 14302 // its styleSheets empty. Parsing the text ourselves still expands the shorthands 14303 // Word writes (margin: 0cm) into the longhands we ask for. 14304 #styleRules() { 14305 const css = Array.from(this.doc.querySelectorAll("style"), (style) => style.textContent).join("\n"); 14306 if (css.trim() === "") return [] 14307 14308 const sheet = new CSSStyleSheet(); 14309 sheet.replaceSync(css); 14310 14311 const rules = []; 14312 for (const rule of sheet.cssRules) { 14313 if (rule instanceof CSSStyleRule) { 14314 rules.push(rule); 14315 } 14316 } 14317 return rules 14318 } 14319 14320 // A declaration the element already carries inline is the author's own and wins. 14321 #inlineDeclaredStyles(element, properties, rules) { 14322 for (const property of properties) { 14323 if (element.style.getPropertyValue(property) === "") { 14324 const value = this.#declaredValue(rules, element, property); 14325 if (value) { 14326 this.#appendStyleProperty(element, property, value); 14327 } 14328 } 14329 } 14330 } 14331 14332 // Source order alone doesn't decide the cascade, so when the matching rules 14333 // disagree we can't say which value wins without resolving specificity. Skip 14334 // the property rather than guess: guessing is permanent, since the sheet is 14335 // about to go, and skipping only leaves the host on its own default. 14336 #declaredValue(rules, element, property) { 14337 const declared = new Set(); 14338 for (const rule of rules) { 14339 const value = rule.style.getPropertyValue(property); 14340 if (value !== "" && element.matches(rule.selectorText)) { 14341 declared.add(value); 14342 } 14343 } 14344 14345 if (declared.size === 1) { 14346 return declared.values().next().value 14347 } else { 14348 return null 14349 } 14350 } 14351 14352 // Assigning through element.style would reserialize the style attribute and 14353 // drop the mso-* declarations Word leaves inline (they aren't valid CSS), 14354 // and OfficeFormatter still needs to read mso-list from them. Append to the 14355 // attribute instead so the original declarations survive untouched. 14356 #appendStyleProperty(element, property, value) { 14357 const style = element.getAttribute("style"); 14358 const declaration = `${property}:${value}`; 14359 if (style === null || style.trim() === "") { 14360 element.setAttribute("style", declaration); 14361 } else { 14362 element.setAttribute("style", `${style.replace(/;\s*$/, "")};${declaration}`); 14363 } 14364 } 14365 14366 #firstStrayListChild(list) { 14367 for (const child of list.childNodes) { 14368 if (child.nodeType !== Node.ELEMENT_NODE || child.tagName !== "LI") { 14369 return child 14370 } 14371 } 14372 return null 14373 } 14374 14375 #isNestedList(node) { 14376 return node.nodeType === Node.ELEMENT_NODE && (node.tagName === "OL" || node.tagName === "UL") 14377 } 14378 14379 #containsListItems(node) { 14380 return node.nodeType === Node.ELEMENT_NODE && node.querySelector("li") !== null 14381 } 14382 14383 // Emoji in gmail: <img data-emoji="ð" class="an1" alt="ð" aria-label="ð" draggable="false" src="https://fonts.gstatic.com/s/e/notoemoji/17.0/1f602/32.png" loading="lazy" style="height: 1.2em; width: 1.2em; vertical-align: middle;"> 14384 #replaceGmailEmojiImgTags() { 14385 for (const emojiImg of this.doc.querySelectorAll("img[data-emoji]")) { 14386 const emoji = emojiImg.dataset.emoji; 14387 if (emoji === emojiImg.alt) { 14388 emojiImg.replaceWith(emoji); 14389 } 14390 } 14391 } 14392} 14393 14394class Contents { 14395 constructor(editorElement) { 14396 this.editorElement = editorElement; 14397 this.editor = editorElement.editor; 14398 } 14399 14400 dispose() { 14401 this.editorElement = null; 14402 this.editor = null; 14403 } 14404 14405 get selection() { return this.editorElement.selection } 14406 14407 insertHtml(html, { tag } = {}) { 14408 this.insertDOM(parseHtml(html), { tag }); 14409 } 14410 14411 insertDOM(doc, { tag } = {}) { 14412 this.editor.update(() => { 14413 if (
vendor: 14,478 bytes, lines 14413-14929
14413Es(jn)) this.#formatPastedDOM(doc); 14414 14415 const nodes = this.editorElement.$generateNodesFromDOM(doc); 14416 14417 if (!Es(jn) || !this.#dispatchPastedNodesCommand(nodes)) { 14418 this.#insertUploadNodes(nodes) || this.insertAtCursor(...nodes); 14419 } 14420 }, { tag }); 14421 } 14422 14423 insertText(text, { tag } = {}) { 14424 this.editor.update(() => { 14425 const paragraph = eo(); 14426 text.split(/\r\n|\r|\n/).forEach((line, index) => { 14427 if (index > 0) paragraph.append(or()); 14428 paragraph.append(kr(line)); 14429 }); 14430 this.insertAtCursor(paragraph); 14431 }, { tag }); 14432 } 14433 14434 insertAtCursor(...nodes) { 14435 const selection = this.#insertableSelection(); 14436 const inserter = BaseNodeInserter.for(selection); 14437 14438 inserter.insertNodes(nodes); 14439 } 14440 14441 applyParagraphFormat() { 14442 const selection = Qr(); 14443 if (!Fr(selection)) return 14444 14445 $expandSelectionToLineBreaksAndSplitAtEdges(selection, (node) => Nt$2(node)); 14446 H$6(selection, () => eo()); 14447 } 14448 14449 applyHeadingFormat(tag) { 14450 const selection = Qr(); 14451 if (!Fr(selection)) return 14452 14453 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 14454 H$6(selection, () => Jt$2(tag)); 14455 } 14456 14457 applyUnorderedListFormat() { 14458 this.#applyListFormat("bullet", Ee$2); 14459 } 14460 14461 applyOrderedListFormat() { 14462 this.#applyListFormat("number", Oe$1); 14463 } 14464 14465 clearFormatting() { 14466 const selection = Qr(); 14467 if (!Fr(selection)) return 14468 14469 D$3(node => { 14470 node.setFormat(0); 14471 node.setStyle(""); 14472 }); 14473 14474 Q$6(null); 14475 14476 this.#topLevelElementsInSelection(selection).filter(Mt$2).forEach(node => this.#unwrap(node)); 14477 14478 H$6(selection, () => eo()); 14479 } 14480 14481 toggleCodeBlock() { 14482 const selection = Qr(); 14483 if (!Fr(selection)) return 14484 14485 if (this.#insertNodeIfRoot(I$1("plain"))) return 14486 14487 const blockElements = this.#blockLevelElementsInSelection(selection); 14488 const allCode = blockElements.every(W$1); 14489 14490 if (allCode) { 14491 blockElements.forEach(node => this.#unwrapCodeBlock(node)); 14492 } else { 14493 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 14494 const elements = this.#outermostElements(this.#blockLevelElementsInSelection(selection)); 14495 if (elements.length === 0) return 14496 14497 const codeNode = I$1("plain"); 14498 elements.at(-1).insertAfter(codeNode); 14499 codeNode.selectEnd(); 14500 this.insertAtCursor(...elements); 14501 } 14502 } 14503 14504 toggleBlockquote() { 14505 const selection = Qr(); 14506 if (!Fr(selection)) return 14507 14508 if (this.#insertNodeIfRoot(St$1())) return 14509 14510 const topLevelElements = this.#topLevelElementsInSelection(selection); 14511 14512 const allQuoted = topLevelElements.length > 0 && topLevelElements.every(Mt$2); 14513 14514 if (allQuoted) { 14515 topLevelElements.forEach(node => this.#unwrap(node)); 14516 } else { 14517 topLevelElements.filter(Mt$2).forEach(node => this.#unwrap(node)); 14518 14519 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 14520 const elements = this.#topLevelElementsInSelection(selection); 14521 if (elements.length === 0) return 14522 14523 const blockquote = St$1(); 14524 elements[0].insertBefore(blockquote); 14525 elements.forEach((element) => blockquote.append(element)); 14526 } 14527 } 14528 14529 hasSelectedText() { 14530 let result = false; 14531 14532 this.editor.read(() => { 14533 const selection = Qr(); 14534 result = Fr(selection) && !selection.isCollapsed(); 14535 }); 14536 14537 return result 14538 } 14539 14540 createLink(url) { 14541 let linkNodeKey = null; 14542 14543 this.editor.update(() => { 14544 const textNode = kr(url); 14545 const linkNode = $$2(url); 14546 linkNode.append(textNode); 14547 14548 const selection = Qr(); 14549 if (Fr(selection)) { 14550 BaseNodeInserter.for(selection).insertNodes([ linkNode ]); 14551 linkNodeKey = linkNode.getKey(); 14552 } 14553 }); 14554 14555 return linkNodeKey 14556 } 14557 14558 createLinkWithSelectedText(url) { 14559 if (!this.hasSelectedText()) return 14560 14561 this.editor.update(() => { 14562 Q$6(null); 14563 Q$6(url); 14564 }); 14565 } 14566 14567 textBackUntil(string) { 14568 let result = ""; 14569 14570 this.editor.getEditorState().read(() => { 14571 const selection = Qr(); 14572 if (!selection || !selection.isCollapsed()) return 14573 14574 const anchor = selection.anchor; 14575 const anchorNode = anchor.getNode(); 14576 14577 if (!Tr(anchorNode)) return 14578 14579 const fullText = anchorNode.getTextContent(); 14580 const offset = anchor.offset; 14581 14582 const lastIndex = fullText.slice(0, offset).lastIndexOf(string); 14583 if (lastIndex !== -1) { 14584 result = fullText.slice(lastIndex + string.length, this.#endOffsetAt(fullText, offset)); 14585 } 14586 }); 14587 14588 return result 14589 } 14590 14591 // The query runs from the trigger up to the next boundary, even when the 14592 // cursor sits inside an existing word â inserting "@" before "Jack" must 14593 // filter by "Jack" rather than treating the prompt as empty. 14594 #endOffsetAt(fullText, cursorOffset) { 14595 for (let offset = cursorOffset; offset < fullText.length; offset++) { 14596 if (this.#isQueryBoundary(fullText, offset)) { 14597 return offset 14598 } 14599 } 14600 14601 return fullText.length 14602 } 14603 14604 // Whitespace always ends the query. Punctuation ends it too: with "@" typed 14605 // right before a period, extending across it would glue "." onto everything 14606 // typed ("B" would query "B."), matching the wrong names or nothing at all. 14607 // But punctuation joining two word characters is part of a name â "@" before 14608 // "Anne-Marie" or "O'Connor" must keep the whole name as the query. 14609 #isQueryBoundary(fullText, offset) { 14610 const character = fullText[offset]; 14611 if (/\s/.test(character)) return true 14612 if (!/\p{P}/u.test(character)) return false 14613 14614 return !(this.#isWordCharacter(fullText[offset - 1]) && this.#isWordCharacter(fullText[offset + 1])) 14615 } 14616 14617 #isWordCharacter(character) { 14618 return character != null && /[\p{L}\p{N}]/u.test(character) 14619 } 14620 14621 containsTextBackUntil(string) { 14622 let result = false; 14623 14624 this.editor.getEditorState().read(() => { 14625 const selection = Qr(); 14626 if (!selection || !selection.isCollapsed()) return 14627 14628 const anchor = selection.anchor; 14629 const anchorNode = anchor.getNode(); 14630 14631 if (!Tr(anchorNode)) return 14632 14633 const fullText = anchorNode.getTextContent(); 14634 const offset = anchor.offset; 14635 14636 const textBeforeCursor = fullText.slice(0, offset); 14637 14638 result = textBeforeCursor.includes(string); 14639 }); 14640 14641 return result 14642 } 14643 14644 replaceTextBackUntil(stringToReplace, replacementNodes) { 14645 replacementNodes = Array.isArray(replacementNodes) ? replacementNodes : [ replacementNodes ]; 14646 14647 const { anchorNode, offset } = this.#getTextAnchorData(); 14648 if (!anchorNode) return 14649 14650 const lastIndex = this.#findReplacementStart(anchorNode, offset, stringToReplace); 14651 if (lastIndex === -1) return 14652 14653 this.#performTextReplacement(anchorNode, lastIndex, stringToReplace, replacementNodes); 14654 } 14655 14656 uploadFiles(files, { selectLast } = {}) { 14657 if (!this.editorElement) return // Disposed (e.g. on turbo:before-cache); a late drop can still land here 14658 14659 if (!this.editorElement.supportsAttachments) { 14660 console.warn("This editor does not supports attachments (it's configured with [attachments=false])"); 14661 return 14662 } 14663 const validFiles = Array.from(files).filter(file => this.editorElement.acceptsFile(file)); 14664 14665 this.editor.update(() => { 14666 const uploader = Uploader.for(this.editorElement, validFiles); 14667 uploader.$uploadFiles(); 14668 14669 if (selectLast && uploader.nodes?.length) { 14670 const lastNode = uploader.nodes.at(-1); 14671 lastNode.selectEnd(); 14672 this.#normalizeSelectionInShadowRoot(); 14673 } 14674 }); 14675 } 14676 14677 $createUploadNode(file) { 14678 return $createActionTextAttachmentUploadNode({ 14679 file, 14680 uploadUrl: this.editorElement.directUploadUrl, 14681 blobUrlTemplate: this.editorElement.blobUrlTemplate, 14682 contentType: file.type, 14683 }) 14684 } 14685 14686 $createPendingUploadNode(file) { 14687 return $createActionTextAttachmentUploadNode({ 14688 file, 14689 uploadUrl: null, 14690 blobUrlTemplate: this.editorElement.blobUrlTemplate, 14691 contentType: file.type, 14692 }) 14693 } 14694 14695 insertPendingAttachment(file) { 14696 if (!this.editorElement.supportsAttachments) return null 14697 14698 let nodeKey = null; 14699 this.editor.update(() => { 14700 const uploadNode = this.$createPendingUploadNode(file); 14701 this.insertAtCursor(uploadNode); 14702 nodeKey = uploadNode.getKey(); 14703 }); 14704 14705 return nodeKey ? this.#pendingAttachmentHandle(nodeKey) : null 14706 } 14707 14708 insertPendingAttachments(files) { 14709 const fileList = Array.from(files); 14710 if (!this.editorElement.supportsAttachments || fileList.length === 0) return [] 14711 14712 let nodeKeys = []; 14713 this.editor.update(() => { 14714 const uploader = Uploader.for(this.editorElement, fileList, { pending: true }); 14715 uploader.$uploadFiles(); 14716 nodeKeys = (uploader.nodes ?? []).map(node => node.getKey()); 14717 }); 14718 14719 return nodeKeys.map(nodeKey => this.#pendingAttachmentHandle(nodeKey)) 14720 } 14721 14722 #pendingAttachmentHandle(initialNodeKey) { 14723 const editor = this.editor; 14724 let nodeKey = initialNodeKey; 14725 14726 return { 14727 setAttributes(blob) { 14728 editor.update(() => { 14729 const node = Yo(nodeKey); 14730 if (!(node instanceof ActionTextAttachmentUploadNode)) return 14731 14732 const replacementNodeKey = node.$showUploadedAttachment(blob); 14733 if (replacementNodeKey) { 14734 nodeKey = replacementNodeKey; 14735 } 14736 }, { tag: Jn }); 14737 }, 14738 setUploadProgress(progress) { 14739 editor.update(() => { 14740 const node = Yo(nodeKey); 14741 if (!(node instanceof ActionTextAttachmentUploadNode)) return 14742 14743 node.getWritable().progress = progress; 14744 }, { tag: Jn }); 14745 }, 14746 remove() { 14747 editor.update(() => { 14748 const node = Yo(nodeKey); 14749 if (node) node.remove(); 14750 }); 14751 } 14752 } 14753 } 14754 14755 replaceNodeWithHTML(nodeKey, html, options = {}) { 14756 this.editor.update(() => { 14757 const node = Yo(nodeKey); 14758 if (!node) return 14759 14760 const selection = Qr(); 14761 let wasSelected = false; 14762 14763 if (Fr(selection)) { 14764 const selectedNodes = selection.getNodes(); 14765 wasSelected = selectedNodes.includes(node) || selectedNodes.some(n => n.getParent() === node); 14766 14767 if (wasSelected) { 14768 es(null); 14769 } 14770 } 14771 14772 const replacementNode = options.attachment ? this.#createCustomAttachmentNodeWithHtml(html, options.attachment) : this.#createHtmlNodeWith(html); 14773 node.replace(replacementNode); 14774 14775 if (wasSelected) { 14776 replacementNode.selectEnd(); 14777 } 14778 }); 14779 } 14780 14781 insertHTMLBelowNode(nodeKey, html, options = {}) { 14782 this.editor.update(() => { 14783 const node = Yo(nodeKey); 14784 if (!node) return 14785 14786 const previousNode = node.getTopLevelElement() || node; 14787 14788 const newNode = options.attachment ? this.#createCustomAttachmentNodeWithHtml(html, options.attachment) : this.#createHtmlNodeWith(html); 14789 previousNode.insertAfter(newNode); 14790 }); 14791 } 14792 14793 #insertableSelection() { 14794 const selection = Qr(); 14795 if (Ir(selection) && selection.getNodes().length === 0) { 14796 return Zo().selectEnd() 14797 } 14798 14799 return selection ?? Zo().selectEnd() 14800 } 14801 14802 #formatPastedDOM(doc) { 14803 new PastedContentFormatter(doc).format(); 14804 } 14805 14806 #dispatchPastedNodesCommand(nodes) { 14807 return this.editor.dispatchCommand(oe$6, { 14808 nodes, selection: Qr() 14809 }) 14810 } 14811 14812 #insertNodeIfRoot(node) { 14813 const selection = Qr(); 14814 if (!Fr(selection)) return false 14815 14816 const anchorNode = selection.anchor.getNode(); 14817 if (Is(anchorNode)) { 14818 anchorNode.append(node); 14819 node.selectEnd(); 14820 14821 return true 14822 } 14823 14824 return false 14825 } 14826 14827 #unwrapCodeBlock(codeNode) { 14828 const children = codeNode.getChildren(); 14829 const groups = [ [] ]; 14830 14831 for (const child of children) { 14832 if (sr(child)) { 14833 groups.push([]); 14834 } else { 14835 groups[groups.length - 1].push(child.getTextContent()); 14836 } 14837 } 14838 14839 for (const group of groups) { 14840 const paragraph = eo(); 14841 const text = group.join(""); 14842 if (text) { 14843 paragraph.append(kr(text)); 14844 } 14845 codeNode.insertBefore(paragraph); 14846 } 14847 14848 codeNode.remove(); 14849 } 14850 14851 #applyListFormat(listType, command) { 14852 if (this.selection.isInsideBlockQuote) { 14853 this.#insertListInsideQuote(listType); 14854 } else { 14855 this.#splitParagraphsAtLineBreaksUnlessInsideList(); 14856 this.editor.dispatchCommand(command); 14857 } 14858 } 14859 14860 #insertListInsideQuote(listType) { 14861 for (const group of $consecutiveSiblingGroups(this.#quotedBlocksInSelection())) { 14862 this.#wrapBlocksInList(group, listType); 14863 } 14864 } 14865 14866 #quotedBlocksInSelection() { 14867 const selection = Qr(); 14868 if (!Fr(selection)) return [] 14869 14870 const blocks = this.#outermostElements(this.#blockLevelElementsInSelection(selection)); 14871 return blocks.filter((block) => Mt$2(block.getParent())) 14872 } 14873 14874 #wrapBlocksInList(blocks, listType) { 14875 const list = Te$1(listType); 14876 blocks[0].insertBefore(list); 14877 14878 for (const block of blocks) { 14879 const listItem = fe$2(); 14880 if (Se$1(block)) { 14881 listItem.append(...block.getChildren().flatMap((item) => item.getChildren())); 14882 } else { 14883 listItem.append(...block.getChildren()); 14884 } 14885 list.append(listItem); 14886 block.remove(); 14887 } 14888 } 14889 14890 #splitParagraphsAtLineBreaksUnlessInsideList() { 14891 if (this.selection.isInsideList) return 14892 14893 const selection = Qr(); 14894 if (!Fr(selection)) return 14895 14896 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 14897 $splitSelectedParagraphsAtInnerLineBreaks(selection); 14898 } 14899 14900 #blockLevelElementsInSelection(selection) { 14901 const blocks = new Set(); 14902 for (const node of selection.getNodes()) { 14903 blocks.add(Nt$2(node)); 14904 } 14905 14906 return Array.from(blocks) 14907 } 14908 14909 #topLevelElementsInSelection(selection) { 14910 const elements = new Set(); 14911 for (const node of selection.getNodes()) { 14912 const topLevel = node.getTopLevelElement(); 14913 if (topLevel) elements.add(topLevel); 14914 } 14915 return Array.from(elements) 14916 } 14917 14918 // Selections spanning nested structures (a quote and its inner paragraphs, 14919 // nested list items) yield both an element and its ancestor. Converting the 14920 // ancestor detaches its whole subtree â including a node freshly inserted 14921 // inside it â which can leave the selection on removed nodes (Lexical 14922 // invariant #19). The outermost elements already cover their descendants' 14923 // text content, so keep only those. 14924 #outermostElements(elements) { 14925 return elements.filter((element) => { 14926 return elements.every((other) => other === element || !element.getParents().includes(other)) 14927 }) 14928 } 14929
14930 #insertUploadNodes(nodes) { 14931 if (nodes.every($isActionTextAttachmentNode)) { 14932 const uploader = Uploader.for(this.editorElement, []); 14933 uploader.nodes = nodes; 14934 uploader.$insertUploadNodes(); 14935 return true 14936 } 14937 } 14938 14939 #unwrap(node) { 14940 const children = node.getChildren(); 14941 14942 if (children.length == 0) { 14943 node.insertBefore(eo()); 14944 } else { 14945 children.forEach((child) => { 14946 if (Tr(child) && child.getTextContent().trim() !== "") { 14947 const newParagraph = eo(); 14948 newParagraph.append(child); 14949 node.insertBefore(newParagraph); 14950 } else if (!sr(child)) { 14951 node.insertBefore(child); 14952 } 14953 }); 14954 } 14955 14956 node.remove(); 14957 } 14958 14959 #getTextAnchorData() { 14960 const selection = Qr(); 14961 if (!selection || !selection.isCollapsed()) return { anchorNode: null, offset: 0 } 14962 14963 const anchor = selection.anchor; 14964 const anchorNode = anchor.getNode(); 14965 14966 if (!Tr(anchorNode)) return { anchorNode: null, offset: 0 } 14967 14968 return { anchorNode, offset: anchor.offset } 14969 } 14970 14971 // The replaced span must start before the cursor but can extend past it 14972 // (e.g. "@Jack" when "@" was just inserted before "Jack"), so we bound the 14973 // match's start with lastIndexOf's fromIndex rather than slicing the text. 14974 #findReplacementStart(anchorNode, offset, stringToReplace) { 14975 if (offset === 0) { 14976 // A negative fromIndex clamps to 0 and could match at the cursor 14977 return -1 14978 } else { 14979 return anchorNode.getTextContent().lastIndexOf(stringToReplace, offset - 1) 14980 } 14981 } 14982 14983 #performTextReplacement(anchorNode, startIndex, stringToReplace, replacementNodes) { 14984 const fullText = anchorNode.getTextContent(); 14985 const textBeforeString = fullText.slice(0, startIndex); 14986 const textAfterString = fullText.slice(startIndex + stringToReplace.length); 14987 14988 const textNodeBefore = this.#cloneTextNodeFormatting(anchorNode, textBeforeString); 14989 const textNodeAfter = this.#cloneTextNodeFormatting(anchorNode, textAfterString || " "); 14990 14991 anchorNode.replace(textNodeBefore); 14992 14993 const lastInsertedNode = this.#insertReplacementNodes(textNodeBefore, replacementNodes); 14994 lastInsertedNode.insertAfter(textNodeAfter); 14995 14996 this.#appendLineBreakIfNeeded(textNodeAfter.getParentOrThrow()); 14997 const cursorOffset = textAfterString ? 0 : 1; 14998 textNodeAfter.select(cursorOffset, cursorOffset); 14999 } 15000 15001 #cloneTextNodeFormatting(anchorNode, text) { 15002 return kr(text) 15003 .setFormat(anchorNode.getFormat()) 15004 .setDetail(anchorNode.getDetail()) 15005 .setMode(anchorNode.getMode()) 15006 .setStyle(anchorNode.getStyle()) 15007 } 15008 15009 #insertReplacementNodes(startNode, replacementNodes) { 15010 let previousNode = startNode; 15011 for (const node of replacementNodes) { 15012 previousNode.insertAfter(node); 15013 previousNode = node; 15014 } 15015 return previousNode 15016 } 15017 15018 #appendLineBreakIfNeeded(paragraph) { 15019 if (no(paragraph) && this.editorElement.supportsMultiLine) { 15020 const children = paragraph.getChildren(); 15021 const last = children[children.length - 1]; 15022 const beforeLast = children[children.length - 2]; 15023 15024 if (Tr(last) && last.getTextContent() === "" && (beforeLast && !Tr(beforeLast))) { 15025 paragraph.append(or()); 15026 } 15027 } 15028 } 15029 15030 #createCustomAttachmentNodeWithHtml(html, options = {}) { 15031 const attachmentConfig = typeof options === "object" ? options : {}; 15032 const contentType = attachmentConfig.contentType || "text/html"; 15033 if (!this.editorElement.permitsAttachmentContentType(contentType)) { 15034 return this.#createHtmlNodeWith(html) 15035 } 15036 return new CustomActionTextAttachmentNode({ 15037 sgid: attachmentConfig.sgid || null, 15038 contentType, 15039 innerHtml: html, 15040 }) 15041 } 15042 15043 #createHtmlNodeWith(html) { 15044 const htmlNodes = this.editorElement.$generateNodesFromDOM(parseHtml(html)); 15045 return htmlNodes[0] || eo() 15046 } 15047 15048 // When the selection anchor is on a shadow root (e.g. a table cell), Lexical's 15049 // insertNodes can't find a block parent and fails silently. Normalize the 15050 // selection to point inside the shadow root's content instead. 15051 #normalizeSelectionInShadowRoot() { 15052 const selection = Qr(); 15053 if (!Fr(selection)) return 15054 15055 const anchorNode = selection.anchor.getNode(); 15056 if (!$isShadowRoot(anchorNode)) return 15057 15058 // Append a paragraph inside the shadow root so there's a valid text-level 15059 // target for subsequent insertions. This is necessary because decorator 15060 // nodes (e.g. attachments) at the end of a table cell leave the selection 15061 // on the cell itself with no block-level descendant to anchor to. 15062 const paragraph = eo(); 15063 anchorNode.append(paragraph); 15064 paragraph.selectStart(); 15065 } 15066} 15067 15068/** 15069 * marked v16.4.1 - a markdown parser 15070 * Copyright (c) 2011-2025, Christopher Jeffrey. (MIT Licensed) 15071 * https://github.com/markedjs/marked 15072 */ 15073 15074/** 15075 * DO NOT EDIT THIS FILE 15076 * The code in this file is generated from files in ./src/ 15077 */ 15078 15079function L(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:null,pedantic:false,renderer:null,silent:false,tokenizer:null,walkTokens:null}}var T=L();function G(u){T=u;}var I={exec:()=>null};function h(u,e=""){let t=typeof u=="string"?u:u.source,n={replace:(r,i)=>{let s=typeof i=="string"?i:i.source;return s=s.replace(m.caret,"$1"),t=t.replace(r,s),n},getRegex:()=>new RegExp(t,e)};return n}var m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine
vendor: 4,627 bytes, line 15079
15079:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:u=>new RegExp(`^( {0,3}${u})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:u=>new RegExp(`^ {0,${Math.min(3,u-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:u=>new RegExp(`^ {0,${Math.min(3,u-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:u=>new RegExp(`^ {0,${Math.min(3,u-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:u=>new RegExp(`^ {0,${Math.min(3,u-1)}}#`),htmlBeginRegex:u=>new RegExp(`^ {0,${Math.min(3,u-1)}}<(?:[a-z].*>|!--)`,"i")},be=/^(?:[ \t]*(?:\n|$))+/,Re=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,Te=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,E=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,Oe=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,F=/(?:[*+-]|\d{1,9}[.)])/,ie=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,oe=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),we=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),j=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,ye=/^[^\n]+/,Q=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,Pe=h(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",Q).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Se=h(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,F).getRegex(),v="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",U=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,$e=h("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",U).replace("tag",v).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),ae=h(j).replace("hr",E).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),_e=h(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",ae).getRegex(),K={blockquote:_e,code:Re,def:Pe,fences:Te,heading:Oe,hr:E,html:$e,lheading:oe,list:Se,newline:be,paragraph:ae,table:I,text:ye},re=h("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",E
vendor: 7,033 bytes, lines 15079-15081
15079).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Le={...K,lheading:we,table:re,paragraph:h(j).replace("hr",E).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",re).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex()},Me={...K,html:h(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",U).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:I,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:h(j).replace("hr",E).replace("heading",` *#{1,6} *[^ 15080]`).replace("lheading",oe).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},ze=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,Ae=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,le=/^( {2,}|\\)\n(?!\s*$)/,Ie=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,D=/[\p{P}\p{S}]/u,W=/[\s\p{P}\p{S}]/u,ue=/[^\s\p{P}\p{S}]/u,Ee=h(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,W).getRegex(),pe=/(?!~)[\p{P}\p{S}]/u,Ce=/(?!~)[\s\p{P}\p{S}]/u,Be=/(?:[^\s\p{P}\p{S}]|~)/u,qe=h(/link|code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<!`)(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("code",/(?<!`)(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),ce=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,ve=h(ce,"u").replace(/punct/g,D).getRegex(),De=h(ce,"u").replace(/punct/g,pe).getRegex(),he="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",He=h(he,"gu").replace(/notPunctSpace/g,ue).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Ze=h(he,"gu").replace(/notPunctSpace/g,Be).replace(/punctSpace/g,Ce).replace(/punct/g,pe).getRegex(),Ge=h("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ue).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Ne=h(/\\(punct)/,"gu").replace(/punct/g,D).getRegex(),Fe=h(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),je=h(U).replace("(?:-->|$)","-->").getRegex(),Qe=h("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",je).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),q=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+[^`]*?`+(?!`)|[^\[\]\\`])*?/,Ue=h(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label",q).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),de=h(/^!?\[(label)\]\[(ref)\]/).replace("label",q).replace("ref",Q).getRegex(),ke=h(/^!?\[(ref)\](?:\[\])?/).replace("ref",Q).getRegex(),Ke=h("reflink|nolink(?!\\()","g").replace("reflink",de).replace("nolink",ke).getRegex(),se=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,X={_backpedal:I,anyPunctuation:Ne,autolink:Fe,blockSkip:qe,br:le,code:Ae,del:I,emStrongLDelim:ve,emStrongRDelimAst:He,emStrongRDelimUnd:Ge,escape:ze,link:Ue,nolink:ke,punctuation:Ee,reflink:de,reflinkSearch:Ke,tag:Qe,text:Ie,url:I},We={...X,link:h(/^!?\[(label)\]\((.*?)\)/).replace("label",q).getRegex(),reflink:h(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",q).getRegex()},N={...X,emStrongRDelimAst:Ze,emStrongLDelim:De,url:h(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",se).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:h(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",se).getRegex()},Xe={...N,br:h(le).replace("{2,}","*").getRegex(),text:h(N.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},C={normal:K,gfm:Le,pedantic:Me},M={normal:X,gfm:N,breaks:Xe,pedantic:We};var Je={"&":"&","<":"<",">":">",'"':""","'":"'"},ge=u=>Je[u];function w(u,e){if(e){if(m.escapeTest.test(u))return u.replace(m.escapeReplace,ge)}else if(m.escapeTestNoEncode.test(u))return u.replace(m.escapeReplaceNoEncode,ge);return u}function J(u){try{u=encodeURI(u).replace(m.percentDecode,"%");}catch{return null}return u}function V(u,e){let t=u.replace(m.findPipe,(i,s,o)=>{let a=false,l=s;for(;--l>=0&&o[l]==="\\";)a=!a;return a?"|":" |"}),n=t.split(m.splitPipe),r=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;r<n.length;r++)n[r]=n[r].trim().replace(m.slashPipe,"|");return n}function z(u,e,t){let n=u.length;if(n===0)return "";let r=0;for(;r<n;){let i=u.charAt(n-r-1);if(i===e&&true)r++;else break}return u.slice(0,n-r)}function fe(u,e){if(u.indexOf(e[1])===-1)return -1;let t=0;for(let n=0;n<u.length;n++)if(u[n]==="\\")n++;else if(u[n]===e[0])t++;else if(u[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function me(u,e,t,n,r){let i=e.href,s=e.title||null,o=u[1].replace(r.other.outputLinkReplace,"$1");n.state.inLink=true;let a={type:u[0].charAt(0)==="!"?"image":"link",raw:t,href:i,title:s,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=false,a}function Ve(u,e,t){let n=u.match(t.other.indentCodeCompensation);if(n===null)return e;let r=n[1];return e.split(` 15081`).map(i=>{let s=i.match(t.other.beginningSpace);if(s===null)return i;let[o]=s;return o.length>
vendor: 6,982 bytes, lines 15081-15104
15081=r.length?i.slice(r.length):i}).join(` 15082`)}var y=class{options;rules;lexer;constructor(e){this.options=e||T;}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return {type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=t[0].replace(this.rules.other.codeRemoveIndent,"");return {type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?n:z(n,` 15083`)}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],r=Ve(n,t[3]||"",this.rules);return {type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:r}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let r=z(n,"#");(this.options.pedantic||!r||this.rules.other.endingSpaceChar.test(r))&&(n=r.trim());}return {type:"heading",raw:t[0],depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return {type:"hr",raw:z(t[0],` 15084`)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=z(t[0],` 15085`).split(` 15086`),r="",i="",s=[];for(;n.length>0;){let o=false,a=[],l;for(l=0;l<n.length;l++)if(this.rules.other.blockquoteStart.test(n[l]))a.push(n[l]),o=true;else if(!o)a.push(n[l]);else break;n=n.slice(l);let c=a.join(` 15087`),p=c.replace(this.rules.other.blockquoteSetextReplace,` 15088 $1`).replace(this.rules.other.blockquoteSetextReplace2,"");r=r?`${r} 15089${c}`:c,i=i?`${i} 15090${p}`:p;let g=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.blockTokens(p,s,true),this.lexer.state.top=g,n.length===0)break;let d=s.at(-1);if(d?.type==="code")break;if(d?.type==="blockquote"){let R=d,f=R.raw+` 15091`+n.join(` 15092`),O=this.blockquote(f);s[s.length-1]=O,r=r.substring(0,r.length-R.raw.length)+O.raw,i=i.substring(0,i.length-R.text.length)+O.text;break}else if(d?.type==="list"){let R=d,f=R.raw+` 15093`+n.join(` 15094`),O=this.list(f);s[s.length-1]=O,r=r.substring(0,r.length-d.raw.length)+O.raw,i=i.substring(0,i.length-R.raw.length)+O.raw,n=f.substring(s.at(-1).raw.length).split(` 15095`);continue}}return {type:"blockquote",raw:r,tokens:s,text:i}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),r=n.length>1,i={type:"list",raw:"",ordered:r,start:r?+n.slice(0,-1):"",loose:false,items:[]};n=r?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=r?n:"[*+-]");let s=this.rules.other.listItemRegex(n),o=false;for(;e;){let l=false,c="",p="";if(!(t=s.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let g=t[2].split(` 15096`,1)[0].replace(this.rules.other.listReplaceTabs,H=>" ".repeat(3*H.length)),d=e.split(` 15097`,1)[0],R=!g.trim(),f=0;if(this.options.pedantic?(f=2,p=g.trimStart()):R?f=t[1].length+1:(f=t[2].search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=g.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(d)&&(c+=d+` 15098`,e=e.substring(d.length+1),l=true),!l){let H=this.rules.other.nextBulletRegex(f),ee=this.rules.other.hrRegex(f),te=this.rules.other.fencesBeginRegex(f),ne=this.rules.other.headingBeginRegex(f),xe=this.rules.other.htmlBeginRegex(f);for(;e;){let Z=e.split(` 15099`,1)[0],A;if(d=Z,this.options.pedantic?(d=d.replace(this.rules.other.listReplaceNesting," "),A=d):A=d.replace(this.rules.other.tabCharGlobal," "),te.test(d)||ne.test(d)||xe.test(d)||H.test(d)||ee.test(d))break;if(A.search(this.rules.other.nonSpaceChar)>=f||!d.trim())p+=` 15100`+A.slice(f);else {if(R||g.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||te.test(g)||ne.test(g)||ee.test(g))break;p+=` 15101`+d;}!R&&!d.trim()&&(R=true),c+=Z+` 15102`,e=e.substring(Z.length+1),g=A.slice(f);}}i.loose||(o?i.loose=true:this.rules.other.doubleBlankLine.test(c)&&(o=true));let O=null,Y;this.options.gfm&&(O=this.rules.other.listIsTask.exec(p),O&&(Y=O[0]!=="[ ] ",p=p.replace(this.rules.other.listReplaceTask,""))),i.items.push({type:"list_item",raw:c,task:!!O,checked:Y,loose:false,text:p,tokens:[]}),i.raw+=c;}let a=i.items.at(-1);if(a)a.raw=a.raw.trimEnd(),a.text=a.text.trimEnd();else return;i.raw=i.raw.trimEnd();for(let l=0;l<i.items.length;l++)if(this.lexer.state.top=false,i.items[l].tokens=this.lexer.blockTokens(i.items[l].text,[]),!i.loose){let c=i.items[l].tokens.filter(g=>g.type==="space"),p=c.length>0&&c.some(g=>this.rules.other.anyLine.test(g.raw));i.loose=p;}if(i.loose)for(let l=0;l<i.items.length;l++)i.items[l].loose=true;return i}}html(e){let t=this.rules.block.html.exec(e);if(t)return {type:"html",block:true,raw:t[0],pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:t[0]}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),r=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",i=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return {type:"def",tag:n,raw:t[0],href:r,title:i}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=V(t[1]),r=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),i=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(` 15103`):[],s={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===r.length){for(let o of r)this.rules.other.tableAlignRight.test(o)?s.align.push("right"):this.rules.other.tableAlignCenter.test(o)?s.align.push("center"):this.rules.other.tableAlignLeft.test(o)?s.align.push("left"):s.align.push(null);for(let o=0;o<n.length;o++)s.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:true,align:s.align[o]});for(let o of i)s.rows.push(V(o,s.header.length).map((a,l)=>({text:a,tokens:this.lexer.inline(a),header:false,align:s.align[l]})));return s}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t)return {type:"heading",raw:t[0],depth:t[2].charAt(0)==="="?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===` 15104`?t[1].slice(0,-1):t[1];return {type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return {type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return {type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return !this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=true:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=false),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=true:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=false),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:false,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if
vendor: 19,520 bytes, lines 15104-15138
15104(!this.rules.other.endAngleBracket.test(n))return;let s=z(n.slice(0,-1),"\\");if((n.length-s.length)%2===0)return}else {let s=fe(t[2],"()");if(s===-2)return;if(s>-1){let a=(t[0].indexOf("!")===0?5:4)+t[1].length+s;t[2]=t[2].substring(0,s),t[0]=t[0].substring(0,a).trim(),t[3]="";}}let r=t[2],i="";if(this.options.pedantic){let s=this.rules.other.pedanticHrefTitle.exec(r);s&&(r=s[1],i=s[3]);}else i=t[3]?t[3].slice(1,-1):"";return r=r.trim(),this.rules.other.startAngleBracket.test(r)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?r=r.slice(1):r=r.slice(1,-1)),me(t,{href:r&&r.replace(this.rules.inline.anyPunctuation,"$1"),title:i&&i.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let r=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),i=t[r.toLowerCase()];if(!i){let s=n[0].charAt(0);return {type:"text",raw:s,text:s}}return me(n,i,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let r=this.rules.inline.emStrongLDelim.exec(e);if(!r||r[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(r[1]||r[2]||"")||!n||this.rules.inline.punctuation.exec(n)){let s=[...r[0]].length-1,o,a,l=s,c=0,p=r[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+s);(r=p.exec(t))!=null;){if(o=r[1]||r[2]||r[3]||r[4]||r[5]||r[6],!o)continue;if(a=[...o].length,r[3]||r[4]){l+=a;continue}else if((r[5]||r[6])&&s%3&&!((s+a)%3)){c+=a;continue}if(l-=a,l>0)continue;a=Math.min(a,a+l+c);let g=[...r[0]][0].length,d=e.slice(0,s+r.index+g+a);if(Math.min(s,a)%2){let f=d.slice(1,-1);return {type:"em",raw:d,text:f,tokens:this.lexer.inlineTokens(f)}}let R=d.slice(2,-2);return {type:"strong",raw:d,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),r=this.rules.other.nonSpaceChar.test(n),i=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return r&&i&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return {type:"br",raw:t[0]}}del(e){let t=this.rules.inline.del.exec(e);if(t)return {type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,r;return t[2]==="@"?(n=t[1],r="mailto:"+n):(n=t[1],r=n),{type:"link",raw:t[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,r;if(t[2]==="@")n=t[0],r="mailto:"+n;else {let i;do i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(i!==t[0]);n=t[0],t[1]==="www."?r="http://"+t[0]:r=t[0];}return {type:"link",raw:t[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return {type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class u{tokens;options;state;tokenizer;inlineQueue;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new y,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:false,inRawBlock:false,top:true};let t={other:m,block:C.normal,inline:M.normal};this.options.pedantic?(t.block=C.pedantic,t.inline=M.pedantic):this.options.gfm&&(t.block=C.gfm,this.options.breaks?t.inline=M.breaks:t.inline=M.gfm),this.tokenizer.rules=t;}static get rules(){return {block:C,inline:M}}static lex(e,t){return new u(t).lex(e)}static lexInline(e,t){return new u(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,` 15105`),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let n=this.inlineQueue[t];this.inlineTokens(n.src,n.tokens);}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=false){for(this.options.pedantic&&(e=e.replace(m.tabCharGlobal," ").replace(m.spaceLine,""));e;){let r;if(this.options.extensions?.block?.some(s=>(r=s.call({lexer:this},e,t))?(e=e.substring(r.raw.length),t.push(r),true):false))continue;if(r=this.tokenizer.space(e)){e=e.substring(r.raw.length);let s=t.at(-1);r.raw.length===1&&s!==void 0?s.raw+=` 15106`:t.push(r);continue}if(r=this.tokenizer.code(e)){e=e.substring(r.raw.length);let s=t.at(-1);s?.type==="paragraph"||s?.type==="text"?(s.raw+=(s.raw.endsWith(` 15107`)?"":` 15108`)+r.raw,s.text+=` 15109`+r.text,this.inlineQueue.at(-1).src=s.text):t.push(r);continue}if(r=this.tokenizer.fences(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.heading(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.hr(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.blockquote(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.list(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.html(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.def(e)){e=e.substring(r.raw.length);let s=t.at(-1);s?.type==="paragraph"||s?.type==="text"?(s.raw+=(s.raw.endsWith(` 15110`)?"":` 15111`)+r.raw,s.text+=` 15112`+r.raw,this.inlineQueue.at(-1).src=s.text):this.tokens.links[r.tag]||(this.tokens.links[r.tag]={href:r.href,title:r.title},t.push(r));continue}if(r=this.tokenizer.table(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.lheading(e)){e=e.substring(r.raw.length),t.push(r);continue}let i=e;if(this.options.extensions?.startBlock){let s=1/0,o=e.slice(1),a;this.options.extensions.startBlock.forEach(l=>{a=l.call({lexer:this},o),typeof a=="number"&&a>=0&&(s=Math.min(s,a));}),s<1/0&&s>=0&&(i=e.substring(0,s+1));}if(this.state.top&&(r=this.tokenizer.paragraph(i))){let s=t.at(-1);n&&s?.type==="paragraph"?(s.raw+=(s.raw.endsWith(` 15113`)?"":` 15114`)+r.raw,s.text+=` 15115`+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=s.text):t.push(r),n=i.length!==e.length,e=e.substring(r.raw.length);continue}if(r=this.tokenizer.text(e)){e=e.substring(r.raw.length);let s=t.at(-1);s?.type==="text"?(s.raw+=(s.raw.endsWith(` 15116`)?"":` 15117`)+r.raw,s.text+=` 15118`+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=s.text):t.push(r);continue}if(e){let s="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(s);break}else throw new Error(s)}}return this.state.top=true,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,r=null;if(this.tokens.links){let o=Object.keys(this.tokens.links);if(o.length>0)for(;(r=this.tokenizer.rules.inline.reflinkSearch.exec(n))!=null;)o.includes(r[0].slice(r[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,r.index)+"["+"a".repeat(r[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));}for(;(r=this.tokenizer.rules.inline.anyPunctuation.exec(n))!=null;)n=n.slice(0,r.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;(r=this.tokenizer.rules.inline.blockSkip.exec(n))!=null;)n=n.slice(0,r.index)+"["+"a".repeat(r[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=false,s="";for(;e;){i||(s=""),i=false;let o;if(this.options.extensions?.inline?.some(l=>(o=l.call({lexer:this},e,t))?(e=e.substring(o.raw.length),t.push(o),true):false))continue;if(o=this.tokenizer.escape(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.tag(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.link(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(o.raw.length);let l=t.at(-1);o.type==="text"&&l?.type==="text"?(l.raw+=o.raw,l.text+=o.text):t.push(o);continue}if(o=this.tokenizer.emStrong(e,n,s)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.codespan(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.br(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.del(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.autolink(e)){e=e.substring(o.raw.length),t.push(o);continue}if(!this.state.inLink&&(o=this.tokenizer.url(e))){e=e.substring(o.raw.length),t.push(o);continue}let a=e;if(this.options.extensions?.startInline){let l=1/0,c=e.slice(1),p;this.options.extensions.startInline.forEach(g=>{p=g.call({lexer:this},c),typeof p=="number"&&p>=0&&(l=Math.min(l,p));}),l<1/0&&l>=0&&(a=e.substring(0,l+1));}if(o=this.tokenizer.inlineText(a)){e=e.substring(o.raw.length),o.raw.slice(-1)!=="_"&&(s=o.raw.slice(-1)),i=true;let l=t.at(-1);l?.type==="text"?(l.raw+=o.raw,l.text+=o.text):t.push(o);continue}if(e){let l="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(l);break}else throw new Error(l)}}return t}};var P=class{options;parser;constructor(e){this.options=e||T;}space(e){return ""}code({text:e,lang:t,escaped:n}){let r=(t||"").match(m.notSpaceStart)?.[0],i=e.replace(m.endingNewline,"")+` 15119`;return r?'<pre><code class="language-'+w(r)+'">'+(n?i:w(i,true))+`</code></pre> 15120`:"<pre><code>"+(n?i:w(i,true))+`</code></pre> 15121`}blockquote({tokens:e}){return `<blockquote> 15122${this.parser.parse(e)}</blockquote> 15123`}html({text:e}){return e}def(e){return ""}heading({tokens:e,depth:t}){return `<h${t}>${this.parser.parseInline(e)}</h${t}> 15124`}hr(e){return `<hr> 15125`}list(e){let t=e.ordered,n=e.start,r="";for(let o=0;o<e.items.length;o++){let a=e.items[o];r+=this.listitem(a);}let i=t?"ol":"ul",s=t&&n!==1?' start="'+n+'"':"";return "<"+i+s+`> 15126`+r+"</"+i+`> 15127`}listitem(e){let t="";if(e.task){let n=this.checkbox({checked:!!e.checked});e.loose?e.tokens[0]?.type==="paragraph"?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&e.tokens[0].tokens[0].type==="text"&&(e.tokens[0].tokens[0].text=n+" "+w(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=true)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:true}):t+=n+" ";}return t+=this.parser.parse(e.tokens,!!e.loose),`<li>${t}</li> 15128`}checkbox({checked:e}){return "<input "+(e?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph({tokens:e}){return `<p>${this.parser.parseInline(e)}</p> 15129`}table(e){let t="",n="";for(let i=0;i<e.header.length;i++)n+=this.tablecell(e.header[i]);t+=this.tablerow({text:n});let r="";for(let i=0;i<e.rows.length;i++){let s=e.rows[i];n="";for(let o=0;o<s.length;o++)n+=this.tablecell(s[o]);r+=this.tablerow({text:n});}return r&&(r=`<tbody>${r}</tbody>`),`<table> 15130<thead> 15131`+t+`</thead> 15132`+r+`</table> 15133`}tablerow({text:e}){return `<tr> 15134${e}</tr> 15135`}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return (e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}> 15136`}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${w(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let r=this.parser.parseInline(n),i=J(e);if(i===null)return r;e=i;let s='<a href="'+e+'"';return t&&(s+=' title="'+w(t)+'"'),s+=">"+r+"</a>",s}image({href:e,title:t,text:n,tokens:r}){r&&(n=this.parser.parseInline(r,this.parser.textRenderer));let i=J(e);if(i===null)return w(n);e=i;let s=`<img src="${e}" alt="${n}"`;return t&&(s+=` title="${w(t)}"`),s+=">",s}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:w(e.text)}};var $=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}};var b=class u{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new P,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new $;}static parse(e,t){return new u(t).parse(e)}static parseInline(e,t){return new u(t).parseInline(e)}parse(e,t=true){let n="";for(let r=0;r<e.length;r++){let i=e[r];if(this.options.extensions?.renderers?.[i.type]){let o=i,a=this.options.extensions.renderers[o.type].call({parser:this},o);if(a!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(o.type)){n+=a||"";continue}}let s=i;switch(s.type){case "space":{n+=this.renderer.space(s);continue}case "hr":{n+=this.renderer.hr(s);continue}case "heading":{n+=this.renderer.heading(s);continue}case "code":{n+=this.renderer.code(s);continue}case "table":{n+=this.renderer.table(s);continue}case "blockquote":{n+=this.renderer.blockquote(s);continue}case "list":{n+=this.renderer.list(s);continue}case "html":{n+=this.renderer.html(s);continue}case "def":{n+=this.renderer.def(s);continue}case "paragraph":{n+=this.renderer.paragraph(s);continue}case "text":{let o=s,a=this.renderer.text(o);for(;r+1<e.length&&e[r+1].type==="text";)o=e[++r],a+=` 15137`+this.renderer.text(o);t?n+=this.renderer.paragraph({type:"paragraph",raw:a,text:a,tokens:[{type:"text",raw:a,text:a,escaped:true}]}):n+=a;continue}default:{let o='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}parseInline(e,t=this.renderer){let n="";for(let r=0;r<e.length;r++){let i=e[r];if(this.options.extensions?.renderers?.[i.type]){let o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(i.type)){n+=o||"";continue}}let s=i;switch(s.type){case "escape":{n+=t.text(s);break}case "html":{n+=t.html(s);break}case "link":{n+=t.link(s);break}case "image":{n+=t.image(s);break}case "strong":{n+=t.strong(s);break}case "em":{n+=t.em(s);break}case "codespan":{n+=t.codespan(s);break}case "br":{n+=t.br(s);break}case "del":{n+=t.del(s);break}case "text":{n+=t.text(s);break}default:{let o='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var S=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(){return this.block?x.lex:x.lexInline}provideParser(){return this.block?b.parse:b.parseInline}};var B=class{defaults=L();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=P;TextRenderer=$;Lexer=x;Tokenizer=y;Hooks=S;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let r of e)switch(n=n.concat(t.call(this,r)),r.type){case "table":{let i=r;for(let s of i.header)n=n.concat(this.walkTokens(s.tokens,t));for(let s of i.rows)for(let o of s)n=n.concat(this.walkTokens(o.tokens,t));break}case "list":{let i=r;n=n.concat(this.walkTokens(i.items,t));break}default:{let i=r;this.defaults.extensions?.childTokens?.[i.type]?this.defaults.extensions.childTokens[i.type].forEach(s=>{let o=i[s].flat(1/0);n=n.concat(this.walkTokens(o,t));}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let r={...n};if(r.async=this.defaults.async||r.async||false,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let s=t.renderers[i.name];s?t.renderers[i.name]=function(...o){let a=i.renderer.apply(this,o);return a===false&&(a=s.apply(this,o)),a}:t.renderers[i.name]=i.renderer;}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let s=t[i.level];s?s.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]));}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens);}),r.extensions=t),n.renderer){let i=this.defaults.renderer||new P(this.defaults);for(let s in n.renderer){if(!(s in i))throw new Error(`renderer '${s}' does not exist`);if(["options","parser"].includes(s))continue;let o=s,a=n.renderer[o],l=i[o];i[o]=(...c)=>{let p=a.apply(i,c);return p===false&&(p=l.apply(i,c)),p||""};}r.renderer=i;}if(n.tokenizer){let i=this.defaults.tokenizer||new y(this.defaults);for(let s in n.tokenizer){if(!(s in i))throw new Error(`tokenizer '${s}' does not exist`);if(["options","rules","lexer"].includes(s))continue;let o=s,a=n.tokenizer[o],l=i[o];i[o]=(...c)=>{let p=a.apply(i,c);return p===false&&(p=l.apply(i,c)),p};}r.tokenizer=i;}if(n.hooks){let i=this.defaults.hooks||new S;for(let s in n.hooks){if(!(s in i))throw new Error(`hook '${s}' does not exist`);if(["options","block"].includes(s))continue;let o=s,a=n.hooks[o],l=i[o];S.passThroughHooks.has(s)?i[o]=c=>{if(this.defaults.async&&S.passThroughHooksRespectAsync.has(s))return (async()=>{let g=await a.call(i,c);return l.call(i,g)})();let p=a.call(i,c);return l.call(i,p)}:i[o]=(...c)=>{if(this.defaults.async)return (async()=>{let g=await a.apply(i,c);return g===false&&(g=await l.apply(i,c)),g})();let p=a.apply(i,c);return p===false&&(p=l.apply(i,c)),p};}r.hooks=i;}if(n.walkTokens){let i=this.defaults.walkTokens,s=n.walkTokens;r.walkTokens=function(o){let a=[];return a.push(s.call(this,o)),i&&(a=a.concat(i.call(this,o))),a};}this.defaults={...this.defaults,...r};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,r)=>{let i={...r},s={...this.defaults,...i},o=this.onError(!!s.silent,!!s.async);if(this.defaults.async===true&&i.async===false)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(s.hooks&&(s.hooks.options=s,s.hooks.block=e),s.async)return (async()=>{let a=s.hooks?await s.hooks.preprocess(n):n,c=await(s.hooks?await s.hooks.provideLexer():e?x.lex:x.lexInline)(a,s),p=s.hooks?await s.hooks.processAllTokens(c):c;s.walkTokens&&await Promise.all(this.walkTokens(p,s.walkTokens));let d=await(s.hooks?await s.hooks.provideParser():e?b.parse:b.parseInline)(p,s);return s.hooks?await s.hooks.postprocess(d):d})().catch(o);try{s.hooks&&(n=s.hooks.preprocess(n));let l=(s.hooks?s.hooks.provideLexer():e?x.lex:x.lexInline)(n,s);s.hooks&&(l=s.hooks.processAllTokens(l)),s.walkTokens&&this.walkTokens(l,s.walkTokens);let p=(s.hooks?s.hooks.provideParser():e?b.parse:b.parseInline)(l,s);return s.hooks&&(p=s.hooks.postprocess(p)),p}catch(a){return o(a)}}}onError(e,t){return n=>{if(n.message+=` 15138Please report this to https://github.com/markedjs/marked.`,e){let r="<p>An error occurred:</p><pre>"+w(n.message+"",true)+"</pre>";return t?Promise.resolve(r):r}if(t)return Promise.reject(n);throw n}}};var _=new B;function k(u,e){return _.parse(u,e)}
15138k.options=k.setOptions=function(u){return _.setOptions(u),k.defaults=_.defaults,G(k.defaults),k};k.getDefaults=L;k.defaults=T;k.use=function(...u){return _.use(...u),k.defaults=_.defaults,G(k.defaults),k};k.walkTokens=function(u,e){return _.walkTokens(u,e)};k.parseInline=_.parseInline;k.Parser=b;k.parser=b.parse;k.Renderer=P;k.TextRenderer=$;k.Lexer=x;k.lexer=x.lex;k.Tokenizer=y;k.Hooks=S;k.parse=k;k.options;k.setOptions;k.use;k.walkTokens;k.parseInline;b.parse;x.lex; 15139 15140// Markdown reads any line indented by a tab or four spaces as a code block. Pasted 15141// plain text is full of incidental indentation â outlines, notes, logs â and nobody 15142// indents a note meaning "this is code"; they fence it. Keep fences, drop the 15143// indentation rule. 15144const pastedMarkdown = new B({ breaks: true }).use({ tokenizer: { code: () => undefined } }); 15145 15146class Clipboard { 15147 #listeners = new ListenerBin() 15148 15149 constructor(editorElement) { 15150 this.editorElement = editorElement; 15151 this.editor = editorElement.editor; 15152 this.contents = editorElement.contents; 15153 15154 this.#registerPasteCommands(); 15155 } 15156 15157 dispose() { 15158 this.editorElement = null; 15159 this.editor = null; 15160 this.contents = null; 15161 15162 this.#listeners.dispose(); 15163 } 15164 15165 paste(event) { 15166 const clipboardData = event.clipboardData; 15167 15168 if (!clipboardData) return false 15169 15170 if (this.#isPastingIntoCodeBlock()) { 15171 this.#pastePlainTextIntoCodeBlock(clipboardData); 15172 event.preventDefault(); 15173 return true 15174 } 15175 15176 if (this.#isPlainTextOrURLPasted(clipboardData)) { 15177 this.#pastePlainTextOrURL(clipboardData); 15178 event.preventDefault(); 15179 return true 15180 } 15181 15182 const handled = this.#handlePastedFiles(clipboardData); 15183 if (handled) event.preventDefault(); 15184 return handled 15185 } 15186 15187 #registerPasteCommands() { 15188 this.#listeners.track( 15189 this.editor.registerCommand(_e$2, this.paste.bind(this), oo), 15190 this.editor.registerCommand( 15191 oe$6, 15192 (payload) => this.#handleParsedClipboardNodes(payload), 15193 oo 15194 ) 15195 ); 15196 } 15197 15198 #handleParsedClipboardNodes({ nodes, selection }) { 15199 const url = $bareUrlFromSingleLink(nodes); 15200 if (url && Fr(selection)) { 15201 this.#insertSingleLinkAt(selection, url); 15202 return true 15203 } 15204 } 15205 15206 #isPlainTextOrURLPasted(clipboardData) { 15207 return this.#isOnlyPlainTextPasted(clipboardData) || this.#isOnlyURLPasted(clipboardData) 15208 } 15209 15210 #isOnlyPlainTextPasted(clipboardData) { 15211 const types = Array.from(clipboardData.types); 15212 return types.length === 1 && types[0] === "text/plain" 15213 } 15214 15215 // Browsers expose a copied URL in several shapes: 15216 // Safari [ text/plain, text/uri-list ] 15217 // App ShareSheet [ text/uri-list ] 15218 // Chromium macOS [ text/plain, text/html, (?:text/link-preview) ] 15219 #isOnlyURLPasted(clipboardData) { 15220 if (this.#isLexicalClipboardData(clipboardData)) return false 15221 15222 const types = Array.from(clipboardData.types); 15223 if (types.includes("text/uri-list")) { 15224 return types.every(type =>
vendor: 34,167 bytes, lines 15224-16330
15224 type === "text/plain" || type === "text/uri-list") 15225 } 15226 15227 if (clipboardData.files.length) return false 15228 15229 const text = clipboardData.getData("text/plain").trim(); 15230 if (!isAutolinkableURL(text)) return false 15231 15232 const html = clipboardData.getData("text/html"); 15233 return !html || this.#htmlIsBareLinkToURL(html, text) 15234 } 15235 15236 #htmlIsBareLinkToURL(html, url) { 15237 const doc = parseHtml(html); 15238 if (doc.body.textContent.trim() !== url) return false 15239 15240 const links = doc.body.querySelectorAll("a"); 15241 if (links.length === 0) return true 15242 return links.length === 1 && links[0].getAttribute("href") === url 15243 } 15244 15245 #isPastingIntoCodeBlock() { 15246 let result = false; 15247 15248 this.editor.getEditorState().read(() => { 15249 const selection = Qr(); 15250 if (!Fr(selection)) return 15251 15252 let currentNode = selection.anchor.getNode(); 15253 15254 while (currentNode) { 15255 if (W$1(currentNode)) { 15256 result = true; 15257 return 15258 } 15259 currentNode = currentNode.getParent(); 15260 } 15261 }); 15262 15263 return result 15264 } 15265 15266 #pastePlainTextIntoCodeBlock(clipboardData) { 15267 const text = clipboardData.getData("text/plain"); 15268 if (!text) return 15269 15270 this.editor.update(() => { 15271 const selection = Qr(); 15272 if (Fr(selection)) selection.insertRawText(text); 15273 }, { tag: jn }); 15274 } 15275 15276 #pastePlainTextOrURL(clipboardData) { 15277 const item = this.#plainTextOrURLItem(clipboardData); 15278 item.getAsString((text) => { 15279 const url = text.trim(); 15280 if (isAutolinkableURL(url)) { 15281 this.#pasteURL(url); 15282 } else if (this.editorElement.supportsMarkdown) { 15283 this.#pasteMarkdown(text); 15284 } else { 15285 this.#pasteRichText(clipboardData); 15286 } 15287 }); 15288 } 15289 15290 #plainTextOrURLItem(clipboardData) { 15291 const items = Array.from(clipboardData.items); 15292 return items.find((item) => item.type === "text/plain") || items.find((item) => item.type === "text/uri-list") 15293 } 15294 15295 #pasteURL(url) { 15296 if (this.contents.hasSelectedText()) { 15297 this.contents.createLinkWithSelectedText(url); 15298 } else { 15299 const nodeKey = this.contents.createLink(url); 15300 this.#dispatchLinkInsertEvent(nodeKey, { url }); 15301 } 15302 } 15303 15304 #insertSingleLinkAt(selection, url) { 15305 if (!Fr(selection)) return 15306 15307 if (!selection.isCollapsed()) { 15308 Q$6(null); 15309 Q$6(url); 15310 return 15311 } 15312 15313 const linkNode = $$2(url).append(kr(url)); 15314 BaseNodeInserter.for(selection).insertNodes([ linkNode ]); 15315 15316 Ms(() => this.#dispatchLinkInsertEvent(linkNode.getKey(), { url })); 15317 } 15318 15319 #dispatchLinkInsertEvent(nodeKey, payload) { 15320 const linkManipulationMethods = { 15321 replaceLinkWith: (html, options) => this.contents.replaceNodeWithHTML(nodeKey, html, options), 15322 insertBelowLink: (html, options) => this.contents.insertHTMLBelowNode(nodeKey, html, options) 15323 }; 15324 15325 dispatch(this.editorElement, "lexxy:insert-link", { 15326 ...payload, 15327 ...linkManipulationMethods 15328 }); 15329 } 15330 15331 #pasteMarkdown(text) { 15332 const html = pastedMarkdown.parse(text); 15333 const doc = parseHtml(html); 15334 15335 if (this.#isPlainTextWithoutMarkdown(doc)) { 15336 this.contents.insertText(text, { tag: jn }); 15337 } else { 15338 const detail = Object.freeze({ 15339 markdown: text, 15340 document: doc, 15341 addBlockSpacing: () => addBlockSpacing(doc) 15342 }); 15343 15344 dispatch(this.editorElement, "lexxy:insert-markdown", detail); 15345 this.contents.insertDOM(doc, { tag: jn }); 15346 } 15347 } 15348 15349 // Markdown conversion collapses runs of whitespace and unescapes backslashes, 15350 // silently corrupting plain text such as Windows/UNC file paths. When the text 15351 // carries no Markdown structure, paste it verbatim instead. A path that wrapped 15352 // across lines renders as a single paragraph with <br> line breaks (marked runs 15353 // with breaks: true), which is still plain text we should preserve untouched. 15354 #isPlainTextWithoutMarkdown(doc) { 15355 const elements = Array.from(doc.body.children); 15356 if (elements.length !== 1) return false 15357 15358 const paragraph = elements[0]; 15359 return paragraph.nodeName === "P" 15360 && Array.from(paragraph.childNodes).every((node) => node.nodeType === Node.TEXT_NODE || node.nodeName === "BR") 15361 } 15362 15363 #pasteRichText(clipboardData) { 15364 this.editor.update(() => { 15365 const selection = Qr(); 15366 I$3(clipboardData, selection, this.editor); 15367 }, { tag: jn }); 15368 } 15369 15370 #handlePastedFiles(clipboardData) { 15371 if (!this.editorElement.supportsAttachments) return false 15372 15373 const html = clipboardData.getData("text/html"); 15374 const files = clipboardData.files; 15375 15376 if (files.length && this.#isCopiedImageHTML(html)) { 15377 this.#uploadFilesPreservingScroll(files); 15378 return true 15379 } 15380 15381 if (html && !this.#isLexicalClipboardData(clipboardData)) { 15382 this.contents.insertHtml(html, { tag: jn }); 15383 return true 15384 } 15385 15386 if (files.length) { 15387 this.#uploadFilesPreservingScroll(files); 15388 return true 15389 } 15390 15391 return false 15392 } 15393 15394 #isLexicalClipboardData(clipboardData) { 15395 return Array.from(clipboardData.types).includes("application/x-lexical-editor") 15396 } 15397 15398 #isCopiedImageHTML(html) { 15399 if (!html) return false 15400 15401 const doc = parseHtml(html); 15402 const elementChildren = Array.from(doc.body.children); 15403 15404 return elementChildren.length === 1 && elementChildren[0].tagName === "IMG" 15405 } 15406 15407 #uploadFilesPreservingScroll(files) { 15408 this.#preservingScrollPosition(() => { 15409 if (files.length) { 15410 this.contents.uploadFiles(files, { selectLast: true }); 15411 } 15412 }); 15413 } 15414 15415 // Deals with an issue in Safari where it scrolls to the tops after pasting attachments 15416 async #preservingScrollPosition(callback) { 15417 const scrollY = window.scrollY; 15418 const scrollX = window.scrollX; 15419 15420 callback(); 15421 15422 await nextFrame(); 15423 15424 window.scrollTo(scrollX, scrollY); 15425 this.editor.focus(); 15426 } 15427} 15428 15429function $bareUrlFromSingleLink(nodes) { 15430 if (nodes.length !== 1) return null 15431 15432 const node = nodes[0]; 15433 if (z$5(node)) return $bareUrlFromLink(node) 15434 15435 if (no(node)) { 15436 const children = node.getChildren(); 15437 if (children.length === 1 && z$5(children[0])) { 15438 return $bareUrlFromLink(children[0]) 15439 } 15440 } 15441 15442 return null 15443} 15444 15445function $bareUrlFromLink(linkNode) { 15446 const url = linkNode.getURL(); 15447 if (!url) return null 15448 return linkNode.getTextContent() === url ? url : null 15449} 15450 15451class Extensions { 15452 15453 constructor(lexxyElement) { 15454 this.lexxyElement = lexxyElement; 15455 15456 this.enabledExtensions = this.#initializeExtensions(); 15457 } 15458 15459 get lexicalExtensions() { 15460 return this.enabledExtensions.map(ext => ext.lexicalExtension).filter(Boolean) 15461 } 15462 15463 initializeToolbars() { 15464 const toolbar = this.#lexxyToolbar; 15465 if (!toolbar) return 15466 15467 this.#clearPreviousExtensionToolbarButtons(toolbar); 15468 this.#addExtensionToolbarButtons(toolbar); 15469 toolbar.requestOverflowRefresh(); 15470 } 15471 15472 dispose() { 15473 while (this.enabledExtensions.length) { 15474 this.enabledExtensions.pop().dispose(); 15475 } 15476 } 15477 15478 #clearPreviousExtensionToolbarButtons(toolbar) { 15479 toolbar.querySelectorAll("[data-lexxy-extension]").forEach(el => el.remove()); 15480 } 15481 15482 #addExtensionToolbarButtons(toolbar) { 15483 this.enabledExtensions.forEach(ext => { 15484 const childrenBefore = new Set(toolbar.children); 15485 ext.initializeToolbar(toolbar); 15486 for (const child of toolbar.children) { 15487 if (!childrenBefore.has(child)) { 15488 child.setAttribute("data-lexxy-extension", ""); 15489 } 15490 } 15491 }); 15492 } 15493 15494 get allowedElements() { 15495 return this.enabledExtensions.flatMap(ext => ext.allowedElements) 15496 } 15497 15498 get #lexxyToolbar() { 15499 return this.lexxyElement.toolbar 15500 } 15501 15502 get #baseExtensions() { 15503 return this.lexxyElement.baseExtensions 15504 } 15505 15506 get #configuredExtensions() { 15507 return Lexxy.global.get("extensions") 15508 } 15509 15510 #initializeExtensions() { 15511 const extensionDefinitions = this.#baseExtensions.concat(this.#configuredExtensions); 15512 15513 return extensionDefinitions.map( 15514 extension => new extension(this.lexxyElement) 15515 ).filter(extension => extension.enabled) 15516 } 15517} 15518 15519class BrowserAdapter { 15520 frozenLinkKey = null 15521 15522 dispatchAttributesChange(attributes, linkHref, highlight, headingTag) {} 15523 dispatchEditorInitialized(detail) {} 15524 freeze() {} 15525 thaw() {} 15526 unlinkFrozenNode() { 15527 return false 15528 } 15529} 15530 15531// Custom TextNode exportDOM that avoids redundant wrapping. 15532// 15533// Lexical's built-in TextNode.exportDOM() calls createDOM() which produces semantic tags 15534// like <strong> for bold and <em> for italic, then unconditionally wraps the result 15535// with presentational tags (<b>, <i>) for the same formats. This produces redundant markup 15536// like <b><strong>text</strong></b>. 15537// 15538// This custom export skips <b> when <strong> is already present and <i> when <em> is 15539// already present, while preserving <s> and <u> wrappers which have no semantic equivalents 15540// in createDOM's output. 15541// 15542// Any <span> elements produced by createDOM() are unwrapped, since they only carry 15543// editor classes that aren't meaningful in exported HTML. 15544 15545function exportTextNodeDOM(editor, textNode) { 15546 const element = textNode.createDOM(editor._config, editor); 15547 element.style.whiteSpace = "pre-wrap"; 15548 15549 if (textNode.hasFormat("lowercase")) { 15550 element.style.textTransform = "lowercase"; 15551 } else if (textNode.hasFormat("uppercase")) { 15552 element.style.textTransform = "uppercase"; 15553 } else if (textNode.hasFormat("capitalize")) { 15554 element.style.textTransform = "capitalize"; 15555 } 15556 15557 let result = element; 15558 15559 if (textNode.hasFormat("bold") && !containsTag(element, "strong")) { 15560 result = wrapWith(result, "b"); 15561 } 15562 if (textNode.hasFormat("italic") && !containsTag(element, "em")) { 15563 result = wrapWith(result, "i"); 15564 } 15565 if (textNode.hasFormat("strikethrough")) { 15566 result = wrapWith(result, "s"); 15567 } 15568 if (textNode.hasFormat("underline")) { 15569 result = wrapWith(result, "u"); 15570 } 15571 15572 return { element: unwrapSpans(result) } 15573} 15574 15575function containsTag(element, tagName) { 15576 const upperTag = tagName.toUpperCase(); 15577 if (element.tagName === upperTag) return true 15578 15579 return element.querySelector(tagName) !== null 15580} 15581 15582function wrapWith(element, tag) { 15583 const wrapper = document.createElement(tag); 15584 wrapper.appendChild(element); 15585 return wrapper 15586} 15587 15588function unwrapSpans(element) { 15589 if (element.tagName === "SPAN") return element.firstChild 15590 15591 for (const span of element.querySelectorAll("span")) { 15592 span.replaceWith(...span.childNodes); 15593 } 15594 15595 return element 15596} 15597 15598class ProvisionalParagraphNode extends Zi { 15599 $config() { 15600 return this.config("provisonal_paragraph", { 15601 extends: Zi, 15602 importDOM: () => null, 15603 $transform: (node) => { 15604 node.concretizeIfEdited(node); 15605 node.removeUnlessRequired(node); 15606 } 15607 }) 15608 } 15609 15610 static neededBetween(nodeBefore, nodeAfter) { 15611 return !$isSelectableElement(nodeBefore, "next") 15612 && !$isSelectableElement(nodeAfter, "previous") 15613 } 15614 15615 createDOM(editor) { 15616 const p = super.createDOM(editor); 15617 const selected = this.isSelected(Qr()); 15618 p.classList.add("provisional-paragraph"); 15619 p.classList.toggle("hidden", !selected); 15620 return p 15621 } 15622 15623 updateDOM(_prevNode, dom) { 15624 const selected = this.isSelected(Qr()); 15625 dom.classList.toggle("hidden", !selected); 15626 return false 15627 } 15628 15629 getTextContent() { 15630 return "" 15631 } 15632 15633 exportDOM() { 15634 return { 15635 element: null 15636 } 15637 } 15638 15639 // override as Lexical has an interesting view of collapsed selection in ElementNodes 15640 // https://github.com/facebook/lexical/blob/f1e4f66014377b1f2595aec2b0ee17f5b7ef4dfc/packages/lexical/src/LexicalNode.ts#L646 15641 isSelected(selection = null) { 15642 const targetSelection = selection || Qr(); 15643 if (!targetSelection) return false 15644 15645 if (targetSelection.getNodes().some(node => node.is(this) || this.isParentOf(node))) return true 15646 15647 // A collapsed range selection on the parent element at an offset adjacent to 15648 // this node means the caret is visually at this paragraph's position. Treat it 15649 // as selected so the paragraph is visible and the caret renders correctly. 15650 // 15651 // Both the offset matching our index (cursor just before us) and index + 1 15652 // (cursor just after us) count, because the provisional paragraph is an 15653 // invisible spacer: the browser resolves both offsets to the same visual spot. 15654 if (Fr(targetSelection) && targetSelection.isCollapsed()) { 15655 const { anchor } = targetSelection; 15656 const parent = this.getParent(); 15657 if (parent && anchor.getNode().is(parent) && anchor.type === "element") { 15658 const index = this.getIndexWithinParent(); 15659 return anchor.offset === index || anchor.offset === index + 1 15660 } 15661 } 15662 15663 return false 15664 } 15665 15666 removeUnlessRequired(self = this.getLatest()) { 15667 if (!self.required) self.remove(); 15668 } 15669 15670 concretizeIfEdited(self = this.getLatest()) { 15671 if (self.getTextContentSize() > 0) { 15672 self.replace(eo(), true); 15673 } 15674 } 15675 15676 15677 get required() { 15678 return this.isDirectRootChild && ProvisionalParagraphNode.neededBetween(...this.immediateSiblings) 15679 } 15680 15681 get isDirectRootChild() { 15682 const parent = this.getParent(); 15683 return Is(parent) 15684 } 15685 15686 get immediateSiblings() { 15687 return [ this.getPreviousSibling(), this.getNextSibling() ] 15688 } 15689} 15690 15691function $isProvisionalParagraphNode(node) { 15692 return node instanceof ProvisionalParagraphNode 15693} 15694 15695function $isSelectableElement(node, direction) { 15696 return Wi(node) && (direction === "next" ? node.canInsertTextBefore() : node.canInsertTextAfter()) 15697} 15698 15699class ProvisionalParagraphExtension extends LexxyExtension { 15700 get lexicalExtension() { 15701 return dc({ 15702 name: "lexxy/provisional-paragraph", 15703 nodes: [ 15704 ProvisionalParagraphNode 15705 ], 15706 register(editor) { 15707 return Cc( 15708 // Process Provisional Paragraph Nodes on RootNode changes as sibling status influences whether 15709 // they are required and their visible/hidden status 15710 editor.registerNodeTransform(Ui, $insertRequiredProvisionalParagraphs), 15711 editor.registerNodeTransform(Ui, $removeUnneededProvisionalParagraphs), 15712 editor.registerCommand(ie$4, $markAllProvisionalParagraphsDirty, so) 15713 ) 15714 } 15715 }) 15716 } 15717} 15718 15719function $insertRequiredProvisionalParagraphs(rootNode) { 15720 const nodeBeforeRootSelection = $nodeBeforeRootSelection(rootNode); 15721 15722 const firstNode = rootNode.getFirstChild(); 15723 if (ProvisionalParagraphNode.neededBetween(null, firstNode)) { 15724 $t$2(rootNode, new ProvisionalParagraphNode); 15725 } 15726 15727 for (const node of jt$2(rootNode)) { 15728 const nextNode = node.getNextSibling(); 15729 if (ProvisionalParagraphNode.neededBetween(node, nextNode)) { 15730 node.insertAfter(new ProvisionalParagraphNode); 15731 if (node.is(nodeBeforeRootSelection)) node.selectNext(); 15732 } 15733 } 15734} 15735 15736function $nodeBeforeRootSelection(rootNode) { 15737 const selection = Qr(); 15738 if (!Is(selection?.anchor?.getNode())) return null 15739 15740 return rootNode.getChildAtIndex(selection.anchor.offset - 1) 15741} 15742 15743function $removeUnneededProvisionalParagraphs(rootNode) { 15744 for (const provisionalParagraph of $getAllProvisionalParagraphs(rootNode)) { 15745 provisionalParagraph.removeUnlessRequired(); 15746 } 15747} 15748 15749function $markAllProvisionalParagraphsDirty() { 15750 // Selection-driven visibility updates must not become standalone undo steps. 15751 Os(Jn); 15752 15753 for (const provisionalParagraph of $getAllProvisionalParagraphs()) { 15754 provisionalParagraph.markDirty(); 15755 } 15756} 15757 15758function $getAllProvisionalParagraphs(rootNode = Zo()) { 15759 return Ht$3(rootNode.getChildren(), $isProvisionalParagraphNode) 15760} 15761 15762// Registers code highlighting through the extension system so its node 15763// transforms exist before the initial editor state is applied. Registering 15764// after editor creation misses code blocks loaded from the initial value: 15765// their transform pass has already run, and Lexical's catch-up dirtying 15766// only sees the committed (still empty) state. 15767class CodeHighlightingExtension extends LexxyExtension { 15768 get enabled() { 15769 return this.editorElement.supportsRichText 15770 } 15771 15772 get lexicalExtension() { 15773 return dc({ 15774 name: "lexxy/code-highlighting", 15775 register(editor) { 15776 return L$1(editor, buildHighlightPreservingTokenizer(editor)) 15777 } 15778 }) 15779 } 15780} 15781 15782const TRIX_LANGUAGE_ATTR = "language"; 15783 15784class TrixContentExtension extends LexxyExtension { 15785 15786 get enabled() { 15787 return this.editorElement.supportsRichText 15788 } 15789 15790 get lexicalExtension() { 15791 return dc({ 15792 name: "lexxy/trix-content", 15793 html: { 15794 import: { 15795 em: (element) => onlyStyledElements(element, { 15796 conversion: extendTextNodeConversion("i", $applyHighlightStyle), 15797 priority: 1 15798 }), 15799 span: (element) => onlyStyledElements(element, { 15800 conversion: extendTextNodeConversion("mark", $applyHighlightStyle), 15801 priority: 1 15802 }), 15803 strong: (element) => onlyStyledElements(element, { 15804 conversion: extendTextNodeConversion("b", $applyHighlightStyle), 15805 priority: 1 15806 }), 15807 del: () => ({ 15808 conversion: extendTextNodeConversion("s", $applyStrikethrough, $applyHighlightStyle), 15809 priority: 1 15810 }), 15811 pre: (element) => onlyPreLanguageElements(element, { 15812 conversion: extendConversion(z$1, "pre", $applyLanguage), 15813 priority: 1 15814 }) 15815 } 15816 } 15817 }) 15818 } 15819} 15820 15821function onlyStyledElements(element, conversion) { 15822 const elementHighlighted = element.style.color !== "" || element.style.backgroundColor !== ""; 15823 return elementHighlighted ? conversion : null 15824} 15825 15826function $applyStrikethrough(textNode) { 15827 if (!textNode.hasFormat("strikethrough")) textNode.toggleFormat("strikethrough"); 15828 return textNode 15829} 15830 15831function onlyPreLanguageElements(element, conversion) { 15832 return element.hasAttribute(TRIX_LANGUAGE_ATTR) ? conversion : null 15833} 15834 15835function $applyLanguage(conversionOutput, element) { 15836 const language = a(element.getAttribute(TRIX_LANGUAGE_ATTR)); 15837 conversionOutput.node.setLanguage(language); 15838} 15839 15840class WrappedTableNode extends vn { 15841 $config() { 15842 return this.config("wrapped_table_node", { extends: vn }) 15843 } 15844 15845 static importDOM() { 15846 return super.importDOM() 15847 } 15848 15849 canInsertTextBefore() { 15850 return false 15851 } 15852 15853 canInsertTextAfter() { 15854 return false 15855 } 15856 15857 exportDOM(editor) { 15858 const superExport = super.exportDOM(editor); 15859 15860 return { 15861 ...superExport, 15862 after: (tableElement) => { 15863 if (superExport.after) { 15864 tableElement = superExport.after(tableElement); 15865 const clonedTable = tableElement.cloneNode(true); 15866 const wrappedTable = createElement("figure", { className: "lexxy-content__table-wrapper" }, clonedTable.outerHTML); 15867 return wrappedTable 15868 } 15869 15870 return tableElement 15871 } 15872 } 15873 } 15874} 15875 15876class TablesExtension extends LexxyExtension { 15877 15878 get enabled() { 15879 return this.editorElement.supportsRichText 15880 } 15881 15882 get allowedElements() { 15883 return [ "figure", "tbody" ] 15884 } 15885 15886 get lexicalExtension() { 15887 return dc({ 15888 name: "lexxy/tables", 15889 nodes: [ 15890 WrappedTableNode, 15891 { 15892 replace: vn, 15893 with: () => new WrappedTableNode(), 15894 withKlass: WrappedTableNode 15895 }, 15896 Ee$1, 15897 He$1 15898 ], 15899 register(editor) { 15900 Nn(editor); 15901 15902 return Cc( 15903 Wn(editor), 15904 15905 // Lexxy registers extensions before setRootElement(), but table 15906 // drag-selection needs a root before wiring its pointer handlers. 15907 editor.registerRootListener((rootElement) => { 15908 if (rootElement) { 15909 return $n(editor, true) 15910 } 15911 }), 15912 15913 // A table in Lexxy is a Lexxy table: cell shading can't be set in the 15914 // editor, so any cell background only ever comes from foreign content 15915 // (pasted spreadsheets, loaded documents). Normalize every cell to no 15916 // background so it adopts the current theme. This also clears 15917 // Lexical's hardcoded default header background (Lexical #8089). 15918 editor.registerNodeTransform(Ee$1, (node) => { 15919 if (node.getBackgroundColor() !== "") { 15920 node.setBackgroundColor(""); 15921 } 15922 }), 15923 15924 // Bug fix: Fix column header states (Lexical #8090) 15925 editor.registerNodeTransform(Ee$1, (node) => { 15926 const headerState = node.getHeaderStyles(); 15927 15928 if (headerState !== Ae$1.ROW) return 15929 15930 const rowParent = node.getParent(); 15931 const tableNode = rowParent?.getParent(); 15932 if (!tableNode) return 15933 15934 const rows = tableNode.getChildren(); 15935 const cellIndex = rowParent.getChildren().indexOf(node); 15936 15937 const cellsInRow = rowParent.getChildren(); 15938 const isHeaderRow = cellsInRow.every(cell => 15939 cell.getHeaderStyles() !== Ae$1.NO_STATUS 15940 ); 15941 15942 const isHeaderColumn = rows.every(row => { 15943 const cell = row.getChildren()[cellIndex]; 15944 return cell && cell.getHeaderStyles() !== Ae$1.NO_STATUS 15945 }); 15946 15947 let newHeaderState = Ae$1.NO_STATUS; 15948 15949 if (isHeaderRow) newHeaderState |= Ae$1.ROW; 15950 if (isHeaderColumn) newHeaderState |= Ae$1.COLUMN; 15951 15952 if (newHeaderState !== headerState) { 15953 node.setHeaderStyles(newHeaderState, Ae$1.BOTH); 15954 } 15955 }), 15956 15957 editor.registerCommand("insertTableRowAfter", () => { 15958 nt(true); 15959 }, oo), 15960 15961 editor.registerCommand("insertTableRowBefore", () => { 15962 nt(false); 15963 }, oo), 15964 15965 editor.registerCommand("insertTableColumnAfter", () => { 15966 st(true); 15967 }, oo), 15968 15969 editor.registerCommand("insertTableColumnBefore", () => { 15970 st(false); 15971 }, oo), 15972 15973 editor.registerCommand("deleteTableRow", () => { 15974 ut(); 15975 }, oo), 15976 15977 editor.registerCommand("deleteTableColumn", () => { 15978 dt(); 15979 }, oo), 15980 15981 editor.registerCommand("deleteTable", () => { 15982 const selection = Qr(); 15983 if (!Fr(selection)) return false 15984 hn(selection.anchor.getNode())?.remove(); 15985 }, oo) 15986 ) 15987 } 15988 }) 15989 } 15990} 15991 15992const MIME_TYPE$1 = "application/x-lexxy-node-key"; 15993 15994class AttachmentDragAndDrop { 15995 #editor 15996 #draggedNodeKey = null 15997 #rafId = null 15998 #draggingRafId = null 15999 #listeners = new ListenerBin() 16000 16001 constructor(editor) { 16002 this.#editor = editor; 16003 16004 // Register Lexical commands at HIGH priority to intercept before the 16005 // base @lexical/rich-text handlers (which return true and consume the events). 16006 this.#listeners.track( 16007 editor.registerCommand(Be$2, (event) => this.#handleDragStart(event), so), 16008 editor.registerCommand(ze$2, (event) => this.#handleDrop(event), so), 16009 ); 16010 16011 // Use a root listener to register DOM-level dragover/dragend handlers 16012 // (these events need throttled rAF handling that works better as DOM listeners). 16013 this.#listeners.track(editor.registerRootListener((root, prevRoot) => { 16014 if (prevRoot) { 16015 prevRoot.removeEventListener("dragover", this.#onDragOver); 16016 prevRoot.removeEventListener("dragend", this.#onDragEnd); 16017 } 16018 if (root) { 16019 root.addEventListener("dragover", this.#onDragOver); 16020 root.addEventListener("dragend", this.#onDragEnd); 16021 } 16022 })); 16023 } 16024 16025 destroy() { 16026 this.#cleanup(); 16027 this.#listeners.dispose(); 16028 } 16029 16030 // -- Event handlers -------------------------------------------------------- 16031 16032 #handleDragStart(event) { 16033 if (event.target.closest?.("textarea")) return false 16034 16035 const figure = event.target.closest?.("figure.attachment[data-lexical-node-key]"); 16036 if (!figure) return false 16037 16038 this.#draggedNodeKey = figure.dataset.lexicalNodeKey; 16039 event.dataTransfer.setData(MIME_TYPE$1, this.#draggedNodeKey); 16040 event.dataTransfer.effectAllowed = "move"; 16041 16042 // Add dragging class after a tick so it doesn't affect the drag image 16043 this.#draggingRafId = requestAnimationFrame(() => { 16044 this.#draggingRafId = null; 16045 figure.classList.add("lexxy-dragging"); 16046 }); 16047 16048 return true 16049 } 16050 16051 #onDragOver = (event) => { 16052 if (!this.#draggedNodeKey) return 16053 16054 event.preventDefault(); 16055 event.dataTransfer.dropEffect = "move"; 16056 16057 if (!this.#rafId) { 16058 this.#rafId = requestAnimationFrame(() => { 16059 this.#rafId = null; 16060 this.#updateDropTarget(event); 16061 }); 16062 } 16063 } 16064 16065 #handleDrop(event) { 16066 if (!this.#draggedNodeKey) return false 16067 16068 event.preventDefault(); 16069 16070 const target = this.#resolveDropTarget(event); 16071 const draggedKey = this.#draggedNodeKey; 16072 this.#cleanup(); 16073 16074 if (target) { 16075 this.#performDrop(draggedKey, target); 16076 } 16077 return true 16078 } 16079 16080 #onDragEnd = () => { 16081 this.#cleanup(); 16082 } 16083 16084 // -- Drop target resolution ----------------------------------------------- 16085 16086 #updateDropTarget(event) { 16087 this.#clearDropIndicators(); 16088 16089 const target = this.#resolveDropTarget(event); 16090 if (!target) return 16091 16092 if (target.type === "gallery" || target.type === "gallery-reorder") { 16093 target.element.classList.add(`lexxy-drop-target--gallery-${target.position}`); 16094 } else if (target.type === "list-item") { 16095 target.element.classList.add(`lexxy-drop-target--list-${target.position}`); 16096 } else { 16097 target.element.classList.add(`lexxy-drop-target--block-${target.position}`); 16098 } 16099 } 16100 16101 #resolveDropTarget(event) { 16102 const element = document.elementFromPoint(event.clientX, event.clientY); 16103 if (!element) return null 16104 16105 const rootElement = this.#editor.getRootElement(); 16106 if (!rootElement || !rootElement.contains(element)) return null 16107 16108 // Check if hovering over a previewable image (for gallery merge or reorder) 16109 const targetFigure = element.closest("figure.attachment--preview[data-lexical-node-key]"); 16110 if (targetFigure && targetFigure.dataset.lexicalNodeKey !== this.#draggedNodeKey) { 16111 const targetGallery = targetFigure.closest(".attachment-gallery"); 16112 if (targetGallery) { 16113 // If the dragged image is in the same gallery, this is a reorder 16114 const draggedFigure = rootElement.querySelector(`[data-lexical-node-key="${this.#draggedNodeKey}"]`); 16115 if (draggedFigure && targetGallery.contains(draggedFigure)) { 16116 const position = this.#computeHorizontalPosition(targetFigure, event.clientX); 16117 return { type: "gallery-reorder", element: targetFigure, nodeKey: targetFigure.dataset.lexicalNodeKey, position } 16118 } 16119 } 16120 const position = this.#computeHorizontalPosition(targetFigure, event.clientX); 16121 return { type: "gallery", element: targetFigure, nodeKey: targetFigure.dataset.lexicalNodeKey, position } 16122 } 16123 16124 // Hovering over the dragged image itself inside a gallery â treat as no-op 16125 // to prevent fallthrough to the block handler, which would eject it from the gallery. 16126 if (targetFigure && targetFigure.closest(".attachment-gallery")) return null 16127 16128 // Check if hovering over a gallery's empty space (for reorder within gallery) 16129 const targetGallery = element.closest(".attachment-gallery"); 16130 if (targetGallery) { 16131 let galleryFigure = element.closest("figure.attachment[data-lexical-node-key]"); 16132 if (!galleryFigure) { 16133 galleryFigure = this.#findNearestFigureInGallery(targetGallery, event.clientX); 16134 } 16135 if (galleryFigure && galleryFigure.dataset.lexicalNodeKey !== this.#draggedNodeKey) { 16136 const position = this.#computeHorizontalPosition(galleryFigure, event.clientX); 16137 return { type: "gallery-reorder", element: galleryFigure, nodeKey: galleryFigure.dataset.lexicalNodeKey, position } 16138 } 16139 // Nearest figure is the dragged image â no-op to avoid block handler fallthrough 16140 if (galleryFigure) return null 16141 } 16142 16143 // Check if hovering over a list item (for list splitting) 16144 const listItem = element.closest("li"); 16145 if (listItem && rootElement.contains(listItem)) { 16146 const position = this.#computeVerticalPosition(listItem, event.clientY); 16147 return { type: "list-item", element: listItem, position } 16148 } 16149 16150 // Otherwise, find nearest block-level element for between-block insertion. 16151 // Normalize so each gap has exactly one indicator: prefer "after" on the 16152 // previous sibling, falling back to "before" only for the first block. 16153 const block = this.#findNearestBlock(element, rootElement, event.clientY); 16154 if (!block) return null 16155 16156 const position = this.#computeVerticalPosition(block, event.clientY); 16157 if (position === "before" && block.previousElementSibling) { 16158 return { type: "block", element: block.previousElementSibling, position: "after" } 16159 } 16160 return { type: "block", element: block, position } 16161 } 16162 16163 #findNearestBlock(element, rootElement, clientY) { 16164 let current = element; 16165 while (current && current !== rootElement) { 16166 if (current.parentElement === rootElement) return current 16167 current = current.parentElement; 16168 } 16169 16170 // elementFromPoint landed on the root itself (e.g. a margin gap between 16171 // blocks). Fall back to the nearest child by vertical distance. 16172 let nearest = null; 16173 let minDistance = Infinity; 16174 for (const child of rootElement.children) { 16175 const rect = child.getBoundingClientRect(); 16176 const distance = Math.min(Math.abs(clientY - rect.top), Math.abs(clientY - rect.bottom)); 16177 if (distance < minDistance) { 16178 minDistance = distance; 16179 nearest = child; 16180 } 16181 } 16182 return nearest 16183 } 16184 16185 #computeVerticalPosition(element, clientY) { 16186 const rect = element.getBoundingClientRect(); 16187 return clientY < rect.top + rect.height / 2 ? "before" : "after" 16188 } 16189 16190 #computeHorizontalPosition(element, clientX) { 16191 const rect = element.getBoundingClientRect(); 16192 return clientX < rect.left + rect.width / 2 ? "before" : "after" 16193 } 16194 16195 #findNearestFigureInGallery(gallery, clientX) { 16196 const figures = gallery.querySelectorAll("figure.attachment[data-lexical-node-key]"); 16197 let nearest = null; 16198 let minDistance = Infinity; 16199 for (const figure of figures) { 16200 const rect = figure.getBoundingClientRect(); 16201 const center = rect.left + rect.width / 2; 16202 const distance = Math.abs(clientX - center); 16203 if (distance < minDistance) { 16204 minDistance = distance; 16205 nearest = figure; 16206 } 16207 } 16208 return nearest 16209 } 16210 16211 // -- Drop indicator -------------------------------------------------------- 16212 16213 static #DROP_CLASSES = [ 16214 "lexxy-drop-target--gallery-before", "lexxy-drop-target--gallery-after", 16215 "lexxy-drop-target--list-before", "lexxy-drop-target--list-after", 16216 "lexxy-drop-target--block-before", "lexxy-drop-target--block-after", 16217 ] 16218 16219 #clearDropIndicators() { 16220 const rootElement = this.#editor.getRootElement(); 16221 if (!rootElement) return 16222 16223 for (const el of rootElement.querySelectorAll("[class*='lexxy-drop-target--']")) { 16224 el.classList.remove(...AttachmentDragAndDrop.#DROP_CLASSES); 16225 } 16226 } 16227 16228 // -- Node operations ------------------------------------------------------- 16229 16230 #performDrop(draggedKey, target) { 16231 const draggedNode = Yo(draggedKey); 16232 if (!draggedNode || !$isActionTextAttachmentNode(draggedNode)) return 16233 16234 if (target.type === "gallery") { 16235 this.#dropOntoImage(draggedNode, target.nodeKey, target.position); 16236 } else if (target.type === "gallery-reorder") { 16237 this.#reorderInGallery(draggedNode, target.nodeKey, target.position); 16238 } else if (target.type === "list-item") { 16239 this.#dropIntoList(draggedNode, target); 16240 } else { 16241 this.#dropBetweenBlocks(draggedNode, target); 16242 } 16243 16244 // Clear selection to prevent a second history entry. Lexical dispatches 16245 // SELECTION_CHANGE_COMMAND during commit for non-range selections, which 16246 // creates a separate update. Null selection avoids that dispatch entirely 16247 // and also prevents Firefox's follow-up selectionchange from dirtying nodes. 16248 es(null); 16249 } 16250 16251 #dropOntoImage(draggedNode, targetKey, position) { 16252 const targetNode = Yo(targetKey); 16253 if (!targetNode || !$isActionTextAttachmentNode(targetNode)) return 16254 if (draggedNode.is(targetNode)) return 16255 16256 draggedNode.remove(); 16257 16258 const gallery = $findOrCreateGalleryForImage(targetNode); 16259 if (gallery) { 16260 if (position === "before") { 16261 targetNode.insertBefore(draggedNode); 16262 } else { 16263 targetNode.insertAfter(draggedNode); 16264 } 16265 } 16266 } 16267 16268 #reorderInGallery(draggedNode, targetKey, position) { 16269 const targetNode = Yo(targetKey); 16270 if (!targetNode || draggedNode.is(targetNode)) return 16271 16272 draggedNode.remove(); 16273 16274 if (position === "before") { 16275 targetNode.insertBefore(draggedNode); 16276 } else { 16277 targetNode.insertAfter(draggedNode); 16278 } 16279 } 16280 16281 #dropIntoList(draggedNode, target) { 16282 const listItemNode = Go(target.element); 16283 if (!listItemNode || !pe$2(listItemNode)) return 16284 16285 const listNode = listItemNode.getParent(); 16286 if (!listNode || !Se$1(listNode)) return 16287 16288 const children = listNode.getChildren(); 16289 const index = children.indexOf(listItemNode); 16290 if (index === -1) return 16291 16292 const splitIndex = target.position === "before" ? index : index + 1; 16293 16294 draggedNode.remove(); 16295 16296 if (splitIndex === 0) { 16297 listNode.insertBefore(draggedNode); 16298 } else if (splitIndex >= children.length) { 16299 listNode.insertAfter(draggedNode); 16300 } else { 16301 const [ , listAfter ] = Us(listNode, splitIndex); 16302 listAfter.insertBefore(draggedNode); 16303 } 16304 } 16305 16306 #dropBetweenBlocks(draggedNode, target) { 16307 const targetNode = Go(target.element); 16308 if (!targetNode) return 16309 16310 const topLevelTarget = targetNode.getTopLevelElement?.() || targetNode; 16311 if (draggedNode.is(topLevelTarget)) return 16312 16313 draggedNode.remove(); 16314 16315 if (target.position === "before") { 16316 topLevelTarget.insertBefore(draggedNode); 16317 } else { 16318 topLevelTarget.insertAfter(draggedNode); 16319 } 16320 } 16321 16322 // -- Lifecycle helpers ----------------------------------------------------- 16323 16324 #cleanup() { 16325 this.#clearDropIndicators(); 16326 16327 if (this.#draggedNodeKey) { 16328 const rootElement = this.#editor.getRootElement(); 16329 if (rootElement) { 16330 const figure = rootElement.querySelector(`[data-lexical-node
16330-key="${this.#draggedNodeKey}"]`); 16331 figure?.classList.remove("lexxy-dragging"); 16332 } 16333 } 16334 16335 this.#draggedNodeKey = null; 16336 16337 if (this.#rafId) { 16338 cancelAnimationFrame(this.#rafId); 16339 this.#rafId = null; 16340 } 16341 16342 if (this.#draggingRafId) { 16343 cancelAnimationFrame(this.#draggingRafId); 16344 this.#draggingRafId = null; 16345 } 16346 } 16347} 16348 16349const ATTACHMENT_ATTRIBUTES = [ "alt", "caption", "content", "content-type", "data-direct-upload-id", 16350 "data-sgid", "filename", "filesize", "height", "presentation", "previewable", "sgid", "url", "width" ]; 16351 16352const UPLOADS_BUSY_MESSAGE = "Please wait for all files to upload"; 16353 16354class AttachmentsExtension extends LexxyExtension { 16355 #uploadsCount = 0 16356 16357 get enabled() { 16358 return this.editorElement.supportsAttachments 16359 } 16360 16361 get allowedElements() { 16362 return [ { tag: ActionTextAttachmentNode.TAG_NAME, attributes: ATTACHMENT_ATTRIBUTES } ] 16363 } 16364 16365 get lexicalExtension() { 16366 return dc({ 16367 name: "lexxy/action-text-attachments", 16368 nodes: [ 16369 ActionTextAttachmentNode, 16370 ActionTextAttachmentUploadNode, 16371 ImageGalleryNode 16372 ], 16373 register: (editor) => { 16374 const dragAndDrop = new AttachmentDragAndDrop(editor); 16375 16376 return Cc( 16377 editor.registerNodeTransform(ActionTextAttachmentNode, $extractAttachmentFromParagraph), 16378 editor.registerCommand(fe$4, $collapseIntoGallery, oo), 16379 editor.registerMutationListener(ActionTextAttachmentUploadNode, this.#handleUploadMutations.bind(this)), 16380 () => dragAndDrop.destroy() 16381 ) 16382 } 16383 }) 16384 } 16385 16386 #handleUploadMutations(mutations) { 16387 const previousUploadsCount = this.#uploadsCount; 16388 for (const [ key, mutation ] of mutations) { 16389 if (mutation === "created") { 16390 this.#uploadsCount++; 16391 } else if (mutation === "destroyed") { 16392 this.#uploadsCount--; 16393 this.editorElement.uploadRequests.abort(key); 16394 } 16395 } 16396 16397 if (this.#uploadsCount !== previousUploadsCount) { 16398 this.#setUploadsValidity(); 16399 } 16400 } 16401 16402 #setUploadsValidity() { 16403 if (this.#uploadsCount) { 16404 this.setEditorValidity({ customError: true }, UPLOADS_BUSY_MESSAGE); 16405 } else { 16406 this.setEditorValidity({}); 16407 } 16408 } 16409} 16410 16411// Decorator nodes can be wrapped in a Paragraph Node by Lexical when contained in a <div> 16412// We remove them, splitting the node as needed 16413function $extractAttachmentFromParagraph(attachmentNode) { 16414 const parentNode = attachmentNode.getParent(); 16415 if (!no(parentNode)) return 16416 16417 if (parentNode.getChildrenSize() === 1) { 16418 parentNode.replace(attachmentNode); 16419 } else { 16420 const index = attachmentNode.getIndexWithinParent(); 16421 const [ topParagraph, bottomParagraph ] = Us(parentNode, index); 16422 topParagraph.insertAfter(attachmentNode); 16423 16424 for (const p of [ topParagraph, bottomParagraph ]) { 16425 if (p.isEmpty()) p.remove(); 16426 } 16427 } 16428} 16429 16430function $collapseIntoGallery(backwards) { 16431 const anchor = Qr()?.anchor; 16432 if (!anchor) return false 16433 16434 if ($collapseAtGalleryEdge(anchor, backwards)) { 16435 return true 16436 } else if (backwards) { 16437 return $collapseAroundEmptyParagraph(anchor) 16438 || $moveSelectionBeforeGallery(anchor) 16439 } 16440 16441 return false 16442} 16443 16444function $collapseAroundEmptyParagraph(anchor) { 16445 const anchorNode = anchor.getNode(); 16446 if (!anchorNode) return false 16447 16448 const isWithinEmptyParagraph = no(anchorNode) && anchorNode.isEmpty(); 16449 const previousSibling = anchorNode.getPreviousSibling(); 16450 const topGallery = $findOrCreateGalleryForImage(previousSibling); 16451 const selectionIndex = topGallery?.getChildrenSize(); 16452 16453 if (isWithinEmptyParagraph && topGallery?.collapseWith(anchorNode.getNextSibling())) { 16454 topGallery.select(selectionIndex, selectionIndex); 16455 anchorNode.remove(); 16456 return true 16457 } else { 16458 return false 16459 } 16460} 16461 16462function $collapseAtGalleryEdge(anchor, backwards) { 16463 const anchorNode = anchor.getNode(); 16464 if (!$isImageGalleryNode(anchorNode)) return false 16465 16466 const isAtGalleryEdge = $isAtNodeEdge(anchor, backwards); 16467 const sibling = backwards ? anchorNode.getPreviousSibling() : anchorNode.getNextSibling(); 16468 16469 if (isAtGalleryEdge && anchorNode.collapseWith(sibling, backwards)) { 16470 const selectionOffset = backwards ? 1 : anchorNode.getChildrenSize() - 1; 16471 anchorNode.select(selectionOffset, selectionOffset); 16472 return true 16473 } else { 16474 return false 16475 } 16476} 16477 16478// Manual selection handling to prevent Lexical merging the gallery with a <p> and unwrapping it 16479function $moveSelectionBeforeGallery(anchor) { 16480 const previousNode = anchor.getNode().getPreviousSibling(); 16481 if (!$isImageGalleryNode(anchor.getNode()) || !$isAtNodeEdge(anchor, true) || !previousNode) return false 16482 16483 if (ji(previousNode)) { 16484 // Handled by Lexxy decorator selection behavior 16485 return false 16486 } else if (previousNode.isEmpty()) { 16487 previousNode.remove(); 16488 } else { 16489 previousNode.selectEnd(); 16490 } 16491 16492 return true 16493} 16494
vendor: 71,654 bytes, lines 16495-18937
16495class EarlyEscapeCodeNode extends z$1 { 16496 $config() { 16497 return this.config("early_escape_code", { extends: z$1 }) 16498 } 16499 16500 static $fromSelection(selection) { 16501 const anchorNode = selection.anchor.getNode(); 16502 return At$2(anchorNode, EarlyEscapeCodeNode) 16503 || (anchorNode instanceof EarlyEscapeCodeNode ? anchorNode : null) 16504 } 16505 16506 insertNewAfter(selection, restoreSelection) { 16507 if (Es(jn) || !selection.isCollapsed()) { 16508 return super.insertNewAfter(selection, restoreSelection) 16509 } else if (this.#isCursorAtStart(selection)) { 16510 return this.#insertParagraphBefore() 16511 } else if (this.#isCursorOnWhitespaceOnlyLastLine(selection)) { 16512 return this.#insertBlankLineBelow(selection, restoreSelection) 16513 } else if (this.#isCursorOnEmptyLastLine(selection)) { 16514 return this.#escapeToNewParagraphAfter() 16515 } else { 16516 return super.insertNewAfter(selection, restoreSelection) 16517 } 16518 } 16519 16520 #isCursorAtStart(selection) { 16521 const { anchor } = selection; 16522 if (!$isAtNodeStart(anchor)) return false 16523 16524 const anchorNode = anchor.getNode(); 16525 return this.is(anchorNode) || this.getFirstChild()?.is(anchorNode) 16526 } 16527 16528 #isCursorOnEmptyLastLine(selection) { 16529 if (!$isCursorOnLastLine(selection)) return false 16530 16531 const textContent = this.getTextContent(); 16532 return textContent === "" || textContent.endsWith("\n") 16533 } 16534 16535 #isCursorOnWhitespaceOnlyLastLine(selection) { 16536 if (!$isCursorOnLastLine(selection)) return false 16537 16538 const textContent = this.getTextContent(); 16539 const lastNewlineIndex = textContent.lastIndexOf("\n"); 16540 const lastLine = lastNewlineIndex === -1 ? textContent : textContent.slice(lastNewlineIndex + 1); 16541 return lastLine.length > 0 && lastLine.trim() === "" 16542 } 16543 16544 #insertParagraphBefore() { 16545 this.insertBefore(eo()); 16546 return null 16547 } 16548 16549 #insertBlankLineBelow(selection, restoreSelection) { 16550 super.insertNewAfter(selection, restoreSelection); 16551 this.getLastChild().remove(); 16552 return null 16553 } 16554 16555 #escapeToNewParagraphAfter() { 16556 $trimTrailingBlankNodes(this); 16557 const paragraph = eo(); 16558 this.insertAfter(paragraph); 16559 return paragraph 16560 } 16561} 16562 16563class EarlyEscapeListItemNode extends ge$2 { 16564 $config() { 16565 return this.config("early_escape_listitem", { extends: ge$2 }) 16566 } 16567 16568 insertNewAfter(selection, restoreSelection) { 16569 if (this.#shouldEscape(selection)) { 16570 return this.#escapeFromList() 16571 } 16572 16573 return super.insertNewAfter(selection, restoreSelection) 16574 } 16575 16576 get #isInBlockquote() { 16577 return Boolean(At$2(this, At$1)) 16578 } 16579 16580 #shouldEscape(selection) { 16581 if (this.#isInPasteOperation() || !this.#isInBlockquote) { 16582 return false 16583 } else if ($isBlankNode(this)) { 16584 return true 16585 } else { 16586 const paragraph = At$2(selection.anchor.getNode(), Zi); 16587 return paragraph && $isBlankNode(paragraph) && pe$2(paragraph.getParent()) 16588 } 16589 } 16590 16591 #isInPasteOperation() { 16592 return Es(jn) 16593 } 16594 16595 #escapeFromList() { 16596 const parentList = this.getParent(); 16597 if (!parentList || !Se$1(parentList)) return 16598 16599 const blockquote = parentList.getParent(); 16600 const isInBlockquote = blockquote && Mt$2(blockquote); 16601 16602 if (isInBlockquote) { 16603 const hasNonEmptyListItems = this.getNextSiblings().some( 16604 sibling => pe$2(sibling) && !$isBlankNode(sibling) 16605 ); 16606 16607 if (hasNonEmptyListItems) { 16608 return this.#splitBlockquoteWithList() 16609 } 16610 } 16611 16612 const paragraph = eo(); 16613 parentList.insertAfter(paragraph); 16614 16615 this.remove(); 16616 return paragraph 16617 } 16618 16619 #splitBlockquoteWithList() { 16620 const splitQuotes = Us(this.getParent(), this.getIndexWithinParent()); 16621 this.remove(); 16622 16623 const middleParagraph = eo(); 16624 splitQuotes[0].insertAfter(middleParagraph); 16625 16626 splitQuotes.forEach($trimTrailingBlankNodes); 16627 16628 return middleParagraph 16629 } 16630 16631} 16632 16633class FormatEscapeExtension extends LexxyExtension { 16634 16635 get enabled() { 16636 return this.editorElement.supportsRichText 16637 } 16638 16639 get allowedElements() { 16640 return [ { tag: "ol", attributes: [ "start" ] }, { tag: "li", attributes: [ "value" ] } ] 16641 } 16642 16643 get lexicalExtension() { 16644 return dc({ 16645 name: "lexxy/format-escape", 16646 nodes: [ 16647 EarlyEscapeCodeNode, 16648 { replace: z$1, with: (node) => new EarlyEscapeCodeNode(node.getLanguage()), withKlass: EarlyEscapeCodeNode }, 16649 EarlyEscapeListItemNode, 16650 { replace: ge$2, with: () => new EarlyEscapeListItemNode(), withKlass: EarlyEscapeListItemNode }, 16651 ], 16652 register(editor) { 16653 return Cc( 16654 editor.registerCommand( 16655 he$3, 16656 () => $escapeFromBlockquote(), 16657 so 16658 ), 16659 editor.registerCommand( 16660 Ee$3, 16661 (event) => $handleArrowDownInCodeBlock(event), 16662 oo 16663 ), 16664 editor.registerNodeTransform(At$1, $ensureQuoteHasParagraphChild) 16665 ) 16666 } 16667 }) 16668 } 16669} 16670 16671function $escapeFromBlockquote() { 16672 return $escapeBeforeBlockquoteStart() || $escapeFromBlankBlockquoteParagraph() 16673} 16674 16675function $escapeBeforeBlockquoteStart() { 16676 const selection = Qr(); 16677 if (!Fr(selection) || !selection.isCollapsed() || selection.anchor.offset !== 0) return false 16678 16679 const paragraph = At$2(selection.anchor.getNode(), Zi); 16680 if (paragraph && !$isBlankNode(paragraph) && !paragraph.getPreviousSibling()) { 16681 const blockquote = paragraph.getParent(); 16682 if (Mt$2(blockquote)) { 16683 blockquote.insertBefore(eo()); 16684 return true 16685 } 16686 } 16687 16688 return false 16689} 16690 16691function $escapeFromBlankBlockquoteParagraph() { 16692 const anchorNode = Qr().anchor.getNode(); 16693 16694 const paragraph = At$2(anchorNode, Zi); 16695 if (!paragraph || !$isBlankNode(paragraph)) return false 16696 16697 const blockquote = paragraph.getParent(); 16698 if (Mt$2(blockquote)) { 16699 const nonEmptySiblings = paragraph.getNextSiblings().filter(sibling => !$isBlankNode(sibling)); 16700 16701 if (nonEmptySiblings.length > 0) { 16702 $splitQuoteNode(blockquote, paragraph); 16703 } else { 16704 blockquote.insertAfter(paragraph); 16705 paragraph.selectStart(); 16706 } 16707 16708 return true 16709 } 16710 16711 return false 16712} 16713 16714function $splitQuoteNode(node, paragraph) { 16715 const splitQuotes = Us(node, paragraph.getIndexWithinParent()); 16716 splitQuotes[0].insertAfter(paragraph); 16717 splitQuotes.forEach($trimTrailingBlankNodes); 16718 paragraph.selectEnd(); 16719} 16720 16721function $handleArrowDownInCodeBlock(event) { 16722 const selection = Qr(); 16723 if (!Fr(selection) || !selection.isCollapsed()) return false 16724 16725 const codeNode = EarlyEscapeCodeNode.$fromSelection(selection); 16726 if (!codeNode) return false 16727 16728 if ($isCursorOnLastLine(selection) && !codeNode.getNextSibling()) { 16729 event?.preventDefault(); 16730 const paragraph = eo(); 16731 codeNode.insertAfter(paragraph); 16732 paragraph.selectEnd(); 16733 return true 16734 } 16735 16736 return false 16737} 16738 16739function $ensureQuoteHasParagraphChild(quoteNode) { 16740 if (!quoteNode.isEmpty()) return 16741 16742 quoteNode.append(eo()); 16743 if ($containsRangeSelection(quoteNode)) quoteNode.getFirstChild().select(); 16744} 16745 16746class LinkOpenerExtension extends LexxyExtension { 16747 get enabled() { 16748 return this.editorElement.supportsRichText 16749 } 16750 16751 get lexicalExtension() { 16752 return dc({ 16753 name: "lexxy/link-opener", 16754 register: (editor) => Cc( 16755 editor.registerCommand(se$5, this.#handleClick.bind(this), oo), 16756 registerEventListener(this.editorElement.editorContentElement, "auxclick", this.#handleAuxClick.bind(this)), 16757 registerEventListener(window, "keydown", this.#handleKey.bind(this)), 16758 registerEventListener(window, "keyup", this.#handleKey.bind(this)), 16759 registerEventListener(window, "focus", this.#handleFocus.bind(this)) 16760 ) 16761 }) 16762 } 16763 16764 #handleClick(event) { 16765 if (this.#isModified(event)) { 16766 return $openLink(event.target) 16767 } else { 16768 return false 16769 } 16770 } 16771 16772 #handleAuxClick(event) { 16773 if (event.button === 1) { 16774 this.editorElement.editor.read(() => $openLink(event.target)); 16775 } 16776 } 16777 16778 #handleKey(event) { 16779 this.#updateOpenableAttribute(event); 16780 } 16781 16782 // Chrome dispatches events without modifier keys *for a while* after changing tabs 16783 async #handleFocus() { 16784 await delay(200); 16785 this.editorElement.addEventListener("mousemove", this.#updateOpenableAttribute.bind(this), { once: true }); 16786 } 16787 16788 #updateOpenableAttribute(event) { 16789 this.editorElement.toggleAttribute("data-links-openable", this.#isModified(event)); 16790 } 16791 16792 #isModified(event) { 16793 return lt$2 ? event.metaKey : event.ctrlKey 16794 } 16795} 16796 16797function $openLink(target) { 16798 const node = Go(target); 16799 const linkNode = dl(node, z$5); 16800 if (linkNode) { 16801 const url = linkNode.sanitizeUrl(linkNode.getURL()); 16802 window.open(url, "_blank", "noopener,noreferrer"); 16803 return true 16804 } else { 16805 return false 16806 } 16807} 16808 16809class PreventLexicalTripleClickExtension extends LexxyExtension { 16810 get lexicalExtension() { 16811 return dc({ 16812 name: "lexxy/prevent-lexical-triple-click", 16813 register: (editor) => editor.registerRootListener((rootElement) => { 16814 if (rootElement) { 16815 return registerEventListener( 16816 rootElement, 16817 "click", 16818 this.#handleTripleClick.bind(this), 16819 { capture: true } 16820 ) 16821 } 16822 }) 16823 }) 16824 } 16825 16826 // Stop propagation of the triple-click to prevent Lexical's handler from running. 16827 // 16828 // Lexical's onClick handler implements a triple-click handler that is trivial/anemic/naïve. The 16829 // intention of the change, made in facebook/lexical#4512, seems to be to deal with browsers' 16830 // "overselection" behavior, where a triple-click selection might end at offset 0 of the following 16831 // block, which can cause issues when transforming the selection. But the implementation breaks 16832 // many common real-world use cases and Lexxy does not demonstrate the behavior it's intended to 16833 // work around (in headers or tables). 16834 #handleTripleClick(event) { 16835 if (event.detail === 3) { 16836 event.stopPropagation(); 16837 } 16838 } 16839} 16840 16841function caretRect(node, offset) { 16842 const range = document.createRange(); 16843 range.setStart(node, offset); 16844 range.collapse(true); 16845 16846 const rect = range.getBoundingClientRect(); 16847 if (rect.height > 0) { 16848 return rect 16849 } else { 16850 return null 16851 } 16852} 16853 16854function caretFromPoint(clientX, clientY) { 16855 if (document.caretPositionFromPoint) { 16856 const position = document.caretPositionFromPoint(clientX, clientY); 16857 if (position) return { node: position.offsetNode, offset: position.offset } 16858 } else if (document.caretRangeFromPoint) { 16859 const range = document.caretRangeFromPoint(clientX, clientY); 16860 if (range) return { node: range.startContainer, offset: range.startOffset } 16861 } 16862 16863 return null 16864} 16865 16866const MIME_TYPE = "application/x-lexxy-custom-attachment-key"; 16867 16868// Custom inline attachments reorder by dropping at a text caret, unlike block 16869// attachments which insert between blocks or into galleries. 16870class CustomAttachmentDragAndDrop { 16871 #editor 16872 #draggedNodeKey = null 16873 #draggingRafId = null 16874 #dragOverRafId = null 16875 #dropIndicator = null 16876 #listeners = new ListenerBin() 16877 16878 constructor(editor) { 16879 this.#editor = editor; 16880 16881 // Register at HIGH priority to intercept before the base @lexical/rich-text 16882 // handlers, which consume drag events. The block-attachment handler also 16883 // registers here but bails for inline custom attachments, so we get our turn. 16884 this.#listeners.track( 16885 editor.registerCommand(Be$2, (event) => this.#handleDragStart(event), so), 16886 editor.registerCommand(ze$2, (event) => this.#handleDrop(event), so) 16887 ); 16888 16889 this.#listeners.track(editor.registerRootListener((root, prevRoot) => { 16890 if (prevRoot) { 16891 prevRoot.removeEventListener("dragover", this.#onDragOver); 16892 prevRoot.removeEventListener("dragend", this.#onDragEnd); 16893 } 16894 if (root) { 16895 root.addEventListener("dragover", this.#onDragOver); 16896 root.addEventListener("dragend", this.#onDragEnd); 16897 } 16898 })); 16899 } 16900 16901 destroy() { 16902 this.#cleanup(); 16903 this.#dropIndicator?.remove(); 16904 this.#dropIndicator = null; 16905 this.#listeners.dispose(); 16906 } 16907 16908 #handleDragStart(event) { 16909 const attachment = this.#customAttachmentElementFrom(event.target); 16910 if (!attachment) return false 16911 16912 this.#draggedNodeKey = attachment.dataset.lexicalNodeKey; 16913 event.dataTransfer.setData(MIME_TYPE, this.#draggedNodeKey); 16914 event.dataTransfer.effectAllowed = "move"; 16915 16916 this.#draggingRafId = requestAnimationFrame(() => { 16917 this.#draggingRafId = null; 16918 attachment.classList.add("lexxy-dragging"); 16919 }); 16920 16921 return true 16922 } 16923 16924 #onDragOver = (event) => { 16925 if (!this.#draggedNodeKey) return 16926 16927 event.preventDefault(); 16928 event.dataTransfer.dropEffect = "move"; 16929 16930 if (!this.#dragOverRafId) { 16931 this.#dragOverRafId = requestAnimationFrame(() => { 16932 this.#dragOverRafId = null; 16933 this.#updateDropIndicator(event); 16934 }); 16935 } 16936 } 16937 16938 #onDragEnd = () => { 16939 this.#cleanup(); 16940 } 16941 16942 #handleDrop(event) { 16943 if (!this.#draggedNodeKey) return false 16944 16945 event.preventDefault(); 16946 16947 const dropPoint = this.#resolveDropPoint(event); 16948 const draggedKey = this.#draggedNodeKey; 16949 this.#cleanup(); 16950 16951 if (dropPoint) { 16952 this.#moveAttachment(draggedKey, dropPoint); 16953 } 16954 16955 return true 16956 } 16957 16958 #resolveDropPoint(event) { 16959 const rootElement = this.#editor.getRootElement(); 16960 if (!rootElement) return null 16961 16962 const caret = caretFromPoint(event.clientX, event.clientY); 16963 if (!caret || !rootElement.contains(caret.node)) return null 16964 16965 // A caret on the root itself points between blocks. Mentions behave like text: 16966 // they only drop onto an existing line, so snap to the nearest one. 16967 if (caret.node === rootElement) { 16968 return this.#nearestLineCaret(rootElement, event.clientY) 16969 } 16970 16971 // When mentions sit next to each other with no text between them, the caret 16972 // lands inside the neighbouring decorator's DOM. Lexical can't resolve a point 16973 // inside a decorator to an editable position, and the cursor has no business 16974 // showing there anyway, so snap to just before or after that mention. 16975 const decorator = this.#decoratorElementContaining(caret.node); 16976 if (decorator) { 16977 return this.#dropPointBesideDecorator(decorator, event.clientX) 16978 } else { 16979 return caret 16980 } 16981 } 16982 16983 #nearestLineCaret(rootElement, clientY) { 16984 let nearestLine = null; 16985 let nearestDistance = Infinity; 16986 16987 for (const line of rootElement.children) { 16988 const rect = line.getBoundingClientRect(); 16989 const distance = Math.min(Math.abs(clientY - rect.top), Math.abs(clientY - rect.bottom)); 16990 if (distance < nearestDistance) { 16991 nearestDistance = distance; 16992 nearestLine = line; 16993 } 16994 } 16995 16996 if (!nearestLine) return null 16997 16998 const rect = nearestLine.getBoundingClientRect(); 16999 if (clientY < rect.top) { 17000 return { node: nearestLine, offset: 0 } 17001 } else { 17002 return { node: nearestLine, offset: nearestLine.childNodes.length } 17003 } 17004 } 17005 17006 #decoratorElementContaining(node) { 17007 const element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement; 17008 return element?.closest("[data-lexxy-decorator][data-lexical-node-key]") 17009 } 17010 17011 #dropPointBesideDecorator(decorator, clientX) { 17012 const rect = decorator.getBoundingClientRect(); 17013 const placement = clientX > rect.left + rect.width / 2 ? "after" : "before"; 17014 return { decoratorKey: decorator.dataset.lexicalNodeKey, placement } 17015 } 17016 17017 #moveAttachment(draggedKey, dropPoint) { 17018 this.#editor.update(() => { 17019 const draggedNode = Yo(draggedKey); 17020 if (!$isCustomActionTextAttachmentNode(draggedNode)) return 17021 17022 if (dropPoint.decoratorKey) { 17023 this.#moveBesideNode(draggedNode, dropPoint); 17024 } else { 17025 this.#moveToCaret(draggedNode, dropPoint); 17026 } 17027 }); 17028 } 17029 17030 #moveBesideNode(draggedNode, { decoratorKey, placement }) { 17031 const targetNode = Yo(decoratorKey); 17032 if (!targetNode || targetNode === draggedNode) return 17033 17034 draggedNode.remove(); 17035 if (placement === "after") { 17036 targetNode.insertAfter(draggedNode); 17037 } else { 17038 targetNode.insertBefore(draggedNode); 17039 } 17040 } 17041 17042 #moveToCaret(draggedNode, dropPoint) { 17043 const selection = Gr({ 17044 anchorNode: dropPoint.node, 17045 anchorOffset: dropPoint.offset, 17046 focusNode: dropPoint.node, 17047 focusOffset: dropPoint.offset 17048 }, this.#editor); 17049 if (!selection) return 17050 17051 es(selection); 17052 17053 draggedNode.remove(); 17054 selection.insertNodes([ draggedNode ]); 17055 } 17056 17057 #updateDropIndicator(event) { 17058 this.#hideCaret(); 17059 17060 const dropPoint = this.#resolveDropPoint(event); 17061 if (dropPoint) this.#showCaret(this.#caretRectFor(dropPoint)); 17062 } 17063 17064 #caretRectFor(dropPoint) { 17065 if (dropPoint.decoratorKey) { 17066 return this.#decoratorEdgeRect(dropPoint) 17067 } 17068 17069 const { node, offset } = dropPoint; 17070 const rect = caretRect(node, offset); 17071 if (rect) return rect 17072 17073 // A blank line has no text to measure, so fall back to the line's own box. 17074 const line = node.nodeType === Node.TEXT_NODE ? node.parentElement : node; 17075 if (!line) return null 17076 17077 const lineRect = line.getBoundingClientRect(); 17078 return { left: lineRect.left, top: lineRect.top, height: lineRect.height } 17079 } 17080 17081 #decoratorEdgeRect({ decoratorKey, placement }) { 17082 const decorator = this.#editor.getRootElement()?.querySelector(`[data-lexical-node-key="${decoratorKey}"]`); 17083 if (!decorator) return null 17084 17085 const rect = decorator.getBoundingClientRect(); 17086 const left = placement === "after" ? rect.right : rect.left; 17087 return { left, top: rect.top, height: rect.height } 17088 } 17089 17090 #showCaret(rect) { 17091 if (!rect) return 17092 17093 const caret = this.#ensureCaretIndicator(); 17094 caret.style.blockSize = `${rect.height}px`; 17095 caret.style.insetInlineStart = `${rect.left}px`; 17096 caret.style.insetBlockStart = `${rect.top}px`; 17097 } 17098 17099 #ensureCaretIndicator() { 17100 this.#dropIndicator ||= createElement("div", { className: "lexxy-drop-caret" }); 17101 17102 this.#editorElement().appendChild(this.#dropIndicator); 17103 this.#dropIndicator.style.display = "block"; 17104 return this.#dropIndicator 17105 } 17106 17107 #editorElement() { 17108 return this.#editor.getRootElement().closest("lexxy-editor") 17109 } 17110 17111 #hideCaret() { 17112 if (this.#dropIndicator) this.#dropIndicator.style.display = "none"; 17113 } 17114 17115 #customAttachmentElementFrom(target) { 17116 return target?.closest?.("[data-lexxy-decorator][data-lexical-node-key]") 17117 } 17118 17119 #cleanup() { 17120 if (this.#draggedNodeKey) { 17121 const rootElement = this.#editor.getRootElement(); 17122 const attachment = rootElement?.querySelector(`[data-lexical-node-key="${this.#draggedNodeKey}"]`); 17123 attachment?.classList.remove("lexxy-dragging"); 17124 } 17125 17126 this.#hideCaret(); 17127 this.#draggedNodeKey = null; 17128 17129 if (this.#draggingRafId) { 17130 cancelAnimationFrame(this.#draggingRafId); 17131 this.#draggingRafId = null; 17132 } 17133 17134 if (this.#dragOverRafId) { 17135 cancelAnimationFrame(this.#dragOverRafId); 17136 this.#dragOverRafId = null; 17137 } 17138 } 17139} 17140 17141class CustomAttachmentDragAndDropExtension extends LexxyExtension { 17142 get enabled() { 17143 return this.editorElement.supportsRichText 17144 } 17145 17146 get lexicalExtension() { 17147 return dc({ 17148 name: "lexxy/custom-attachment-drag-and-drop", 17149 register: (editor) => { 17150 const dragAndDrop = new CustomAttachmentDragAndDrop(editor); 17151 return () => dragAndDrop.destroy() 17152 } 17153 }) 17154 } 17155} 17156 17157const LINE_SEPARATORS = /\r\n|[\n\r\u2028\u2029]/; 17158 17159// A literal line separator inside a text node renders as a break in the editor, or not at all, 17160// but never survives serialization to HTML. macOS text replacements deliver U+2028 LINE SEPARATOR, 17161// and other insertions can carry "\n", so however the text arrives, a transform converts whatever 17162// lands in a text node into line break nodes. 17163class LineSeparatorsExtension extends LexxyExtension { 17164 get lexicalExtension() { 17165 return this.defineExtension({ 17166 name: "lexxy/line-separators", 17167 register(editor) { 17168 return editor.registerNodeTransform(gr, $replaceLineSeparatorWithLineBreak) 17169 } 17170 }) 17171 } 17172} 17173 17174// Replaces the first separator only: the split leaves dirty text nodes behind, so Lexical re-runs 17175// the transform until none remain. 17176function $replaceLineSeparatorWithLineBreak(textNode) { 17177 const match = textNode.getTextContent().match(LINE_SEPARATORS); 17178 17179 if (match) { 17180 let separatorNode; 17181 if (match.index === 0) { 17182 [ separatorNode ] = textNode.splitText(match[0].length); 17183 } else { 17184 [ , separatorNode ] = textNode.splitText(match.index, match.index + match[0].length); 17185 } 17186 separatorNode.replace(or()); 17187 } 17188} 17189 17190class LexicalEditorElement extends HTMLElement { 17191 static formAssociated = true 17192 static debug = false 17193 static commands = [ "bold", "italic", "strikethrough" ] 17194 17195 static observedAttributes = [ "autocapitalize", "connected", "required" ] 17196 17197 #initialValue = "" 17198 #previousInternalFormValue = null 17199 17200 #initializeEventDispatched = false 17201 #editorInitializedDispatched = false 17202 #listeners = new ListenerBin() 17203 #disposables = [] 17204 #historyState = { undo: false, redo: false } 17205 17206 #validity = new Map() 17207 #validationTextArea = document.createElement("textarea") 17208 #uploadRequests 17209 17210 constructor() { 17211 super(); 17212 this.internals = this.attachInternals(); 17213 this.internals.role = "presentation"; 17214 } 17215 17216 get uploadRequests() { 17217 return this.#uploadRequests 17218 } 17219 17220 connectedCallback() { 17221 this.id ||= generateDomId("lexxy-editor"); 17222 this.config = new EditorConfiguration(this); 17223 this.extensions = new Extensions(this); 17224 this.#disposables.push(this.extensions); 17225 17226 this.editor = this.#createEditor(); 17227 this.#disposables.push(this.editor); 17228 this.#disposables.push(this.#listeners); 17229 17230 this.contents = new Contents(this); 17231 this.#disposables.push(this.contents); 17232 17233 this.selection = new Selection(this); 17234 this.#disposables.push(this.selection); 17235 17236 this.clipboard = new Clipboard(this); 17237 this.#disposables.push(this.clipboard); 17238 17239 this.adapter = new BrowserAdapter(); 17240 this.#uploadRequests = new UploadRequests(); 17241 17242 const commandDispatcher = CommandDispatcher.configureFor(this); 17243 this.#disposables.push(commandDispatcher); 17244 17245 this.#initialize(); 17246 17247 this.toggleAttribute("connected", true); 17248 17249 requestAnimationFrame(() => { 17250 this.#mountRoot(); 17251 this.#handleAutofocus(); 17252 this.#dispatchInitialize(); 17253 }); 17254 } 17255 17256 disconnectedCallback() { 17257 this.#initializeEventDispatched = false; 17258 this.#editorInitializedDispatched = false; 17259 17260 this.#previousInternalFormValue = null; 17261 this.valueBeforeDisconnect = this.value; 17262 17263 this.#clearCachedValues(); 17264 this.#reset(); // Prevent hangs with Safari when morphing 17265 } 17266 17267 attributeChangedCallback(name, oldValue, newValue) { 17268 if (typeof this[`${name}ChangedCallback`] === "function") { 17269 this[`${name}ChangedCallback`](oldValue, newValue); 17270 } 17271 } 17272 17273 autocapitalizeChangedCallback() { 17274 if (this.editorContentElement) { 17275 this.#transferAttributeToContentEditable(this.editorContentElement, "autocapitalize"); 17276 } 17277 } 17278 17279 connectedChangedCallback(oldValue, newValue) { 17280 if (this.isConnected && oldValue != null && oldValue !== newValue) { 17281 requestAnimationFrame(() => this.#reconnect()); 17282 } 17283 } 17284 17285 requiredChangedCallback() { 17286 if (this.isConnected) this.#requestValidityRefresh(); 17287 } 17288 17289 formResetCallback() { 17290 this.value = this.#initialValue; 17291 this.editor.dispatchCommand(Ye$1, undefined); 17292 } 17293 17294 toString() { 17295 return this.cachedStringValue ??= this.editor?.read(() => { 17296 return $getReadableTextContent(Zo()) 17297 }) 17298 } 17299 17300 get form() { 17301 return this.internals.form 17302 } 17303 17304 get name() { 17305 return this.getAttribute("name") 17306 } 17307 17308 get required() { 17309 return this.hasAttribute("required") 17310 } 17311 17312 get validity() { 17313 return this.internals.validity 17314 } 17315 17316 checkValidity() { 17317 return this.internals.checkValidity() 17318 } 17319 17320 reportValidity() { 17321 return this.internals.reportValidity() 17322 } 17323 17324 setElementValidity(key, flags, message) { 17325 this.#validity.set(key, { flags, message }); 17326 this.#requestValidityRefresh(); 17327 } 17328 17329 get toolbarElement() { 17330 if (!this.#hasToolbar) return null 17331 17332 this.toolbar ??= this.#findOrCreateDefaultToolbar(); 17333 return this.toolbar 17334 } 17335 17336 get baseExtensions() { 17337 return [ 17338 ProvisionalParagraphExtension, 17339 CodeHighlightingExtension, 17340 HighlightExtension, 17341 TrixContentExtension, 17342 TablesExtension, 17343 RewritableHistoryExtension, 17344 AttachmentsExtension, 17345 FormatEscapeExtension, 17346 LinkOpenerExtension, 17347 PreventLexicalTripleClickExtension, 17348 CustomAttachmentDragAndDropExtension, 17349 LineSeparatorsExtension 17350 ] 17351 } 17352 17353 get directUploadUrl() { 17354 return this.dataset.directUploadUrl 17355 } 17356 17357 get blobUrlTemplate() { 17358 return this.dataset.blobUrlTemplate 17359 } 17360 17361 get permittedAttachmentTypes() { 17362 const raw = this.config.get("permittedAttachmentTypes"); 17363 if (raw == null) { 17364 return null 17365 } else { 17366 const tokens = Array.isArray(raw) ? raw : String(raw).split(/\s+/); 17367 return Object.freeze(tokens.filter(t => t && t !== "false")) 17368 } 17369 } 17370 17371 permitsAttachmentContentType(contentType) { 17372 if (!this.supportsAttachments) { 17373 return false 17374 } else { 17375 const list = this.permittedAttachmentTypes; 17376 return list === null || list.includes(contentType) 17377 } 17378 } 17379 17380 acceptsFile(file) { 17381 return dispatch(this, "lexxy:file-accept", { file }, true) 17382 } 17383 17384 $generateNodesFromDOM(doc, { editor = this.editor } = {}) { 17385 let nodes = dt$1(editor, doc); 17386 if (Es(jn)) nodes = $convertInlineImageDataURIs(nodes, this); 17387 return filterDisallowedAttachmentNodes(nodes, this) 17388 } 17389 17390 get isEmpty() { 17391 return [ "<p><br></p>", "<p></p>", "" ].includes(this.value.trim()) 17392 } 17393 17394 get isBlank() { 17395 return this.isEmpty || this.toString().match(/^\s*$/g) !== null 17396 } 17397 17398 get hasOpenPrompt() { 17399 return this.querySelector(".lexxy-prompt-menu.lexxy-prompt-menu--visible") !== null 17400 } 17401 17402 get preset() { 17403 return this.getAttribute("preset") || "default" 17404 } 17405 17406 get supportsAttachments() { 17407 return this.config.get("attachments") 17408 } 17409 17410 get supportsMarkdown() { 17411 return this.supportsRichText && this.config.get("markdown") 17412 } 17413 17414 get supportsMultiLine() { 17415 return this.config.get("multiLine") && !this.isSingleLineMode 17416 } 17417 17418 get supportsRichText() { 17419 return this.config.get("richText") 17420 } 17421 17422 registerAdapter(adapter) { 17423 this.adapter = adapter; 17424 17425 if (!this.editor) return 17426 17427 this.#dispatchEditorInitialized(); 17428 this.#dispatchAttributesChange(); 17429 } 17430 17431 freezeSelection() { 17432 this.adapter.freeze(); 17433 } 17434 17435 thawSelection() { 17436 this.adapter.thaw(); 17437 } 17438 17439 dispatchAttributesChange() { 17440 this.#dispatchAttributesChange(); 17441 } 17442 17443 dispatchEditorInitialized() { 17444 this.#dispatchEditorInitialized(); 17445 } 17446 17447 // TODO: Deprecate `single-line` attribute 17448 get isSingleLineMode() { 17449 return this.hasAttribute("single-line") 17450 } 17451 17452 get contentTabIndex() { 17453 return parseInt(this.editorContentElement?.getAttribute("tabindex") ?? "0") 17454 } 17455 17456 focus() { 17457 // `editor.focus()` commits a reconciler update to position the cursor. 17458 // Skip if the contenteditable already owns focus â the update would be a 17459 // no-op but still triggers a full style/layout pass on pages with large 17460 // DOMs. 17461 if (this.#isContentFocused) return 17462 17463 this.editor.focus(() => this.#onFocus()); 17464 } 17465 17466 get #isContentFocused() { 17467 return !!this.editor && isEditorFocused(this.editor) 17468 } 17469 17470 get value() { 17471 return this.cachedValue ??= this.#readSanitizedEditorValue() 17472 } 17473 17474 set value(html) { 17475 const editorHasFocus = this.#isContentFocused; 17476 17477 this.editor.update(() => { 17478 if (editorHasFocus) { 17479 // Address Safari inconsistently placing the cursor in the contenteditable by forcing focus back onto the editor 17480 // Use direct `editor.focus` to bypass the pre-existing focus optimization and skip the callback 17481 Ms(() => this.editor.focus()); 17482 } else { 17483 Os(qn); 17484 } 17485 17486 17487 this.#setEditorHtml(html); 17488 this.#toggleEmptyStatus(); 17489 }, { discrete: true }); 17490 } 17491 17492 get canUndo() { 17493 return this.#historyState.undo 17494 } 17495 17496 get canRedo() { 17497 return this.#historyState.redo 17498 } 17499 17500 #readSanitizedEditorValue() { 17501 return this.editor?.read(() => { 17502 return this.sanitizer.sanitize(ht$1(this.editor, null)) 17503 }) ?? null 17504 } 17505 17506 #parseHtmlIntoLexicalNodes(html, { editor = this.editor } = {}) { 17507 if (!html) html = "<p></p>"; 17508 const nodes = this.$generateNodesFromDOM(parseHtml(`${html}`), { editor }); 17509 17510 return nodes 17511 .filter(this.#isNotWhitespaceOnlyNode) 17512 .map(this.#wrapTextNode) 17513 } 17514 17515 // Whitespace-only text nodes (e.g. "\n" between block elements like <div>) and stray line break 17516 // nodes are formatting artifacts from the HTML source. They can't be appended to the root node 17517 // and have no semantic meaning, so we strip them during import. 17518 #isNotWhitespaceOnlyNode(node) { 17519 if (sr(node)) return false 17520 if (Tr(node) && node.getTextContent().trim() === "") return false 17521 return true 17522 } 17523 17524 // Raw string values produce TextNodes which cannot be appended directly to the RootNode. 17525 // We wrap those in <p> 17526 #wrapTextNode(node) { 17527 if (!Tr(node)) return node 17528 17529 const paragraph = eo(); 17530 paragraph.append(node); 17531 return paragraph 17532 } 17533 17534 #initialize() { 17535 this.#registerComponents(); 17536 this.#handleEnter(); 17537 this.#registerFocusEvents(); 17538 this.#registerHistoryEvents(); 17539 this.#registerFileAcceptFilter(); 17540 this.#attachDebugHooks(); 17541 this.#attachToolbar(); 17542 this.#resetBeforeTurboCaches(); 17543 17544 this.#setInternalFormValue(this.value, { suppressEvent: true }); 17545 this.#synchronizeWithChanges(); 17546 } 17547 17548 #registerFileAcceptFilter() { 17549 this.#listeners.track( 17550 registerEventListener(this, "lexxy:file-accept", (event) => { 17551 if (!this.permitsAttachmentContentType(event.detail.file.type)) { 17552 event.preventDefault(); 17553 } 17554 }) 17555 ); 17556 } 17557 17558 #createEditor() { 17559 this.editorContentElement ||= this.#createEditorContentElement(); 17560 this.appendChild(this.editorContentElement); 17561 17562 const editor = oe$4({ 17563 name: "lexxy/core", 17564 namespace: "Lexxy", 17565 theme: theme, 17566 nodes: this.#lexicalNodes, 17567 html: { 17568 export: new Map([ [ gr, exportTextNodeDOM ], [ K$1, exportTextNodeDOM ] ]) 17569 }, 17570 $initialEditorState: (editor) => { 17571 this.#configureSanitizer(editor); 17572 this.#loadInitialValue(editor); 17573 }, 17574 }, 17575 ...this.extensions.lexicalExtensions 17576 ); 17577 17578 return editor 17579 } 17580 17581 // Toggling editable around setRootElement skips Lexical's DOM-selection sync, 17582 // which would otherwise steal focus from elsewhere on the page. 17583 #mountRoot() { 17584 this.editor.setEditable(false); 17585 this.editor.setRootElement(this.editorContentElement); 17586 this.editor.setEditable(true); 17587 } 17588 17589 get #lexicalNodes() { 17590 const nodes = [ CustomActionTextAttachmentNode ]; 17591 17592 if (this.supportsRichText) { 17593 nodes.push( 17594 At$1, 17595 It$1, 17596 me$2, 17597 ge$2, 17598 z$1, 17599 K$1, 17600 F$4, 17601 j$5, 17602 HorizontalDividerNode 17603 ); 17604 } 17605 17606 return nodes 17607 } 17608 17609 #createEditorContentElement() { 17610 const editorContentElement = createElement("div", { 17611 id: `${this.id}-content`, 17612 classList: "lexxy-editor__content", 17613 contenteditable: true, 17614 role: "textbox", 17615 "aria-multiline": true, 17616 "aria-label": this.#labelText, 17617 placeholder: this.getAttribute("placeholder") 17618 }); 17619 17620 this.#ariaAttributes.forEach(attribute => editorContentElement.setAttribute(attribute.name, attribute.value)); 17621 17622 this.#transferAttributeToContentEditable(editorContentElement, "autocapitalize"); 17623 this.#transferAttributeToContentEditable(editorContentElement, "tabindex", { defaultValue: 0, removeSource: true }); 17624 17625 return editorContentElement 17626 } 17627 17628 #transferAttributeToContentEditable(element, qualifiedName, { defaultValue = null, removeSource = false } = {}) { 17629 if (this.hasAttribute(qualifiedName)) { 17630 element.setAttribute(qualifiedName, this.getAttribute(qualifiedName)); 17631 } else if (defaultValue !== null) { 17632 element.setAttribute(qualifiedName, defaultValue); 17633 } else { 17634 element.removeAttribute(qualifiedName); 17635 } 17636 17637 if (removeSource) this.removeAttribute(qualifiedName); 17638 } 17639 17640 get #labelText() { 17641 return Array.from(this.internals.labels).map(label => label.textContent).join(" ") 17642 } 17643 17644 get #ariaAttributes() { 17645 return Array.from(this.attributes).filter(attribute => attribute.name.startsWith("aria-")) 17646 } 17647 17648 #setInternalFormValue(html, { suppressEvent = false } = {}) { 17649 const changed = html !== this.#previousInternalFormValue; 17650 17651 this.internals.setFormValue(html); 17652 this.#previousInternalFormValue = html; 17653 17654 if (changed && !suppressEvent) { 17655 dispatch(this, "lexxy:change"); 17656 } 17657 } 17658 17659 #loadInitialValue(editor) { 17660 const initialHtml = this.valueBeforeDisconnect || this.getAttribute("value") || "<p><br></p>"; 17661 17662 this.#initialValue = initialHtml; 17663 this.#setEditorHtml(initialHtml, { editor }); 17664 } 17665 17666 #setEditorHtml(html, { editor = this.editor } = { }) { 17667 Zo() 17668 .clear() 17669 .selectEnd() 17670 .insertNodes(this.#parseHtmlIntoLexicalNodes(html, { editor })); 17671 } 17672 17673 #resetBeforeTurboCaches() { 17674 this.#listeners.track( 17675 registerEventListener(document, "turbo:before-cache", this.#handleTurboBeforeCache) 17676 ); 17677 } 17678 17679 #handleTurboBeforeCache = (event) => { 17680 if (!this.closest("[data-turbo-permanent]")) { 17681 this.#reset(); 17682 } 17683 } 17684 17685 #synchronizeWithChanges() { 17686 this.#listeners.track(this.editor.registerUpdateListener(({ editorState }) => { 17687 this.#clearCachedValues(); 17688 this.#setInternalFormValue(this.value); 17689 this.#toggleEmptyStatus(); 17690 this.#requestValidityRefresh(); 17691 this.#dispatchAttributesChange(); 17692 })); 17693 } 17694 17695 async #requestValidityRefresh() { 17696 await nextFrame(); 17697 17698 if (this.isConnected) this.#refreshValidity(); 17699 } 17700 17701 #refreshValidity() { 17702 this.#refreshInternalValidity(); 17703 const { validity, message } = this.#calculateValidity(); 17704 this.internals.setValidity(validity, message, this.editorContentElement); 17705 } 17706 17707 #refreshInternalValidity() { 17708 this.#validationTextArea.required = this.required && this.isBlank; 17709 const flags = this.#validationTextArea.validity; 17710 const message = this.#validationTextArea.validationMessage; 17711 17712 this.#validity.set(this, { flags, message }); 17713 } 17714 17715 #calculateValidity() { 17716 const validity = {}; 17717 const messages = []; 17718 17719 for (const { flags, message } of this.#validity.values()) { 17720 // internal TextArea's ValidityState can contain `valid: true` 17721 if (flags.valid === true) continue 17722 17723 for (const flag in flags) { 17724 if (flags[flag]) { 17725 validity[flag] = true; 17726 messages.push(message); 17727 } 17728 } 17729 } 17730 17731 return { validity, message: messages.join("\n") } 17732 } 17733 17734 #clearCachedValues() { 17735 this.cachedValue = null; 17736 this.cachedStringValue = null; 17737 } 17738 17739 #registerComponents() { 17740 const registered = []; 17741 17742 if (this.supportsRichText) { 17743 registered.push( 17744 zt$2(this.editor), 17745 Ie$2(this.editor) 17746 ); 17747 this.#registerTableComponents(); 17748 this.#registerCodeLanguagePicker(); 17749 if (this.supportsMarkdown) { 17750 const transformers = [ ...te, HORIZONTAL_DIVIDER ]; 17751 registered.push( 17752 se$1(this.editor, transformers), 17753 registerMarkdownLeadingTagHandler(this.editor, transformers) 17754 ); 17755 } 17756 } else { 17757 registered.push(H$2(this.editor)); 17758 } 17759 17760 this.#listeners.track(...registered); 17761 } 17762 17763 #registerTableComponents() { 17764 let tableTools = this.querySelector("lexxy-table-tools"); 17765 tableTools ??= createElement("lexxy-table-tools"); 17766 this.append(tableTools); 17767 this.#disposables.push(tableTools); 17768 } 17769 17770 #registerCodeLanguagePicker() { 17771 let codeLanguagePicker = this.querySelector("lexxy-code-language-picker"); 17772 codeLanguagePicker ??= createElement("lexxy-code-language-picker"); 17773 this.append(codeLanguagePicker); 17774 this.#disposables.push(codeLanguagePicker); 17775 } 17776 17777 #handleEnter() { 17778 // We can't prevent these externally using regular keydown because Lexical handles it first. 17779 this.#listeners.track(this.editor.registerCommand( 17780 Oe$2, 17781 (event) => { 17782 // Prevent CTRL+ENTER 17783 if (event.ctrlKey || event.metaKey) { 17784 event.preventDefault(); 17785 return true 17786 } 17787 17788 // In single line mode, prevent ENTER 17789 if (!this.supportsMultiLine) { 17790 event.preventDefault(); 17791 return true 17792 } 17793 17794 return false 17795 }, 17796 oo 17797 )); 17798 } 17799 17800 #registerFocusEvents() { 17801 this.#listeners.track( 17802 registerEventListener(this, "focusin", this.#handleFocusIn), 17803 registerEventListener(this, "focusout", this.#handleFocusOut) 17804 ); 17805 } 17806 17807 #handleFocusIn(event) { 17808 if (this.#elementInEditorOrToolbar(event.target) && !this.currentlyFocused) { 17809 this.#dispatchAttributesChange(); 17810 dispatch(this, "lexxy:focus"); 17811 this.currentlyFocused = true; 17812 } 17813 } 17814 17815 #handleFocusOut(event) { 17816 if (!this.#elementInEditorOrToolbar(event.relatedTarget)) { 17817 dispatch(this, "lexxy:blur"); 17818 this.currentlyFocused = false; 17819 } 17820 } 17821 17822 #elementInEditorOrToolbar(element) { 17823 return this.contains(element) || this.toolbarElement?.contains(element) 17824 } 17825 17826 #onFocus() { 17827 if (this.isEmpty) { 17828 this.selection.placeCursorAtTheEnd(); 17829 } 17830 } 17831 17832 #handleAutofocus() { 17833 if (!document.querySelector(":focus")) { 17834 if (this.hasAttribute("autofocus") && document.querySelector("[autofocus]") === this) { 17835 this.focus(); 17836 } 17837 } 17838 } 17839 17840 #registerHistoryEvents() { 17841 this.#listeners.track( 17842 this.editor.registerCommand(He$2, (enabled) => { this.#historyState.undo = enabled; }, oo), 17843 this.editor.registerCommand(qe$2, (enabled) => { this.#historyState.redo = enabled; }, oo) 17844 ); 17845 } 17846 17847 #attachDebugHooks() { 17848 return 17849 } 17850 17851 #attachToolbar() { 17852 if (this.#hasToolbar) { 17853 this.toolbarElement.setEditor(this); 17854 if (typeof this.toolbarElement.dispose === "function") { 17855 this.#disposables.push(this.toolbarElement); 17856 } 17857 17858 this.extensions.initializeToolbars(); 17859 } 17860 } 17861 17862 #findOrCreateDefaultToolbar() { 17863 const toolbarConfig = this.config.get("toolbar"); 17864 if (typeof toolbarConfig === "string") { 17865 return document.getElementById(toolbarConfig) 17866 } else { 17867 return this.querySelector("lexxy-toolbar") ?? this.#createDefaultToolbar() 17868 } 17869 } 17870 17871 get #hasToolbar() { 17872 return this.supportsRichText && !!this.config.get("toolbar") 17873 } 17874 17875 #createDefaultToolbar() { 17876 const toolbar = createElement("lexxy-toolbar"); 17877 toolbar.innerHTML = LexicalToolbarElement.defaultTemplate; 17878 toolbar.setAttribute("data-attachments", this.supportsAttachments); // Drives toolbar CSS styles 17879 toolbar.configure(this.config.get("toolbar")); 17880 this.prepend(toolbar); 17881 return toolbar 17882 } 17883 17884 #toggleEmptyStatus() { 17885 this.classList.toggle("lexxy-editor--empty", this.isEmpty); 17886 } 17887 17888 #configureSanitizer(editor) { 17889 this.sanitizer = EditorSanitizer.register(editor, this.extensions.allowedElements); 17890 } 17891 17892 #dispatchAttributesChange() { 17893 let attributes = null; 17894 let linkHref = null; 17895 let highlight = null; 17896 let headingTag = null; 17897 17898 this.editor.getEditorState().read(() => { 17899 const selection = Qr(); 17900 if (!Fr(selection)) return 17901 17902 const format = this.selection.getFormat(); 17903 if (Object.keys(format).length === 0) return 17904 17905 const anchorNode = selection.anchor.getNode(); 17906 const linkNode = At$2(anchorNode, F$4); 17907 17908 attributes = { 17909 bold: { active: format.isBold, enabled: true }, 17910 italic: { active: format.isItalic, enabled: true }, 17911 strikethrough: { active: format.isStrikethrough, enabled: true }, 17912 code: { active: format.isInCode, enabled: true }, 17913 highlight: { active: format.isHighlight, enabled: true }, 17914 link: { active: format.isInLink, enabled: true }, 17915 quote: { active: format.isInQuote, enabled: true }, 17916 heading: { active: format.isInHeading, enabled: true }, 17917 "unordered-list": { active: format.isInList && format.listType === "bullet", enabled: true }, 17918 "ordered-list": { active: format.isInList && format.listType === "number", enabled: true }, 17919 undo: { active: false, enabled: this.canUndo }, 17920 redo: { active: false, enabled: this.canRedo } 17921 }; 17922 17923 linkHref = linkNode ? linkNode.getURL() : null; 17924 highlight = format.isHighlight ? getHighlightStyles(selection) : null; 17925 headingTag = format.headingTag ?? null; 17926 }); 17927 17928 if (attributes) { 17929 this.adapter.dispatchAttributesChange(attributes, linkHref, highlight, headingTag); 17930 } 17931 } 17932 17933 #dispatchEditorInitialized() { 17934 if (!this.adapter) return 17935 17936 this.#editorInitializedDispatched = true; 17937 17938 this.adapter.dispatchEditorInitialized({ 17939 highlightColors: this.#resolvedHighlightColors, 17940 headingFormats: this.#supportedHeadingFormats 17941 }); 17942 } 17943 17944 #dispatchInitialize() { 17945 if (this.isConnected && this.adapter) { 17946 if (!this.#initializeEventDispatched) { 17947 this.#initializeEventDispatched = true; 17948 dispatch(this, "lexxy:initialize"); 17949 } 17950 17951 if (!this.#editorInitializedDispatched) { 17952 this.#dispatchEditorInitialized(); 17953 } 17954 } 17955 } 17956 17957 get #resolvedHighlightColors() { 17958 const buttons = this.config.get("highlight.buttons"); 17959 if (!buttons) return null 17960 17961 const colors = this.#resolveColors("color", buttons.color || []); 17962 const backgroundColors = this.#resolveColors("background-color", buttons["background-color"] || []); 17963 return { colors, backgroundColors } 17964 } 17965 17966 get #supportedHeadingFormats() { 17967 if (!this.supportsRichText) return [] 17968 17969 const headings = this.config.get("headings"); 17970 return [ 17971 { label: "Normal", command: "setFormatParagraph", tag: null }, 17972 ...headings.map((tag, index) => ({ 17973 label: HeadingDropdown.labelFor(tag, index), 17974 command: HeadingDropdown.commandFor(index), 17975 tag 17976 })) 17977 ] 17978 } 17979 17980 // Builds one resolver element per CSS value inside a hidden container, attaches 17981 // the container in a single DOM write, then reads all computed values in one pass 17982 // â triggering at most one forced reflow. The previous implementation interleaved 17983 // setProperty/getComputedStyle/removeProperty on the same element, forcing a style 17984 // recalc on every iteration during editor initialization. 17985 #resolveColors(property, cssValues) { 17986 const container = document.createElement("span"); 17987 container.style.display = "none"; 17988 17989 const resolvers = cssValues.map(cssValue => { 17990 const element = document.createElement("span"); 17991 element.style.setProperty(property, cssValue); 17992 container.appendChild(element); 17993 return { element, name: cssValue } 17994 }); 17995 17996 styleResolverRoot().appendChild(container); 17997 17998 const resolved = resolvers.map(({ element, name }) => ({ 17999 name, 18000 value: window.getComputedStyle(element).getPropertyValue(property) 18001 })); 18002 18003 container.remove(); 18004 return resolved 18005 } 18006 18007 #reset() { 18008 this.#dispose(); 18009 this.#resetValidity(); 18010 this.#uploadRequests?.clear(); 18011 this.editorContentElement?.remove(); 18012 this.editorContentElement = null; 18013 18014 // Prevents issues with turbo morphing receiving an empty <lexxy-editor> which wipes 18015 // out the DOM for the tools, and the old toolbar reference will cause issues 18016 this.toolbar = null; 18017 } 18018 18019 #dispose() { 18020 while (this.#disposables.length) { 18021 this.#disposables.pop().dispose(); 18022 } 18023 } 18024 18025 #reconnect() { 18026 this.disconnectedCallback(); 18027 this.valueBeforeDisconnect = null; 18028 this.connectedCallback(); 18029 } 18030 18031 #resetValidity() { 18032 this.#validity = new Map(); 18033 } 18034} 18035 18036// Like $getRoot().getTextContent() but uses readable text for custom attachment nodes 18037// (e.g., mentions) instead of their single-character cursor placeholder. 18038function $getReadableTextContent(node) { 18039 if (node instanceof CustomActionTextAttachmentNode) { 18040 return node.getReadableTextContent() 18041 } 18042 18043 if (Wi(node)) { 18044 let text = ""; 18045 const children = node.getChildren(); 18046 for (let i = 0; i < children.length; i++) { 18047 const child = children[i]; 18048 const previousChild = children[i - 1]; 18049 18050 if (isAttachmentSpacerTextNode(child, previousChild, i, children.length)) continue 18051 18052 text += $getReadableTextContent(child); 18053 if (Wi(child) && i !== children.length - 1 && !child.isInline()) { 18054 text += "\n\n"; 18055 } 18056 } 18057 return text 18058 } 18059 18060 return node.getTextContent() 18061} 18062 18063class BaseSource { 18064 // Template method to override 18065 async buildListItems(filter = "") { 18066 return Promise.resolve([]) 18067 } 18068 18069 // Template method to override 18070 promptItemFor(listItem) { 18071 return null 18072 } 18073 18074 // Protected 18075 18076 buildListItemElementFor(promptItemElement) { 18077 const template = promptItemElement.querySelector("template[type='menu']"); 18078 const fragment = template.content.cloneNode(true); 18079 const listItemElement = createElement("li", { role: "option", id: generateDomId("prompt-item"), tabindex: "0" }); 18080 listItemElement.classList.add("lexxy-prompt-menu__item"); 18081 listItemElement.appendChild(fragment); 18082 return listItemElement 18083 } 18084 18085 async loadPromptItemsFromUrl(url) { 18086 try { 18087 const response = await fetch(url); 18088 const html = await response.text(); 18089 const promptItems = parseHtml(html).querySelectorAll("lexxy-prompt-item"); 18090 return Promise.resolve(Array.from(promptItems)) 18091 } catch (error) { 18092 return Promise.reject(error) 18093 } 18094 } 18095} 18096 18097const MAX_RENDERED_SUGGESTIONS$1 = 100; 18098 18099class LocalFilterSource extends BaseSource { 18100 async buildListItems(filter = "") { 18101 const promptItems = await this.fetchPromptItems(); 18102 return this.#buildListItemsFromPromptItems(promptItems, filter) 18103 } 18104 18105 // Template method to override 18106 async fetchPromptItems(filter) { 18107 return Promise.resolve([]) 18108 } 18109 18110 promptItemFor(listItem) { 18111 return this.promptItemByListItem.get(listItem) 18112 } 18113 18114 #buildListItemsFromPromptItems(promptItems, filter) { 18115 this.promptItemByListItem = new WeakMap(); 18116 18117 if (!filter) { 18118 return this.#buildAllListItems(promptItems) 18119 } 18120 18121 const matches = []; 18122 for (const promptItem of promptItems) { 18123 const searchableText = promptItem.getAttribute("search"); 18124 const position = filterMatchPosition(searchableText, filter); 18125 if (position >= 0) { 18126 matches.push({ promptItem, position }); 18127 } 18128 } 18129 18130 matches.sort((a, b) => a.position - b.position); 18131 18132 const listItems = []; 18133 for (const { promptItem } of matches) { 18134 if (listItems.length >= MAX_RENDERED_SUGGESTIONS$1) break 18135 const listItem = this.buildListItemElementFor(promptItem); 18136 this.promptItemByListItem.set(listItem, promptItem); 18137 listItems.push(listItem); 18138 } 18139 return listItems 18140 } 18141 18142 #buildAllListItems(promptItems) { 18143 const listItems = []; 18144 for (const promptItem of promptItems) { 18145 if (listItems.length >= MAX_RENDERED_SUGGESTIONS$1) break 18146 const listItem = this.buildListItemElementFor(promptItem); 18147 this.promptItemByListItem.set(listItem, promptItem); 18148 listItems.push(listItem); 18149 } 18150 return listItems 18151 } 18152} 18153 18154class InlinePromptSource extends LocalFilterSource { 18155 constructor(inlinePromptItems) { 18156 super(); 18157 this.inlinePromptItemElements = Array.from(inlinePromptItems); 18158 } 18159 18160 async fetchPromptItems() { 18161 return Promise.resolve(this.inlinePromptItemElements) 18162 } 18163} 18164 18165class DeferredPromptSource extends LocalFilterSource { 18166 constructor(url) { 18167 super(); 18168 this.url = url; 18169 18170 this.fetchPromptItems(); 18171 } 18172 18173 async fetchPromptItems() { 18174 this.promptItems ??= await this.loadPromptItemsFromUrl(this.url); 18175 18176 return Promise.resolve(this.promptItems) 18177 } 18178} 18179 18180const DEBOUNCE_INTERVAL = 200; 18181const MAX_RENDERED_SUGGESTIONS = 100; 18182 18183class RemoteFilterSource extends BaseSource { 18184 constructor(url) { 18185 super(); 18186 18187 this.baseURL = url; 18188 this.loadAndFilterListItems = debounceAsync(this.fetchFilteredListItems.bind(this), DEBOUNCE_INTERVAL); 18189 } 18190 18191 async buildListItems(filter = "") { 18192 return await this.loadAndFilterListItems(filter) 18193 } 18194 18195 promptItemFor(listItem) { 18196 return this.promptItemByListItem.get(listItem) 18197 } 18198 18199 async fetchFilteredListItems(filter) { 18200 const promptItems = await this.loadPromptItemsFromUrl(this.#urlFor(filter)); 18201 return this.#buildListItemsFromPromptItems(promptItems) 18202 } 18203 18204 #urlFor(filter) { 18205 const url = new URL(this.baseURL, window.location.origin); 18206 url.searchParams.append("filter", filter); 18207 return url.toString() 18208 } 18209 18210 #buildListItemsFromPromptItems(promptItems) { 18211 const listItems = []; 18212 this.promptItemByListItem = new WeakMap(); 18213 18214 for (const promptItem of promptItems) { 18215 if (listItems.length >= MAX_RENDERED_SUGGESTIONS) break 18216 18217 const listItem = this.buildListItemElementFor(promptItem); 18218 this.promptItemByListItem.set(listItem, promptItem); 18219 listItems.push(listItem); 18220 } 18221 18222 return listItems 18223 } 18224} 18225 18226const NOTHING_FOUND_DEFAULT_MESSAGE = "Nothing found"; 18227const FILTER_DEBOUNCE_INTERVAL = 50; 18228 18229// Start of line, or after a space or newline. 18230const DEFAULT_ONLY_AT_PATTERN = "^|[ \\n]"; 18231 18232class LexicalPromptElement extends HTMLElement { 18233 #globalListeners = new ListenerBin() 18234 #popoverListeners = new ListenerBin() 18235 #debouncedFilterOptions = debounce(() => this.#filterOptions(), FILTER_DEBOUNCE_INTERVAL) 18236 18237 constructor() { 18238 super(); 18239 this.showPopoverId = 0; 18240 } 18241 18242 static observedAttributes = [ "connected" ] 18243 18244 connectedCallback() { 18245 this.source = this.#createSource(); 18246 18247 this.#addTriggerListener(); 18248 this.#removePopoverBeforeTurboCaches(); 18249 this.toggleAttribute("connected", true); 18250 } 18251 18252 disconnectedCallback() { 18253 this.#popoverListeners.dispose(); 18254 this.#globalListeners.dispose(); 18255 this.source = null; 18256 this.#removePopover(); 18257 } 18258 18259 18260 attributeChangedCallback(name, oldValue, newValue) { 18261 if (name === "connected" && this.isConnected && oldValue != null && oldValue !== newValue) { 18262 requestAnimationFrame(() => this.#reconnect()); 18263 } 18264 } 18265 18266 get name() { 18267 return this.getAttribute("name") 18268 } 18269 18270 get trigger() { 18271 return this.getAttribute("trigger") 18272 } 18273 18274 get supportsSpaceInSearches() { 18275 return this.hasAttribute("supports-space-in-searches") 18276 } 18277 18278 get onlyAt() { 18279 return this.getAttribute("only-at") 18280 } 18281 18282 get verticalDirection() { 18283 return this.getAttribute("vertical-direction") 18284 } 18285 18286 get open() { 18287 return this.popoverElement?.classList?.contains("lexxy-prompt-menu--visible") 18288 } 18289 18290 get closed() { 18291 return !this.open 18292 } 18293 18294 get #doesSpaceSelect() { 18295 return !this.supportsSpaceInSearches 18296 } 18297 18298 #createSource() { 18299 const src = this.getAttribute("src"); 18300 if (src) { 18301 if (this.hasAttribute("remote-filtering")) { 18302 return new RemoteFilterSource(src) 18303 } else { 18304 return new DeferredPromptSource(src) 18305 } 18306 } else { 18307 return new InlinePromptSource(this.querySelectorAll("lexxy-prompt-item")) 18308 } 18309 } 18310 18311 #addTriggerListener() { 18312 if (!this.#promptContentTypePermitted) return 18313 18314 this.#popoverListeners.track(this.#editor.registerUpdateListener(({ editorState }) => { 18315 editorState.read(() => { 18316 if (this.#selection.isInsideCodeBlock) return 18317 18318 const { node, offset } = this.#selection.selectedNodeWithOffset(); 18319 if (!node) return 18320 18321 if (Tr(node)) { 18322 const fullText = node.getTextContent(); 18323 const triggerLength = this.trigger.length; 18324 18325 // Check if we have enough characters for the trigger 18326 if (offset >= triggerLength) { 18327 const textBeforeCursor = fullText.slice(offset - triggerLength, offset); 18328 18329 if (textBeforeCursor === this.trigger) { 18330 const textBeforeTrigger = $textBeforeOffset(node, offset - triggerLength); 18331 18332 if (this.#onlyAtRegExp.test(textBeforeTrigger)) { 18333 this.#popoverListeners.dispose(); 18334 this.#showPopover(); 18335 } 18336 } 18337 } 18338 } 18339 }); 18340 })); 18341 } 18342 18343 get #onlyAtRegExp() { 18344 return new RegExp(`(?:${this.onlyAt ?? DEFAULT_ONLY_AT_PATTERN})$`) 18345 } 18346 18347 get #promptContentTypePermitted() { 18348 // `insert-editable-text` prompts never create attachments, so the 18349 // editor's attachment support and content-type allowlist don't apply. 18350 if (this.hasAttribute("insert-editable-text")) return true 18351 18352 const el = this.#editorElement; 18353 if (!el.supportsAttachments) { 18354 return false 18355 } else { 18356 const templates = Array.from(this.querySelectorAll("template[type='editor']")); 18357 const types = templates.length 18358 ? templates.map(t => t.getAttribute("content-type") || this.#defaultPromptContentType) 18359 : [ this.#defaultPromptContentType ]; 18360 return types.some(t => el.permitsAttachmentContentType(t)) 18361 } 18362 } 18363 18364 #addCursorPositionListener() { 18365 this.#popoverListeners.track(this.#editor.registerUpdateListener(({ editorState }) => { 18366 if (this.closed) return 18367 18368 editorState.read(() => { 18369 if (this.#selection.isInsideCodeBlock) { 18370 this.#hidePopover(); 18371 return 18372 } 18373 18374 const { node, offset } = this.#selection.selectedNodeWithOffset(); 18375 if (!node) return 18376 18377 if (this.#cursorIsTypingSearchTerm(node, offset)) { 18378 if (!this.popoverElement.hasAttribute("data-anchored")) { 18379 this.#positionPopover(); 18380 } 18381 } else { 18382 this.#hidePopover(); 18383 } 18384 }); 18385 })); 18386 } 18387 18388 // The popover should stay open only while the cursor sits at the end of the 18389 // trigger and its search term. When the cursor moves away â before the 18390 // trigger, or past the token into later text â the text between the trigger 18391 // and the cursor breaks that run and we dismiss. A newline always breaks the 18392 // run; a space breaks it only for triggers that don't support spaces in 18393 // searches, since those that do (e.g. `person:`) expect multi-word terms. 18394 #cursorIsTypingSearchTerm(node, offset) { 18395 if (!Tr(node) || offset === 0) return false 18396 18397 const textBeforeCursor = node.getTextContent().slice(0, offset); 18398 const lastTriggerIndex = textBeforeCursor.lastIndexOf(this.trigger); 18399 if (lastTriggerIndex === -1) return false 18400 18401 const searchTerm = textBeforeCursor.slice(lastTriggerIndex + this.trigger.length); 18402 const breakPattern = this.supportsSpaceInSearches ? /\n/ : /[ \n]/; 18403 return !breakPattern.test(searchTerm) 18404 } 18405 18406 get #editor() { 18407 return this.#editorElement.editor 18408 } 18409 18410 get #editorElement() { 18411 return this.closest("lexxy-editor") 18412 } 18413 18414 get #selection() { 18415 return this.#editorElement.selection 18416 } 18417 18418 async #showPopover() { 18419 const showId = ++this.showPopoverId; 18420 this.popoverElement ??= await this.#buildPopover(); 18421 if (this.showPopoverId !== showId) return 18422 18423 this.#resetPopoverPosition(); 18424 await this.#filterOptions(); 18425 if (this.showPopoverId !== showId) return 18426 18427 this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", true); 18428 this.#selectFirstOption(); 18429 18430 this.#popoverListeners.track( 18431 registerEventListener(this.#editorElement, "keydown", this.#handleKeydownOnPopover), 18432 registerEventListener(this.#editorElement, "lexxy:change", this.#debouncedFilterOptions) 18433 ); 18434 18435 this.#registerKeyListeners(); 18436 this.#addCursorPositionListener(); 18437 } 18438 18439 #registerKeyListeners() { 18440 // We can't use a regular keydown for Enter as Lexical handles it first 18441 this.#popoverListeners.track( 18442 this.#editor.registerCommand(Oe$2, this.#handleSelectedOption.bind(this), lo), 18443 this.#editor.registerCommand(Fe$2, this.#handleSelectedOption.bind(this), lo) 18444 ); 18445 18446 if (this.#doesSpaceSelect) { 18447 this.#popoverListeners.track(this.#editor.registerCommand(Me$2, this.#handleSelectedOption.bind(this), lo)); 18448 this.#popoverListeners.track(this.#editor.registerCommand(ce$4, this.#handleInputCommand.bind(this), lo)); 18449 } 18450 18451 // Register arrow keys with CRITICAL priority to prevent Lexical's selection handlers from running 18452 this.#popoverListeners.track( 18453 this.#editor.registerCommand(we$1, this.#handleArrowUp.bind(this), lo), 18454 this.#editor.registerCommand(Ee$3, this.#handleArrowDown.bind(this), lo) 18455 ); 18456 } 18457 18458 #handleArrowUp(event) { 18459 this.#moveSelectionUp(); 18460 event.preventDefault(); 18461 return true 18462 } 18463 18464 #handleArrowDown(event) { 18465 this.#moveSelectionDown(); 18466 event.preventDefault(); 18467 return true 18468 } 18469 18470 #selectFirstOption() { 18471 const firstOption = this.#listItemElements[0]; 18472 18473 if (firstOption) { 18474 this.#selectOption(firstOption); 18475 } 18476 } 18477 18478 get #listItemElements() { 18479 return Array.from(this.popoverElement.querySelectorAll(".lexxy-prompt-menu__item")) 18480 } 18481 18482 #selectOption(listItem, { scrollIntoView = false } = {}) { 18483 this.#clearListItemSelection(); 18484 listItem.toggleAttribute("aria-selected", true); 18485 if (scrollIntoView) { 18486 listItem.scrollIntoView({ block: "nearest", container: "nearest", behavior: "smooth" }); 18487 } 18488 18489 this.#setEditorAssociationAttribute("aria-controls", this.popoverElement.id); 18490 this.#setEditorAssociationAttribute("aria-activedescendant", listItem.id); 18491 this.#setEditorAssociationAttribute("aria-haspopup", "listbox"); 18492 } 18493 18494 #clearListItemSelection() { 18495 this.#listItemElements.forEach((item) => { item.toggleAttribute("aria-selected", false); }); 18496 } 18497 18498 #clearSelection() { 18499 this.#clearListItemSelection(); 18500 this.#editorContentElement.removeAttribute("aria-controls"); 18501 this.#editorContentElement.removeAttribute("aria-activedescendant"); 18502 this.#editorContentElement.removeAttribute("aria-haspopup"); 18503 } 18504 18505 #setEditorAssociationAttribute(name, value) { 18506 if (this.#editorContentElement.getAttribute(name) !== value) { 18507 this.#editorContentElement.setAttribute(name, value); 18508 } 18509 } 18510 18511 // Right after a Turbo history restore the editor reconnects before the DOM selection 18512 // is re-established, so the cursor geometry is momentarily unavailable. Anchoring then 18513 // would pin the menu to the editor's left edge for the rest of the open cycle, so we 18514 // skip it and let a later reposition anchor it once the selection is ready. The menu 18515 // stays hidden until anchored (see the `[data-anchored]` rule in the stylesheet). 18516 #positionPopover() { 18517 const cursorPosition = this.#selection.cursorPosition; 18518 if (!cursorPosition) return 18519 18520 const { x, y, fontSize } = cursorPosition; 18521 const editorRect = this.#editorElement.getBoundingClientRect(); 18522 const contentRect = this.#editorContentElement.getBoundingClientRect(); 18523 const verticalOffset = contentRect.top - editorRect.top; 18524 18525 if (!this.popoverElement.hasAttribute("data-anchored")) { 18526 this.#setPopoverOffsetX(x); 18527 this.#setPopoverOffsetY(y + verticalOffset); 18528 this.popoverElement.toggleAttribute("data-anchored", true); 18529 } 18530 18531 const popoverRect = this.popoverElement.getBoundingClientRect(); 18532 18533 if (popoverRect.right > editorRect.right) { 18534 this.popoverElement.toggleAttribute("data-clipped-at-right", true); 18535 } 18536 18537 const forceTop = this.verticalDirection === "top"; 18538 const forceBottom = this.verticalDirection === "bottom"; 18539 const overflowsWindow = popoverRect.bottom > window.innerHeight; 18540 18541 if (!forceBottom && (forceTop || overflowsWindow)) { 18542 this.#setPopoverOffsetY(contentRect.height - y + fontSize); 18543 this.popoverElement.toggleAttribute("data-clipped-at-bottom", true); 18544 } 18545 } 18546 18547 #setPopoverOffsetX(value) { 18548 this.popoverElement.style.setProperty("--lexxy-prompt-offset-x", `${value}px`); 18549 } 18550 18551 #setPopoverOffsetY(value) { 18552 this.popoverElement.style.setProperty("--lexxy-prompt-offset-y", `${value}px`); 18553 } 18554 18555 #resetPopoverPosition() { 18556 this.popoverElement.removeAttribute("data-clipped-at-bottom"); 18557 this.popoverElement.removeAttribute("data-clipped-at-right"); 18558 this.popoverElement.removeAttribute("data-anchored"); 18559 } 18560 18561 async #hidePopover() { 18562 this.showPopoverId++; 18563 this.#clearSelection(); 18564 this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", false); 18565 this.#popoverListeners.dispose(); 18566 18567 await nextFrame(); 18568 this.#addTriggerListener(); 18569 } 18570 18571 // The popover is appended to the <lexxy-editor> subtree, so Turbo serializes it 18572 // into the page cache. Removing it before caching prevents an orphaned, unmanaged 18573 // popover from being restored on history back/forward. 18574 #removePopoverBeforeTurboCaches() { 18575 this.#globalListeners.track( 18576 registerEventListener(document, "turbo:before-cache", () => this.#removePopover()) 18577 ); 18578 } 18579 18580 #removePopover() { 18581 this.#popoverListeners.dispose(); 18582 this.popoverElement?.remove(); 18583 this.popoverElement = null; 18584 } 18585 18586 #filterOptions = async () => { 18587 if (this.initialPrompt) { 18588 this.initialPrompt = false; 18589 return 18590 } 18591 18592 if (this.#editorContents.containsTextBackUntil(this.trigger)) { 18593 await this.#showFilteredOptions(); 18594 18595 // Re-check after async operation â the trigger may have been consumed 18596 // (e.g. markdown heading shortcut converted "# " to h1 during the fetch) 18597 if (!this.#editorContents.containsTextBackUntil(this.trigger)) { 18598 this.#hidePopover(); 18599 return 18600 } 18601 18602 await nextFrame(); 18603 this.#positionPopover(); 18604 } else { 18605 this.#hidePopover(); 18606 } 18607 } 18608 18609 async #showFilteredOptions() { 18610 const showId = this.showPopoverId; 18611 const filter = this.#editorContents.textBackUntil(this.trigger); 18612 const filteredListItems = await this.source.buildListItems(filter); 18613 if (this.showPopoverId !== showId) return 18614 if (!this.#editorContents.containsTextBackUntil(this.trigger)) return 18615 18616 this.popoverElement.innerHTML = ""; 18617 18618 if (filteredListItems.length > 0) { 18619 this.#showResults(filteredListItems); 18620 } else { 18621 this.#showEmptyResults(); 18622 } 18623 this.#selectFirstOption(); 18624 } 18625 18626 #showResults(filteredListItems) { 18627 this.popoverElement.classList.remove("lexxy-prompt-menu--empty"); 18628 this.popoverElement.append(...filteredListItems); 18629 } 18630 18631 #showEmptyResults() { 18632 this.popoverElement.classList.add("lexxy-prompt-menu--empty"); 18633 const el = createElement("li", { textContent: this.#emptyResultsMessage }); 18634 el.classList.add("lexxy-prompt-menu__item--empty"); 18635 this.popoverElement.append(el); 18636 } 18637 18638 get #emptyResultsMessage() { 18639 return this.getAttribute("empty-results") || NOTHING_FOUND_DEFAULT_MESSAGE 18640 } 18641 18642 #handleKeydownOnPopover = (event) => { 18643 if (event.key === "Escape") { 18644 this.#hidePopover(); 18645 this.#editorElement.focus(); 18646 event.stopPropagation(); 18647 } else if (event.key === ",") { 18648 event.preventDefault(); 18649 event.stopPropagation(); 18650 this.#optionWasSelected(); 18651 this.#editor.update(() => { 18652 const selection = Qr(); 18653 if (Fr(selection)) { 18654 selection.insertText(","); 18655 } 18656 }); 18657 } 18658 // Arrow keys are handled via Lexical commands 18659 } 18660 18661 // Android Mobile keyboard doesn't trigger KEY_SPACE_COMMAND 18662 #handleInputCommand(event) { 18663 if (event.inputType === "insertText" && event.data === " ") return this.#handleSelectedOption(event) 18664 } 18665 18666 #moveSelectionDown() { 18667 const nextIndex = this.#selectedIndex + 1; 18668 if (nextIndex < this.#listItemElements.length) this.#selectOption(this.#listItemElements[nextIndex], { scrollIntoView: true }); 18669 } 18670 18671 #moveSelectionUp() { 18672 const previousIndex = this.#selectedIndex - 1; 18673 if (previousIndex >= 0) this.#selectOption(this.#listItemElements[previousIndex], { scrollIntoView: true }); 18674 } 18675 18676 get #selectedIndex() { 18677 return this.#listItemElements.findIndex((item) => item.hasAttribute("aria-selected")) 18678 } 18679 18680 get #selectedListItem() { 18681 return this.#listItemElements[this.#selectedIndex] 18682 } 18683 18684 #handleSelectedOption(event) { 18685 event.preventDefault(); 18686 event.stopPropagation(); 18687 this.#optionWasSelected(); 18688 return true 18689 } 18690 18691 #optionWasSelected() { 18692 this.#replaceTriggerWithSelectedItem(); 18693 this.#hidePopover(); 18694 this.#editorElement.focus(); 18695 } 18696 18697 #replaceTriggerWithSelectedItem() { 18698 const promptItem = this.source.promptItemFor(this.#selectedListItem); 18699 18700 if (!promptItem) { return } 18701 18702 const templates = Array.from(promptItem.querySelectorAll("template[type='editor']")); 18703 const stringToReplace = `${this.trigger}${this.#editorContents.textBackUntil(this.trigger)}`; 18704 18705 if (this.hasAttribute("insert-editable-text")) { 18706 this.#insertTemplatesAsEditableText(templates, stringToReplace); 18707 } else { 18708 this.#insertTemplatesAsAttachments(templates, stringToReplace, promptItem.getAttribute("sgid")); 18709 } 18710 } 18711 18712 #insertTemplatesAsEditableText(templates, stringToReplace) { 18713 this.#editor.update(() => { 18714 const nodes = templates.flatMap(template => this.#buildEditableTextNodes(template)); 18715 this.#editorContents.replaceTextBackUntil(stringToReplace, nodes); 18716 }); 18717 } 18718 18719 #buildEditableTextNodes(template) { 18720 return this.#editorElement.$generateNodesFromDOM(parseHtml(`${template.innerHTML}`)) 18721 } 18722 18723 #insertTemplatesAsAttachments(templates, stringToReplace, fallbackSgid = null) { 18724 this.#editor.update(() => { 18725 const attachmentNodes = this.#buildAttachmentNodes(templates, fallbackSgid); 18726 const spacedAttachmentNodes = attachmentNodes.flatMap(node => [ node, this.#getSpacerTextNode() ]).slice(0, -1); 18727 this.#editorContents.replaceTextBackUntil(stringToReplace, spacedAttachmentNodes); 18728 }); 18729 } 18730 18731 #buildAttachmentNodes(templates, fallbackSgid = null) { 18732 return templates 18733 .filter(template => this.#editorElement.permitsAttachmentContentType( 18734 template.getAttribute("content-type") || this.#defaultPromptContentType)) 18735 .map(template => this.#buildAttachmentNode( 18736 template.innerHTML, 18737 template.getAttribute("content-type") || this.#defaultPromptContentType, 18738 template.getAttribute("sgid") || fallbackSgid 18739 )) 18740 } 18741 18742 #getSpacerTextNode() { 18743 return kr(" ") 18744 } 18745 18746 get #defaultPromptContentType() { 18747 const attachmentContentTypeNamespace = Lexxy.global.get("attachmentContentTypeNamespace"); 18748 return `application/vnd.${attachmentContentTypeNamespace}.${this.name}` 18749 } 18750 18751 #buildAttachmentNode(innerHtml, contentType, sgid) { 18752 return new CustomActionTextAttachmentNode({ sgid, contentType, innerHtml }) 18753 } 18754 18755 get #editorContents() { 18756 return this.#editorElement.contents 18757 } 18758 18759 get #editorContentElement() { 18760 return this.#editorElement.editorContentElement 18761 } 18762 18763 async #buildPopover() { 18764 const popoverContainer = createElement("ul", { role: "listbox", id: generateDomId("prompt-popover") }); // Avoiding [popover] due to not being able to position at an arbitrary X, Y position. 18765 popoverContainer.classList.add("lexxy-prompt-menu"); 18766 popoverContainer.style.position = "absolute"; 18767 popoverContainer.setAttribute("nonce", getNonce()); 18768 popoverContainer.append(...await this.source.buildListItems()); 18769 this.#globalListeners.track(registerEventListener(popoverContainer, "click", this.#handlePopoverClick)); 18770 this.#editorElement.appendChild(popoverContainer); 18771 return popoverContainer 18772 } 18773 18774 #handlePopoverClick = (event) => { 18775 const listItem = event.target.closest(".lexxy-prompt-menu__item"); 18776 if (listItem) { 18777 this.#selectOption(listItem); 18778 this.#optionWasSelected(); 18779 } 18780 } 18781 18782 #reconnect() { 18783 this.disconnectedCallback(); 18784 this.connectedCallback(); 18785 } 18786} 18787 18788class CodeLanguagePicker extends HTMLElement { 18789 #abortController = null 18790 #listeners = new ListenerBin() 18791 18792 connectedCallback() { 18793 this.editorElement = this.closest("lexxy-editor"); 18794 this.editor = this.editorElement.editor; 18795 this.classList.add("lexxy-floating-controls"); 18796 this.#abortController = new AbortController(); 18797 this.#listeners.track(() => this.#abortController?.abort()); 18798 18799 this.#attachLanguagePicker(); 18800 this.#hide(); 18801 this.#monitorForCodeBlockSelection(); 18802 } 18803 18804 disconnectedCallback() { 18805 this.dispose(); 18806 } 18807 18808 dispose() { 18809 this.#listeners.dispose(); 18810 } 18811 18812 #attachLanguagePicker() { 18813 this.languagePickerElement = this.#findLanguagePicker() ?? this.#createLanguagePicker(); 18814 18815 const signal = this.#abortController.signal; 18816 18817 this.#listeners.track(registerEventListener(this.languagePickerElement, "change", () => { 18818 this.#updateCodeBlockLanguage(this.languagePickerElement.value); 18819 }, { signal })); 18820 18821 this.#listeners.track(registerEventListener(this.languagePickerElement, "mousedown", (event) => { 18822 this.#dispatchOpenEvent(event); 18823 }, { signal })); 18824 18825 this.languagePickerElement.setAttribute("nonce", getNonce()); 18826 this.appendChild(this.languagePickerElement); 18827 } 18828 18829 #findLanguagePicker() { 18830 return this.querySelector("select") 18831 } 18832 18833 #createLanguagePicker() { 18834 const selectElement = createElement("select", { className: "lexxy-code-language-picker", "aria-label": "Pick a languageâ¦", name: "lexxy-code-language" }); 18835 18836 for (const [ value, label ] of Object.entries(this.#languages)) { 18837 const option = document.createElement("option"); 18838 option.value = value; 18839 option.textContent = label; 18840 selectElement.appendChild(option); 18841 } 18842 18843 return selectElement 18844 } 18845 18846 get #languages() { 18847 const languages = { ...o }; 18848 18849 languages.ruby ||= "Ruby"; 18850 languages.php ||= "PHP"; 18851 languages.go ||= "Go"; 18852 languages.bash ||= "Bash"; 18853 languages.json ||= "JSON"; 18854 languages.diff ||= "Diff"; 18855 languages.kotlin ||= "Kotlin"; 18856 18857 18858 // Place the "plain" entry first, then the rest of language sorted alphabetically 18859 delete languages.plain; 18860 const sortedEntries = Object.entries(languages) 18861 .sort((a, b) => a[1].localeCompare(b[1])); 18862 return { plain: "Plain text", ...Object.fromEntries(sortedEntries) } 18863 } 18864 18865 #dispatchOpenEvent(event) { 18866 const handled = !dispatch(this.editorElement, "lexxy:code-language-picker-open", { 18867 languages: this.#bridgeLanguages, 18868 currentLanguage: this.languagePickerElement.value 18869 }, true); 18870 18871 if (handled) { 18872 event.preventDefault(); 18873 } 18874 } 18875 18876 get #bridgeLanguages() { 18877 return Object.entries(this.#languages).map(([ key, name ]) => ({ key, name })) 18878 } 18879 18880 #updateCodeBlockLanguage(language) { 18881 this.editor.update(() => { 18882 const codeNode = this.#getCurrentCodeNode(); 18883 18884 if (codeNode) { 18885 codeNode.setLanguage(language); 18886 } 18887 }); 18888 } 18889 18890 #monitorForCodeBlockSelection() { 18891 this.#listeners.track(this.editor.registerUpdateListener(({ editorState }) => { 18892 editorState.read(() => { 18893 const codeNode = this.#getCurrentCodeNode(); 18894 18895 if (codeNode) { 18896 this.#codeNodeWasSelected(codeNode); 18897 } else { 18898 this.#hide(); 18899 } 18900 }); 18901 })); 18902 } 18903 18904 #getCurrentCodeNode() { 18905 return this.editorElement.selection.nearestNodeOfType(z$1) 18906 } 18907 18908 #codeNodeWasSelected(codeNode) { 18909 const language = codeNode.getLanguage(); 18910 18911 this.#updateLanguagePickerWith(language); 18912 this.#show(); 18913 this.#positionLanguagePicker(codeNode); 18914 } 18915 18916 #updateLanguagePickerWith(language) { 18917 if (this.languagePickerElement && language) { 18918 const normalizedLanguage = a(language); 18919 this.languagePickerElement.value = normalizedLanguage; 18920 } 18921 } 18922 18923 #positionLanguagePicker(codeNode) { 18924 const codeElement = this.editor.getElementByKey(codeNode.getKey()); 18925 if (!codeElement) return 18926 18927 const codeRect = codeElement.getBoundingClientRect(); 18928 const editorRect = this.editorElement.getBoundingClientRect(); 18929 const relativeTop = codeRect.top - editorRect.top; 18930 const relativeRight = editorRect.right - codeRect.right; 18931 18932 this.style.top = `${relativeTop}px`; 18933 this.style.right = `${relativeRight}px`; 18934 } 18935 18936 #show() { 18937 this.hidden = false;
18938 } 18939 18940 #hide() { 18941 this.hidden = true; 18942 } 18943} 18944 18945const DELETE_ICON = `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 18946 <path d="M11.2041 1.01074C12.2128 1.113 13 1.96435 13 3V4H15L15.1025 4.00488C15.6067 4.05621 16 4.48232 16 5C16 5.55228 15.5523 6 15 6H14.8457L14.1416 15.1533C14.0614 16.1953 13.1925 17 12.1475 17H5.85254L5.6582 16.9902C4.76514 16.9041 4.03607 16.2296 3.88184 15.3457L3.8584 15.1533L3.1543 6H3C2.44772 6 2 5.55228 2 5C2 4.44772 2.44772 4 3 4H5V3C5 1.89543 5.89543 1 7 1H11L11.2041 1.01074ZM5.85254 15H12.1475L12.8398 6H5.16016L5.85254 15ZM7 4H11V3H7V4Z"/> 18947</svg>`; 18948 18949class NodeDeleteButton extends HTMLElement { 18950 connectedCallback() { 18951 this.editorElement = this.closest("lexxy-editor"); 18952 this.editor = this.editorElement.editor; 18953 this.classList.add("lexxy-floating-controls"); 18954 18955 if (!this.querySelector(".lexxy-node-delete")) { 18956 this.#attachDeleteButton(); 18957 } 18958 } 18959 18960 disconnectedCallback() { 18961 this.editor = null; 18962 this.editorElement = null; 18963 } 18964 18965 #attachDeleteButton() { 18966 const container = createElement("div", { className: "lexxy-floating-controls__group" }); 18967 18968 this.deleteButton = createElement("button", { 18969 className: "lexxy-node-delete", 18970 type: "button", 18971 "aria-label": "Remove" 18972 }); 18973 this.deleteButton.tabIndex = -1; 18974 this.deleteButton.innerHTML = DELETE_ICON; 18975 18976 this.handleDeleteClick = () => this.#deleteNode(); 18977 this.deleteButton.addEventListener("click", this.handleDeleteClick); 18978 container.appendChild(this.deleteButton); 18979 18980 this.appendChild(container); 18981 } 18982 18983 #deleteNode() { 18984 this.editor.update(() => { 18985 const node = Go(this); 18986 node?.remove(); 18987 }); 18988 } 18989} 18990 18991class TableController { 18992 #listeners = new ListenerBin() 18993 18994 constructor(editorElement) { 18995 this.editor = editorElement.editor; 18996 this.contents = editorElement.contents; 18997 this.selection = editorElement.selection; 18998 18999 this.currentTableNodeKey = null; 19000 this.currentCellKey = null; 19001 19002 this.#registerKeyHandlers(); 19003 } 19004 19005 destroy() { 19006 this.currentTableNodeKey = null; 19007 this.currentCellKey = null; 19008 19009 this.#listeners.dispose(); 19010 } 19011 19012 get currentCell() { 19013 if (!this.currentCellKey) return null 19014 19015 return this.editor.getEditorState().read(() => { 19016 const cell = Yo(this.currentCellKey); 19017 return (cell instanceof Ee$1) ? cell : null 19018 }) 19019 } 19020 19021 get currentTableNode() { 19022 if (!this.currentTableNodeKey) return null 19023 19024 return this.editor.getEditorState().read(() => { 19025 const tableNode = Yo(this.currentTableNodeKey); 19026 return (tableNode instanceof vn) ? tableNode : null 19027 }) 19028 } 19029 19030 get currentRowCells() { 19031 const currentRowIndex = this.currentRowIndex; 19032 19033 const rows = this.tableRows; 19034 if (!rows) return null 19035 19036 return this.editor.getEditorState().read(() => { 19037 return rows[currentRowIndex]?.getChildren() ?? null 19038 }) ?? null 19039 } 19040 19041 get currentRowIndex() { 19042 const currentCell = this.currentCell; 19043 if (!currentCell) return 0 19044 19045 return this.editor.getEditorState().read(() => { 19046 return Ve$1(currentCell) 19047 }) ?? 0 19048 } 19049 19050 get currentColumnCells() { 19051 const columnIndex = this.currentColumnIndex; 19052 19053 const rows = this.tableRows; 19054 if (!rows) return null 19055 19056 return this.editor.getEditorState().read(() => { 19057 return rows.map(row => row.getChildAtIndex(columnIndex)) 19058 }) ?? null 19059 } 19060 19061 get currentColumnIndex() { 19062 const currentCell = this.currentCell; 19063 if (!currentCell) return 0 19064 19065 return this.editor.getEditorState().read(() => { 19066 return Ge$1(currentCell) 19067 }) ?? 0 19068 } 19069 19070 get tableRows() { 19071 return this.editor.getEditorState().read(() => { 19072 return this.currentTableNode?.getChildren() 19073 }) ?? null 19074 } 19075 19076 updateSelectedTable() {
vendor: 9,676 bytes, lines 19077-19368
19077 let cellNode = null; 19078 let tableNode = null; 19079 19080 this.editor.getEditorState().read(() => { 19081 const selection = Qr(); 19082 if (!selection || !this.selection.isTableCellSelected) return 19083 19084 const node = selection.getNodes()[0]; 19085 19086 cellNode = un(node); 19087 tableNode = hn(node); 19088 }); 19089 19090 this.currentCellKey = cellNode?.getKey() ?? null; 19091 this.currentTableNodeKey = tableNode?.getKey() ?? null; 19092 19093 return tableNode 19094 } 19095 19096 executeTableCommand(command, customIndex = null) { 19097 if (command.action === "delete" && command.childType === "table") { 19098 this.#deleteTable(); 19099 return 19100 } 19101 19102 if (command.action === "toggle") { 19103 this.#executeToggleStyle(command); 19104 return 19105 } 19106 19107 this.#executeCommand(command, customIndex); 19108 } 19109 19110 #executeCommand(command, customIndex = null) { 19111 this.#selectCellAtSelection(); 19112 this.editor.dispatchCommand(this.#commandName(command)); 19113 this.#selectNextBestCell(command, customIndex); 19114 } 19115 19116 #executeToggleStyle(command) { 19117 const childType = command.childType; 19118 19119 let cells = null; 19120 let headerState = null; 19121 19122 if (childType === "row") { 19123 cells = this.currentRowCells; 19124 headerState = Ae$1.ROW; 19125 } else if (childType === "column") { 19126 cells = this.currentColumnCells; 19127 headerState = Ae$1.COLUMN; 19128 } 19129 19130 if (!cells || cells.length === 0) return 19131 19132 this.editor.update(() => { 19133 const firstCell = Ye(cells[0]); 19134 if (!firstCell) return 19135 19136 const currentStyle = firstCell.getHeaderStyles(); 19137 const newStyle = currentStyle ^ headerState; 19138 19139 cells.forEach(cell => { 19140 this.#setHeaderStyle(cell, newStyle, headerState); 19141 }); 19142 }); 19143 } 19144 19145 #deleteTable() { 19146 this.#selectCellAtSelection(); 19147 this.editor.dispatchCommand("deleteTable"); 19148 } 19149 19150 #selectCellAtSelection() { 19151 this.editor.update(() => { 19152 const selection = Qr(); 19153 if (!selection) return 19154 19155 const node = selection.getNodes()[0]; 19156 19157 un(node)?.selectEnd(); 19158 }); 19159 } 19160 19161 #commandName(command) { 19162 const { action, childType, direction } = command; 19163 19164 const childTypeSuffix = upcaseFirst(childType); 19165 const directionSuffix = action == "insert" ? upcaseFirst(direction) : ""; 19166 return `${action}Table${childTypeSuffix}${directionSuffix}` 19167 } 19168 19169 #setHeaderStyle(cell, newStyle, headerState) { 19170 const tableCellNode = Ye(cell); 19171 tableCellNode?.setHeaderStyles(newStyle, headerState); 19172 } 19173 19174 async #selectCellAtIndex(rowIndex, columnIndex) { 19175 // We wait for next frame, otherwise table operations might not have completed yet. 19176 await nextFrame(); 19177 19178 if (!this.currentTableNode) return 19179 19180 const rows = this.tableRows; 19181 if (!rows) return 19182 19183 const row = rows[rowIndex]; 19184 if (!row) return 19185 19186 this.editor.update(() => { 19187 const cell = Ye(row.getChildAtIndex(columnIndex)); 19188 cell?.selectEnd(); 19189 }); 19190 } 19191 19192 #selectNextBestCell(command, customIndex = null) { 19193 const { childType, direction } = command; 19194 19195 let rowIndex = this.currentRowIndex; 19196 let columnIndex = customIndex !== null ? customIndex : this.currentColumnIndex; 19197 19198 const deleteOffset = command.action === "delete" ? -1 : 0; 19199 const offset = direction === "after" ? 1 : deleteOffset; 19200 19201 if (childType === "row") { 19202 rowIndex += offset; 19203 } else if (childType === "column") { 19204 columnIndex += offset; 19205 } 19206 19207 this.#selectCellAtIndex(rowIndex, columnIndex); 19208 } 19209 19210 #selectNextRow() { 19211 const rows = this.tableRows; 19212 if (!rows) return 19213 19214 const nextRow = rows.at(this.currentRowIndex + 1); 19215 if (!nextRow) return 19216 19217 this.editor.update(() => { 19218 nextRow.getChildAtIndex(this.currentColumnIndex)?.selectEnd(); 19219 }); 19220 } 19221 19222 #selectPreviousCell() { 19223 const cell = this.currentCell; 19224 if (!cell) return 19225 19226 this.editor.update(() => { 19227 cell.selectPrevious(); 19228 }); 19229 } 19230 19231 #insertRowAndSelectFirstCell() { 19232 this.executeTableCommand({ action: "insert", childType: "row", direction: "after" }, 0); 19233 } 19234 19235 #deleteRowAndSelectLastCell() { 19236 this.executeTableCommand({ action: "delete", childType: "row" }, -1); 19237 } 19238 19239 #deleteRowAndSelectNextNode() { 19240 const tableNode = this.currentTableNode; 19241 this.executeTableCommand({ action: "delete", childType: "row" }); 19242 19243 this.editor.update(() => { 19244 const next = tableNode?.getNextSibling(); 19245 if (no(next)) { 19246 next.selectStart(); 19247 } else { 19248 const newParagraph = eo(); 19249 this.currentTableNode.insertAfter(newParagraph); 19250 newParagraph.selectStart(); 19251 } 19252 }); 19253 } 19254 19255 #isCurrentCellEmpty() { 19256 if (!this.currentTableNode) return false 19257 19258 const cell = this.currentCell; 19259 if (!cell) return false 19260 19261 return cell.getTextContent().trim() === "" 19262 } 19263 19264 #isCurrentRowLast() { 19265 if (!this.currentTableNode) return false 19266 19267 const rows = this.tableRows; 19268 if (!rows) return false 19269 19270 return rows.length === this.currentRowIndex + 1 19271 } 19272 19273 #isCurrentRowEmpty() { 19274 if (!this.currentTableNode) return false 19275 19276 const cells = this.currentRowCells; 19277 if (!cells) return false 19278 19279 return cells.every(cell => cell.getTextContent().trim() === "") 19280 } 19281 19282 #isFirstCellInRow() { 19283 if (!this.currentTableNode) return false 19284 19285 const cells = this.currentRowCells; 19286 if (!cells) return false 19287 19288 return cells.indexOf(this.currentCell) === 0 19289 } 19290 19291 #registerKeyHandlers() { 19292 // We can't prevent these externally using regular keydown because Lexical handles it first. 19293 this.#listeners.track( 19294 this.editor.registerCommand(Ae$3, (event) => this.#handleBackspaceKey(event), so), 19295 this.editor.registerCommand(Oe$2, (event) => this.#handleEnterKey(event), so) 19296 ); 19297 } 19298 19299 #handleBackspaceKey(event) { 19300 if (!this.currentTableNode) return false 19301 19302 if (this.#isCurrentRowEmpty() && this.#isFirstCellInRow()) { 19303 event.preventDefault(); 19304 this.#deleteRowAndSelectLastCell(); 19305 return true 19306 } 19307 19308 if (this.#isCurrentCellEmpty() && !this.#isFirstCellInRow()) { 19309 event.preventDefault(); 19310 this.#selectPreviousCell(); 19311 return true 19312 } 19313 19314 return false 19315 } 19316 19317 #handleEnterKey(event) { 19318 if ((event.ctrlKey || event.metaKey) || event.shiftKey || !this.currentTableNode) return false 19319 19320 if (this.selection.isInsideList || this.selection.isInsideCodeBlock) return false 19321 19322 event.preventDefault(); 19323 19324 if (this.#isCurrentRowLast() && this.#isCurrentRowEmpty()) { 19325 this.#deleteRowAndSelectNextNode(); 19326 } else if (this.#isCurrentRowLast()) { 19327 this.#insertRowAndSelectFirstCell(); 19328 } else { 19329 this.#selectNextRow(); 19330 } 19331 19332 return true 19333 } 19334} 19335 19336var TableIcons = { 19337 "insert-row-before": 19338 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19339 <path fill-rule="evenodd" clip-rule="evenodd" d="M7.86804e-07 15C8.29055e-07 15.8284 0.671574 16.5 1.5 16.5H15L15.1533 16.4922C15.8593 16.4205 16.4205 15.8593 16.4922 15.1533L16.5 15V4.5L16.4922 4.34668C16.4154 3.59028 15.7767 3 15 3H13.5L13.5 4.5H15V9H1.5L1.5 4.5L3 4.5V3H1.5C0.671574 3 1.20956e-06 3.67157 1.24577e-06 4.5L7.86804e-07 15ZM15 10.5V15H1.5L1.5 10.5H15Z"/> 19340 <path d="M4.5 4.5H7.5V7.5H9V4.5H12L12 3L9 3V6.55671e-08L7.5 0V3L4.5 3V4.5Z"/> 19341 </svg>`, 19342 19343 "insert-row-after": 19344 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19345 <path fill-rule="evenodd" clip-rule="evenodd" d="M7.86804e-07 13.5C7.50592e-07 14.3284 0.671574 15 1.5 15H3V13.5H1.5L1.5 9L15 9V13.5H13.5V15H15C15.7767 15 16.4154 14.4097 16.4922 13.6533L16.5 13.5V3L16.4922 2.84668C16.4205 2.14069 15.8593 1.57949 15.1533 1.50781L15 1.5L1.5 1.5C0.671574 1.5 1.28803e-06 2.17157 1.24577e-06 3L7.86804e-07 13.5ZM15 3V7.5L1.5 7.5L1.5 3L15 3Z"/> 19346 <path d="M7.5 15V18H9V15H12V13.5H9V10.5H7.5V13.5H4.5V15H7.5Z"/> 19347 </svg>`, 19348 19349 "delete-row": 19350 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19351 <path d="M16.4922 12.1533C16.4154 12.9097 15.7767 13.5 15 13.5L12 13.5V12H15V6L1.5 6L1.5 12H4.5V13.5H1.5C0.723337 13.5 0.0846104 12.9097 0.00781328 12.1533L7.86804e-07 12L1.04907e-06 6C1.17362e-06 5.22334 0.590278 4.58461 1.34668 4.50781L1.5 4.5L15 4.5C15.8284 4.5 16.5 5.17157 16.5 6V12L16.4922 12.1533Z"/> 19352 <path d="M10.3711 15.9316L8.25 13.8096L6.12793 15.9316L5.06738 14.8711L7.18945 12.75L5.06738 10.6289L6.12793 9.56836L8.25 11.6895L10.3711 9.56836L11.4316 10.6289L9.31055 12.75L11.4316 14.8711L10.3711 15.9316Z"/> 19353 </svg>`, 19354 19355 "toggle-row": 19356 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19357 <path fill-rule="evenodd" clip-rule="evenodd" d="M0.00781328 13.6533C0.0846108 14.4097 0.723337 15 1.5 15L15 15L15.1533 14.9922C15.8593 14.9205 16.4205 14.3593 16.4922 13.6533L16.5 13.5V4.5L16.4922 4.34668C16.4205 3.64069 15.8593 3.07949 15.1533 3.00781L15 3L1.5 3C0.671574 3 1.24863e-06 3.67157 1.18021e-06 4.5L7.86804e-07 13.5L0.00781328 13.6533ZM15 9V13.5L1.5 13.5L1.5 9L15 9Z"/> 19358 </svg>`, 19359 19360 "insert-column-before": 19361 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19362 <path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 0C3.67157 0 3 0.671573 3 1.5V3H4.5V1.5H9V15H4.5V13.5H3V15C3 15.7767 3.59028 16.4154 4.34668 16.4922L4.5 16.5H15L15.1533 16.4922C15.8593 16.4205 16.4205 15.8593 16.4922 15.1533L16.5 15V1.5C16.5 0.671573 15.8284 6.03989e-09 15 0H4.5ZM15 15H10.5V1.5H15V15Z"/> 19363 <path d="M3 7.5H0V9H3V12H4.5V9H7.5V7.5H4.5V4.5H3V7.5Z"/> 19364 </svg>`, 19365 19366 "insert-column-after": 19367 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19368 <path fill-rule="evenodd" clip-rule="evenodd" d="M13.5 0C14.3284 0 15 0.671573 15 1.5V3H13.5V1.5H9V15H13.5V13.5H15V15C15 15.7767 14.4097 16.4154 13.6533 16.4922L13.5 16.5H3L2.84668 16.4922C2.14069 16.4205 1.57949 15.8593 1.50781 15.1533L1.5 15V1.5C1.5 0.671573 2.17157 6.03989e-09 3 0H13.5ZM3
1936815H7.5V1.5H3V15Z"/> 19369 <path d="M15 7.5H18V9H15V12H13.5V9H10.5V7.5H13.5V4.5H15V7.5Z"/> 19370 </svg>`, 19371 19372 "delete-column": 19373 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19374 <path d="M12.1533 0.0078125C12.9097 0.0846097 13.5 0.723336 13.5 1.5V4.5H12V1.5H6V15H12V12H13.5V15C13.5 15.7767 12.9097 16.4154 12.1533 16.4922L12 16.5H6C5.22334 16.5 4.58461 15.9097 4.50781 15.1533L4.5 15V1.5C4.5 0.671573 5.17157 2.41596e-08 6 0H12L12.1533 0.0078125Z"/> 19375 <path d="M15.9316 6.12891L13.8105 8.24902L15.9326 10.3711L14.8711 11.4316L12.75 9.31055L10.6289 11.4316L9.56738 10.3711L11.6885 8.24902L9.56836 6.12891L10.6289 5.06836L12.75 7.18848L14.8711 5.06836L15.9316 6.12891Z"/> 19376 </svg>`, 19377 19378 "toggle-column": 19379 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19380 <path fill-rule="evenodd" clip-rule="evenodd" d="M13.6533 17.9922C14.4097 17.9154 15 17.2767 15 16.5L15 3L14.9922 2.84668C14.9205 2.14069 14.3593 1.57949 13.6533 1.50781L13.5 1.5L4.5 1.5L4.34668 1.50781C3.59028 1.58461 3 2.22334 3 3L3 16.5C3 17.2767 3.59028 17.9154 4.34668 17.9922L4.5 18L13.5 18L13.6533 17.9922ZM9 3L13.5 3L13.5 16.5L9 16.5L9 3Z"/> 19381 </svg>`, 19382 19383 "delete-table": 19384 `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 19385 <path d="M11.2041 1.01074C12.2128 1.113 13 1.96435 13 3V4H15L15.1025 4.00488C15.6067 4.05621 16 4.48232 16 5C16 5.55228 15.5523 6 15 6H14.8457L14.1416 15.1533C14.0614 16.1953 13.1925 17 12.1475 17H5.85254L5.6582 16.9902C4.76514 16.9041 4.03607 16.2296 3.88184 15.3457L3.8584 15.1533L3.1543 6H3C2.44772 6 2 5.55228 2 5C2 4.44772 2.44772 4 3 4H5V3C5 1.89543 5.89543 1 7 1H11L11.2041 1.01074ZM5.85254 15H12.1475L12.8398 6H5.16016L5.85254 15ZM7 4H11V3H7V4Z"/> 19386 </svg>` 19387}; 19388 19389class TableTools extends HTMLElement { 19390 #listeners = new ListenerBin() 19391 19392 connectedCallback() { 19393 this.tableController = new TableController(this.#editorElement); 19394 this.classList.add("lexxy-floating-controls"); 19395 this.role = "toolbar"; 19396 19397 this.#setUpButtons(); 19398 this.#hide(); 19399 this.#monitorForTableSelection(); 19400 this.#registerKeyboardShortcuts(); 19401 } 19402 19403 disconnectedCallback() { 19404 this.dispose(); 19405 } 19406 19407 dispose() { 19408 this.#listeners.dispose(); 19409 19410 this.tableController?.destroy(); 19411 this.tableController = null; 19412 } 19413 19414 get #editor() { 19415 return this.#editorElement.editor 19416 } 19417 19418 get #editorElement() { 19419 return this.closest("lexxy-editor") 19420 } 19421 19422 get #tableToolsButtons() { 19423 return Array.from(this.querySelectorAll("button, details > summary")) 19424 } 19425 19426 #setUpButtons() { 19427 this.innerHTML = ""; 19428 19429 this.appendChild(this.#createRowButtonsContainer()); 19430 this.appendChild(this.#createColumnButtonsContainer()); 19431 19432 this.appendChild(this.#createDeleteTableButton()); 19433 this.#listeners.track(registerEventListener(this, "keydown", this.#handleToolsKeydown)); 19434 } 19435 19436 #createButtonsContainer(childType, setCountProperty, moreMenu) { 19437 const container = createElement("div", { className: `lexxy-floating-controls__group lexxy-table-control lexxy-table-control--${childType}` }); 19438 19439 const plusButton = this.#createButton(`Add ${childType}`, { action: "insert", childType, direction: "after" }, "+"); 19440 const minusButton = this.#createButton(`Remove ${childType}`, { action: "delete", childType }, "â"); 19441 19442 const dropdown = createElement("details", { className: "lexxy-table-control__more-menu" }); 19443 dropdown.setAttribute("name", "lexxy-dropdown"); 19444 dropdown.tabIndex = -1; 19445 19446 const count = createElement("summary", {}, `_ ${childType}s`); 19447 setCountProperty(count); 19448 dropdown.appendChild(count); 19449 19450 dropdown.appendChild(moreMenu); 19451 19452 container.appendChild(minusButton); 19453 container.appendChild(dropdown); 19454 container.appendChild(plusButton); 19455 19456 return container 19457 } 19458 19459 #createRowButtonsContainer() { 19460 return this.#createButtonsContainer( 19461 "row", 19462 (count) => { this.rowCount = count; }, 19463 this.#createMoreMenuSection("row") 19464 ) 19465 } 19466 19467 #createColumnButtonsContainer() { 19468 return this.#createButtonsContainer( 19469 "column", 19470 (count) => { this.columnCount = count; }, 19471 this.#createMoreMenuSection("column") 19472 ) 19473 } 19474 19475 #createMoreMenuSection(childType) { 19476 const section = createElement("div", { className: "lexxy-floating-control
vendor: 4,464 bytes, lines 19476-19617
19476s__group lexxy-table-control__more-menu-details" }); 19477 const addBeforeButton = this.#createButton(`Add ${childType} before`, { action: "insert", childType, direction: "before" }); 19478 const addAfterButton = this.#createButton(`Add ${childType} after`, { action: "insert", childType, direction: "after" }); 19479 const toggleStyleButton = this.#createButton(`Toggle ${childType} style`, { action: "toggle", childType }); 19480 const deleteButton = this.#createButton(`Remove ${childType}`, { action: "delete", childType }); 19481 19482 section.appendChild(addBeforeButton); 19483 section.appendChild(addAfterButton); 19484 section.appendChild(toggleStyleButton); 19485 section.appendChild(deleteButton); 19486 19487 return section 19488 } 19489 19490 #createDeleteTableButton() { 19491 const container = createElement("div", { className: "lexxy-table-control lexxy-floating-controls__group" }); 19492 19493 const deleteTableButton = this.#createButton("Delete this table?", { action: "delete", childType: "table" }); 19494 deleteTableButton.classList.add("lexxy-table-control__button--delete-table"); 19495 19496 container.appendChild(deleteTableButton); 19497 19498 this.deleteContainer = container; 19499 19500 return container 19501 } 19502 19503 #createButton(label, command = {}, icon = this.#icon(command)) { 19504 const button = createElement("button", { 19505 className: "lexxy-table-control__button", 19506 "aria-label": label, 19507 type: "button" 19508 }); 19509 button.tabIndex = -1; 19510 button.innerHTML = `${icon} <span>${label}</span>`; 19511 19512 button.dataset.action = command.action; 19513 button.dataset.childType = command.childType; 19514 button.dataset.direction = command.direction; 19515 19516 button.addEventListener("click", () => this.#executeTableCommand(command)); 19517 19518 button.addEventListener("mouseover", () => this.#handleCommandButtonHover()); 19519 button.addEventListener("focus", () => this.#handleCommandButtonHover()); 19520 button.addEventListener("mouseout", () => this.#handleCommandButtonHover()); 19521 19522 return button 19523 } 19524 19525 #registerKeyboardShortcuts() { 19526 this.#listeners.track(this.#editor.registerCommand(ve$2, this.#focusToolbarOnAltF10, so)); 19527 } 19528 19529 #focusToolbarOnAltF10 = (event) => { 19530 if (this.#hasSelectedTable && event.altKey && event.key === "F10") { 19531 event.preventDefault(); 19532 // Ask for the ring explicitly: a programmatic focus coming from a mouse-focused 19533 // editor otherwise inherits the mouse modality and paints no focus ring. 19534 this.#tableToolsButtons[0]?.focus({ focusVisible: true }); 19535 return true 19536 } else { 19537 return false 19538 } 19539 } 19540 19541 get #hasSelectedTable() { 19542 return this.tableController?.currentTableNodeKey != null 19543 } 19544 19545 #handleToolsKeydown = (event) => { 19546 if (event.key === "Escape") { 19547 this.#handleEscapeKey(); 19548 } else { 19549 handleRollingTabIndex(this.#tableToolsButtons, event); 19550 } 19551 } 19552 19553 #handleEscapeKey() { 19554 const cell = this.tableController.currentCell; 19555 if (!cell) return 19556 19557 this.#editor.update(() => { 19558 cell.select(); 19559 this.#editor.focus(); 19560 }); 19561 19562 this.#update(); 19563 } 19564 19565 async #handleCommandButtonHover() { 19566 await nextFrame(); 19567 19568 this.#clearCellStyles(); 19569 19570 const activeElement = this.querySelector("button:hover, button:focus"); 19571 if (!activeElement) return 19572 19573 const command = { 19574 action: activeElement.dataset.action, 19575 childType: activeElement.dataset.childType, 19576 direction: activeElement.dataset.direction 19577 }; 19578 19579 let cellsToHighlight = null; 19580 19581 switch (command.childType) { 19582 case "row": 19583 cellsToHighlight = this.tableController.currentRowCells; 19584 break 19585 case "column": 19586 cellsToHighlight = this.tableController.currentColumnCells; 19587 break 19588 case "table": 19589 cellsToHighlight = this.tableController.tableRows; 19590 break 19591 } 19592 19593 if (!cellsToHighlight) return 19594 19595 cellsToHighlight.forEach(cell => { 19596 const cellElement = this.#editor.getElementByKey(cell.getKey()); 19597 if (!cellElement) return 19598 19599 cellElement.classList.toggle(theme.tableCellHighlight, true); 19600 Object.assign(cellElement.dataset, command); 19601 }); 19602 } 19603 19604 #monitorForTableSelection() { 19605 this.#listeners.track(this.#editor.registerUpdateListener(() => { 19606 const tableNode = this.#editor.getRootElement() && this.tableController.updateSelectedTable(); 19607 19608 if (tableNode) { 19609 this.#show(); 19610 } else { 19611 this.#hide(); 19612 } 19613 })); 19614 } 19615 19616 #executeTableCommand(command) { 19617 this.tableController.executeTableCommand(command);
19618 this.#update(); 19619 } 19620 19621 #show() { 19622 this.#updateButtonsPosition(); 19623 this.style.display = "flex"; 19624 this.#updateRowColumnCount(); 19625 this.#closeMoreMenu(); 19626 this.#handleCommandButtonHover(); 19627 } 19628 19629 #hide() { 19630 this.style.display = "none"; 19631 this.#clearCellStyles(); 19632 } 19633 19634 #update() { 19635 this.#updateButtonsPosition(); 19636 this.#updateRowColumnCount(); 19637 this.#closeMoreMenu(); 19638 this.#handleCommandButtonHover(); 19639 } 19640 19641 #closeMoreMenu() { 19642 this.querySelector("details[open]")?.removeAttribute("open"); 19643 } 19644 19645 #updateButtonsPosition() { 19646 const tableNode = this.tableController.currentTableNode; 19647 if (!tableNode) return 19648 19649 const tableElement = this.#editor.getElementByKey(tableNode.getKey()); 19650 if (!tableElement) return 19651 19652 const tableRect = tableElement.getBoundingClientRect(); 19653 const editorRect = this.#editorElement.getBoundingClientRect(); 19654 19655 const relativeTop = tableRect.top - editorRect.top; 19656 const relativeCenter = (tableRect.left + tableRect.right) / 2 - editorRect.left; 19657 this.style.top = `${relativeTop}px`; 19658 this.style.left = `${relativeCenter}px`; 19659 } 19660 19661 #updateRowColumnCount() { 19662 const tableNode = this.tableController.currentTableNode; 19663 if (!tableNode) return 19664 19665 const tableElement = xn(this.#editor, tableNode); 19666 if (!tableElement) return 19667 19668 const rowCount = tableElement.rows; 19669 const columnCount = tableElement.columns; 19670 19671 this.rowCount.textContent = `${rowCount} row${rowCount === 1 ? "" : "s"}`; 19672 this.columnCount.textContent = `${columnCount} column${columnCount === 1 ? "" : "s"}`; 19673 } 19674 19675 #setTableCellFocus() { 19676 const cell = this.tableController.currentCell; 19677 if (!cell) return 19678 19679 const cellElement = this.#editor.getElementByKey(cell.getKey()); 19680 if (!cellElement) return 19681 19682 cellElement.classList.add(theme.tableCellFocus); 19683 } 19684 19685 #clearCellStyles() { 19686 this.#editorElement.querySelectorAll(`.${theme.tableCellFocus}`)?.forEach(cell => { 19687 cell.classList.remove(theme.tableCellFocus); 19688 }); 19689 19690 this.#editorElement.querySelectorAll(`.${theme.tableCellHighlight}`)?.forEach(cell => { 19691 cell.classList.remove(theme.tableCellHighlight); 19692 cell.removeAttribute("data-action"); 19693 cell.removeAttribute("data-child-type"); 19694 cell.removeAttribute("data-direction"); 19695 }); 19696 19697 this.#setTableCellFocus(); 19698 } 19699 19700 #icon(command) { 19701 const { action, childType } = command; 19702 const direction = (action == "insert" ? command.direction : null); 19703 const iconId = [ action, childType, direction ].filter(Boolean).join("-"); 19704 return TableIcons[iconId] 19705 } 19706} 19707 19708function defineElements() { 19709 const elements = { 19710 // Toolbar must be registered BEFORE Editor 19711 "lexxy-toolbar": LexicalToolbarElement, 19712 "lexxy-toolbar-dropdown": ToolbarDropdown, 19713 "lexxy-heading-dropdown": HeadingDropdown, 19714 "lexxy-highlight-dropdown": HighlightDropdown, 19715 "lexxy-link-dropdown": LinkDropdown, 19716 19717 "lexxy-editor": LexicalEditorElement, 19718 19719 // Prompt must be registered AFTER Editor 19720 "lexxy-prompt": LexicalPromptElement, 19721 "lexxy-code-language-picker": CodeLanguagePicker, 19722 "lexxy-node-delete-button": NodeDeleteButton, 19723 "lexxy-table-tools": TableTools 19724 }; 19725 19726 Object.entries(elements).forEach(([ name, element ]) => { 19727 customElements.define(name, element); 19728 }); 19729} 19730 19731function highlightCode(root = document) { 19732 const elements = root.querySelectorAll("pre[data-language]:not([data-highlighted])"); 19733 19734 elements.forEach(preElement => { 19735 highlightElement(preElement); 19736 }); 19737} 19738 19739function highlightElement(preElement) { 19740 if (preElement.dataset.highlighted === "true") return 19741 19742 const language = preElement.getAttribute("data-language"); 19743 19744 const grammar = Prism$1.languages?.[language]; 19745 if (!grammar) return 19746 19747 // Read the source text and <mark> ranges in a single walk, before Prism 19748 // rewrites the element. Sharing one traversal keeps the highlight offsets 19749 // aligned with the code string and preserves leading whitespace â deriving 19750 // either of them separately (e.g. textContent through DOMParser) collapses 19751 // leading whitespace and shifts every range, re-indenting the rendered block. 19752 const { code, highlights } = extractCodeAndHighlights(preElement); 19753 19754 const highlightedHtml = Prism$1.highlight(code, grammar, language); 19755 preElement.innerHTML = highlightedHtml; 19756 19757 if (highlights.length > 0) { 19758 applyHighlightRanges(preElement, highlights); 19759 } 19760 19761 preElement.dataset.highlighted = "true"; 19762} 19763 19764// Walk the <pre> once, building Prism's source text and the <mark> ranges 19765// together: a text node contributes its text verbatim, a <br> contributes a 19766// newline, and a <mark>
19766 records the slice of code it covers. Because both 19767// outputs come from the same walk, every range offset is just a position in 19768// `code` â so the highlights can't drift out of sync with the source, and the 19769// block's leading whitespace survives (HTML parsing would collapse it). 19770function extractCodeAndHighlights(preElement) { 19771 const root = preElement.querySelector("code") || preElement; 19772 const highlights = []; 19773 let code = ""; 19774 19775 function walk(node) { 19776 if (node.nodeType === Node.TEXT_NODE) { 19777 code += node.textContent; 19778 } else if (node.nodeType === Node.ELEMENT_NODE) { 19779 if (node.tagName === "BR") { 19780 code += "\n"; 19781 } else if (node.tagName === "MARK") { 19782 const start = code.length; 19783 for (const child of node.childNodes) { 19784 walk(child); 19785 } 19786 const style = extractStyle(node); 19787 if (style) { 19788 highlights.push({ start, end: code.length, style }); 19789 } 19790 } else { 19791 for (const child of node.childNodes) { 19792 walk(child); 19793 } 19794 } 19795 } 19796 } 19797 19798 for (const child of root.childNodes) { 19799 walk(child); 19800 } 19801 19802 return { code, highlights } 19803} 19804 19805function extractStyle(element) { 19806 const parts = []; 19807 if (element.style?.color) parts.push(`color: ${element.style.color};`); 19808 if (element.style?.backgroundColor) parts.push(`background-color: ${element.style.backgroundColor};`); 19809 return parts.length > 0 ? parts.join(" ") : null 19810} 19811 19812// Wrap character ranges in <mark> elements within a Prism-highlighted DOM tree. 19813// Each range is applied independently, re-collecting text nodes each time to 19814// account for splits from previous ranges. 19815function applyHighlightRanges(element, highlights) { 19816 for (const { start, end, style } of highlights) { 19817 wrapRange(element, start, end, style); 19818 } 19819} 19820 19821function wrapRange(container, rangeStart, rangeEnd, style) { 19822 const textNodes = collectTextNodes(container); 19823 19824 // Process in reverse so DOM mutations don't shift earlier text node offsets 19825 for (let i = textNodes.length - 1; i >= 0; i--) { 19826 const { node, start: nodeStart, end: nodeEnd } = textNodes[i]; 19827 const overlapStart = Math.max(rangeStart, nodeStart); 19828 const overlapEnd = Math.min(rangeEnd, nodeEnd); 19829 if (overlapStart >= overlapEnd) continue 19830 19831 const relStart = overlapStart - nodeStart; 19832 const relEnd = overlapEnd - nodeStart; 19833 const text = node.textContent; 19834 const parent = node.parentNode; 19835 19836 const mark = document.createElement("mark"); 19837 mark.setAttribute("style", style); 19838 mark.textContent = text.slice(relStart, relEnd); 19839 19840 if (relEnd < text.length) { 19841 parent.insertBefore(document.createTextNode(text.slice(relEnd)), node.nextSibling); 19842 } 19843 parent.insertBefore(mark, node.nextSibling); 19844 19845 if (relStart > 0) { 19846 node.textContent = text.slice(0, relStart); 19847 } else { 19848 parent.removeChild(node); 19849 } 19850 } 19851} 19852 19853function collectTextNodes(root) { 19854 const nodes = []; 19855 let offset = 0; 19856 const walker = document.createTreeWalker(root, 4 /* NodeFilter.SHOW_TEXT */); 19857 19858 let node; 19859 while ((node = walker.nextNode())) { 19860 const length = node.textContent.length; 19861 nodes.push({ node, start: offset, end: offset + length }); 19862 offset += length; 19863 } 19864 19865 return nodes 19866} 19867 19868class NativeAdapter { 19869 frozenLinkKey = null 19870 19871 constructor(editorElement) { 19872 this.editorElement = editorElement; 19873 this.editorContentElement = editorElement.editorContentElement; 19874 } 19875 19876 dispatchAttributesChange(attributes, linkHref, highlight, headingTag) { 19877 dispatch(this.editorElement, "lexxy:attributes-change", { 19878 attributes, 19879 link: linkHref ? { href: linkHref } : null, 19880 highlight, 19881 headingTag 19882 }); 19883 } 19884 19885 dispatchEditorInitialized(detail) { 19886 dispatch(this.editorElement, "lexxy:editor-initialized", detail); 19887 } 19888 19889 freeze() { 19890 let frozenLinkKey = null; 19891 this.editorElement.editor?.getEditorState().read(() => { 19892 const selection = Qr(); 19893 if (!Fr(selection)) return 19894 19895 const linkNode = At$2(selection.anchor.getNode(), F$4); 19896 if (linkNode) { 19897 frozenLinkKey = linkNode.getKey(); 19898 } 19899 }); 19900 19901 this.frozenLinkKey = frozenLinkKey; 19902 this.editorContentElement.contentEditable = "false"; 19903 } 19904 19905 thaw() { 19906 this.editorContentElement.contentEditable = "true"; 19907 } 19908 19909 unlinkFrozenNode() {
vendor: 2,125 bytes, lines 19910-19972
19910 const key = this.frozenLinkKey; 19911 if (!key) return false 19912 19913 const linkNode = Yo(key); 19914 if (!z$5(linkNode)) { 19915 this.frozenLinkKey = null; 19916 return false 19917 } 19918 19919 const children = linkNode.getChildren(); 19920 for (const child of children) { 19921 linkNode.insertBefore(child); 19922 } 19923 linkNode.remove(); 19924 19925 // Select the former link text so a follow-up createLink can re-wrap it. 19926 const firstText = this.#findFirstTextDescendant(children); 19927 const lastText = this.#findLastTextDescendant(children); 19928 if (firstText && lastText) { 19929 const selection = Qr(); 19930 if (Fr(selection)) { 19931 selection.anchor.set(firstText.getKey(), 0, "text"); 19932 selection.focus.set(lastText.getKey(), lastText.getTextContent().length, "text"); 19933 } 19934 } 19935 19936 this.frozenLinkKey = null; 19937 return true 19938 } 19939 19940 #findFirstTextDescendant(nodes) { 19941 for (const node of nodes) { 19942 if (Tr(node)) return node 19943 if (Wi(node)) { 19944 const nestedTextNode = this.#findFirstTextDescendant(node.getChildren()); 19945 if (nestedTextNode) return nestedTextNode 19946 } 19947 } 19948 19949 return null 19950 } 19951 19952 #findLastTextDescendant(nodes) { 19953 for (let index = nodes.length - 1; index >= 0; index--) { 19954 const node = nodes[index]; 19955 if (Tr(node)) return node 19956 if (Wi(node)) { 19957 const nestedTextNode = this.#findLastTextDescendant(node.getChildren()); 19958 if (nestedTextNode) return nestedTextNode 19959 } 19960 } 19961 19962 return null 19963 } 19964} 19965 19966const configure = Lexxy.configure; 19967 19968// Pushing elements definition to after the current call stack to allow global configuration to take place first 19969setTimeout(defineElements, 0); 19970 19971export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, $isCustomActionTextAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, EditorSanitizer, LexxyExtension as Extension, HorizontalDividerNode, Lexical_prod as Lexical, NativeAdapter, REWRITE_HISTORY_COMMAND, configure, highlightCode, highlightElement }; 19972//# sourceMappingURL=/assets/lexxy-cf25b7b2.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.